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