X-Git-Url: https://git.saurik.com/apple/syslog.git/blobdiff_plain/8158235332f5a3f4f20cebe26bf739b481ca2df5..f3df4c032d7a59379e2d8e1a5cf8a8f0e9ea9f63:/aslcommon/asl_common.c diff --git a/aslcommon/asl_common.c b/aslcommon/asl_common.c index a4c21d3..fea5e91 100644 --- a/aslcommon/asl_common.c +++ b/aslcommon/asl_common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include "asl_common.h" @@ -45,6 +46,12 @@ #define _PATH_ASL_CONF "/etc/asl.conf" #define _PATH_ASL_CONF_DIR "/etc/asl" +#define PATH_VAR_LOG "/var/log/" +#define PATH_VAR_LOG_LEN 9 + +#define PATH_LIBRARY_LOGS "/Library/Logs/" +#define PATH_LIBRARY_LOGS_LEN 14 + #if !TARGET_IPHONE_SIMULATOR #define _PATH_ASL_CONF_LOCAL_DIR "/usr/local/etc/asl" #endif @@ -60,6 +67,8 @@ static const char *asl_out_action_name[] = "notify ", "broadcast ", "access ", + "set ", + "unset ", "store ", "asl_file ", "asl_dir ", @@ -71,13 +80,15 @@ static const char *asl_out_action_name[] = "set (profile)" }; -static time_t start_today; - -extern asl_msg_t *asl_msg_from_string(const char *buf); - #define forever for(;;) #define KEYMATCH(S,K) ((strncasecmp(S, K, strlen(K)) == 0)) +#define STAMP_STYLE_INVALID -1 +#define STAMP_STYLE_NULL 0 +#define STAMP_STYLE_SEC 1 +#define STAMP_STYLE_SEQ 2 +#define STAMP_STYLE_UTC_OR_LCL 3 + asl_msg_t * xpc_object_to_asl_msg(xpc_object_t xobj) { @@ -432,8 +443,143 @@ next_word_from_string(char **s) return out; } +static asl_out_dst_data_t * +_asl_out_dest_for_path(asl_out_module_t *m, const char *path) +{ + if (m == NULL) return NULL; + if (path == NULL) return NULL; + + while (m != NULL) + { + asl_out_rule_t *r = m->ruleset; + while (r != NULL) + { + if ((r->action == ACTION_OUT_DEST) && (r->dst != NULL) && (r->dst->path != NULL) && (!strcmp(r->dst->path, path))) return r->dst; + r = r->next; + } + + m = m->next; + } + + return NULL; +} + +/* + * Create a directory path. + * + * mlist provides owner, group, and access mode, which are required for "non-standard" + * directories. Directories for standard paths (/var/log or /Library/Logs) default + * to root/admin/0755 if there is no mlist rule for them. + */ +static int +_asl_common_make_dir_path(asl_out_module_t *mlist, uint32_t flags, const char *path) +{ + int i; + char **path_parts; + asl_string_t *processed_path; + mode_t mode; + + if (path == NULL) return 0; + + path_parts = explode(path, "/"); + if (path_parts == NULL) return 0; + + processed_path = asl_string_new(ASL_ENCODE_NONE); + + i = 0; + if (path[0] == '/') i = 1; + + for (; path_parts[i] != NULL; i++) + { + struct stat sb; + int status; + mode_t mask; + asl_out_dst_data_t *dst; + char *tmp; + + asl_string_append_char_no_encoding(processed_path, '/'); + asl_string_append_no_encoding(processed_path, path_parts[i]); + tmp = asl_string_bytes(processed_path); + + memset(&sb, 0, sizeof(struct stat)); + status = lstat(tmp, &sb); + if ((status == 0) && S_ISLNK(sb.st_mode)) + { + char real[MAXPATHLEN]; + if (realpath(tmp, real) == NULL) + { + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + memset(&sb, 0, sizeof(struct stat)); + status = stat(real, &sb); + } + + if (status == 0) + { + if (!S_ISDIR(sb.st_mode)) + { + /* path component is not a directory! */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + /* exists and is a directory or a link to a directory */ + continue; + } + else if (errno != ENOENT) + { + /* unexpected status from stat() */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + dst = _asl_out_dest_for_path(mlist, tmp); + if ((dst == NULL) && (flags & MODULE_FLAG_NONSTD_DIR)) + { + /* no rule to create a non-standard path component! */ + asl_string_release(processed_path); + free_string_list(path_parts); + return -1; + } + + mode = 0755; + if (dst != NULL) + { + mode = dst->mode; + if (mode == 010000) mode = 0755; + } + + mask = umask(0); + status = mkdir(tmp, mode); + umask(mask); + +#if !TARGET_IPHONE_SIMULATOR + uid_t u = 0; + gid_t g = 80; + + if (dst != NULL) + { + if (dst->nuid > 0) u = dst->uid[0]; + if (dst->ngid > 0) g = dst->gid[0]; + } + + chown(tmp, u, g); +#endif + } + + asl_string_release(processed_path); + free_string_list(path_parts); + + return 0; +} + int -asl_out_mkpath(asl_out_rule_t *r) +asl_out_mkpath(asl_out_module_t *mlist, asl_out_rule_t *r) { char tmp[MAXPATHLEN], *p; struct stat sb; @@ -456,14 +602,18 @@ asl_out_mkpath(asl_out_rule_t *r) status = stat(tmp, &sb); if (status == 0) { - if (!S_ISDIR(sb.st_mode)) return -1; + if (S_ISDIR(sb.st_mode)) return 0; + return -1; } - else if (errno == ENOENT) + + if (errno == ENOENT) { - status = mkpath_np(tmp, 0755); + uint32_t dirflag = r->dst->flags & MODULE_FLAG_NONSTD_DIR; + status = _asl_common_make_dir_path(mlist, dirflag, tmp); + return status; } - return status; + return -1; } void @@ -534,13 +684,16 @@ asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len) if (dst == NULL) return; if (buf == NULL) return; - if (dst->flags & MODULE_FLAG_BASESTAMP) + if (dst->flags & (MODULE_FLAG_BASESTAMP | MODULE_FLAG_TYPE_ASL_DIR)) { char tstamp[32]; + const char *name = dst->path; + + if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) name = dst->fname; if (dst->stamp == 0) dst->stamp = time(NULL); asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp)); - snprintf(buf, len, "%s.%s", dst->path, tstamp); + snprintf(buf, len, "%s.%s", name, tstamp); } else { @@ -549,95 +702,7 @@ asl_make_dst_filename(asl_out_dst_data_t *dst, char *buf, size_t len) } int -asl_out_dst_checkpoint(asl_out_dst_data_t *dst, uint32_t force) -{ - char newpath[MAXPATHLEN]; - time_t now; - - now = time(NULL); - - /* clock went backwards - force a reset */ - if (now < start_today) start_today = 0; - - /* check start_today and reset if required */ - if (now >= (start_today + SECONDS_PER_DAY)) - { - /* use localtime / mktime since start_today might be zero */ - struct tm t; - - start_today = now; - - localtime_r(&start_today, &t); - - t.tm_sec = 0; - t.tm_min = 0; - t.tm_hour = 0; - - start_today = mktime(&t); - } - - /* sleep to prevent a sub-second rotation */ - while (now == dst->stamp) - { - sleep(1); - now = time(NULL); - } - - if ((dst->stamp == 0) || (dst->size == 0)) - { - struct stat sb; - - memset(&sb, 0, sizeof(struct stat)); - - if (stat(dst->path, &sb) < 0) - { - if (errno == ENOENT) return 0; - return -1; - } - - if (dst->stamp == 0) dst->stamp = sb.st_birthtimespec.tv_sec; - if (dst->stamp == 0) dst->stamp = sb.st_mtimespec.tv_sec; - dst->size = sb.st_size; - } - - if (force == CHECKPOINT_TEST) - { - if ((dst->file_max > 0) && (dst->size >= dst->file_max)) force |= CHECKPOINT_SIZE; - if (dst->stamp < start_today) force |= CHECKPOINT_TIME; - - if (force == CHECKPOINT_TEST) return 0; - } - - if (dst->flags & MODULE_FLAG_TYPE_ASL_DIR) - { - if (force & CHECKPOINT_SIZE) - { - snprintf(newpath, sizeof(newpath), "%s.%c%lu", dst->fname, STYLE_SEC_PREFIX_CHAR, dst->stamp); - rename(dst->fname, newpath); - } - else - { - return 0; - } - } - - if ((dst->flags & MODULE_FLAG_BASESTAMP) == 0) - { - char tstamp[32]; - - asl_make_timestamp(dst->stamp, dst->flags, tstamp, sizeof(tstamp)); - snprintf(newpath, sizeof(newpath), "%s.%s", dst->path, tstamp); - rename(dst->path, newpath); - } - - dst->stamp = 0; - dst->size = 0; - - return 1; -} - -int -asl_check_option(aslmsg msg, const char *opt) +asl_check_option(asl_msg_t *msg, const char *opt) { const char *p; uint32_t len; @@ -648,7 +713,7 @@ asl_check_option(aslmsg msg, const char *opt) len = strlen(opt); if (len == 0) return 0; - p = asl_get(msg, ASL_KEY_OPTION); + p = asl_msg_get_val_for_key(msg, ASL_KEY_OPTION); if (p == NULL) return 0; while (*p != '\0') @@ -737,7 +802,7 @@ asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst) * Don't bother setting group access if this is * file's group and the file is group-readable. */ - if ((dst->gid[i] == fgid) && (dst->mode & 0040)) continue; + if ((dst->gid[i] == fgid) && (dst->mode & 00040)) continue; status = mbr_gid_to_uuid(dst->gid[i], uuid); if (status != 0) @@ -770,7 +835,7 @@ asl_out_dst_set_access(int fd, asl_out_dst_data_t *dst) * Don't bother setting user access if this is * file's owner and the file is owner-readable. */ - if ((dst->uid[i] == fuid) && (dst->mode & 0400)) continue; + if ((dst->uid[i] == fuid) && (dst->mode & 00400)) continue; status = mbr_uid_to_uuid(dst->uid[i], uuid); if (status != 0) @@ -812,7 +877,7 @@ asl_file_create_return: /* create a file with acls */ int -asl_out_dst_file_create_open(asl_out_dst_data_t *dst) +asl_out_dst_file_create_open(asl_out_dst_data_t *dst, char **pathp) { int fd, status; struct stat sb; @@ -822,6 +887,12 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst) if (dst->path == NULL) return -1; asl_make_dst_filename(dst, outpath, sizeof(outpath)); + if (dst->fname != NULL) free(dst->fname); + + dst->fname = strdup(outpath); + if (dst->fname == NULL) return -1; + + if (pathp != NULL) *pathp = strdup(outpath); memset(&sb, 0, sizeof(struct stat)); status = stat(outpath, &sb); @@ -845,7 +916,7 @@ asl_out_dst_file_create_open(asl_out_dst_data_t *dst) return -1; } - fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 0666)); + fd = open(outpath, O_RDWR | O_CREAT | O_EXCL, (dst->mode & 00666)); if (fd < 0) return -1; dst->stamp = time(NULL); @@ -1176,6 +1247,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) char *p, *opts, *path; char **path_parts; int has_dotdot, recursion_limit; + uint32_t i, flags = 0; if (m == NULL) return NULL; if (s == NULL) return NULL; @@ -1233,16 +1305,13 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } free_string_list(path_parts); + path_parts = NULL; - if ((did_sub == 0) || (has_dotdot == 1)) - { - path_parts = NULL; - } - else + if ((did_sub == 1) && (has_dotdot == 0)) { /* substitution might have added a ".." so check the new path */ free(path); - path = asl_string_free_return_bytes(processed_path); + path = asl_string_release_return_bytes(processed_path); processed_path = asl_string_new(ASL_ENCODE_NONE); path_parts = explode(path, "/"); recursion_limit--; @@ -1250,14 +1319,16 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } free(path); + free_string_list(path_parts); + path_parts = NULL; if ((has_dotdot != 0) || (recursion_limit == 0)) { - asl_string_free(processed_path); + asl_string_release(processed_path); return NULL; } - path = asl_string_free_return_bytes(processed_path); + path = asl_string_release_return_bytes(processed_path); /* check if there's already a dst for this path */ for (rule = m->ruleset; rule != NULL; rule = rule->next) @@ -1274,20 +1345,38 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } } + flags |= MODULE_FLAG_NONSTD_DIR; + if (path[0] != '/') { char *t = path; const char *log_root = "/var/log"; #if TARGET_IPHONE_SIMULATOR - log_root = getenv("IPHONE_SIMULATOR_LOG_ROOT"); - assert(log_root); + log_root = getenv("SIMULATOR_LOG_ROOT"); + if (log_root == NULL) log_root = "/tmp/log"; #endif - if (!strcmp(m->name, ASL_MODULE_NAME)) asprintf(&path, "%s/%s", log_root, t); - else asprintf(&path, "%s/module/%s/%s", log_root, m->name, t); + if (!strcmp(m->name, ASL_MODULE_NAME)) + { + asprintf(&path, "%s/%s", log_root, t); + } + else + { + asprintf(&path, "%s/module/%s/%s", log_root, m->name, t); + } free(t); + flags &= ~MODULE_FLAG_NONSTD_DIR; + } + else + { + /* + * Standard log directories get marked so that syslogd + * will create them without explicit rules. + */ + if (!strncmp(path, PATH_VAR_LOG, PATH_VAR_LOG_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; + else if (!strncmp(path, PATH_LIBRARY_LOGS, PATH_LIBRARY_LOGS_LEN)) flags &= ~MODULE_FLAG_NONSTD_DIR; } out = (asl_out_rule_t *)calloc(1, sizeof(asl_out_rule_t)); @@ -1303,13 +1392,12 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) dst->refcount = 1; dst->path = path; dst->mode = def_mode; - dst->ttl = DEFAULT_TTL; - dst->flags = MODULE_FLAG_COALESCE; + dst->ttl[LEVEL_ALL] = DEFAULT_TTL; + dst->flags = flags | MODULE_FLAG_COALESCE; while (NULL != (p = next_word_from_string(&opts))) { if (KEYMATCH(p, "mode=")) dst->mode = strtol(p+5, NULL, 0); - else if (KEYMATCH(p, "ttl=")) dst->ttl = strtol(p+4, NULL, 0); #if !TARGET_IPHONE_SIMULATOR else if (KEYMATCH(p, "uid=")) _dst_add_uid(dst, p+4); else if (KEYMATCH(p, "gid=")) _dst_add_gid(dst, p+4); @@ -1326,6 +1414,8 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } else if (KEYMATCH(p, "compress")) dst->flags |= MODULE_FLAG_COMPRESS; else if (KEYMATCH(p, "extern")) dst->flags |= MODULE_FLAG_EXTERNAL; + else if (KEYMATCH(p, "truncate")) dst->flags |= MODULE_FLAG_TRUNCATE; + else if (KEYMATCH(p, "dir")) dst->flags |= MODULE_FLAG_TYPE_ASL_DIR; else if (KEYMATCH(p, "soft")) dst->flags |= MODULE_FLAG_SOFT_WRITE; else if (KEYMATCH(p, "file_max=")) dst->file_max = asl_str_to_size(p+9); else if (KEYMATCH(p, "all_max=")) dst->all_max = asl_str_to_size(p+8); @@ -1375,6 +1465,19 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) { dst->flags |= MODULE_FLAG_BASESTAMP; } + else if (KEYMATCH(p, "ttl")) + { + char *q = p + 3; + if (*q == '=') + { + dst->ttl[LEVEL_ALL] = strtol(p+4, NULL, 0); + } + else if ((*q >= '0') && (*q <= '7') && (*(q+1) == '=')) + { + uint32_t x = *q - '0'; + dst->ttl[x] = strtol(p+5, NULL, 0); + } + } free(p); p = NULL; @@ -1382,7 +1485,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) #if TARGET_OS_EMBEDDED /* check for crashreporter files */ - if (KEYMATCH(dst->path, _PATH_CRASHREPORTER)) + if ((KEYMATCH(dst->path, _PATH_CRASHREPORTER)) || (KEYMATCH(dst->path, _PATH_CRASHREPORTER_MOBILE))) { dst->flags |= MODULE_FLAG_ROTATE; dst->flags |= MODULE_FLAG_CRASHLOG; @@ -1391,6 +1494,9 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) } #endif + /* ttl[LEVEL_ALL] must be max of all level-specific ttls */ + for (i = 0; i <= 7; i++) if (dst->ttl[i] > dst->ttl[LEVEL_ALL]) dst->ttl[LEVEL_ALL] = dst->ttl[i]; + /* default text file format is "std" */ if (dst->fmt == NULL) dst->fmt = strdup("std"); @@ -1398,7 +1504,7 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) if (strcmp(dst->fmt, "std") && strcmp(dst->fmt, "bsd")) dst->flags &= ~MODULE_FLAG_COALESCE; /* note if format is one of std, bsd, or msg */ - if ((!strcmp(dst->fmt, "std")) || (!strcmp(dst->fmt, "bsd")) || (!strcmp(dst->fmt, "msg"))) dst->flags |= MODULE_FLAG_STD_BSD_MSG; + if (!strcmp(dst->fmt, "std") || !strcmp(dst->fmt, "bsd") || !strcmp(dst->fmt, "msg")) dst->flags |= MODULE_FLAG_STD_BSD_MSG; /* MODULE_FLAG_STYLE_SEQ can not be used with MODULE_FLAG_BASESTAMP */ if ((dst->flags & MODULE_FLAG_BASESTAMP) && (dst->flags & MODULE_FLAG_STYLE_SEQ)) @@ -1410,6 +1516,12 @@ _asl_out_module_parse_dst(asl_out_module_t *m, char *s, mode_t def_mode) /* set time format for raw output */ if (!strcmp(dst->fmt, "raw")) dst->tfmt = "sec"; + /* check for ASL_PLACE_DATABASE_DEFAULT */ + if (!strcmp(dst->path, ASL_PLACE_DATABASE_DEFAULT)) + { + dst->flags = MODULE_FLAG_TYPE_ASL_DIR; + } + out->action = ACTION_OUT_DEST; out->dst = dst; @@ -1455,6 +1567,8 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) else if (!strcasecmp(act, "save")) out->action = ACTION_ASL_STORE; else if (!strcasecmp(act, "store")) out->action = ACTION_ASL_STORE; else if (!strcasecmp(act, "access")) out->action = ACTION_ACCESS; + else if (!strcasecmp(act, "set")) out->action = ACTION_SET_KEY; + else if (!strcasecmp(act, "unset")) out->action = ACTION_UNSET_KEY; else if (!strcmp(m->name, ASL_MODULE_NAME)) { /* actions only allowed in com.apple.asl */ @@ -1505,7 +1619,12 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) } /* store /some/path means save to an asl file */ - if ((out->action == ACTION_ASL_STORE) && (out->options != NULL)) out->action = ACTION_ASL_FILE; + if (out->action == ACTION_ASL_STORE) + { + if (out->options == NULL) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, ASL_PLACE_DATABASE_DEFAULT, 0755)); + else if (!strncmp(out->options, ASL_PLACE_DATABASE_DEFAULT, strlen(ASL_PLACE_DATABASE_DEFAULT))) out->dst = asl_out_dst_data_retain(_asl_out_module_parse_dst(m, out->options, 0755)); + else if (out->options != NULL) out->action = ACTION_ASL_FILE; + } if ((out->action == ACTION_FILE) || (out->action == ACTION_ASL_FILE) || (out->action == ACTION_ASL_DIR)) { @@ -1519,6 +1638,12 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) return out; } + /* + * dst might have been set up by a previous ACTION_OUT_DEST ('>') rule with no mode. + * If so, mode would be 010000. Set it now, since we know whether it is a file or dir. + */ + if (out->dst->mode == 010000) out->dst->mode = def_mode; + if ((out->action == ACTION_FILE) && (out->dst != NULL) && (out->dst->fmt != NULL) && (!strcasecmp(out->dst->fmt, "asl"))) { out->action = ACTION_ASL_FILE; @@ -1526,19 +1651,21 @@ _asl_out_module_parse_query_action(asl_out_module_t *m, char *s) if ((out->action == ACTION_ASL_FILE) && (out->dst != NULL)) { - /* remove meaningless flags */ - out->dst->flags &= ~MODULE_FLAG_COALESCE; - out->dst->flags &= ~MODULE_FLAG_STD_BSD_MSG; out->dst->flags |= MODULE_FLAG_TYPE_ASL; } if (out->action == ACTION_ASL_DIR) { - /* remove meaningless flags */ - out->dst->flags &= ~MODULE_FLAG_ROTATE; + /* coalesce is meaningless for ASL directories */ out->dst->flags &= ~MODULE_FLAG_COALESCE; - out->dst->flags &= ~MODULE_FLAG_STD_BSD_MSG; + + /* no compression at this point */ + out->dst->flags &= ~MODULE_FLAG_COMPRESS; + out->dst->flags |= MODULE_FLAG_TYPE_ASL_DIR; + + /* set style bits for basestamp asl_dirs */ + if (((out->dst->flags & MODULE_FLAG_STYLE_BITS) == 0) && (out->dst->flags & MODULE_FLAG_BASESTAMP)) out->dst->flags |= MODULE_FLAG_STYLE_LCL_B; } /* only ACTION_FILE and ACTION_ASL_FILE may rotate */ @@ -1578,7 +1705,7 @@ asl_out_module_parse_line(asl_out_module_t *m, char *s) } else if (*s == '>') { - _asl_out_module_parse_dst(m, s + 1, 0644); + _asl_out_module_parse_dst(m, s + 1, 010000); } return NULL; @@ -1775,7 +1902,7 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) { asl_out_rule_t *r, *n; asl_out_dst_data_t *o; - uint32_t i; + uint32_t i, ttlnset; n = NULL; for (r = m->ruleset; r != NULL; r = n) @@ -1810,9 +1937,9 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%cenabled", c); c = ' '; } - if (o->flags & MODULE_FLAG_LOCAL) + if (o->flags & MODULE_FLAG_SOFT_WRITE) { - fprintf(f, "%clocal", c); + fprintf(f, "%csoft", c); c = ' '; } if (o->flags & MODULE_FLAG_ROTATE) @@ -1830,11 +1957,6 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%ccompress", c); c = ' '; } - if (o->flags & MODULE_FLAG_EXTERNAL) - { - fprintf(f, "%cexternal", c); - c = ' '; - } if (o->flags & MODULE_FLAG_STYLE_SEC) { fprintf(f, "%cseconds", c); @@ -1870,14 +1992,19 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%cbasestamp", c); c = ' '; } - if (o->flags & MODULE_FLAG_CRASHLOG) + if (o->flags & MODULE_FLAG_NONSTD_DIR) { - fprintf(f, "%ccrashlog", c); + fprintf(f, "%cnon-std_dir", c); c = ' '; } - if (o->flags & MODULE_FLAG_SOFT_WRITE) + if (o->flags & MODULE_FLAG_EXTERNAL) { - fprintf(f, "%csoft", c); + fprintf(f, "%cexternal", c); + c = ' '; + } + if (o->flags & MODULE_FLAG_CRASHLOG) + { + fprintf(f, "%ccrashlog", c); c = ' '; } if (o->flags & MODULE_FLAG_TYPE_ASL) @@ -1890,16 +2017,16 @@ asl_out_module_print(FILE *f, asl_out_module_t *m) fprintf(f, "%casl_directory", c); c = ' '; } - if (o->flags & MODULE_FLAG_STD_BSD_MSG) - { - fprintf(f, "%cstd/bsd/msg", c); - c = ' '; - } fprintf(f, ")"); } fprintf(f, "\n"); - fprintf(f, " ttl: %u\n", o->ttl); + fprintf(f, " ttl: %u", o->ttl[LEVEL_ALL]); + ttlnset = 0; + for (i = 0; (i <= 7) & (ttlnset == 0); i++) if (o->ttl[i] != 0) ttlnset = 1; + if (ttlnset != 0) for (i = 0; i <= 7; i++) printf(" [%d %d]", i, (o->ttl[i] == 0) ? o->ttl[LEVEL_ALL] : o->ttl[i]); + fprintf(f, "\n"); + fprintf(f, " mode: 0%o\n", o->mode); fprintf(f, " file_max: %lu\n", o->file_max); fprintf(f, " all_max: %lu\n", o->all_max); @@ -2033,6 +2160,104 @@ _check_file_name(const char *name, const char *base, bool src, char **stamp) * MODULE_FLAG_STYLE_LCL_B requires a date/time component as the file's timestamp. * E.g. foo.20120406T153000-07 */ +int +_parse_stamp_style(char *stamp, uint32_t flags, uint32_t *sp, time_t *tp) +{ + int i, n; + bool digits; + struct tm t; + char zone; + uint32_t h, m, s; + long utc_offset = 0; + time_t ftime = 0; + + /* check for NULL (no stamp) */ + if (stamp == NULL) return STAMP_STYLE_NULL; + + /* check for MODULE_FLAG_STYLE_SEC (foo.T12345678) */ + if (stamp[0] == 'T') + { + n = atoi(stamp + 1); + if ((n == 0) && strcmp(stamp + 1, "0")) return STAMP_STYLE_INVALID; + if (tp != NULL) *tp = (time_t)n; + + return STAMP_STYLE_SEC; + } + + /* check for MODULE_FLAG_STYLE_SEQ (foo.0 or foo.2.gz) */ + digits = true; + for (i = 0; digits && (stamp[i] != '\0'); i++) digits = (stamp[i] >= '0') && (stamp[i] <= '9'); + + if (!digits && (!strcmp(stamp + i, ".gz"))) digits = true; + + if (digits) + { + n = atoi(stamp); + if (sp != NULL) *sp = (uint32_t)n; + return STAMP_STYLE_SEQ; + } + + /* check for MODULE_FLAG_STYLE_UTC, UTC_B, LCL, or LCL_B */ + memset(&t, 0, sizeof(t)); + h = m = s = 0; + + n = 0; + if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) + { + n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); + } + else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) + { + n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); + } + else + { + return STAMP_STYLE_INVALID; + } + + if (n < 6) return STAMP_STYLE_INVALID; + + if (n == 6) + { + zone = 'J'; + } + else if ((zone == '-') || (zone == '+')) + { + if (n >= 8) utc_offset += (3600 * h); + if (n >= 9) utc_offset += (60 * m); + if (n == 10) utc_offset += s; + if (zone == '-') utc_offset *= -1; + } + else if ((zone >= 'A') && (zone <= 'Z')) + { + if (zone < 'J') utc_offset = 3600 * ((zone - 'A') + 1); + else if ((zone >= 'K') && (zone <= 'M')) utc_offset = 3600 * (zone - 'A'); + else if (zone <= 'Y') utc_offset = -3600 * ((zone - 'N') + 1); + } + else if ((zone >= 'a') && (zone <= 'z')) + { + if (zone < 'j') utc_offset = 3600 * ((zone - 'a') + 1); + else if ((zone >= 'k') && (zone <= 'm')) utc_offset = 3600 * (zone - 'a'); + else if (zone <= 'y') utc_offset = -3600 * ((zone - 'n') + 1); + } + else + { + return STAMP_STYLE_INVALID; + } + + t.tm_year -= 1900; + t.tm_mon -= 1; + t.tm_sec += utc_offset; + t.tm_isdst = -1; + + if ((zone == 'J') || (zone == 'j')) ftime = mktime(&t); + else ftime = timegm(&t); + + if (tp != NULL) *tp = ftime; + + return STAMP_STYLE_UTC_OR_LCL; +} + asl_out_file_list_t * asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) { @@ -2042,7 +2267,7 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) uint32_t seq; time_t ftime; struct stat sb; - int n; + int pstyle, fstyle; asl_out_file_list_t *out, *x, *y; if (dir == NULL) return NULL; @@ -2063,90 +2288,33 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) check = _check_file_name(ent->d_name, base, src, &stamp); if (!check) continue; - /* exclude base from dst list */ - seq = IndexNull; ftime = 0; - if (stamp == NULL) - { - } - else if (flags & MODULE_FLAG_STYLE_SEQ) - { - seq = atoi(stamp); - if ((seq == 0) && strcmp(stamp, "0")) - { - free(stamp); - continue; - } - } - else if (flags & MODULE_FLAG_STYLE_SEC) - { - ftime = atoi(stamp + 1); - } - else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL) || (flags & MODULE_FLAG_STYLE_LCL_B)) - { - struct tm t; - char zone; - uint32_t h, m, s; - long utc_offset = 0; - - memset(&t, 0, sizeof(t)); - h = m = s = 0; + pstyle = _parse_stamp_style(stamp, flags, &seq, &ftime); + free(stamp); - n = 0; - if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) - { - n = sscanf(stamp, "%d-%d-%dT%d:%d:%d%c%u:%u:%u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); - } - else - { - n = sscanf(stamp, "%4d%2d%2dT%2d%2d%2d%c%2u%2u%2u", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &zone, &h, &m, &s); - } + if (pstyle == STAMP_STYLE_INVALID) continue; - if (n < 6) - { - continue; - } - else if (n == 6) - { - zone = 'J'; - } - else if ((zone == '-') || (zone == '+')) - { - if (n >= 8) utc_offset += (3600 * h); - if (n >= 9) utc_offset += (60 * m); - if (n == 10) utc_offset += s; - if (zone == '-') utc_offset *= -1; - } - else if ((zone >= 'A') && (zone <= 'Z')) - { - if (zone < 'J') utc_offset = 3600 * ((zone - 'A') + 1); - else if ((zone >= 'K') && (zone <= 'M')) utc_offset = 3600 * (zone - 'A'); - else if (zone <= 'Y') utc_offset = -3600 * ((zone - 'N') + 1); - } - else if ((zone >= 'a') && (zone <= 'z')) - { - if (zone < 'j') utc_offset = 3600 * ((zone - 'a') + 1); - else if ((zone >= 'k') && (zone <= 'm')) utc_offset = 3600 * (zone - 'a'); - else if (zone <= 'y') utc_offset = -3600 * ((zone - 'n') + 1); - } - else - { - free(stamp); - continue; - } + fstyle = STAMP_STYLE_NULL; + if (flags & MODULE_FLAG_STYLE_SEC) fstyle = STAMP_STYLE_SEC; + else if (flags & MODULE_FLAG_STYLE_SEQ) fstyle = STAMP_STYLE_SEQ; + else if ((flags & MODULE_FLAG_STYLE_UTC) || (flags & MODULE_FLAG_STYLE_LCL)) fstyle = STAMP_STYLE_UTC_OR_LCL; + else if ((flags & MODULE_FLAG_STYLE_UTC_B) || (flags & MODULE_FLAG_STYLE_LCL_B)) fstyle = STAMP_STYLE_UTC_OR_LCL; - t.tm_year -= 1900; - t.tm_mon -= 1; - t.tm_sec += utc_offset; - t.tm_isdst = -1; + /* + * accept the file if: + * style is STAMP_STYLE_NULL (no timestamp) + * src is true and style is STAMP_STYLE_SEC + * actual style matches the style implied by the input flags + */ - if ((zone == 'J') || (zone == 'j')) ftime = mktime(&t); - else ftime = timegm(&t); - } + check = false; + if (pstyle == STAMP_STYLE_NULL) check = true; + if ((pstyle == STAMP_STYLE_SEC) && src) check = true; + if (pstyle == fstyle) check = true; - free(stamp); + if (!check) continue; x = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (x == NULL) @@ -2164,14 +2332,14 @@ asl_list_log_files(const char *dir, const char *base, bool src, uint32_t flags) if (stat(path, &sb) == 0) { x->size = sb.st_size; - if (flags & MODULE_FLAG_STYLE_SEQ) + if (pstyle == STAMP_STYLE_SEQ) { x->ftime = sb.st_birthtimespec.tv_sec; if (x->ftime == 0) x->ftime = sb.st_mtimespec.tv_sec; } } - if (flags & MODULE_FLAG_STYLE_SEQ) + if (pstyle == STAMP_STYLE_SEQ) { if (out == NULL) { @@ -2258,7 +2426,7 @@ asl_list_src_files(asl_out_dst_data_t *dst) /* * MODULE_FLAG_EXTERNAL means some process other than syslogd writes the file. - * We simply check for its existence. + * We check for its existence, and that it is non-zero in size. */ if (dst->flags & MODULE_FLAG_EXTERNAL) { @@ -2268,7 +2436,7 @@ asl_list_src_files(asl_out_dst_data_t *dst) if (stat(dst->path, &sb) == 0) { - if (S_ISREG(sb.st_mode)) + if (S_ISREG(sb.st_mode) && (sb.st_size != 0)) { out = (asl_out_file_list_t *)calloc(1, sizeof(asl_out_file_list_t)); if (out != NULL) @@ -2350,3 +2518,78 @@ asl_list_dst_files(asl_out_dst_data_t *dst) return out; } + +static int +asl_secure_open_dir(const char *path) +{ + int fd, i; + char **path_parts; + + if (path == NULL) return -1; + if (path[0] != '/') return -1; + + path_parts = explode(path + 1, "/"); + if (path_parts == NULL) return 0; + + fd = open("/", O_RDONLY | O_NOFOLLOW, 0); + if (fd < 0) + { + free_string_list(path_parts); + return -1; + } + + for (i = 0; path_parts[i] != NULL; i++) + { + int fd_next, status; + struct stat sb; + + fd_next = openat(fd, path_parts[i], O_RDONLY | O_NOFOLLOW, 0); + close(fd); + fd = fd_next; + if (fd < 0) + { + free_string_list(path_parts); + return -1; + } + + memset(&sb, 0, sizeof(sb)); + + status = fstat(fd, &sb); + if (status < 0) + { + free_string_list(path_parts); + return -1; + } + + if (!S_ISDIR(sb.st_mode)) + { + free_string_list(path_parts); + return -1; + } + } + + free_string_list(path_parts); + return fd; +} + +int +asl_secure_chown_chmod_dir(const char *path, uid_t uid, gid_t gid, mode_t mode) +{ + int fd, status; + + fd = asl_secure_open_dir(path); + if (fd < 0) return fd; + + status = fchown(fd, uid, gid); + if (status < 0) + { + close(fd); + return -1; + } + + if (mode >= 0) status = fchmod(fd, mode); + close(fd); + + if (status < 0) return -1; + return 0; +}