diff options
author | Camiel Dobbelaar <camield@cvs.openbsd.org> | 2001-09-21 20:22:07 +0000 |
---|---|---|
committer | Camiel Dobbelaar <camield@cvs.openbsd.org> | 2001-09-21 20:22:07 +0000 |
commit | f2234427fb48ac1ddff2888d88175a676f349d57 (patch) | |
tree | afeb388eb8d1d7da514b1395ecb5fe6502adc2aa /usr.sbin/popa3d | |
parent | fa205f9135d5a17814a8cee8cd9022324337f970 (diff) |
update to 0.4.9.4:
- stand-alone or inetd selectable from command-line (-D = daemon mode)
- logging priorities more accurate
- chroots to empty dir
- tcp wrappers support
Diffstat (limited to 'usr.sbin/popa3d')
-rw-r--r-- | usr.sbin/popa3d/Makefile | 14 | ||||
-rw-r--r-- | usr.sbin/popa3d/auth_passwd.c | 8 | ||||
-rw-r--r-- | usr.sbin/popa3d/mailbox.c | 49 | ||||
-rw-r--r-- | usr.sbin/popa3d/mailbox.h | 6 | ||||
-rw-r--r-- | usr.sbin/popa3d/params.h | 62 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_auth.c | 20 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_auth.h | 7 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_root.c | 99 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_trans.c | 54 | ||||
-rw-r--r-- | usr.sbin/popa3d/protocol.c | 19 | ||||
-rw-r--r-- | usr.sbin/popa3d/protocol.h | 7 | ||||
-rw-r--r-- | usr.sbin/popa3d/standalone.c | 56 | ||||
-rw-r--r-- | usr.sbin/popa3d/startup.c | 66 | ||||
-rw-r--r-- | usr.sbin/popa3d/virtual.c | 18 | ||||
-rw-r--r-- | usr.sbin/popa3d/virtual.h | 8 |
15 files changed, 358 insertions, 135 deletions
diff --git a/usr.sbin/popa3d/Makefile b/usr.sbin/popa3d/Makefile index f1e0a6da594..9f8c7e85a53 100644 --- a/usr.sbin/popa3d/Makefile +++ b/usr.sbin/popa3d/Makefile @@ -1,10 +1,16 @@ -# $OpenBSD: Makefile,v 1.1 2001/08/19 13:05:57 deraadt Exp $ +# $OpenBSD: Makefile,v 1.2 2001/09/21 20:22:06 camield Exp $ PROG= popa3d - +MAN= popa3d.8 SRCS= auth_passwd.c database.c mailbox.c misc.c pop_auth.c pop_root.c \ - pop_trans.c protocol.c standalone.c virtual.c + pop_trans.c protocol.c standalone.c startup.c virtual.c -MAN= popa3d.8 +CFLAGS+=-Wall -Werror -DHAVE_PROGNAME .include <bsd.prog.mk> + +.if (${TCP_WRAPPERS:L} == "yes") +CFLAGS+= -DLIBWRAP +LDADD+= -lwrap +DPADD+= ${LIBWRAP} +.endif diff --git a/usr.sbin/popa3d/auth_passwd.c b/usr.sbin/popa3d/auth_passwd.c index 924fc03981d..d0503ac7aa7 100644 --- a/usr.sbin/popa3d/auth_passwd.c +++ b/usr.sbin/popa3d/auth_passwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth_passwd.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: auth_passwd.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * The /etc/passwd authentication routine. @@ -8,7 +8,7 @@ #if AUTH_PASSWD && !VIRTUAL_ONLY -#define _XOPEN_SOURCE +#define _XOPEN_SOURCE 4 #define _XOPEN_SOURCE_EXTENDED #define _XOPEN_VERSION 4 #define _XPG4_2 @@ -17,11 +17,11 @@ #include <pwd.h> #include <sys/types.h> -struct passwd *auth_userpass(char *user, char *pass, char **mailbox) +struct passwd *auth_userpass(char *user, char *pass, int *known) { struct passwd *pw, *result; - if ((pw = getpwnam(user))) *mailbox = user; + *known = (pw = getpwnam(user)) != NULL; endpwent(); result = NULL; diff --git a/usr.sbin/popa3d/mailbox.c b/usr.sbin/popa3d/mailbox.c index 3316ed26b4a..b67f2655838 100644 --- a/usr.sbin/popa3d/mailbox.c +++ b/usr.sbin/popa3d/mailbox.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mailbox.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: mailbox.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Mailbox access. @@ -50,14 +50,14 @@ static int db_compare(struct db_message *msg) /* * Checks if the buffer pointed to by s1, of n1 chars, starts with the - * string s2. + * string s2, of n2 chars. */ -static int linecmp(char *s1, char *s2, int n1) +#ifdef __GNUC__ +inline +#endif +static int linecmp(char *s1, int n1, char *s2, int n2) { - int n2; - - if (s1[0] != s2[0]) return 1; - if (n1 < (n2 = strlen(s2))) return 1; + if (s1[0] != s2[0] || n1 < n2) return 1; return memcmp(s1, s2, n2); } @@ -217,12 +217,12 @@ static int mailbox_parse(int init) /* Check for a new message if we've just seen a blank line */ if (blank && start) - if (!linecmp(line, "From ", length)) { + if (!linecmp(line, length, "From ", 5)) { /* Process the previous one first, if exists */ if (offset) { if (!header && !body) break; msg.raw_size = offset - msg.raw_offset; - msg.data_size = offset - msg.data_offset; + msg.data_size = offset - 1 - msg.data_offset; MD5Final(msg.hash, &hash); if (db_op(&msg)) break; } @@ -255,10 +255,10 @@ static int mailbox_parse(int init) /* Some header lines are known to remain fixed over MUA runs */ if (header && start) - if (!linecmp(line, "Received:", length) || - !linecmp(line, "Date:", length) || - !linecmp(line, "Message-Id:", length) || - !linecmp(line, "Subject:", length)) + if (!linecmp(line, length, "Received:", 9) || + !linecmp(line, length, "Date:", 5) || + !linecmp(line, length, "Message-Id:", 11) || + !linecmp(line, length, "Subject:", 8)) fixed = 1; /* We can hash all fragments of those lines (until "end"), for UIDL */ @@ -275,7 +275,7 @@ static int mailbox_parse(int init) if (offset != mailbox_size) return 1; if (!header && !body) return 1; msg.raw_size = offset - msg.raw_offset; - msg.data_size = offset - msg.data_offset; + msg.data_size = offset - blank - msg.data_offset; MD5Final(msg.hash, &hash); if (db_op(&msg)) return 1; @@ -303,12 +303,17 @@ int mailbox_open(char *spool, char *mailbox) return errno != ENOENT; } + if (!S_ISREG(stat.st_mode)) { + free(pathname); + return 1; + } + if (!stat.st_size) { free(pathname); return 0; } - mailbox_fd = open(pathname, O_RDWR); + mailbox_fd = open(pathname, O_RDWR | O_NOCTTY); free(pathname); @@ -349,14 +354,18 @@ static int mailbox_changed(void) int mailbox_get(struct db_message *msg, int lines) { - if (mailbox_changed()) return 1; + if (mailbox_changed()) return POP_CRASH_SERVER; + + if (lseek(mailbox_fd, msg->data_offset, SEEK_SET) < 0) + return POP_CRASH_SERVER; + if (pop_reply_multiline(mailbox_fd, msg->data_size, lines)) + return POP_CRASH_NETFAIL; - if (lseek(mailbox_fd, msg->data_offset, SEEK_SET) < 0) return 1; - if (pop_reply_multiline(mailbox_fd, msg->data_size, lines)) return 1; + if (mailbox_changed()) return POP_CRASH_SERVER; - if (mailbox_changed()) return 1; + if (pop_reply_terminate()) return POP_CRASH_NETFAIL; - return pop_reply_terminate(); + return POP_OK; } static int mailbox_write(char *buffer) diff --git a/usr.sbin/popa3d/mailbox.h b/usr.sbin/popa3d/mailbox.h index ba6fc7ad0b0..102774ec97f 100644 --- a/usr.sbin/popa3d/mailbox.h +++ b/usr.sbin/popa3d/mailbox.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mailbox.h,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: mailbox.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Mailbox access. @@ -14,8 +14,8 @@ extern int mailbox_open(char *spool, char *mailbox); /* - * Sends (first lines of) a message to the POP client. Returns a non-zero - * value on error; the POP session then has to crash. + * Sends (first lines of) a message to the POP client. Returns one of the + * POP_* event codes. */ extern int mailbox_get(struct db_message *msg, int lines); diff --git a/usr.sbin/popa3d/params.h b/usr.sbin/popa3d/params.h index 717a3aa77b8..5d4e7db370b 100644 --- a/usr.sbin/popa3d/params.h +++ b/usr.sbin/popa3d/params.h @@ -1,4 +1,4 @@ -/* $OpenBSD: params.h,v 1.4 2001/08/25 15:35:09 camield Exp $ */ +/* $OpenBSD: params.h,v 1.5 2001/09/21 20:22:06 camield Exp $ */ /* * Global POP daemon parameters. @@ -8,6 +8,11 @@ #define _POP_PARAMS_H /* + * Our name to use when talking to various interfaces. + */ +#define POP_SERVER "popa3d" + +/* * Are we going to be a standalone server or start via an inetd clone? */ #define POP_STANDALONE 1 @@ -15,12 +20,40 @@ #if POP_STANDALONE /* + * Should the command line options be supported? + * If enabled, popa3d will default to inetd mode and will require a -D + * to actually enable the standalone mode. + */ +#define POP_OPTIONS 1 + +/* * The address and port to listen on. */ #define DAEMON_ADDR "0.0.0.0" /* INADDR_ANY */ #define DAEMON_PORT 110 /* + * Should libwrap be used? + * + * This may make things slower and also adds to code running as root, + * so it is recommended that you use a packet filter instead. This + * option is provided primarily as a way to meet conventions of certain + * systems where all services obey libwrap access controls. + */ +#ifdef LIBWRAP +#define DAEMON_LIBWRAP 1 +#else +#define DAEMON_LIBWRAP 0 +#endif + +#if DAEMON_LIBWRAP +/* + * How do we talk to libwrap? + */ +#define DAEMON_LIBWRAP_IDENT POP_SERVER +#endif + +/* * Limit the number of POP sessions we can handle at a time to reduce * the impact of connection flood DoS attacks. */ @@ -69,10 +102,16 @@ #endif /* - * An unprivileged dummy user to run as before authentication. The user - * and its UID must not be used for any other purpose. + * A pseudo-user to run as before authentication. The user and its UID + * must not be used for any other purpose. + */ +#define POP_USER POP_SERVER + +/* + * An empty directory to chroot to before authentication. The directory + * and its parent directories must not be writable by anyone but root. */ -#define POP_USER "popa3d" +#define POP_CHROOT "/usr/share/empty" /* * Sessions will be closed if idle for longer than POP_TIMEOUT seconds. @@ -133,9 +172,18 @@ /* * Your mail spool directory. Note: only local (non-NFS) mode 775 mail * spools are currently supported. + * + * #undef this for qmail-style $HOME/Mailbox mailboxes. */ #define MAIL_SPOOL_PATH "/var/mail" +#ifndef MAIL_SPOOL_PATH +/* + * The mailbox file name relative to the user's home directory. + */ +#define HOME_MAILBOX_NAME "Mailbox" +#endif + #endif /* @@ -148,10 +196,12 @@ /* * How do we talk to syslogd? These should be fine for most systems. */ -#define SYSLOG_IDENT "popa3d" +#define SYSLOG_IDENT POP_SERVER #define SYSLOG_OPTIONS LOG_PID #define SYSLOG_FACILITY LOG_DAEMON -#define SYSLOG_PRIORITY LOG_INFO +#define SYSLOG_PRI_LO LOG_INFO +#define SYSLOG_PRI_HI LOG_NOTICE +#define SYSLOG_PRI_ERROR LOG_CRIT /* * There's probably no reason to touch anything below this comment. diff --git a/usr.sbin/popa3d/pop_auth.c b/usr.sbin/popa3d/pop_auth.c index 65ea612d0bc..cbec928bc1d 100644 --- a/usr.sbin/popa3d/pop_auth.c +++ b/usr.sbin/popa3d/pop_auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pop_auth.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: pop_auth.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * AUTHORIZATION state handling. @@ -31,14 +31,14 @@ static int pop_auth_user(char *params) user = pop_get_param(¶ms); if (!user || pop_user || params) return POP_ERROR; - if (!(pop_user = strdup(user))) return POP_CRASH; + if (!(pop_user = strdup(user))) return POP_CRASH_SERVER; return POP_OK; } static int pop_auth_pass(char *params) { if (!params || !pop_user) return POP_ERROR; - if (!(pop_pass = strdup(params))) return POP_CRASH; + if (!(pop_pass = strdup(params))) return POP_CRASH_SERVER; return POP_STATE; } @@ -67,23 +67,25 @@ int do_pop_auth(int channel) return 0; } -void log_pop_auth(int result, char *mailbox) +void log_pop_auth(int result, char *user) { if (result == AUTH_NONE) { - syslog(SYSLOG_PRIORITY, "Didn't attempt authentication"); + syslog(SYSLOG_PRI_LO, "Didn't attempt authentication"); return; } #if POP_VIRTUAL if (virtual_domain) { - syslog(SYSLOG_PRIORITY, "Authentication %s for %s@%s", + syslog(result == AUTH_OK ? SYSLOG_PRI_LO : SYSLOG_PRI_HI, + "Authentication %s for %s@%s", result == AUTH_OK ? "passed" : "failed", - mailbox ? mailbox : "UNKNOWN", + user ? user : "UNKNOWN USER", virtual_domain); return; } #endif - syslog(SYSLOG_PRIORITY, "Authentication %s for %s", + syslog(result == AUTH_OK ? SYSLOG_PRI_LO : SYSLOG_PRI_HI, + "Authentication %s for %s", result == AUTH_OK ? "passed" : "failed", - mailbox ? mailbox : "UNKNOWN"); + user ? user : "UNKNOWN USER"); } diff --git a/usr.sbin/popa3d/pop_auth.h b/usr.sbin/popa3d/pop_auth.h index 4352552f133..2708dcd6058 100644 --- a/usr.sbin/popa3d/pop_auth.h +++ b/usr.sbin/popa3d/pop_auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pop_auth.h,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: pop_auth.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * AUTHORIZATION state handling. @@ -21,9 +21,8 @@ extern int do_pop_auth(int channel); /* - * Logs an authentication attempt for mailbox (or NULL if the requested - * mailbox doesn't exist). + * Logs an authentication attempt for user, use NULL for non-existent. */ -extern void log_pop_auth(int result, char *mailbox); +extern void log_pop_auth(int result, char *user); #endif diff --git a/usr.sbin/popa3d/pop_root.c b/usr.sbin/popa3d/pop_root.c index 194de4a19e4..d7509b133fd 100644 --- a/usr.sbin/popa3d/pop_root.c +++ b/usr.sbin/popa3d/pop_root.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pop_root.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: pop_root.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Main daemon code: invokes the actual POP handling routines. Most calls @@ -6,6 +6,7 @@ * POP_USER or the authenticated user). Depending on compile-time options * in params.h, the following files may contain code executed as root: * + * startup.c if supporting command line options (POP_OPTIONS) * standalone.c if not running via an inetd clone (POP_STANDALONE) * virtual.c if supporting virtual domains (POP_VIRTUAL) * auth_passwd.c if using passwd or *BSD (AUTH_PASSWD && !VIRTUAL_ONLY) @@ -17,6 +18,7 @@ #include <stdlib.h> #include <syslog.h> #include <errno.h> +#include <time.h> #include <grp.h> #include <pwd.h> #include <sys/stat.h> @@ -32,15 +34,19 @@ #endif #if !VIRTUAL_ONLY -extern struct passwd *auth_userpass(char *user, char *pass, char **mailbox); +extern struct passwd *auth_userpass(char *user, char *pass, int *known); #endif +/* POP_USER's pw_uid and pw_gid, other fields may not be valid */ static struct passwd pop_pw; -static char *mailbox; + +static int known; +static char *user; +static char *spool, *mailbox; int log_error(char *s) { - syslog(SYSLOG_PRIORITY, "%s: %m", s); + syslog(SYSLOG_PRI_ERROR, "%s: %m", s); return 1; } @@ -58,6 +64,17 @@ static int set_user(struct passwd *pw) return 0; } +static int drop_root(void) +{ + tzset(); + openlog(SYSLOG_IDENT, SYSLOG_OPTIONS | LOG_NDELAY, SYSLOG_FACILITY); + + if (chroot(POP_CHROOT)) return log_error("chroot"); + if (chdir("/")) return log_error("chdir"); + + return set_user(&pop_pw); +} + /* * Attempts to read until EOF, and returns the number of bytes read. * We don't expect any signals, so even EINTR is considered an error. @@ -89,10 +106,10 @@ static int read_loop(int fd, char *buffer, int count) static int do_root_auth(int channel) { static char auth[AUTH_BUFFER_SIZE + 2]; - char *user, *pass; + char *pass; struct passwd *pw; - mailbox = NULL; + known = 0; #if POP_VIRTUAL virtual_domain = NULL; #endif @@ -104,30 +121,56 @@ static int do_root_auth(int channel) sizeof(pop_buffer)) return AUTH_NONE; /* Now, the authentication data. */ - memset(auth, 0, sizeof(auth)); /* Ensure the NUL termination */ - if (read_loop(channel, auth, AUTH_BUFFER_SIZE) < 0) return AUTH_NONE; + memset(auth, 0, sizeof(auth)); /* Ensure NUL termination */ + if (read_loop(channel, auth, AUTH_BUFFER_SIZE) < 0) { + memset(auth, 0, sizeof(auth)); + return AUTH_NONE; + } user = auth; pass = &user[strlen(user) + 1]; pw = NULL; #if POP_VIRTUAL - if (!(pw = virtual_userpass(user, pass, &mailbox)) && virtual_domain) + if (!(pw = virtual_userpass(user, pass, &known)) && virtual_domain) { + memset(pass, 0, strlen(pass)); return AUTH_FAILED; + } #endif #if VIRTUAL_ONLY - if (!pw) + if (!pw) { + memset(pass, 0, strlen(pass)); return AUTH_FAILED; + } #else - if (!pw && !(pw = auth_userpass(user, pass, &mailbox))) + if (!pw && !(pw = auth_userpass(user, pass, &known))) { + memset(pass, 0, strlen(pass)); return AUTH_FAILED; + } #endif - if (!*user || !*pass) return AUTH_FAILED; - + if (!*pass) return AUTH_FAILED; memset(pass, 0, strlen(pass)); + if (!*user) return AUTH_FAILED; if (set_user(pw)) return AUTH_FAILED; +#if POP_VIRTUAL + if (virtual_domain) { + spool = virtual_spool; + mailbox = user; + + return AUTH_OK; + } +#endif + +#ifdef MAIL_SPOOL_PATH + spool = MAIL_SPOOL_PATH; + mailbox = user; +#else + spool = pw->pw_dir; + mailbox = HOME_MAILBOX_NAME; +#endif + return AUTH_OK; } @@ -142,11 +185,14 @@ int do_pop_startup(void) errno = 0; if (!(pw = getpwnam(POP_USER))) { - syslog(SYSLOG_PRIORITY, "getpwnam(\"" POP_USER "\"): %s", + syslog(SYSLOG_PRI_ERROR, "getpwnam(\"" POP_USER "\"): %s", errno ? strerror(errno) : "No such user"); return 1; } - memcpy(&pop_pw, pw, sizeof(pop_pw)); + memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); + endpwent(); + pop_pw.pw_uid = pw->pw_uid; + pop_pw.pw_gid = pw->pw_gid; #if POP_VIRTUAL if (virtual_startup()) return 1; @@ -160,7 +206,10 @@ int do_pop_session(void) int channel[2]; int result, status; - signal(SIGCHLD, SIG_IGN); +/* For SIGCHLD, default action is to ignore the signal. {SIGCHLD, SIG_IGN} + * may be invalid (POSIX) or may enable a different behavior (SUSv2), none + * of which are any good for us. */ + signal(SIGCHLD, SIG_DFL); if (pipe(channel)) return log_error("pipe"); @@ -170,7 +219,7 @@ int do_pop_session(void) case 0: if (close(channel[0])) return log_error("close"); - if (set_user(&pop_pw)) return 1; + if (drop_root()) return 1; return do_pop_auth(channel[1]); } @@ -189,18 +238,12 @@ int do_pop_session(void) if (result == AUTH_OK) { if (close(channel[0])) return log_error("close"); - log_pop_auth(result, mailbox); -#if POP_VIRTUAL - if (virtual_domain) - return do_pop_trans(virtual_spool, mailbox); -#endif -#if !VIRTUAL_ONLY - return do_pop_trans(MAIL_SPOOL_PATH, mailbox); -#endif + log_pop_auth(result, user); + return do_pop_trans(spool, mailbox); } - if (set_user(&pop_pw)) return 1; - log_pop_auth(result, mailbox); + if (drop_root()) return 1; + log_pop_auth(result, known ? user : NULL); #ifdef AUTH_FAILED_MESSAGE if (result == AUTH_FAILED) pop_reply("-ERR %s", AUTH_FAILED_MESSAGE); @@ -211,7 +254,7 @@ int do_pop_session(void) return status; } -#if !POP_STANDALONE +#if !POP_STANDALONE && !POP_OPTIONS int main(void) { if (do_pop_startup()) return 1; diff --git a/usr.sbin/popa3d/pop_trans.c b/usr.sbin/popa3d/pop_trans.c index 05ecbec76a3..59155066ce8 100644 --- a/usr.sbin/popa3d/pop_trans.c +++ b/usr.sbin/popa3d/pop_trans.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pop_trans.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: pop_trans.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * TRANSACTION state handling. @@ -28,7 +28,7 @@ static int pop_trans_stat(char *params) { if (params) return POP_ERROR; if (pop_reply("+OK %d %ld", db.visible_count, db.visible_size)) - return POP_CRASH; + return POP_CRASH_NETFAIL; return POP_QUIET; } @@ -51,14 +51,14 @@ static int pop_trans_list_or_uidl(char *params, int uidl) msg->hash[1], msg->hash[0], msg->hash[7], msg->hash[6], msg->hash[5], msg->hash[4])) - return POP_CRASH; + return POP_CRASH_NETFAIL; } else if (pop_reply("+OK %d %ld", number, msg->size)) - return POP_CRASH; + return POP_CRASH_NETFAIL; return POP_QUIET; } - if (pop_reply_ok()) return POP_CRASH; + if (pop_reply_ok()) return POP_CRASH_NETFAIL; for (number = 1; number <= db.total_count; number++) { msg = db.array[number - 1]; if (msg->flags & MSG_DELETED) continue; @@ -70,12 +70,12 @@ static int pop_trans_list_or_uidl(char *params, int uidl) msg->hash[1], msg->hash[0], msg->hash[7], msg->hash[6], msg->hash[5], msg->hash[4])) - return POP_CRASH; + return POP_CRASH_NETFAIL; } else if (pop_reply("%d %ld", number, msg->size)) - return POP_CRASH; + return POP_CRASH_NETFAIL; } - if (pop_reply_terminate()) return POP_CRASH; + if (pop_reply_terminate()) return POP_CRASH_NETFAIL; return POP_QUIET; } @@ -94,12 +94,13 @@ static int pop_trans_retr(char *params) { int number; struct db_message *msg; + int event; number = pop_get_int(¶ms); if (number < 1 || number > db.total_count || params) return POP_ERROR; msg = db.array[number - 1]; if (msg->flags & MSG_DELETED) return POP_ERROR; - if (mailbox_get(msg, -1)) return POP_CRASH; + if ((event = mailbox_get(msg, -1)) != POP_OK) return event; #if POP_SUPPORT_LAST if (number > db.last) db.last = number; #endif @@ -110,6 +111,7 @@ static int pop_trans_top(char *params) { int number, lines; struct db_message *msg; + int event; number = pop_get_int(¶ms); if (number < 1 || number > db.total_count) return POP_ERROR; @@ -117,7 +119,7 @@ static int pop_trans_top(char *params) if (lines < 0 || params) return POP_ERROR; msg = db.array[number - 1]; if (msg->flags & MSG_DELETED) return POP_ERROR; - if (mailbox_get(msg, lines)) return POP_CRASH; + if ((event = mailbox_get(msg, lines)) != POP_OK) return event; return POP_QUIET; } @@ -161,7 +163,7 @@ static int pop_trans_rset(char *params) static int pop_trans_last(char *params) { if (params) return POP_ERROR; - if (pop_reply("+OK %d", db.last)) return POP_CRASH; + if (pop_reply("+OK %d", db.last)) return POP_CRASH_NETFAIL; return POP_QUIET; } #endif @@ -203,28 +205,32 @@ int do_pop_trans(char *spool, char *mailbox) if (!pop_sane()) return 1; if (db_load(spool, mailbox)) { - syslog(SYSLOG_PRIORITY, "Failed to open mailbox"); + syslog(SYSLOG_PRI_HI, + "Failed or refused to load %s/%s", + spool, mailbox); pop_reply_error(); return 0; } - syslog(SYSLOG_PRIORITY, "%d message%s (%ld byte%s) loaded", + syslog(SYSLOG_PRI_LO, "%d message%s (%ld byte%s) loaded", db.total_count, db.total_count == 1 ? "" : "s", db.total_size, db.total_size == 1 ? "" : "s"); if (pop_reply_ok()) - result = POP_CRASH; + result = POP_CRASH_NETFAIL; else switch ((result = pop_handle_state(pop_trans_commands))) { case POP_STATE: if (mailbox_update()) { if (db.flags & DB_STALE) break; - syslog(SYSLOG_PRIORITY, "Failed to update mailbox"); + syslog(SYSLOG_PRI_ERROR, + "Failed to update %s/%s", + spool, mailbox); pop_reply_error(); break; } - syslog(SYSLOG_PRIORITY, "%d (%ld) deleted, %d (%ld) left", + syslog(SYSLOG_PRI_LO, "%d (%ld) deleted, %d (%ld) left", db.total_count - db.visible_count, db.total_size - db.visible_size, db.visible_count, @@ -232,15 +238,21 @@ int do_pop_trans(char *spool, char *mailbox) pop_reply_ok(); break; - case POP_TIMED_OUT: - syslog(SYSLOG_PRIORITY, "Connection timed out"); + case POP_CRASH_NETFAIL: + syslog(SYSLOG_PRI_LO, "Premature disconnect"); + break; + + case POP_CRASH_NETTIME: + syslog(SYSLOG_PRI_LO, "Connection timed out"); } if (db.flags & DB_STALE) - syslog(SYSLOG_PRIORITY, "Another MUA active, giving up"); + syslog(SYSLOG_PRI_LO, "Another MUA active, giving up"); else - if (result == POP_CRASH) - syslog(SYSLOG_PRIORITY, "Session crashed"); + if (result == POP_CRASH_SERVER) + syslog(SYSLOG_PRI_ERROR, + "Server failure accessing %s/%s", + spool, mailbox); mailbox_close(); diff --git a/usr.sbin/popa3d/protocol.c b/usr.sbin/popa3d/protocol.c index cbe5aa41b19..4ff40f97769 100644 --- a/usr.sbin/popa3d/protocol.c +++ b/usr.sbin/popa3d/protocol.c @@ -1,4 +1,4 @@ -/* $OpenBSD: protocol.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: protocol.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * POP protocol handling. @@ -17,7 +17,7 @@ #include "protocol.h" struct pop_buffer pop_buffer; -static jmp_buf pop_timed_out; +static sigjmp_buf pop_timed_out; void pop_init(void) { @@ -41,7 +41,7 @@ int pop_sane(void) static void pop_timeout(int signum) { signal(SIGALRM, SIG_DFL); - longjmp(pop_timed_out, 1); + siglongjmp(pop_timed_out, 1); } static int pop_fetch(void) @@ -103,7 +103,7 @@ int pop_handle_state(struct pop_command *commands) struct pop_command *command; int response; - if (setjmp(pop_timed_out)) return POP_TIMED_OUT; + if (sigsetjmp(pop_timed_out, 1)) return POP_CRASH_NETTIME; while (pop_get_line(line, sizeof(line))) { if ((params = strchr(line, ' '))) { @@ -120,24 +120,24 @@ int pop_handle_state(struct pop_command *commands) switch (response) { case POP_OK: - if (pop_reply_ok()) return POP_CRASH; + if (pop_reply_ok()) return POP_CRASH_NETFAIL; break; case POP_ERROR: - if (pop_reply_error()) return POP_CRASH; + if (pop_reply_error()) return POP_CRASH_NETFAIL; case POP_QUIET: break; case POP_LEAVE: - if (pop_reply_ok()) return POP_CRASH; + if (pop_reply_ok()) return POP_CRASH_NETFAIL; default: return response; } } - return POP_CRASH; + return POP_CRASH_NETFAIL; } char *pop_get_param(char **params) @@ -207,8 +207,7 @@ int pop_reply_error(void) int pop_reply_multiline(int fd, long size, int lines) { - char *in_buffer; - char *out_buffer; + char *in_buffer, *out_buffer; char *in, *out; int in_block, out_block; int start, body; diff --git a/usr.sbin/popa3d/protocol.h b/usr.sbin/popa3d/protocol.h index 05cacace937..8f2863184d3 100644 --- a/usr.sbin/popa3d/protocol.h +++ b/usr.sbin/popa3d/protocol.h @@ -1,4 +1,4 @@ -/* $OpenBSD: protocol.h,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: protocol.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * POP protocol handling. @@ -15,8 +15,9 @@ #define POP_QUIET 2 /* We've already replied */ #define POP_LEAVE 3 /* Leave the session */ #define POP_STATE 4 /* Advance the state */ -#define POP_CRASH 5 /* Session crashed */ -#define POP_TIMED_OUT 6 /* Connection timed out */ +#define POP_CRASH_NETFAIL 5 /* Network failure */ +#define POP_CRASH_NETTIME 6 /* Network timeout */ +#define POP_CRASH_SERVER 7 /* POP server failure */ /* * POP command description. diff --git a/usr.sbin/popa3d/standalone.c b/usr.sbin/popa3d/standalone.c index 0f374e01ce3..da8d60f19f7 100644 --- a/usr.sbin/popa3d/standalone.c +++ b/usr.sbin/popa3d/standalone.c @@ -1,4 +1,4 @@ -/* $OpenBSD: standalone.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: standalone.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Standalone POP server: accepts connections, checks the anti-flood limits, @@ -24,6 +24,12 @@ #include <netinet/in.h> #include <arpa/inet.h> +#if DAEMON_LIBWRAP +#include <tcpd.h> +int allow_severity = SYSLOG_PRI_LO; +int deny_severity = SYSLOG_PRI_HI; +#endif + /* * These are defined in pop_root.c. */ @@ -31,6 +37,9 @@ extern int log_error(char *s); extern int do_pop_startup(void); extern int do_pop_session(void); +typedef sig_atomic_t a_int; +typedef volatile a_int va_int; + /* * Active POP sessions. Those that were started within the last MIN_DELAY * seconds are also considered active (regardless of their actual state), @@ -39,13 +48,13 @@ extern int do_pop_session(void); */ static struct { struct in_addr addr; /* Source IP address */ - int pid; /* PID of the server, or 0 for none */ + a_int pid; /* PID of the server, or 0 for none */ clock_t start; /* When the server was started */ clock_t log; /* When we've last logged a failure */ } sessions[MAX_SESSIONS]; -static volatile int child_blocked; /* We use blocking to avoid races */ -static volatile int child_pending; /* Are any dead children waiting? */ +static va_int child_blocked; /* We use blocking to avoid races */ +static va_int child_pending; /* Are any dead children waiting? */ /* * SIGCHLD handler; can also be called directly with a zero signum. @@ -76,7 +85,31 @@ static void handle_child(int signum) errno = saved_errno; } +#if DAEMON_LIBWRAP +static void check_access(int sock) +{ + struct request_info request; + + request_init(&request, + RQ_DAEMON, DAEMON_LIBWRAP_IDENT, + RQ_FILE, sock, + 0); + fromhost(&request); + + if (!hosts_access(&request)) { +/* refuse() shouldn't return... */ + refuse(&request); +/* ...but just in case */ + exit(1); + } +} +#endif + +#if POP_OPTIONS +int do_standalone(void) +#else int main(void) +#endif { int true = 1; int sock, new; @@ -169,7 +202,7 @@ int main(void) if (!sessions[i].log || now < sessions[i].log || now - sessions[i].log >= MIN_DELAY * CLK_TCK) { - syslog(SYSLOG_PRIORITY, + syslog(SYSLOG_PRI_HI, "%s: per source limit reached", inet_ntoa(addr.sin_addr)); sessions[i].log = now; @@ -178,21 +211,24 @@ int main(void) } if (j < 0) { - syslog(SYSLOG_PRIORITY, "%s: sessions limit reached", + syslog(SYSLOG_PRI_HI, "%s: sessions limit reached", inet_ntoa(addr.sin_addr)); continue; } switch ((pid = fork())) { case -1: - syslog(SYSLOG_PRIORITY, "%s: fork: %m", + syslog(SYSLOG_PRI_ERROR, "%s: fork: %m", inet_ntoa(addr.sin_addr)); break; case 0: - syslog(SYSLOG_PRIORITY, "Session from %s", - inet_ntoa(addr.sin_addr)); if (close(sock)) return log_error("close"); +#if DAEMON_LIBWRAP + check_access(new); +#endif + syslog(SYSLOG_PRI_LO, "Session from %s", + inet_ntoa(addr.sin_addr)); if (dup2(new, 0) < 0) return log_error("dup2"); if (dup2(new, 1) < 0) return log_error("dup2"); if (dup2(new, 2) < 0) return log_error("dup2"); @@ -201,7 +237,7 @@ int main(void) default: sessions[j].addr = addr.sin_addr; - (volatile int)sessions[j].pid = pid; + (va_int)sessions[j].pid = pid; sessions[j].start = now; sessions[j].log = 0; } diff --git a/usr.sbin/popa3d/startup.c b/usr.sbin/popa3d/startup.c new file mode 100644 index 00000000000..d554fbe992e --- /dev/null +++ b/usr.sbin/popa3d/startup.c @@ -0,0 +1,66 @@ +/* $OpenBSD: startup.c,v 1.1 2001/09/21 20:22:06 camield Exp $ */ + +/* + * Command line option parsing. + */ + +#include "params.h" + +#if POP_OPTIONS + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +/* pop_root.c */ +extern int do_pop_startup(void); +extern int do_pop_session(void); + +/* standalone.c */ +extern int do_standalone(void); + +#ifdef HAVE_PROGNAME +extern char *__progname; +#define progname __progname +#else +static char *progname; +#endif + +static void usage(void) +{ + fprintf(stderr, "Usage: %s [-D]\n", progname); + exit(1); +} + +int main(int argc, char **argv) +{ + int c; + int standalone = 0; + +#ifndef HAVE_PROGNAME + if (!(progname = argv[0])) + progname = POP_SERVER; +#endif + + while ((c = getopt(argc, argv, "D")) != -1) { + switch (c) { + case 'D': + standalone++; + break; + + default: + usage(); + } + } + + if (optind != argc) + usage(); + + if (standalone) + return do_standalone(); + + if (do_pop_startup()) return 1; + return do_pop_session(); +} + +#endif diff --git a/usr.sbin/popa3d/virtual.c b/usr.sbin/popa3d/virtual.c index c11975d7a5d..2202f8409f3 100644 --- a/usr.sbin/popa3d/virtual.c +++ b/usr.sbin/popa3d/virtual.c @@ -1,4 +1,4 @@ -/* $OpenBSD: virtual.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: virtual.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Virtual domain support. @@ -8,7 +8,7 @@ #if POP_VIRTUAL -#define _XOPEN_SOURCE +#define _XOPEN_SOURCE 4 #define _XOPEN_SOURCE_EXTENDED #define _XOPEN_VERSION 4 #define _XPG4_2 @@ -52,7 +52,7 @@ static char *lookup(void) return inet_ntoa(sin.sin_addr); } -static int isvaliduser(char *user) +static int is_valid_user(char *user) { unsigned char *p; @@ -66,7 +66,7 @@ static int isvaliduser(char *user) return 1; } -struct passwd *virtual_userpass(char *user, char *pass, char **mailbox) +struct passwd *virtual_userpass(char *user, char *pass, int *known) { struct passwd *pw, *result; struct stat stat; @@ -76,6 +76,8 @@ struct passwd *virtual_userpass(char *user, char *pass, char **mailbox) int fail; int fd, size; + *known = 0; + /* Make sure we don't try to authenticate globally if something fails * before we find out whether the virtual domain is known to us */ virtual_domain = "UNKNOWN"; @@ -90,7 +92,7 @@ struct passwd *virtual_userpass(char *user, char *pass, char **mailbox) } fail = 0; - if (!isvaliduser(user)) { + if (!is_valid_user(user)) { user = "INVALID"; fail = 1; } @@ -138,7 +140,7 @@ struct passwd *virtual_userpass(char *user, char *pass, char **mailbox) size = 0; if (fd >= 0) { - if (!fail) *mailbox = user; + *known = !fail; if ((size = read(fd, auth, sizeof(auth))) < 0) { log_error("read"); @@ -167,10 +169,8 @@ struct passwd *virtual_userpass(char *user, char *pass, char **mailbox) } if (!strtok(NULL, ":")) fail = 1; - if ((pw = getpwnam(template))) { + if ((pw = getpwnam(template))) memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); - pw->pw_passwd = "*"; - } endpwent(); result = NULL; diff --git a/usr.sbin/popa3d/virtual.h b/usr.sbin/popa3d/virtual.h index 312e7c99743..baa8e3b6d8d 100644 --- a/usr.sbin/popa3d/virtual.h +++ b/usr.sbin/popa3d/virtual.h @@ -1,4 +1,4 @@ -/* $OpenBSD: virtual.h,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ +/* $OpenBSD: virtual.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ /* * Virtual domain support. @@ -28,9 +28,9 @@ extern int virtual_startup(void); * indicated either by the connected IP address (the socket is available * on fd 0), or as a part of the username. If the virtual domain is known, * virtual_domain and virtual_spool are set appropriately. If the username - * is known as well, mailbox is set to the username. Returns the template - * user to run as if the authentication is successful, or NULL otherwise. + * is known as well, known is set. Returns the template user to run as if + * authentication is succeeds, or NULL otherwise. */ -extern struct passwd *virtual_userpass(char *user, char *pass, char **mailbox); +extern struct passwd *virtual_userpass(char *user, char *pass, int *known); #endif |