X-Git-Url: https://git.saurik.com/apple/syslog.git/blobdiff_plain/02b408bf291fdcb65e851a9c1a558913dcc66184..30cde84f1eb4f8e4638b3c120d12001b121882b9:/syslogd.tproj/daemon.c?ds=sidebyside diff --git a/syslogd.tproj/daemon.c b/syslogd.tproj/daemon.c index f519a17..746cd42 100644 --- a/syslogd.tproj/daemon.c +++ b/syslogd.tproj/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,6 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ +#include #include #include #include @@ -29,458 +30,1034 @@ #include #include #include -#include #include #include #define SYSLOG_NAMES #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "daemon.h" -#define streq(A,B) (strcmp(A,B)==0) +#define LIST_SIZE_DELTA 256 +#define STATS_TABLE_SIZE 256 + +#define forever for(;;) + +#define ASL_MSG_TYPE_MASK 0x0000000f +#define ASL_TYPE_ERROR 2 + +#define ASL_KEY_FACILITY "Facility" + +#define FACILITY_USER "user" +#define FACILITY_CONSOLE "com.apple.console" +#define SYSTEM_RESERVED "com.apple.system" +#define SYSTEM_RESERVED_LEN 16 + +#define VERIFY_STATUS_OK 0 +#define VERIFY_STATUS_INVALID_MESSAGE 1 +#define VERIFY_STATUS_EXCEEDED_QUOTA 2 + +extern void disaster_message(asl_msg_t *m); +extern int asl_action_reset(void); +extern int asl_action_control_set_param(const char *s); static char myname[MAXHOSTNAMELEN + 1] = {0}; -static int gotname = 0; +static int name_change_token = -1; -struct aslevent -{ - int fd; - unsigned char read:1; - unsigned char write:1; - unsigned char except:1; - aslreadfn readfn; - aslwritefn writefn; - aslexceptfn exceptfn; - char *sender; - uid_t uid; - gid_t gid; - TAILQ_ENTRY(aslevent) entries; -}; +static OSSpinLock count_lock = 0; -struct asloutput -{ - aslsendmsgfn sendmsg; - const char *outid; - TAILQ_ENTRY(asloutput) entries; -}; +#if !TARGET_OS_EMBEDDED +static vproc_transaction_t vproc_trans = {0}; +#endif -struct aslmatch +#define DEFAULT_MEMORY_MAX SYSLOGD_WORK_QUEUE_MEMORY + +#define QUOTA_KERN_EXCEEDED_MESSAGE "*** kernel exceeded %d log message per second limit - remaining messages this second discarded ***" + +#define DEFAULT_DB_FILE_MAX 25600000 +#define DEFAULT_DB_MEMORY_MAX 256 +#define DEFAULT_DB_MEMORY_STR_MAX 1024000 +#define DEFAULT_MPS_LIMIT 500 +#define DEFAULT_REMOTE_DELAY 5000 +#define DEFAULT_BSD_MAX_DUP_SEC 30 +#define DEFAULT_MARK_SEC 0 +#define DEFAULT_UTMP_TTL_SEC 31622400 +#define DEFAULT_STATS_INTERVAL 600 + +#define ASL_STATS_LEVEL 5 + +static time_t quota_time = 0; +static int32_t kern_quota; +static int32_t kern_level; + +static const char *kern_notify_key[] = { - char *outid; - asl_msg_t *query; - TAILQ_ENTRY(aslmatch) entries; + "com.apple.system.log.kernel.emergency", + "com.apple.system.log.kernel.alert", + "com.apple.system.log.kernel.critical", + "com.apple.system.log.kernel.error", + "com.apple.system.log.kernel.warning", + "com.apple.system.log.kernel.notice", + "com.apple.system.log.kernel.info", + "com.apple.system.log.kernel.debug" }; -TAILQ_HEAD(ae, aslevent) Eventq; -TAILQ_HEAD(ao, asloutput) Outq; -TAILQ_HEAD(am, aslmatch) Matchq; +static int kern_notify_token[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; -int -aslevent_init(void) +static stats_table_t * +stats_table_new() { - TAILQ_INIT(&Eventq); - TAILQ_INIT(&Outq); - TAILQ_INIT(&Matchq); + stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t)); + if (t == NULL) return NULL; - return 0; + t->bucket_count = STATS_TABLE_SIZE; + t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *)); + if (t->bucket == NULL) + { + free(t); + return NULL; + } + + t->mcount = 0; + t->shim_count = 0; + + return t; } -int -aslevent_log(asl_msg_t *msg, char *outid) +static asl_msg_t * +stats_table_final(stats_table_t *t) { - struct asloutput *i; - int status = -1; - - for (i = Outq.tqh_first; i != NULL; i = i->entries.tqe_next) + uint32_t i; + asl_msg_t *msg; + char val[64]; + + if (t == NULL) return NULL; + + msg = asl_msg_new(ASL_TYPE_MSG); + if (msg == NULL) return NULL; + + asl_msg_set_key_val(msg, ASL_KEY_MSG, "ASL Sender Statistics"); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "syslogd"); + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, "com.apple.asl.statistics"); + snprintf(val, sizeof(val), "%d", global.pid); + asl_msg_set_key_val(msg, ASL_KEY_PID, val); + snprintf(val, sizeof(val), "%d", ASL_STATS_LEVEL); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, val); + snprintf(val, sizeof(val), "%u", t->mcount); + asl_msg_set_key_val(msg, "MsgCount", val); + snprintf(val, sizeof(val), "%u", t->shim_count); + asl_msg_set_key_val(msg, "ShimCount", val); + + for (i = 0; i < t->bucket_count; i++) { - if ((outid != NULL) && (strcmp(i->outid, outid) == 0)) + sender_stats_t *s; + s = t->bucket[i]; + while (s != NULL) { - status = i->sendmsg(msg, outid); + char val[64], *key = NULL; + sender_stats_t *n = s->next; + + snprintf(val, sizeof(val), "%llu %llu", s->count, s->size); + asprintf(&key, "*%s", s->sender); + if (key != NULL) asl_msg_set_key_val(msg, key, val); + free(key); + free(s->sender); + free(s); + s = n; } } - return status; + free(t->bucket); + free(t); + + return msg; } -int -aslevent_addmatch(asl_msg_t *query, char *outid) +static void +stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size) { - struct aslmatch *tmp; + uint32_t i; + sender_stats_t *s; + uint8_t *p; - if (query == NULL) return -1; - if (outid == NULL) return -1; + if (t == NULL) return; + if (sender == NULL) return; - tmp = calloc(1, sizeof(struct aslmatch)); - if (tmp == NULL) return -1; - tmp->query = query; - tmp->outid = outid; - TAILQ_INSERT_TAIL(&Matchq, tmp, entries); + /* hash */ + i = 0; + for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p); + i %= STATS_TABLE_SIZE; - return 0; + for (s = t->bucket[i]; s != NULL; s = s->next) + { + if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0)) + { + s->count++; + s->size += msg_size; + return; + } + } + + s = (sender_stats_t *)malloc(sizeof(sender_stats_t)); + s->sender = strdup(sender); + if (s->sender == NULL) + { + free(s); + return; + } + + s->count = 1; + s->size = msg_size; + s->next = t->bucket[i]; + t->bucket[i] = s; } -void -aslevent_match(asl_msg_t *msg) +static uint32_t +kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level) { - struct aslmatch *i; + char *str, lstr[2]; - if (msg == NULL) return; + if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE; + if (global.mps_limit == 0) return VERIFY_STATUS_OK; - for (i = Matchq.tqh_first; i != NULL; i = i->entries.tqe_next) + if (quota_time != now) { - if (asl_msg_cmp(i->query, msg) != 0) - { - aslevent_log(msg, i->outid); - } + kern_quota = global.mps_limit; + kern_level = 7; + quota_time = now; + } + + if (level < kern_level) kern_level = level; + if (kern_quota > 0) kern_quota--; + + if (kern_quota > 0) return VERIFY_STATUS_OK; + if (kern_quota < 0) return VERIFY_STATUS_EXCEEDED_QUOTA; + + kern_quota = -1; + + str = NULL; + asprintf(&str, QUOTA_KERN_EXCEEDED_MESSAGE, global.mps_limit); + if (str != NULL) + { + asl_msg_set_key_val(msg, ASL_KEY_MSG, str); + free(str); + lstr[0] = kern_level + '0'; + lstr[1] = 0; + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, lstr); } + + return VERIFY_STATUS_OK; } -int -aslevent_removefd(int fd) +static void +stats_msg(const char *sender, time_t now, asl_msg_t *msg) { - struct aslevent *i; - int found = -1; + asl_msg_t *x; + uint64_t msize = 0; - for (i = Eventq.tqh_first; i != NULL; i = i->entries.tqe_next) + /* flush stats after N seconds */ + if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL)) { - if (fd == i->fd) - { - asldebug("removing %d\n", i->fd); - TAILQ_REMOVE(&Eventq, i, entries); - found = 0; - if (i->sender != NULL) free(i->sender); - free(i); - i = NULL; - return 0; - } + asl_msg_t *msg = stats_table_final(global.stats); + process_message(msg, SOURCE_INTERNAL); + global.stats = NULL; + global.stats_last = now; } - return -1; + if (global.stats == NULL) global.stats = stats_table_new(); + + for (x = msg; x != NULL; x = x->next) msize += x->mem_size; + + const char *shim_vers = asl_msg_get_val_for_key(msg, "ASLSHIM"); + global.stats->mcount++; + if (shim_vers != NULL) global.stats->shim_count++; + + /* update count and total size - total and for this sender */ + stats_table_update(global.stats, "*", msize); + stats_table_update(global.stats, sender, msize); } -const char * +static const char * whatsmyhostname() { - char *dot; + static dispatch_once_t once; + int check, status; + + if (global.hostname != NULL) return global.hostname; + + dispatch_once(&once, ^{ + snprintf(myname, sizeof(myname), "%s", "localhost"); + notify_register_check(kNotifySCHostNameChange, &name_change_token); + }); - if (gotname != 0) return (const char *)myname; + check = 1; + status = 0; + + if (name_change_token >= 0) status = notify_check(name_change_token, &check); + + if ((status == 0) && (check == 0)) return (const char *)myname; if (gethostname(myname, MAXHOSTNAMELEN) < 0) { - memset(myname, 0, sizeof(myname)); - return "localhost"; + snprintf(myname, sizeof(myname), "%s", "localhost"); + } + else + { + char *dot; + dot = strchr(myname, '.'); + if (dot != NULL) *dot = '\0'; } - if (strcmp(myname, "localhost")) gotname = 1; + return (const char *)myname; +} - dot = strchr(myname, '.'); - if (dot != NULL) *dot = '\0'; +void +asl_client_count_increment() +{ + OSSpinLockLock(&count_lock); - return (const char *)myname; +#if !TARGET_OS_EMBEDDED + if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL); +#endif + global.client_count++; + + OSSpinLockUnlock(&count_lock); } -int -aslevent_addfd(int fd, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn) +void +asl_client_count_decrement() { - struct aslevent *e; - int found = 0; -#ifdef LOCAL_PEERCRED - struct xucred cr; + OSSpinLockLock(&count_lock); + + if (global.client_count > 0) global.client_count--; +#if !TARGET_OS_EMBEDDED + if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans); #endif - int len; - uid_t u; - gid_t g; - struct sockaddr_storage ss; - char *sender, str[256]; - u = 99; - g = 99; - sender = NULL; + OSSpinLockUnlock(&count_lock); +} + +/* + * Checks message content and sets attributes as required + * + * SOURCE_INTERNAL log messages sent by syslogd itself + * SOURCE_ASL_SOCKET legacy asl(3) TCP socket + * SOURCE_BSD_SOCKET legacy syslog(3) UDP socket + * SOURCE_UDP_SOCKET from the network + * SOURCE_KERN from the kernel + * SOURCE_ASL_MESSAGE mach messages sent from Libc by asl(3) and syslog(3) + * SOURCE_LAUNCHD forwarded from launchd + */ - memset(&ss, 0, sizeof(struct sockaddr_storage)); +static uint32_t +aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out) +{ + const char *val, *fac, *ruval, *rgval, *sval = NULL; + char buf[64]; + time_t tick, now; + uid_t uid; + gid_t gid; + uint32_t status, level, fnum; + pid_t pid; + uuid_string_t ustr; + struct proc_uniqidentifierinfo pinfo; + + if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE; + + /* Time */ + now = time(NULL); + + if (kern_post_level != NULL) *kern_post_level = -1; + if (uid_out != NULL) *uid_out = -2; + + /* PID */ + pid = 0; - len = sizeof(struct sockaddr_storage); + val = asl_msg_get_val_for_key(msg, ASL_KEY_PID); + if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_PID, "0"); + else pid = (pid_t)atoi(val); - if (getpeername(fd, (struct sockaddr *)&ss, &len) == 0) + /* if PID is 1 (launchd), use the RefPID and RefProc provided */ + if (pid == 1) { - if (len == 0) + val = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PID); + if (val != NULL) pid = (pid_t)atoi(val); + + sval = asl_msg_get_val_for_key(msg, ASL_KEY_REF_PROC); + } + + /* Level */ + val = asl_msg_get_val_for_key(msg, ASL_KEY_LEVEL); + level = ASL_LEVEL_DEBUG; + if (source == SOURCE_KERN) level = ASL_LEVEL_NOTICE; + + if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0'; + snprintf(buf, sizeof(buf), "%d", level); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, buf); + + + /* check kernel quota if enabled and no processes are watching */ + if ((pid == 0) && (global.mps_limit > 0) && (global.watchers_active == 0)) + { + status = kern_quota_check(now, msg, level); + if (status != VERIFY_STATUS_OK) return status; + } + + if (pid != 0) + { + /* set Sender_Mach_UUID */ + uuid_clear(pinfo.p_uuid); + if (proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo)) { - /* UNIX Domain socket */ - snprintf(str, sizeof(str), whatsmyhostname()); - sender = str; + uuid_unparse(pinfo.p_uuid, ustr); + asl_msg_set_key_val(msg, ASL_KEY_SENDER_MACH_UUID, ustr); } - else + } + + tick = 0; + val = asl_msg_get_val_for_key(msg, ASL_KEY_TIME); + if (val != NULL) tick = asl_core_parse_time(val, NULL); + + /* Set time to now if it is unset or from the future (not allowed!) */ + if ((tick == 0) || (tick > now)) tick = now; + + /* Canonical form: seconds since the epoch */ + snprintf(buf, sizeof(buf) - 1, "%llu", (unsigned long long) tick); + asl_msg_set_key_val(msg, ASL_KEY_TIME, buf); + + /* Host */ + val = asl_msg_get_val_for_key(msg, ASL_KEY_HOST); + if (val == NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, whatsmyhostname()); + + /* UID & GID */ + uid = -2; + val = asl_msg_get_val_for_key(msg, ASL_KEY_UID); + if (val == NULL) + { + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); + } + else + { + uid = atoi(val); + if ((uid == 0) && strcmp(val, "0")) { - if (inet_ntop(ss.ss_family, (struct sockaddr *)&ss, str, 256) == 0) sender = str; + uid = -2; + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); } } -#ifdef LOCAL_PEERCRED - len = sizeof(cr); + gid = -2; + val = asl_msg_get_val_for_key(msg, ASL_KEY_GID); + if (val == NULL) + { + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); + } + else + { + gid = atoi(val); + if ((gid == 0) && strcmp(val, "0")) + { + gid = -2; + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); + } + } - if (getsockopt(fd, LOCAL_PEERCRED, 1, &cr, &len) == 0) + switch (source) { - u = cr.cr_uid; - g = cr.cr_gid; + case SOURCE_KERN: + case SOURCE_INTERNAL: + { + uid = 0; + asl_msg_set_key_val(msg, ASL_KEY_UID, "0"); + + gid = 0; + asl_msg_set_key_val(msg, ASL_KEY_GID, "0"); + + break; + } + case SOURCE_ASL_MESSAGE: + case SOURCE_LAUNCHD: + { + break; + } + default: + { + /* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */ + if (uid == 0) + { + uid = -2; + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); + } + + if ((gid == 0) || (gid == 80)) + { + gid = -2; + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); + } + } } -#endif - asldebug("fd %d UID %d GID %d Sender %s\n", fd, u, g, (sender == NULL) ? "NULL" : sender ); + if (uid_out != NULL) *uid_out = uid; - for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next) + /* Sender */ + if (sval == NULL) sval = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER); + if (sval == NULL) { - if (fd == e->fd) + switch (source) { - e->readfn = readfn; - e->writefn = writefn; - e->exceptfn = exceptfn; - if (e->sender != NULL) free(e->sender); - e->sender = NULL; - if (sender != NULL) e->sender = strdup(sender); - e->uid = u; - e->gid = g; - found = 1; + case SOURCE_KERN: + { + sval = "kernel"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); + break; + } + case SOURCE_INTERNAL: + { + sval = "syslogd"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); + break; + } + default: + { + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown"); + } } } + else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(sval, "kernel"))) + { + /* allow UID 0 to send messages with "Sender kernel", but nobody else */ + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown"); + sval = NULL; + } - if (found) return 0; + /* Facility */ + fac = asl_msg_get_val_for_key(msg, ASL_KEY_FACILITY); + if (fac == NULL) + { + if (source == SOURCE_KERN) fac = "kern"; + else fac = "user"; + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac); + } + else if (fac[0] == '#') + { + fnum = LOG_USER; + if ((fac[1] >= '0') && (fac[1] <= '9')) + { + fnum = atoi(fac + 1) << 3; + if ((fnum == 0) && (strcmp(fac + 1, "0"))) fnum = LOG_USER; + } - e = calloc(1, sizeof(struct aslevent)); - if (e == NULL) return -1; + fac = asl_syslog_faciliy_num_to_name(fnum); + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac); + } + else if (!strncmp(fac, SYSTEM_RESERVED, SYSTEM_RESERVED_LEN)) + { + /* only UID 0 may use "com.apple.system" */ + if (uid != 0) asl_msg_set_key_val(msg, ASL_KEY_FACILITY, FACILITY_USER); + } - e->fd = fd; - e->readfn = readfn; - e->writefn = writefn; - e->exceptfn = exceptfn; - e->sender = NULL; - if (sender != NULL) e->sender = strdup(sender); - e->uid = u; - e->gid = g; + /* + * kernel messages are only readable by root and admin group. + * all other messages are admin-only readable unless they already + * have specific read access controls set. + */ + if (source == SOURCE_KERN) + { + asl_msg_set_key_val(msg, ASL_KEY_READ_UID, "0"); + asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80"); + } + else + { + ruval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_UID); + rgval = asl_msg_get_val_for_key(msg, ASL_KEY_READ_GID); - TAILQ_INSERT_TAIL(&Eventq, e, entries); + if ((ruval == NULL) && (rgval == NULL)) + { + asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80"); + } + } - return 0; + /* Set DB Expire Time for com.apple.system.utmpx and lastlog */ + if ((!strcmp(fac, "com.apple.system.utmpx")) || (!strcmp(fac, "com.apple.system.lastlog"))) + { + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl); + asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf); + } + + /* + * special case handling of kernel disaster messages + */ + if ((source == SOURCE_KERN) && (level <= KERN_DISASTER_LEVEL)) + { + if (kern_post_level != NULL) *kern_post_level = level; + disaster_message(msg); + } + + /* + * gather sender stats + */ + if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg); + + return VERIFY_STATUS_OK; } -int -aslmsg_verify(struct aslevent *e, asl_msg_t *msg) +void +list_append_msg(asl_msg_list_t *list, asl_msg_t *msg) { - const char *val; - char buf[32], *timestr; - time_t tick; - struct tm gtime; + if (list == NULL) return; + if (msg == NULL) return; - if (msg == NULL) return -1; + /* + * NB: curr is the list size + * grow list if necessary + */ + if (list->count == list->curr) + { + if (list->curr == 0) + { + list->msg = (asl_msg_t **)calloc(LIST_SIZE_DELTA, sizeof(asl_msg_t *)); + } + else + { + list->msg = (asl_msg_t **)reallocf(list->msg, (list->curr + LIST_SIZE_DELTA) * sizeof(asl_msg_t *)); + } - /* Time */ - tick = 0; - val = asl_get(msg, ASL_KEY_TIME); - if (val != NULL) tick = asl_parse_time(val); + if (list->msg == NULL) + { + list->curr = 0; + list->count = 0; + return; + } + + list->curr += LIST_SIZE_DELTA; + } + + list->msg[list->count] = (asl_msg_t *)msg; + list->count++; +} + +void +init_globals(void) +{ + asl_out_rule_t *r; + + OSSpinLockLock(&global.lock); - if (tick == 0) tick = time(NULL); - memset(>ime, 0, sizeof(struct tm)); - gmtime_r(&tick, >ime); + global.pid = getpid(); + global.debug = 0; + free(global.debug_file); + global.debug_file = NULL; + global.launchd_enabled = 1; - /* Canonical form: YYYY.MM.DD hh:mm:ss UTC */ - asprintf(×tr, "%d.%02d.%02d %02d:%02d:%02d UTC", gtime.tm_year + 1900, gtime.tm_mon + 1, gtime.tm_mday, gtime.tm_hour, gtime.tm_min, gtime.tm_sec); - if (timestr != NULL) +#if TARGET_OS_EMBEDDED + global.dbtype = DB_TYPE_MEMORY; +#else + global.dbtype = DB_TYPE_FILE; +#endif + global.db_file_max = DEFAULT_DB_FILE_MAX; + global.db_memory_max = DEFAULT_DB_MEMORY_MAX; + global.db_memory_str_max = DEFAULT_DB_MEMORY_STR_MAX; + global.mps_limit = DEFAULT_MPS_LIMIT; + global.remote_delay_time = DEFAULT_REMOTE_DELAY; + global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; + global.mark_time = DEFAULT_MARK_SEC; + global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; + global.memory_max = DEFAULT_MEMORY_MAX; + global.stats_interval = DEFAULT_STATS_INTERVAL; + + global.asl_out_module = asl_out_module_init(); + OSSpinLockUnlock(&global.lock); + + if (global.asl_out_module != NULL) { - asl_set(msg, ASL_KEY_TIME, timestr); - free(timestr); + for (r = global.asl_out_module->ruleset; r != NULL; r = r->next) + { + if ((r->action == ACTION_SET_PARAM) && (r->query == NULL) && (!strncmp(r->options, "debug", 5))) control_set_param(r->options, true); + } } +} - /* Host */ - if (e == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); - else if (e->sender != NULL) asl_set(msg, ASL_KEY_HOST, e->sender); +/* + * Used to set config parameters. + * Line format "= name value" + */ +int +control_set_param(const char *s, bool eval) +{ + char **l; + uint32_t intval, count, v32a, v32b, v32c; - /* Sender */ - val = asl_get(msg, ASL_KEY_SENDER); - if (val == NULL) asl_set(msg, ASL_KEY_SENDER, "Unknown"); + if (s == NULL) return -1; + if (s[0] == '\0') return 0; - /* PID */ - val = asl_get(msg, ASL_KEY_PID); - if (val == NULL) asl_set(msg, ASL_KEY_PID, "0"); + /* skip '=' and whitespace */ + if (*s == '=') s++; + while ((*s == ' ') || (*s == '\t')) s++; - /* UID */ - val = asl_get(msg, ASL_KEY_UID); - if (val == NULL) + l = explode(s, " \t"); + if (l == NULL) return -1; + + for (count = 0; l[count] != NULL; count++); + + /* name is required */ + if (count == 0) { - if (e == NULL) asl_set(msg, ASL_KEY_UID, "-2"); - else if (e->uid == 99) asl_set(msg, ASL_KEY_UID, "-2"); + free_string_list(l); + return -1; + } + + /* Check variables that allow 0 or 1 / boolean */ + if (!strcasecmp(l[0], "debug")) + { + /* = debug [0|1] [file] */ + if (count == 1) + { + intval = (eval) ? 1 : 0; + config_debug(intval, NULL); + } + else if (!strcmp(l[1], "0")) + { + config_debug(0, l[2]); + } + else if (!strcmp(l[1], "1")) + { + config_debug(1, l[2]); + } else { - snprintf(buf, sizeof(buf), "%d", e->uid); - asl_set(msg, ASL_KEY_UID, buf); + intval = (eval) ? 1 : 0; + config_debug(intval, l[1]); } + + free_string_list(l); + return 0; } - else if ((e != NULL) && (e->uid != 99)) + + /* value is required */ + if (count == 1) { - snprintf(buf, sizeof(buf), "%d", e->uid); - asl_set(msg, ASL_KEY_UID, buf); + free_string_list(l); + return -1; } - /* GID */ - val = asl_get(msg, ASL_KEY_GID); - if (val == NULL) + if (!strcasecmp(l[0], "hostname")) { - if (e == NULL) asl_set(msg, ASL_KEY_GID, "-2"); - else if (e->gid == 99) asl_set(msg, ASL_KEY_GID, "-2"); + /* = hostname name */ + OSSpinLockLock(&global.lock); + if (eval) + { + global.hostname = strdup(l[1]); + } else { - snprintf(buf, sizeof(buf), "%d", e->gid); - asl_set(msg, ASL_KEY_GID, buf); + free(global.hostname); + global.hostname = NULL; } + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "mark_time")) + { + /* = mark_time seconds */ + OSSpinLockLock(&global.lock); + if (eval) global.mark_time = atoll(l[1]); + else global.mark_time = 0; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "dup_delay")) + { + /* = bsd_max_dup_time seconds */ + OSSpinLockLock(&global.lock); + if (eval) global.bsd_max_dup_time = atoll(l[1]); + else global.bsd_max_dup_time = DEFAULT_BSD_MAX_DUP_SEC; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "remote_delay")) + { + /* = remote_delay microseconds */ + OSSpinLockLock(&global.lock); + if (eval) global.remote_delay_time = atol(l[1]); + else global.remote_delay_time = DEFAULT_REMOTE_DELAY; + OSSpinLockUnlock(&global.lock); } - else if ((e != NULL) && (e->gid != 99)) + else if (!strcasecmp(l[0], "utmp_ttl")) { - snprintf(buf, sizeof(buf), "%d", e->gid); - asl_set(msg, ASL_KEY_GID, buf); + /* = utmp_ttl seconds */ + OSSpinLockLock(&global.lock); + if (eval) global.utmp_ttl = (time_t)atoll(l[1]); + else global.utmp_ttl = DEFAULT_UTMP_TTL_SEC; + OSSpinLockUnlock(&global.lock); } + else if (!strcasecmp(l[0], "mps_limit")) + { + /* = mps_limit number */ + OSSpinLockLock(&global.lock); + if (eval) global.mps_limit = (uint32_t)atol(l[1]); + else global.mps_limit = DEFAULT_MPS_LIMIT; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "memory_max")) + { + /* = memory_max number */ + OSSpinLockLock(&global.lock); + if (eval) global.memory_max = (int64_t)atoll(l[1]); + else global.memory_max = DEFAULT_MEMORY_MAX; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "stats_interval")) + { + /* = stats_interval number */ + OSSpinLockLock(&global.lock); + if (eval) global.stats_interval = (time_t)atoll(l[1]); + else global.stats_interval = DEFAULT_STATS_INTERVAL; + OSSpinLockUnlock(&global.lock); + } + else if (!strcasecmp(l[0], "max_file_size")) + { + /* = max_file_size bytes */ + pthread_mutex_lock(global.db_lock); - /* Level */ - val = asl_get(msg, ASL_KEY_LEVEL); - if (val == NULL) asl_set(msg, ASL_KEY_LEVEL, "7"); + if (global.dbtype & DB_TYPE_FILE) + { + asl_store_close(global.file_db); + global.file_db = NULL; + if (eval) global.db_file_max = atoi(l[1]); + else global.db_file_max = DEFAULT_DB_FILE_MAX; + } + + pthread_mutex_unlock(global.db_lock); + } + else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore"))) + { + /* NB this is private / unpublished */ + /* = db type [max]... */ + if (eval) + { + v32a = 0; + v32b = 0; + v32c = 0; + + if ((l[1][0] >= '0') && (l[1][0] <= '9')) + { + intval = atoi(l[1]); + if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]); + if ((count >= 4) && (strcmp(l[3], "-"))) v32b = atoi(l[3]); + if ((count >= 5) && (strcmp(l[4], "-"))) v32c = atoi(l[4]); + } + else if (!strcasecmp(l[1], "file")) + { + intval = DB_TYPE_FILE; + if ((count >= 3) && (strcmp(l[2], "-"))) v32a = atoi(l[2]); + } + else if (!strncasecmp(l[1], "mem", 3)) + { + intval = DB_TYPE_MEMORY; + if ((count >= 3) && (strcmp(l[2], "-"))) v32b = atoi(l[2]); + } + else + { + free_string_list(l); + return -1; + } + + if (v32a == 0) v32a = global.db_file_max; + if (v32b == 0) v32b = global.db_memory_max; + if (v32c == 0) v32c = global.db_memory_str_max; + config_data_store(intval, v32a, v32b, v32c); + } + else + { +#if TARGET_OS_EMBEDDED + intval = DB_TYPE_MEMORY; +#else + intval = DB_TYPE_FILE; +#endif + config_data_store(intval, DEFAULT_DB_FILE_MAX, DEFAULT_DB_MEMORY_MAX, DEFAULT_DB_MEMORY_STR_MAX); + } + } + + free_string_list(l); return 0; } -int -aslevent_addoutput(aslsendmsgfn fn, const char *outid) +static int +control_message(asl_msg_t *msg) { - struct asloutput *tmp; - - tmp = calloc(1, sizeof(struct asloutput)); - if (tmp == NULL) return -1; + const char *str = asl_msg_get_val_for_key(msg, ASL_KEY_MSG); - tmp->sendmsg = fn; - tmp->outid = outid; + if (str == NULL) return 0; - TAILQ_INSERT_TAIL(&Outq, tmp, entries); + if (!strncmp(str, "= reset", 7)) + { + init_globals(); + return asl_action_reset(); + } + else if (!strncmp(str, "= crash", 7)) + { + abort(); + } + else if (!strncmp(str, "@ ", 2)) + { + return asl_action_control_set_param(str); + } + else if (!strncmp(str, "= ", 2)) + { + return control_set_param(str, true); + } return 0; } -int -aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex) +void +process_message(asl_msg_t *msg, uint32_t source) { - struct aslevent *e; - int status = 0; + int64_t msize = 0; + static bool wq_draining = false; + bool is_control = false; + asl_msg_t *x; - asldebug("--> aslevent_fdsets\n"); - FD_ZERO(rd); - FD_ZERO(wr); - FD_ZERO(ex); + if (msg == NULL) return; + + is_control = asl_check_option(msg, ASL_OPT_CONTROL) != 0; - for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next) + if ((!is_control) && wq_draining) { - asldebug("adding fd %d\n", e->fd); - if (e->readfn) + if (global.memory_size >= (global.memory_max / 2)) { - FD_SET(e->fd, rd); - status = MAX(e->fd, status); + asldebug("Work queue draining: dropped message.\n"); + asl_msg_release(msg); + return; } - - if (e->writefn) + else { - FD_SET(e->fd, wr); - status = MAX(e->fd, status); + asldebug("Work queue re-enabled at 1/2 max. size %lld max %lld\n", global.memory_size, global.memory_max); + wq_draining = false; } + } - if (e->exceptfn) - { - FD_SET(e->fd, ex); - status = MAX(e->fd, status); - } + __block vproc_transaction_t vt = vproc_transaction_begin(NULL); + + for (x = msg; x != NULL; x = x->next) msize += x->mem_size; + + if ((global.memory_size + msize) >= global.memory_max) + { + char str[256]; + + wq_draining = true; + asl_msg_release(msg); + + asldebug("Work queue disabled. msize %lld size %lld max %lld\n", msize, global.memory_size + msize, global.memory_max); + snprintf(str, sizeof(str), "[Sender syslogd] [Level 2] [PID %u] [Message Internal memory size limit %lld exceeded - dropping messages] [UID 0] [UID 0] [Facility syslog]", global.pid, global.memory_max); + msg = asl_msg_from_string(str); } - asldebug("<--aslevent_fdsets\n"); - return status; -} + OSAtomicAdd64(msize, &global.memory_size); + OSAtomicIncrement32(&global.work_queue_count); -void -aslevent_handleevent(fd_set rd, fd_set wr, fd_set ex, char *errstr) -{ - struct aslevent *e; - char *out = NULL; - asl_msg_t *msg; + dispatch_async(global.work_queue, ^{ + int32_t kplevel; + uint32_t status; + uid_t uid; - asldebug("--> aslevent_handleevent\n"); - if (errstr) errstr = NULL; + kplevel = -1; + uid = -2; - for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next) - { - if (FD_ISSET(e->fd, &rd) && (e->readfn != NULL)) + status = aslmsg_verify(msg, source, &kplevel, &uid); + if (status == VERIFY_STATUS_OK) { - asldebug("handling read event on %d\n", e->fd); - msg = e->readfn(e->fd); - if (msg == NULL) + if ((source == SOURCE_KERN) && (kplevel >= 0)) { - asldebug("error reading message\n"); - continue; + if (kplevel > 7) kplevel = 7; + if (kern_notify_token[kplevel] < 0) + { + status = notify_register_plain(kern_notify_key[kplevel], &(kern_notify_token[kplevel])); + if (status != 0) asldebug("notify_register_plain(%s) failed status %u\n", status); + } + + notify_post(kern_notify_key[kplevel]); } - if (aslmsg_verify(e, msg) < 0) - { - asl_free(msg); - asldebug("recieved invalid message\n"); - } - else - { - aslevent_match(msg); - asl_free(msg); - } - } + if ((uid == 0) && is_control) control_message(msg); - if (FD_ISSET(e->fd, &ex) && e->exceptfn) + /* + * Send message to output module chain (asl is first). + * The last module in the chain will decrement global.memory_size. + */ + asl_out_message(msg, msize); + } + else { - asldebug("handling except event on %d\n", e->fd); - out = e->exceptfn(e->fd); - if (out == NULL) asldebug("error writing message\n"); + OSAtomicAdd64(-1ll * msize, &global.memory_size); } - } - asldebug("<-- aslevent_handleevent\n"); + asl_msg_release(msg); + + OSAtomicDecrement32(&global.work_queue_count); + vproc_transaction_end(NULL, vt); + }); } int -asl_log_string(const char *str) +internal_log_message(const char *str) { asl_msg_t *msg; if (str == NULL) return 1; msg = asl_msg_from_string(str); - if (aslmsg_verify(NULL, msg) < 0) - { - asl_free(msg); - return -1; - } + if (msg == NULL) return 1; + + process_message(msg, SOURCE_INTERNAL); + + return 0; +} + +int +asldebug(const char *str, ...) +{ + va_list v; + FILE *dfp = NULL; + + if (global.debug == 0) return 0; + + if (global.debug_file == NULL) dfp = fopen(_PATH_SYSLOGD_LOG, "a"); + else dfp = fopen(global.debug_file, "a"); + if (dfp == NULL) return 0; + + va_start(v, str); + fprintf(dfp, "W %d %llu", global.work_queue_count, global.memory_size); + 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); + fprintf(dfp, " ; "); + vfprintf(dfp, str, v); + va_end(v); + + fclose(dfp); - aslevent_match(msg); - asl_free(msg); return 0; } void -aslmark(void) +asl_mark(void) { - char *str; + char *str = NULL; - str = NULL; - asprintf(&str, "[%s syslogd] [%s %u] [%s %u] [%s -- MARK --] [%s 0] [%s 0] [Facility syslog]", - ASL_KEY_SENDER, - ASL_KEY_LEVEL, ASL_LEVEL_INFO, - ASL_KEY_PID, getpid(), - ASL_KEY_MSG, ASL_KEY_UID, ASL_KEY_GID); - - asl_log_string(str); - if (str != NULL) free(str); + asprintf(&str, "[Sender syslogd] [Level 6] [PID %u] [Message -- MARK --] [UID 0] [UID 0] [Facility syslog]", global.pid); + internal_log_message(str); + free(str); } asl_msg_t * -asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) +asl_syslog_input_convert(const char *in, int len, char *rhost, uint32_t source) { int pf, pri, index, n; - char *p, *colon, *brace, *tmp, *tval, *sval, *pval, *mval; + char *p, *colon, *brace, *space, *tmp, *tval, *hval, *sval, *pval, *mval; char prival[8]; const char *fval; asl_msg_t *msg; @@ -490,10 +1067,11 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) if (in == NULL) return NULL; if (len <= 0) return NULL; - asldebug("asl_syslog_input_convert: %s\n", in); - pri = LOG_DEBUG; + if (source == SOURCE_KERN) pri = LOG_NOTICE; + tval = NULL; + hval = NULL; sval = NULL; pval = NULL; mval = NULL; @@ -502,6 +1080,7 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) index = 0; p = (char *)in; + /* skip leading whitespace */ while ((index < len) && ((*p == ' ') || (*p == '\t'))) { p++; @@ -510,6 +1089,7 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) if (index >= len) return NULL; + /* parse "" priority (level and facility) */ if (*p == '<') { p++; @@ -537,13 +1117,16 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) snprintf(prival, sizeof(prival), "%d", pri); + /* check if a timestamp is included */ if (((len - index) > 15) && (p[9] == ':') && (p[12] == ':') && (p[15] == ' ')) { tmp = malloc(16); + if (tmp == NULL) return NULL; + memcpy(tmp, p, 15); tmp[15] = '\0'; - tick = asl_parse_time(tmp); + tick = asl_core_parse_time(tmp, NULL); if (tick == (time_t)-1) { tval = tmp; @@ -559,49 +1142,56 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) index += 16; } - if (kern != 0) + /* stop here for kernel messages */ + if (source == SOURCE_KERN) { - msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); - msg->type = ASL_TYPE_MSG; - - asl_set(msg, ASL_KEY_SENDER, "kernel"); - - asl_set(msg, "Facility", "kern"); - if (tval != NULL) - { - asl_set(msg, ASL_KEY_TIME, tval); - free(tval); - } + msg = asl_msg_new(ASL_TYPE_MSG); + if (msg == NULL) return NULL; - asl_set(msg, ASL_KEY_MSG, p); + asl_msg_set_key_val(msg, ASL_KEY_MSG, p); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival); + asl_msg_set_key_val(msg, ASL_KEY_PID, "0"); - asl_set(msg, ASL_KEY_LEVEL, prival); - - asl_set(msg, ASL_KEY_PID, "0"); - - asl_set(msg, ASL_KEY_UID, "0"); + return msg; + } - asl_set(msg, ASL_KEY_GID, "0"); + /* if message is from a network socket, hostname follows */ + if (source == SOURCE_UDP_SOCKET) + { + space = strchr(p, ' '); + if (space != NULL) + { + n = space - p; + hval = malloc(n + 1); + if (hval == NULL) return NULL; - asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); + memcpy(hval, p, n); + hval[n] = '\0'; - return msg; + p = space + 1; + index += (n + 1); + } } colon = strchr(p, ':'); brace = strchr(p, '['); + /* check for "sender:" or sender[pid]:" */ if (colon != NULL) { if ((brace != NULL) && (brace < colon)) { n = brace - p; sval = malloc(n + 1); + if (sval == NULL) return NULL; + memcpy(sval, p, n); sval[n] = '\0'; n = colon - (brace + 1) - 1; pval = malloc(n + 1); + if (pval == NULL) return NULL; + memcpy(pval, (brace + 1), n); pval[n] = '\0'; } @@ -609,6 +1199,8 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) { n = colon - p; sval = malloc(n + 1); + if (sval == NULL) return NULL; + memcpy(sval, p, n); sval[n] = '\0'; } @@ -628,72 +1220,207 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) if (n > 0) { mval = malloc(n + 1); + if (mval == NULL) return NULL; + memcpy(mval, p, n); mval[n] = '\0'; } if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER); - msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); - msg->type = ASL_TYPE_MSG; + msg = asl_msg_new(ASL_TYPE_MSG); + if (msg == NULL) return NULL; if (tval != NULL) { - asl_set(msg, ASL_KEY_TIME, tval); + asl_msg_set_key_val(msg, ASL_KEY_TIME, tval); free(tval); } - if (fval != NULL) asl_set(msg, "Facility", fval); - else asl_set(msg, "Facility", "user"); + if (fval != NULL) asl_msg_set_key_val(msg, "Facility", fval); + else asl_msg_set_key_val(msg, "Facility", "user"); if (sval != NULL) { - asl_set(msg, ASL_KEY_SENDER, sval); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); free(sval); } if (pval != NULL) { - asl_set(msg, ASL_KEY_PID, pval); + asl_msg_set_key_val(msg, ASL_KEY_PID, pval); free(pval); } - else asl_set(msg, ASL_KEY_PID, "-1"); + else + { + asl_msg_set_key_val(msg, ASL_KEY_PID, "-1"); + } if (mval != NULL) { - asl_set(msg, ASL_KEY_MSG, mval); + asl_msg_set_key_val(msg, ASL_KEY_MSG, mval); free(mval); } - asl_set(msg, ASL_KEY_LEVEL, prival); - asl_set(msg, ASL_KEY_UID, "-2"); - asl_set(msg, ASL_KEY_GID, "-2"); + asl_msg_set_key_val(msg, ASL_KEY_LEVEL, prival); + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); - if (rhost == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); - else asl_set(msg, ASL_KEY_HOST, rhost); + if (hval != NULL) + { + asl_msg_set_key_val(msg, ASL_KEY_HOST, hval); + free(hval); + } + else if (rhost != NULL) + { + asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost); + } - if (msg->count == 0) + return msg; +} + +asl_msg_t * +asl_input_parse(const char *in, int len, char *rhost, uint32_t source) +{ + asl_msg_t *msg; + int status, x, legacy, off; + + asldebug("asl_input_parse: %s\n", (in == NULL) ? "NULL" : in); + + if (in == NULL) return NULL; + + legacy = 1; + msg = NULL; + + /* calculate length if not provided */ + if (len == 0) len = strlen(in); + + /* + * Determine if the input is "old" syslog format or new ASL format. + * Old format lines should start with "<", but they can just be straight text. + * ASL input may start with a length (10 bytes) followed by a space and a '['. + * The length is optional, so ASL messages may also just start with '['. + */ + if ((in[0] != '<') && (len > 11)) { - asl_free(msg); - return NULL; + status = sscanf(in, "%d ", &x); + if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0; } + if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source); + + off = 11; + if (in[0] == '[') off = 0; + + msg = asl_msg_from_string(in + off); + if (msg == NULL) return NULL; + + if (rhost != NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost); + return msg; } -char * -get_line_from_file(FILE *f) +#if !TARGET_IPHONE_SIMULATOR +void +launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t sender_uid, gid_t sender_gid, int priority, const char *from_name, const char *about_name, const char *session_name, const char *msg) { - char *s, *out; - size_t len; + asl_msg_t *m; + char str[256]; + time_t now; + + if (global.launchd_enabled == 0) return; - out = fgetln(f, &len); - if (out == NULL) return NULL; - if (len == 0) return NULL; +/* + 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", + when->tv_sec, when->tv_usec, from_pid, about_pid, sender_uid, sender_gid, priority, from_name, about_name, session_name, msg); +*/ - s = malloc(len + 1); - memcpy(s, out, len); + m = asl_msg_new(ASL_TYPE_MSG); + if (m == NULL) return; + + /* Level */ + if (priority < ASL_LEVEL_EMERG) priority = ASL_LEVEL_EMERG; + if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG; + snprintf(str, sizeof(str), "%d", priority); + + asl_msg_set_key_val(m, ASL_KEY_LEVEL, str); + + /* Time */ + if (when != NULL) + { + snprintf(str, sizeof(str), "%llu", (unsigned long long) when->tv_sec); + asl_msg_set_key_val(m, ASL_KEY_TIME, str); - s[len - 1] = '\0'; - return s; + snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec); + asl_msg_set_key_val(m, ASL_KEY_TIME_NSEC, str); + } + else + { + now = time(NULL); + snprintf(str, sizeof(str), "%llu", (unsigned long long) now); + asl_msg_set_key_val(m, ASL_KEY_TIME, str); + } + + /* Facility */ + asl_msg_set_key_val(m, ASL_KEY_FACILITY, FACILITY_CONSOLE); + + /* UID */ + snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid); + asl_msg_set_key_val(m, ASL_KEY_UID, str); + + /* GID */ + snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid); + asl_msg_set_key_val(m, ASL_KEY_GID, str); + + /* PID */ + if (from_pid != 0) + { + snprintf(str, sizeof(str), "%u", (unsigned int)from_pid); + asl_msg_set_key_val(m, ASL_KEY_PID, str); + } + + /* Reference PID */ + if ((about_pid > 0) && (about_pid != from_pid)) + { + snprintf(str, sizeof(str), "%u", (unsigned int)about_pid); + asl_msg_set_key_val(m, ASL_KEY_REF_PID, str); + } + + /* Sender */ + if (from_name != NULL) + { + asl_msg_set_key_val(m, ASL_KEY_SENDER, from_name); + } + + /* ReadUID */ + if (sender_uid != 0) + { + snprintf(str, sizeof(str), "%d", (int)sender_uid); + asl_msg_set_key_val(m, ASL_KEY_READ_UID, str); + } + + /* Reference Process */ + if (about_name != NULL) + { + if ((from_name != NULL) && (strcmp(from_name, about_name) != 0)) + { + asl_msg_set_key_val(m, ASL_KEY_REF_PROC, about_name); + } + } + + /* Session */ + if (session_name != NULL) + { + asl_msg_set_key_val(m, ASL_KEY_SESSION, session_name); + } + + /* Message */ + if (msg != NULL) + { + asl_msg_set_key_val(m, ASL_KEY_MSG, msg); + } + + process_message(m, SOURCE_LAUNCHD); } + +#endif