diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/popa3d/DESIGN | 210 | ||||
-rw-r--r-- | usr.sbin/popa3d/LICENSE | 9 | ||||
-rw-r--r-- | usr.sbin/popa3d/Makefile | 16 | ||||
-rw-r--r-- | usr.sbin/popa3d/VIRTUAL | 5 | ||||
-rw-r--r-- | usr.sbin/popa3d/auth_passwd.c | 41 | ||||
-rw-r--r-- | usr.sbin/popa3d/database.c | 95 | ||||
-rw-r--r-- | usr.sbin/popa3d/database.h | 57 | ||||
-rw-r--r-- | usr.sbin/popa3d/mailbox.c | 503 | ||||
-rw-r--r-- | usr.sbin/popa3d/mailbox.h | 32 | ||||
-rw-r--r-- | usr.sbin/popa3d/misc.c | 89 | ||||
-rw-r--r-- | usr.sbin/popa3d/misc.h | 29 | ||||
-rw-r--r-- | usr.sbin/popa3d/params.h | 250 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_auth.c | 98 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_auth.h | 28 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_root.c | 275 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_trans.c | 266 | ||||
-rw-r--r-- | usr.sbin/popa3d/pop_trans.h | 12 | ||||
-rw-r--r-- | usr.sbin/popa3d/popa3d.8 | 187 | ||||
-rw-r--r-- | usr.sbin/popa3d/protocol.c | 287 | ||||
-rw-r--r-- | usr.sbin/popa3d/protocol.h | 106 | ||||
-rw-r--r-- | usr.sbin/popa3d/standalone.c | 339 | ||||
-rw-r--r-- | usr.sbin/popa3d/startup.c | 91 | ||||
-rw-r--r-- | usr.sbin/popa3d/version.c | 9 | ||||
-rw-r--r-- | usr.sbin/popa3d/virtual.c | 197 | ||||
-rw-r--r-- | usr.sbin/popa3d/virtual.h | 36 |
25 files changed, 0 insertions, 3267 deletions
diff --git a/usr.sbin/popa3d/DESIGN b/usr.sbin/popa3d/DESIGN deleted file mode 100644 index e1466b9b251..00000000000 --- a/usr.sbin/popa3d/DESIGN +++ /dev/null @@ -1,210 +0,0 @@ -This file describes the design goals and the reasoning behind some of -the design decisions for my tiny POP3 daemon, popa3d. - - - Why popa3d? - -There're lots of different POP3 servers -- with different feature -sets, performance, and reliability. However, as far as I know, before -I started the work on popa3d, there had been only one with security as -one of its primary design goals: qmail-pop3d. Unfortunately, it would -only work with qmail, and only with its new maildir format. While -both qmail and maildirs do indeed have some advantages, a lot of -people continue running other MTAs, and/or use the older mailbox -format, for various reasons. Many of them need a POP3 server. - - - The design goals. - -Well, the goals themselves are obvious; they're probably the same for -most other POP3 servers as well. It's their priority that differs. -For popa3d, the goals are: - -1. Security (to the extent that is possible with POP3 at all, of -course). - -2. Reliability (again, as limited by the mailbox format and the -protocol). - -3. RFC compliance (slightly relaxed to work with real-world POP3 -clients). - -4. Performance (limited by the more important goals, above). - -Obviously, just like the comments indicate, none of the goals can be -met completely, and balanced decisions need to be made. - - - Security. - -First, it is important that none of the popa3d users get a false sense -of security just because it was the primary design goal. The POP3 -protocol transmits passwords in plaintext and thus, if you care about -the security of your individual user accounts, should only be used -either in trusted networks or tunneled over encrypted channels. -There exist extensions to the protocol that are supposed to fix this -problem. I am not supporting them yet, partly because this isn't -going to fully fix the problem. In fact, APOP and the weaker defined -SASL mechanisms such as CRAM-MD5 may potentially be even less secure -than transmission of plaintext passwords because of the requirement -that plaintext equivalents be stored on the server. - -It is also important to understand that nothing can be perfectly -secure. I can make mistakes. While the design of popa3d makes it -harder for those to turn into security holes, this is nevertheless -still possible. - -Having that said, let's get to the security-critical design decisions. - - - Privilege management. - -Initially, popa3d is started as root to handle a connection. However, -it does very little work as root: switching to less privileged UIDs, -communication with child processes, and authentication information -checks (which often involve accessing shadow or master.passwd files). - -The following privilege switches happen during a successful POP3 -session, with /etc/shadow authentication: - - startup as root - | - ----------------- - |child |parent - v v - drop to user popa3d, still as root, - handle the AUTHORIZATION wait for and - state, write the results, - - > read the authentication - and exit information - | - ----------------- - |child |parent - v v - getspnam(3), crypt(3), wait for and - check, write the result, - - > read the authentication - and exit (to clean up) result - | - v - drop to the authenticated user, - handle the TRANSACTION state, - possibly UPDATE the mailbox, - and exit - - - Trust. - -No part of popa3d trusts any information obtained from external -sources (that is, the data is never assumed to be of the expected -format, and is treated as subject to authorization checks). This -includes POP3 commands, mailbox contents, and even popa3d's own -less-privileged child process for the AUTHORIZATION state handling. - - - DoS attacks. - -Just like with most other software, there exist ways to cause a Denial -of Service, by supplying popa3d with an enormous amount of otherwise -valid input. I am aware of the following attacks on popa3d itself: - -1. Connection flood. When running in the standalone mode, popa3d does -quite a few checks to significantly reduce the impact of such attacks -by limiting resource consumption (child processes and logging rate), -while still providing full service for other source IP addresses and -logging everything that might be important. However, when running -from an inetd clone, the handling of these attacks is left up to your -inetd and the kernel. - -2. Huge mailbox sizes, either in message count or bytes. There're -limits in popa3d (see params.h) that are intended to prevent this -attack from stopping the entire service. Depending on your disk and -other quotas, it may still be possible to stop individual users from -getting their mail. - - - Reliability. - -Quoting Dan Bernstein, "the mbox format ... is inherently unreliable". - -While popa3d, just like other mail software that deals with mailboxes, -doesn't guarantee reliability over system crashes, it still makes -sense to talk about its operation on an otherwise stable system. - - - Interaction with other MUAs. - -Similarly to cucipop (but unlike qpopper), popa3d works on the -original mailbox file, without copying. However, unlike cucipop, -popa3d is able to ensure that the mailbox doesn't get corrupted if -another MUA modifies it during the POP session. Before each mailbox -access, popa3d checks its timestamp and, if that has changed, -determines if that is due to new mail that has just been delivered, or -other changes made to the mailbox. In the latter case, the POP -session is silently aborted (which doesn't violate the RFC). popa3d -is careful to make sure the timestamp will change if the mailbox is -written to, by keeping the lock for up to a second if necessary. - - - Mailbox access. - -Except for the total size and message count limits mentioned above -(and you can disable even those), there're no other artificial limits -on the mailbox contents. In particular, there're no line length -limits; unlike with qmail-pop3d, lines don't even need to fit in the -available memory. NUL bytes are allowed in messages as well. - - - Locking. - -Because of dropping to the user "completely" (that is, not even -keeping a GID of mail like some other POP3 servers do), popa3d only -uses fcntl(2) or flock(2) for locking. As a result, it may not be -safe over NFS. This is where I choose security over either -functionality or reliability. - - - RFC compliance. - -I tried to make popa3d as strictly RFC 1939 compliant as possible. -Most other POP3 servers have extra "features" that violate the RFC. -Examples include: wrapping long commands (no matter if they're valid -or not) and thus generating multiple -ERR responses (if not even -worse: processing something from the middle of the line as a command) -to a single command, processing "LIST 4294967297" as "LIST 1" instead -of reporting the error, ignoring past a NUL byte till end of line and -thus misinterpreting the command. While these are mostly harmless, -they can theoretically cause a POP3 client not to detect the -unavailability of a protocol extension. - -There's however one place where popa3d's RFC compliance is -deliberately relaxed: popa3d accepts commands terminated by single -LFs, even though the RFC says the commands are terminated by a CRLF -pair. - - - Performance. - -Despite the two extra "security" fork(2) calls, popa3d seems to behave -fairly efficiently: the efficient mailbox parsing code and the lack of -mailbox copying compensate for the extra fork's. - -Here's some real performance data that I've collected (popa3d running -via inetd; larger sites would use the standalone mode instead): - - 24864 295.50re 16.92cp popa3d* - 12749 4578.88re 15.50cp popa3d - -That is, 12749 POP3 sessions took 32.42 minutes of CPU time (on a 350 -MHz Pentium II); of those, more than a half was spent in the temporary -child processes. It's not that bad though, as this system was running -an (intentionally) expensive crypt(3) that got accounted to the child -/etc/shadow authentication processes. - -Before upgrading to popa3d, the same machine was running qpopper (out -of inetd, too): - - 12025 3169.38re 35.56cp popper - -It used to take a bit more CPU for less POP3 sessions. - --- -Solar Designer <solar at openwall.com> diff --git a/usr.sbin/popa3d/LICENSE b/usr.sbin/popa3d/LICENSE deleted file mode 100644 index dc50971f05d..00000000000 --- a/usr.sbin/popa3d/LICENSE +++ /dev/null @@ -1,9 +0,0 @@ -You're allowed to do whatever you like with this software (including -re-distribution in source and/or binary form, with or without -modification), provided that credit is given where it is due and any -modified versions are marked as such. There's absolutely no warranty. - -Note that you don't have to re-distribute this software under these -same relaxed terms. In particular, you're free to place modified -versions under (L)GPL, thus disallowing further re-distribution in -binary-only form. diff --git a/usr.sbin/popa3d/Makefile b/usr.sbin/popa3d/Makefile deleted file mode 100644 index 2d71146b2df..00000000000 --- a/usr.sbin/popa3d/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# $OpenBSD: Makefile,v 1.4 2003/05/12 19:28:22 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 startup.c version.c - -CFLAGS+=-Wall -DHAVE_PROGNAME - -.include <bsd.prog.mk> - -.if (${TCP_WRAPPERS:L} == "yes") -CFLAGS+= -DLIBWRAP -LDADD+= -lwrap -DPADD+= ${LIBWRAP} -.endif diff --git a/usr.sbin/popa3d/VIRTUAL b/usr.sbin/popa3d/VIRTUAL deleted file mode 100644 index 23341277b81..00000000000 --- a/usr.sbin/popa3d/VIRTUAL +++ /dev/null @@ -1,5 +0,0 @@ -The virtual domain support in popa3d is in development and is currently -undocumented. - -Please only use it if you know what you are doing, -- it is too easy to -misconfigure it in dangerous ways. diff --git a/usr.sbin/popa3d/auth_passwd.c b/usr.sbin/popa3d/auth_passwd.c deleted file mode 100644 index d0503ac7aa7..00000000000 --- a/usr.sbin/popa3d/auth_passwd.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $OpenBSD: auth_passwd.c,v 1.2 2001/09/21 20:22:06 camield Exp $ */ - -/* - * The /etc/passwd authentication routine. - */ - -#include "params.h" - -#if AUTH_PASSWD && !VIRTUAL_ONLY - -#define _XOPEN_SOURCE 4 -#define _XOPEN_SOURCE_EXTENDED -#define _XOPEN_VERSION 4 -#define _XPG4_2 -#include <unistd.h> -#include <string.h> -#include <pwd.h> -#include <sys/types.h> - -struct passwd *auth_userpass(char *user, char *pass, int *known) -{ - struct passwd *pw, *result; - - *known = (pw = getpwnam(user)) != NULL; - endpwent(); - result = NULL; - - if (!pw || !*pw->pw_passwd || - *pw->pw_passwd == '*' || *pw->pw_passwd == '!') - crypt(pass, AUTH_DUMMY_SALT); - else - if (!strcmp(crypt(pass, pw->pw_passwd), pw->pw_passwd)) - result = pw; - - if (pw) - memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); - - return result; -} - -#endif diff --git a/usr.sbin/popa3d/database.c b/usr.sbin/popa3d/database.c deleted file mode 100644 index c85ffcc8d77..00000000000 --- a/usr.sbin/popa3d/database.c +++ /dev/null @@ -1,95 +0,0 @@ -/* $OpenBSD: database.c,v 1.2 2003/05/12 19:28:22 camield Exp $ */ - -/* - * Message database management. - */ - -#include <stdlib.h> -#include <string.h> - -#include "params.h" -#include "database.h" - -struct db_main db; - -void db_init(void) -{ - db.head = db.tail = NULL; - db.total_count = 0; - db.total_size = 0; - db.flags = 0; -#if POP_SUPPORT_LAST - db.last = 0; -#endif -} - -int db_add(struct db_message *msg) -{ - struct db_message *entry; - - if (db.total_count >= MAX_MAILBOX_MESSAGES) goto out_fail; - if (++db.total_count <= 0) goto out_undo_count; - if ((db.total_size += msg->size) < msg->size) goto out_undo_size; - - entry = malloc(sizeof(struct db_message)); - if (!entry) goto out_undo_size; - - memcpy(entry, msg, sizeof(struct db_message)); - entry->next = NULL; - entry->flags = 0; - - if (db.tail) - db.tail = db.tail->next = entry; - else - db.tail = db.head = entry; - - return 0; - -out_undo_size: - db.total_size -= msg->size; - -out_undo_count: - db.total_count--; - -out_fail: - return 1; -} - -int db_delete(struct db_message *msg) -{ - if (msg->flags & MSG_DELETED) return 1; - - msg->flags |= MSG_DELETED; - - db.visible_count--; - db.visible_size -= msg->size; - db.flags |= DB_DIRTY; - - return 0; -} - -int db_fix(void) -{ - unsigned long size; - struct db_message *entry; - unsigned int index; - - db.visible_count = db.total_count; - db.visible_size = db.total_size; - - if (!db.total_count) return 0; - - size = sizeof(struct db_message *) * db.total_count; - if (size / sizeof(struct db_message *) != db.total_count) return 1; - - db.array = malloc(size); - if (!db.array) return 1; - - entry = db.head; - index = 0; - do { - db.array[index++] = entry; - } while ((entry = entry->next)); - - return 0; -} diff --git a/usr.sbin/popa3d/database.h b/usr.sbin/popa3d/database.h deleted file mode 100644 index 71dc9ee4956..00000000000 --- a/usr.sbin/popa3d/database.h +++ /dev/null @@ -1,57 +0,0 @@ -/* $OpenBSD: database.h,v 1.2 2003/05/12 19:28:22 camield Exp $ */ - -/* - * Message database management. - */ - -#ifndef _POP_DATABASE_H -#define _POP_DATABASE_H - -#include "params.h" - -/* - * Message flags. - */ -/* Marked for deletion */ -#define MSG_DELETED 0x00000001 - -/* - * Database flags. - */ -/* Some messages are marked for deletion, mailbox update is needed */ -#define DB_DIRTY 0x00000001 -/* Another MUA has modified our part of the mailbox */ -#define DB_STALE 0x00000002 - -struct db_message { - struct db_message *next; - unsigned long size; /* Size as reported via POP */ - unsigned int flags; /* MSG_* flags defined above */ - unsigned long raw_offset; /* Raw, with the "From " line */ - unsigned long raw_size; - unsigned long data_offset; /* Just the message itself */ - unsigned long data_size; - unsigned char hash[16]; /* MD5 hash, to be used for UIDL */ -}; - -struct db_main { - struct db_message *head, *tail; /* Messages in a linked list */ - struct db_message **array; /* Direct access to messages */ - unsigned int total_count; /* All loaded messages and */ - unsigned int visible_count; /* just those not DELEted */ - unsigned long total_size; /* Their cumulative sizes, */ - unsigned long visible_size; /* to be reported via POP */ - unsigned int flags; /* DB_* flags defined above */ -#if POP_SUPPORT_LAST - unsigned int last; /* Last message touched */ -#endif -}; - -extern struct db_main db; - -extern void db_init(void); -extern int db_add(struct db_message *msg); -extern int db_delete(struct db_message *msg); -extern int db_fix(void); - -#endif diff --git a/usr.sbin/popa3d/mailbox.c b/usr.sbin/popa3d/mailbox.c deleted file mode 100644 index 70968f69de9..00000000000 --- a/usr.sbin/popa3d/mailbox.c +++ /dev/null @@ -1,503 +0,0 @@ -/* $OpenBSD: mailbox.c,v 1.7 2009/12/20 15:57:26 tobias Exp $ */ - -/* - * Mailbox access. - */ - -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <time.h> -#include <errno.h> - -#include <md5.h> - -#include "misc.h" -#include "params.h" -#include "protocol.h" -#include "database.h" - -static int mailbox_fd; /* fd for the mailbox, or -1 */ -static time_t mailbox_mtime; /* mtime, as of the last check */ -static unsigned long mailbox_size; /* Its original size */ - -static struct db_message *cmp; - -/* - * If a message has changed since the database was filled in, then we - * consider the database stale. This is called for every message when - * the mailbox is being re-parsed (because of its mtime change). - */ -static int db_compare(struct db_message *msg) -{ - if (!cmp) return 1; - - if (msg->raw_size != cmp->raw_size || msg->size != cmp->size || - memcmp(msg->hash, cmp->hash, sizeof(msg->hash))) { - db.flags |= DB_STALE; - return 1; - } - - cmp = cmp->next; - - return 0; -} - -/* - * Checks if the buffer pointed to by s1, of n1 chars, starts with the - * string s2, of n2 chars. - */ -#ifdef __GNUC__ -__inline__ -#endif -static int eq(char *s1, int n1, char *s2, int n2) -{ - if (n1 < n2) return 0; - if (!memcmp(s1, s2, n2)) return 1; - return !strncasecmp(s1, s2, n2); -} - -/* - * The mailbox parsing routine: first called to fill the database in, - * then to check if the database is still up to date. We implement a - * state machine at the line fragment level (that is, full or partial - * lines). This is faster than dealing with individual characters (we - * leave that job for libc), and doesn't require ever loading entire - * lines into memory. - */ -static int mailbox_parse(int init) -{ - struct stat stat; /* File information */ - struct db_message msg; /* Message being parsed */ - MD5_CTX hash; /* Its hash being computed */ - int (*db_op)(struct db_message *msg); /* db_add or db_compare */ - char *file_buffer, *line_buffer; /* Our internal buffers */ - unsigned long file_offset, line_offset; /* Their offsets in the file */ - unsigned long offset; /* A line fragment's offset */ - char *current, *next, *line; /* Line pointers */ - int block, saved, extra, length; /* Internal block sizes */ - int done, start, end; /* Various boolean flags: */ - int blank, header, body; /* the state information */ - int fixed, received; /* ...and more of it */ - - if (fstat(mailbox_fd, &stat)) return 1; - - if (init) { -/* Prepare for the database initialization */ - if (!S_ISREG(stat.st_mode)) return 1; - mailbox_mtime = stat.st_mtime; - if (stat.st_size > MAX_MAILBOX_OPEN_BYTES || - stat.st_size > ~0UL) return 1; - mailbox_size = stat.st_size; - if (!mailbox_size) return 0; - db_op = db_add; - } else { -/* Prepare for checking against the database */ - if (mailbox_mtime == stat.st_mtime) return 0; - if (!mailbox_size) return 0; - if (stat.st_size < mailbox_size) { - db.flags |= DB_STALE; - return 1; - } - if (stat.st_size > MAX_MAILBOX_WORK_BYTES || - stat.st_size > ~0UL) return 1; - if (lseek(mailbox_fd, 0, SEEK_SET) < 0) return 1; - db_op = db_compare; cmp = db.head; - } - - memset(&msg, 0, sizeof(msg)); - MD5Init(&hash); - - file_buffer = malloc(FILE_BUFFER_SIZE + LINE_BUFFER_SIZE); - if (!file_buffer) return 1; - line_buffer = &file_buffer[FILE_BUFFER_SIZE]; - - file_offset = 0; line_offset = 0; offset = 0; /* Start at 0, with */ - current = file_buffer; block = 0; saved = 0; /* empty buffers */ - - done = 0; /* Haven't reached EOF or the original size yet */ - end = 1; /* Assume we've just seen a LF: parse a new line */ - blank = 1; /* Assume we've seen a blank line: look for "From " */ - header = 0; /* Not in message headers, */ - body = 0; /* and not in message body */ - fixed = 0; /* Not in a "fixed" part of a message, */ - received = 0; /* and haven't got a Received: header yet */ - -/* - * The main loop. Its first part extracts the line fragments, while the - * second one manages the state flags and performs whatever is required - * based on the state. Unfortunately, splitting this into two functions - * didn't seem to simplify the code. - */ - do { -/* - * Part 1. - * The line fragment extraction. - */ - -/* Look for the next LF in the file buffer */ - if ((next = memchr(current, '\n', block))) { -/* Found it: get the length of this piece, and check for buffered data */ - length = ++next - current; - if (saved) { -/* Have this line's beginning in the line buffer: combine them */ - extra = LINE_BUFFER_SIZE - saved; - if (extra > length) extra = length; - memcpy(&line_buffer[saved], current, extra); - current += extra; block -= extra; - length = saved + extra; - line = line_buffer; - offset = line_offset; - start = end; end = current == next; - saved = 0; - } else { -/* Nothing in the line buffer: just process what we've got now */ - line = current; - offset = file_offset - block; - start = end; end = 1; - current = next; block -= length; - } - } else { -/* No more LFs in the file buffer */ - if (saved || block <= LINE_BUFFER_SIZE) { -/* Have this line's beginning in the line buffer: combine them */ -/* Not enough data to process right now: buffer it */ - extra = LINE_BUFFER_SIZE - saved; - if (extra > block) extra = block; - if (!saved) line_offset = file_offset - block; - memcpy(&line_buffer[saved], current, extra); - current += extra; block -= extra; - saved += extra; - length = saved; - line = line_buffer; - offset = line_offset; - } else { -/* Nothing in the line buffer and we've got enough data: just process it */ - length = block - 1; - line = current; - offset = file_offset - block; - current += length; - block = 1; - } - if (!block) { -/* We've emptied the file buffer: fetch some more data */ - current = file_buffer; - block = FILE_BUFFER_SIZE; - if (!init && - block > mailbox_size - file_offset) - block = mailbox_size - file_offset; - block = read(mailbox_fd, file_buffer, block); - if (block < 0) break; - file_offset += block; - if (block > 0 && saved < LINE_BUFFER_SIZE) - continue; - if (!saved) { -/* Nothing in the line buffer, and read(2) returned 0: we're done */ - offset = file_offset; - done = 1; - break; - } - } - start = end; end = !block; - saved = 0; - } - -/* - * Part 2. - * The following variables are set when we get here: - * -- line the line fragment, not NUL terminated; - * -- length its length; - * -- offset its offset in the file; - * -- start whether it's at the start of the line; - * -- end whether it's at the end of the line - * (all four combinations of "start" and "end" are possible). - */ - -/* Check for a new message if we've just seen a blank line */ - if (blank && start) - if (line[0] == 'F' && length >= 5 && - line[1] == 'r' && line[2] == 'o' && line[3] == 'm' && - line[4] == ' ') { -/* Process the previous one first, if exists */ - if (offset) { -/* If we aren't at the very beginning, there must have been a message */ - if (!msg.data_offset) break; - msg.raw_size = offset - msg.raw_offset; - msg.data_size = offset - body - msg.data_offset; - msg.size -= body << 1; - MD5Final(msg.hash, &hash); - if (db_op(&msg)) break; - } -/* Now prepare for parsing the new one */ - msg.raw_offset = offset; - msg.data_offset = 0; - MD5Init(&hash); - header = 1; body = 0; - fixed = received = 0; - continue; - } - -/* Memorize file offset of the message data (the line next to "From ") */ - if (header && start && !msg.data_offset) { - msg.data_offset = offset; - msg.data_size = 0; - msg.size = 0; - } - -/* Count this fragment, with LFs as CRLF, into the message size */ - if (msg.data_offset) - msg.size += length + end; - -/* If we see LF at start of line, then this is a blank line :-) */ - blank = start && line[0] == '\n'; - - if (!header) { -/* If we're no longer in message headers and we see more data, then it's - * the body. */ - if (msg.data_offset) - body = 1; -/* The rest of actions in this loop are for header lines only */ - continue; - } - -/* Blank line ends message headers */ - if (blank) { - header = 0; - continue; - } - -/* Some header lines are known to remain fixed over MUA runs */ - if (start) - switch (line[0]) { - case '\t': - case ' ': -/* Inherit "fixed" from the previous line */ - break; - - case 'R': - case 'r': -/* One Received: header from the local MTA should be sufficient */ - fixed = !received && - (received = eq(line, length, "Received:", 9)); - break; - - case 'D': - case 'd': - fixed = eq(line, length, "Delivered-To:", 13) || - (!received && eq(line, length, "Date:", 5)); - break; - - case 'M': - case 'm': - fixed = !received && - eq(line, length, "Message-ID:", 11); - break; - - case 'X': -/* Let the local delivery agent help generate unique IDs but don't blindly - * trust this header alone as it could just as easily come from the remote. */ - fixed = eq(line, length, "X-Delivery-ID:", 14); - break; - - default: - fixed = 0; - continue; - } - -/* We can hash all fragments of those lines, for UIDL */ - if (fixed) - MD5Update(&hash, (u_char *)line, length); - } while (1); - - free(file_buffer); - - if (done) { -/* Process the last message */ - if (offset != mailbox_size) return 1; - if (!msg.data_offset) return 1; - msg.raw_size = offset - msg.raw_offset; - msg.data_size = offset - (blank & body) - msg.data_offset; - msg.size -= (blank & body) << 1; - MD5Final(msg.hash, &hash); - if (db_op(&msg)) return 1; - -/* Everything went well, update our timestamp if we were checking */ - if (!init) mailbox_mtime = stat.st_mtime; - } - - return !done; -} - -int mailbox_open(char *spool, char *mailbox) -{ - char *pathname; - int result; - - mailbox_fd = -1; - - if (asprintf(&pathname, "%s/%s", spool, mailbox) == -1) - return 1; - - mailbox_fd = open(pathname, - O_RDWR | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK); - - free(pathname); - - if (mailbox_fd < 0) - return errno != ENOENT; - - if (lock_fd(mailbox_fd, 1)) return 1; - - result = mailbox_parse(1); - - if (!result && time(NULL) == mailbox_mtime) - if (sleep_select(1, 0)) result = 1; - - if (unlock_fd(mailbox_fd)) return 1; - - return result; -} - -static int mailbox_changed(void) -{ - struct stat stat; - int result; - - if (fstat(mailbox_fd, &stat)) return 1; - if (mailbox_mtime == stat.st_mtime) return 0; - - if (lock_fd(mailbox_fd, 1)) return 1; - - result = mailbox_parse(0); - - if (!result && time(NULL) == mailbox_mtime) - if (sleep_select(1, 0)) result = 1; - - if (unlock_fd(mailbox_fd)) return 1; - - return result; -} - -int mailbox_get(struct db_message *msg, int lines) -{ - int event; - - if (mailbox_changed()) return POP_CRASH_SERVER; - -/* The calls to mailbox_changed() will set DB_STALE if that is the case */ - if (lseek(mailbox_fd, msg->data_offset, SEEK_SET) < 0) { - mailbox_changed(); - return POP_CRASH_SERVER; - } - if ((event = pop_reply_multiline(mailbox_fd, msg->data_size, lines))) { - if (event == POP_CRASH_SERVER) mailbox_changed(); - return event; - } - - if (mailbox_changed()) return POP_CRASH_SERVER; - - if (pop_reply_terminate()) return POP_CRASH_NETFAIL; - - return POP_OK; -} - -static int mailbox_write(char *buffer) -{ - struct db_message *msg; - unsigned long old, new; - unsigned long size; - int block; - - msg = db.head; - old = new = 0; - do { - if (msg->flags & MSG_DELETED) continue; - old = msg->raw_offset; - - if (old == new) { - old = (new += msg->raw_size); - continue; - } - - while ((size = msg->raw_size - (old - msg->raw_offset))) { - if (lseek(mailbox_fd, old, SEEK_SET) < 0) return 1; - if (size > FILE_BUFFER_SIZE) - size = FILE_BUFFER_SIZE; - block = read(mailbox_fd, buffer, size); - if (!block && old == mailbox_size) break; - if (block <= 0) return 1; - - if (lseek(mailbox_fd, new, SEEK_SET) < 0) return 1; - if (write_loop(mailbox_fd, buffer, block) != block) - return 1; - - old += block; new += block; - } - } while ((msg = msg->next)); - - old = mailbox_size; - while (1) { - if (lseek(mailbox_fd, old, SEEK_SET) < 0) return 1; - block = read(mailbox_fd, buffer, FILE_BUFFER_SIZE); - if (!block) break; - if (block < 0) return 1; - - if (lseek(mailbox_fd, new, SEEK_SET) < 0) return 1; - if (write_loop(mailbox_fd, buffer, block) != block) return 1; - -/* Cannot overflow unless locking is bypassed */ - if ((old += block) < block || (new += block) < block) return 1; - } - - if (ftruncate(mailbox_fd, new)) return 1; - - return fsync(mailbox_fd); -} - -static int mailbox_write_blocked(void) -{ - sigset_t blocked_set, old_set; - char *buffer; - int result; - - if (sigfillset(&blocked_set)) return 1; - if (sigprocmask(SIG_BLOCK, &blocked_set, &old_set)) return 1; - - if ((buffer = malloc(FILE_BUFFER_SIZE))) { - result = mailbox_write(buffer); - free(buffer); - } else - result = 1; - - if (sigprocmask(SIG_SETMASK, &old_set, NULL)) return 1; - - return result; -} - -int mailbox_update(void) -{ - int result; - - if (mailbox_fd < 0 || !(db.flags & DB_DIRTY)) return 0; - - if (lock_fd(mailbox_fd, 0)) return 1; - - if (!(result = mailbox_parse(0))) - result = mailbox_write_blocked(); - - if (unlock_fd(mailbox_fd)) return 1; - - return result; -} - -int mailbox_close(void) -{ - if (mailbox_fd < 0) return 0; - - return close(mailbox_fd); -} diff --git a/usr.sbin/popa3d/mailbox.h b/usr.sbin/popa3d/mailbox.h deleted file mode 100644 index 102774ec97f..00000000000 --- a/usr.sbin/popa3d/mailbox.h +++ /dev/null @@ -1,32 +0,0 @@ -/* $OpenBSD: mailbox.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ - -/* - * Mailbox access. - */ - -#ifndef _POP_MAILBOX_H -#define _POP_MAILBOX_H - -/* - * Opens the mailbox, filling in the message database. Returns a non-zero - * value on error. - */ -extern int mailbox_open(char *spool, char *mailbox); - -/* - * 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); - -/* - * Rewrites the mailbox according to flags in the database. - */ -extern int mailbox_update(void); - -/* - * Closes the mailbox file. - */ -extern int mailbox_close(void); - -#endif diff --git a/usr.sbin/popa3d/misc.c b/usr.sbin/popa3d/misc.c deleted file mode 100644 index 7b43a5d8134..00000000000 --- a/usr.sbin/popa3d/misc.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $OpenBSD: misc.c,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ - -/* - * Miscellaneous syscall wrappers. See misc.h for the descriptions. - */ - -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <errno.h> -#include <sys/time.h> -#include <sys/file.h> - -#include "params.h" - -int sleep_select(int sec, int usec) -{ - struct timeval timeout; - - timeout.tv_sec = sec; - timeout.tv_usec = usec; - - return select(0, NULL, NULL, NULL, &timeout); -} - -int lock_fd(int fd, int shared) -{ -#if LOCK_FCNTL - struct flock l; - - memset(&l, 0, sizeof(l)); - l.l_whence = SEEK_SET; - l.l_type = shared ? F_RDLCK : F_WRLCK; - while (fcntl(fd, F_SETLKW, &l)) { - if (errno != EBUSY) return -1; - sleep_select(1, 0); - } -#endif - -#if LOCK_FLOCK - while (flock(fd, shared ? LOCK_SH : LOCK_EX)) { - if (errno != EBUSY) return -1; - sleep_select(1, 0); - } -#endif - - return 0; -} - -int unlock_fd(int fd) -{ -#if LOCK_FCNTL - struct flock l; - - memset(&l, 0, sizeof(l)); - l.l_whence = SEEK_SET; - l.l_type = F_UNLCK; - if (fcntl(fd, F_SETLK, &l)) return -1; -#endif - -#if LOCK_FLOCK - if (flock(fd, LOCK_UN)) return -1; -#endif - - return 0; -} - -int write_loop(int fd, char *buffer, int count) -{ - int offset, block; - - offset = 0; - while (count > 0) { - block = write(fd, &buffer[offset], count); - -/* If any write(2) fails, we consider that the entire write_loop() has - * failed to do its job. We don't even ignore EINTR here. We also don't - * retry when a write(2) returns zero, as we could start eating up the - * CPU if we did. */ - if (block < 0) return block; - if (!block) return offset; - - offset += block; - count -= block; - } - -/* Should be equal to the requested size, unless our kernel got crazy. */ - return offset; -} diff --git a/usr.sbin/popa3d/misc.h b/usr.sbin/popa3d/misc.h deleted file mode 100644 index 2dba9f555fa..00000000000 --- a/usr.sbin/popa3d/misc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $OpenBSD: misc.h,v 1.2 2001/09/19 10:58:08 mpech Exp $ */ - -/* - * Miscellaneous syscall wrappers. - */ - -#ifndef _POP_MISC_H -#define _POP_MISC_H - -/* - * A select(2)-based sleep() equivalent: no more problems with SIGALRM, - * subsecond precision. - */ -extern int sleep_select(int sec, int usec); - -/* - * Obtain or remove a lock. - */ -extern int lock_fd(int fd, int shared); -extern int unlock_fd(int fd); - -/* - * Attempts to write all the supplied data. Returns the number of bytes - * written. Any value that differs from the requested count means that - * an error has occurred; if the value is -1, errno is set appropriately. - */ -extern int write_loop(int fd, char *buffer, int count); - -#endif diff --git a/usr.sbin/popa3d/params.h b/usr.sbin/popa3d/params.h deleted file mode 100644 index f27e171eaa8..00000000000 --- a/usr.sbin/popa3d/params.h +++ /dev/null @@ -1,250 +0,0 @@ -/* $OpenBSD: params.h,v 1.10 2012/07/17 11:34:47 otto Exp $ */ - -/* - * Global POP daemon parameters. - */ - -#ifndef _POP_PARAMS_H -#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 - -#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. - */ -#define MAX_SESSIONS 100 -#define MAX_SESSIONS_PER_SOURCE 10 -#define MAX_BACKLOG 5 -#define MIN_DELAY 10 - -#endif - -/* - * Do we want to support virtual domains? - */ -#define POP_VIRTUAL 0 - -#if POP_VIRTUAL - -/* - * VIRTUAL_HOME_PATH is where the virtual domain root directories live. - */ -#define VIRTUAL_HOME_PATH "/vhome" - -/* - * Subdirectories within each virtual domain root for the authentication - * information and mailboxes, respectively. These defaults correspond to - * full pathnames of the form "/vhome/IP/{auth,mail}/username". - */ -#define VIRTUAL_AUTH_PATH "auth" -#define VIRTUAL_SPOOL_PATH "mail" - -/* - * Do we want to support virtual domains only? Normally, if the connected - * IP address doesn't correspond to a directory in VIRTUAL_HOME_PATH, the - * authentication will be done globally. - */ -#define VIRTUAL_ONLY 0 - -#else - -/* - * We don't support virtual domains (!POP_VIRTUAL), so we're definitely - * not virtual-only. Don't edit this. - */ -#define VIRTUAL_ONLY 0 - -#endif - -/* - * 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_CHROOT "/var/empty" - -/* - * Sessions will be closed if idle for longer than POP_TIMEOUT seconds. - * RFC 1939 says that "such a timer MUST be of at least 10 minutes' - * duration", so I've made 10 minutes the default. In practice, you - * may want to reduce this to, say, 2 minutes. - */ -#define POP_TIMEOUT (10 * 60) - -/* - * Do we want to support the obsolete LAST command, as defined in RFC - * 1460? It has been removed from the protocol in 1994 by RFC 1725, - * and isn't even mentioned in RFC 1939. Still, some software doesn't - * work without it. - */ -#define POP_SUPPORT_LAST 1 - -/* - * Introduce some sane limits on the mailbox size in order to prevent - * a single huge mailbox from stopping the entire POP service. - */ -#define MAX_MAILBOX_MESSAGES 200000 -#define MAX_MAILBOX_OPEN_BYTES 2000000000LL -#define MAX_MAILBOX_WORK_BYTES 2500000000LL - -#if !VIRTUAL_ONLY - -/* - * Choose the password authentication method your system uses: - * - * AUTH_PASSWD Use getpwnam(3) only, for *BSD or readable passwd; - * - * Note that there's no built-in password aging support. - */ -#define AUTH_PASSWD 1 - -#endif - -#if POP_VIRTUAL || AUTH_PASSWD - -/* - * A salt used to waste some CPU time on dummy crypt(3) calls and make - * it harder (but still far from impossible, on most systems) to check - * for valid usernames. Adjust it for your crypt(3). - */ -/* echo -n "dummyblowfishsalt" | encrypt -b 6 */ -#define AUTH_DUMMY_SALT "$2a$06$bycSsJMBAEDy1E6zzaL5u.vd4GlIrmCWyDgB33OD36h6mrRympUwS" - -#endif - -/* - * Message to return to the client when authentication fails. You can - * #undef this for no message. - */ -#define AUTH_FAILED_MESSAGE "Authentication failed (bad password?)" - -#if !VIRTUAL_ONLY - -/* - * 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 - -/* - * Locking method your system uses for user mailboxes. It is important - * that you set this correctly. - * - * *BSDs use flock(2), others typically use fcntl(2). - */ -#define LOCK_FCNTL 0 -#define LOCK_FLOCK 1 - -/* - * How do we talk to syslogd? These should be fine for most systems. - */ -#define SYSLOG_IDENT POP_SERVER -#define SYSLOG_OPTIONS LOG_PID -#define SYSLOG_FACILITY LOG_DAEMON -#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. - */ - -/* - * According to RFC 1939: "Keywords and arguments are each separated by - * a single SPACE character. Keywords are three or four characters long. - * Each argument may be up to 40 characters long." We're only processing - * up to two arguments, so it is safe to truncate after this length. - */ -#define POP_BUFFER_SIZE 0x80 - -/* - * There's no reason to change this one either. Making this larger would - * waste memory, and smaller values could make the authentication fail. - */ -#define AUTH_BUFFER_SIZE (2 * POP_BUFFER_SIZE) - -#if POP_VIRTUAL - -/* - * Buffer size for reading entire per-user authentication files. - */ -#define VIRTUAL_AUTH_SIZE 0x100 - -#endif - -/* - * File buffer sizes to use while parsing the mailbox and retrieving a - * message, respectively. Can be changed. - */ -#define FILE_BUFFER_SIZE 0x10000 -#define RETR_BUFFER_SIZE 0x8000 - -/* - * The mailbox parsing code isn't allowed to truncate lines earlier than - * this length. Keep this at least as large as the longest header field - * name we need to check for, but not too large for performance reasons. - */ -#define LINE_BUFFER_SIZE 0x20 - -#endif diff --git a/usr.sbin/popa3d/pop_auth.c b/usr.sbin/popa3d/pop_auth.c deleted file mode 100644 index 31d66f764b4..00000000000 --- a/usr.sbin/popa3d/pop_auth.c +++ /dev/null @@ -1,98 +0,0 @@ -/* $OpenBSD: pop_auth.c,v 1.4 2009/12/20 15:55:42 tobias Exp $ */ - -/* - * AUTHORIZATION state handling. - */ - -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <syslog.h> - -#include "misc.h" -#include "params.h" -#include "protocol.h" -#include "pop_auth.h" -#if POP_VIRTUAL -#include "virtual.h" -#endif - -static char *pop_user, *pop_pass; - -static int pop_auth_quit(char *params) -{ - if (params) return POP_ERROR; - return POP_LEAVE; -} - -static int pop_auth_user(char *params) -{ - char *user; - - user = pop_get_param(¶ms); - if (!user || pop_user || params) return POP_ERROR; - if (!(pop_user = strdup(user))) return POP_CRASH_SERVER; - return POP_OK; -} - -static int pop_auth_pass(char *params) -{ - if (!params) return POP_ERROR; - if (!pop_user) { - memset(params, 0, strlen(params)); - return POP_ERROR; - } - pop_pass = strdup(params); - memset(params, 0, strlen(params)); - if (pop_pass == NULL) return POP_CRASH_SERVER; - return POP_STATE; -} - -static struct pop_command pop_auth_commands[] = { - {"QUIT", pop_auth_quit}, - {"USER", pop_auth_user}, - {"PASS", pop_auth_pass}, - {NULL, NULL} -}; - -int do_pop_auth(int channel) -{ - pop_init(); - - if (pop_reply_ok()) return 1; - - pop_user = NULL; - if (pop_handle_state(pop_auth_commands) == POP_STATE) { - pop_clean(); - write_loop(channel, (char *)&pop_buffer, sizeof(pop_buffer)); - write_loop(channel, pop_user, strlen(pop_user) + 1); - write_loop(channel, pop_pass, strlen(pop_pass) + 1); - memset(pop_pass, 0, strlen(pop_pass)); - if (close(channel)) return 1; - } - - return 0; -} - -void log_pop_auth(int result, char *user) -{ - if (result == AUTH_NONE) { - syslog(SYSLOG_PRI_LO, "Didn't attempt authentication"); - return; - } - -#if POP_VIRTUAL - if (virtual_domain) { - syslog(result == AUTH_OK ? SYSLOG_PRI_LO : SYSLOG_PRI_HI, - "Authentication %s for %s@%s", - result == AUTH_OK ? "passed" : "failed", - user ? user : "UNKNOWN USER", - virtual_domain); - return; - } -#endif - syslog(result == AUTH_OK ? SYSLOG_PRI_LO : SYSLOG_PRI_HI, - "Authentication %s for %s", - result == AUTH_OK ? "passed" : "failed", - user ? user : "UNKNOWN USER"); -} diff --git a/usr.sbin/popa3d/pop_auth.h b/usr.sbin/popa3d/pop_auth.h deleted file mode 100644 index 2708dcd6058..00000000000 --- a/usr.sbin/popa3d/pop_auth.h +++ /dev/null @@ -1,28 +0,0 @@ -/* $OpenBSD: pop_auth.h,v 1.2 2001/09/21 20:22:06 camield Exp $ */ - -/* - * AUTHORIZATION state handling. - */ - -#ifndef _POP_AUTH_H -#define _POP_AUTH_H - -/* - * Possible authentication results. - */ -#define AUTH_OK 0 -#define AUTH_NONE 1 -#define AUTH_FAILED 2 - -/* - * Handles the AUTHORIZATION state commands, and writes authentication - * data into the channel. - */ -extern int do_pop_auth(int channel); - -/* - * Logs an authentication attempt for user, use NULL for non-existent. - */ -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 deleted file mode 100644 index 972d8a63557..00000000000 --- a/usr.sbin/popa3d/pop_root.c +++ /dev/null @@ -1,275 +0,0 @@ -/* $OpenBSD: pop_root.c,v 1.5 2005/05/03 05:44:35 djm Exp $ */ - -/* - * Main daemon code: invokes the actual POP handling routines. Most calls - * to functions in other source files are done as a non-root user (either - * 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) - */ - -#include <unistd.h> -#include <signal.h> -#include <string.h> -#include <stdlib.h> -#include <syslog.h> -#include <errno.h> -#include <time.h> -#include <grp.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <sys/types.h> - -#include "params.h" -#include "protocol.h" -#include "pop_auth.h" -#include "pop_trans.h" -#if POP_VIRTUAL -#include "virtual.h" -#endif - -#if !VIRTUAL_ONLY -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 int known; -static char *user; -static char *spool, *mailbox; - -int log_error(char *s) -{ - syslog(SYSLOG_PRI_ERROR, "%s: %m", s); - return 1; -} - -static int set_user(struct passwd *pw) -{ - gid_t groups[2]; - - if (!pw->pw_uid) return 1; - - groups[0] = groups[1] = pw->pw_gid; - if (setgroups(1, groups)) - return log_error("setgroups"); - if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid)) - return log_error("setresgid"); - if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) - return log_error("setresuid"); - - 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. - */ -static int read_loop(int fd, char *buffer, int count) -{ - int offset, block; - - offset = 0; - while (count > 0) { - block = read(fd, &buffer[offset], count); - - if (block < 0) return block; - if (!block) return offset; - - offset += block; - count -= block; - } - - return offset; -} - -/* - * The root-privileged part of the AUTHORIZATION state handling: reads - * the authentication data obtained over POP from its end of the pipe, - * attempts authentication, and, if successful, drops privilege to the - * authenticated user. Returns one of the AUTH_* result codes. - */ -static int do_root_auth(int channel) -{ - static char auth[AUTH_BUFFER_SIZE + 2]; - char *pass; - struct passwd *pw; - - known = 0; -#if POP_VIRTUAL - virtual_domain = NULL; -#endif - -/* The POP client could have sent extra commands without waiting for - * successful authentication. We're passing them into the TRANSACTION - * state if we ever get there. */ - if (read_loop(channel, (char *)&pop_buffer, sizeof(pop_buffer)) != - sizeof(pop_buffer)) return AUTH_NONE; - -/* Now, the authentication data. */ - 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, &known)) && virtual_domain) { - memset(pass, 0, strlen(pass)); - return AUTH_FAILED; - } -#endif -#if VIRTUAL_ONLY - if (!pw) { - memset(pass, 0, strlen(pass)); - return AUTH_FAILED; - } -#else - if (!pw && !(pw = auth_userpass(user, pass, &known))) { - memset(pass, 0, strlen(pass)); - return AUTH_FAILED; - } -#endif - if (!*pass) return AUTH_FAILED; - memset(pass, 0, strlen(pass)); - if (!*user) return AUTH_FAILED; - -#if VIRTUAL_ONLY - if (!virtual_domain) return AUTH_FAILED; -#endif - - if (set_user(pw)) return AUTH_FAILED; - -#if POP_VIRTUAL - if (virtual_domain) { - spool = virtual_spool; - mailbox = user; - - return AUTH_OK; - } -#endif - -#if VIRTUAL_ONLY - /* never reached */ - return AUTH_FAILED; -#else -#ifdef MAIL_SPOOL_PATH - spool = MAIL_SPOOL_PATH; - mailbox = user; -#else - spool = pw->pw_dir; - mailbox = HOME_MAILBOX_NAME; -#endif - - return AUTH_OK; -#endif -} - -int do_pop_startup(void) -{ - struct passwd *pw; - - umask(077); - signal(SIGPIPE, SIG_IGN); - - openlog(SYSLOG_IDENT, SYSLOG_OPTIONS, SYSLOG_FACILITY); - - errno = 0; - if (!(pw = getpwnam(POP_USER))) { - syslog(SYSLOG_PRI_ERROR, "getpwnam(\"" POP_USER "\"): %s", - errno ? strerror(errno) : "No such user"); - return 1; - } - 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; -#endif - - return 0; -} - -int do_pop_session(void) -{ - int channel[2]; - int result, status; - -/* 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"); - - switch (fork()) { - case -1: - return log_error("fork"); - - case 0: - if (close(channel[0])) return log_error("close"); - if (drop_root()) return 1; - return do_pop_auth(channel[1]); - } - - if (close(channel[1])) - result = AUTH_NONE; - else - result = do_root_auth(channel[0]); - - if (wait(&status) < 0) - status = 1; - else - if (WIFEXITED(status)) - status = WEXITSTATUS(status); - else - status = 1; - - if (result == AUTH_OK) { - if (close(channel[0])) return log_error("close"); - log_pop_auth(result, user); - return do_pop_trans(spool, 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); -#else - if (result == AUTH_FAILED) pop_reply_error(); -#endif - - return status; -} - -#if !POP_STANDALONE && !POP_OPTIONS -int main(void) -{ - if (do_pop_startup()) return 1; - return do_pop_session(); -} -#endif diff --git a/usr.sbin/popa3d/pop_trans.c b/usr.sbin/popa3d/pop_trans.c deleted file mode 100644 index 2c2f97cb3bb..00000000000 --- a/usr.sbin/popa3d/pop_trans.c +++ /dev/null @@ -1,266 +0,0 @@ -/* $OpenBSD: pop_trans.c,v 1.6 2009/12/17 11:04:39 sobrado Exp $ */ - -/* - * TRANSACTION state handling. - */ - -#include <stdio.h> -#include <syslog.h> - -#include "params.h" -#include "protocol.h" -#include "database.h" -#include "mailbox.h" - -static int pop_trans_quit(char *params) -{ - if (params) return POP_ERROR; - return POP_STATE; -} - -static int pop_trans_noop(char *params) -{ - if (params) return POP_ERROR; - return POP_OK; -} - -static int pop_trans_stat(char *params) -{ - if (params) return POP_ERROR; - if (pop_reply("+OK %u %lu", db.visible_count, db.visible_size)) - return POP_CRASH_NETFAIL; - return POP_QUIET; -} - -static int pop_trans_list_or_uidl_all(int uidl) -{ - unsigned int number; - struct db_message *msg; - - 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; - if (uidl) { - if (pop_reply("%u " - "%02x%02x%02x%02x%02x%02x%02x%02x", - number, - msg->hash[3], msg->hash[2], - msg->hash[1], msg->hash[0], - msg->hash[7], msg->hash[6], - msg->hash[5], msg->hash[4])) - return POP_CRASH_NETFAIL; - } else - if (pop_reply("%u %lu", number, msg->size)) - return POP_CRASH_NETFAIL; - } - if (pop_reply_terminate()) return POP_CRASH_NETFAIL; - return POP_QUIET; -} - -static int pop_trans_list_or_uidl(char *params, int uidl) -{ - int number; - struct db_message *msg; - - if (!params) - return pop_trans_list_or_uidl_all(uidl); - - 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 (uidl) { - if (pop_reply("+OK %d " - "%02x%02x%02x%02x%02x%02x%02x%02x", - number, - msg->hash[3], msg->hash[2], - msg->hash[1], msg->hash[0], - msg->hash[7], msg->hash[6], - msg->hash[5], msg->hash[4])) - return POP_CRASH_NETFAIL; - } else - if (pop_reply("+OK %d %lu", number, msg->size)) - return POP_CRASH_NETFAIL; - return POP_QUIET; -} - -static int pop_trans_list(char *params) -{ - return pop_trans_list_or_uidl(params, 0); -} - -static int pop_trans_uidl(char *params) -{ - return pop_trans_list_or_uidl(params, 1); -} - -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 ((event = mailbox_get(msg, -1)) != POP_OK) return event; -#if POP_SUPPORT_LAST - if (number > db.last) db.last = number; -#endif - return POP_QUIET; -} - -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; - lines = pop_get_int(¶ms); - if (lines < 0 || params) return POP_ERROR; - msg = db.array[number - 1]; - if (msg->flags & MSG_DELETED) return POP_ERROR; - if ((event = mailbox_get(msg, lines)) != POP_OK) return event; - return POP_QUIET; -} - -static int pop_trans_dele(char *params) -{ - int number; - struct db_message *msg; - - number = pop_get_int(¶ms); - if (number < 1 || number > db.total_count || params) return POP_ERROR; - msg = db.array[number - 1]; - if (db_delete(msg)) return POP_ERROR; -#if POP_SUPPORT_LAST - if (number > db.last) db.last = number; -#endif - return POP_OK; -} - -static int pop_trans_rset(char *params) -{ - struct db_message *msg; - - if (params) return POP_ERROR; - - if ((msg = db.head)) - do { - msg->flags &= ~MSG_DELETED; - } while ((msg = msg->next)); - - db.visible_count = db.total_count; - db.visible_size = db.total_size; - db.flags &= ~DB_DIRTY; -#if POP_SUPPORT_LAST - db.last = 0; -#endif - - return POP_OK; -} - -#if POP_SUPPORT_LAST -static int pop_trans_last(char *params) -{ - if (params) return POP_ERROR; - if (pop_reply("+OK %u", db.last)) return POP_CRASH_NETFAIL; - return POP_QUIET; -} -#endif - -static struct pop_command pop_trans_commands[] = { - {"QUIT", pop_trans_quit}, - {"NOOP", pop_trans_noop}, - {"STAT", pop_trans_stat}, - {"LIST", pop_trans_list}, - {"UIDL", pop_trans_uidl}, - {"RETR", pop_trans_retr}, - {"TOP", pop_trans_top}, - {"DELE", pop_trans_dele}, - {"RSET", pop_trans_rset}, -#if POP_SUPPORT_LAST - {"LAST", pop_trans_last}, -#endif - {NULL, NULL} -}; - -static int db_load(char *spool, char *mailbox) -{ - db_init(); - - if (mailbox_open(spool, mailbox)) return 1; - - if (db_fix()) { - mailbox_close(); - return 1; - } - - return 0; -} - -int do_pop_trans(char *spool, char *mailbox) -{ - int event; - - if (!pop_sane()) return 1; - - if (db_load(spool, mailbox)) { - syslog(SYSLOG_PRI_HI, - "Failure reading %s/%s or mailbox limits exceeded", - spool, mailbox); - pop_reply_error(); - return 0; - } - - syslog(SYSLOG_PRI_LO, "%u message%s (%lu byte%s) loaded", - db.total_count, db.total_count == 1 ? "" : "s", - db.total_size, db.total_size == 1 ? "" : "s"); - - if (pop_reply_ok()) - event = POP_CRASH_NETFAIL; - else - switch ((event = pop_handle_state(pop_trans_commands))) { - case POP_STATE: - if (mailbox_update()) { - if (db.flags & DB_STALE) break; - syslog(SYSLOG_PRI_ERROR, - "Failed to update %s/%s", - spool, mailbox); - pop_reply_error(); - break; - } - - syslog(SYSLOG_PRI_LO, "%u (%lu) deleted, %u (%lu) left", - db.total_count - db.visible_count, - db.total_size - db.visible_size, - db.visible_count, - db.visible_size); - pop_reply_ok(); - break; - - 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_PRI_LO, "Another MUA active, giving up"); - else - if (event == POP_CRASH_SERVER) - syslog(SYSLOG_PRI_ERROR, - "Server failure accessing %s/%s", - spool, mailbox); - - mailbox_close(); - - return 0; -} diff --git a/usr.sbin/popa3d/pop_trans.h b/usr.sbin/popa3d/pop_trans.h deleted file mode 100644 index 0e0edd91cf9..00000000000 --- a/usr.sbin/popa3d/pop_trans.h +++ /dev/null @@ -1,12 +0,0 @@ -/* $OpenBSD: pop_trans.h,v 1.1 2001/08/19 13:05:57 deraadt Exp $ */ - -/* - * TRANSACTION state handling. - */ - -#ifndef _POP_TRANS_H -#define _POP_TRANS_H - -extern int do_pop_trans(char *spool, char *mailbox); - -#endif diff --git a/usr.sbin/popa3d/popa3d.8 b/usr.sbin/popa3d/popa3d.8 deleted file mode 100644 index 9474c904cd1..00000000000 --- a/usr.sbin/popa3d/popa3d.8 +++ /dev/null @@ -1,187 +0,0 @@ -.\" $OpenBSD: popa3d.8,v 1.19 2013/08/14 06:32:36 jmc Exp $ -.\" -.\" Copyright (c) 2001-2003 Camiel Dobbelaar (cd@sentia.nl) -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.Dd $Mdocdate: August 14 2013 $ -.Dt POPA3D 8 -.Os -.Sh NAME -.Nm popa3d -.Nd Post Office Protocol (POP3) server -.Sh SYNOPSIS -.Nm -.Op Fl 46DV -.Sh DESCRIPTION -.Nm -is a POP3 server. -It offers network access to user mailboxes through the POP3 protocol. -The server uses the -.Tn TCP -protocol -and listens at the port specified in the -.Dq pop3 -service specification; see -.Xr services 5 . -.Pp -A POP3 server operates on local mailboxes on behalf of its remote -users. -Users can connect at any time to check their mailbox and fetch the -mail that has accumulated. -The advantage of this ``pull'' approach is that any user with a simple -POP3-capable mail reader program can receive mail, eschewing the need -for a full-fledged Mail Transfer Agent (MTA) and a permanent network -connection. -.Pp -Note that POP3 can only be used to retrieve mail, not to send it. -To send mail, the SMTP protocol is commonly used; see -.Xr sendmail 8 . -.Pp -The options are as follows: -.Bl -tag -width Ds -.It Fl 4 -In standalone mode -.Pq Fl D , -listen to IPv4 only. -.It Fl 6 -In standalone mode -.Pq Fl D , -listen to IPv6 only. -.It Fl D -With this option set, -.Nm -will detach and become a daemon, accepting connections on the pop3 -port and forking child processes to handle them. -This has lower overhead than starting -.Nm -from -.Xr inetd 8 -and is thus useful on busy servers to reduce load. -.Pp -In this mode -.Nm -also does quite a few checks to significantly reduce the impact of -connection flood attacks. -.It Fl V -Show version information and exit. -.El -.Pp -Alternatively, -.Nm -can be used through -.Xr inetd 8 . -This requires the following entry to be activated in -.Pa /etc/inetd.conf : -.Pp -.Dl pop3 stream tcp nowait root /usr/sbin/popa3d popa3d -.Pp -or, using -.Xr tcpd 8 -for TCP-wrappers access control: -.Pp -.Dl pop3 stream tcp nowait root /usr/libexec/tcpd /usr/sbin/popa3d -.Pp -For access to a mailbox through the POP3 service, the username must -be in the password database. -Additionally, -.Nm -does not permit null passwords and will refuse to serve mail for -root (uid 0) users. -.Sh COMMANDS -A normal POP3 session progresses through three states: authorization, -transaction and update. -.Pp -After the TCP connection opens, the client must authenticate itself -to the server in the authorization state. -The following commands are supported in the authorization state. -All commands are case-insensitive. -.Bl -column "PASS string" "Description""Description" -offset indent -.It Sy Command Ta Sy Description -.It USER name Ta "authenticate as user ``name''" -.It PASS string Ta "authenticate using password ``string''" -.It QUIT Ta "quit; do not enter update state" -.El -.Pp -When authorization is successful, the server enters the transaction -state. -The client can now list and retrieve messages or mark messages for -deletion. -The following commands are supported in the transaction state. -.Bl -column "LIST [msg]" "Description" -offset indent -.It Sy Command Ta Sy Description -.It DELE msg Ta "mark message for deletion" -.It LAST Ta "show highest message number accessed (obsolete)" -.It LIST [msg] Ta "list message number and size" -.It NOOP Ta "do nothing" -.It QUIT Ta "quit; enter update state" -.It RETR msg Ta "retrieve message" -.It RSET Ta "clear deletion marks" -.It STAT Ta "return total number of messages and total size" -.It TOP msg n Ta "show top n lines of message body" -.It UIDL [msg] Ta "list message number and digest" -.El -.Pp -When the client issues the QUIT command in the transaction state, -the server enters the update state. -All messages that were marked for deletion are now removed. -The server then closes the connection. -.Sh FILES -.Bl -tag -width "/var/mailXX" -.It Pa /var/mail -User mail spools -.It Pa /etc/hosts.allow, /etc/hosts.deny -TCP-wrappers access controls may be defined here as described in -.Xr hosts_access 5 . -Valid if -.Nm -is started in daemon-mode, or if -.Nm -is running through -.Xr inetd 8 -and is used in combination with -.Xr tcpd 8 . -.El -.Sh SEE ALSO -.Xr hosts_access 5 , -.Xr inetd 8 , -.Xr sendmail 8 , -.Xr tcpd 8 -.Pp -.Lk http://www.openwall.com/popa3d/ -.Sh STANDARDS -.Rs -.%A J. Myers -.%A M. Rose -.%D May 1996 -.%R RFC 1939 -.%T Post Office Protocol \(en Version 3 -.Re -.Sh HISTORY -.Nm -first appeared in -.Ox 3.0 . -.Sh AUTHORS -.An Solar Designer Aq Mt solar@openwall.com -.Sh CAVEATS -POP3 authenticates using cleartext passwords. diff --git a/usr.sbin/popa3d/protocol.c b/usr.sbin/popa3d/protocol.c deleted file mode 100644 index 0ae47dd4b82..00000000000 --- a/usr.sbin/popa3d/protocol.c +++ /dev/null @@ -1,287 +0,0 @@ -/* $OpenBSD: protocol.c,v 1.4 2005/04/13 02:33:09 deraadt Exp $ */ - -/* - * POP protocol handling. - */ - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <signal.h> -#include <setjmp.h> -#include <string.h> -#include <stdarg.h> -#include <errno.h> - -#include "misc.h" -#include "params.h" -#include "protocol.h" - -struct pop_buffer pop_buffer; -static sigjmp_buf pop_timed_out; - -void pop_init(void) -{ - pop_buffer.ptr = pop_buffer.size = 0; -} - -void pop_clean(void) -{ - memset(pop_buffer.data, 0, pop_buffer.ptr); - memmove(pop_buffer.data, &pop_buffer.data[pop_buffer.ptr], - pop_buffer.size -= pop_buffer.ptr); - pop_buffer.ptr = 0; -} - -int pop_sane(void) -{ - return pop_buffer.size <= sizeof(pop_buffer.data) && - pop_buffer.ptr <= pop_buffer.size; -} - -static void pop_timeout(int signum) -{ - signal(SIGALRM, SIG_DFL); - siglongjmp(pop_timed_out, 1); -} - -static void pop_fetch(void) -{ - int size; - - signal(SIGALRM, pop_timeout); - alarm(POP_TIMEOUT); - - size = read(STDIN_FILENO, pop_buffer.data, sizeof(pop_buffer.data)); - - alarm(0); - signal(SIGALRM, SIG_DFL); - - pop_buffer.ptr = 0; - pop_buffer.size = (size >= 0) ? size : 0; -} - -static int pop_get_char(void) -{ - if (pop_buffer.ptr >= pop_buffer.size) { - pop_fetch(); - if (!pop_buffer.size) return -1; - } - - return (unsigned char)pop_buffer.data[pop_buffer.ptr++]; -} - -static char *pop_get_line(char *line, int size) -{ - int pos; - int seen_cr, seen_nul; - int c; - - pos = 0; - seen_cr = seen_nul = 0; - while ((c = pop_get_char()) >= 0) { - if (c == '\n') { - if (seen_cr) line[pos - 1] = 0; - break; - } - if (pos < size - 1) - seen_cr = ((line[pos++] = c) == '\r'); - else - seen_cr = 0; - seen_nul |= !c; - } - line[pos] = 0; - - if (seen_nul) - line[0] = 0; - - if (pos || c >= 0) - return line; - else - return NULL; -} - -int pop_handle_state(struct pop_command *commands) -{ - char line[POP_BUFFER_SIZE]; - char *params; - struct pop_command *command; - int response; - - if (sigsetjmp(pop_timed_out, 1)) return POP_CRASH_NETTIME; - - while (pop_get_line(line, sizeof(line))) { - if ((params = strchr(line, ' '))) { - *params++ = 0; - if (!*params) params = NULL; - } - - response = POP_ERROR; - for (command = commands; command->name; command++) - if (!strcasecmp(command->name, line)) { - response = command->handler(params); - break; - } - - switch (response) { - case POP_OK: - if (pop_reply_ok()) return POP_CRASH_NETFAIL; - break; - - case POP_ERROR: - if (pop_reply_error()) return POP_CRASH_NETFAIL; - - case POP_QUIET: - break; - - case POP_LEAVE: - if (pop_reply_ok()) return POP_CRASH_NETFAIL; - - default: - return response; - } - } - - return POP_CRASH_NETFAIL; -} - -char *pop_get_param(char **params) -{ - char *current, *next; - - if ((current = *params)) { - if ((next = strchr(current, ' '))) { - *next++ = 0; - *params = *next ? next : NULL; - } else - *params = NULL; - - if (strlen(current) > 40) current = NULL; - } - - return current; -} - -int pop_get_int(char **params) -{ - char *param, *error; - long value; - - if ((param = pop_get_param(params))) { -/* SUSv2 says: - * "Because 0, LONG_MIN and LONG_MAX are returned on error and are also - * valid returns on success, an application wishing to check for error - * situations should set errno to 0, then call strtol(), then check errno." */ - errno = 0; - value = strtol(param, &error, 10); - if (errno || !*param || *error || - value < 0 || (long)(int)value != value) - return -1; - - return (int)value; - } - - return -1; -} - -int pop_reply(char *format, ...) -{ - va_list args; - - va_start(args, format); - vfprintf(stdout, format, args); - va_end(args); - - putc('\r', stdout); - putc('\n', stdout); - - switch (format[0]) { - case '+': - case '-': - return fflush(stdout); - - case '.': - if (!format[1]) return fflush(stdout); - } - - return ferror(stdout); -} - -int pop_reply_ok(void) -{ - return pop_reply("+OK"); -} - -int pop_reply_error(void) -{ - return pop_reply("-ERR"); -} - -int pop_reply_multiline(int fd, unsigned long size, int lines) -{ - char *in_buffer, *out_buffer; - char *in, *out; - int in_block, out_block; - int start, body; - - if (lines >= 0) lines++; - - if (pop_reply_ok()) return POP_CRASH_NETFAIL; - - in_buffer = malloc(RETR_BUFFER_SIZE * 3); - if (!in_buffer) return POP_CRASH_SERVER; - out_buffer = &in_buffer[RETR_BUFFER_SIZE]; - - start = 1; - body = 0; - while (size && lines) { - if (size > RETR_BUFFER_SIZE) - in_block = read(fd, in_buffer, RETR_BUFFER_SIZE); - else - in_block = read(fd, in_buffer, size); - if (in_block <= 0) { - free(in_buffer); - return POP_CRASH_SERVER; - } - - in = in_buffer; - out = out_buffer; - while (in < &in_buffer[in_block] && lines) - switch (*in) { - case '\n': - *out++ = '\r'; - *out++ = *in++; - if (start) body = 1; - if (body) lines--; - start = 1; - break; - - case '.': - if (start) *out++ = '.'; - - default: - *out++ = *in++; - start = 0; - } - - out_block = out - out_buffer; - if (write_loop(1, out_buffer, out_block) != out_block) { - free(in_buffer); - return POP_CRASH_NETFAIL; - } - - size -= in_block; - } - - free(in_buffer); - - if (!start) - if (pop_reply("%s", "")) return POP_CRASH_NETFAIL; - - return POP_OK; -} - -int pop_reply_terminate(void) -{ - return pop_reply("."); -} diff --git a/usr.sbin/popa3d/protocol.h b/usr.sbin/popa3d/protocol.h deleted file mode 100644 index e5bd394f9be..00000000000 --- a/usr.sbin/popa3d/protocol.h +++ /dev/null @@ -1,106 +0,0 @@ -/* $OpenBSD: protocol.h,v 1.3 2003/05/12 19:28:22 camield Exp $ */ - -/* - * POP protocol handling. - */ - -#ifndef _POP_PROTOCOL_H -#define _POP_PROTOCOL_H - -/* - * Responses and events, to be returned by command and state handlers. - */ -#define POP_OK 0 /* Reply with "+OK" */ -#define POP_ERROR 1 /* Reply with "-ERR" */ -#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_NETFAIL 5 /* Network failure */ -#define POP_CRASH_NETTIME 6 /* Network timeout */ -#define POP_CRASH_SERVER 7 /* POP server failure */ - -/* - * POP command description. - */ -struct pop_command { - char *name; - int (*handler)(char *params); -}; - -/* - * Internal POP command buffer. - */ -struct pop_buffer { - unsigned int ptr, size; - char data[POP_BUFFER_SIZE]; -}; - -extern struct pop_buffer pop_buffer; - -/* - * Initializes the buffer. - */ -extern void pop_init(void); - -/* - * Zeroes out the part of the buffer that has already been processed. - */ -extern void pop_clean(void); - -/* - * Checks if the buffer is sane. - */ -extern int pop_sane(void); - -/* - * Handles a POP protocol state (AUTHORIZATION or TRANSACTION, as defined - * in RFC 1939), processing the supplied commands. Returns when the state - * is changed. - */ -extern int pop_handle_state(struct pop_command *commands); - -/* - * Returns the next parameter, or NULL if there's none or it is too long - * to be valid (as defined in the RFC). - */ -extern char *pop_get_param(char **params); - -/* - * Returns the next parameter as a non-negative number, or -1 if there's - * none or the syntax is invalid. - */ -extern int pop_get_int(char **params); - -/* - * Produces a generic POP response. Returns a non-zero value on error; - * the POP session then has to crash. - */ -extern int pop_reply(char *format, ...) -#ifdef __GNUC__ - __attribute__ ((format (printf, 1, 2))); -#else - ; -#endif - -/* - * The two simple POP responses. Return a non-zero value on error; the - * POP session then has to crash. - */ -extern int pop_reply_ok(void); -extern int pop_reply_error(void); - -/* - * Produces a multi-line POP response, reading the data from the supplied - * file descriptor for up to the requested size or number of lines of the - * message body, if that number is non-negative. Returns POP_OK or one of - * the POP_CRASH_* event codes. - */ -extern int pop_reply_multiline(int fd, unsigned long size, int lines); - -/* - * Terminates a multi-line POP response. Returns a non-zero value on error; - * the POP session then has to crash. - */ -extern int pop_reply_terminate(void); - -#endif diff --git a/usr.sbin/popa3d/standalone.c b/usr.sbin/popa3d/standalone.c deleted file mode 100644 index b3be2844793..00000000000 --- a/usr.sbin/popa3d/standalone.c +++ /dev/null @@ -1,339 +0,0 @@ -/* $OpenBSD: standalone.c,v 1.14 2009/11/12 11:03:37 jsg Exp $ */ - -/* - * Standalone POP server: accepts connections, checks the anti-flood limits, - * logs and starts the actual POP sessions. - */ - -#include "params.h" - -#if POP_STANDALONE - -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <syslog.h> -#include <time.h> -#include <errno.h> -#include <netdb.h> -#include <poll.h> -#include <sys/times.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/socket.h> -#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. - */ -extern int log_error(char *s); -extern int do_pop_startup(void); -extern int do_pop_session(void); -extern int af; - -typedef volatile sig_atomic_t va_int; - -/* - * Active POP sessions. Those that were started within the last MIN_DELAY - * seconds are also considered active (regardless of their actual state), - * to allow for limiting the logging rate without throwing away critical - * information about sessions that we could have allowed to proceed. - */ -static struct { - char addr[NI_MAXHOST]; /* Source IP address */ - va_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 va_int child_blocked; /* We use blocking to avoid races */ -static va_int child_pending; /* Are any dead children waiting? */ - -int handle(int); - -/* - * SIGCHLD handler. - */ -static void handle_child(int signum) -{ - int saved_errno; - pid_t pid; - int i; - - saved_errno = errno; - - if (child_blocked) - child_pending = 1; - else { - child_pending = 0; - - while ((pid = waitpid(0, NULL, WNOHANG)) > 0) - for (i = 0; i < MAX_SESSIONS; i++) - if (sessions[i].pid == pid) { - sessions[i].pid = 0; - break; - } - } - - signal(SIGCHLD, handle_child); - - 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 error, i, n, true = 1; - struct pollfd *pfds; - struct addrinfo hints, *res, *res0; - char sbuf[NI_MAXSERV]; - - if (do_pop_startup()) return 1; - - snprintf(sbuf, sizeof(sbuf), "%u", DAEMON_PORT); - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = af; - hints.ai_flags = AI_PASSIVE; - error = getaddrinfo(NULL, sbuf, &hints, &res0); - if (error) - return log_error("getaddrinfo"); - - i = 0; - for (res = res0; res; res = res->ai_next) - i++; - - pfds = calloc(i, sizeof(pfds[0])); - if (!pfds) { - freeaddrinfo(res0); - return log_error("malloc"); - } - - i = 0; - for (res = res0; res; res = res->ai_next) { - if ((pfds[i].fd = socket(res->ai_family, res->ai_socktype, - res->ai_protocol)) < 0) - continue; - - if (setsockopt(pfds[i].fd, SOL_SOCKET, SO_REUSEADDR, - (void *)&true, sizeof(true))) { - close(pfds[i].fd); - continue; - } - -#ifdef IPV6_V6ONLY - if (res->ai_family == AF_INET6) - (void)setsockopt(pfds[i].fd, IPPROTO_IPV6, IPV6_V6ONLY, - (void *)&true, sizeof(true)); -#endif - - if (bind(pfds[i].fd, res->ai_addr, res->ai_addrlen)) { - close(pfds[i].fd); - continue; - } - - if (listen(pfds[i].fd, MAX_BACKLOG)) { - close(pfds[i].fd); - continue; - } - - pfds[i].events = POLLIN; - i++; - } - freeaddrinfo(res0); - - if (i == 0) { - free(pfds); - return log_error("socket"); - } - - n = i; - - chdir("/"); - setsid(); - - switch (fork()) { - case -1: - free(pfds); - return log_error("fork"); - - case 0: - break; - - default: - free(pfds); - return 0; - } - - setsid(); - - child_blocked = 1; - child_pending = 0; - signal(SIGCHLD, handle_child); - - memset((void *)sessions, 0, sizeof(sessions)); - - while (1) { - child_blocked = 0; - if (child_pending) raise(SIGCHLD); - - i = poll(pfds, n, INFTIM); - if (i < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - free(pfds); - return log_error("poll"); - } - - for (i = 0; i < n; i++) - if (pfds[i].revents & POLLIN) - handle(pfds[i].fd); - } -} - -int -handle(int sock) -{ - clock_t now, log; - int new; - char hbuf[NI_MAXHOST]; - struct sockaddr_storage addr; - socklen_t addrlen; - pid_t pid; - struct tms buf; - int error; - int j, n, i, s; - - log = 0; - new = 0; - - addrlen = sizeof(addr); - new = accept(sock, (struct sockaddr *)&addr, &addrlen); -/* - * I wish there was a portable way to classify errno's... In this case, - * it appears to be better to risk eating up the CPU on a fatal error - * rather than risk terminating the entire service because of a minor - * temporary error having to do with one particular connection attempt. - */ - if (new < 0) - return -1; - - error = getnameinfo((struct sockaddr *)&addr, addrlen, - hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); - if (error) { - syslog(SYSLOG_PRI_HI, - "could not get host address"); - close(new); - return -1; - } - - now = times(&buf); - if (!now) - now = 1; - - child_blocked = 1; - - j = -1; - n = 0; - s = 0; - for (i = 0; i < MAX_SESSIONS; i++) { - s = i; - if (sessions[i].start > now) - sessions[i].start = 0; - if (sessions[i].pid || - (sessions[i].start && - now - sessions[i].start < MIN_DELAY * CLK_TCK)) { - if (strcmp(sessions[i].addr, hbuf) == 0) - if (++n >= MAX_SESSIONS_PER_SOURCE) - break; - } else if (j < 0) - j = i; - } - - if (n >= MAX_SESSIONS_PER_SOURCE) { - if (!sessions[s].log || - now < sessions[s].log || - now - sessions[s].log >= MIN_DELAY * CLK_TCK) { - syslog(SYSLOG_PRI_HI, - "%s: per source limit reached", - hbuf); - sessions[s].log = now; - } - close(new); - return -1; - } - - if (j < 0) { - if (!log || - now < log || now - log >= MIN_DELAY * CLK_TCK) { - syslog(SYSLOG_PRI_HI, - "%s: sessions limit reached", hbuf); - log = now; - } - close(new); - return -1; - } - - switch ((pid = fork())) { - case -1: - syslog(SYSLOG_PRI_ERROR, "%s: fork: %m", hbuf); - close(new); - return -1; - - case 0: -#if DAEMON_LIBWRAP - check_access(new); -#endif - syslog(SYSLOG_PRI_LO, "Session from %s", - hbuf); - if (dup2(new, 0) < 0 || dup2(new, 1) < 0 || dup2(new, 2) < 0) { - log_error("dup2"); - _exit(1); - } - closefrom(3); - _exit(do_pop_session()); - - default: - close(new); - strlcpy(sessions[j].addr, hbuf, - sizeof(sessions[j].addr)); - sessions[j].pid = (va_int)pid; - sessions[j].start = now; - sessions[j].log = 0; - return 0; - } -} - -#endif diff --git a/usr.sbin/popa3d/startup.c b/usr.sbin/popa3d/startup.c deleted file mode 100644 index 0e41d5d6499..00000000000 --- a/usr.sbin/popa3d/startup.c +++ /dev/null @@ -1,91 +0,0 @@ -/* $OpenBSD: startup.c,v 1.7 2008/05/17 23:31:52 sobrado Exp $ */ - -/* - * Command line option parsing. - */ - -#include "params.h" - -#if POP_OPTIONS - -#include <sys/types.h> -#include <sys/socket.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> - -/* version.c */ -extern char popa3d_version[]; -extern char popa3d_date[]; - -/* standalone.c */ -extern int do_standalone(void); - -/* pop_root.c */ -extern int do_pop_startup(void); -extern int do_pop_session(void); - -#ifdef HAVE_PROGNAME -extern char *__progname; -#define progname __progname -#else -static char *progname; -#endif - -int af = PF_UNSPEC; - -static void usage(void) -{ - fprintf(stderr, "usage: %s [-46DV]\n", progname); - exit(1); -} - -static void version(void) -{ - printf("popa3d version %s (%.10s)\n", popa3d_version, popa3d_date + 7); - exit(0); -} - -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, "46DV")) != -1) { - switch (c) { - case '4': - af = AF_INET; - break; - - case '6': - af = AF_INET6; - break; - - case 'D': - standalone++; - break; - - case 'V': - version(); - - 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/version.c b/usr.sbin/popa3d/version.c deleted file mode 100644 index 31adeea49ab..00000000000 --- a/usr.sbin/popa3d/version.c +++ /dev/null @@ -1,9 +0,0 @@ -/* $OpenBSD: version.c,v 1.1 2003/05/12 19:28:22 camield Exp $ */ - -/* - * popa3d version information. - */ - -char popa3d_version[] = "0.6.2"; -char popa3d_date[] = "$Date: 2003/05/12 19:28:22 $"; -char popa3d_id[] = "@(#) $Id: version.c,v 1.1 2003/05/12 19:28:22 camield Exp $"; diff --git a/usr.sbin/popa3d/virtual.c b/usr.sbin/popa3d/virtual.c deleted file mode 100644 index 1153fd474bd..00000000000 --- a/usr.sbin/popa3d/virtual.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $OpenBSD: virtual.c,v 1.6 2004/06/20 05:18:07 itojun Exp $ */ - -/* - * Virtual domain support. - */ - -#include "params.h" - -#if POP_VIRTUAL - -#define _XOPEN_SOURCE 4 -#define _XOPEN_SOURCE_EXTENDED -#define _XOPEN_VERSION 4 -#define _XPG4_2 -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <stdlib.h> -#include <limits.h> -#include <errno.h> -#include <pwd.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -#ifndef NAME_MAX -#define NAME_MAX 255 -#endif - -extern int log_error(char *s); - -char *virtual_domain; -char *virtual_spool; - -int virtual_startup(void) -{ - return 0; -} - -static char *lookup(void) -{ - struct sockaddr_storage ss; - int length; - int error; - static char hbuf[NI_MAXHOST]; - - length = sizeof(ss); - if (getsockname(0, (struct sockaddr *)&ss, &length)) { - if (errno == ENOTSOCK) return ""; - log_error("getsockname"); - return NULL; - } - - error = getnameinfo((struct sockaddr *)&ss, length, hbuf, sizeof(hbuf), - NULL, 0, NI_NUMERICHOST); - if (error) { - /* logging? */ - return NULL; - } - - return hbuf; -} - -static int is_valid_user(char *user) -{ - unsigned char *p; - -/* This is pretty liberal, but we're going to use direct syscalls only, - * and they have to accept all the printable characters */ - for (p = (unsigned char *)user; *p; p++) - if (*p < ' ' || *p > 0x7E || *p == '.' || *p == '/') return 0; - - if (p - (unsigned char *)user > NAME_MAX) return 0; - - return 1; -} - -struct passwd *virtual_userpass(char *user, char *pass, int *known) -{ - struct passwd *pw, *result; - struct stat stat; - char auth[VIRTUAL_AUTH_SIZE]; - char *address, *pathname; - char *template, *passwd; - 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"; - virtual_spool = NULL; - - if (!(address = lookup())) return NULL; - -/* Authenticate globally (if supported) if run on a non-socket */ - if (!*address) { - virtual_domain = NULL; - return NULL; - } - - fail = 0; - if (!is_valid_user(user)) { - user = "INVALID"; - fail = 1; - } - -/* This "can't happen", but is just too critical to not check explicitly */ - if (strchr(address, '/') || strchr(user, '/')) - return NULL; - - if (asprintf(&pathname, "%s/%s", VIRTUAL_HOME_PATH, address) == -1) - return NULL; - - if (lstat(pathname, &stat)) { - if (errno == ENOENT) - virtual_domain = NULL; - else - log_error("lstat"); - free(pathname); - return NULL; - } - - if (!(address = strdup(address))) { - free(pathname); - return NULL; - } - virtual_domain = address; - - free(pathname); - - if (asprintf(&pathname, "%s/%s/%s/%s", VIRTUAL_HOME_PATH, address, - VIRTUAL_AUTH_PATH, user) == -1) - return NULL; - - if ((fd = open(pathname, O_RDONLY)) < 0 && errno != ENOENT) { - log_error("open"); - fail = 1; - } - - free(pathname); - - if (asprintf(&virtual_spool, "%s/%s/%s", VIRTUAL_HOME_PATH, - virtual_domain, VIRTUAL_SPOOL_PATH) == -1) { - close(fd); - return NULL; - } - - size = 0; - if (fd >= 0) { - *known = !fail; - - if ((size = read(fd, auth, sizeof(auth))) < 0) { - log_error("read"); - size = 0; - fail = 1; - } - - close(fd); - } - - if (size >= sizeof(auth)) { - size = 0; - fail = 1; - } - - auth[size] = 0; - - if (!(template = strtok(auth, ":")) || !*template) { - template = "INVALID"; - fail = 1; - } - if (!(passwd = strtok(NULL, ":")) || !*passwd || - *passwd == '*' || *passwd == '!') { - passwd = AUTH_DUMMY_SALT; - fail = 1; - } - if (!strtok(NULL, ":")) fail = 1; - - if ((pw = getpwnam(template))) - memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); - endpwent(); - - result = NULL; - if (!strcmp(crypt(pass, passwd), passwd) && !fail) - result = pw; - - memset(auth, 0, sizeof(auth)); - - return result; -} - -#endif diff --git a/usr.sbin/popa3d/virtual.h b/usr.sbin/popa3d/virtual.h deleted file mode 100644 index 307c21a05df..00000000000 --- a/usr.sbin/popa3d/virtual.h +++ /dev/null @@ -1,36 +0,0 @@ -/* $OpenBSD: virtual.h,v 1.3 2002/03/27 14:08:43 camield Exp $ */ - -/* - * Virtual domain support. - */ - -#ifndef _POP_VIRTUAL_H -#define _POP_VIRTUAL_H - -#include <pwd.h> -#include <sys/types.h> - -/* - * These are set by the authentication routine, below. - */ -extern char *virtual_domain; -extern char *virtual_spool; - -/* - * Initializes the virtual domain support at startup. Note that this will - * only be called once in standalone mode, so don't expect an open socket - * here. Returns a non-zero value on error. - */ -extern int virtual_startup(void); - -/* - * Tries to authenticate a username/password pair for the virtual domain - * 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, known is set. Returns the template user to run as if - * authentication succeeds, or NULL otherwise. - */ -extern struct passwd *virtual_userpass(char *user, char *pass, int *known); - -#endif |