xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
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 *)&param->handle;
268 	ndr_handle_t *hd;
269 
270 	if ((hd = ndr_hdlookup(mxa, id)) == NULL) {
271 		bzero(&param->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(&param->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(&param->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(&param->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, &param->handle, sizeof (logr_handle_t));
317 		param->status = NT_STATUS_SUCCESS;
318 	} else {
319 		bzero(&param->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 *)&param->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 *)&param->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 *)&param->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