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