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