diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8 index d68c2c1179a9..31d8460c9383 100644 --- a/usr.sbin/syslogd/syslogd.8 +++ b/usr.sbin/syslogd/syslogd.8 @@ -1,4 +1,4 @@ -.\" $NetBSD: syslogd.8,v 1.22 2001/07/01 16:23:42 itojun Exp $ +.\" $NetBSD: syslogd.8,v 1.23 2001/07/16 05:04:47 manu Exp $ .\" .\" Copyright (c) 1983, 1986, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -46,6 +46,15 @@ .Op Fl f Ar config_file .Ek .Bk -words +.Op Fl u Ar user +.Ek +.Bk -words +.Op Fl g Ar user +.Ek +.Bk -words +.Op Fl t Ar chroot_dir +.Ek +.Bk -words .Op Fl m Ar mark_interval .Ek .Bk -words @@ -70,6 +79,19 @@ and do not disassociate from the controlling terminal. Specify the pathname of an alternative configuration file; the default is .Pa /etc/syslog.conf . +.It Fl u Ar user +Set UID to +.Ar user +after the sockets and log files have been open. +.It Fl g Ar group +Set GID to +.Ar group +after the sockets and log files have been open. +.It Fl t Ar chroot_dir +.Xr chroot 2 +to +.Ar chroot_dir +after the sockets and log files have been open. .It Fl m Select the number of minutes between ``mark'' messages; the default is 20 minutes. diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 4c18518d68f5..b1b2d6977256 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -1,4 +1,4 @@ -/* $NetBSD: syslogd.c,v 1.46 2001/07/01 16:23:42 itojun Exp $ */ +/* $NetBSD: syslogd.c,v 1.47 2001/07/16 05:04:47 manu Exp $ */ /* * Copyright (c) 1983, 1988, 1993, 1994 @@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ #if 0 static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; #else -__RCSID("$NetBSD: syslogd.c,v 1.46 2001/07/01 16:23:42 itojun Exp $"); +__RCSID("$NetBSD: syslogd.c,v 1.47 2001/07/16 05:04:47 manu Exp $"); #endif #endif /* not lint */ @@ -105,6 +105,9 @@ __RCSID("$NetBSD: syslogd.c,v 1.46 2001/07/01 16:23:42 itojun Exp $"); #include #include #include +#include +#include +#include #include "pathnames.h" #define SYSLOG_NAMES @@ -193,6 +196,7 @@ struct filed *Files; struct filed consfile; int Debug; /* debug flag */ +int daemonized = 0; /* we are not daemonized yet */ char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ char *LocalDomain; /* our local domain name */ int *finet = NULL; /* Internet datagram sockets */ @@ -213,7 +217,7 @@ void fprintlog __P((struct filed *, int, char *)); int getmsgbufsize __P((void)); int* socksetup __P((int)); void init __P((int)); -void logerror __P((char *)); +void logerror __P((const char *, ...)); void logmsg __P((int, char *, char *, int)); void printline __P((char *, char *)); void printsys __P((char *)); @@ -236,11 +240,35 @@ main(argc, argv) struct sockaddr_storage frominet; char *p, *line, **pp; struct pollfd *readfds; + uid_t uid = 0; + gid_t gid = 0; + char *user = NULL; + char *group = NULL; + char *root = "/"; + char *endp; + struct group *gr; + struct passwd *pw; + (void)setlocale(LC_ALL, ""); - while ((ch = getopt(argc, argv, "dnsf:m:p:P:")) != -1) + while ((ch = getopt(argc, argv, "dnsf:m:p:P:u:g:t:")) != -1) switch(ch) { + case 'u': + user = optarg; + if (*user == '\0') + usage(); + break; + case 'g': + group = optarg; + if (*group == '\0') + usage(); + break; + case 't': + root = optarg; + if (*root == '\0') + usage(); + break; case 'd': /* debug */ Debug++; break; @@ -271,10 +299,46 @@ main(argc, argv) if ((argc -= optind) != 0) usage(); - if (!Debug) - (void)daemon(0, 0); - else - setlinebuf(stdout); + setlinebuf(stdout); + + if (user != NULL) { + if (isdigit((unsigned char)*user)) { + uid = (uid_t)strtoul(user, &endp, 0); + if (*endp != '\0') + goto getuser; + } else { +getuser: + if ((pw = getpwnam(user)) != NULL) { + uid = pw->pw_uid; + } else { + errno = 0; + logerror("Cannot find user `%s'", user); + die (0); + } + } + } + + if (group != NULL) { + if (isdigit((unsigned char)*group)) { + gid = (gid_t)strtoul(group, &endp, 0); + if (*endp != '\0') + goto getgroup; + } else { +getgroup: + if ((gr = getgrnam(group)) != NULL) { + gid = gr->gr_gid; + } else { + errno = 0; + logerror("Cannot find group `%s'", group); + die(0); + } + } + } + + if (access (root, F_OK | R_OK)) { + logerror ("Cannot access `%s'", root); + die (0); + } consfile.f_type = F_CONSOLE; (void)strcpy(consfile.f_un.f_fname, ctty); @@ -291,7 +355,7 @@ main(argc, argv) linesize++; line = malloc(linesize); if (line == NULL) { - logerror("couldn't allocate line buffer"); + logerror("Couldn't allocate line buffer"); die(0); } (void)signal(SIGTERM, die); @@ -309,11 +373,11 @@ main(argc, argv) &funixmaxsize, _PATH_LOG); funix = (int *)malloc(sizeof(int) * funixsize); if (funix == NULL) { - logerror("couldn't allocate funix descriptors"); + logerror("Couldn't allocate funix descriptors"); die(0); } for (j = 0, pp = LogPaths; *pp; pp++, j++) { - dprintf("making unix dgram socket %s\n", *pp); + dprintf("Making unix dgram socket `%s'\n", *pp); unlink(*pp); memset(&sunx, 0, sizeof(sunx)); sunx.sun_family = AF_LOCAL; @@ -322,31 +386,25 @@ main(argc, argv) if (funix[j] < 0 || bind(funix[j], (struct sockaddr *)&sunx, SUN_LEN(&sunx)) < 0 || chmod(*pp, 0666) < 0) { - int serrno = errno; - (void)snprintf(line, sizeof line, - "cannot create %s", *pp); - errno = serrno; - logerror(line); - errno = serrno; - dprintf("cannot create %s (%d)\n", *pp, errno); + logerror("Cannot create `%s'", *pp); die(0); } - dprintf("listening on unix dgram socket %s\n", *pp); + dprintf("Listening on unix dgram socket `%s'\n", *pp); } init(0); if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) < 0) { - dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); + dprintf("Can't open `%s' (%d)\n", _PATH_KLOG, errno); } else { - dprintf("listening on kernel log %s\n", _PATH_KLOG); + dprintf("Listening on kernel log `%s'\n", _PATH_KLOG); } /* tuck my process id away, if i'm not in debug mode */ if (Debug == 0) pidfile(NULL); - dprintf("off & running....\n"); + dprintf("Off & running....\n"); (void)signal(SIGHUP, init); @@ -354,7 +412,7 @@ main(argc, argv) readfds = (struct pollfd *)malloc(sizeof(struct pollfd) * (funixsize + (finet ? *finet : 0) + 1)); if (readfds == NULL) { - logerror("couldn't allocate pollfds"); + logerror("Couldn't allocate pollfds"); die(0); } nfds = 0; @@ -377,6 +435,36 @@ main(argc, argv) readfds[nfds++].events = POLLIN | POLLPRI; } + /* + * All files are open, we can drop privileges and chroot + */ + dprintf ("Attempt to chroot to `%s'\n", root); + if (chroot (root)) { + logerror ("Failed to chroot to `%s'", root); + die(0); + } + dprintf ("Attempt to set GID/EGID to `%d'\n", gid); + if (setgid (gid) || setegid (gid)) { + logerror ("Failed to set gid to `%d'", gid); + die(0); + } + dprintf ("Attempt to set UID/EUID to `%d'\n", uid); + if (setuid (uid) || seteuid (uid)) { + logerror ("Failed to set uid to `%d'", uid); + die(0); + } + + /* + * We cannot detach from the terminal before we are sure we won't + * have a fatal error, because error message would not go to the + * terminal and would not be logged because syslogd dies. + * All die() calls are behind us, we can call daemon() + */ + if (!Debug) { + (void)daemon(0, 0); + daemonized = 1; + } + for (;;) { int rv; @@ -385,19 +473,19 @@ main(argc, argv) continue; if (rv < 0) { if (errno != EINTR) - logerror("poll"); + logerror("poll() failed"); continue; } - dprintf("got a message (%d)\n", rv); + dprintf("Got a message (%d)\n", rv); if (fklog >= 0 && (readfds[nfklogix].revents & (POLLIN | POLLPRI))) { - dprintf("kernel log active\n"); + dprintf("Kernel log active\n"); i = read(fklog, line, linesize - 1); if (i > 0) { line[i] = '\0'; printsys(line); } else if (i < 0 && errno != EINTR) { - logerror("klog"); + logerror("klog failed"); fklog = -1; } } @@ -406,7 +494,7 @@ main(argc, argv) (POLLIN | POLLPRI)) == 0) continue; - dprintf("unix socket (%s) active\n", *pp); + dprintf("Unix socket (%s) active\n", *pp); len = sizeof(fromunix); i = recvfrom(funix[j], line, MAXLINE, 0, (struct sockaddr *)&fromunix, &len); @@ -414,13 +502,7 @@ main(argc, argv) line[i] = '\0'; printline(LocalHostName, line); } else if (i < 0 && errno != EINTR) { - char buf[MAXPATHLEN]; - int serrno = errno; - - (void)snprintf(buf, sizeof buf, - "recvfrom unix %s", *pp); - errno = serrno; - logerror(buf); + logerror("recvfrom() unix `%s'", *pp); } } if (finet && !SecureMode) { @@ -487,7 +569,7 @@ logpath_add(lp, szp, maxszp, new) char *new; { - dprintf("adding %s to the %p logpath list\n", new, *lp); + dprintf("Adding `%s' to the %p logpath list\n", new, *lp); if (*szp == *maxszp) { if (*maxszp == 0) { *maxszp = 4; /* start of with enough for now */ @@ -497,7 +579,7 @@ logpath_add(lp, szp, maxszp, new) *maxszp *= 2; *lp = realloc(*lp, sizeof(char *) * (*maxszp + 1)); if (*lp == NULL) { - logerror("couldn't allocate line buffer"); + logerror("Couldn't allocate line buffer"); die(0); } } @@ -519,11 +601,7 @@ logpath_fileadd(lp, szp, maxszp, file) fp = fopen(file, "r"); if (fp == NULL) { - int serrno = errno; - - dprintf("can't open %s (%d)\n", file, errno); - errno = serrno; - logerror("could not open socket file list"); + logerror("Could not open socket file list `%s'", file); die(0); } @@ -700,7 +778,7 @@ logmsg(pri, msg, from, flags) !strcmp(from, f->f_prevhost)) { (void)strncpy(f->f_lasttime, timestamp, 15); f->f_prevcount++; - dprintf("msg repeated %d times, %ld sec of %d\n", + dprintf("Msg repeated %d times, %ld sec of %d\n", f->f_prevcount, (long)(now - f->f_time), repeatinterval[f->f_repeatcount]); /* @@ -831,7 +909,7 @@ fprintlog(f, flags, msg) } if (lsent != l) { f->f_type = F_UNUSED; - logerror("sendto"); + logerror("sendto() failed"); } } break; @@ -1010,7 +1088,7 @@ domark(signo) for (f = Files; f; f = f->f_next) { if (f->f_prevcount && now >= REPEATTIME(f)) { - dprintf("flush %s: repeated %d times, %d sec.\n", + dprintf("Flush %s: repeated %d times, %d sec.\n", TypeNames[f->f_type], f->f_prevcount, repeatinterval[f->f_repeatcount]); fprintlog(f, 0, (char *)NULL); @@ -1024,19 +1102,32 @@ domark(signo) * Print syslogd errors some place. */ void -logerror(type) - char *type; +logerror(const char *fmt, ...) { - char buf[100]; + va_list ap; + char tmpbuf[BUFSIZ]; + char buf[BUFSIZ]; + + va_start(ap, fmt); + + (void)vsnprintf(tmpbuf, sizeof(tmpbuf), fmt, ap); + + va_end(ap); if (errno) - (void)snprintf(buf, - sizeof(buf), "syslogd: %s: %s", type, strerror(errno)); + (void)snprintf(buf, sizeof(buf), "syslogd: %s: %s", + tmpbuf, strerror(errno)); else - (void)snprintf(buf, sizeof(buf), "syslogd: %s", type); - errno = 0; - dprintf("%s\n", buf); - logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); + (void)snprintf(buf, sizeof(buf), "syslogd: %s", tmpbuf); + + if (daemonized) + logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); + if (!daemonized && Debug) + dprintf("%s\n", buf); + if (!daemonized && !Debug) + printf("%s\n", buf); + + return; } void @@ -1044,19 +1135,18 @@ die(signo) int signo; { struct filed *f; - char buf[100], **p; + char **p; for (f = Files; f != NULL; f = f->f_next) { /* flush any pending output */ if (f->f_prevcount) fprintlog(f, 0, (char *)NULL); } - if (signo) { - dprintf("syslogd: exiting on signal %d\n", signo); - (void)snprintf(buf, sizeof buf, "exiting on signal %d", signo); - errno = 0; - logerror(buf); - } + errno = 0; + if (signo) + logerror("Exiting on signal %d\n", signo); + else + logerror("Fatal error, exiting"); for (p = LogPaths; p && *p; p++) unlink(*p); exit(0); @@ -1110,7 +1200,7 @@ init(signo) if (finet) { for (i = 0; i < *finet; i++) { if (close(finet[i+1]) < 0) { - logerror("close"); + logerror("close() failed"); die(0); } } @@ -1124,7 +1214,7 @@ init(signo) /* open the configuration file */ if ((cf = fopen(ConfFile, "r")) == NULL) { - dprintf("cannot open %s\n", ConfFile); + dprintf("Cannot open `%s'\n", ConfFile); *nextp = (struct filed *)calloc(1, sizeof(*f)); cfline("*.ERR\t/dev/console", *nextp); (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); @@ -1194,13 +1284,13 @@ init(signo) if (SecureMode) { for (i = 0; i < *finet; i++) { if (shutdown(finet[i+1], SHUT_RD) < 0) { - logerror("shutdown"); + logerror("shutdown() failed"); die(0); } } } else - dprintf("listening on inet and/or inet6 socket\n"); - dprintf("sending on inet and/or inet6 socket\n"); + dprintf("Listening on inet and/or inet6 socket\n"); + dprintf("Sending on inet and/or inet6 socket\n"); } logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); @@ -1218,7 +1308,8 @@ cfline(line, f) struct addrinfo hints, *res; int error, i, pri; char *bp, *p, *q; - char buf[MAXLINE], ebuf[100]; + char buf[MAXLINE]; + int sp_err; dprintf("cfline(%s)\n", line); @@ -1228,6 +1319,58 @@ cfline(line, f) memset(f, 0, sizeof(*f)); for (i = 0; i <= LOG_NFACILITIES; i++) f->f_pmask[i] = INTERNAL_NOPRI; + + /* + * There should not be any space before the log facility. + * Check this is okay, complain and fix if it is not. + */ + q = line; + if (isblank((unsigned char)*line)) { + errno = 0; + logerror( + "Warning: `%s' space or tab before the log facility", + line); + /* Fix: strip all spaces/tabs before the log facility */ + while (*q++ && isblank((unsigned char)*q)); + line = q; + } + + /* + * q is now at the first char of the log facility + * There should be at least one tab after the log facility + * Check this is okay, and complain and fix if it is not. + */ + q = line + strlen(line); + while (!isblank((unsigned char)*q) && (q != line)) + q--; + if ((q == line) && strlen(line)) { + /* No tabs or space in a non empty line: complain */ + errno = 0; + logerror( + "Error: `%s' log facility or log target missing", + line); + } + + /* q is at the end of the blank between the two fields */ + sp_err = 0; + while (isblank((unsigned char)*q) && (q != line)) + if (*q-- == ' ') + sp_err = 1; + + if (sp_err) { + /* + * A space somewhere between the log facility + * and the log target: complain + */ + errno = 0; + logerror( + "Warning: `%s' space found where tab is expected", + line); + /* ... and fix the problem: replace all spaces by tabs */ + while (*++q && isblank((unsigned char)*q)) + if (*q == ' ') + *q='\t'; + } /* scan through the list of selectors */ for (p = line; *p && *p != '\t';) { @@ -1251,9 +1394,8 @@ cfline(line, f) else { pri = decode(buf, prioritynames); if (pri < 0) { - (void)snprintf(ebuf, sizeof ebuf, - "unknown priority name \"%s\"", buf); - logerror(ebuf); + errno = 0; + logerror("Unknown priority name `%s'", buf); return; } } @@ -1269,10 +1411,9 @@ cfline(line, f) else { i = decode(buf, facilitynames); if (i < 0) { - (void)snprintf(ebuf, sizeof ebuf, - "unknown facility name \"%s\"", + errno = 0; + logerror("Unknown facility name `%s'", buf); - logerror(ebuf); return; } f->f_pmask[i >> 3] = pri; @@ -1285,7 +1426,8 @@ cfline(line, f) } /* skip to action part */ - while (*p == '\t') + sp_err = 0; + while ((*p == '\t') || (*p == ' ')) p++; switch (*p) @@ -1386,7 +1528,7 @@ getmsgbufsize() mib[1] = KERN_MSGBUFSIZE; size = sizeof msgbufsize; if (sysctl(mib, 2, &msgbufsize, &size, NULL, 0) == -1) { - dprintf("couldn't get kern.msgbufsize\n"); + dprintf("Couldn't get kern.msgbufsize\n"); return (0); } return (msgbufsize); @@ -1418,7 +1560,7 @@ socksetup(af) continue; socks = malloc ((maxs+1) * sizeof(int)); if (!socks) { - logerror("couldn't allocate memory for sockets"); + logerror("Couldn't allocate memory for sockets"); die(0); } @@ -1427,12 +1569,12 @@ socksetup(af) for (r = res; r; r = r->ai_next) { *s = socket(r->ai_family, r->ai_socktype, r->ai_protocol); if (*s < 0) { - logerror("socket"); + logerror("socket() failed"); continue; } if (!SecureMode && bind(*s, r->ai_addr, r->ai_addrlen) < 0) { + logerror("bind() failed"); close (*s); - logerror("bind"); continue; }