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