xref: /NextBSD/usr.sbin/asl/daemon.c (revision a246bbe8b3d631ddb24ff83291df77e8e188cc74)
1 /*
2  * Copyright (c) 2004-2012 Apple Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. Please obtain a copy of the License at
10  * http://www.opensource.apple.com/apsl/ and read it before using this
11  * file.
12  *
13  * The Original Code and all software distributed under the License are
14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18  * Please see the License for the specific language governing rights and
19  * limitations under the License.
20  *
21  * @APPLE_LICENSE_HEADER_END@
22  */
23 
24 #include <TargetConditionals.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <sys/ucred.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #define SYSLOG_NAMES
36 #include <syslog.h>
37 //#include <sys/fslog.h>
38 #include <vproc.h>
39 #include <pthread.h>
40 #include <vproc_priv.h>
41 #include <mach/mach.h>
42 #include <libkern/OSAtomic.h>
43 #include <libproc.h>
44 #include <uuid/uuid.h>
45 #include "daemon.h"
46 
47 #define LIST_SIZE_DELTA 256
48 
49 #define forever for(;;)
50 
51 #define ASL_MSG_TYPE_MASK 0x0000000f
52 #define ASL_TYPE_ERROR 2
53 
54 #define ASL_KEY_FACILITY "Facility"
55 
56 #define FACILITY_USER "user"
57 #define FACILITY_CONSOLE "com.apple.console"
58 #define SYSTEM_RESERVED "com.apple.system"
59 #define SYSTEM_RESERVED_LEN 16
60 
61 #define VERIFY_STATUS_OK 0
62 #define VERIFY_STATUS_INVALID_MESSAGE 1
63 #define VERIFY_STATUS_EXCEEDED_QUOTA 2
64 
65 extern void disaster_message(asl_msg_t *m);
66 extern int asl_action_reset(void);
67 extern int asl_action_control_set_param(const char *s);
68 
69 static char myname[MAXHOSTNAMELEN + 1] = {0};
70 static int name_change_token = -1;
71 
72 static OSSpinLock count_lock = 0;
73 static int aslmanager_triggered = 0;
74 
75 
76 #if !TARGET_OS_EMBEDDED
77 static vproc_transaction_t vproc_trans = {0};
78 #define DEFAULT_WORK_QUEUE_SIZE_MAX 10240000
79 #else
80 #define DEFAULT_WORK_QUEUE_SIZE_MAX 4096000
81 #endif
82 
83 #define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit  -  remaining messages this second discarded ***"
84 
85 #define DEFAULT_DB_FILE_MAX 25600000
86 #define DEFAULT_DB_MEMORY_MAX 512
87 #define DEFAULT_DB_MEMORY_STR_MAX 4096000
88 #define DEFAULT_MPS_LIMIT 500
89 #define DEFAULT_REMOTE_DELAY 5000
90 #define DEFAULT_BSD_MAX_DUP_SEC 30
91 #define DEFAULT_MARK_SEC 0
92 #define DEFAULT_UTMP_TTL_SEC 31622400
93 
94 static time_t quota_time = 0;
95 static int32_t kern_quota;
96 static int32_t kern_level;
97 
98 static const char *kern_notify_key[] =
99 {
100 	"com.apple.system.log.kernel.emergency",
101 	"com.apple.system.log.kernel.alert",
102 	"com.apple.system.log.kernel.critical",
103 	"com.apple.system.log.kernel.error",
104 	"com.apple.system.log.kernel.warning",
105 	"com.apple.system.log.kernel.notice",
106 	"com.apple.system.log.kernel.info",
107 	"com.apple.system.log.kernel.debug"
108 };
109 
110 static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1 };
111 
112 static uint32_t
kern_quota_check(time_t now,asl_msg_t * msg,uint32_t level)113 kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level)
114 {
115 	char *str, lstr[2];
116 
117 	if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
118 	if (global.mps_limit == 0) return VERIFY_STATUS_OK;
119 
120 	if (quota_time != now)
121 	{
122 		kern_quota = global.mps_limit;
123 		kern_level = 7;
124 		quota_time = now;
125 	}
126 
127 	if (level < kern_level) kern_level = level;
128 	if (kern_quota > 0) kern_quota--;
129 
130 	if (kern_quota > 0) return VERIFY_STATUS_OK;
131 	if (kern_quota < 0)	return VERIFY_STATUS_EXCEEDED_QUOTA;
132 
133 	kern_quota = -1;
134 
135 	str = NULL;
136 	asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit);
137 	if (str != NULL)
138 	{
139 		asl_msg_set_key_val(msg, ASL_KEY_MSG, str);
140 		free(str);
141 		lstr[0] = kern_level + '0';
142 		lstr[1] = 0;
143 		asl_msg_set_key_val(msg, ASL_KEY_LEVEL, lstr);
144 	}
145 
146 	return VERIFY_STATUS_OK;
147 }
148 
149 static const char *
whatsmyhostname()150 whatsmyhostname()
151 {
152 	static dispatch_once_t once;
153 	int check, status;
154 
155 #if 0
156 //	dispatch_once(&once, ^{
157 //		snprintf(myname, sizeof(myname), "%s", "localhost");
158 //		notify_register_check(kNotifySCHostNameChange, &name_change_token);
159 //	});
160 #endif
161 
162 	check = 1;
163 	status = 0;
164 
165 	if (name_change_token >= 0) status = notify_check(name_change_token, &check);
166 
167 	if ((status == 0) && (check == 0)) return (const char *)myname;
168 
169 	if (gethostname(myname, MAXHOSTNAMELEN) < 0)
170 	{
171 		snprintf(myname, sizeof(myname), "%s", "localhost");
172 	}
173 	else
174 	{
175 		char *dot;
176 		dot = strchr(myname, '.');
177 		if (dot != NULL) *dot = '\0';
178 	}
179 
180 	return (const char *)myname;
181 }
182 
183 void
asl_client_count_increment()184 asl_client_count_increment()
185 {
186 	OSSpinLockLock(&count_lock);
187 
188 #if !TARGET_OS_EMBEDDED
189 	if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL);
190 #endif
191 	global.client_count++;
192 
193 	OSSpinLockUnlock(&count_lock);
194 }
195 
196 void
asl_client_count_decrement()197 asl_client_count_decrement()
198 {
199 	OSSpinLockLock(&count_lock);
200 
201 	if (global.client_count > 0) global.client_count--;
202 #if !TARGET_OS_EMBEDDED
203 	if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans);
204 #endif
205 
206 	OSSpinLockUnlock(&count_lock);
207 }
208 
209 /*
210  * Checks message content and sets attributes as required
211  *
212  * SOURCE_INTERNAL log messages sent by syslogd itself
213  * SOURCE_ASL_SOCKET legacy asl(3) TCP socket
214  * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket
215  * SOURCE_UDP_SOCKET from the network
216  * SOURCE_KERN from the kernel
217  * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3)
218  * SOURCE_LAUNCHD forwarded from launchd
219  */
220 
221 static uint32_t
aslmsg_verify(asl_msg_t * msg,uint32_t source,int32_t * kern_post_level,uid_t * uid_out)222 aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out)
223 {
224 	const char *val, *fac, *ruval, *rgval;
225 	char buf[64];
226 	time_t tick, now;
227 	uid_t uid;
228 	gid_t gid;
229 	uint32_t status, level, fnum;
230 	pid_t pid;
231 	uuid_string_t ustr;
232 	struct proc_uniqidentifierinfo pinfo;
233 
234 	if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE;
235 
236 	/* Time */
237 	now = time(NULL);
238 
239 	if (kern_post_level != NULL) *kern_post_level = -1;
240 	if (uid_out != NULL) *uid_out = -2;
241 
242 	/* PID */
243 	pid = 0;
244 
245 	val = asl_msg_get_val_for_key(msg, ASL_KEY_PID);
246 	if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
247 	else pid = (pid_t)atoi(val);
248 
249 	/* if PID is 1 (launchd), use the refpid if provided */
250 	if (pid == 1)
251 	{
252 		val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID);
253 		if (val != NULL) pid = (pid_t)atoi(val);
254 	}
255 
256 	/* Level */
257 	val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL);
258 	level = ASL_LEVEL_DEBUG;
259 	if (source == SOURCE_KERN) level = ASL_LEVEL_NOTICE;
260 
261 	if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0';
262 	snprintf(buf, sizeof(buf), "%d", level);
263 	asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf);
264 
265 	/* check kernel quota if enabled and no processes are watching */
266 	if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0))
267 	{
268 		status = kern_quota_check(now, msg, level);
269 		if (status != VERIFY_STATUS_OK) return status;
270 	}
271 
272 	if (pid != 0)
273 	{
274 		/* set Sender_Mach_UUID */
275 		uuid_clear(pinfo.p_uuid);
276 		if (proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo))
277 		{
278 			uuid_unparse(pinfo.p_uuid, ustr);
279 			asl_msg_set_key_val(msg, ASL_KEY_SENDER_MACH_UUID, ustr);
280 		}
281 	}
282 
283 	tick = 0;
284 	val = asl_msg_get_val_for_key(msg, ASL_KEY_TIME);
285 	if (val != NULL) tick = asl_core_parse_time(val, NULL);
286 
287 	/* Set time to now if it is unset or from the future (not allowed!) */
288 	if ((tick == 0) || (tick > now)) tick = now;
289 
290 	/* Canonical form: seconds since the epoch */
291 	snprintf(buf, sizeof(buf) - 1, "%lu", tick);
292 	asl_msg_set_key_val(msg, ASL_KEY_TIME, buf);
293 
294 	/* Host */
295 	val = asl_msg_get_val_for_key(msg, ASL_KEY_HOST);
296 	if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, whatsmyhostname());
297 
298 	/* UID  & GID */
299 	uid = -2;
300 	val = asl_msg_get_val_for_key(msg, ASL_KEY_UID);
301 	if (val == NULL)
302 	{
303 		asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
304 	}
305 	else
306 	{
307 		uid = atoi(val);
308 		if ((uid == 0) && strcmp(val, "0"))
309 		{
310 			uid = -2;
311 			asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
312 		}
313 	}
314 
315 	if (uid_out != NULL) *uid_out = uid;
316 
317 	gid = -2;
318 	val = asl_msg_get_val_for_key(msg, ASL_KEY_GID);
319 	if (val == NULL)
320 	{
321 		asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
322 	}
323 	else
324 	{
325 		gid = atoi(val);
326 		if ((gid == 0) && strcmp(val, "0"))
327 		{
328 			gid = -2;
329 			asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
330 		}
331 	}
332 
333 	switch (source)
334 	{
335 		case SOURCE_KERN:
336 		case SOURCE_INTERNAL:
337 		{
338 			uid = 0;
339 			asl_msg_set_key_val(msg, ASL_KEY_UID, "0");
340 
341 			gid = 0;
342 			asl_msg_set_key_val(msg, ASL_KEY_GID, "0");
343 
344 			break;
345 		}
346 		case SOURCE_UDP_SOCKET:
347 		case SOURCE_ASL_MESSAGE:
348 		case SOURCE_LAUNCHD:
349 		{
350 			break;
351 		}
352 		default:
353 		{
354 			/* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */
355 			if (uid == 0)
356 			{
357 				uid = -2;
358 				asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
359 			}
360 
361 			if ((gid == 0) || (gid == 80))
362 			{
363 				gid = -2;
364 				asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
365 			}
366 		}
367 	}
368 
369 	/* Sender */
370 	val = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER);
371 	if (val == NULL)
372 	{
373 		switch (source)
374 		{
375 			case SOURCE_KERN:
376 			{
377 				asl_msg_set_key_val(msg, ASL_KEY_SENDER, "kernel");
378 				break;
379 			}
380 			case SOURCE_INTERNAL:
381 			{
382 				asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd");
383 				break;
384 			}
385 			default:
386 			{
387 				asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
388 			}
389 		}
390 	}
391 	else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel")))
392 	{
393 		/* allow UID 0 to send messages with "Sender kernel", but nobody else */
394 		asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown");
395 	}
396 
397 	/* Facility */
398 	fac = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY);
399 	if (fac == NULL)
400 	{
401 		if (source == SOURCE_KERN) fac = "kern";
402 		else fac = "user";
403 		asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac);
404 	}
405 	else if (fac[0] == '#')
406 	{
407 		fnum = LOG_USER;
408 		if ((fac[1] >= '0') && (fac[1] <= '9'))
409 		{
410 			fnum = atoi(fac + 1) << 3;
411 			if ((fnum == 0) && (strcmp(fac + 1, "0"))) fnum = LOG_USER;
412 		}
413 
414 		fac = asl_syslog_faciliy_num_to_name(fnum);
415 		asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac);
416 	}
417 	else if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN))
418 	{
419 		/* only UID 0 may use "com.apple.system" */
420 		if (uid != 0) asl_msg_set_key_val(msg, ASL_KEY_FACILITY, FACILITY_USER);
421 	}
422 
423 	/*
424 	 * kernel messages are only readable by root and admin group.
425 	 * all other messages are admin-only readable unless they already
426 	 * have specific read access controls set.
427 	 */
428 	if (source == SOURCE_KERN)
429 	{
430 		asl_msg_set_key_val(msg, ASL_KEY_READ_UID, "0");
431 		asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80");
432 	}
433 	else
434 	{
435 		ruval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_UID);
436 		rgval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_GID);
437 
438 		if ((ruval == NULL) && (rgval == NULL))
439 		{
440 			asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80");
441 		}
442 	}
443 
444 	/* Set DB Expire Time for com.apple.system.utmpx and lastlog */
445 	if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog")))
446 	{
447 		snprintf(buf, sizeof(buf), "%lu", tick + global.utmp_ttl);
448 		asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
449 	}
450 
451 #if 0
452 	/* Set DB Expire Time for Filesystem errors */
453 	if (!strcmp(fac, FSLOG_VAL_FACILITY))
454 	{
455 		snprintf(buf, sizeof(buf), "%lu", tick + FS_TTL_SEC);
456 		asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf);
457 	}
458 #endif
459 
460 	/*
461 	 * special case handling of kernel disaster messages
462 	 */
463 	if ((source == SOURCE_KERN) && (level <= KERN_DISASTER_LEVEL))
464 	{
465 		if (kern_post_level != NULL) *kern_post_level = level;
466 		disaster_message(msg);
467 	}
468 
469 	return VERIFY_STATUS_OK;
470 }
471 
472 void
list_append_msg(asl_msg_list_t * list,asl_msg_t * msg)473 list_append_msg(asl_msg_list_t *list, asl_msg_t *msg)
474 {
475 	if (list == NULL) return;
476 	if (msg == NULL) return;
477 
478 	/*
479 	 * NB: curr is the list size
480 	 * grow list if necessary
481 	 */
482 	if (list->count == list->curr)
483 	{
484 		if (list->curr == 0)
485 		{
486 			list->msg = (asl_msg_t **)calloc(LIST_SIZE_DELTA, sizeof(asl_msg_t *));
487 		}
488 		else
489 		{
490 			list->msg = (asl_msg_t **)reallocf(list->msg, (list->curr + LIST_SIZE_DELTA) * sizeof(asl_msg_t *));
491 		}
492 
493 		if (list->msg == NULL)
494 		{
495 			list->curr = 0;
496 			list->count = 0;
497 			return;
498 		}
499 
500 		list->curr += LIST_SIZE_DELTA;
501 	}
502 
503 	list->msg[list->count] = (asl_msg_t *)msg;
504 	list->count++;
505 }
506 
507 void
init_globals(void)508 init_globals(void)
509 {
510 	asl_out_rule_t *r;
511 
512 	OSSpinLockLock(&global.lock);
513 
514 	global.pid = getpid();
515 	global.debug = 0;
516 	free(global.debug_file);
517 	global.debug_file = NULL;
518 	global.launchd_enabled = 1;
519 
520 #if TARGET_OS_EMBEDDED
521 	global.dbtype = DB_TYPE_MEMORY;
522 #else
523 	global.dbtype = DB_TYPE_FILE;
524 #endif
525 	global.db_file_max = DEFAULT_DB_FILE_MAX;
526 	global.db_memory_max = DEFAULT_DB_MEMORY_MAX;
527 	global.db_memory_str_max = DEFAULT_DB_MEMORY_STR_MAX;
528 	global.mps_limit = DEFAULT_MPS_LIMIT;
529 	global.remote_delay_time = DEFAULT_REMOTE_DELAY;
530 	global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
531 	global.mark_time = DEFAULT_MARK_SEC;
532 	global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
533 	global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
534 
535 	global.asl_out_module = asl_out_module_init();
536 	OSSpinLockUnlock(&global.lock);
537 
538 	if (global.asl_out_module != NULL)
539 	{
540 		for (r = global.asl_out_module->ruleset; r != NULL; r = r->next)
541 		{
542 			if ((r->action == ACTION_SET_PARAM) && (r->query == NULL) && (!strncmp(r->options, "debug", 5))) control_set_param(r->options, true);
543 		}
544 	}
545 }
546 
547 /*
548  * Used to set config parameters.
549  * Line format "= name value"
550  */
551 int
control_set_param(const char * s,bool eval)552 control_set_param(const char *s, bool eval)
553 {
554 	char **l;
555 	uint32_t intval, count, v32a, v32b, v32c;
556 
557 	if (s == NULL) return -1;
558 	if (s[0] == '\0') return 0;
559 
560 	/* skip '=' and whitespace */
561 	if (*s == '=') s++;
562 	while ((*s == ' ') || (*s == '\t')) s++;
563 
564 	l = explode(s, " \t");
565 	if (l == NULL) return -1;
566 
567 	for (count = 0; l[count] != NULL; count++);
568 
569 	/* name is required */
570 	if (count == 0)
571 	{
572 		free_string_list(l);
573 		return -1;
574 	}
575 
576 	/* Check variables that allow 0 or 1 / boolean */
577 	if (!strcasecmp(l[0], "debug"))
578 	{
579 		/* = debug [0|1] [file] */
580 		if (count == 1)
581 		{
582 			intval = (eval) ? 1 : 0;
583 			config_debug(intval, NULL);
584 		}
585 		else if (!strcmp(l[1], "0"))
586 		{
587 			config_debug(0, l[2]);
588 		}
589 		else if (!strcmp(l[1], "1"))
590 		{
591 			config_debug(1, l[2]);
592 		}
593 		else
594 		{
595 			intval = (eval) ? 1 : 0;
596 			config_debug(intval, l[1]);
597 		}
598 
599 		free_string_list(l);
600 		return 0;
601 	}
602 
603 	/* value is required */
604 	if (count == 1)
605 	{
606 		free_string_list(l);
607 		return -1;
608 	}
609 
610 	if (!strcasecmp(l[0], "mark_time"))
611 	{
612 		/* = mark_time seconds */
613 		OSSpinLockLock(&global.lock);
614 		if (eval) global.mark_time = atoll(l[1]);
615 		else global.mark_time = 0;
616 		OSSpinLockUnlock(&global.lock);
617 	}
618 	else if (!strcasecmp(l[0], "dup_delay"))
619 	{
620 		/* = bsd_max_dup_time seconds */
621 		OSSpinLockLock(&global.lock);
622 		if (eval) global.bsd_max_dup_time = atoll(l[1]);
623 		else global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC;
624 		OSSpinLockUnlock(&global.lock);
625 	}
626 	else if (!strcasecmp(l[0], "remote_delay"))
627 	{
628 		/* = remote_delay microseconds */
629 		OSSpinLockLock(&global.lock);
630 		if (eval) global.remote_delay_time = atol(l[1]);
631 		else global.remote_delay_time = DEFAULT_REMOTE_DELAY;
632 		OSSpinLockUnlock(&global.lock);
633 	}
634 	else if (!strcasecmp(l[0], "utmp_ttl"))
635 	{
636 		/* = utmp_ttl seconds */
637 		OSSpinLockLock(&global.lock);
638 		if (eval) global.utmp_ttl = (time_t)atoll(l[1]);
639 		else global.utmp_ttl = DEFAULT_UTMP_TTL_SEC;
640 		OSSpinLockUnlock(&global.lock);
641 	}
642 	else if (!strcasecmp(l[0], "mps_limit"))
643 	{
644 		/* = mps_limit number */
645 		OSSpinLockLock(&global.lock);
646 		if (eval) global.mps_limit = (uint32_t)atol(l[1]);
647 		else global.mps_limit = DEFAULT_MPS_LIMIT;
648 		OSSpinLockUnlock(&global.lock);
649 	}
650 	else if (!strcasecmp(l[0], "max_work_queue_size"))
651 	{
652 		/* = max_work_queue_size number */
653 		OSSpinLockLock(&global.lock);
654 		if (eval) global.max_work_queue_size = (int64_t)atoll(l[1]);
655 		else global.max_work_queue_size = DEFAULT_WORK_QUEUE_SIZE_MAX;
656 		OSSpinLockUnlock(&global.lock);
657 	}
658 	else if (!strcasecmp(l[0], "max_file_size"))
659 	{
660 		/* = max_file_size bytes */
661 		pthread_mutex_lock(global.db_lock);
662 
663 		if (global.dbtype & DB_TYPE_FILE)
664 		{
665 			asl_store_close(global.file_db);
666 			global.file_db = NULL;
667 			if (eval) global.db_file_max = atoi(l[1]);
668 			else global.db_file_max = DEFAULT_DB_FILE_MAX;
669 		}
670 
671 		pthread_mutex_unlock(global.db_lock);
672 	}
673 	else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore")))
674 	{
675 		/* NB this is private / unpublished */
676 		/* = db type [max]... */
677 		if (eval)
678 		{
679 			v32a = 0;
680 			v32b = 0;
681 			v32c = 0;
682 
683 			if ((l[1][0] >= '0') && (l[1][0] <= '9'))
684 			{
685 				intval = atoi(l[1]);
686 				if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
687 				if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]);
688 				if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]);
689 			}
690 			else if (!strcasecmp(l[1], "file"))
691 			{
692 				intval = DB_TYPE_FILE;
693 				if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]);
694 			}
695 			else if (!strncasecmp(l[1], "mem", 3))
696 			{
697 				intval = DB_TYPE_MEMORY;
698 				if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]);
699 			}
700 			else
701 			{
702 				free_string_list(l);
703 				return -1;
704 			}
705 
706 			if (v32a == 0) v32a = global.db_file_max;
707 			if (v32b == 0) v32b = global.db_memory_max;
708 			if (v32c == 0) v32c = global.db_memory_str_max;
709 
710 			config_data_store(intval, v32a, v32b, v32c);
711 		}
712 		else
713 		{
714 #if TARGET_OS_EMBEDDED
715 			intval = DB_TYPE_MEMORY;
716 #else
717 			intval = DB_TYPE_FILE;
718 #endif
719 			config_data_store(intval, DEFAULT_DB_FILE_MAX, DEFAULT_DB_MEMORY_MAX, DEFAULT_DB_MEMORY_STR_MAX);
720 		}
721 	}
722 
723 	free_string_list(l);
724 	return 0;
725 }
726 
727 static int
control_message(asl_msg_t * msg)728 control_message(asl_msg_t *msg)
729 {
730 	const char *str = asl_msg_get_val_for_key(msg, ASL_KEY_MSG);
731 
732 	if (str == NULL) return 0;
733 
734 	if (!strncmp(str, "= reset", 7))
735 	{
736 		init_globals();
737 		return asl_action_reset();
738 	}
739 	else if (!strncmp(str, "= crash", 7))
740 	{
741 		abort();
742 	}
743 	else if (!strncmp(str, "@ ", 2))
744 	{
745 		return asl_action_control_set_param(str);
746 	}
747 	else if (!strncmp(str, "= ", 2))
748 	{
749 		return control_set_param(str, true);
750 	}
751 
752 	return 0;
753 }
754 
755 void
process_message(asl_msg_t * msg,uint32_t source)756 process_message(asl_msg_t *msg, uint32_t source)
757 {
758 	int64_t msize = 0;
759 	static bool wq_draining = false;
760 	bool is_control = false;
761 	asl_msg_t *x;
762 
763 	if (msg == NULL) return;
764 
765 	is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0;
766 
767 	if ((!is_control) && wq_draining)
768 	{
769 		if (global.work_queue_size >= (global.max_work_queue_size / 2))
770 		{
771 			asldebug("Work queue draining: dropped message.\n");
772 			asl_msg_release(msg);
773 			return;
774 		}
775 		else
776 		{
777 			asldebug("Work queue re-enabled at 1/2 max.  size %llu  max %llu\n", global.work_queue_size, global.max_work_queue_size);
778 			wq_draining = false;
779 		}
780 	}
781 
782 	for (x = msg; x != NULL; x = x->next) msize += x->mem_size;
783 
784 	if ((global.work_queue_size + msize) >= global.max_work_queue_size)
785 	{
786 		char *str = NULL;
787 
788 		wq_draining = true;
789 		asl_msg_release(msg);
790 
791 		asldebug("Work queue disabled.  msize %llu  size %llu  max %llu\n", msize, global.work_queue_size + msize, global.max_work_queue_size);
792 		asprintf(&str, "[Sender syslogd] [Level 2] [PID %u] [Message Internal work queue size limit exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid);
793 		msg = asl_msg_from_string(str);
794 		free(str);
795 	}
796 
797 	OSAtomicAdd64(msize, &global.work_queue_size);
798 	OSAtomicIncrement32(&global.work_queue_count);
799 	dispatch_async(global.work_queue, ^{
800 		int32_t kplevel;
801 		uint32_t status;
802 		uid_t uid;
803 
804 		kplevel = -1;
805 		uid = -2;
806 
807 		status = aslmsg_verify(msg, source, &kplevel, &uid);
808 		if (status == VERIFY_STATUS_OK)
809 		{
810 			if ((source == SOURCE_KERN) && (kplevel >= 0))
811 			{
812 				if (kplevel > 7) kplevel = 7;
813 				if (kern_notify_token[kplevel] < 0)
814 				{
815 					status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel]));
816 					if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status);
817 				}
818 
819 				notify_post(kern_notify_key[kplevel]);
820 			}
821 
822 			if ((uid == 0) && is_control) control_message(msg);
823 
824 			/* send message to output modules */
825 			asl_out_message(msg);
826 #if !TARGET_IPHONE_SIMULATOR
827 			if (global.bsd_out_enabled) bsd_out_message(msg);
828 #endif
829 		}
830 
831 		asl_msg_release(msg);
832 
833 		OSAtomicAdd64(-1ll * msize, &global.work_queue_size);
834 		OSAtomicDecrement32(&global.work_queue_count);
835 	});
836 }
837 
838 int
internal_log_message(const char * str)839 internal_log_message(const char *str)
840 {
841 	asl_msg_t *msg;
842 
843 	if (str == NULL) return 1;
844 
845 	msg = asl_msg_from_string(str);
846 	if (msg == NULL) return 1;
847 
848 	process_message(msg, SOURCE_INTERNAL);
849 
850 	return 0;
851 }
852 
853 void
trigger_aslmanager()854 trigger_aslmanager()
855 {
856 #if 0
857 	dispatch_async(dispatch_get_main_queue(), ^{
858 		if (aslmanager_triggered == 0)
859 		{
860 			aslmanager_triggered = 1;
861 
862 			time_t now = time(0);
863 			if ((now - global.aslmanager_last_trigger) >= ASLMANAGER_DELAY)
864 			{
865 				global.aslmanager_last_trigger = now;
866 			//	asl_trigger_aslmanager();
867 				aslmanager_triggered = 0;
868 			}
869 			else
870 			{
871 				uint64_t delta = ASLMANAGER_DELAY - (now - global.aslmanager_last_trigger);
872 				dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
873 					global.aslmanager_last_trigger = time(0);
874 			// XXX		asl_trigger_aslmanager();
875 					aslmanager_triggered = 0;
876 				});
877 			}
878 		}
879 	});
880 #endif
881 }
882 
883 int
asldebug(const char * str,...)884 asldebug(const char *str, ...)
885 {
886 	va_list v;
887 	FILE *dfp = NULL;
888 
889 	if (global.debug == 0) return 0;
890 
891 	if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a");
892 	else dfp = fopen(global.debug_file, "a");
893 	if (dfp == NULL) return 0;
894 
895 	va_start(v, str);
896 	vfprintf(dfp, str, v);
897 	va_end(v);
898 
899 	fclose(dfp);
900 
901 	return 0;
902 }
903 
904 void
asl_mark(void)905 asl_mark(void)
906 {
907 	char *str = NULL;
908 
909 	asprintf(&str, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global.pid);
910 	internal_log_message(str);
911 	free(str);
912 }
913 
914 asl_msg_t *
asl_syslog_input_convert(const char * in,int len,char * rhost,uint32_t source)915 asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source)
916 {
917 	int pf, pri, index, n;
918 	char *p, *colon, *brace, *space, *tmp, *tval, *hval, *sval, *pval, *mval;
919 	char prival[8];
920 	const char *fval;
921 	asl_msg_t *msg;
922 	struct tm time;
923 	time_t tick;
924 
925 	if (in == NULL) return NULL;
926 	if (len <= 0) return NULL;
927 
928 	pri = LOG_DEBUG;
929 	if (source == SOURCE_KERN) pri = LOG_NOTICE;
930 
931 	tval = NULL;
932 	hval = NULL;
933 	sval = NULL;
934 	pval = NULL;
935 	mval = NULL;
936 	fval = NULL;
937 
938 	index = 0;
939 	p = (char *)in;
940 
941 	/* skip leading whitespace */
942 	while ((index < len) && ((*p == ' ') || (*p == '\t')))
943 	{
944 		p++;
945 		index++;
946 	}
947 
948 	if (index >= len) return NULL;
949 
950 	/* parse "<NN>" priority (level and facility) */
951 	if (*p == '<')
952 	{
953 		p++;
954 		index++;
955 
956 		n = sscanf(p, "%d", &pf);
957 		if (n == 1)
958 		{
959 			pri = pf & 0x7;
960 			if (pf > 0x7) fval = asl_syslog_faciliy_num_to_name(pf & LOG_FACMASK);
961 		}
962 
963 		while ((index < len) && (*p != '>'))
964 		{
965 			p++;
966 			index++;
967 		}
968 
969 		if (index < len)
970 		{
971 			p++;
972 			index++;
973 		}
974 	}
975 
976 	snprintf(prival, sizeof(prival), "%d", pri);
977 
978 	/* check if a timestamp is included */
979 	if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' '))
980 	{
981 		tmp = malloc(16);
982 		if (tmp == NULL) return NULL;
983 
984 		memcpy(tmp, p, 15);
985 		tmp[15] = '\0';
986 
987 		tick = asl_core_parse_time(tmp, NULL);
988 		if (tick == (time_t)-1)
989 		{
990 			tval = tmp;
991 		}
992 		else
993 		{
994 			free(tmp);
995 			gmtime_r(&tick, &time);
996 			asprintf(&tval, "%d.%02d.%02d %02d:%02d:%02d UTC", time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
997 		}
998 
999 		p += 16;
1000 		index += 16;
1001 	}
1002 
1003 	/* stop here for kernel messages */
1004 	if (source == SOURCE_KERN)
1005 	{
1006 		msg = asl_msg_new(ASL_TYPE_MSG);
1007 		if (msg == NULL) return NULL;
1008 
1009 		asl_msg_set_key_val(msg, ASL_KEY_MSG, p);
1010 		asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival);
1011 		asl_msg_set_key_val(msg, ASL_KEY_PID, "0");
1012 
1013 		return msg;
1014 	}
1015 
1016 	/* if message is from a network socket, hostname follows */
1017 	if (source == SOURCE_UDP_SOCKET)
1018 	{
1019 		space = strchr(p, ' ');
1020 		if (space != NULL)
1021 		{
1022 			n = space - p;
1023 			hval = malloc(n + 1);
1024 			if (hval == NULL) return NULL;
1025 
1026 			memcpy(hval, p, n);
1027 			hval[n] = '\0';
1028 
1029 			p = space + 1;
1030 			index += (n + 1);
1031 		}
1032 	}
1033 
1034 	colon = strchr(p, ':');
1035 	brace = strchr(p, '[');
1036 
1037 	/* check for "sender:" or sender[pid]:"  */
1038 	if (colon != NULL)
1039 	{
1040 		if ((brace != NULL) && (brace < colon))
1041 		{
1042 			n = brace - p;
1043 			sval = malloc(n + 1);
1044 			if (sval == NULL) return NULL;
1045 
1046 			memcpy(sval, p, n);
1047 			sval[n] = '\0';
1048 
1049 			n = colon - (brace + 1) - 1;
1050 			pval = malloc(n + 1);
1051 			if (pval == NULL) return NULL;
1052 
1053 			memcpy(pval, (brace + 1), n);
1054 			pval[n] = '\0';
1055 		}
1056 		else
1057 		{
1058 			n = colon - p;
1059 			sval = malloc(n + 1);
1060 			if (sval == NULL) return NULL;
1061 
1062 			memcpy(sval, p, n);
1063 			sval[n] = '\0';
1064 		}
1065 
1066 		n = colon - p;
1067 		p = colon + 1;
1068 		index += (n + 1);
1069 	}
1070 
1071 	if (*p == ' ')
1072 	{
1073 		p++;
1074 		index++;
1075 	}
1076 
1077 	n = len - index;
1078 	if (n > 0)
1079 	{
1080 		mval = malloc(n + 1);
1081 		if (mval == NULL) return NULL;
1082 
1083 		memcpy(mval, p, n);
1084 		mval[n] = '\0';
1085 	}
1086 
1087 	if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER);
1088 
1089 	msg = asl_msg_new(ASL_TYPE_MSG);
1090 	if (msg == NULL) return NULL;
1091 
1092 	if (tval != NULL)
1093 	{
1094 		asl_msg_set_key_val(msg, ASL_KEY_TIME, tval);
1095 		free(tval);
1096 	}
1097 
1098 	if (fval != NULL) asl_msg_set_key_val(msg, "Facility", fval);
1099 	else asl_msg_set_key_val(msg, "Facility", "user");
1100 
1101 	if (sval != NULL)
1102 	{
1103 		asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval);
1104 		free(sval);
1105 	}
1106 
1107 	if (pval != NULL)
1108 	{
1109 		asl_msg_set_key_val(msg, ASL_KEY_PID, pval);
1110 		free(pval);
1111 	}
1112 	else
1113 	{
1114 		asl_msg_set_key_val(msg, ASL_KEY_PID, "-1");
1115 	}
1116 
1117 	if (mval != NULL)
1118 	{
1119 		asl_msg_set_key_val(msg, ASL_KEY_MSG, mval);
1120 		free(mval);
1121 	}
1122 
1123 	asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival);
1124 	asl_msg_set_key_val(msg, ASL_KEY_UID, "-2");
1125 	asl_msg_set_key_val(msg, ASL_KEY_GID, "-2");
1126 
1127 	if (hval != NULL)
1128 	{
1129 		asl_msg_set_key_val(msg, ASL_KEY_HOST, hval);
1130 		free(hval);
1131 	}
1132 	else if (rhost != NULL)
1133 	{
1134 		asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost);
1135 	}
1136 
1137 	return msg;
1138 }
1139 
1140 asl_msg_t *
asl_input_parse(const char * in,int len,char * rhost,uint32_t source)1141 asl_input_parse(const char *in, int len, char *rhost, uint32_t source)
1142 {
1143 	asl_msg_t *msg;
1144 	int status, x, legacy, off;
1145 
1146 	asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in);
1147 
1148 	if (in == NULL) return NULL;
1149 
1150 	legacy = 1;
1151 	msg = NULL;
1152 
1153 	/* calculate length if not provided */
1154 	if (len == 0) len = strlen(in);
1155 
1156 	/*
1157 	 * Determine if the input is "old" syslog format or new ASL format.
1158 	 * Old format lines should start with "<", but they can just be straight text.
1159 	 * ASL input may start with a length (10 bytes) followed by a space and a '['.
1160 	 * The length is optional, so ASL messages may also just start with '['.
1161 	 */
1162 	if ((in[0] != '<') && (len > 11))
1163 	{
1164 		status = sscanf(in, "%d ", &x);
1165 		if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0;
1166 	}
1167 
1168 	if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source);
1169 
1170 	off = 11;
1171 	if (in[0] == '[') off = 0;
1172 
1173 	msg = asl_msg_from_string(in + off);
1174 	if (msg == NULL) return NULL;
1175 
1176 	if (rhost != NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost);
1177 
1178 	return msg;
1179 }
1180 
1181 #if !TARGET_IPHONE_SIMULATOR
1182 void
launchd_callback(struct timeval * when,pid_t from_pid,pid_t about_pid,uid_t sender_uid,gid_t sender_gid,int priority,const char * from_name,const char * about_name,const char * session_name,const char * msg)1183 launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, const char *from_name, const char *about_name, const char *session_name, const char *msg)
1184 {
1185 	asl_msg_t *m;
1186 	char str[256];
1187 	time_t now;
1188 
1189 	if (global.launchd_enabled == 0) return;
1190 
1191 /*
1192 	asldebug("launchd_callback Time %lu %lu PID %u RefPID %u UID %d GID %d PRI %d Sender %s Ref %s Session %s Message %s\n",
1193 	when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg);
1194 */
1195 
1196 	m = asl_msg_new(ASL_TYPE_MSG);
1197 	if (m == NULL) return;
1198 
1199 	/* Level */
1200 	if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG;
1201 	if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG;
1202 	snprintf(str, sizeof(str), "%d", priority);
1203 
1204 	asl_msg_set_key_val(m, ASL_KEY_LEVEL, str);
1205 
1206 	/* Time */
1207 	if (when != NULL)
1208 	{
1209 		snprintf(str, sizeof(str), "%lu", when->tv_sec);
1210 		asl_msg_set_key_val(m, ASL_KEY_TIME, str);
1211 
1212 		snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec);
1213 		asl_msg_set_key_val(m, ASL_KEY_TIME_NSEC, str);
1214 	}
1215 	else
1216 	{
1217 		now = time(NULL);
1218 		snprintf(str, sizeof(str), "%lu", now);
1219 		asl_msg_set_key_val(m, ASL_KEY_TIME, str);
1220 	}
1221 
1222 	/* Facility */
1223 	asl_msg_set_key_val(m, ASL_KEY_FACILITY, FACILITY_CONSOLE);
1224 
1225 	/* UID */
1226 	snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid);
1227 	asl_msg_set_key_val(m, ASL_KEY_UID, str);
1228 
1229 	/* GID */
1230 	snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid);
1231 	asl_msg_set_key_val(m, ASL_KEY_GID, str);
1232 
1233 	/* PID */
1234 	if (from_pid != 0)
1235 	{
1236 		snprintf(str, sizeof(str), "%u", (unsigned int)from_pid);
1237 		asl_msg_set_key_val(m, ASL_KEY_PID, str);
1238 	}
1239 
1240 	/* Reference PID */
1241 	if ((about_pid > 0) && (about_pid != from_pid))
1242 	{
1243 		snprintf(str, sizeof(str), "%u", (unsigned int)about_pid);
1244 		asl_msg_set_key_val(m, ASL_KEY_REF_PID, str);
1245 	}
1246 
1247 	/* Sender */
1248 	if (from_name != NULL)
1249 	{
1250 		asl_msg_set_key_val(m, ASL_KEY_SENDER, from_name);
1251 	}
1252 
1253 	/* ReadUID */
1254 	if (sender_uid != 0)
1255 	{
1256 		snprintf(str, sizeof(str), "%d", (int)sender_uid);
1257 		asl_msg_set_key_val(m, ASL_KEY_READ_UID, str);
1258 	}
1259 
1260 	/* Reference Process */
1261 	if (about_name != NULL)
1262 	{
1263 		if ((from_name != NULL) && (strcmp(from_name, about_name) != 0))
1264 		{
1265 			asl_msg_set_key_val(m, ASL_KEY_REF_PROC, about_name);
1266 		}
1267 	}
1268 
1269 	/* Session */
1270 	if (session_name != NULL)
1271 	{
1272 		asl_msg_set_key_val(m, ASL_KEY_SESSION, session_name);
1273 	}
1274 
1275 	/* Message */
1276 	if (msg != NULL)
1277 	{
1278 		asl_msg_set_key_val(m, ASL_KEY_MSG, msg);
1279 	}
1280 
1281 	process_message(m, SOURCE_LAUNCHD);
1282 }
1283 
1284 #endif
1285