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