X-Git-Url: https://git.saurik.com/apple/syslog.git/blobdiff_plain/1496e7d1dd53a3a0fed695ccb7ea6f5197672810..4865c03e306b8431c4e88a88772ec2c11580fc22:/syslogd.tproj/daemon.c diff --git a/syslogd.tproj/daemon.c b/syslogd.tproj/daemon.c index ca428fc..8a30222 100644 --- a/syslogd.tproj/daemon.c +++ b/syslogd.tproj/daemon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2009 Apple 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 @@ -38,15 +39,16 @@ #include #include #include -#include #include +#include +#include +#include #include "daemon.h" #define LIST_SIZE_DELTA 256 +#define STATS_TABLE_SIZE 256 -#define streq(A,B) (strcmp(A,B)==0) #define forever for(;;) -#define IndexNull ((uint32_t)-1) #define ASL_MSG_TYPE_MASK 0x0000000f #define ASL_TYPE_ERROR 2 @@ -63,23 +65,37 @@ #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 name_change_token = -1; static OSSpinLock count_lock = 0; -#ifndef CONFIG_IPHONE +#if !TARGET_OS_EMBEDDED static vproc_transaction_t vproc_trans = {0}; #endif -#define QUOTA_TABLE_SIZE 8192 -#define QUOTA_TABLE_SLOTS 8 +#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 QUOTA_EXCEEDED_MESSAGE "*** process %d exceeded %d log message per second limit - remaining messages this second discarded ***" -#define QUOTA_EXCEEDED_LEVEL "3" +#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 -static time_t quota_table_time = 0; -static pid_t quota_table_pid[QUOTA_TABLE_SIZE]; -static int32_t quota_table_quota[QUOTA_TABLE_SIZE]; +#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[] = { @@ -93,354 +109,212 @@ static const char *kern_notify_key[] = "com.apple.system.log.kernel.debug" }; -struct asloutput -{ - aslsendmsgfn sendmsg; - const char *outid; - TAILQ_ENTRY(asloutput) entries; -}; - -struct aslmatch -{ - char *outid; - asl_msg_t *query; - TAILQ_ENTRY(aslmatch) entries; -}; - -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}; -static char ** -_insertString(char *s, char **l, uint32_t x) +static stats_table_t * +stats_table_new() { - int i, len; + stats_table_t *t = (stats_table_t *)malloc(sizeof(stats_table_t)); + if (t == NULL) return NULL; - if (s == NULL) return l; - if (l == NULL) + t->bucket_count = STATS_TABLE_SIZE; + t->bucket = (sender_stats_t **)calloc(t->bucket_count, sizeof(sender_stats_t *)); + if (t->bucket == NULL) { - l = (char **)malloc(2 * sizeof(char *)); - if (l == NULL) return NULL; + free(t); + return NULL; + } - l[0] = strdup(s); - if (l[0] == NULL) - { - free(l); - return NULL; - } + t->mcount = 0; + t->shim_count = 0; - l[1] = NULL; - return l; - } + return t; +} - for (i = 0; l[i] != NULL; i++); - len = i + 1; /* count the NULL on the end of the list too! */ +static asl_msg_t * +stats_table_final(stats_table_t *t) +{ + uint32_t i; + asl_msg_t *msg; + char val[64]; - l = (char **)reallocf(l, (len + 1) * sizeof(char *)); - if (l == NULL) return NULL; + if (t == NULL) return NULL; + + msg = asl_msg_new(ASL_TYPE_MSG); + if (msg == NULL) return NULL; - if ((x >= (len - 1)) || (x == IndexNull)) + 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++) { - l[len - 1] = strdup(s); - if (l[len - 1] == NULL) + sender_stats_t *s; + s = t->bucket[i]; + while (s != NULL) { - free(l); - return NULL; + 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; } - - l[len] = NULL; - return l; } - for (i = len; i > x; i--) l[i] = l[i - 1]; - l[x] = strdup(s); - if (l[x] == NULL) return NULL; + free(t->bucket); + free(t); - return l; + return msg; } -char ** -explode(const char *s, const char *delim) +static void +stats_table_update(stats_table_t *t, const char *sender, uint64_t msg_size) { - char **l = NULL; - const char *p; - char *t, quote; - int i, n; + uint32_t i; + sender_stats_t *s; + uint8_t *p; - if (s == NULL) return NULL; + if (t == NULL) return; + if (sender == NULL) return; - quote = '\0'; + /* hash */ + i = 0; + for (p = (uint8_t *)sender; *p != '\0'; p++) i = (i << 1) ^ (i ^ *p); + i %= STATS_TABLE_SIZE; - p = s; - while (p[0] != '\0') + for (s = t->bucket[i]; s != NULL; s = s->next) { - /* scan forward */ - for (i = 0; p[i] != '\0'; i++) + if ((s->sender != NULL) && (strcmp(sender, s->sender) == 0)) { - if (quote == '\0') - { - /* not inside a quoted string: check for delimiters and quotes */ - if (strchr(delim, p[i]) != NULL) break; - else if (p[i] == '\'') quote = p[i]; - else if (p[i] == '"') quote = p[i]; - } - else - { - /* inside a quoted string - look for matching quote */ - if (p[i] == quote) quote = '\0'; - } + s->count++; + s->size += msg_size; + return; } - - n = i; - t = malloc(n + 1); - if (t == NULL) return NULL; - - for (i = 0; i < n; i++) t[i] = p[i]; - t[n] = '\0'; - l = _insertString(t, l, IndexNull); - free(t); - t = NULL; - if (p[i] == '\0') return l; - if (p[i + 1] == '\0') l = _insertString("", l, IndexNull); - p = p + i + 1; } - return l; -} - -void -freeList(char **l) -{ - int i; + s = (sender_stats_t *)malloc(sizeof(sender_stats_t)); + s->sender = strdup(sender); + if (s->sender == NULL) + { + free(s); + return; + } - if (l == NULL) return; - for (i = 0; l[i] != NULL; i++) free(l[i]); - free(l); + s->count = 1; + s->size = msg_size; + s->next = t->bucket[i]; + t->bucket[i] = s; } -/* - * Quotas are maintained using a very fast fixed-size table. - * We hash into the pid table (quota_table_pid) using the last 10 - * bits of the pid, so the table has 1024 "buckets". The table is - * actually just an array with 8 entry slots (for collisions) per bucket. - * If there are more than 8 pids that hash to the same bucket, we - * re-use the one with the lowest message usage (highest remaining - * quota). This can lead to "generosity: if there are nine or more - * pids with the same last 10 bits all logging like crazy, we may - * end up allowing some of them to log more than their quota. - * That would be a remarkably rare occurrence. - */ - static uint32_t -quota_check(pid_t pid, time_t now, asl_msg_t *msg) +kern_quota_check(time_t now, asl_msg_t *msg, uint32_t level) { - int i, x, maxx, max; - char *str; + char *str, lstr[2]; if (msg == NULL) return VERIFY_STATUS_INVALID_MESSAGE; if (global.mps_limit == 0) return VERIFY_STATUS_OK; - OSSpinLockLock(&global.lock); - - if (quota_table_time != now) + if (quota_time != now) { - memset(quota_table_pid, 0, sizeof(quota_table_pid)); - quota_table_time = now; + kern_quota = global.mps_limit; + kern_level = 7; + quota_time = now; } - /* hash is last 10 bits of the pid, shifted up 3 bits to allow 8 slots per bucket */ - x = (pid & 0x000003ff) << 3; - maxx = x; - max = quota_table_quota[x]; - - for (i = 0; i < QUOTA_TABLE_SLOTS; i++) - { - if (quota_table_pid[x] == 0) - { - quota_table_pid[x] = pid; - quota_table_quota[x] = global.mps_limit; + if (level < kern_level) kern_level = level; + if (kern_quota > 0) kern_quota--; - OSSpinLockUnlock(&global.lock); - return VERIFY_STATUS_OK; - } + if (kern_quota > 0) return VERIFY_STATUS_OK; + if (kern_quota < 0) return VERIFY_STATUS_EXCEEDED_QUOTA; - if (quota_table_pid[x] == pid) - { - quota_table_quota[x] = quota_table_quota[x] - 1; + kern_quota = -1; - if (quota_table_quota[x] == 0) - { - quota_table_quota[x] = -1; - - str = NULL; - asprintf(&str, QUOTA_EXCEEDED_MESSAGE, (int)pid, global.mps_limit); - if (str != NULL) - { - asl_set(msg, ASL_KEY_MSG, str); - free(str); - asl_set(msg, ASL_KEY_LEVEL, QUOTA_EXCEEDED_LEVEL); - } - - OSSpinLockUnlock(&global.lock); - return VERIFY_STATUS_OK; - } - - if (quota_table_quota[x] < 0) - { - OSSpinLockUnlock(&global.lock); - return VERIFY_STATUS_EXCEEDED_QUOTA; - } - - OSSpinLockUnlock(&global.lock); - return VERIFY_STATUS_OK; - } - - if (quota_table_quota[x] > max) - { - maxx = x; - max = quota_table_quota[x]; - } - - x += 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); } - /* can't find the pid and no slots were available - reuse slot with highest remaining quota */ - quota_table_pid[maxx] = pid; - quota_table_quota[maxx] = global.mps_limit; - - OSSpinLockUnlock(&global.lock); return VERIFY_STATUS_OK; } -int -asl_check_option(asl_msg_t *msg, const char *opt) +static void +stats_msg(const char *sender, time_t now, asl_msg_t *msg) { - const char *p; - uint32_t len; + asl_msg_t *x; + uint64_t msize = 0; - if (msg == NULL) return 0; - if (opt == NULL) return 0; - - len = strlen(opt); - if (len == 0) return 0; - - p = asl_get(msg, ASL_KEY_OPTION); - if (p == NULL) return 0; - - while (*p != '\0') + /* flush stats after N seconds */ + if ((global.stats_interval != 0) && ((now - global.stats_last) >= global.stats_interval) && (global.stats != NULL)) { - while ((*p == ' ') || (*p == '\t') || (*p == ',')) p++; - if (*p == '\0') return 0; - - if (strncasecmp(p, opt, len) == 0) - { - p += len; - if ((*p == ' ') || (*p == '\t') || (*p == ',') || (*p == '\0')) return 1; - } - - while ((*p != ' ') && (*p != '\t') && (*p != ',') && (*p != '\0')) p++; + asl_msg_t *msg = stats_table_final(global.stats); + process_message(msg, SOURCE_INTERNAL); + global.stats = NULL; + global.stats_last = now; } - return 0; -} + if (global.stats == NULL) global.stats = stats_table_new(); -int -aslevent_init(void) -{ - TAILQ_INIT(&Eventq); - TAILQ_INIT(&Outq); - TAILQ_INIT(&Matchq); + for (x = msg; x != NULL; x = x->next) msize += x->mem_size; - return 0; -} - -int -aslevent_log(asl_msg_t *msg, char *outid) -{ - struct asloutput *i; - int status = -1; + const char *shim_vers = asl_msg_get_val_for_key(msg, "ASLSHIM"); + global.stats->mcount++; + if (shim_vers != NULL) global.stats->shim_count++; - for (i = Outq.tqh_first; i != NULL; i = i->entries.tqe_next) - { - if ((outid != NULL) && (strcmp(i->outid, outid) == 0)) - { - status = i->sendmsg(msg, outid); - } - } - - return status; + /* update count and total size - total and for this sender */ + stats_table_update(global.stats, "*", msize); + stats_table_update(global.stats, sender, msize); } -int -aslevent_addmatch(asl_msg_t *query, char *outid) +static const char * +whatsmyhostname() { - struct aslmatch *tmp; - - if (query == NULL) return -1; - if (outid == NULL) return -1; - - tmp = calloc(1, sizeof(struct aslmatch)); - if (tmp == NULL) return -1; - - tmp->query = query; - tmp->outid = outid; - TAILQ_INSERT_TAIL(&Matchq, tmp, entries); - - return 0; -} + static dispatch_once_t once; + int check, status; -void -asl_message_match_and_log(asl_msg_t *msg) -{ - struct aslmatch *i; + if (global.hostname != NULL) return global.hostname; - if (msg == NULL) return; + dispatch_once(&once, ^{ + snprintf(myname, sizeof(myname), "%s", "localhost"); + notify_register_check(kNotifySCHostNameChange, &name_change_token); + }); - for (i = Matchq.tqh_first; i != NULL; i = i->entries.tqe_next) - { - if (asl_msg_cmp(i->query, msg) != 0) - { - aslevent_log(msg, i->outid); - } - } -} + check = 1; + status = 0; -int -aslevent_removefd(int fd) -{ - struct aslevent *e, *next; + if (name_change_token >= 0) status = notify_check(name_change_token, &check); - e = Eventq.tqh_first; + if ((status == 0) && (check == 0)) return (const char *)myname; - while (e != NULL) + if (gethostname(myname, MAXHOSTNAMELEN) < 0) { - next = e->entries.tqe_next; - if (fd == e->fd) - { - e->fd = -1; - return 0; - } - - e = next; + snprintf(myname, sizeof(myname), "%s", "localhost"); } - - return -1; -} - -const char * -whatsmyhostname() -{ - char *dot; - - if (gethostname(myname, MAXHOSTNAMELEN) < 0) + else { - memset(myname, 0, sizeof(myname)); - return "localhost"; + char *dot; + dot = strchr(myname, '.'); + if (dot != NULL) *dot = '\0'; } - dot = strchr(myname, '.'); - if (dot != NULL) *dot = '\0'; - return (const char *)myname; } @@ -449,13 +323,10 @@ asl_client_count_increment() { OSSpinLockLock(&count_lock); -#ifndef CONFIG_IPHONE +#if !TARGET_OS_EMBEDDED if (global.client_count == 0) vproc_trans = vproc_transaction_begin(NULL); #endif global.client_count++; -#ifdef DEBUG - asldebug("global.client_count++ (%d)\n", global.client_count); -#endif OSSpinLockUnlock(&count_lock); } @@ -466,121 +337,13 @@ asl_client_count_decrement() OSSpinLockLock(&count_lock); if (global.client_count > 0) global.client_count--; -#ifndef CONFIG_IPHONE +#if !TARGET_OS_EMBEDDED if (global.client_count == 0) vproc_transaction_end(NULL, vproc_trans); #endif -#ifdef DEBUG - asldebug("global.client_count-- (%d)\n", global.client_count); -#endif OSSpinLockUnlock(&count_lock); } -int -aslevent_addfd(int source, int fd, uint32_t flags, aslreadfn readfn, aslwritefn writefn, aslexceptfn exceptfn) -{ - struct aslevent *e; - int found = 0, status; -#ifdef LOCAL_PEERCRED - struct xucred cr; -#endif - socklen_t len; - uid_t u; - gid_t g; - struct sockaddr_storage ss; - char *sender, str[256]; - - u = 99; - g = 99; - sender = NULL; - - memset(&ss, 0, sizeof(struct sockaddr_storage)); - memset(str, 0, sizeof(str)); - - len = sizeof(struct sockaddr_storage); - - if (flags & ADDFD_FLAGS_LOCAL) - { - snprintf(str, sizeof(str), "localhost"); - sender = str; - -#ifdef LOCAL_PEERCRED - len = sizeof(cr); - - status = getsockopt(fd, LOCAL_PEERCRED, 1, &cr, &len); - if (status == 0) - { - u = cr.cr_uid; - g = cr.cr_gid; - } -#endif - } - else - { - status = getpeername(fd, (struct sockaddr *)&ss, &len); - if (status == 0) - { - if (len == 0) - { - /* UNIX Domain socket */ - snprintf(str, sizeof(str), "localhost"); - sender = str; - } - else - { - if (inet_ntop(ss.ss_family, (struct sockaddr *)&ss, str, 256) == NULL) sender = str; - } - } - } - - asldebug("source %d fd %d flags 0x%08x UID %d GID %d Sender %s\n", source, fd, flags, u, g, (sender == NULL) ? "NULL" : sender ); - - for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next) - { - if (fd == e->fd) - { - 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); - if (e->sender == NULL) return -1; - } - - e->uid = u; - e->gid = g; - found = 1; - } - } - - if (found) return 0; - - e = calloc(1, sizeof(struct aslevent)); - if (e == NULL) return -1; - - e->source = source; - e->fd = fd; - e->readfn = readfn; - e->writefn = writefn; - e->exceptfn = exceptfn; - e->sender = NULL; - if (sender != NULL) - { - e->sender = strdup(sender); - if (e->sender == NULL) return -1; - } - - e->uid = u; - e->gid = g; - - TAILQ_INSERT_TAIL(&Eventq, e, entries); - - return 0; -} - /* * Checks message content and sets attributes as required * @@ -594,197 +357,194 @@ aslevent_addfd(int source, int fd, uint32_t flags, aslreadfn readfn, aslwritefn */ static uint32_t -aslmsg_verify(uint32_t source, struct aslevent *e, asl_msg_t *msg, int32_t *kern_post_level) +aslmsg_verify(asl_msg_t *msg, uint32_t source, int32_t *kern_post_level, uid_t *uid_out) { - const char *val, *fac; + 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; - if (kern_post_level != NULL) *kern_post_level = -1; - /* Time */ now = time(NULL); - tick = 0; - val = asl_get(msg, ASL_KEY_TIME); - if (val != NULL) tick = asl_parse_time(val); - - /* 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, "%lu", tick); - asl_set(msg, ASL_KEY_TIME, buf); - - /* Host */ - if (e == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); - else if (e->sender != NULL) - { - if (!strcmp(e->sender, "localhost")) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); - else asl_set(msg, ASL_KEY_HOST, e->sender); - } + if (kern_post_level != NULL) *kern_post_level = -1; + if (uid_out != NULL) *uid_out = -2; /* PID */ pid = 0; - val = asl_get(msg, ASL_KEY_PID); - if (val == NULL) asl_set(msg, ASL_KEY_PID, "0"); + 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 PID is 1 (launchd), use the refpid if there is one */ + /* if PID is 1 (launchd), use the RefPID and RefProc provided */ if (pid == 1) { - val = asl_get(msg, ASL_KEY_REF_PID); + 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); } - /* if quotas are enabled and pid > 1 (not kernel or launchd) check quota */ - if ((global.mps_limit > 0) && (pid > 1)) + /* 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 = quota_check(pid, now, msg); + status = kern_quota_check(now, msg, level); if (status != VERIFY_STATUS_OK) return status; } - /* UID */ - uid = -2; - val = asl_get(msg, ASL_KEY_UID); - - switch (source) + if (pid != 0) { - case SOURCE_KERN: - case SOURCE_INTERNAL: - { - /* we know the UID is 0 */ - uid = 0; - asl_set(msg, ASL_KEY_UID, "0"); - break; - } - case SOURCE_ASL_SOCKET: - case SOURCE_ASL_MESSAGE: - case SOURCE_LAUNCHD: + /* set Sender_Mach_UUID */ + uuid_clear(pinfo.p_uuid); + if (proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &pinfo, sizeof(pinfo)) == sizeof(pinfo)) { - /* we trust the UID in the message */ - if (val != NULL) uid = atoi(val); - break; + uuid_unparse(pinfo.p_uuid, ustr); + asl_msg_set_key_val(msg, ASL_KEY_SENDER_MACH_UUID, ustr); } - case SOURCE_BSD_SOCKET: - case SOURCE_UDP_SOCKET: + } + + 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 (val == NULL) - { - if (e == NULL) asl_set(msg, ASL_KEY_UID, "-2"); - else if (e->uid == 99) asl_set(msg, ASL_KEY_UID, "-2"); - else - { - uid = e->uid; - snprintf(buf, sizeof(buf), "%d", e->uid); - asl_set(msg, ASL_KEY_UID, buf); - } - } - else if ((e != NULL) && (e->uid != 99)) - { - uid = e->uid; - snprintf(buf, sizeof(buf), "%d", e->uid); - asl_set(msg, ASL_KEY_UID, buf); - } + uid = -2; + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); } - default: + } + + if (uid_out != NULL) *uid_out = uid; + + 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")) { - asl_set(msg, ASL_KEY_UID, "-2"); + gid = -2; + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); } } - /* GID */ - val = asl_get(msg, ASL_KEY_GID); - switch (source) { case SOURCE_KERN: case SOURCE_INTERNAL: { - /* we know the GID is 0 */ - asl_set(msg, ASL_KEY_GID, "0"); + 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_SOCKET: + case SOURCE_UDP_SOCKET: case SOURCE_ASL_MESSAGE: case SOURCE_LAUNCHD: { - /* we trust the GID in the message */ break; } - case SOURCE_BSD_SOCKET: - case SOURCE_UDP_SOCKET: + default: { - if (val == NULL) + /* do not trust the UID 0 or GID 0 or 80 in SOURCE_BSD_SOCKET or SOURCE_UNKNOWN */ + if (uid == 0) { - if (e == NULL) asl_set(msg, ASL_KEY_GID, "-2"); - else if (e->gid == 99) asl_set(msg, ASL_KEY_GID, "-2"); - else - { - snprintf(buf, sizeof(buf), "%d", e->gid); - asl_set(msg, ASL_KEY_GID, buf); - } + uid = -2; + asl_msg_set_key_val(msg, ASL_KEY_UID, "-2"); } - else if ((e != NULL) && (e->gid != 99)) + + if ((gid == 0) || (gid == 80)) { - snprintf(buf, sizeof(buf), "%d", e->gid); - asl_set(msg, ASL_KEY_GID, buf); + gid = -2; + asl_msg_set_key_val(msg, ASL_KEY_GID, "-2"); } } - default: - { - asl_set(msg, ASL_KEY_GID, "-2"); - } } /* Sender */ - val = asl_get(msg, ASL_KEY_SENDER); - if (val == NULL) + if (sval == NULL) sval = asl_msg_get_val_for_key(msg, ASL_KEY_SENDER); + if (sval == NULL) { switch (source) { case SOURCE_KERN: { - asl_set(msg, ASL_KEY_SENDER, "kernel"); + sval = "kernel"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); break; } case SOURCE_INTERNAL: { - asl_set(msg, ASL_KEY_SENDER, "syslogd"); + sval = "syslogd"; + asl_msg_set_key_val(msg, ASL_KEY_SENDER, sval); break; } default: { - asl_set(msg, ASL_KEY_SENDER, "Unknown"); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown"); } } } - else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(val, "kernel"))) + else if ((source != SOURCE_KERN) && (uid != 0) && (!strcmp(sval, "kernel"))) { /* allow UID 0 to send messages with "Sender kernel", but nobody else */ - asl_set(msg, ASL_KEY_SENDER, "Unknown"); + asl_msg_set_key_val(msg, ASL_KEY_SENDER, "Unknown"); + sval = NULL; } - /* Level */ - val = asl_get(msg, ASL_KEY_LEVEL); - level = ASL_LEVEL_DEBUG; - if ((val != NULL) && (val[1] == '\0') && (val[0] >= '0') && (val[0] <= '7')) level = val[0] - '0'; - snprintf(buf, sizeof(buf), "%d", level); - asl_set(msg, ASL_KEY_LEVEL, buf); - /* Facility */ - fac = asl_get(msg, ASL_KEY_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_set(msg, ASL_KEY_FACILITY, fac); + asl_msg_set_key_val(msg, ASL_KEY_FACILITY, fac); } else if (fac[0] == '#') { @@ -796,40 +556,47 @@ aslmsg_verify(uint32_t source, struct aslevent *e, asl_msg_t *msg, int32_t *kern } fac = asl_syslog_faciliy_num_to_name(fnum); - asl_set(msg, ASL_KEY_FACILITY, fac); + 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_set(msg, ASL_KEY_FACILITY, FACILITY_USER); + if (uid != 0) asl_msg_set_key_val(msg, ASL_KEY_FACILITY, FACILITY_USER); } /* * 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_set(msg, ASL_KEY_READ_UID, "0"); - asl_set(msg, ASL_KEY_READ_GID, "80"); + 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); - /* - * Access Control: only UID 0 may use facility com.apple.system (or anything with that prefix). - * N.B. kernel can use any facility name. - */ + if ((ruval == NULL) && (rgval == NULL)) + { + asl_msg_set_key_val(msg, ASL_KEY_READ_GID, "80"); + } + } /* 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), "%lu", tick + global.utmp_ttl); - asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + global.utmp_ttl); + asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf); } - /* Set DB Expire Time for Filestsrem errors */ + /* Set DB Expire Time for Filesystem errors */ if (!strcmp(fac, FSLOG_VAL_FACILITY)) { - snprintf(buf, sizeof(buf), "%lu", tick + global.fs_ttl); - asl_set(msg, ASL_KEY_EXPIRE_TIME, buf); + snprintf(buf, sizeof(buf), "%llu", (unsigned long long) tick + FS_TTL_SEC); + asl_msg_set_key_val(msg, ASL_KEY_EXPIRE_TIME, buf); } /* @@ -841,87 +608,16 @@ aslmsg_verify(uint32_t source, struct aslevent *e, asl_msg_t *msg, int32_t *kern disaster_message(msg); } - return VERIFY_STATUS_OK; -} - -int -aslevent_addoutput(aslsendmsgfn fn, const char *outid) -{ - struct asloutput *tmp; - - tmp = calloc(1, sizeof(struct asloutput)); - if (tmp == NULL) return -1; - - tmp->sendmsg = fn; - tmp->outid = outid; - - TAILQ_INSERT_TAIL(&Outq, tmp, entries); - - return 0; -} - -int -aslevent_fdsets(fd_set *rd, fd_set *wr, fd_set *ex) -{ - struct aslevent *e; - int status = 0; - -// asldebug("--> aslevent_fdsets\n"); - FD_ZERO(rd); - FD_ZERO(wr); - FD_ZERO(ex); - - for (e = Eventq.tqh_first; e != NULL; e = e->entries.tqe_next) - { - if (e->fd < 0) continue; - -// asldebug("adding fd %d\n", e->fd); - if (e->readfn) - { - FD_SET(e->fd, rd); - status = MAX(e->fd, status); - } - - if (e->writefn) - { - FD_SET(e->fd, wr); - status = MAX(e->fd, status); - } - - if (e->exceptfn) - { - FD_SET(e->fd, ex); - status = MAX(e->fd, status); - } - } - -// asldebug("<--aslevent_fdsets\n"); - return status; -} - -void -aslevent_cleanup() -{ - struct aslevent *e, *next; - - e = Eventq.tqh_first; - - while (e != NULL) - { - next = e->entries.tqe_next; - if (e->fd < 0) - { - TAILQ_REMOVE(&Eventq, e, entries); - if (e->sender != NULL) free(e->sender); - free(e); - } + /* + * gather sender stats + */ + if (source != SOURCE_INTERNAL) stats_msg(sval, now, msg); - e = next; - } + return VERIFY_STATUS_OK; } void -list_append_msg(asl_search_result_t *list, asl_msg_t *msg) +list_append_msg(asl_msg_list_t *list, asl_msg_t *msg) { if (list == NULL) return; if (msg == NULL) return; @@ -951,115 +647,373 @@ list_append_msg(asl_search_result_t *list, asl_msg_t *msg) list->curr += LIST_SIZE_DELTA; } - list->msg[list->count] = msg; + list->msg[list->count] = (asl_msg_t *)msg; list->count++; } void -work_enqueue(asl_msg_t *m) +init_globals(void) { - pthread_mutex_lock(global.work_queue_lock); - list_append_msg(global.work_queue, m); - pthread_mutex_unlock(global.work_queue_lock); - pthread_cond_signal(&global.work_queue_cond); + asl_out_rule_t *r; + + OSSpinLockLock(&global.lock); + + global.pid = getpid(); + global.debug = 0; + free(global.debug_file); + global.debug_file = NULL; + global.launchd_enabled = 1; + +#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) + { + 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); + } + } } -void -asl_enqueue_message(uint32_t source, struct aslevent *e, asl_msg_t *msg) +/* + * Used to set config parameters. + * Line format "= name value" + */ +int +control_set_param(const char *s, bool eval) { - int32_t kplevel; - uint32_t status; + char **l; + uint32_t intval, count, v32a, v32b, v32c; - if (msg == NULL) return; + if (s == NULL) return -1; + if (s[0] == '\0') return 0; + + /* skip '=' and whitespace */ + if (*s == '=') s++; + while ((*s == ' ') || (*s == '\t')) s++; - /* set retain count to 1 */ - msg->type |= 0x10; + l = explode(s, " \t"); + if (l == NULL) return -1; - kplevel = -1; - status = aslmsg_verify(source, e, msg, &kplevel); - if (status == VERIFY_STATUS_OK) + for (count = 0; l[count] != NULL; count++); + + /* name is required */ + if (count == 0) { - if ((source == SOURCE_KERN) && (kplevel >= 0)) notify_post(kern_notify_key[kplevel]); - work_enqueue(msg); + free_string_list(l); + return -1; } - else + + /* Check variables that allow 0 or 1 / boolean */ + if (!strcasecmp(l[0], "debug")) { - asl_msg_release(msg); + /* = 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 + { + intval = (eval) ? 1 : 0; + config_debug(intval, l[1]); + } + + free_string_list(l); + return 0; } -} -asl_msg_t ** -asl_work_dequeue(uint32_t *count) -{ - asl_msg_t **work; + /* value is required */ + if (count == 1) + { + free_string_list(l); + return -1; + } - pthread_mutex_lock(global.work_queue_lock); - pthread_cond_wait(&global.work_queue_cond, global.work_queue_lock); + if (!strcasecmp(l[0], "hostname")) + { + /* = hostname name */ + OSSpinLockLock(&global.lock); + if (eval) + { + global.hostname = strdup(l[1]); + } + else + { + 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 (!strcasecmp(l[0], "utmp_ttl")) + { + /* = 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); - work = NULL; - *count = 0; + 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; + } - if (global.work_queue->count == 0) + pthread_mutex_unlock(global.db_lock); + } + else if ((!strcasecmp(l[0], "db")) || (!strcasecmp(l[0], "database")) || (!strcasecmp(l[0], "datastore"))) { - pthread_mutex_unlock(global.work_queue_lock); - return NULL; + /* 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); + } } - work = global.work_queue->msg; - *count = global.work_queue->count; + free_string_list(l); + return 0; +} + +static int +control_message(asl_msg_t *msg) +{ + const char *str = asl_msg_get_val_for_key(msg, ASL_KEY_MSG); - global.work_queue->count = 0; - global.work_queue->curr = 0; - global.work_queue->msg = NULL; + if (str == NULL) return 0; - pthread_mutex_unlock(global.work_queue_lock); - return work; + 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; } void -aslevent_handleevent(fd_set *rd, fd_set *wr, fd_set *ex) +process_message(asl_msg_t *msg, uint32_t source) { - struct aslevent *e; - char *out = NULL; - asl_msg_t *msg; - int32_t cleanup; + int64_t msize = 0; + static bool wq_draining = false; + bool is_control = false; + asl_msg_t *x; -// asldebug("--> aslevent_handleevent\n"); + if (msg == NULL) return; - cleanup = 0; + 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) { - if (e->fd < 0) + if (global.memory_size >= (global.memory_max / 2)) { - cleanup = 1; - continue; + asldebug("Work queue draining: dropped message.\n"); + asl_msg_release(msg); + return; + } + else + { + asldebug("Work queue re-enabled at 1/2 max. size %lld max %lld\n", global.memory_size, global.memory_max); + wq_draining = false; } + } + + __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); + } + + OSAtomicAdd64(msize, &global.memory_size); + OSAtomicIncrement32(&global.work_queue_count); + + dispatch_async(global.work_queue, ^{ + int32_t kplevel; + uint32_t status; + uid_t uid; + + kplevel = -1; + uid = -2; - 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) continue; + if ((source == SOURCE_KERN) && (kplevel >= 0)) + { + 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); + } - asl_enqueue_message(e->source, e, msg); - } + notify_post(kern_notify_key[kplevel]); + } + + 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\n"); + OSAtomicAdd64(-1ll * msize, &global.memory_size); } - } - if (cleanup != 0) aslevent_cleanup(); + asl_msg_release(msg); -// asldebug("<-- aslevent_handleevent\n"); + 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; @@ -1068,7 +1022,7 @@ asl_log_string(const char *str) msg = asl_msg_from_string(str); if (msg == NULL) return 1; - asl_enqueue_message(SOURCE_INTERNAL, NULL, msg); + process_message(msg, SOURCE_INTERNAL); return 0; } @@ -1077,55 +1031,41 @@ int asldebug(const char *str, ...) { va_list v; - int status; - FILE *dfp; + FILE *dfp = NULL; - OSSpinLockLock(&global.lock); - if (global.debug == 0) - { - OSSpinLockUnlock(&global.lock); - return 0; - } + if (global.debug == 0) return 0; - dfp = stderr; - if (global.debug_file != NULL) dfp = fopen(global.debug_file, "a"); - if (dfp == NULL) - { - OSSpinLockUnlock(&global.lock); - 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); - status = vfprintf(dfp, str, v); + 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); - if (global.debug_file != NULL) fclose(dfp); - OSSpinLockUnlock(&global.lock); + fclose(dfp); - return status; + return 0; } 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; @@ -1136,7 +1076,10 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) if (len <= 0) return NULL; pri = LOG_DEBUG; + if (source == SOURCE_KERN) pri = LOG_NOTICE; + tval = NULL; + hval = NULL; sval = NULL; pval = NULL; mval = NULL; @@ -1145,6 +1088,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++; @@ -1153,6 +1097,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++; @@ -1180,6 +1125,7 @@ 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); @@ -1188,7 +1134,7 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) 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; @@ -1204,26 +1150,41 @@ 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 = asl_msg_new(ASL_TYPE_MSG); if (msg == NULL) return NULL; + 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_MSG, p); - - asl_set(msg, ASL_KEY_LEVEL, prival); + return msg; + } - asl_set(msg, ASL_KEY_PID, "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)) @@ -1275,65 +1236,69 @@ asl_syslog_input_convert(const char *in, int len, char *rhost, int kern) if (fval == NULL) fval = asl_syslog_faciliy_num_to_name(LOG_USER); - msg = (asl_msg_t *)calloc(1, sizeof(asl_msg_t)); + 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"); - - if (rhost == NULL) asl_set(msg, ASL_KEY_HOST, whatsmyhostname()); - else asl_set(msg, ASL_KEY_HOST, rhost); + 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 (msg->count == 0) + if (hval != NULL) { - asl_msg_release(msg); - return 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); } return msg; } asl_msg_t * -asl_input_parse(const char *in, int len, char *rhost, int kern) +asl_input_parse(const char *in, int len, char *rhost, uint32_t source) { - asl_msg_t *m; - int status, x, legacy; + 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; - m = NULL; + msg = NULL; /* calculate length if not provided */ if (len == 0) len = strlen(in); @@ -1341,7 +1306,8 @@ asl_input_parse(const char *in, int len, char *rhost, int kern) /* * 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 starts with a length (10 bytes) followed by a space and a '['. + * 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)) { @@ -1349,70 +1315,20 @@ asl_input_parse(const char *in, int len, char *rhost, int kern) if ((status == 1) && (in[10] == ' ') && (in[11] == '[')) legacy = 0; } - if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, kern); - - m = asl_msg_from_string(in + 11); - if (m == NULL) return NULL; - - if (rhost != NULL) asl_set(m, ASL_KEY_HOST, rhost); - - return m; -} - -char * -get_line_from_file(FILE *f) -{ - char *s, *out; - size_t len; - - out = fgetln(f, &len); - if (out == NULL) return NULL; - if (len == 0) return NULL; - - s = malloc(len + 1); - if (s == NULL) return NULL; - - memcpy(s, out, len); - - s[len - 1] = '\0'; - return s; -} - -uint32_t -asl_msg_type(asl_msg_t *m) -{ - if (m == NULL) return ASL_TYPE_ERROR; - return (m->type & ASL_MSG_TYPE_MASK); -} - -void -asl_msg_release(asl_msg_t *m) -{ - int32_t newval; + if (legacy == 1) return asl_syslog_input_convert(in, len, rhost, source); - if (m == NULL) return; - - newval = OSAtomicAdd32(-0x10, (int32_t*)&m->type) >> 4; - assert(newval >= 0); + off = 11; + if (in[0] == '[') off = 0; - if (newval > 0) return; - - asl_free(m); -} - -asl_msg_t * -asl_msg_retain(asl_msg_t *m) -{ - int32_t newval; - - if (m == NULL) return NULL; + msg = asl_msg_from_string(in + off); + if (msg == NULL) return NULL; - newval = OSAtomicAdd32(0x10, (int32_t*)&m->type) >> 4; - assert(newval > 0); + if (rhost != NULL) asl_msg_set_key_val(msg, ASL_KEY_HOST, rhost); - return m; + return msg; } +#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) { @@ -1420,12 +1336,14 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se char str[256]; time_t now; + if (global.launchd_enabled == 0) return; + /* 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); */ - m = asl_new(ASL_TYPE_MSG); + m = asl_msg_new(ASL_TYPE_MSG); if (m == NULL) return; /* Level */ @@ -1433,63 +1351,60 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se if (priority > ASL_LEVEL_DEBUG) priority = ASL_LEVEL_DEBUG; snprintf(str, sizeof(str), "%d", priority); - asl_set(m, ASL_KEY_LEVEL, str); + asl_msg_set_key_val(m, ASL_KEY_LEVEL, str); /* Time */ if (when != NULL) { - snprintf(str, sizeof(str), "%lu", when->tv_sec); - asl_set(m, ASL_KEY_TIME, str); + snprintf(str, sizeof(str), "%llu", (unsigned long long) when->tv_sec); + asl_msg_set_key_val(m, ASL_KEY_TIME, str); snprintf(str, sizeof(str), "%lu", 1000 * (unsigned long int)when->tv_usec); - asl_set(m, ASL_KEY_TIME_NSEC, str); + asl_msg_set_key_val(m, ASL_KEY_TIME_NSEC, str); } else { now = time(NULL); - snprintf(str, sizeof(str), "%lu", now); - asl_set(m, ASL_KEY_TIME, str); + snprintf(str, sizeof(str), "%llu", (unsigned long long) now); + asl_msg_set_key_val(m, ASL_KEY_TIME, str); } - /* Host */ - asl_set(m, ASL_KEY_HOST, whatsmyhostname()); - /* Facility */ - asl_set(m, ASL_KEY_FACILITY, FACILITY_CONSOLE); + asl_msg_set_key_val(m, ASL_KEY_FACILITY, FACILITY_CONSOLE); /* UID */ snprintf(str, sizeof(str), "%u", (unsigned int)sender_uid); - asl_set(m, ASL_KEY_UID, str); + asl_msg_set_key_val(m, ASL_KEY_UID, str); /* GID */ snprintf(str, sizeof(str), "%u", (unsigned int)sender_gid); - asl_set(m, ASL_KEY_GID, str); + 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_set(m, ASL_KEY_PID, str); + 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_set(m, ASL_KEY_REF_PID, str); + asl_msg_set_key_val(m, ASL_KEY_REF_PID, str); } /* Sender */ if (from_name != NULL) { - asl_set(m, ASL_KEY_SENDER, from_name); + 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_set(m, ASL_KEY_READ_UID, str); + asl_msg_set_key_val(m, ASL_KEY_READ_UID, str); } /* Reference Process */ @@ -1497,31 +1412,23 @@ launchd_callback(struct timeval *when, pid_t from_pid, pid_t about_pid, uid_t se { if ((from_name != NULL) && (strcmp(from_name, about_name) != 0)) { - asl_set(m, ASL_KEY_REF_PROC, about_name); + asl_msg_set_key_val(m, ASL_KEY_REF_PROC, about_name); } } /* Session */ if (session_name != NULL) { - asl_set(m, ASL_KEY_SESSION, session_name); + asl_msg_set_key_val(m, ASL_KEY_SESSION, session_name); } /* Message */ if (msg != NULL) { - asl_set(m, ASL_KEY_MSG, msg); + asl_msg_set_key_val(m, ASL_KEY_MSG, msg); } - /* verify and push to receivers */ - asl_enqueue_message(SOURCE_LAUNCHD, NULL, m); + process_message(m, SOURCE_LAUNCHD); } -void -launchd_drain() -{ - forever - { - _vprocmgr_log_drain(NULL, NULL, launchd_callback); - } -} +#endif