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