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 *)¶m->handle; 268 ndr_handle_t *hd; 269 270 if ((hd = ndr_hdlookup(mxa, id)) == NULL) { 271 bzero(¶m->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(¶m->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(¶m->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(¶m->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, ¶m->handle, sizeof (logr_handle_t)); 317 param->status = NT_STATUS_SUCCESS; 318 } else { 319 bzero(¶m->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 *)¶m->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 *)¶m->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 *)¶m->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 } 580