Changeset View
Changeset View
Standalone View
Standalone View
syslogd.c
Show First 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | |||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <sysexits.h> | #include <sysexits.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <utmpx.h> | #include <utmpx.h> | ||||
#include <regex.h> | |||||
#include "pathnames.h" | #include "pathnames.h" | ||||
#include "ttymsg.h" | #include "ttymsg.h" | ||||
#define SYSLOG_NAMES | #define SYSLOG_NAMES | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
static const char *ConfFile = _PATH_LOGCONF; | static const char *ConfFile = _PATH_LOGCONF; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | struct logtime { | ||||
suseconds_t usec; | suseconds_t usec; | ||||
}; | }; | ||||
/* Traditional syslog timestamp format. */ | /* Traditional syslog timestamp format. */ | ||||
#define RFC3164_DATELEN 15 | #define RFC3164_DATELEN 15 | ||||
#define RFC3164_DATEFMT "%b %e %H:%M:%S" | #define RFC3164_DATEFMT "%b %e %H:%M:%S" | ||||
/* | /* | ||||
* This structure holds a property-based filter | |||||
*/ | |||||
struct prop_filter { | |||||
uint8_t prop_type; | |||||
#define PROP_TYPE_NOOP 0 | |||||
#define PROP_TYPE_MSG 1 | |||||
#define PROP_TYPE_HOSTNAME 2 | |||||
#define PROP_TYPE_PROGNAME 3 | |||||
uint8_t cmp_type; | |||||
#define PROP_CMP_CONTAINS 1 | |||||
#define PROP_CMP_EQUAL 2 | |||||
#define PROP_CMP_STARTS 3 | |||||
#define PROP_CMP_REGEX 4 | |||||
uint16_t cmp_flags; | |||||
#define PROP_FLAG_EXCLUDE (1 << 0) | |||||
#define PROP_FLAG_ICASE (1 << 1) | |||||
union { | |||||
char *p_strval; | |||||
regex_t *p_re; | |||||
} pflt_uniptr; | |||||
#define pflt_strval pflt_uniptr.p_strval | |||||
#define pflt_re pflt_uniptr.p_re | |||||
size_t pflt_strlen; | |||||
}; | |||||
/* | |||||
* This structure represents the files that will have log | * This structure represents the files that will have log | ||||
* copies printed. | * copies printed. | ||||
* We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY | * We require f_file to be valid if f_type is F_FILE, F_CONSOLE, F_TTY | ||||
* or if f_type is F_PIPE and f_pid > 0. | * or if f_type is F_PIPE and f_pid > 0. | ||||
*/ | */ | ||||
struct filed { | struct filed { | ||||
STAILQ_ENTRY(filed) next; /* next in linked list */ | STAILQ_ENTRY(filed) next; /* next in linked list */ | ||||
short f_type; /* entry type, see below */ | short f_type; /* entry type, see below */ | ||||
short f_file; /* file descriptor */ | short f_file; /* file descriptor */ | ||||
time_t f_time; /* time this was last written */ | time_t f_time; /* time this was last written */ | ||||
char *f_host; /* host from which to recd. */ | char *f_host; /* host from which to recd. */ | ||||
u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ | u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ | ||||
u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ | u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ | ||||
#define PRI_LT 0x1 | #define PRI_LT 0x1 | ||||
#define PRI_EQ 0x2 | #define PRI_EQ 0x2 | ||||
#define PRI_GT 0x4 | #define PRI_GT 0x4 | ||||
char *f_program; /* program this applies to */ | char *f_program; /* program this applies to */ | ||||
struct prop_filter *f_prop_filter; /* property-based filter */ | |||||
union { | union { | ||||
char f_uname[MAXUNAMES][MAXLOGNAME]; | char f_uname[MAXUNAMES][MAXLOGNAME]; | ||||
struct { | struct { | ||||
char f_hname[MAXHOSTNAMELEN]; | char f_hname[MAXHOSTNAMELEN]; | ||||
struct addrinfo *f_addr; | struct addrinfo *f_addr; | ||||
} f_forw; /* forwarding address */ | } f_forw; /* forwarding address */ | ||||
char f_fname[MAXPATHLEN]; | char f_fname[MAXPATHLEN]; | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild; | static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild; | ||||
struct iovlist; | struct iovlist; | ||||
static int allowaddr(char *); | static int allowaddr(char *); | ||||
static int addfile(struct filed *); | static int addfile(struct filed *); | ||||
static int addpeer(struct peer *); | static int addpeer(struct peer *); | ||||
static int addsock(struct addrinfo *, struct socklist *); | static int addsock(struct addrinfo *, struct socklist *); | ||||
static struct filed *cfline(const char *, const char *, const char *); | static struct filed *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(pid_t, const char *); | static void deadq_enter(pid_t, const char *); | ||||
static int deadq_remove(struct deadq_entry *); | static int deadq_remove(struct deadq_entry *); | ||||
static int deadq_removebypid(pid_t); | static int deadq_removebypid(pid_t); | ||||
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 dodie(int); | static void dodie(int); | ||||
static void dofsync(void); | static void dofsync(void); | ||||
Show All 9 Lines | |||||
static void log_deadchild(pid_t, int, const char *); | static void log_deadchild(pid_t, int, const char *); | ||||
static void markit(void); | static void markit(void); | ||||
static int socksetup(struct peer *); | static int socksetup(struct peer *); | ||||
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 socklist_recv_signal(struct socklist *); | static int socklist_recv_signal(struct socklist *); | ||||
static void sighandler(int); | static void sighandler(int); | ||||
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, | |||||
const char *value); | |||||
static int prop_filter_compile(struct prop_filter *pfilter, | |||||
char *filterstr); | |||||
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 void reapchild(int); | static void reapchild(int); | ||||
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 int validate(struct sockaddr *, const char *); | static int validate(struct sockaddr *, const char *); | ||||
static void unmapped(struct sockaddr *); | static void unmapped(struct sockaddr *); | ||||
▲ Show 20 Lines • Show All 1,012 Lines • ▼ Show 20 Lines | skip_message(const char *name, const char *spec, int checkcase) | ||||
} | } | ||||
/* No explicit match for this name: skip the message iff | /* No explicit match for this name: skip the message iff | ||||
the spec is an inclusive one. */ | the spec is an inclusive one. */ | ||||
return !exclude; | return !exclude; | ||||
} | } | ||||
/* | /* | ||||
* Match some property of the message against a filter. | |||||
* Return a non-0 value if the message must be ignored | |||||
* based on the filter. | |||||
*/ | |||||
static int | |||||
evaluate_prop_filter(const struct prop_filter *filter, const char *value) | |||||
{ | |||||
const char *s = NULL; | |||||
const int exclude = ((filter->cmp_flags & PROP_FLAG_EXCLUDE) > 0); | |||||
if (value == NULL) | |||||
return (-1); | |||||
if (filter->cmp_type == PROP_CMP_REGEX) { | |||||
if (regexec(filter->pflt_re, value, 0, NULL, 0) == 0) | |||||
return (exclude); | |||||
else | |||||
return (!exclude); | |||||
} | |||||
size_t valuelen = strlen(value); | |||||
/* a shortcut for equal with different length is always false */ | |||||
if (filter->cmp_type == PROP_CMP_EQUAL | |||||
&& valuelen != filter->pflt_strlen) | |||||
return (!exclude); | |||||
if (filter->cmp_flags & PROP_FLAG_ICASE) | |||||
s = strcasestr (value, filter->pflt_strval); | |||||
else | |||||
s = strstr (value, filter->pflt_strval); | |||||
/* | |||||
* PROP_CMP_CONTAINS true if s | |||||
* PROP_CMP_STARTS true if s && s == value | |||||
* PROP_CMP_EQUAL true if s && s == value && | |||||
* valuelen == filter->pflt_strlen | |||||
* (and length match is checked | |||||
* already) | |||||
*/ | |||||
switch (filter->cmp_type) { | |||||
case PROP_CMP_STARTS: | |||||
case PROP_CMP_EQUAL: | |||||
if (s != value) | |||||
return (!exclude); | |||||
/* FALLTHROUGH */ | |||||
case PROP_CMP_CONTAINS: | |||||
if (s) | |||||
return (exclude); | |||||
else | |||||
return (!exclude); | |||||
break; | |||||
default: | |||||
/* unknown cmp_type */ | |||||
break; | |||||
} | |||||
return (-1); | |||||
} | |||||
/* | |||||
* Logs a message to the appropriate log files, users, etc. based on the | * Logs a message to the appropriate log files, users, etc. based on the | ||||
* priority. Log messages are always formatted according to RFC 3164, | * priority. Log messages are always formatted according to RFC 3164, | ||||
* even if they were in RFC 5424 format originally, The MSGID and | * even if they were in RFC 5424 format originally, The MSGID and | ||||
* STRUCTURED-DATA fields are thus discarded for the time being. | * STRUCTURED-DATA fields are thus discarded for the time being. | ||||
*/ | */ | ||||
static void | static void | ||||
logmsg(int pri, const struct logtime *timestamp, const char *hostname, | logmsg(int pri, const struct logtime *timestamp, const char *hostname, | ||||
const char *app_name, const char *procid, const char *msgid, | const char *app_name, const char *procid, const char *msgid, | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(f, &fhead, next) { | ||||
if (skip_message(hostname, f->f_host, 0)) | if (skip_message(hostname, f->f_host, 0)) | ||||
continue; | continue; | ||||
/* skip messages with the incorrect program name */ | /* skip messages with the incorrect program name */ | ||||
if (skip_message(app_name == NULL ? "" : app_name, | if (skip_message(app_name == NULL ? "" : app_name, | ||||
f->f_program, 1)) | f->f_program, 1)) | ||||
continue; | continue; | ||||
/* skip messages if a property does not match filter */ | |||||
if (f->f_prop_filter | |||||
&& f->f_prop_filter->prop_type != PROP_TYPE_NOOP) { | |||||
switch (f->f_prop_filter->prop_type) { | |||||
case PROP_TYPE_MSG: | |||||
if (evaluate_prop_filter(f->f_prop_filter, | |||||
msg)) | |||||
continue; | |||||
break; | |||||
case PROP_TYPE_HOSTNAME: | |||||
if (evaluate_prop_filter(f->f_prop_filter, | |||||
hostname)) | |||||
continue; | |||||
break; | |||||
case PROP_TYPE_PROGNAME: | |||||
if (evaluate_prop_filter(f->f_prop_filter, | |||||
app_name == NULL ? "" : app_name)) | |||||
continue; | |||||
break; | |||||
default: | |||||
continue; | |||||
} | |||||
} | |||||
/* skip message to console if it has already been printed */ | /* skip message to console if it has already been printed */ | ||||
if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) | if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) | ||||
continue; | continue; | ||||
/* don't output marks to recently written files */ | /* don't output marks to recently written files */ | ||||
if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) | if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 675 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
FILE *cf2; | FILE *cf2; | ||||
struct filed *f; | struct filed *f; | ||||
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 *p, *tmp; | char *p, *tmp; | ||||
int i, nents; | int i, nents; | ||||
size_t include_len; | size_t include_len; | ||||
/* | /* | ||||
* Foreach line in the conf table, open that file. | * Foreach line in the conf table, open that file. | ||||
*/ | */ | ||||
include_len = sizeof(include_str) -1; | include_len = sizeof(include_str) -1; | ||||
(void)strlcpy(host, "*", sizeof(host)); | (void)strlcpy(host, "*", sizeof(host)); | ||||
(void)strlcpy(prog, "*", sizeof(prog)); | (void)strlcpy(prog, "*", sizeof(prog)); | ||||
(void)strlcpy(pfilter, "*", sizeof(pfilter)); | |||||
while (fgets(cline, sizeof(cline), cf) != NULL) { | while (fgets(cline, sizeof(cline), cf) != NULL) { | ||||
/* | /* | ||||
* check for end-of-section, comments, strip off trailing | * check for end-of-section, comments, strip off trailing | ||||
* spaces and newline character. #!prog is treated specially: | * spaces and newline character. #!prog is treated specially: | ||||
* following lines apply only to that program. | * following lines apply only to that program. | ||||
*/ | */ | ||||
for (p = cline; isspace(*p); ++p) | for (p = cline; isspace(*p); ++p) | ||||
continue; | continue; | ||||
Show All 32 Lines | if (allow_includes && | ||||
readconfigfile(cf2, 0); | readconfigfile(cf2, 0); | ||||
fclose(cf2); | fclose(cf2); | ||||
} | } | ||||
free(ent); | free(ent); | ||||
continue; | continue; | ||||
} | } | ||||
if (*p == '#') { | if (*p == '#') { | ||||
p++; | p++; | ||||
if (*p != '!' && *p != '+' && *p != '-') | if (*p == '\0' || strchr("!+-:", *p) == NULL) | ||||
continue; | continue; | ||||
} | } | ||||
if (*p == '+' || *p == '-') { | if (*p == '+' || *p == '-') { | ||||
host[0] = *p++; | host[0] = *p++; | ||||
while (isspace(*p)) | while (isspace(*p)) | ||||
p++; | p++; | ||||
if ((!*p) || (*p == '*')) { | if ((!*p) || (*p == '*')) { | ||||
(void)strlcpy(host, "*", sizeof(host)); | (void)strlcpy(host, "*", sizeof(host)); | ||||
Show All 20 Lines | if (*p == '!') { | ||||
for (i = 0; i < LINE_MAX - 1; i++) { | for (i = 0; i < LINE_MAX - 1; i++) { | ||||
if (!isprint(p[i]) || isspace(p[i])) | if (!isprint(p[i]) || isspace(p[i])) | ||||
break; | break; | ||||
prog[i] = p[i]; | prog[i] = p[i]; | ||||
} | } | ||||
prog[i] = 0; | prog[i] = 0; | ||||
continue; | continue; | ||||
} | } | ||||
if (*p == ':') { | |||||
p++; | |||||
while (isspace(*p)) | |||||
p++; | |||||
if ((!*p) || (*p == '*')) { | |||||
(void)strlcpy(pfilter, "*", sizeof(pfilter)); | |||||
continue; | |||||
} | |||||
(void)strlcpy(pfilter, p, sizeof(pfilter)); | |||||
continue; | |||||
} | |||||
for (p = cline + 1; *p != '\0'; p++) { | for (p = cline + 1; *p != '\0'; p++) { | ||||
if (*p != '#') | if (*p != '#') | ||||
continue; | continue; | ||||
if (*(p - 1) == '\\') { | if (*(p - 1) == '\\') { | ||||
strcpy(p - 1, p); | strcpy(p - 1, 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'; | ||||
f = cfline(cline, prog, host); | f = cfline(cline, prog, host, pfilter); | ||||
if (f != NULL) | if (f != NULL) | ||||
addfile(f); | addfile(f); | ||||
free(f); | free(f); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
sighandler(int signo) | sighandler(int signo) | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | case F_PIPE: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
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); | ||||
free(f->f_program); | free(f->f_program); | ||||
free(f->f_host); | free(f->f_host); | ||||
if (f->f_prop_filter) { | |||||
switch (f->f_prop_filter->cmp_type) { | |||||
case PROP_CMP_REGEX: | |||||
regfree(f->f_prop_filter->pflt_re); | |||||
free(f->f_prop_filter->pflt_re); | |||||
break; | |||||
case PROP_CMP_CONTAINS: | |||||
case PROP_CMP_EQUAL: | |||||
case PROP_CMP_STARTS: | |||||
free(f->f_prop_filter->pflt_strval); | |||||
break; | |||||
} | |||||
free(f->f_prop_filter); | |||||
} | |||||
free(f); | free(f); | ||||
} | } | ||||
/* open the configuration file */ | /* open the configuration file */ | ||||
if ((cf = fopen(ConfFile, "r")) == NULL) { | if ((cf = fopen(ConfFile, "r")) == NULL) { | ||||
dprintf("cannot open %s\n", ConfFile); | dprintf("cannot open %s\n", ConfFile); | ||||
f = cfline("*.ERR\t/dev/console", "*", "*"); | f = cfline("*.ERR\t/dev/console", "*", "*", "*"); | ||||
if (f != NULL) | if (f != NULL) | ||||
addfile(f); | addfile(f); | ||||
free(f); | free(f); | ||||
f = cfline("*.PANIC\t*", "*", "*"); | f = cfline("*.PANIC\t*", "*", "*", "*"); | ||||
if (f != NULL) | if (f != NULL) | ||||
addfile(f); | addfile(f); | ||||
free(f); | free(f); | ||||
Initialized = 1; | Initialized = 1; | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | (void)snprintf(bootfileMsg, sizeof(bootfileMsg), | ||||
"kernel boot file is %s", bootfile); | "kernel boot file is %s", bootfile); | ||||
logmsg(LOG_KERN | LOG_INFO, NULL, LocalHostName, "syslogd", | 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. | |||||
* Returns 0 on success, -1 otherwise. | |||||
*/ | |||||
static int | |||||
prop_filter_compile(struct prop_filter *pfilter, char *filter) | |||||
{ | |||||
char *filter_endpos, *p; | |||||
char **ap, *argv[2] = {NULL, NULL}; | |||||
int re_flags = REG_NOSUB; | |||||
int escaped; | |||||
bzero(pfilter, sizeof(struct prop_filter)); | |||||
/* | |||||
* Here's some filter examples mentioned in syslog.conf(5) | |||||
* 'msg, contains, ".*Deny.*"' | |||||
* 'processname, regex, "^bird6?$"' | |||||
* 'hostname, icase_ereregex, "^server-(dcA|podB)-rack1[0-9]{2}\\..*"' | |||||
*/ | |||||
/* | |||||
* Split filter into 3 parts: property name (argv[0]), | |||||
* cmp type (argv[1]) and lvalue for comparison (filter). | |||||
*/ | |||||
for (ap = argv; (*ap = strsep(&filter, ", \t\n")) != NULL;) { | |||||
if (**ap != '\0') | |||||
if (++ap >= &argv[2]) | |||||
break; | |||||
} | |||||
if (argv[0] == NULL || argv[1] == NULL) { | |||||
logerror("filter parse error"); | |||||
return (-1); | |||||
} | |||||
/* fill in prop_type */ | |||||
if (strcasecmp(argv[0], "msg") == 0) | |||||
pfilter->prop_type = PROP_TYPE_MSG; | |||||
else if(strcasecmp(argv[0], "hostname") == 0) | |||||
pfilter->prop_type = PROP_TYPE_HOSTNAME; | |||||
else if(strcasecmp(argv[0], "source") == 0) | |||||
pfilter->prop_type = PROP_TYPE_HOSTNAME; | |||||
else if(strcasecmp(argv[0], "programname") == 0) | |||||
pfilter->prop_type = PROP_TYPE_PROGNAME; | |||||
else { | |||||
logerror("unknown property"); | |||||
return (-1); | |||||
} | |||||
/* full in cmp_flags (i.e. !contains, icase_regex, etc.) */ | |||||
if (*argv[1] == '!') { | |||||
pfilter->cmp_flags |= PROP_FLAG_EXCLUDE; | |||||
argv[1]++; | |||||
} | |||||
if (strncasecmp(argv[1], "icase_", (sizeof("icase_") - 1)) == 0) { | |||||
pfilter->cmp_flags |= PROP_FLAG_ICASE; | |||||
argv[1] += sizeof("icase_") - 1; | |||||
} | |||||
/* fill in cmp_type */ | |||||
if (strcasecmp(argv[1], "contains") == 0) | |||||
pfilter->cmp_type = PROP_CMP_CONTAINS; | |||||
else if (strcasecmp(argv[1], "isequal") == 0) | |||||
pfilter->cmp_type = PROP_CMP_EQUAL; | |||||
else if (strcasecmp(argv[1], "startswith") == 0) | |||||
pfilter->cmp_type = PROP_CMP_STARTS; | |||||
else if (strcasecmp(argv[1], "regex") == 0) | |||||
pfilter->cmp_type = PROP_CMP_REGEX; | |||||
else if (strcasecmp(argv[1], "ereregex") == 0) { | |||||
pfilter->cmp_type = PROP_CMP_REGEX; | |||||
re_flags |= REG_EXTENDED; | |||||
} else { | |||||
logerror("unknown cmp function"); | |||||
return (-1); | |||||
} | |||||
/* | |||||
* Handle filter value | |||||
*/ | |||||
/* ' ".*Deny.*"' */ | |||||
/* remove leading whitespace and check for '"' next character */ | |||||
filter += strspn(filter, ", \t\n"); | |||||
if (*filter != '"' || strlen(filter) < 3) { | |||||
logerror("property value parse error"); | |||||
return (-1); | |||||
} | |||||
filter++; | |||||
/* '.*Deny.*"' */ | |||||
/* process possible backslash (\") escaping */ | |||||
escaped = 0; | |||||
filter_endpos = filter; | |||||
for (p = filter; *p != '\0'; p++) { | |||||
if (*p == '\\' && !escaped) { | |||||
escaped = 1; | |||||
/* do not shift filter_endpos */ | |||||
continue; | |||||
} | |||||
if (*p == '"' && !escaped) { | |||||
p++; | |||||
break; | |||||
} | |||||
/* we've seen some esc symbols, need to compress the line */ | |||||
if (filter_endpos != p) | |||||
*filter_endpos = *p; | |||||
filter_endpos++; | |||||
escaped = 0; | |||||
} | |||||
*filter_endpos = '\0'; | |||||
/* '.*Deny.*' */ | |||||
/* We should not have anything but whitespace left after closing '"' */ | |||||
if (*p != '\0' && strspn(p, " \t\n") != strlen(p)) { | |||||
logerror("property value parse error"); | |||||
return (-1); | |||||
} | |||||
if (pfilter->cmp_type == PROP_CMP_REGEX) { | |||||
pfilter->pflt_re = calloc(1, sizeof(*pfilter->pflt_re)); | |||||
if (pfilter->pflt_re == NULL) { | |||||
logerror("RE calloc() error"); | |||||
free(pfilter->pflt_re); | |||||
return (-1); | |||||
} | |||||
if (pfilter->cmp_flags & PROP_FLAG_ICASE) | |||||
re_flags |= REG_ICASE; | |||||
if (regcomp(pfilter->pflt_re, filter, re_flags) != 0) { | |||||
logerror("RE compilation error"); | |||||
free(pfilter->pflt_re); | |||||
return (-1); | |||||
} | |||||
} else { | |||||
pfilter->pflt_strval = strdup(filter); | |||||
pfilter->pflt_strlen = strlen(filter); | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Crack a configuration file line | * Crack a configuration file line | ||||
*/ | */ | ||||
static struct filed * | static struct filed * | ||||
cfline(const char *line, const char *prog, const char *host) | cfline(const char *line, const char *prog, const char *host, | ||||
const char *pfilter) | |||||
{ | { | ||||
struct filed *f; | struct filed *f; | ||||
struct addrinfo hints, *res; | struct addrinfo hints, *res; | ||||
int error, i, pri, syncfile; | int error, i, pri, syncfile; | ||||
const char *p, *q; | const char *p, *q; | ||||
char *bp; | char *bp, *pfilter_dup; | ||||
char buf[MAXLINE], ebuf[100]; | char buf[MAXLINE], ebuf[100]; | ||||
dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host); | dprintf("cfline(\"%s\", f, \"%s\", \"%s\", \"%s\")\n", line, prog, | ||||
host, pfilter); | |||||
f = calloc(1, sizeof(*f)); | f = calloc(1, sizeof(*f)); | ||||
if (f == NULL) { | if (f == NULL) { | ||||
logerror("malloc"); | logerror("malloc"); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
errno = 0; /* keep strerror() stuff out of logerror messages */ | errno = 0; /* keep strerror() stuff out of logerror messages */ | ||||
Show All 20 Lines | cfline(const char *line, const char *prog, const char *host, | ||||
/* save program name if any */ | /* save program name if any */ | ||||
if (prog && *prog == '*') | if (prog && *prog == '*') | ||||
prog = NULL; | prog = NULL; | ||||
if (prog) { | if (prog) { | ||||
f->f_program = strdup(prog); | f->f_program = strdup(prog); | ||||
if (f->f_program == NULL) { | if (f->f_program == NULL) { | ||||
logerror("strdup"); | logerror("strdup"); | ||||
exit(1); | exit(1); | ||||
} | |||||
} | |||||
if (pfilter) { | |||||
f->f_prop_filter = calloc(1, sizeof(*(f->f_prop_filter))); | |||||
if (f->f_prop_filter == NULL) { | |||||
logerror("pfilter calloc"); | |||||
exit(1); | |||||
} | |||||
if (*pfilter == '*') | |||||
f->f_prop_filter->prop_type = PROP_TYPE_NOOP; | |||||
else { | |||||
pfilter_dup = strdup(pfilter); | |||||
if (pfilter_dup == NULL) { | |||||
logerror("strdup"); | |||||
exit(1); | |||||
} | |||||
if (prop_filter_compile(f->f_prop_filter, pfilter_dup)) { | |||||
logerror("filter compile error"); | |||||
exit(1); | |||||
} | |||||
} | } | ||||
} | } | ||||
/* scan through the list of selectors */ | /* scan through the list of selectors */ | ||||
for (p = line; *p && *p != '\t' && *p != ' ';) { | for (p = line; *p && *p != '\t' && *p != ' ';) { | ||||
int pri_done; | int pri_done; | ||||
int pri_cmp; | int pri_cmp; | ||||
int pri_invert; | int pri_invert; | ||||
▲ Show 20 Lines • Show All 983 Lines • Show Last 20 Lines |