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