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