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 289 id = logr_hdalloc(mxa); 290 if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) { 291 hd->nh_data_free = logr_context_data_free; 292 bcopy(id, ¶m->handle, sizeof (logr_handle_t)); 293 param->status = ERROR_SUCCESS; 294 } else { 295 bzero(¶m->handle, sizeof (logr_handle_t)); 296 param->status = ERROR_ACCESS_DENIED; 297 } 298 299 return (NDR_DRC_OK); 300 } 301 302 /* 303 * logr_get_snapshot 304 * 305 * Allocate memory and make a copy, as a snapshot, from system log. 306 */ 307 static int 308 logr_get_snapshot(logr_context_t *ctx) 309 { 310 logr_read_data_t *data = NULL; 311 312 ctx->lc_cached_read_data = malloc(sizeof (logr_read_data_t)); 313 if (ctx->lc_cached_read_data != NULL) { 314 data = ctx->lc_cached_read_data; 315 316 data->rd_log = (logr_info_t *)malloc(sizeof (logr_info_t)); 317 if (data->rd_log == NULL) { 318 free(data); 319 return (-1); 320 } 321 bzero(data->rd_log, sizeof (logr_info_t)); 322 323 data->rd_tot_recnum = logr_syslog_snapshot(data->rd_log); 324 if (data->rd_tot_recnum < 0) { 325 free(data->rd_log); 326 free(data); 327 return (-1); 328 } 329 330 data->rd_first_read = 1; 331 332 return (0); 333 } 334 335 return (-1); 336 } 337 338 /* 339 * logr_s_EventLogQueryCount 340 * 341 * take a snapshot from system log, assign it to the given handle. 342 * return number of log entries in the snapshot as result of RPC 343 * call. 344 */ 345 static int 346 logr_s_EventLogQueryCount(void *arg, ndr_xa_t *mxa) 347 { 348 struct logr_EventLogQueryCount *param = arg; 349 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 350 ndr_handle_t *hd; 351 logr_context_t *ctx; 352 logr_read_data_t *data; 353 354 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 355 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 356 return (NDR_DRC_OK); 357 } 358 359 ctx = (logr_context_t *)hd->nh_data; 360 data = ctx->lc_cached_read_data; 361 362 param->rec_num = data->rd_tot_recnum; 363 param->status = NT_STATUS_SUCCESS; 364 return (NDR_DRC_OK); 365 } 366 367 /* 368 * logr_s_EventLogGetOldestRec 369 * 370 * Return oldest record number in the snapshot as result of RPC call. 371 */ 372 static int 373 logr_s_EventLogGetOldestRec(void *arg, ndr_xa_t *mxa) 374 { 375 struct logr_EventLogGetOldestRec *param = arg; 376 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 377 ndr_handle_t *hd; 378 logr_context_t *ctx; 379 logr_read_data_t *data; 380 381 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 382 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 383 return (NDR_DRC_OK); 384 } 385 386 ctx = (logr_context_t *)hd->nh_data; 387 data = ctx->lc_cached_read_data; 388 389 param->oldest_rec = data->rd_log->li_idx - data->rd_tot_recnum + 1; 390 391 param->status = NT_STATUS_SUCCESS; 392 return (NDR_DRC_OK); 393 } 394 395 /* 396 * logr_set_event_typeid 397 * 398 * Map the local system log priority to the event type and event ID 399 * for Windows events. 400 */ 401 void 402 logr_set_event_typeid(int le_pri, WORD *etype, DWORD *eid) 403 { 404 switch (LOGR_PRI(le_pri)) { 405 case LOG_EMERG: 406 case LOG_ALERT: 407 case LOG_CRIT: 408 case LOG_ERR: 409 *eid = EVENTID_SEVERITY_ERROR; 410 *etype = EVENTLOG_ERROR_TYPE; 411 break; 412 case LOG_WARNING: 413 *eid = EVENTID_SEVERITY_WARNING; 414 *etype = EVENTLOG_WARNING_TYPE; 415 break; 416 case LOG_NOTICE: 417 case LOG_INFO: 418 case LOG_DEBUG: 419 *eid = EVENTID_SEVERITY_INFO; 420 *etype = EVENTLOG_INFORMATION_TYPE; 421 break; 422 default: 423 *eid = EVENTID_SEVERITY_SUCCESS; 424 *etype = EVENTLOG_SUCCESS; 425 } 426 } 427 428 /* 429 * logr_get_entry 430 * 431 * Gets a log entry. 432 */ 433 static logr_entry_t * 434 logr_get_entry(logr_info_t *linfo, int entno) 435 { 436 return (&linfo->li_entry[entno]); 437 } 438 439 /* 440 * logr_set_logrecord 441 * 442 * Fill a Windows event record based on a local system log record. 443 */ 444 static void 445 logr_set_logrecord(char *src_name, logr_entry_t *le, 446 DWORD recno, logr_record_t *rec) 447 { 448 int srcname_len = 0, hostname_len = 0, len; 449 int str_offs, sh_len; 450 mts_wchar_t wcs_hostname[MAXHOSTNAMELEN]; 451 mts_wchar_t wcs_srcname[SYS_NMLN * 2]; 452 453 (void) mts_mbstowcs(wcs_srcname, src_name, 454 strlen(src_name) + 1); 455 srcname_len = LOGR_WNSTRLEN(src_name); 456 457 /* Because, Solaris allows remote logging, need to get hostname here */ 458 (void) mts_mbstowcs(wcs_hostname, le->le_hostname, 459 strlen(le->le_hostname) + 1); 460 hostname_len = LOGR_WNSTRLEN(le->le_hostname); 461 462 sh_len = srcname_len + hostname_len; 463 str_offs = LOGR_MSG_DWORD_OFFSET * sizeof (DWORD) + 464 LOGR_MSG_WORD_OFFSET * sizeof (WORD) + sh_len; 465 466 rec->Length1 = sizeof (logr_record_t); 467 rec->Reserved = LOGR_RECORD_SIGNATURE; 468 rec->RecordNumber = recno; 469 rec->TimeGenerated = le->le_timestamp.tv_sec; 470 rec->TimeWritten = le->le_timestamp.tv_sec; 471 logr_set_event_typeid(le->le_pri, &rec->EventType, &rec->EventID); 472 rec->NumStrings = 1; 473 rec->EventCategory = 0; 474 rec->ReservedFlags = 0; 475 rec->ClosingRecordNumber = 0; 476 rec->StringOffset = str_offs; 477 rec->UserSidLength = 0; 478 rec->UserSidOffset = 0; 479 rec->DataLength = 0; 480 rec->DataOffset = 0; 481 482 bzero(rec->info, LOGR_MAXENTRYLEN); 483 (void) memcpy(rec->info, wcs_srcname, srcname_len); 484 (void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len); 485 486 len = strlen(le->le_msg) + 1; 487 if (len > 0) 488 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 489 (void) mts_mbstowcs((mts_wchar_t *)(rec->info + sh_len), 490 le->le_msg, len); 491 492 rec->Length2 = sizeof (logr_record_t); 493 } 494 495 /* 496 * logr_s_EventLogRead 497 * 498 * Reads a whole number of entries from system log. The function can 499 * read log entries in chronological or reverse chronological order. 500 */ 501 static int 502 logr_s_EventLogRead(void *arg, ndr_xa_t *mxa) 503 { 504 struct logr_EventLogRead *param = arg; 505 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 506 ndr_handle_t *hd; 507 logr_read_data_t *rdata; 508 logr_entry_t *le; 509 DWORD ent_no, ent_num, ent_remain; 510 logr_record_t *rec; 511 BYTE *buf; 512 int dir, ent_per_req, iter; 513 logr_context_t *ctx; 514 515 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 516 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 517 return (NDR_DRC_OK); 518 } 519 520 ctx = (logr_context_t *)hd->nh_data; 521 rdata = ctx->lc_cached_read_data; 522 if (rdata == NULL) { 523 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); 524 return (NDR_DRC_OK); 525 } 526 527 dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ? 528 LOGR_FWD : LOGR_REW; 529 530 if (param->read_flags & EVENTLOG_SEEK_READ) 531 rdata->rd_last_sentrec = param->rec_offset; 532 else if (rdata->rd_first_read) 533 /* 534 * set last record number which is read for 535 * the first iteration of sequential read. 536 */ 537 rdata->rd_last_sentrec = (dir == LOGR_FWD) 538 ? (rdata->rd_log->li_idx - rdata->rd_tot_recnum) 539 : rdata->rd_log->li_idx; 540 541 ent_remain = (dir == LOGR_FWD) 542 ? (rdata->rd_tot_recnum - rdata->rd_last_sentrec) 543 : rdata->rd_last_sentrec; 544 545 /* 546 * function should return as many whole log entries as 547 * will fit in the buffer; it should not return partial 548 * entries, even if there is room in the buffer. 549 */ 550 ent_per_req = param->nbytes_to_read / sizeof (logr_record_t); 551 if (ent_remain > ent_per_req) 552 ent_remain = ent_per_req; 553 554 if (ent_remain == 0) { 555 /* 556 * Send this error to Windows client so that it 557 * can figure out that there is no more record 558 * to read. 559 */ 560 param->buf = NDR_STRDUP(mxa, ""); 561 param->sent_size = 0; 562 param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE); 563 return (NDR_DRC_OK); 564 } 565 566 param->buf = NDR_MALLOC(mxa, param->nbytes_to_read); 567 buf = (BYTE *)param->buf; 568 569 for (ent_num = 0, ent_no = rdata->rd_last_sentrec; 570 ent_num < ent_remain; ent_num++, ent_no += dir) { 571 572 iter = ent_no & LOGR_NMSGMASK; 573 if (dir == LOGR_REW) 574 iter = (ent_no - 1) & LOGR_NMSGMASK; 575 576 le = logr_get_entry(rdata->rd_log, iter); 577 578 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 579 rec = (logr_record_t *)buf; 580 logr_set_logrecord(ctx->lc_source_name, le, ent_no, rec); 581 buf += sizeof (logr_record_t); 582 } 583 584 rdata->rd_last_sentrec = ent_no; 585 rdata->rd_first_read = 0; 586 587 param->sent_size = sizeof (logr_record_t) * ent_remain; 588 param->status = NT_STATUS_SUCCESS; 589 590 return (NDR_DRC_OK); 591 } 592