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 #include <smbsrv/libsmb.h> 33 #include <smbsrv/libmlrpc.h> 34 #include <smbsrv/ntstatus.h> 35 #include <smbsrv/nmpipes.h> 36 #include <smbsrv/libmlsvc.h> 37 #include <smbsrv/ndl/eventlog.ndl> 38 #include <smbsrv/nterror.h> 39 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 /* 166 * logr_initialize 167 * 168 * This function registers the LOGR RPC interface with the RPC runtime 169 * library. It must be called in order to use either the client side 170 * or the server side functions. 171 */ 172 void 173 logr_initialize(void) 174 { 175 (void) ndr_svc_register(&logr_service); 176 logr_init(); 177 } 178 179 void 180 logr_finalize(void) 181 { 182 logr_fini(); 183 } 184 185 /* 186 * logr_hdlookup 187 * 188 * Handle lookup wrapper to validate the local service and/or manager context. 189 */ 190 static ndr_handle_t * 191 logr_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id) 192 { 193 ndr_handle_t *hd; 194 logr_context_t *ctx; 195 196 if ((hd = ndr_hdlookup(mxa, id)) == NULL) 197 return (NULL); 198 199 if ((ctx = (logr_context_t *)hd->nh_data) == NULL) 200 return (NULL); 201 202 if (ctx->lc_source_name == NULL) 203 return (NULL); 204 205 return (hd); 206 } 207 208 /* 209 * logr_context_data_free 210 * 211 * Callback to free the context data associated with local service 212 * and/or manager context. 213 */ 214 static void 215 logr_context_data_free(void *ctxp) 216 { 217 logr_context_t *ctx = (logr_context_t *)ctxp; 218 219 if (ctx == NULL) 220 return; 221 222 free(ctx->lc_source_name); 223 free(ctx->lc_cached_read_data->rd_log); 224 free(ctx->lc_cached_read_data); 225 free(ctx); 226 ctx = NULL; 227 } 228 229 /* 230 * logr_hdalloc 231 * 232 * Handle allocation wrapper to setup the local manager context. 233 */ 234 static ndr_hdid_t * 235 logr_hdalloc(ndr_xa_t *mxa, char *logname) 236 { 237 logr_context_t *ctx; 238 239 if ((ctx = malloc(sizeof (logr_context_t))) == NULL) 240 return (NULL); 241 bzero(ctx, sizeof (logr_context_t)); 242 243 ctx->lc_source_name = strdup(logname); 244 if (ctx->lc_source_name == NULL) { 245 free(ctx); 246 return (NULL); 247 } 248 249 if (logr_get_snapshot(ctx) != 0) { 250 free(ctx->lc_source_name); 251 free(ctx); 252 return (NULL); 253 } 254 255 return (ndr_hdalloc(mxa, ctx)); 256 } 257 258 /* 259 * logr_s_EventLogClose 260 * 261 * This is a request to close the LOGR interface specified by handle. 262 * Free the handle and associated resources, and zero out the result 263 * handle for the client. 264 */ 265 static int 266 logr_s_EventLogClose(void *arg, ndr_xa_t *mxa) 267 { 268 struct logr_EventLogClose *param = arg; 269 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 270 ndr_handle_t *hd; 271 272 if ((hd = ndr_hdlookup(mxa, id)) == NULL) { 273 bzero(¶m->result_handle, sizeof (logr_handle_t)); 274 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 275 return (NDR_DRC_OK); 276 } 277 logr_context_data_free(hd->nh_data); 278 ndr_hdfree(mxa, id); 279 280 bzero(¶m->result_handle, sizeof (logr_handle_t)); 281 param->status = NT_STATUS_SUCCESS; 282 283 return (NDR_DRC_OK); 284 } 285 286 /* 287 * logr_s_EventLogOpen 288 * 289 * Open the event log. Not supported yet. 290 */ 291 /*ARGSUSED*/ 292 static int 293 logr_s_EventLogOpen(void *arg, ndr_xa_t *mxa) 294 { 295 struct logr_EventLogOpen *param = arg; 296 ndr_hdid_t *id = NULL; 297 ndr_handle_t *hd; 298 char *log_name = NULL; 299 300 if (!ndr_is_admin(mxa)) { 301 bzero(¶m->handle, sizeof (logr_handle_t)); 302 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); 303 return (NDR_DRC_OK); 304 } 305 306 if (param->log_name.length != 0) 307 log_name = (char *)param->log_name.str; 308 309 if (!logr_is_supported(log_name)) { 310 bzero(¶m->handle, sizeof (logr_handle_t)); 311 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); 312 return (NDR_DRC_OK); 313 } 314 315 id = logr_hdalloc(mxa, log_name); 316 if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) { 317 hd->nh_data_free = logr_context_data_free; 318 bcopy(id, ¶m->handle, sizeof (logr_handle_t)); 319 param->status = NT_STATUS_SUCCESS; 320 } else { 321 bzero(¶m->handle, sizeof (logr_handle_t)); 322 param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); 323 } 324 325 return (NDR_DRC_OK); 326 } 327 328 /* 329 * logr_s_EventLogQueryCount 330 * 331 * take a snapshot from system log, assign it to the given handle. 332 * return number of log entries in the snapshot as result of RPC 333 * call. 334 */ 335 static int 336 logr_s_EventLogQueryCount(void *arg, ndr_xa_t *mxa) 337 { 338 struct logr_EventLogQueryCount *param = arg; 339 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 340 ndr_handle_t *hd; 341 logr_context_t *ctx; 342 logr_read_data_t *data; 343 344 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 345 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 346 return (NDR_DRC_OK); 347 } 348 349 ctx = (logr_context_t *)hd->nh_data; 350 data = ctx->lc_cached_read_data; 351 352 param->rec_num = data->rd_tot_recnum; 353 param->status = NT_STATUS_SUCCESS; 354 return (NDR_DRC_OK); 355 } 356 357 /* 358 * logr_s_EventLogGetOldestRec 359 * 360 * Return oldest record number in the snapshot as result of RPC call. 361 */ 362 static int 363 logr_s_EventLogGetOldestRec(void *arg, ndr_xa_t *mxa) 364 { 365 struct logr_EventLogGetOldestRec *param = arg; 366 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 367 ndr_handle_t *hd; 368 logr_context_t *ctx; 369 logr_read_data_t *data; 370 371 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 372 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 373 return (NDR_DRC_OK); 374 } 375 376 ctx = (logr_context_t *)hd->nh_data; 377 data = ctx->lc_cached_read_data; 378 379 param->oldest_rec = data->rd_log->li_idx - data->rd_tot_recnum + 1; 380 381 param->status = NT_STATUS_SUCCESS; 382 return (NDR_DRC_OK); 383 } 384 385 /* 386 * logr_set_event_typeid 387 * 388 * Map the local system log priority to the event type and event ID 389 * for Windows events. 390 */ 391 void 392 logr_set_event_typeid(int le_pri, WORD *etype, DWORD *eid) 393 { 394 switch (LOGR_PRI(le_pri)) { 395 case LOG_EMERG: 396 case LOG_ALERT: 397 case LOG_CRIT: 398 case LOG_ERR: 399 *eid = EVENTID_SEVERITY_ERROR; 400 *etype = EVENTLOG_ERROR_TYPE; 401 break; 402 case LOG_WARNING: 403 *eid = EVENTID_SEVERITY_WARNING; 404 *etype = EVENTLOG_WARNING_TYPE; 405 break; 406 case LOG_NOTICE: 407 case LOG_INFO: 408 case LOG_DEBUG: 409 *eid = EVENTID_SEVERITY_INFO; 410 *etype = EVENTLOG_INFORMATION_TYPE; 411 break; 412 default: 413 *eid = EVENTID_SEVERITY_SUCCESS; 414 *etype = EVENTLOG_SUCCESS; 415 } 416 } 417 418 /* 419 * logr_get_entry 420 * 421 * Gets a log entry. 422 */ 423 static logr_entry_t * 424 logr_get_entry(logr_info_t *linfo, int entno) 425 { 426 return (&linfo->li_entry[entno]); 427 } 428 429 /* 430 * logr_set_logrecord 431 * 432 * Fill a Windows event record based on a local system log record. 433 */ 434 static void 435 logr_set_logrecord(char *src_name, logr_entry_t *le, 436 DWORD recno, logr_record_t *rec) 437 { 438 int srcname_len = 0, hostname_len = 0, len; 439 int str_offs, sh_len; 440 mts_wchar_t wcs_hostname[MAXHOSTNAMELEN]; 441 mts_wchar_t wcs_srcname[SYS_NMLN * 2]; 442 443 (void) mts_mbstowcs(wcs_srcname, src_name, 444 strlen(src_name) + 1); 445 srcname_len = LOGR_WNSTRLEN(src_name); 446 447 /* Because, Solaris allows remote logging, need to get hostname here */ 448 (void) mts_mbstowcs(wcs_hostname, le->le_hostname, 449 strlen(le->le_hostname) + 1); 450 hostname_len = LOGR_WNSTRLEN(le->le_hostname); 451 452 sh_len = srcname_len + hostname_len; 453 str_offs = LOGR_MSG_DWORD_OFFSET * sizeof (DWORD) + 454 LOGR_MSG_WORD_OFFSET * sizeof (WORD) + sh_len; 455 456 rec->Length1 = sizeof (logr_record_t); 457 rec->Reserved = LOGR_RECORD_SIGNATURE; 458 rec->RecordNumber = recno; 459 rec->TimeGenerated = le->le_timestamp.tv_sec; 460 rec->TimeWritten = le->le_timestamp.tv_sec; 461 logr_set_event_typeid(le->le_pri, &rec->EventType, &rec->EventID); 462 rec->NumStrings = 1; 463 rec->EventCategory = 0; 464 rec->ReservedFlags = 0; 465 rec->ClosingRecordNumber = 0; 466 rec->StringOffset = str_offs; 467 rec->UserSidLength = 0; 468 rec->UserSidOffset = 0; 469 rec->DataLength = 0; 470 rec->DataOffset = 0; 471 472 bzero(rec->info, LOGR_MAXENTRYLEN); 473 (void) memcpy(rec->info, wcs_srcname, srcname_len); 474 (void) memcpy(rec->info + srcname_len, wcs_hostname, hostname_len); 475 476 len = strlen(le->le_msg) + 1; 477 if (len > 0) 478 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 479 (void) mts_mbstowcs((mts_wchar_t *)(rec->info + sh_len), 480 le->le_msg, len); 481 482 rec->Length2 = sizeof (logr_record_t); 483 } 484 485 /* 486 * logr_s_EventLogRead 487 * 488 * Reads a whole number of entries from system log. The function can 489 * read log entries in chronological or reverse chronological order. 490 */ 491 static int 492 logr_s_EventLogRead(void *arg, ndr_xa_t *mxa) 493 { 494 struct logr_EventLogRead *param = arg; 495 ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; 496 ndr_handle_t *hd; 497 logr_read_data_t *rdata; 498 logr_entry_t *le; 499 DWORD ent_no, ent_num, ent_remain; 500 logr_record_t *rec; 501 BYTE *buf; 502 int dir, ent_per_req, iter; 503 logr_context_t *ctx; 504 505 if ((hd = logr_hdlookup(mxa, id)) == NULL) { 506 param->status = NT_SC_ERROR(NT_STATUS_INVALID_HANDLE); 507 return (NDR_DRC_OK); 508 } 509 510 ctx = (logr_context_t *)hd->nh_data; 511 rdata = ctx->lc_cached_read_data; 512 if (rdata == NULL) { 513 param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); 514 return (NDR_DRC_OK); 515 } 516 517 dir = (param->read_flags & EVENTLOG_FORWARDS_READ) ? 518 LOGR_FWD : LOGR_REW; 519 520 if (param->read_flags & EVENTLOG_SEEK_READ) 521 rdata->rd_last_sentrec = param->rec_offset; 522 else if (rdata->rd_first_read) 523 /* 524 * set last record number which is read for 525 * the first iteration of sequential read. 526 */ 527 rdata->rd_last_sentrec = (dir == LOGR_FWD) 528 ? (rdata->rd_log->li_idx - rdata->rd_tot_recnum) 529 : rdata->rd_log->li_idx; 530 531 ent_remain = (dir == LOGR_FWD) 532 ? (rdata->rd_tot_recnum - rdata->rd_last_sentrec) 533 : rdata->rd_last_sentrec; 534 535 /* 536 * function should return as many whole log entries as 537 * will fit in the buffer; it should not return partial 538 * entries, even if there is room in the buffer. 539 */ 540 ent_per_req = param->nbytes_to_read / sizeof (logr_record_t); 541 if (ent_remain > ent_per_req) 542 ent_remain = ent_per_req; 543 544 if (ent_remain == 0) { 545 /* 546 * Send this error to Windows client so that it 547 * can figure out that there is no more record 548 * to read. 549 */ 550 param->buf = NDR_STRDUP(mxa, ""); 551 param->sent_size = 0; 552 param->status = NT_SC_ERROR(NT_STATUS_END_OF_FILE); 553 return (NDR_DRC_OK); 554 } 555 556 param->buf = NDR_MALLOC(mxa, param->nbytes_to_read); 557 buf = (BYTE *)param->buf; 558 559 for (ent_num = 0, ent_no = rdata->rd_last_sentrec; 560 ent_num < ent_remain; ent_num++, ent_no += dir) { 561 562 iter = ent_no & LOGR_NMSGMASK; 563 if (dir == LOGR_REW) 564 iter = (ent_no - 1) & LOGR_NMSGMASK; 565 566 le = logr_get_entry(rdata->rd_log, iter); 567 568 /*LINTED E_BAD_PTR_CAST_ALIGN*/ 569 rec = (logr_record_t *)buf; 570 logr_set_logrecord(ctx->lc_source_name, le, ent_no, rec); 571 buf += sizeof (logr_record_t); 572 } 573 574 rdata->rd_last_sentrec = ent_no; 575 rdata->rd_first_read = 0; 576 577 param->sent_size = sizeof (logr_record_t) * ent_remain; 578 param->status = NT_STATUS_SUCCESS; 579 580 return (NDR_DRC_OK); 581 } 582