Commit 8bf58774 8bf587746ac8af3afc03214f03b08b72d1971b9b by Jakob Kaivo

Actually add the files, not just the directory, to CVS

1 parent 767d2006
INCLUDES =-I$(srcdir) -I$(top_srcdir)/libsrc -I$(top_srcdir)/libmailbox
sbin_PROGRAMS = pop3d
pop3d_DEPENDENDENCIES = ../libmailbox/libmailbox.la ../libsrc/libgetopt.la\
../libsrc/libmd5.la
pop3d_SOURCES = apop.c auth.c capa.c dele.c extra.c pop3d.c pop3d.h\
list.c noop.c quit.c retr.c rset.c stat.c top.c uidl.c user.c
pop3d_LDADD = ../libmailbox/libmailbox.la
\ No newline at end of file
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
#ifdef _USE_APOP
/* Check if a username exists in APOP password file
returns pinter to password if found, otherwise NULL */
char *
pop3_apopuser (const char *user)
{
char *password;
char buf[POP_MAXCMDLEN];
struct stat st;
#ifdef BDB2
int errno;
DB *dbp;
DBT key, data;
if (stat (APOP_PASSFILE ".db", &st) != -1)
#else
char *tmp;
FILE *apop_file;
if (stat (APOP_PASSFILE ".passwd", &st) != -1)
#endif
if ((st.st_mode & 0777) != 0600)
{
syslog (LOG_INFO, "Bad permissions on APOP password file");
return NULL;
}
#ifdef BDB2
if ((errno = db_open (APOP_PASSFILE ".db", DB_HASH, DB_RDONLY, 0600,
NULL, NULL, &dbp)) != 0)
{
syslog (LOG_ERR, "Unable to open APOP database: %s", strerror (errno));
return NULL;
}
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
strncpy (buf, user, sizeof (buf));
key.data = buf;
key.size = strlen (user);
if ((errno = dbp->get (dbp, NULL, &key, &data, 0)) != 0)
{
syslog (LOG_ERR, "db_get error: %s", strerror (errno));
dbp->close (dbp, 0);
return NULL;
}
if ((password = malloc (sizeof (char) * data.size)) == NULL)
{
dbp->close (dbp, 0);
return NULL;
}
sprintf (password, "%.*s", (int) data.size, (char *) data.data);
dbp->close (dbp, 0);
return password;
#else /* !BDBD2 */
if ((apop_file = fopen (APOP_PASSFILE ".passwd", "r")) == NULL)
{
syslog (LOG_INFO, "Unable to open APOP password file");
return NULL;
}
if ((password = malloc (sizeof (char) * APOP_DIGEST)) == NULL)
{
fclose (apop_file);
pop3_abquit (ERR_NO_MEM);
}
password[0] = '\0';
while (fgets (buf, sizeof (buf) - 1, apop_file) != NULL)
{
tmp = index (buf, ':');
*tmp = '\0';
tmp++;
if (strncmp (user, buf, strlen (user)))
continue;
strncpy (password, tmp, strlen (tmp));
tmp = index (password, '\n');
*tmp = '\0';
break;
}
fclose (apop_file);
if (strlen (password) == 0)
{
free (password);
return NULL;
}
return password;
#endif /* BDB2 */
}
int
pop3_apop (const char *arg)
{
char *tmp, *user_digest, *password;
struct passwd *pw;
char buf[POP_MAXCMDLEN];
struct md5_ctx md5context;
unsigned char md5digest[16];
int i;
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
if (strlen (arg) == 0)
return ERR_BAD_ARGS;
tmp = pop3_cmd (arg);
if (strlen (tmp) > (POP_MAXCMDLEN - APOP_DIGEST))
return ERR_BAD_ARGS;
if ((username = strdup (tmp)) == NULL)
pop3_abquit (ERR_NO_MEM);
free (tmp);
tmp = pop3_args (arg);
if (strlen (tmp) > APOP_DIGEST)
return ERR_BAD_ARGS;
if ((user_digest = strdup (tmp)) == NULL)
pop3_abquit (ERR_NO_MEM);
free (tmp);
if ((password = pop3_apopuser (username)) == NULL)
return ERR_BAD_LOGIN;
md5_init_ctx (&md5context);
md5_process_bytes (md5shared, strlen (md5shared), &md5context);
md5_process_bytes (password, strlen (password), &md5context);
/* pop3_wipestr (password); */
free (password);
md5_finish_ctx (&md5context, md5digest);
tmp = buf;
for (i = 0; i < 16; i++, tmp += 2)
sprintf (tmp, "%02x", md5digest[i]);
*tmp++ = '\0';
if (strcmp (user_digest, buf))
return ERR_BAD_LOGIN;
if ((pw = getpwnam (username)) == NULL)
return ERR_BAD_LOGIN;
#ifdef MAILSPOOLHOME
mailbox = malloc ((strlen (pw->pw_dir) + strlen (MAILSPOOLHOME) + 1) * sizeof (char));
if (mailbox == NULL)
pop3_abquit (ERR_NO_MEM);
strcpy (mailbox, pw->pw_dir);
strcat (mailbox, MAILSPOOLHOME);
mbox = fopen (mailbox, "r");
if (mbox == NULL)
{
free (mailbox);
chdir (_PATH_MAILDIR);
#endif
mailbox = malloc (sizeof (char) * (strlen (_PATH_MAILDIR) + strlen (username) + 2));
strcpy (mailbox, _PATH_MAILDIR "/");
strcat (mailbox, username);
if (mailbox == NULL)
pop3_abquit (ERR_NO_MEM);
mbox = fopen (mailbox, "r");
if (mbox == NULL)
{
mailbox = strdup ("/dev/null");
if (mailbox == NULL)
pop3_abquit (ERR_NO_MEM);
mbox = fopen (mailbox, "r");
}
#ifdef MAILSPOOLHOME
}
else
#endif
if (pop3_lock () != OK)
{
pop3_unlock ();
free (mailbox);
state = AUTHORIZATION;
return ERR_MBOX_LOCK;
}
if ((pw->pw_uid < 1)
#ifdef MAILSPOOLHOME
/* Drop mail group for home dirs */
|| setgid (pw->pw_gid) == -1
#endif
|| setuid (pw->pw_uid) == -1)
{
pop3_unlock ();
free (mailbox);
return ERR_BAD_LOGIN;
}
state = TRANSACTION;
messages = NULL;
pop3_getsizes ();
fprintf (ofile, "+OK opened mailbox for %s\r\n", username);
syslog (LOG_INFO, "User %s logged in with mailbox %s", username, mailbox);
cursor = 0;
return OK;
}
#else
int
pop3_apop (const char *foo)
{
return ERR_NOT_IMPL;
}
#endif
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* AUTH is not yet implemented */
int
pop3_auth (const char *arg)
{
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
return ERR_NOT_IMPL;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
* Code for capa support by Sean 'Shaleh' Perry <shaleh@debian.org>
* added 4/2/1999
*
*/
#include "pop3d.h"
int
pop3_capa (const char *arg)
{
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
if (state != AUTHORIZATION && state != TRANSACTION)
return ERR_WRONG_STATE;
fprintf (ofile, "+OK Capability list follows\r\n");
fprintf (ofile, "TOP\r\n");
fprintf (ofile, "USER\r\n");
fprintf (ofile, "RESP-CODES\r\n");
if (state == TRANSACTION) /* let's not advertise to just anyone */
fprintf (ofile, "IMPLEMENTATION %s %s\r\n", IMPL, VERSION);
fprintf (ofile, ".\r\n");
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* DELE adds a message number to the list of messages to be deleted on QUIT */
int
pop3_dele (const char *arg)
{
int num = 0;
if ((arg == NULL) || (strchr (arg, ' ') != NULL))
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
num = atoi (arg) - 1;
if (mbox_delete(mbox, num) != 0)
return ERR_NO_MESG;
fprintf (ofile, "+OK Message %d marked\r\n", num + 1);
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Takes a string as input and returns either the remainder of the string
after the first space, or a zero length string if no space */
char *
pop3_args (const char *cmd)
{
int space = -1, i = 0, len;
char *buf;
len = strlen (cmd) + 1;
buf = malloc (len * sizeof (char));
if (buf == NULL)
pop3_abquit (ERR_NO_MEM);
while (space < 0 && i < len)
{
if (cmd[i] == ' ')
space = i + 1;
else if (cmd[i] == '\0' || cmd[i] == '\r' || cmd[i] == '\n')
len = i;
i++;
}
if (space < 0)
buf[0] = '\0';
else
{
for (i = space; i < len; i++)
if (cmd[i] == '\0' || cmd[i] == '\r' || cmd[i] == '\n')
buf[i - space] = '\0';
else
buf[i - space] = cmd[i];
}
return buf;
}
/* This takes a string and returns the string up to the first space or end of
the string, whichever occurs first */
char *
pop3_cmd (const char *cmd)
{
char *buf;
int i = 0, len;
len = strlen (cmd) + 1;
buf = malloc (len * sizeof (char));
if (buf == NULL)
pop3_abquit (ERR_NO_MEM);
for (i = 0; i < len; i++)
{
if (cmd[i] == ' ' || cmd[i] == '\0' || cmd[i] == '\r' || cmd[i] == '\n')
len = i;
else
buf[i] = cmd[i];
}
buf[i - 1] = '\0';
return buf;
}
/* This is called if GNU POP needs to quit without going to the UPDATE stage.
This is used for conditions such as out of memory, a broken socket, or
being killed on a signal */
int
pop3_abquit (int reason)
{
mbox_close(mbox);
switch (reason)
{
case ERR_NO_MEM:
fprintf (ofile, "-ERR Out of memory, quitting\r\n");
syslog (LOG_ERR, "Out of memory");
break;
case ERR_DEAD_SOCK:
fprintf (ofile, "-ERR Socket closed, quitting\r\n");
syslog (LOG_ERR, "Socket closed");
break;
case ERR_SIGNAL:
fprintf (ofile, "-ERR Quitting on signal\r\n");
syslog (LOG_ERR, "Quitting on signal");
break;
case ERR_TIMEOUT:
fprintf (ofile, "-ERR Session timed out\r\n");
if (state == TRANSACTION)
syslog (LOG_INFO, "Session timed out for user: %s", username);
else
syslog (LOG_INFO, "Session timed out for no user");
break;
default:
fprintf (ofile, "-ERR Quitting (reason unknown)\r\n");
syslog (LOG_ERR, "Unknown quit");
break;
}
fflush (ofile);
exit (1);
}
/* Prints out usage information and exits the program */
void
pop3_usage (char *argv0)
{
printf ("Usage: %s [OPTIONS]\n", argv0);
printf ("Runs the GNU POP3 daemon.\n\n");
printf (" -d, --daemon=MAXCHILDREN runs in daemon mode with a maximum\n");
printf (" of MAXCHILDREN child processes\n");
printf (" -h, --help display this help and exit\n");
printf (" -i, --inetd runs in inetd mode (default)\n");
printf (" -p, --port=PORT specifies port to listen on, implies -d\n");
printf (" defaults to 110, which need not be specified\n");
printf (" -t, --timeout=TIMEOUT sets idle timeout to TIMEOUT seconds\n");
printf (" TIMEOUT must be at least 600 (10 minutes) or\n");
printf (" it will be disabled\n");
printf (" -v, --version display version information and exit\n");
printf ("\nReport bugs to gnu-pop-list@nodomainname.net\n");
exit (0);
}
/* Default signal handler to call the pop3_abquit() function */
void
pop3_signal (int signal)
{
if (signal == SIGCHLD)
{
int stat;
while (waitpid (-1, &stat, WNOHANG) > 0);
return;
}
else
pop3_abquit (ERR_SIGNAL);
}
/* Gets a line of input from the client */
char *
pop3_readline (int fd)
{
fd_set rfds;
struct timeval tv;
char buf[1024], *ret = NULL;
int available;
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
memset (buf, '\0', 1024);
while (strchr (buf, '\n') == NULL)
{
if (timeout > 0)
{
available = select (fd + 1, &rfds, NULL, NULL, &tv);
if (!available)
pop3_abquit (ERR_TIMEOUT);
}
if (read (fd, buf, 1024) < 1)
pop3_abquit (ERR_DEAD_SOCK);
if (ret == NULL)
{
ret = malloc ((strlen (buf) + 1) * sizeof (char));
strcpy (ret, buf);
}
else
{
ret = realloc (ret, (strlen (ret) + strlen (buf) + 1) * sizeof (char));
strcat (ret, buf);
}
}
return ret;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Displays the size of message number arg or all messages (if no arg) */
int
pop3_list (const char *arg)
{
int mesg = 0;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
if (strchr (arg, ' ') != NULL)
return ERR_BAD_ARGS;
if (strlen (arg) == 0)
{
fprintf (ofile, "+OK\r\n");
for (mesg = 0; mesg < mbox->messages ; mesg++)
if (!mbox_is_deleted(mbox, mesg))
fprintf (ofile, "%d %d\r\n", mesg + 1, mbox->sizes[mesg]);
fprintf (ofile, ".\r\n");
}
else
{
mesg = atoi (arg) - 1;
if (mesg > mbox->messages || mbox_is_deleted(mbox, mesg))
return ERR_NO_MESG;
fprintf (ofile, "+OK %d %d\r\n", mesg + 1, mbox->sizes[mesg]);
}
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Does nothing */
int
pop3_noop (const char *arg)
{
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
fprintf (ofile, "+OK\r\n");
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
static struct option long_options[] =
{
{"daemon", 2, 0, 'd'},
{"help", 0, 0, 'h'},
{"inetd", 0, 0, 'i'},
{"port", 1, 0, 'p'},
{"timeout", 1, 0, 't'},
{"version", 0, 0, 'v'},
{0, 0, 0, 0}
};
int
main (int argc, char **argv)
{
struct group *gr;
static int mode;
int maxchildren = 10;
int option_index = 0;
int c = 0;
port = 110; /* Default POP3 port */
timeout = 0; /* Default timeout of 0 */
while ((c = getopt_long (argc, argv, "d::hip:t:v", long_options, &option_index)) && c != -1)
{
switch (c)
{
case 'd':
mode = DAEMON;
maxchildren = optarg ? atoi (optarg) : 10;
break;
case 'h':
pop3_usage (argv[0]);
break;
case 'i':
mode = INTERACTIVE;
break;
case 'p':
mode = DAEMON;
port = atoi (optarg);
break;
case 't':
timeout = atoi (optarg);
break;
case 'v':
printf (IMPL " ("PACKAGE " " VERSION ")\n");
exit (0);
break;
default:
break;
}
}
/* First we want our group to be mail so we can access the spool */
gr = getgrnam ("mail");
if (gr == NULL)
{
perror ("Error getting group");
exit (1);
}
if (setgid (gr->gr_gid) == -1)
{
perror ("Error setting group");
exit (1);
}
/* Set the signal handlers */
signal (SIGINT, pop3_signal);
signal (SIGQUIT, pop3_signal);
signal (SIGILL, pop3_signal);
signal (SIGBUS, pop3_signal);
signal (SIGFPE, pop3_signal);
signal (SIGSEGV, pop3_signal);
signal (SIGTERM, pop3_signal);
signal (SIGSTOP, pop3_signal);
if (timeout < 600) /* RFC 1939 says no less than 10 minutes */
timeout = 0; /* So we'll turn it off */
if (mode == DAEMON)
pop3_daemon_init ();
/* change directories */
#ifdef MAILSPOOLHOME
chdir ("/");
#else
chdir (_PATH_MAILDIR);
#endif
/* Set up for syslog */
openlog ("gnu-pop3d", LOG_PID, LOG_MAIL);
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
/* Actually run the daemon */
switch (mode)
{
case DAEMON:
if (maxchildren < 10)
maxchildren = 10;
pop3_daemon (maxchildren);
break;
case INTERACTIVE:
default:
pop3_mainloop (fileno (stdin), fileno (stdout));
break;
}
/* Close the syslog connection and exit */
closelog ();
return OK;
}
/* Sets things up for daemon mode */
void
pop3_daemon_init (void)
{
if (fork ())
exit (0); /* parent exits */
setsid (); /* become session leader */
if (fork ())
exit (0); /* new parent exits */
/* close inherited file descriptors */
close (0);
close (1);
close (2);
signal (SIGHUP, SIG_IGN); /* ignore SIGHUP */
signal (SIGCHLD, pop3_signal); /* for forking */
}
/* The main part of the daemon. This function reads input from the client and
executes the proper functions. Also handles the bulk of error reporting. */
int
pop3_mainloop (int infile, int outfile)
{
int status = OK;
char *buf, *arg, *cmd;
struct hostent *htbuf;
char *local_hostname;
ifile = infile;
ofile = fdopen (outfile, "w+");
if (ofile == NULL)
pop3_abquit (ERR_NO_OFILE);
state = AUTHORIZATION;
curr_time = time (NULL);
syslog (LOG_INFO, "Incoming connection opened");
/* Prepare the shared secret for APOP */
local_hostname = malloc (MAXHOSTNAMELEN + 1);
if (local_hostname == NULL)
pop3_abquit (ERR_NO_MEM);
gethostname (local_hostname, MAXHOSTNAMELEN);
htbuf = gethostbyname (local_hostname);
if (htbuf)
{
free (local_hostname);
local_hostname = strdup (htbuf->h_name);
}
md5shared = malloc (strlen (local_hostname) + 51);
if (md5shared == NULL)
pop3_abquit (ERR_NO_MEM);
snprintf (md5shared, strlen (local_hostname) + 50, "<%d.%ld@%s>", getpid (),
time (NULL), local_hostname);
free (local_hostname);
fflush (ofile);
fprintf (ofile, "+OK POP3 " WELCOME " %s\r\n", md5shared);
while (state != UPDATE)
{
fflush (ofile);
status = OK;
buf = pop3_readline (ifile);
cmd = pop3_cmd (buf);
arg = pop3_args (buf);
if (strlen (arg) > POP_MAXCMDLEN || strlen (cmd) > POP_MAXCMDLEN)
status = ERR_TOO_LONG;
else if (strlen (cmd) > 4)
status = ERR_BAD_CMD;
else if (strncasecmp (cmd, "USER", 4) == 0)
status = pop3_user (arg);
else if (strncasecmp (cmd, "QUIT", 4) == 0)
status = pop3_quit (arg);
else if (strncasecmp (cmd, "APOP", 4) == 0)
status = pop3_apop (arg);
else if (strncasecmp (cmd, "AUTH", 4) == 0)
status = pop3_auth (arg);
else if (strncasecmp (cmd, "STAT", 4) == 0)
status = pop3_stat (arg);
else if (strncasecmp (cmd, "LIST", 4) == 0)
status = pop3_list (arg);
else if (strncasecmp (cmd, "RETR", 4) == 0)
status = pop3_retr (arg);
else if (strncasecmp (cmd, "DELE", 4) == 0)
status = pop3_dele (arg);
else if (strncasecmp (cmd, "NOOP", 4) == 0)
status = pop3_noop (arg);
else if (strncasecmp (cmd, "RSET", 4) == 0)
status = pop3_rset (arg);
else if ((strncasecmp (cmd, "TOP", 3) == 0) && (strlen (cmd) == 3))
status = pop3_top (arg);
else if (strncasecmp (cmd, "UIDL", 4) == 0)
status = pop3_uidl (arg);
else if (strncasecmp (cmd, "CAPA", 4) == 0)
status = pop3_capa (arg);
else
status = ERR_BAD_CMD;
if (status == OK)
fflush (ofile);
else if (status == ERR_WRONG_STATE)
fprintf (ofile, "-ERR " BAD_STATE "\r\n");
else if (status == ERR_BAD_ARGS)
fprintf (ofile, "-ERR " BAD_ARGS "\r\n");
else if (status == ERR_NO_MESG)
fprintf (ofile, "-ERR " NO_MESG "\r\n");
else if (status == ERR_NOT_IMPL)
fprintf (ofile, "-ERR " NOT_IMPL "\r\n");
else if (status == ERR_BAD_CMD)
fprintf (ofile, "-ERR " BAD_COMMAND "\r\n");
else if (status == ERR_BAD_LOGIN)
fprintf (ofile, "-ERR " BAD_LOGIN "\r\n");
else if (status == ERR_MBOX_LOCK)
fprintf (ofile, "-ERR [IN-USE] " MBOX_LOCK "\r\n");
else if (status == ERR_TOO_LONG)
fprintf (ofile, "-ERR " TOO_LONG "\r\n");
free (buf);
free (cmd);
free (arg);
}
fflush (ofile);
return OK;
}
/* Runs GNU POP in standalone daemon mode. This opens and binds to a port
(default 110) then executes a pop3_mainloop() upon accepting a connection.
It starts maxchildren child processes to listen to and accept socket
connections */
int
pop3_daemon (int maxchildren)
{
int children = 0;
struct sockaddr_in client;
int sock, sock2;
unsigned int socksize;
sock = socket (PF_INET, SOCK_STREAM, (getprotobyname ("tcp"))->p_proto);
if (sock < 0)
{
syslog (LOG_ERR, "%s\n", strerror (errno));
exit (1);
}
memset (&client, 0, sizeof (struct sockaddr_in));
client.sin_family = AF_INET;
client.sin_port = htons (port);
client.sin_addr.s_addr = htonl (INADDR_ANY);
socksize = sizeof (client);
if (bind (sock, (struct sockaddr *) &client, socksize))
{
perror ("Couldn't bind to socket");
exit (1);
}
listen (sock, 128);
while (1)
{
if (children < maxchildren)
{
if (!fork ())
{
sock2 = accept (sock, &client, &socksize);
pop3_mainloop (sock2, sock2);
close (sock2);
exit (OK);
}
else
{
/* wait (NULL); */
children++;
}
}
else
{
wait (NULL);
children--;
}
}
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _POP3D_H
#define _POP3D_H 1
#include "config.h"
/* The implementation */
#define IMPL "GNU POP3 Daemon"
/* You can edit the messages the POP server prints out here */
/* Initial greeting */
#define WELCOME "Welcome to " IMPL " (" PACKAGE " " VERSION ")"
/* A command that doesn't exist */
#define BAD_COMMAND "Invalid command"
/* Incorrect number of arguments passed to a command */
#define BAD_ARGS "Invalid arguments"
/* Command issued in wrong state */
#define BAD_STATE "Incorrect state"
/* An action on a message that doesn't exist */
#define NO_MESG "No such message"
/* A command that is known but not implemented */
#define NOT_IMPL "Not implemented"
/* Invalid username or password */
#define BAD_LOGIN "Bad login"
/* User authenticated, but mailbox is locked */
#define MBOX_LOCK "Mailbox in use"
/* The command argument was > 40 characters */
#define TOO_LONG "Argument too long"
/* APOP password file, without .db or .passwd, which are added based on file
type automatically */
#define APOP_PASSFILE "/etc/apop"
/* Size of the MD5 digest for APOP */
#define APOP_DIGEST 70
/* Maximum length of a hostname (is this defined somewhere else?) */
#define MAXHOSTNAMELEN 64
/* Longest legal POP command */
#define POP_MAXCMDLEN 255
#define _GNU_SOURCE
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#include <ctype.h>
#include "md5.h"
#include "getopt.h"
#include "mailbox.h"
/* For Berkley DB2 APOP password file */
#ifdef BDB2
#include <db2/db.h>
#endif
/* The path to the mail spool files */
#ifdef HAVE_PATHS_H
#include <paths.h>
#else
#define _PATH_MAILDIR "/usr/spool/mail"
#endif
#ifdef HAVE_SECURITY_PAM_APPL_H
#include <security/pam_appl.h>
#endif
#ifdef HAVE_SHADOW_H
#include <shadow.h>
#endif
#define AUTHORIZATION 0
#define TRANSACTION 1
#define UPDATE 2
#define INTERACTIVE 0
#define DAEMON 1
#define OK 0
#define ERR_WRONG_STATE 1
#define ERR_BAD_ARGS 2
#define ERR_BAD_LOGIN 3
#define ERR_NO_MESG 4
#define ERR_NOT_IMPL 5
#define ERR_BAD_CMD 6
#define ERR_MBOX_LOCK 7
#define ERR_TOO_LONG 8
#define ERR_NO_MEM 9
#define ERR_DEAD_SOCK 10
#define ERR_SIGNAL 11
#define ERR_FILE 12
#define ERR_NO_OFILE 13
#define ERR_TIMEOUT 14
mailbox *mbox;
unsigned int port;
unsigned int timeout;
int state;
char *username;
int ifile;
FILE *ofile;
time_t curr_time;
char *md5shared;
int pop3_dele (const char *arg);
int pop3_list (const char *arg);
int pop3_noop (const char *arg);
int pop3_quit (const char *arg);
int pop3_retr (const char *arg);
int pop3_rset (const char *arg);
int pop3_stat (const char *arg);
int pop3_top (const char *arg);
int pop3_uidl (const char *arg);
int pop3_user (const char *arg);
int pop3_apop (const char *arg);
int pop3_auth (const char *arg);
int pop3_capa (const char *arg);
char *pop3_args (const char *cmd);
char *pop3_cmd (const char *cmd);
int pop3_mesg_exist (int mesg);
int pop3_abquit (int reason);
int pop3_lock (void);
int pop3_unlock (void);
int pop3_getsizes (void);
int pop3_mainloop (int infile, int outfile);
int pop3_daemon (int maxchildren);
void pop3_usage (char *argv0);
void pop3_signal (int signal);
void pop3_daemon_init (void);
#ifdef _USE_APOP
char *pop3_apopuser (const char *user);
#endif
char *pop3_readline (int fd);
#endif /* _POP3D_H */
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Enters the UPDATE phase and deletes marked messages */
int
pop3_quit (const char *arg)
{
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
if (state == TRANSACTION)
{
mbox_expunge (mbox);
mbox_close (mbox);
syslog (LOG_INFO, "Session ended for user: %s", username);
}
else
syslog (LOG_INFO, "Session ended for no user");
state = UPDATE;
free (username);
free (md5shared);
fprintf (ofile, "+OK\r\n");
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Prints out the specified message */
int
pop3_retr (const char *arg)
{
int mesg;
char *buf;
if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
mesg = atoi (arg) - 1;
if (mesg > mbox->messages || mbox_is_deleted(mbox, mesg))
return ERR_NO_MESG;
fprintf (ofile, "+OK\r\n");
buf = mbox_get_header (mbox, mesg);
fprintf (ofile, "%s", buf);
free (buf);
buf = mbox_get_body (mbox, mesg);
fprintf (ofile, "%s", buf);
free (buf);
fprintf (ofile, ".\r\n");
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Resets the connection so that no messages are marked as deleted */
int
pop3_rset (const char *arg)
{
int i;
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
for (i = 0; i < mbox->messages; i++)
mbox_undelete (mbox, i);
fprintf (ofile, "+OK\r\n");
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Prints the number of messages and the total size of all messages */
int
pop3_stat (const char *arg)
{
int size = 0;
int i;
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
for (i = 0; i < mbox->messages ; i++)
if (!mbox_is_deleted (mbox, i))
size += mbox->sizes[i];
fprintf (ofile, "+OK %d %d\r\n", mbox->messages - mbox->num_deleted, size);
return OK;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
/* Prints the header of a message plus a specified number of lines */
int
pop3_top (const char *arg)
{
#ifdef _HAVE_BLACK_MAGIC
int i = 0, header = 1, done = 0;
int mesg, lines;
char *mesgc, *linesc;
char *buf, buf2[80];
if (strlen (arg) == 0)
return ERR_BAD_ARGS;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
mesgc = pop3_cmd (arg);
linesc = pop3_args (arg);
mesg = atoi (mesgc) - 1;
lines = strlen (linesc) > 0 ? atoi (linesc) : -1;
free (mesgc);
free (linesc);
if (lines < 0)
return ERR_BAD_ARGS;
if (pop3_mesg_exist (mesg) != OK)
return ERR_NO_MESG;
mbox = freopen (mailbox, "r", mbox);
if (mbox == NULL)
return ERR_FILE;
fsetpos (mbox, &(messages[mesg].header));
fprintf (ofile, "+OK\r\n");
buf = malloc (sizeof (char) * 80);
if (buf == NULL)
pop3_abquit (ERR_NO_MEM);
while (fgets (buf, 80, mbox) && !done)
{
while (strchr (buf, '\n') == NULL)
{
buf = realloc (buf, sizeof (char) * (strlen (buf) + 81));
if (buf == NULL)
pop3_abquit (ERR_NO_MEM);
fgets (buf2, 80, mbox);
strncat (buf, buf2, 80);
}
if (!strncmp (buf, "From ", 5))
done = 1;
else
{
buf[strlen (buf) - 1] = '\0';
if (header == 1)
{
if (buf[0] == '.')
fprintf (ofile, ".%s\r\n", buf);
else
fprintf (ofile, "%s\r\n", buf);
if ((buf[0] == '\r') || (buf[0] == '\n') || (buf[0]) == '\0')
header = 0;
}
else
{
if (++i <= lines)
{
if (buf[0] == '.')
fprintf (ofile, ".%s\r\n", buf);
else
fprintf (ofile, "%s\r\n", buf);
}
else
done = 1;
}
}
buf = realloc (buf, sizeof (char) * 80);
if (buf == NULL)
pop3_abquit (ERR_NO_MEM);
}
free (buf);
fprintf (ofile, ".\r\n");
return OK;
#else
return ERR_NOT_IMPL;
#endif
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
int
pop3_uidl (const char *arg)
{
if (state != TRANSACTION)
return ERR_WRONG_STATE;
return ERR_NOT_IMPL;
}
/* GNU POP3 - a small, fast, and efficient POP3 daemon
Copyright (C) 1999 Jakob 'sparky' Kaivo <jkaivo@nodomainname.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
#ifdef USE_LIBPAM
#define COPY_STRING(s) (s) ? strdup(s) : NULL
static char *_pwd;
static char *_user;
static int _perr = 0;
#define PAM_ERROR if (_perr || (pamerror != PAM_SUCCESS)) { \
pam_end(pamh, 0); \
return ERR_BAD_LOGIN; }
static int
PAM_gnupop3d_conv (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
{
int replies = 0;
struct pam_response *reply = NULL;
reply = (struct pam_response *) malloc (sizeof (struct pam_response) * num_msg);
if (!reply)
return PAM_CONV_ERR;
for (replies = 0; replies < num_msg; replies++)
{
switch (msg[replies]->msg_style)
{
case PAM_PROMPT_ECHO_ON:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = COPY_STRING (_user);
/* PAM frees resp */
break;
case PAM_PROMPT_ECHO_OFF:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = COPY_STRING (_pwd);
/* PAM frees resp */
break;
case PAM_TEXT_INFO:
case PAM_ERROR_MSG:
reply[replies].resp_retcode = PAM_SUCCESS;
reply[replies].resp = NULL;
break;
default:
free (reply);
_perr = 1;
return PAM_CONV_ERR;
}
}
*resp = reply;
return PAM_SUCCESS;
}
static struct pam_conv PAM_conversation =
{&PAM_gnupop3d_conv, NULL};
#endif /* USE_LIBPAM */
/* Basic user authentication. This also takes the PASS command and verifies
the user name and password. Calls setuid() upon successful verification,
otherwise it will (likely) return ERR_BAD_LOGIN */
int
pop3_user (const char *arg)
{
char *buf, pass[POP_MAXCMDLEN], *tmp, *cmd;
#ifdef USE_LIBPAM
pam_handle_t *pamh;
int pamerror;
#endif /* !USE_LIBPAM */
struct passwd *pw;
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
return ERR_BAD_ARGS;
fprintf (ofile, "+OK\r\n");
fflush (ofile);
buf = pop3_readline (ifile);
cmd = pop3_cmd (buf);
tmp = pop3_args (buf);
free (buf);
if (strlen (tmp) > POP_MAXCMDLEN)
{
free (tmp);
return ERR_TOO_LONG;
}
else
{
strncpy (pass, tmp, POP_MAXCMDLEN);
free (tmp);
}
if (strlen (cmd) > 4)
{
free (cmd);
return ERR_BAD_CMD;
}
if ((strcasecmp (cmd, "PASS") == 0))
{
free (cmd);
#ifdef _USE_APOP
/* Check to see if they have an APOP password. If so, refuse USER/PASS */
tmp = pop3_apopuser (arg);
if (tmp != NULL)
{
syslog (LOG_INFO, "APOP user %s tried to log in with USER", arg);
free (tmp);
return ERR_BAD_LOGIN;
}
free (tmp);
#endif
pw = getpwnam (arg);
#ifndef USE_LIBPAM
if (pw == NULL)
return ERR_BAD_LOGIN;
if (pw->pw_uid < 1)
return ERR_BAD_LOGIN;
if (strcmp (pw->pw_passwd, crypt (pass, pw->pw_passwd)))
{
#ifdef HAVE_SHADOW_H
struct spwd *spw;
spw = getspnam (arg);
if (spw == NULL)
return ERR_BAD_LOGIN;
if (strcmp (spw->sp_pwdp, crypt (pass, spw->sp_pwdp)))
#endif /* HAVE_SHADOW_H */
return ERR_BAD_LOGIN;
}
#else /* USE_LIBPAM */
_user = (char *) arg;
_pwd = pass;
/* libpam doesn't log to LOG_MAIL */
closelog ();
pamerror = pam_start ("gnu-pop3d", arg, &PAM_conversation, &pamh);
PAM_ERROR;
pamerror = pam_authenticate (pamh, 0);
PAM_ERROR;
pamerror = pam_acct_mgmt (pamh, 0);
PAM_ERROR;
pamerror = pam_setcred (pamh, PAM_ESTABLISH_CRED);
PAM_ERROR;
pam_end (pamh, PAM_SUCCESS);
openlog ("gnu-pop3d", LOG_PID, LOG_MAIL);
#endif /* USE_LIBPAM */
#ifdef MAILSPOOLHOME
chdir (pw->pw_dir);
mbox = mbox_open (MAILSPOOLHOME);
if (mbox == NULL)
{
/* See comments below... */
chdir (_PATH_MAILDIR);
#endif /* MAILSPOOLHOME */
mbox = mbox_open (arg);
if (mbox == NULL)
{
/* Check the error type... */
/* Until then, though */
state = AUTHORIZATION;
return ERR_MBOX_LOCK;
}
#ifdef MAILSPOOLHOME
}
#endif
username = strdup (arg);
if (username == NULL)
pop3_abquit (ERR_NO_MEM);
state = TRANSACTION;
if (pw != NULL && pw->pw_uid > 1)
setuid (pw->pw_uid);
fprintf (ofile, "+OK opened mailbox for %s\r\n", username);
syslog (LOG_INFO, "User '%s' logged in with mailbox '%s'", username,
mbox->name);
return OK;
}
else if (strcasecmp (cmd, "QUIT") == 0)
{
free (cmd);
return pop3_quit (pass);
}
free (cmd);
return ERR_BAD_LOGIN;
}