Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/syslogd/syslogd.c
| Show First 20 Lines • Show All 125 Lines • ▼ Show 20 Lines | |||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <utmpx.h> | #include <utmpx.h> | ||||
| #include "pathnames.h" | #include "pathnames.h" | ||||
| #include "syslogd.h" | #include "syslogd.h" | ||||
| #include "syslogd_cap.h" | #include "syslogd_cap.h" | ||||
| #include "ttymsg.h" | #include "ttymsg.h" | ||||
| static const char *ConfFile = _PATH_LOGCONF; | const char *ConfFile = _PATH_LOGCONF; | ||||
| static const char *PidFile = _PATH_LOGPID; | static const char *PidFile = _PATH_LOGPID; | ||||
| static const char include_str[] = "include"; | static const char include_str[] = "include"; | ||||
| static const char include_ext[] = ".conf"; | static const char include_ext[] = ".conf"; | ||||
| #define dprintf if (Debug) printf | #define dprintf if (Debug) printf | ||||
| #define sstosa(ss) ((struct sockaddr *)(ss)) | #define sstosa(ss) ((struct sockaddr *)(ss)) | ||||
| #ifdef INET | #ifdef INET | ||||
| ▲ Show 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | static const int sigcatch[] = { | ||||
| SIGTERM, | SIGTERM, | ||||
| SIGCHLD, | SIGCHLD, | ||||
| }; | }; | ||||
| static int nulldesc; /* /dev/null descriptor */ | static int nulldesc; /* /dev/null descriptor */ | ||||
| static bool Debug; /* debug flag */ | static bool Debug; /* debug flag */ | ||||
| static bool Foreground = false; /* Run in foreground, instead of daemonizing */ | static bool Foreground = false; /* Run in foreground, instead of daemonizing */ | ||||
| static bool resolve = true; /* resolve hostname */ | static bool resolve = true; /* resolve hostname */ | ||||
| static char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ | char LocalHostName[MAXHOSTNAMELEN]; /* our hostname */ | ||||
| static const char *LocalDomain; /* our local domain name */ | static const char *LocalDomain; /* our local domain name */ | ||||
| static bool Initialized; /* set when we have initialized ourselves */ | static bool Initialized; /* set when we have initialized ourselves */ | ||||
| static int MarkInterval = 20 * 60; /* interval between marks in seconds */ | static int MarkInterval = 20 * 60; /* interval between marks in seconds */ | ||||
| static int MarkSeq; /* mark sequence number */ | static int MarkSeq; /* mark sequence number */ | ||||
| static bool NoBind; /* don't bind() as suggested by RFC 3164 */ | static bool NoBind; /* don't bind() as suggested by RFC 3164 */ | ||||
| static int SecureMode; /* when true, receive only unix domain socks */ | static int SecureMode; /* when true, receive only unix domain socks */ | ||||
| static int MaxForwardLen = 1024; /* max length of forwared message */ | static int MaxForwardLen = 1024; /* max length of forwared message */ | ||||
| #ifdef INET6 | #ifdef INET6 | ||||
| Show All 20 Lines | |||||
| static struct pidfh *pfh; | static struct pidfh *pfh; | ||||
| static bool RFC3164OutputFormat = true; /* Use legacy format by default. */ | static bool RFC3164OutputFormat = true; /* Use legacy format by default. */ | ||||
| struct iovlist; | struct iovlist; | ||||
| static bool allowaddr(char *); | static bool allowaddr(char *); | ||||
| static void addpeer(const char *, const char *, mode_t); | static void addpeer(const char *, const char *, mode_t); | ||||
| static void addsock(const char *, const char *, mode_t); | static void addsock(const char *, const char *, mode_t); | ||||
| static void cfline(const char *, const char *, const char *, const char *); | static nvlist_t *cfline(const char *, const char *, const char *, const char *); | ||||
| static const char *cvthname(struct sockaddr *); | static const char *cvthname(struct sockaddr *); | ||||
| static void deadq_enter(int); | static void deadq_enter(int); | ||||
| static void deadq_remove(struct deadq_entry *); | static void deadq_remove(struct deadq_entry *); | ||||
| static int decode(const char *, const CODE *); | static int decode(const char *, const CODE *); | ||||
| static void die(int) __dead2; | static void die(int) __dead2; | ||||
| static void dofsync(void); | static void dofsync(void); | ||||
| static void fprintlog_first(struct filed *, const char *, const char *, | static void fprintlog_first(struct filed *, const char *, const char *, | ||||
| const char *, const char *, const char *, const char *, int); | const char *, const char *, const char *, const char *, int); | ||||
| static void fprintlog_write(struct filed *, struct iovlist *, int); | static void fprintlog_write(struct filed *, struct iovlist *, int); | ||||
| static void fprintlog_successive(struct filed *, int); | static void fprintlog_successive(struct filed *, int); | ||||
| static void init(bool); | static void init(bool); | ||||
| static void logerror(const char *); | |||||
| static void logmsg(int, const struct logtime *, const char *, const char *, | static void logmsg(int, const struct logtime *, const char *, const char *, | ||||
| const char *, const char *, const char *, const char *, int); | const char *, const char *, const char *, const char *, int); | ||||
| static void markit(void); | static void markit(void); | ||||
| static struct socklist *socksetup(struct addrinfo *, const char *, mode_t); | static struct socklist *socksetup(struct addrinfo *, const char *, mode_t); | ||||
| static int socklist_recv_file(struct socklist *); | static int socklist_recv_file(struct socklist *); | ||||
| static int socklist_recv_sock(struct socklist *); | static int socklist_recv_sock(struct socklist *); | ||||
| static int skip_message(const char *, const char *, int); | static int skip_message(const char *, const char *, int); | ||||
| static int evaluate_prop_filter(const struct prop_filter *filter, | static int evaluate_prop_filter(const struct prop_filter *filter, | ||||
| const char *value); | const char *value); | ||||
| static struct prop_filter *prop_filter_compile(const char *); | static nvlist_t *prop_filter_compile(const char *); | ||||
| static void parsemsg(const char *, char *); | static void parsemsg(const char *, char *); | ||||
| static void printsys(char *); | static void printsys(char *); | ||||
| static int p_open(const char *, pid_t *); | static int p_open(const char *, pid_t *); | ||||
| static const char *ttymsg_check(struct iovec *, int, char *, int); | static const char *ttymsg_check(struct iovec *, int, char *, int); | ||||
| static void usage(void); | static void usage(void); | ||||
| static bool validate(struct sockaddr *, const char *); | static bool validate(struct sockaddr *, const char *); | ||||
| static void unmapped(struct sockaddr *); | static void unmapped(struct sockaddr *); | ||||
| static void wallmsg(struct filed *, struct iovec *, const int iovlen); | static void wallmsg(struct filed *, struct iovec *, const int iovlen); | ||||
| ▲ Show 20 Lines • Show All 1,035 Lines • ▼ Show 20 Lines | |||||
| static int | static int | ||||
| skip_message(const char *name, const char *spec, int checkcase) | skip_message(const char *name, const char *spec, int checkcase) | ||||
| { | { | ||||
| const char *s; | const char *s; | ||||
| char prev, next; | char prev, next; | ||||
| int exclude = 0; | int exclude = 0; | ||||
| /* Behaviour on explicit match */ | /* Behaviour on explicit match */ | ||||
| if (spec == NULL) | if (spec == NULL || *spec == '\0') | ||||
| return (0); | return (0); | ||||
| switch (*spec) { | switch (*spec) { | ||||
| case '-': | case '-': | ||||
| exclude = 1; | exclude = 1; | ||||
| /*FALLTHROUGH*/ | /*FALLTHROUGH*/ | ||||
| case '+': | case '+': | ||||
| spec++; | spec++; | ||||
| break; | break; | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | if (filter->cmp_type == FILT_CMP_REGEX) { | ||||
| else | else | ||||
| return (!exclude); | return (!exclude); | ||||
| } | } | ||||
| valuelen = strlen(value); | valuelen = strlen(value); | ||||
| /* a shortcut for equal with different length is always false */ | /* a shortcut for equal with different length is always false */ | ||||
| if (filter->cmp_type == FILT_CMP_EQUAL && | if (filter->cmp_type == FILT_CMP_EQUAL && | ||||
| valuelen != filter->pflt_strlen) | valuelen != strlen(filter->pflt_strval)) | ||||
| return (!exclude); | return (!exclude); | ||||
| if (filter->cmp_flags & FILT_FLAG_ICASE) | if (filter->cmp_flags & FILT_FLAG_ICASE) | ||||
| s = strcasestr(value, filter->pflt_strval); | s = strcasestr(value, filter->pflt_strval); | ||||
| else | else | ||||
| s = strstr(value, filter->pflt_strval); | s = strstr(value, filter->pflt_strval); | ||||
| /* | /* | ||||
| ▲ Show 20 Lines • Show All 716 Lines • ▼ Show 20 Lines | cvthname(struct sockaddr *f) | ||||
| if (RFC3164OutputFormat) | if (RFC3164OutputFormat) | ||||
| trimdomain(hname, hl); | trimdomain(hname, hl); | ||||
| return (hname); | return (hname); | ||||
| } | } | ||||
| /* | /* | ||||
| * Print syslogd errors some place. | * Print syslogd errors some place. | ||||
| */ | */ | ||||
| static void | void | ||||
| logerror(const char *msg) | logerror(const char *msg) | ||||
| { | { | ||||
| char buf[512]; | char buf[512]; | ||||
| static int recursed = 0; | static int recursed = 0; | ||||
| /* If there's an error while trying to log an error, give up. */ | /* If there's an error while trying to log an error, give up. */ | ||||
| if (recursed) | if (recursed) | ||||
| return; | return; | ||||
| ▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | configfiles(const struct dirent *dp) | ||||
| p = &dp->d_name[dp->d_namlen - ext_len]; | p = &dp->d_name[dp->d_namlen - ext_len]; | ||||
| if (strcmp(p, include_ext) != 0) | if (strcmp(p, include_ext) != 0) | ||||
| return (0); | return (0); | ||||
| return (1); | return (1); | ||||
| } | } | ||||
| static void | static nvlist_t * | ||||
| parseconfigfile(FILE *cf, bool allow_includes) | parseconfigfile(FILE *cf, bool allow_includes, nvlist_t *nvl_conf) | ||||
| { | { | ||||
| FILE *cf2; | FILE *cf2; | ||||
| struct dirent **ent; | struct dirent **ent; | ||||
| char cline[LINE_MAX]; | char cline[LINE_MAX]; | ||||
| char host[MAXHOSTNAMELEN]; | char host[MAXHOSTNAMELEN]; | ||||
| char prog[LINE_MAX]; | char prog[LINE_MAX]; | ||||
| char file[MAXPATHLEN]; | char file[MAXPATHLEN]; | ||||
| char pfilter[LINE_MAX]; | char pfilter[LINE_MAX]; | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (allow_includes && | ||||
| free(ent[i]); | free(ent[i]); | ||||
| continue; | continue; | ||||
| } | } | ||||
| free(ent[i]); | free(ent[i]); | ||||
| cf2 = fopen(file, "r"); | cf2 = fopen(file, "r"); | ||||
| if (cf2 == NULL) | if (cf2 == NULL) | ||||
| continue; | continue; | ||||
| dprintf("reading %s\n", file); | dprintf("reading %s\n", file); | ||||
| parseconfigfile(cf2, false); | parseconfigfile(cf2, false, nvl_conf); | ||||
| fclose(cf2); | fclose(cf2); | ||||
| } | } | ||||
| free(ent); | free(ent); | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (*p == '#') { | if (*p == '#') { | ||||
| p++; | p++; | ||||
| if (*p == '\0' || strchr("!+-:", *p) == NULL) | if (*p == '\0' || strchr("!+-:", *p) == NULL) | ||||
| ▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | for (p = cline + 1; *p != '\0'; p++) { | ||||
| p--; | p--; | ||||
| continue; | continue; | ||||
| } | } | ||||
| *p = '\0'; | *p = '\0'; | ||||
| break; | break; | ||||
| } | } | ||||
| for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--) | for (i = strlen(cline) - 1; i >= 0 && isspace(cline[i]); i--) | ||||
| cline[i] = '\0'; | cline[i] = '\0'; | ||||
| cfline(cline, prog, host, pfilter); | nvlist_append_nvlist_array(nvl_conf, "filed_list", | ||||
| cfline(cline, prog, host, pfilter)); | |||||
| } | } | ||||
| return (nvl_conf); | |||||
| } | } | ||||
| static void | nvlist_t * | ||||
| readconfigfile(const char *path) | readconfigfile(const char *path) | ||||
| { | { | ||||
| FILE *cf; | FILE *cf; | ||||
| nvlist_t *nvl_conf = nvlist_create(0); | |||||
| if ((cf = fopen(path, "r")) != NULL) { | if ((cf = fopen(path, "r")) != NULL) { | ||||
| parseconfigfile(cf, true); | nvl_conf = parseconfigfile(cf, true, nvl_conf); | ||||
| (void)fclose(cf); | (void)fclose(cf); | ||||
| } else { | } else { | ||||
| dprintf("cannot open %s\n", ConfFile); | dprintf("cannot open %s\n", path); | ||||
| cfline("*.ERR\t/dev/console", "*", "*", "*"); | nvlist_append_nvlist_array(nvl_conf, "filed_list", | ||||
| cfline("*.PANIC\t*", "*", "*", "*"); | cfline("*.ERR\t/dev/console", "*", "*", "*")); | ||||
| nvlist_append_nvlist_array(nvl_conf, "filed_list", | |||||
| cfline("*.PANIC\t*", "*", "*", "*")); | |||||
| } | } | ||||
| return (nvl_conf); | |||||
| } | } | ||||
| static void | |||||
| fill_flist(nvlist_t *nvl_conf) | |||||
| { | |||||
| const nvlist_t * const *filed_list; | |||||
| size_t nfileds; | |||||
| if (!nvlist_exists_nvlist_array(nvl_conf, "filed_list")) | |||||
| return; | |||||
| filed_list = nvlist_get_nvlist_array(nvl_conf, "filed_list", | |||||
| &nfileds); | |||||
| for (size_t i = 0; i < nfileds; ++i) { | |||||
| struct filed *f; | |||||
| f = nvlist_to_filed(filed_list[i]); | |||||
| STAILQ_INSERT_TAIL(&fhead, f, next); | |||||
| } | |||||
| nvlist_destroy(nvl_conf); | |||||
| } | |||||
| /* | /* | ||||
| * Close all open log files. | * Close all open log files. | ||||
| */ | */ | ||||
| static void | void | ||||
| closelogfiles(void) | closelogfiles(void) | ||||
| { | { | ||||
| struct filed *f; | struct filed *f; | ||||
| while (!STAILQ_EMPTY(&fhead)) { | while (!STAILQ_EMPTY(&fhead)) { | ||||
| f = STAILQ_FIRST(&fhead); | f = STAILQ_FIRST(&fhead); | ||||
| STAILQ_REMOVE_HEAD(&fhead, next); | STAILQ_REMOVE_HEAD(&fhead, next); | ||||
| /* flush any pending output */ | /* flush any pending output */ | ||||
| if (f->f_prevcount) | if (f->f_prevcount) | ||||
| fprintlog_successive(f, 0); | fprintlog_successive(f, 0); | ||||
| switch (f->f_type) { | switch (f->f_type) { | ||||
| case F_FILE: | case F_FILE: | ||||
| case F_FORW: | case F_FORW: | ||||
| case F_CONSOLE: | case F_CONSOLE: | ||||
| case F_TTY: | case F_TTY: | ||||
| case F_PIPE: | case F_PIPE: | ||||
| close_filed(f); | close_filed(f); | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| free(f->f_program); | |||||
| free(f->f_host); | |||||
| if (f->f_prop_filter) { | if (f->f_prop_filter) { | ||||
| switch (f->f_prop_filter->cmp_type) { | switch (f->f_prop_filter->cmp_type) { | ||||
| case FILT_CMP_REGEX: | case FILT_CMP_REGEX: | ||||
| regfree(f->f_prop_filter->pflt_re); | regfree(f->f_prop_filter->pflt_re); | ||||
| free(f->f_prop_filter->pflt_re); | free(f->f_prop_filter->pflt_re); | ||||
| break; | /* FALLTHROUGH */ | ||||
| case FILT_CMP_CONTAINS: | case FILT_CMP_CONTAINS: | ||||
| case FILT_CMP_EQUAL: | case FILT_CMP_EQUAL: | ||||
| case FILT_CMP_STARTS: | case FILT_CMP_STARTS: | ||||
| free(f->f_prop_filter->pflt_strval); | free(f->f_prop_filter->pflt_strval); | ||||
| break; | break; | ||||
| } | } | ||||
| free(f->f_prop_filter); | free(f->f_prop_filter); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | init(bool reload) | ||||
| } else { | } else { | ||||
| setenv("TZ", ":/etc/localtime", 1); | setenv("TZ", ":/etc/localtime", 1); | ||||
| tzset(); | tzset(); | ||||
| unsetenv("TZ"); | unsetenv("TZ"); | ||||
| } | } | ||||
| Initialized = false; | Initialized = false; | ||||
| closelogfiles(); | closelogfiles(); | ||||
| readconfigfile(ConfFile); | fill_flist(readconfigfile(ConfFile)); | ||||
| Initialized = true; | Initialized = true; | ||||
| if (Debug) { | if (Debug) { | ||||
| struct filed *f; | struct filed *f; | ||||
| int port; | int port; | ||||
| STAILQ_FOREACH(f, &fhead, next) { | STAILQ_FOREACH(f, &fhead, next) { | ||||
| for (i = 0; i <= LOG_NFACILITIES; i++) | for (i = 0; i <= LOG_NFACILITIES; i++) | ||||
| Show All 40 Lines | #endif | ||||
| case F_USERS: | case F_USERS: | ||||
| for (i = 0; i < MAXUNAMES && *f->f_uname[i]; i++) | for (i = 0; i < MAXUNAMES && *f->f_uname[i]; i++) | ||||
| printf("%s, ", f->f_uname[i]); | printf("%s, ", f->f_uname[i]); | ||||
| break; | break; | ||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| if (f->f_program) | if (*f->f_program != '\0') | ||||
| printf(" (%s)", f->f_program); | printf(" (%s)", f->f_program); | ||||
| printf("\n"); | printf("\n"); | ||||
| } | } | ||||
| } | } | ||||
| logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd", NULL, | logmsg(LOG_SYSLOG | LOG_INFO, NULL, LocalHostName, "syslogd", NULL, | ||||
| NULL, NULL, "restart", 0); | NULL, NULL, "restart", 0); | ||||
| dprintf("syslogd: restarted\n"); | dprintf("syslogd: restarted\n"); | ||||
| Show All 19 Lines | logmsg(LOG_KERN | LOG_INFO, NULL, LocalHostName, "syslogd", | ||||
| NULL, NULL, NULL, bootfileMsg, 0); | NULL, NULL, NULL, bootfileMsg, 0); | ||||
| dprintf("%s\n", bootfileMsg); | dprintf("%s\n", bootfileMsg); | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Compile property-based filter. | * Compile property-based filter. | ||||
| */ | */ | ||||
| static struct prop_filter * | static nvlist_t * | ||||
| prop_filter_compile(const char *cfilter) | prop_filter_compile(const char *cfilter) | ||||
| { | { | ||||
| struct prop_filter *pfilter; | nvlist_t *nvl_pfilter; | ||||
| struct prop_filter pfilter = { }; | |||||
| char *filter, *filter_endpos, *filter_begpos, *p; | char *filter, *filter_endpos, *filter_begpos, *p; | ||||
| char **ap, *argv[2] = {NULL, NULL}; | char **ap, *argv[2] = {NULL, NULL}; | ||||
| int re_flags = REG_NOSUB; | |||||
| int escaped; | int escaped; | ||||
| pfilter = calloc(1, sizeof(*pfilter)); | |||||
| if (pfilter == NULL) { | |||||
| logerror("pfilter calloc"); | |||||
| exit(1); | |||||
| } | |||||
| if (*cfilter == '*') { | |||||
| pfilter->prop_type = FILT_PROP_NOOP; | |||||
| return (pfilter); | |||||
| } | |||||
| filter = strdup(cfilter); | filter = strdup(cfilter); | ||||
| if (filter == NULL) { | if (filter == NULL) | ||||
| logerror("strdup"); | err(1, "strdup"); | ||||
| exit(1); | |||||
| } | |||||
| filter_begpos = filter; | filter_begpos = filter; | ||||
| /* | /* | ||||
| * Here's some filter examples mentioned in syslog.conf(5) | * Here's some filter examples mentioned in syslog.conf(5) | ||||
| * 'msg, contains, ".*Deny.*"' | * 'msg, contains, ".*Deny.*"' | ||||
| * 'programname, regex, "^bird6?$"' | * 'programname, regex, "^bird6?$"' | ||||
| * 'hostname, icase_ereregex, "^server-(dcA|podB)-rack1[0-9]{2}\\..*"' | * 'hostname, icase_ereregex, "^server-(dcA|podB)-rack1[0-9]{2}\\..*"' | ||||
| */ | */ | ||||
| /* | /* | ||||
| * Split filter into 3 parts: property name (argv[0]), | * Split filter into 3 parts: property name (argv[0]), | ||||
| * cmp type (argv[1]) and lvalue for comparison (filter). | * cmp type (argv[1]) and lvalue for comparison (filter). | ||||
| */ | */ | ||||
| for (ap = argv; (*ap = strsep(&filter, ", \t\n")) != NULL;) { | for (ap = argv; (*ap = strsep(&filter, ", \t\n")) != NULL;) { | ||||
| if (**ap != '\0') | if (**ap != '\0') | ||||
| if (++ap >= &argv[2]) | if (++ap >= &argv[2]) | ||||
| break; | break; | ||||
| } | } | ||||
| if (argv[0] == NULL || argv[1] == NULL) { | if (argv[0] == NULL || argv[1] == NULL) { | ||||
| logerror("filter parse error"); | dprintf("filter parse error"); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| /* fill in prop_type */ | /* fill in prop_type */ | ||||
| if (strcasecmp(argv[0], "msg") == 0) | if (strcasecmp(argv[0], "msg") == 0) | ||||
| pfilter->prop_type = FILT_PROP_MSG; | pfilter.prop_type = FILT_PROP_MSG; | ||||
| else if (strcasecmp(argv[0], "hostname") == 0) | else if (strcasecmp(argv[0], "hostname") == 0) | ||||
| pfilter->prop_type = FILT_PROP_HOSTNAME; | pfilter.prop_type = FILT_PROP_HOSTNAME; | ||||
| else if (strcasecmp(argv[0], "source") == 0) | else if (strcasecmp(argv[0], "source") == 0) | ||||
| pfilter->prop_type = FILT_PROP_HOSTNAME; | pfilter.prop_type = FILT_PROP_HOSTNAME; | ||||
| else if (strcasecmp(argv[0], "programname") == 0) | else if (strcasecmp(argv[0], "programname") == 0) | ||||
| pfilter->prop_type = FILT_PROP_PROGNAME; | pfilter.prop_type = FILT_PROP_PROGNAME; | ||||
| else { | else { | ||||
| logerror("unknown property"); | dprintf("unknown property"); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| /* full in cmp_flags (i.e. !contains, icase_regex, etc.) */ | /* full in cmp_flags (i.e. !contains, icase_regex, etc.) */ | ||||
| if (*argv[1] == '!') { | if (*argv[1] == '!') { | ||||
| pfilter->cmp_flags |= FILT_FLAG_EXCLUDE; | pfilter.cmp_flags |= FILT_FLAG_EXCLUDE; | ||||
| argv[1]++; | argv[1]++; | ||||
| } | } | ||||
| if (strncasecmp(argv[1], "icase_", (sizeof("icase_") - 1)) == 0) { | if (strncasecmp(argv[1], "icase_", (sizeof("icase_") - 1)) == 0) { | ||||
| pfilter->cmp_flags |= FILT_FLAG_ICASE; | pfilter.cmp_flags |= FILT_FLAG_ICASE; | ||||
| argv[1] += sizeof("icase_") - 1; | argv[1] += sizeof("icase_") - 1; | ||||
| } | } | ||||
| /* fill in cmp_type */ | /* fill in cmp_type */ | ||||
| if (strcasecmp(argv[1], "contains") == 0) | if (strcasecmp(argv[1], "contains") == 0) | ||||
| pfilter->cmp_type = FILT_CMP_CONTAINS; | pfilter.cmp_type = FILT_CMP_CONTAINS; | ||||
| else if (strcasecmp(argv[1], "isequal") == 0) | else if (strcasecmp(argv[1], "isequal") == 0) | ||||
| pfilter->cmp_type = FILT_CMP_EQUAL; | pfilter.cmp_type = FILT_CMP_EQUAL; | ||||
| else if (strcasecmp(argv[1], "startswith") == 0) | else if (strcasecmp(argv[1], "startswith") == 0) | ||||
| pfilter->cmp_type = FILT_CMP_STARTS; | pfilter.cmp_type = FILT_CMP_STARTS; | ||||
| else if (strcasecmp(argv[1], "regex") == 0) | else if (strcasecmp(argv[1], "regex") == 0) | ||||
| pfilter->cmp_type = FILT_CMP_REGEX; | pfilter.cmp_type = FILT_CMP_REGEX; | ||||
| else if (strcasecmp(argv[1], "ereregex") == 0) { | else if (strcasecmp(argv[1], "ereregex") == 0) { | ||||
| pfilter->cmp_type = FILT_CMP_REGEX; | pfilter.cmp_type = FILT_CMP_REGEX; | ||||
| re_flags |= REG_EXTENDED; | pfilter.cmp_flags |= REG_EXTENDED; | ||||
| } else { | } else { | ||||
| logerror("unknown cmp function"); | dprintf("unknown cmp function"); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| /* | /* | ||||
| * Handle filter value | * Handle filter value | ||||
| */ | */ | ||||
| /* ' ".*Deny.*"' */ | /* ' ".*Deny.*"' */ | ||||
| /* remove leading whitespace and check for '"' next character */ | /* remove leading whitespace and check for '"' next character */ | ||||
| filter += strspn(filter, ", \t\n"); | filter += strspn(filter, ", \t\n"); | ||||
| if (*filter != '"' || strlen(filter) < 3) { | if (*filter != '"' || strlen(filter) < 3) { | ||||
| logerror("property value parse error"); | dprintf("property value parse error"); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| filter++; | filter++; | ||||
| /* '.*Deny.*"' */ | /* '.*Deny.*"' */ | ||||
| /* process possible backslash (\") escaping */ | /* process possible backslash (\") escaping */ | ||||
| escaped = 0; | escaped = 0; | ||||
| filter_endpos = filter; | filter_endpos = filter; | ||||
| Show All 15 Lines | for (p = filter; *p != '\0'; p++) { | ||||
| escaped = 0; | escaped = 0; | ||||
| } | } | ||||
| *filter_endpos = '\0'; | *filter_endpos = '\0'; | ||||
| /* '.*Deny.*' */ | /* '.*Deny.*' */ | ||||
| /* We should not have anything but whitespace left after closing '"' */ | /* We should not have anything but whitespace left after closing '"' */ | ||||
| if (*p != '\0' && strspn(p, " \t\n") != strlen(p)) { | if (*p != '\0' && strspn(p, " \t\n") != strlen(p)) { | ||||
| logerror("property value parse error"); | dprintf("property value parse error"); | ||||
| goto error; | goto error; | ||||
| } | } | ||||
| if (pfilter->cmp_type == FILT_CMP_REGEX) { | pfilter.pflt_strval = filter; | ||||
| pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re)); | /* An nvlist is heap allocated heap here. */ | ||||
| if (pfilter->pflt_re == NULL) { | nvl_pfilter = prop_filter_to_nvlist(&pfilter); | ||||
| logerror("RE calloc() error"); | |||||
| goto error; | |||||
| } | |||||
| if (pfilter->cmp_flags & FILT_FLAG_ICASE) | |||||
| re_flags |= REG_ICASE; | |||||
| if (regcomp(pfilter->pflt_re, filter, re_flags) != 0) { | |||||
| logerror("RE compilation error"); | |||||
| goto error; | |||||
| } | |||||
| } else { | |||||
| pfilter->pflt_strval = strdup(filter); | |||||
| pfilter->pflt_strlen = strlen(filter); | |||||
| } | |||||
| free(filter_begpos); | free(filter_begpos); | ||||
| return (pfilter); | return (nvl_pfilter); | ||||
| error: | error: | ||||
| free(filter_begpos); | free(filter_begpos); | ||||
| free(pfilter->pflt_re); | |||||
| free(pfilter); | |||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| static const char * | static const char * | ||||
| parse_selector(const char *p, struct filed *f) | parse_selector(const char *p, struct filed *f) | ||||
| { | { | ||||
| int i, pri; | int i, pri; | ||||
| int pri_done = 0, pri_cmp = 0, pri_invert = 0; | int pri_done = 0, pri_cmp = 0, pri_invert = 0; | ||||
| char *bp, buf[LINE_MAX], ebuf[100]; | char *bp, buf[LINE_MAX]; | ||||
| const char *q; | const char *q; | ||||
| /* find the end of this facility name list */ | /* find the end of this facility name list */ | ||||
| for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.';) | for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.';) | ||||
| continue; | continue; | ||||
| /* get the priority comparison */ | /* get the priority comparison */ | ||||
| if (*q == '!') { | if (*q == '!') { | ||||
| Show All 35 Lines | if (*buf == '*') { | ||||
| pri_cmp = PRI_LT | PRI_EQ | PRI_GT; | pri_cmp = PRI_LT | PRI_EQ | PRI_GT; | ||||
| } else { | } else { | ||||
| /* Ignore trailing spaces. */ | /* Ignore trailing spaces. */ | ||||
| for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--) | for (i = strlen(buf) - 1; i >= 0 && buf[i] == ' '; i--) | ||||
| buf[i] = '\0'; | buf[i] = '\0'; | ||||
| pri = decode(buf, prioritynames); | pri = decode(buf, prioritynames); | ||||
| if (pri < 0) { | if (pri < 0) { | ||||
| errno = 0; | dprintf("unknown priority name \"%s\"", buf); | ||||
| (void)snprintf(ebuf, sizeof(ebuf), | |||||
| "unknown priority name \"%s\"", buf); | |||||
| logerror(ebuf); | |||||
| free(f); | free(f); | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| } | } | ||||
| if (!pri_cmp) | if (!pri_cmp) | ||||
| pri_cmp = UniquePriority ? PRI_EQ : (PRI_EQ | PRI_GT); | pri_cmp = UniquePriority ? PRI_EQ : (PRI_EQ | PRI_GT); | ||||
| if (pri_invert) | if (pri_invert) | ||||
| pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT; | pri_cmp ^= PRI_LT | PRI_EQ | PRI_GT; | ||||
| /* scan facilities */ | /* scan facilities */ | ||||
| while (*p != '\0' && !strchr("\t.; ", *p)) { | while (*p != '\0' && !strchr("\t.; ", *p)) { | ||||
| for (bp = buf; *p != '\0' && !strchr("\t,;. ", *p); ) | for (bp = buf; *p != '\0' && !strchr("\t,;. ", *p); ) | ||||
| *bp++ = *p++; | *bp++ = *p++; | ||||
| *bp = '\0'; | *bp = '\0'; | ||||
| if (*buf == '*') { | if (*buf == '*') { | ||||
| for (i = 0; i < LOG_NFACILITIES; i++) { | for (i = 0; i < LOG_NFACILITIES; i++) { | ||||
| f->f_pmask[i] = pri; | f->f_pmask[i] = pri; | ||||
| f->f_pcmp[i] = pri_cmp; | f->f_pcmp[i] = pri_cmp; | ||||
| } | } | ||||
| } else { | } else { | ||||
| i = decode(buf, facilitynames); | i = decode(buf, facilitynames); | ||||
| if (i < 0) { | if (i < 0) { | ||||
| errno = 0; | dprintf("unknown facility name \"%s\"", buf); | ||||
| (void)snprintf(ebuf, sizeof(ebuf), | |||||
| "unknown facility name \"%s\"", | |||||
| buf); | |||||
| logerror(ebuf); | |||||
| free(f); | free(f); | ||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| f->f_pmask[i >> 3] = pri; | f->f_pmask[i >> 3] = pri; | ||||
| f->f_pcmp[i >> 3] = pri_cmp; | f->f_pcmp[i >> 3] = pri_cmp; | ||||
| } | } | ||||
| while (*p == ',' || *p == ' ') | while (*p == ',' || *p == ' ') | ||||
| p++; | p++; | ||||
| Show All 10 Lines | parse_action(const char *p, struct filed *f) | ||||
| bool syncfile; | bool syncfile; | ||||
| if (*p == '-') { | if (*p == '-') { | ||||
| syncfile = false; | syncfile = false; | ||||
| p++; | p++; | ||||
| } else | } else | ||||
| syncfile = true; | syncfile = true; | ||||
| f->f_file = -1; | |||||
| switch (*p) { | switch (*p) { | ||||
| case '@': | case '@': | ||||
| { | { | ||||
| char *tp; | char *tp; | ||||
| char endkey = ':'; | char endkey = ':'; | ||||
| /* | /* | ||||
| * scan forward to see if there is a port defined. | * scan forward to see if there is a port defined. | ||||
| * so we can't use strlcpy.. | * so we can't use strlcpy.. | ||||
| Show All 24 Lines | else | ||||
| p = NULL; | p = NULL; | ||||
| hints = (struct addrinfo){ | hints = (struct addrinfo){ | ||||
| .ai_family = family, | .ai_family = family, | ||||
| .ai_socktype = SOCK_DGRAM | .ai_socktype = SOCK_DGRAM | ||||
| }; | }; | ||||
| error = getaddrinfo(f->f_hname, p ? p : "syslog", &hints, &res); | error = getaddrinfo(f->f_hname, p ? p : "syslog", &hints, &res); | ||||
| if (error) { | if (error) { | ||||
| logerror(gai_strerror(error)); | dprintf("%s\n", gai_strerror(error)); | ||||
| break; | break; | ||||
| } | } | ||||
| f->f_addr = res; | f->f_addr = res; | ||||
| f->f_type = F_FORW; | f->f_type = F_FORW; | ||||
| break; | break; | ||||
| case '/': | case '/': | ||||
| if ((f->f_file = open(p, logflags, 0600)) < 0) { | if ((f->f_file = open(p, logflags, 0600)) < 0) { | ||||
| f->f_type = F_UNUSED; | f->f_type = F_UNUSED; | ||||
| logerror(p); | dprintf("%s\n", p); | ||||
| break; | break; | ||||
| } | } | ||||
| if (syncfile) | if (syncfile) | ||||
| f->f_flags |= FFLAG_SYNC; | f->f_flags |= FFLAG_SYNC; | ||||
| if (isatty(f->f_file)) { | if (isatty(f->f_file)) { | ||||
| if (strcmp(p, _PATH_CONSOLE) == 0) | if (strcmp(p, _PATH_CONSOLE) == 0) | ||||
| f->f_type = F_CONSOLE; | f->f_type = F_CONSOLE; | ||||
| else | else | ||||
| Show All 32 Lines | default: | ||||
| f->f_type = F_USERS; | f->f_type = F_USERS; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* | /* | ||||
| * Crack a configuration file line | * Crack a configuration file line | ||||
| */ | */ | ||||
| static void | static nvlist_t * | ||||
| cfline(const char *line, const char *prog, const char *host, | cfline(const char *line, const char *prog, const char *host, | ||||
| const char *pfilter) | const char *pfilter) | ||||
| { | { | ||||
| struct filed *f; | nvlist_t *nvl_filed; | ||||
| struct filed f = { }; | |||||
| const char *p; | const char *p; | ||||
| dprintf("cfline(\"%s\", f, \"%s\", \"%s\", \"%s\")\n", line, prog, | dprintf("cfline(\"%s\", f, \"%s\", \"%s\", \"%s\")\n", line, prog, | ||||
| host, pfilter); | host, pfilter); | ||||
| f = calloc(1, sizeof(*f)); | |||||
| if (f == NULL) { | |||||
| logerror("malloc"); | |||||
| exit(1); | |||||
| } | |||||
| errno = 0; /* keep strerror() stuff out of logerror messages */ | |||||
| for (int i = 0; i <= LOG_NFACILITIES; i++) | for (int i = 0; i <= LOG_NFACILITIES; i++) | ||||
| f->f_pmask[i] = INTERNAL_NOPRI; | f.f_pmask[i] = INTERNAL_NOPRI; | ||||
| /* save hostname if any */ | /* save hostname if any */ | ||||
| if (host && *host == '*') | if (host != NULL && *host != '*') { | ||||
| host = NULL; | |||||
| if (host) { | |||||
| int hl; | int hl; | ||||
| f->f_host = strdup(host); | strlcpy(f.f_host, host, sizeof(f.f_host)); | ||||
| if (f->f_host == NULL) { | hl = strlen(f.f_host); | ||||
| logerror("strdup"); | if (hl > 0 && f.f_host[hl-1] == '.') | ||||
| exit(1); | f.f_host[--hl] = '\0'; | ||||
| } | |||||
| hl = strlen(f->f_host); | |||||
| if (hl > 0 && f->f_host[hl-1] == '.') | |||||
| f->f_host[--hl] = '\0'; | |||||
| /* RFC 5424 prefers logging FQDNs. */ | /* RFC 5424 prefers logging FQDNs. */ | ||||
| if (RFC3164OutputFormat) | if (RFC3164OutputFormat) | ||||
| trimdomain(f->f_host, hl); | trimdomain(f.f_host, hl); | ||||
| } | } | ||||
| /* save program name if any */ | /* save program name if any */ | ||||
| if (prog && *prog == '*') | if (prog != NULL && *prog != '*') | ||||
| prog = NULL; | strlcpy(f.f_program, prog, sizeof(f.f_program)); | ||||
| if (prog) { | |||||
| f->f_program = strdup(prog); | |||||
| if (f->f_program == NULL) { | |||||
| logerror("strdup"); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| if (pfilter) { | |||||
| f->f_prop_filter = prop_filter_compile(pfilter); | |||||
| if (f->f_prop_filter == NULL) { | |||||
| logerror("filter compile error"); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| /* scan through the list of selectors */ | /* scan through the list of selectors */ | ||||
| for (p = line; *p != '\0' && *p != '\t' && *p != ' ';) | for (p = line; *p != '\0' && *p != '\t' && *p != ' ';) | ||||
| p = parse_selector(p, f); | p = parse_selector(p, &f); | ||||
| /* skip to action part */ | /* skip to action part */ | ||||
| while (*p == '\t' || *p == ' ') | while (*p == '\t' || *p == ' ') | ||||
| p++; | p++; | ||||
| parse_action(p, f); | parse_action(p, &f); | ||||
| STAILQ_INSERT_TAIL(&fhead, f, next); | /* An nvlist is heap allocated heap here. */ | ||||
| nvl_filed = filed_to_nvlist(&f); | |||||
| if (pfilter && *pfilter != '*') { | |||||
| nvlist_t *nvl_pfilter; | |||||
| nvl_pfilter = prop_filter_compile(pfilter); | |||||
| if (nvl_pfilter == NULL) | |||||
| err(1, "filter compile error"); | |||||
| nvlist_add_nvlist(nvl_filed, "f_prop_filter", nvl_pfilter); | |||||
| } | |||||
| return (nvl_filed); | |||||
| } | } | ||||
| /* | /* | ||||
| * Decode a symbolic name to a numeric value | * Decode a symbolic name to a numeric value | ||||
| */ | */ | ||||
| static int | static int | ||||
| decode(const char *name, const CODE *codetab) | decode(const char *name, const CODE *codetab) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 640 Lines • Show Last 20 Lines | |||||