1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Event Log Service RPC (LOGR) interface definition.
  29  */
  30 #include <sys/utsname.h>
  31 #include <unistd.h>
  32 #include <strings.h>
  33 #include <libmlrpc/libmlrpc.h>
  34 #include <smbsrv/libsmb.h>
  35 #include <smbsrv/nmpipes.h>
  36 #include <smbsrv/libmlsvc.h>
  37 #include <smbsrv/ndl/eventlog.ndl>
  38 
  39 
  40 #define LOGR_FWD                +1
  41 #define LOGR_REW                -1
  42 #define LOGR_RECORD_SIGNATURE   0x654C664C
  43 
  44 #define LOGR_PRI(p)             ((p) & LOG_PRIMASK)
  45 #define LOGR_WNSTRLEN(S)        ((strlen((S)) + 1) * sizeof (smb_wchar_t))
  46 
  47 #define LOGR_MSG_DWORD_OFFSET   12
  48 #define LOGR_MSG_WORD_OFFSET    4
  49 
  50 /*
  51  * READ flags for EventLogRead
  52  *
  53  * EVENTLOG_SEEK_READ
  54  * The read operation proceeds from the record specified by the
  55  * dwRecordOffset parameter. This flag cannot be used with
  56  * EVENTLOG_SEQUENTIAL_READ.
  57  *
  58  * EVENTLOG_SEQUENTIAL_READ
  59  * The read operation proceeds sequentially from the last call to the
  60  * ReadEventLog function using this handle. This flag cannot be used
  61  * with EVENTLOG_SEEK_READ.
  62  *
  63  * If the buffer is large enough, more than one record can be read at
  64  * the specified seek position; you must specify one of the following
  65  * flags to indicate the direction for successive read operations.
  66  *
  67  * EVENTLOG_FORWARDS_READ
  68  * The log is read in chronological order. This flag cannot be used
  69  * with EVENTLOG_BACKWARDS_READ.
  70  *
  71  * EVENTLOG_BACKWARDS_READ
  72  * The log is read in reverse chronological order. This flag cannot be
  73  * used with EVENTLOG_FORWARDS_READ.
  74  */
  75 #define EVENTLOG_SEQUENTIAL_READ        0x0001
  76 #define EVENTLOG_SEEK_READ              0x0002
  77 #define EVENTLOG_FORWARDS_READ          0x0004
  78 #define EVENTLOG_BACKWARDS_READ         0x0008
  79 
  80 /*
  81  * The types of events that can be logged.
  82  */
  83 #define EVENTLOG_SUCCESS                0x0000
  84 #define EVENTLOG_ERROR_TYPE             0x0001
  85 #define EVENTLOG_WARNING_TYPE           0x0002
  86 #define EVENTLOG_INFORMATION_TYPE       0x0004
  87 #define EVENTLOG_AUDIT_SUCCESS          0x0008
  88 #define EVENTLOG_AUDIT_FAILURE          0x0010
  89 
  90 /*
  91  * Event Identifiers
  92  *
  93  * Event identifiers uniquely identify a particular event. Each event
  94  * source can define its own numbered events and the description strings
  95  * to which they are mapped. Event viewers can present these strings to
  96  * the user. They should help the user understand what went wrong and
  97  * suggest what actions to take. Direct the description at users solving
  98  * their own problems, not at administrators or support technicians.
  99  * Make the description clear and concise and avoid culture-specific
 100  * phrases.
 101  *
 102  * The following diagram illustrates the format of an event identifier.
 103  *
 104  *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
 105  *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
 106  *  +---+-+-+-----------------------+-------------------------------+
 107  *  |Sev|C|R|     Facility          |               Code            |
 108  *  +---+-+-+-----------------------+-------------------------------+
 109  *
 110  *  Sev
 111  *        Indicates the severity. This is one of the following values:
 112  *        00 - Success
 113  *        01 - Informational
 114  *        10 - Warning
 115  *        11 - Error
 116  *
 117  *  C
 118  *        Indicates a customer code (1) or a system code (0).
 119  *  R
 120  *        Reserved bit.
 121  *  Facility
 122  *        Facility code.
 123  *  Code
 124  *        Status code for the facility.
 125  */
 126 #define EVENTID_SEVERITY_SUCCESS        0x00000000
 127 #define EVENTID_SEVERITY_INFO           0x40000000
 128 #define EVENTID_SEVERITY_WARNING        0x80000000
 129 #define EVENTID_SEVERITY_ERROR          0xC0000000
 130 
 131 #define EVENTID_SYSTEM_CODE             0x00000000
 132 #define EVENTID_CUSTOMER_CODE           0x20000000
 133 
 134 static int logr_s_EventLogClose(void *, ndr_xa_t *);
 135 static int logr_s_EventLogQueryCount(void *, ndr_xa_t *);
 136 static int logr_s_EventLogGetOldestRec(void *, ndr_xa_t *);
 137 static int logr_s_EventLogOpen(void *, ndr_xa_t *);
 138 static int logr_s_EventLogRead(void *, ndr_xa_t *);
 139 
 140 static ndr_stub_table_t logr_stub_table[] = {
 141         { logr_s_EventLogClose,         LOGR_OPNUM_EventLogClose },
 142         { logr_s_EventLogQueryCount,    LOGR_OPNUM_EventLogQueryCount },
 143         { logr_s_EventLogGetOldestRec,  LOGR_OPNUM_EventLogGetOldestRec },
 144         { logr_s_EventLogOpen,          LOGR_OPNUM_EventLogOpen },
 145         { logr_s_EventLogRead,          LOGR_OPNUM_EventLogRead },
 146         {0}
 147 };
 148 
 149 static ndr_service_t logr_service = {
 150         "LOGR",                         /* name */
 151         "Event Log Service",            /* desc */
 152         "\\eventlog",                   /* endpoint */
 153         PIPE_NTSVCS,                    /* sec_addr_port */
 154         "82273fdc-e32a-18c3-3f78-827929dc23ea", 0,      /* abstract */
 155         NDR_TRANSFER_SYNTAX_UUID,               2,      /* transfer */
 156         0,                              /* no bind_instance_size */
 157         0,                              /* no bind_req() */
 158         0,                              /* no unbind_and_close() */
 159         0,                              /* use generic_call_stub() */
 160         &TYPEINFO(logr_interface),  /* interface ti */
 161         logr_stub_table                 /* stub_table */
 162 };
 163 
 164 /*
 165  * logr_initialize
 166  *
 167  * This function registers the LOGR RPC interface with the RPC runtime
 168  * library. It must be called in order to use either the client side
 169  * or the server side functions.
 170  */
 171 void
 172 logr_initialize(void)
 173 {
 174         (void) ndr_svc_register(&logr_service);
 175         logr_init();
 176 }
 177 
 178 void
 179 logr_finalize(void)
 180 {
 181         logr_fini();
 182 }
 183 
 184 /*
 185  * logr_hdlookup
 186  *
 187  * Handle lookup wrapper to validate the local service and/or manager context.
 188  */
 189 static ndr_handle_t *
 190 logr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id)
 191 {
 192         ndr_handle_t *hd;
 193         logr_context_t *ctx;
 194 
 195         if ((hd = ndr_hdlookup(mxa, id)) == NULL)
 196                 return (NULL);
 197 
 198         if ((ctx = (logr_context_t *)hd->nh_data) == NULL)
 199                 return (NULL);
 200 
 201         if (ctx->lc_source_name == NULL)
 202                 return (NULL);
 203 
 204         return (hd);
 205 }
 206 
 207 /*
 208  * logr_context_data_free
 209  *
 210  * Callback to free the context data associated with local service
 211  * and/or manager context.
 212  */
 213 static void
 214 logr_context_data_free(void *ctxp)
 215 {
 216         logr_context_t *ctx = (logr_context_t *)ctxp;
 217 
 218         if (ctx == NULL)
 219                 return;
 220 
 221         free(ctx->lc_source_name);
 222         free(ctx->lc_cached_read_data->rd_log);
 223         free(ctx->lc_cached_read_data);
 224         free(ctx);
 225         ctx = NULL;
 226 }
 227 
 228 /*
 229  * logr_hdalloc
 230  *
 231  * Handle allocation wrapper to setup the local manager context.
 232  */
 233 static ndr_hdid_t *
 234 logr_hdalloc(ndr_xa_t *mxa, char *logname)
 235 {
 236         logr_context_t *ctx;
 237 
 238         if ((ctx = malloc(sizeof (logr_context_t))) == NULL)
 239                 return (NULL);
 240         bzero(ctx, sizeof (logr_context_t));
 241 
 242         ctx->lc_source_name = strdup(logname);
 243         if (ctx->lc_source_name == NULL) {
 244                 free(ctx);
 245                 return (NULL);
 246         }
 247 
 248         if (logr_get_snapshot(ctx) != 0) {
 249                 free(ctx->lc_source_name);
 250                 free(ctx);
 251                 return (NULL);
 252         }
 253 
 254         return (ndr_hdalloc(mxa, ctx));
 255 }
 256 
 257 /*
 258  * logr_s_EventLogClose
 259  *
 260  * This is a request to close the LOGR interface specified by handle.
 261  * Free the handle and associated resources, and zero out the result
 262  * handle for the client.
 263  */
 264 static int
 265 logr_s_EventLogClose(void *arg, ndr_xa_t *mxa)
 266 {
 267         struct logr_EventLogClose *param = arg;
 268         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 269         ndr_handle_t *hd;
 270 
 271         if ((hd = ndr_hdlookup(mxa, id)) == NULL) {
 272                 bzero(&param->result_handle, sizeof (logr_handle_t));
 273                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 274                 return (NDR_DRC_OK);
 275         }
 276         logr_context_data_free(hd->nh_data);
 277         ndr_hdfree(mxa, id);
 278 
 279         bzero(&param->result_handle, sizeof (logr_handle_t));
 280         param->status = NT_STATUS_SUCCESS;
 281 
 282         return (NDR_DRC_OK);
 283 }
 284 
 285 /*
 286  * logr_s_EventLogOpen
 287  *
 288  * Open the event log. Not supported yet.
 289  */
 290 /*ARGSUSED*/
 291 static int
 292 logr_s_EventLogOpen(void *arg, ndr_xa_t *mxa)
 293 {
 294         struct logr_EventLogOpen *param = arg;
 295         ndr_hdid_t *id = NULL;
 296         ndr_handle_t *hd;
 297         char *log_name = NULL;
 298 
 299         if (!ndr_is_admin(mxa)) {
 300                 bzero(&param->handle, sizeof (logr_handle_t));
 301                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 302                 return (NDR_DRC_OK);
 303         }
 304 
 305         if (param->log_name.length != 0)
 306                 log_name = (char *)param->log_name.str;
 307 
 308         if (!logr_is_supported(log_name)) {
 309                 bzero(&param->handle, sizeof (logr_handle_t));
 310                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 311                 return (NDR_DRC_OK);
 312         }
 313 
 314         id = logr_hdalloc(mxa, log_name);
 315         if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
 316                 hd->nh_data_free = logr_context_data_free;
 317                 bcopy(id, &param->handle, sizeof (logr_handle_t));
 318                 param->status = NT_STATUS_SUCCESS;
 319         } else {
 320                 bzero(&param->handle, sizeof (logr_handle_t));
 321                 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 322         }
 323 
 324         return (NDR_DRC_OK);
 325 }
 326 
 327 /*
 328  * logr_s_EventLogQueryCount
 329  *
 330  * take a snapshot from system log, assign it to the given handle.
 331  * return number of log entries in the snapshot as result of RPC
 332  * call.
 333  */
 334 static int
 335 logr_s_EventLogQueryCount(void *arg, ndr_xa_t *mxa)
 336 {
 337         struct logr_EventLogQueryCount *param = arg;
 338         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 339         ndr_handle_t *hd;
 340         logr_context_t *ctx;
 341         logr_read_data_t *data;
 342 
 343         if ((hd = logr_hdlookup(mxa, id)) == NULL) {
 344                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 345                 return (NDR_DRC_OK);
 346         }
 347 
 348         ctx = (logr_context_t *)hd->nh_data;
 349         data = ctx->lc_cached_read_data;
 350 
 351         param->rec_num = data->rd_tot_recnum;
 352         param->status = NT_STATUS_SUCCESS;
 353         return (NDR_DRC_OK);
 354 }
 355 
 356 /*
 357  * logr_s_EventLogGetOldestRec
 358  *
 359  * Return oldest record number in the snapshot as result of RPC call.
 360  */
 361 static int
 362 logr_s_EventLogGetOldestRec(void *arg, ndr_xa_t *mxa)
 363 {
 364         struct logr_EventLogGetOldestRec *param = arg;
 365         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 366         ndr_handle_t *hd;
 367         logr_context_t *ctx;
 368         logr_read_data_t *data;
 369 
 370         if ((hd = logr_hdlookup(mxa, id)) == NULL) {
 371                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 372                 return (NDR_DRC_OK);
 373         }
 374 
 375         ctx = (logr_context_t *)hd->nh_data;
 376         data = ctx->lc_cached_read_data;
 377 
 378         param->oldest_rec = data->rd_log->li_idx - data->rd_tot_recnum + 1;
 379 
 380         param->status = NT_STATUS_SUCCESS;
 381         return (NDR_DRC_OK);
 382 }
 383 
 384 /*
 385  * logr_set_event_typeid
 386  *
 387  * Map the local system log priority to the event type and event ID
 388  * for Windows events.
 389  */
 390 void
 391 logr_set_event_typeid(int le_pri, WORD *etype, DWORD *eid)
 392 {
 393         switch (LOGR_PRI(le_pri)) {
 394         case LOG_EMERG:
 395         case LOG_ALERT:
 396         case LOG_CRIT:
 397         case LOG_ERR:
 398                 *eid   = EVENTID_SEVERITY_ERROR;
 399                 *etype = EVENTLOG_ERROR_TYPE;
 400                 break;
 401         case LOG_WARNING:
 402                 *eid   = EVENTID_SEVERITY_WARNING;
 403                 *etype = EVENTLOG_WARNING_TYPE;
 404                 break;
 405         case LOG_NOTICE:
 406         case LOG_INFO:
 407         case LOG_DEBUG:
 408                 *eid   = EVENTID_SEVERITY_INFO;
 409                 *etype = EVENTLOG_INFORMATION_TYPE;
 410                 break;
 411         default:
 412                 *eid   = EVENTID_SEVERITY_SUCCESS;
 413                 *etype = EVENTLOG_SUCCESS;
 414         }
 415 }
 416 
 417 /*
 418  * logr_get_entry
 419  *
 420  * Gets a log entry.
 421  */
 422 static logr_entry_t *
 423 logr_get_entry(logr_info_t *linfo, int entno)
 424 {
 425         return (&linfo->li_entry[entno]);
 426 }
 427 
 428 /*
 429  * logr_set_logrecord
 430  *
 431  * Fill a Windows event record based on a local system log record.
 432  */
 433 static void
 434 logr_set_logrecord(char *src_name, logr_entry_t *le,
 435     DWORD recno, logr_record_t *rec)
 436 {
 437         int srcname_len = 0, hostname_len = 0, len;
 438         int str_offs, sh_len;
 439         smb_wchar_t wcs_hostname[MAXHOSTNAMELEN];
 440         smb_wchar_t wcs_srcname[SYS_NMLN * 2];
 441 
 442         (void) smb_mbstowcs(wcs_srcname, src_name,
 443             strlen(src_name) + 1);
 444         srcname_len = LOGR_WNSTRLEN(src_name);
 445 
 446         /* Because, Solaris allows remote logging, need to get hostname here */
 447         (void) smb_mbstowcs(wcs_hostname, le->le_hostname,
 448             strlen(le->le_hostname) + 1);
 449         hostname_len = LOGR_WNSTRLEN(le->le_hostname);
 450 
 451         sh_len = srcname_len + hostname_len;
 452         str_offs = LOGR_MSG_DWORD_OFFSET * sizeof (DWORD) +
 453             LOGR_MSG_WORD_OFFSET * sizeof (WORD) + sh_len;
 454 
 455         rec->Length1 = sizeof (logr_record_t);
 456         rec->Reserved = LOGR_RECORD_SIGNATURE;
 457         rec->RecordNumber = recno;
 458         rec->TimeGenerated = le->le_timestamp.tv_sec;
 459         rec->TimeWritten = le->le_timestamp.tv_sec;
 460         logr_set_event_typeid(le->le_pri, &rec->EventType, &rec->EventID);
 461         rec->NumStrings = 1;
 462         rec->EventCategory = 0;
 463         rec->ReservedFlags = 0;
 464         rec->ClosingRecordNumber = 0;
 465         rec->StringOffset = str_offs;
 466         rec->UserSidLength = 0;
 467         rec->UserSidOffset = 0;
 468         rec->DataLength = 0;
 469         rec->DataOffset = 0;
 470 
 471         bzero(rec->info, LOGR_MAXENTRYLEN);
 472         (void) memcpy(rec->info, wcs_srcname, srcname_len);
 473         (void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len);
 474 
 475         len = strlen(le->le_msg) + 1;
 476         if (len > 0)
 477                 /*LINTED E_BAD_PTR_CAST_ALIGN*/
 478                 (void) smb_mbstowcs((smb_wchar_t *)(rec->info + sh_len),
 479                     le->le_msg, len);
 480 
 481         rec->Length2 = sizeof (logr_record_t);
 482 }
 483 
 484 /*
 485  * logr_s_EventLogRead
 486  *
 487  * Reads a whole number of entries from system log. The function can
 488  * read log entries in chronological or reverse chronological order.
 489  */
 490 static int
 491 logr_s_EventLogRead(void *arg, ndr_xa_t *mxa)
 492 {
 493         struct logr_EventLogRead *param = arg;
 494         ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 495         ndr_handle_t *hd;
 496         logr_read_data_t *rdata;
 497         logr_entry_t *le;
 498         DWORD ent_no, ent_num, ent_remain;
 499         logr_record_t *rec;
 500         BYTE *buf;
 501         int dir, ent_per_req, iter;
 502         logr_context_t *ctx;
 503 
 504         if ((hd = logr_hdlookup(mxa, id)) == NULL) {
 505                 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE);
 506                 return (NDR_DRC_OK);
 507         }
 508 
 509         ctx = (logr_context_t *)hd->nh_data;
 510         rdata = ctx->lc_cached_read_data;
 511         if (rdata == NULL) {
 512                 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 513                 return (NDR_DRC_OK);
 514         }
 515 
 516         dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ?
 517             LOGR_FWD : LOGR_REW;
 518 
 519         if (param->read_flags & EVENTLOG_SEEK_READ)
 520                 rdata->rd_last_sentrec = param->rec_offset;
 521         else if (rdata->rd_first_read)
 522                 /*
 523                  * set last record number which is read for
 524                  * the first iteration of sequential read.
 525                  */
 526                 rdata->rd_last_sentrec = (dir == LOGR_FWD)
 527                     ? (rdata->rd_log->li_idx - rdata->rd_tot_recnum)
 528                     : rdata->rd_log->li_idx;
 529 
 530         ent_remain = (dir == LOGR_FWD)
 531             ? (rdata->rd_tot_recnum - rdata->rd_last_sentrec)
 532             : rdata->rd_last_sentrec;
 533 
 534         /*
 535          * function should return as many whole log entries as
 536          * will fit in the buffer; it should not return partial
 537          * entries, even if there is room in the buffer.
 538          */
 539         ent_per_req = param->nbytes_to_read / sizeof (logr_record_t);
 540         if (ent_remain > ent_per_req)
 541                 ent_remain = ent_per_req;
 542 
 543         if (ent_remain == 0) {
 544                 /*
 545                  * Send this error to Windows client so that it
 546                  * can figure out that there is no more record
 547                  * to read.
 548                  */
 549                 param->buf = NDR_STRDUP(mxa, "");
 550                 param->sent_size = 0;
 551                 param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE);
 552                 return (NDR_DRC_OK);
 553         }
 554 
 555         param->buf = NDR_MALLOC(mxa, param->nbytes_to_read);
 556         buf = (BYTE *)param->buf;
 557 
 558         for (ent_num = 0, ent_no = rdata->rd_last_sentrec;
 559             ent_num < ent_remain; ent_num++, ent_no += dir) {
 560 
 561                 iter = ent_no & LOGR_NMSGMASK;
 562                 if (dir == LOGR_REW)
 563                         iter = (ent_no - 1) & LOGR_NMSGMASK;
 564 
 565                 le = logr_get_entry(rdata->rd_log, iter);
 566 
 567                 /*LINTED E_BAD_PTR_CAST_ALIGN*/
 568                 rec = (logr_record_t *)buf;
 569                 logr_set_logrecord(ctx->lc_source_name, le, ent_no, rec);
 570                 buf += sizeof (logr_record_t);
 571         }
 572 
 573         rdata->rd_last_sentrec = ent_no;
 574         rdata->rd_first_read = 0;
 575 
 576         param->sent_size = sizeof (logr_record_t) * ent_remain;
 577         param->status = NT_STATUS_SUCCESS;
 578 
 579         return (NDR_DRC_OK);
 580 }