Commit 12c30884 12c3088414a4e581901e8bb48648c8249b0b5775 by Alain Magloire

See ChangeLog

1 parent 4d68dc11
2001-05-02 Alain Magloire
Some of the Makefile.am contain gcc specific options
like -Wall, -pedantic or -ansi remove them.
* configure.in: Check for stdarg and sysconf.
* mailbox/mime.c (_mime_set_content_type): Delayed the
creation of the header-field content-type until the message
is requested via mime_get_message().
* pop3d/lock.: new File to implement the locking.
* pop3d/apop.c: Rearrange the code around the #ifdefs
to be clearrer.
Make sure that when we use strncpy() that the buffer is
null terminated. Added the locking propose by Sergey to apop.
* pop3d/capa.c: Announce we support PIPELINING.
* pop3d/extra.c (pop3d_abquit): Remove ERR_DEAD_SOCK.
Remove the extra fflush(), the call to exit() always
flush the buffers.
(pop3d_readline): Implement PIPELINING.
* pop3d/pop3d.c: Remove the typedef struct sockaddr SA
for more clarity since it is not use that often.
port is not longer a global variable.
children should have the volatile qualification.
2001-04-29 Alain Magloire
* pop3d/extra.c (pop3d_readline): Modify the loop to be able
to support PIPELINING.
* pop3d/capa.c: Advertise that we support PIPELINING.
2001-04-29 Sergey Poznyakoff
Return values of all signal handlers are changed to RETSIGTYPE
and configure.in is modified accordingly. This is more portable.
* configure.in: New Macro AC_TYPE_SIGNAL.
* mailbox/locker.c (locker_lock): while trying to read pid value
from the pidfile passed wrong buffer length to read() call, namely:
read(fd, buf, sizeof (pid_t)).
2001-04-29 Sergey Poznyakoff
I have modified locker.c to implement reference count. The
struct _locker is now:
struct _locker { int fd; int refcnt; char *fname; int flags; };
The refcnt member gets incremented each time locker_lock is called and
decremented each time locker_unlock is called. Actual locking is
performed only if refcnt == 0 on entry to locker_lock. Similarly,
unlocking is performed only when refcnt gets decremented to 0 by
locker_unlock. Also I have added basic support for NFS-secure
locking.
* mailbox/locker.c: Reference count implementation.
2001-04-25 Alain Magloire
* imap4d/store.c: First implementation.
* mailbox/attribute.c (attribute_unsee_flags): New function.
* mailbox/attribute.c (attribute_unset_flags): New function.
2001-04-23 Sergey Poznyakoff
* mailbox/mbx_mbox.c (mbx_expunge): It assumes that mbox_get_message()
will place the pointer to message into mum->message member. But
mbox_get_message() relies on 1-based message numbers, whereas `mum'
pointer is obtained using 0-based indexing:
pointer is obtained using 0-based indexing.
2001-04-23 Alain Magloire
Sergey Poznyakoff noted: When the user's mailbox ha zeor size mmap
fails on Solaris. On GNU/Linux it reuturn NULL buf subsequet munmap
Sergey Poznyakoff noted: When the user's mailbox has zero size, mmap
fails on Solaris. On GNU/Linux it reuturn NULL buf subsequent munmap
fails.
* mailbox/mapfile_stream.c: To take care of this will set
the mfs->ptr to NULL for len == 0;
* mailbox/mapfile_stream.c: To take care of this, mfs->ptr is set
to NULL for len == 0;
*mailbox/mbx_mbox.c (mbox_is_updated): Should I have return 0 (FALSE)
when size change.
......@@ -48,7 +103,7 @@
2001-04-23 Sergey Poznyakoff
It is often convenient to separte log outputs from POP and SMTP
It is often convenient to separate log outputs from POP and SMTP
servers. --with-log-facility flag which allows to specify to which
log facility the loggin output should be directed.
System administrators often prefere to have more information about
......
......@@ -15,4 +15,3 @@ noinst_HEADERS = argp-fmtstream.h argp-namefrob.h argp.h
libargp_a_LIBADD = ../lib/libmailutils.a
CFLAGS = -Wall -g
......
......@@ -56,7 +56,7 @@ AC_HEADER_STDC
AC_HEADER_DIRENT
AM_C_PROTOTYPES
AC_CHECK_HEADERS(argp.h errno.h fcntl.h inttypes.h libgen.h limits.h malloc.h \
paths.h shadow.h stdio.h stdlib.h string.h strings.h sys/file.h syslog.h \
paths.h shadow.h stdarg.h stdio.h stdlib.h string.h strings.h sys/file.h syslog.h \
unistd.h)
dnl Checks for typedefs, structures, and compiler characteristics.
......@@ -66,6 +66,7 @@ AC_TYPE_MODE_T
AC_TYPE_OFF_T
AC_TYPE_PID_T
AC_TYPE_SIZE_T
AC_TYPE_SIGNAL
dnl Check for working functions
......@@ -80,7 +81,7 @@ if test "$ac_cv_func_fnmatch_works" = "no"; then
: LIBOBJS="$LIBOBJS fnmatch.o"
fi
AC_REPLACE_FUNCS(setenv snprintf strtok_r strncasecmp strcasecmp vasprintf)
AC_CHECK_FUNCS(mkstemp sigaction)
AC_CHECK_FUNCS(mkstemp sigaction sysconf)
dnl Check for libraries
AC_CHECK_FUNCS(argp_parse)
......
AUTOMAKE_OPTIONS = ../lib/ansi2knr
CFLAGS = -Wall -pedantic -g
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/lib
bin_PROGRAMS = frm
......
AUTOMAKE_OPTIONS = ../lib/ansi2knr
INCLUDES = -I$(top_srcdir)/lib -I$(top_srcdir)/include
CFLAGS = -Wall -ansi
sbin_PROGRAMS = imap4d
......
......@@ -18,11 +18,11 @@
#include "imap4d.h"
#include <ctype.h>
static int add2set (int **set, int *n, unsigned long val, size_t max);
static const char * sc2string (int rc);
static int add2set __P ((int **, int *, unsigned long, size_t));
static const char *sc2string __P ((int));
/* FIXME: Some words are:
between double quotes, between parenthesis. */
/* Get the next space/CR/NL separated word, some words are between double
quotes, strtok() can not handle it. */
char *
util_getword (char *s, char **save)
{
......@@ -50,6 +50,7 @@ util_getword (char *s, char **save)
return strtok_r (s, " \r\n", save);
}
/* Stop a the first char that IMAP4 represent as a special characters. */
int
util_token (char *buf, size_t len, char **ptr)
{
......@@ -142,7 +143,8 @@ util_tilde_expansion (const char *ref, const char *delim)
return p;
}
/* Absolute path. */
/* Get the absolute path. */
/* NOTE: Path is allocated and must be free()d by the caller. */
char *
util_getfullpath (char *name, const char *delim)
{
......@@ -158,7 +160,6 @@ util_getfullpath (char *name, const char *delim)
}
/* Return in set an allocated array contain (n) numbers, for imap messsage set
set ::= sequence_num / (sequence_num ":" sequence_num) / (set "," set)
sequence_num ::= nz_number / "*"
;; * is the largest number in use. For message
......@@ -182,6 +183,7 @@ util_msgset (char *s, int **set, int *n, int isuid)
status = mailbox_messages_count (mbox, &max);
if (status != 0)
return status;
/* If it is a uid sequence, override max with the UID. */
if (isuid)
{
message_t msg = NULL;
......@@ -227,11 +229,20 @@ util_msgset (char *s, int **set, int *n, int isuid)
break;
}
/* A pair of numbers separated by a ':' character indicates a
contiguous set of mesages ranging from the first number to the
second:
3:5 --> 3 4 5
*/
case ':':
low = val + 1;
s++;
break;
/* As a convenience. '*' is provided to refer to the highest message
number int the mailbox:
5:* --> 5 6 7 8
*/
case '*':
{
if (status != 0)
......@@ -246,6 +257,10 @@ util_msgset (char *s, int **set, int *n, int isuid)
break;
}
/* IMAP also allows a set of noncontiguous numbers to be specified
with the ',' character:
1,3,5,7 --> 1 3 5 7
*/
case ',':
s++;
break;
......@@ -275,6 +290,7 @@ util_msgset (char *s, int **set, int *n, int isuid)
return 0;
}
/* Use vfprintf for the dirty work. */
int
util_send (const char *format, ...)
{
......@@ -286,40 +302,42 @@ util_send (const char *format, ...)
return status;
}
/* Send an unsolicited response. */
int
util_out (int rc, const char *format, ...)
{
char *buf = NULL;
int status;
va_list ap;
asprintf (&buf, "* %s%s\r\n", sc2string (rc), format);
va_start (ap, format);
vasprintf (&buf, format, ap);
status = vfprintf (ofile, buf, ap);
va_end (ap);
fprintf (ofile, "* %s%s\r\n", sc2string (rc), buf);
free (buf);
return 0;
return status;
}
/* Send the tag response and reset the state. */
int
util_finish (struct imap4d_command *command, int rc, const char *format, ...)
{
char *buf = NULL;
const char *resp;
int new_state;
int status;
va_list ap;
asprintf (&buf, "%s %s%s %s\r\n", command->tag, sc2string (rc),
command->name, format);
va_start (ap, format);
vasprintf (&buf, format, ap);
status = vfprintf (ofile, buf, ap);
va_end(ap);
resp = sc2string (rc);
fprintf (ofile, "%s %s%s %s\r\n", command->tag, resp, command->name, buf);
free (buf);
/* Reset the state. */
new_state = (rc == RESP_OK) ? command->success : command->failure;
if (new_state != STATE_NONE)
state = new_state;
return 0;
return status;
}
char *
......@@ -339,29 +357,27 @@ imap4d_readline (int fd)
do
{
if (timeout > 0)
if (timeout)
{
available = select (fd + 1, &rfds, NULL, NULL, &tv);
if (!available)
util_quit (1); /* FIXME: Timeout, send a "* BYE". */
util_quit (1);
}
nread = read (fd, buf, sizeof (buf) - 1);
if (nread < 1)
util_quit (1); /* FIXME: dead socket, need to do something? */
util_quit (1);
buf[nread] = '\0';
ret = realloc (ret, (total + nread + 1) * sizeof (char));
if (ret == NULL)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
util_quit (1);
memcpy (ret + total, buf, nread + 1);
total += nread;
/* FIXME: handle literal strings here. */
}
while (memchr (buf, '\n', nread) == NULL);
/* Nuke CR'\r' */
for (nread = total; nread > 0; nread--)
if (ret[nread] == '\r' || ret[nread] == '\n')
ret[nread] = '\0';
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -35,7 +35,7 @@ extern "C" {
struct _locker;
typedef struct _locker *locker_t;
extern int locker_create __P ((locker_t *, char *filename,
extern int locker_create __P ((locker_t *, const char *filename,
size_t len, int flags));
extern void locker_destroy __P ((locker_t *));
......@@ -47,9 +47,11 @@ extern void locker_destroy __P ((locker_t *));
#define MU_LOCKER_FCNTL 2
#define MU_LOCKER_TIME 4
extern int locker_lock __P ((locker_t, int flag));
extern int locker_touchlock __P ((locker_t));
extern int locker_unlock __P ((locker_t));
#define MU_LOCKER_EXPIRE_TIME (5 * 60)
extern int locker_lock __P ((locker_t, int flag));
extern int locker_touchlock __P ((locker_t));
extern int locker_unlock __P ((locker_t));
#ifdef __cplusplus
}
......
......@@ -12,4 +12,3 @@ noinst_HEADERS = argcv.h error.h fnmatch.h getline.h getopt.h md5.h \
libmailutils_a_LIBADD = @LIBOBJS@ @ALLOCA@
CFLAGS = -Wall -pedantic -g
......
AUTOMAKE_OPTIONS = ../lib/ansi2knr no-dependencies
CFLAGS = -Wall -g
INCLUDES = -I${top_srcdir}/include -I${top_srcdir}/lib @ARGPINCS@
bin_PROGRAMS = mail
......
......@@ -4,7 +4,6 @@ AUTOMAKE_OPTIONS = ../lib/ansi2knr
INCLUDES = -I${top_srcdir}/include -I${top_srcdir}/mailbox/include \
-I${top_srcdir}/lib
CFLAGS = -Wall -g
SUBDIRS = include
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -35,33 +35,30 @@
#include <mailutils/locker.h>
#define LOCKFILE_ATTR 0444
#define LOCK_EXPIRE_TIME (5 * 60)
/* First draft by Brian Edmond. */
struct _locker
{
int fd;
int refcnt;
char *fname;
int flags;
};
int
locker_create (locker_t *plocker, char *filename, size_t len, int flags)
locker_create (locker_t *plocker, const char *filename, size_t len, int flags)
{
locker_t l;
if (plocker == NULL)
if (plocker == NULL || filename == NULL || len == 0)
return EINVAL;
if (filename == NULL || len == 0)
return EINVAL;
l = malloc (sizeof(*l));
l = malloc (sizeof (*l));
if (l == NULL)
return ENOMEM;
l->fname = calloc (len + 5 /*strlen(".lock")*/ + 1, sizeof(char));
l->fname = calloc (len + 5 /*strlen(".lock")*/ + 1, sizeof (*(l->fname)));
if (l->fname == NULL)
{
free (l);
......@@ -75,6 +72,7 @@ locker_create (locker_t *plocker, char *filename, size_t len, int flags)
else
l->flags = MU_LOCKER_TIME; /* Default is time lock implementation. */
l->fd = -1;
l->refcnt = 0;
*plocker = l;
return 0;
}
......@@ -98,27 +96,41 @@ locker_lock (locker_t lock, int flags)
pid_t pid;
int removed = 0;
(void)flags;
(void)flags; /* Ignore for now. */
if (lock == NULL)
return EINVAL;
/* Is the lock already applied?
FIXME: should we check flags != lock->flags ?? */
if (lock->fd != -1)
{
lock->refcnt++;
return 0;
}
/*
Check for lock existance:
if it exists but the process is gone the lock can be removed,
if if the lock is expired and remove it. */
if ((fd = open(lock->fname, O_RDONLY)) != -1)
if the lock is expired, remove it. */
fd = open (lock->fname, O_RDONLY);
if (fd != -1)
{
/* Check to see if this process is still running. */
if (lock->flags & MU_LOCKER_PID)
{
if (read(fd, buf, sizeof (pid_t)) > 0)
int nread = read (fd, buf, sizeof (buf) - 1);
if (nread > 0)
{
if ((pid = atoi(buf)) > 0)
buf[nread] = '\0';
pid = strtol (buf, NULL, 10);
if (pid > 0)
{
/* Process is gone so we try to remove the lock. */
if (kill(pid, 0) == -1)
if (kill (pid, 0) == -1)
removed = 1;
}
else
removed = 1; /* Corrupted file, remove the lock. */
}
}
/* Check to see if the lock expired. */
......@@ -126,72 +138,95 @@ locker_lock (locker_t lock, int flags)
{
struct stat stbuf;
fstat(fd, &stbuf);
fstat (fd, &stbuf);
/* The lock has expired. */
if ((time(NULL) - stbuf.st_mtime) > LOCK_EXPIRE_TIME)
if ((time (NULL) - stbuf.st_mtime) > MU_LOCKER_EXPIRE_TIME)
removed = 1;
}
close(fd);
close (fd);
if (removed)
unlink(lock->fname);
unlink (lock->fname);
}
/* Try to create the lockfile. */
if ((fd = open(lock->fname,
O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_ATTR)) == -1)
fd = open (lock->fname, O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_ATTR);
if (fd == -1)
return errno;
else
{
struct stat fn_stat;
struct stat fd_stat;
if (lstat (lock->fname, &fn_stat)
|| fstat(fd, &fd_stat)
|| fn_stat.st_nlink != 1
|| fn_stat.st_dev != fd_stat.st_dev
|| fn_stat.st_ino != fd_stat.st_ino
|| fn_stat.st_uid != fd_stat.st_uid
|| fn_stat.st_gid != fd_stat.st_gid)
{
close (fd);
unlink (lock->fname);
return EPERM;
}
}
/* Success. */
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf));
sprintf (buf, "%ld", (long)getpid ());
write (fd, buf, strlen (buf));
/* Try to get a file lock. */
if (lock->flags & MU_LOCKER_FCNTL)
{
struct flock fl;
memset(&fl, 0, sizeof(struct flock));
memset (&fl, 0, sizeof (struct flock));
fl.l_type = F_WRLCK;
if (fcntl(fd, F_SETLK, &fl) == -1)
if (fcntl (fd, F_SETLK, &fl) == -1)
{
int err = errno;
/* Could not get the file lock. */
close (fd);
unlink(lock->fname); /* Remove the file I created. */
unlink (lock->fname); /* Remove the file I created. */
return err;
}
}
lock->fd = fd;
lock->refcnt++;
return 0;
}
int
locker_touchlock (locker_t lock)
{
if (!lock || ! lock->fname || (lock->fd == -1))
if (!lock || !lock->fname || lock->fd == -1)
return EINVAL;
return (utime(lock->fname, NULL));
return utime (lock->fname, NULL);
}
int
locker_unlock (locker_t lock)
{
if (!lock || ! lock->fname || (lock->fd == -1))
if (!lock || !lock->fname || lock->fd == -1 || lock->refcnt <= 0)
return EINVAL;
if (--lock->refcnt > 0)
return 0;
if (lock->flags & MU_LOCKER_FCNTL)
{
struct flock fl;
memset(&fl, 0, sizeof(struct flock));
memset (&fl, 0, sizeof (struct flock));
fl.l_type = F_UNLCK;
/* Unlock failed ? */
if (fcntl(lock->fd, F_SETLK, &fl) == -1)
/* Unlock failed? */
if (fcntl (lock->fd, F_SETLK, &fl) == -1)
return errno;
}
close(lock->fd);
close (lock->fd);
lock->fd = -1;
unlink(lock->fname);
unlink (lock->fname);
return 0;
}
......
......@@ -127,7 +127,7 @@ static int pop_write __P ((pop_data_t));
If the POP server supports TOP, we can cleanly fetch the header.
But otherwise we use the clumsy approach. .i.e for the header we read 'til
^\n then discard the rest, for the body we read after ^\n and discard the
beginning. This a waste, Pop was not conceive for this obviously. */
beginning. This is a waste, Pop was not conceive for this obviously. */
struct _pop_message
{
int inbody;
......@@ -175,8 +175,8 @@ struct _pop_data
/* Usefull little Macros, since these are very repetitive. */
/* Check if we're busy ? */
/* POP is a one channel dowload protocol, so if someone
is trying to do another command while another is running
/* POP is a one channel download protocol, so if someone
is trying to execute a command while another is running
something is seriously incorrect, So the best course
of action is to close down the connection and start a new one.
For example mime_t only reads part of the message. If a client
......@@ -193,7 +193,7 @@ struct _pop_data
}
if in the while of the readline, one try to get another email. The pop
server will get seriously confused, and the second message will still
be the first one, There is no way to tell POP servers ye! stop/abort.
be the first one, There is no way to tell POP servers yo! stop/abort.
The approach is to close the stream and reopen again. So every time
we go in to a function our state is preserve by the triplets
mpd->{func,state,id}. The macro CHECK_BUSY checks if we are not
......
......@@ -395,6 +395,10 @@ _mime_set_content_type(mime_t mime)
header_t hdr = NULL;
size_t size;
/* Delayed the creation of the header 'til they create the final message via
mime_get_message() */
if (mime->hdrs == NULL)
return 0;
if ( mime->nmtp_parts > 1 ) {
if ( mime->flags & MIME_ADDED_MULTIPART_CT )
return 0;
......
AUTOMAKE_OPTIONS = ../lib/ansi2knr
INCLUDES =-I$(srcdir) -I$(top_srcdir)/lib -I$(top_srcdir)/include
CFLAGS = -Wall -g
sbin_PROGRAMS = pop3d
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 signal.c
pop3d_SOURCES = apop.c auth.c capa.c dele.c extra.c pop3d.c pop3d.h \
list.c lock.c noop.c quit.c retr.c rset.c stat.c top.c uidl.c user.c signal.c
pop3d_LDADD = ../mailbox/libmailbox.la ../lib/libmailutils.a @AUTHLIBS@
......
......@@ -17,6 +17,24 @@
#include "pop3d.h"
/*
APOP name digest
Arguments:
a string identifying a mailbox and a MD5 digest string
(both required)
Restrictions:
may only be given in the AUTHORIZATION state after the POP3
greeting or after an unsuccessful USER or PASS command
When the POP3 server receives the APOP command, it verifies
the digest provided. If the digest is correct, the POP3
server issues a positive response, and the POP3 session
enters the TRANSACTION state. Otherwise, a negative
response is issued and the POP3 session remains in the
AUTHORIZATION state. */
/* Check if a username exists in APOP password file
returns pointer to password if found, otherwise NULL */
char *
......@@ -25,16 +43,11 @@ pop3d_apopuser (const char *user)
char *password;
char buf[POP_MAXCMDLEN];
struct stat st;
#ifdef WITH_BDB2
int errno;
DB *dbp;
DBT key, data;
/* Check the mode, for security reasons. */
#ifdef WITH_BDB2
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)
......@@ -44,80 +57,91 @@ pop3d_apopuser (const char *user)
}
#ifdef WITH_BDB2
errno = db_open (APOP_PASSFILE ".db", DB_HASH, DB_RDONLY, 0600, NULL,
NULL, &dbp);
if (errno != 0)
{
syslog (LOG_ERR, "Unable to open APOP database: %s", strerror (errno));
return NULL;
}
{
int status;
DB *dbp;
DBT key, data;
status = db_open (APOP_PASSFILE ".db", DB_HASH, DB_RDONLY, 0600, NULL,
NULL, &dbp);
if (status != 0)
{
syslog (LOG_ERR, "Unable to open APOP db: %s", strerror (status));
return NULL;
}
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
memset (&key, 0, sizeof (DBT));
memset (&data, 0, sizeof (DBT));
strncpy (buf, user, sizeof (buf));
key.data = buf;
key.size = strlen (user);
errno = dbp->get (dbp, NULL, &key, &data, 0);
if (errno != 0)
{
syslog (LOG_ERR, "db_get error: %s", strerror (errno));
dbp->close (dbp, 0);
return NULL;
}
strncpy (buf, user, sizeof buf);
/* strncpy () is lame and does not NULL terminate. */
buf[sizeof (buf) - 1] = '\0';
key.data = buf;
key.size = strlen (buf);
status = dbp->get (dbp, NULL, &key, &data, 0);
if (status != 0)
{
syslog (LOG_ERR, "db_get error: %s", strerror (status));
dbp->close (dbp, 0);
return NULL;
}
password = malloc (sizeof (char) * data.size);
if (password == NULL)
{
dbp->close (dbp, 0);
return NULL;
}
password = calloc (data.size + 1, sizeof (*password));
if (password == NULL)
{
dbp->close (dbp, 0);
return NULL;
}
sprintf (password, "%.*s", (int) data.size, (char *) data.data);
dbp->close (dbp, 0);
return password;
sprintf (password, "%.*s", (int) data.size, (char *) data.data);
dbp->close (dbp, 0);
return password;
}
#else /* !WITH_BDBD2 */
apop_file = fopen (APOP_PASSFILE ".passwd", "r");
if (apop_file == NULL)
{
syslog (LOG_INFO, "Unable to open APOP password file");
return NULL;
}
{
char *tmp;
FILE *apop_file;
apop_file = fopen (APOP_PASSFILE ".passwd", "r");
if (apop_file == NULL)
{
syslog (LOG_INFO, "Unable to open APOP password file");
return NULL;
}
password = malloc (sizeof (char) * APOP_DIGEST);
if (password == NULL)
{
fclose (apop_file);
pop3d_abquit (ERR_NO_MEM);
}
password[0] = '\0';
password = calloc (APOP_DIGEST, sizeof (*password));
if (password == NULL)
{
fclose (apop_file);
pop3d_abquit (ERR_NO_MEM);
}
while (fgets (buf, sizeof (buf) - 1, apop_file) != NULL)
{
tmp = strchr (buf, ':');
if (tmp == NULL)
continue;
*tmp = '\0';
tmp++;
if (strncmp (user, buf, strlen (user)))
continue;
strncpy (password, tmp, strlen (tmp));
tmp = strchr (password, '\n');
if (tmp)
*tmp = '\0';
break;
}
while (fgets (buf, sizeof (buf) - 1, apop_file) != NULL)
{
tmp = strchr (buf, ':');
if (tmp == NULL)
continue;
*tmp++ = '\0';
fclose (apop_file);
if (strlen (password) == 0)
{
free (password);
return NULL;
}
if (strncmp (user, buf, strlen (user)))
continue;
return password;
strncpy (password, tmp, APOP_DIGEST);
/* strncpy () is lame and does not NULL terminate. */
password[APOP_DIGEST - 1] = '\0';
tmp = strchr (password, '\n');
if (tmp)
*tmp = '\0';
break;
}
fclose (apop_file);
if (*password == '\0')
{
free (password);
return NULL;
}
return password;
}
#endif /* WITH_BDB2 */
}
......@@ -129,8 +153,8 @@ pop3d_apop (const char *arg)
char buf[POP_MAXCMDLEN];
struct md5_ctx md5context;
unsigned char md5digest[16];
int i;
int status;
int lockit = 1;
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
......@@ -142,6 +166,7 @@ pop3d_apop (const char *arg)
if (strlen (username) > (POP_MAXCMDLEN - APOP_DIGEST))
{
free (username);
username = NULL;
return ERR_BAD_ARGS;
}
user_digest = pop3d_args (arg);
......@@ -150,6 +175,7 @@ pop3d_apop (const char *arg)
if (password == NULL)
{
free (username);
username = NULL;
free (user_digest);
return ERR_BAD_LOGIN;
}
......@@ -160,15 +186,19 @@ pop3d_apop (const char *arg)
free (password);
md5_finish_ctx (&md5context, md5digest);
tmp = buf;
for (i = 0; i < 16; i++, tmp += 2)
sprintf (tmp, "%02x", md5digest[i]);
{
int i;
tmp = buf;
for (i = 0; i < 16; i++, tmp += 2)
sprintf (tmp, "%02x", md5digest[i]);
}
*tmp++ = '\0';
if (strcmp (user_digest, buf))
{
free (username);
username = NULL;
free (user_digest);
return ERR_BAD_LOGIN;
}
......@@ -178,24 +208,20 @@ pop3d_apop (const char *arg)
if (pw == NULL)
{
free (username);
username = NULL;
return ERR_BAD_LOGIN;
}
/* Reset the uid. */
/* FIXME: How about the gid. */
if (setuid (pw->pw_uid) == -1)
{
free (username);
username = NULL;
return ERR_BAD_LOGIN;
}
if (mailbox_create_default (&mbox, username) != 0)
{
free (username);
state = AUTHORIZATION;
return ERR_UNKNOWN;
}
else if ((status = mailbox_open (mbox, MU_STREAM_RDWR)) != 0)
if ((status = mailbox_create_default (&mbox, username)) != 0
|| (status = mailbox_open (mbox, MU_STREAM_RDWR)) != 0)
{
mailbox_destroy (&mbox);
/* For non existent mailbox, we fake. */
......@@ -205,6 +231,7 @@ pop3d_apop (const char *arg)
|| mailbox_open (mbox, MU_STREAM_READ) != 0)
{
free (username);
username = NULL;
state = AUTHORIZATION;
return ERR_UNKNOWN;
}
......@@ -212,9 +239,21 @@ pop3d_apop (const char *arg)
else
{
free (username);
username = NULL;
state = AUTHORIZATION;
return ERR_MBOX_LOCK;
}
lockit = 0; /* Do not attempt to lock /dev/null ! */
}
if (lockit && pop3d_lock())
{
mailbox_close(mbox);
mailbox_destroy(&mbox);
state = AUTHORIZATION;
free (username);
username = NULL;
return ERR_MBOX_LOCK;
}
state = TRANSACTION;
......
......@@ -17,6 +17,15 @@
#include "pop3d.h"
/*
The CAPA Command
The POP3 CAPA command returns a list of capabilities supported by the
POP3 server. It is available in both the AUTHORIZATION and
TRANSACTION states.
Capabilities available in the AUTHORIZATION state MUST be announced
in both states. */
int
pop3d_capa (const char *arg)
{
......@@ -31,6 +40,10 @@ pop3d_capa (const char *arg)
fprintf (ofile, "USER\r\n");
fprintf (ofile, "UIDL\r\n");
fprintf (ofile, "RESP-CODES\r\n");
fprintf (ofile, "PIPELINING\r\n");
/* FIXME: This can be Implemented by setting an header field on the
message. */
/*fprintf (ofile, "EXPIRE NEVER\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");
......
......@@ -22,9 +22,9 @@
int
pop3d_dele (const char *arg)
{
size_t num = 0;
size_t num;
message_t msg;
attribute_t attr;
attribute_t attr = NULL;
if ((arg == NULL) || (strchr (arg, ' ') != NULL))
return ERR_BAD_ARGS;
......
......@@ -82,10 +82,11 @@ pop3d_cmd (const char *cmd)
/* This is called if GNU POP3 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
pop3d_abquit (int reason)
{
/* Unlock spool */
pop3d_unlock();
mailbox_close (mbox);
mailbox_destroy (&mbox);
......@@ -96,11 +97,6 @@ pop3d_abquit (int reason)
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");
......@@ -120,7 +116,7 @@ pop3d_abquit (int reason)
case ERR_MBOX_SYNC:
syslog (LOG_ERR, "Mailbox was updated by other party: %s", username);
fprintf (ofile, "-ERR Mailbox updated by other party or corrupt\r\n");
fprintf (ofile, "-ERR [OUT-SYNC] Mailbox updated by other party or corrupt\r\n");
break;
default:
......@@ -129,8 +125,6 @@ pop3d_abquit (int reason)
break;
}
if (ofile)
fflush (ofile);
closelog();
exit (1);
}
......@@ -149,8 +143,7 @@ pop3d_usage (char *argv0)
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 (" TIMEOUT default is 600 (10 minutes)\n");
printf (" -v, --version display version information and exit\n");
printf ("\nReport bugs to bug-mailutils@gnu.org\n");
exit (0);
......@@ -158,7 +151,7 @@ pop3d_usage (char *argv0)
/* Default signal handler to call the pop3d_abquit() function */
void
RETSIGTYPE
pop3d_signal (int signo)
{
(void)signo;
......@@ -167,43 +160,75 @@ pop3d_signal (int signo)
}
/* Gets a line of input from the client */
/* We can also implement PIPELINING by keeping a static buffer.
Implementing this cost an extra allocation with more uglier code.
Is it worth it? How many clients actually use PIPELINING?
*/
char *
pop3d_readline (int fd)
{
fd_set rfds;
struct timeval tv;
char buf[512], *ret = NULL;
int nread;
int total = 0;
int available;
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
do
static char *buffer = NULL; /* Note: This buffer is never free()d. */
static size_t total = 0;
char *nl;
char *line;
size_t len;
nl = memchr (buffer, '\n', total);
if (!nl)
{
if (timeout > 0)
/* Need to refill the buffer. */
do
{
available = select (fd + 1, &rfds, NULL, NULL, &tv);
if (!available)
pop3d_abquit (ERR_TIMEOUT);
char buf[512];
int nread;
if (timeout)
{
int available;
fd_set rfds;
struct timeval tv;
FD_ZERO (&rfds);
FD_SET (fd, &rfds);
tv.tv_sec = timeout;
tv.tv_usec = 0;
available = select (fd + 1, &rfds, NULL, NULL, &tv);
if (!available)
pop3d_abquit (ERR_TIMEOUT);
else if (available == -1)
{
if (errno == EINTR)
continue;
pop3d_abquit (ERR_NO_OFILE);
}
}
errno = 0;
nread = read (fd, buf, sizeof (buf) - 1);
if (nread < 1)
{
if (errno == EINTR)
continue;
pop3d_abquit (ERR_NO_OFILE);
}
buf[nread] = '\0';
buffer = realloc (buffer, (total + nread + 1) * sizeof (*buffer));
if (buffer == NULL)
pop3d_abquit (ERR_NO_MEM);
memcpy (buffer + total, buf, nread + 1); /* copy the null too. */
total += nread;
}
nread = read (fd, buf, sizeof (buf) - 1);
if (nread < 1)
pop3d_abquit (ERR_DEAD_SOCK);
buf[nread] = '\0';
ret = realloc (ret, (total + nread + 1) * sizeof (char));
if (ret == NULL)
pop3d_abquit (ERR_NO_MEM);
memcpy (ret + total, buf, nread + 1);
total += nread;
while ((nl = memchr (buffer, '\n', total)) == NULL);
}
while (memchr (buf, '\n', nread) == NULL);
return ret;
nl++;
len = nl - buffer;
line = calloc (len + 1, sizeof (*line));
memcpy (line, buffer, len); /* copy the newline too. */
line[len] = '\0';
total -= len;
memmove (buffer, nl, total);
return line;
}
......
......@@ -23,10 +23,10 @@ int
pop3d_list (const char *arg)
{
size_t mesgno;
message_t msg = NULL;
attribute_t attr = NULL;
size_t size = 0;
size_t lines = 0;
message_t msg;
attribute_t attr;
if (state != TRANSACTION)
return ERR_WRONG_STATE;
......
......@@ -17,24 +17,15 @@
#include "pop3d.h"
/* Save some line space. */
typedef struct sockaddr_in SA;
/* Declared in <pop3d.h>. */
mailbox_t mbox;
unsigned int port;
unsigned int timeout;
size_t timeout;
int state;
char *username;
int ifile;
FILE *ofile;
time_t curr_time;
char *md5shared;
volatile unsigned int children;
/* Number of child processes. */
unsigned int children = 0;
volatile size_t children;
static struct option long_options[] =
{
......@@ -51,17 +42,22 @@ const char *short_options ="d::hip:t:v";
static int syslog_error_printer __P ((const char *fmt, va_list ap));
#ifndef DEFMAXCHILDREN
# define DEFMAXCHILDREN 10 /* Default maximum number of children */
#endif
int
main (int argc, char **argv)
{
struct group *gr;
static int mode = INTERACTIVE;
size_t maxchildren = 20;
size_t maxchildren = DEFMAXCHILDREN;
int c = 0;
int status = OK;
unsigned int port;
port = 110; /* Default POP3 port. */
timeout = 0; /* Default timeout of 0. */
timeout = 600; /* Default timeout of 600. */
while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
!= -1)
......@@ -70,9 +66,10 @@ main (int argc, char **argv)
{
case 'd':
mode = DAEMON;
maxchildren = optarg ? strtoul (optarg, NULL, 10) : 10;
if (maxchildren <= 0)
maxchildren = 10;
if (optarg)
maxchildren = strtoul (optarg, NULL, 10);
if (maxchildren == 0)
maxchildren = DEFMAXCHILDREN;
break;
case 'h':
......@@ -106,13 +103,13 @@ main (int argc, char **argv)
gr = getgrnam ("mail");
if (gr == NULL)
{
perror ("Error getting group");
perror ("Error getting mail group");
exit (1);
}
if (setgid (gr->gr_gid) == -1)
{
perror ("Error setting group");
perror ("Error setting mail group");
exit (1);
}
......@@ -134,25 +131,25 @@ main (int argc, char **argv)
signal (SIGTERM, pop3d_signal);
signal (SIGSTOP, pop3d_signal);
signal (SIGPIPE, pop3d_signal);
if (timeout < 600) /* RFC 1939 says no less than 10 minutes. */
timeout = 0; /* So we'll turn it off. */
signal (SIGABRT, pop3d_signal);
if (mode == DAEMON)
pop3d_daemon_init ();
/* Change directory. */
/* Make sure that to be in the root directory. */
chdir ("/");
/* Set up for syslog. */
openlog ("gnu-pop3d", LOG_PID, LOG_FACILITY);
mu_error_set_print(syslog_error_printer);
/* Redirect any stdout error from the library to syslog, they
should not go to the client. */
mu_error_set_print (syslog_error_printer);
umask (S_IROTH | S_IWOTH | S_IXOTH); /* 007 */
/* Actually run the daemon. */
if (mode == DAEMON)
pop3d_daemon (maxchildren);
pop3d_daemon (maxchildren, port);
/* exit (0) -- no way out of daemon except a signal. */
else
status = pop3d_mainloop (fileno (stdin), fileno (stdout));
......@@ -167,8 +164,6 @@ void
pop3d_daemon_init (void)
{
pid_t pid;
unsigned int i;
#define MAXFD 64
pid = fork ();
if (pid == -1)
......@@ -183,6 +178,8 @@ pop3d_daemon_init (void)
signal (SIGHUP, SIG_IGN); /* Ignore SIGHUP. */
/* The second fork is to guarantee that the daemon cannot acquire a
controlling terminal. */
pid = fork ();
if (pid == -1)
{
......@@ -193,9 +190,18 @@ pop3d_daemon_init (void)
exit (0); /* Parent exits. */
/* Close inherited file descriptors. */
for (i = 0; i < MAXFD; ++i)
close (i);
{
size_t i;
#if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
size_t fdlimit = sysconf(_SC_OPEN_MAX);
#else
size_t fdlimit = 64;
#endif
for (i = 0; i < fdlimit; ++i)
close (i);
}
/* SIGCHLD is not ignore but rather use to do some simple load balancing. */
#ifdef HAVE_SIGACTION
{
struct sigaction act;
......@@ -211,23 +217,21 @@ pop3d_daemon_init (void)
/* 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
pop3d_mainloop (int infile, int outfile)
{
int status = OK;
char *buf, *arg, *cmd;
struct hostent *htbuf;
char *local_hostname;
/* Reset hup to exit. */
signal (SIGHUP, pop3d_signal);
ifile = infile;
ofile = fdopen (outfile, "w");
if (ofile == NULL)
pop3d_abquit (ERR_NO_OFILE);
state = AUTHORIZATION;
curr_time = time (NULL);
/* FIXME: Retreive hostname with getpeername() and log. */
syslog (LOG_INFO, "Incoming connection opened");
/* log information on the connecting client */
......@@ -242,46 +246,61 @@ pop3d_mainloop (int infile, int outfile)
}
/* Prepare the shared secret for APOP. */
local_hostname = malloc (MAXHOSTNAMELEN + 1);
if (local_hostname == NULL)
pop3d_abquit (ERR_NO_MEM);
{
char *local_hostname;
local_hostname = malloc (MAXHOSTNAMELEN + 1);
if (local_hostname == NULL)
pop3d_abquit (ERR_NO_MEM);
gethostname (local_hostname, MAXHOSTNAMELEN);
htbuf = gethostbyname (local_hostname);
if (htbuf)
/* Get our canonical hostname. */
{
free (local_hostname);
local_hostname = strdup (htbuf->h_name);
struct hostent *htbuf;
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)
pop3d_abquit (ERR_NO_MEM);
md5shared = malloc (strlen (local_hostname) + 51);
if (md5shared == NULL)
pop3d_abquit (ERR_NO_MEM);
snprintf (md5shared, strlen (local_hostname) + 50, "<%u.%u@%s>", getpid (),
(int)time (NULL), local_hostname);
free (local_hostname);
snprintf (md5shared, strlen (local_hostname) + 50, "<%u.%u@%s>", getpid (),
(unsigned)time (NULL), local_hostname);
free (local_hostname);
}
/* Lets boogie. */
fprintf (ofile, "+OK POP3 Ready %s\r\n", md5shared);
while (state != UPDATE)
{
char *buf, *arg, *cmd;
fflush (ofile);
status = OK;
buf = pop3d_readline (ifile);
cmd = pop3d_cmd (buf);
arg = pop3d_args (buf);
/* The mailbox size needs to be check to make sure that we are in
sync. Some other applications may not respect the *.lock or
the lock may be stale because downloading on slow modem.
We rely on the size of the mailbox for the check and bail if out
of sync. */
if (state == TRANSACTION && !mailbox_is_updated (mbox))
{
static off_t mailbox_size;
off_t newsize = 0;
mailbox_get_size (mbox, &newsize);
/* Did we shrink? */
/* Did we shrink? First time save the size. */
if (!mailbox_size)
mailbox_size = newsize;
else if (newsize < mailbox_size)
pop3d_abquit (ERR_MBOX_SYNC);
else if (newsize < mailbox_size) /* FIXME: Should it be a != ? */
pop3d_abquit (ERR_MBOX_SYNC); /* Out of sync, Bail out. */
}
if (strlen (arg) > POP_MAXCMDLEN || strlen (cmd) > POP_MAXCMDLEN)
......@@ -318,7 +337,7 @@ pop3d_mainloop (int infile, int outfile)
status = ERR_BAD_CMD;
if (status == OK)
fflush (ofile);
; /* Everything is good. */
else if (status == ERR_WRONG_STATE)
fprintf (ofile, "-ERR " BAD_STATE "\r\n");
else if (status == ERR_BAD_ARGS)
......@@ -347,7 +366,6 @@ pop3d_mainloop (int infile, int outfile)
free (arg);
}
fflush (ofile);
return (status != OK);
}
......@@ -355,11 +373,10 @@ pop3d_mainloop (int infile, int outfile)
(default 110) then executes a pop3d_mainloop() upon accepting a connection.
It starts maxchildren child processes to listen to and accept socket
connections. */
void
pop3d_daemon (unsigned int maxchildren)
pop3d_daemon (unsigned int maxchildren, unsigned int port)
{
SA server, client;
struct sockaddr_in server, client;
pid_t pid;
int listenfd, connfd;
size_t size;
......@@ -394,7 +411,7 @@ pop3d_daemon (unsigned int maxchildren)
{
if (children > maxchildren)
{
syslog (LOG_ERR, "too many children");
syslog (LOG_ERR, "too many children (%d)", children);
pause ();
continue;
}
......
......@@ -151,13 +151,12 @@
#define ERR_MBOX_LOCK 8
#define ERR_TOO_LONG 9
#define ERR_NO_MEM 10
#define ERR_DEAD_SOCK 11
#define ERR_SIGNAL 12
#define ERR_FILE 13
#define ERR_NO_OFILE 14
#define ERR_TIMEOUT 15
#define ERR_UNKNOWN 16
#define ERR_MBOX_SYNC 17
#define ERR_SIGNAL 11
#define ERR_FILE 12
#define ERR_NO_OFILE 13
#define ERR_TIMEOUT 14
#define ERR_UNKNOWN 15
#define ERR_MBOX_SYNC 16
#ifndef __P
# ifdef __STDC__
......@@ -169,40 +168,39 @@
extern mailbox_t mbox;
extern unsigned int port;
extern unsigned int timeout;
extern int state;
extern char *username;
extern int ifile;
extern FILE *ofile;
extern time_t curr_time;
extern char *md5shared;
extern unsigned int children;
extern int pop3d_dele __P ((const char *arg));
extern int pop3d_list __P ((const char *arg));
extern int pop3d_noop __P ((const char *arg));
extern int pop3d_quit __P ((const char *arg));
extern int pop3d_retr __P ((const char *arg));
extern int pop3d_rset __P ((const char *arg));
extern int pop3d_stat __P ((const char *arg));
extern int pop3d_top __P ((const char *arg));
extern int pop3d_uidl __P ((const char *arg));
extern int pop3d_user __P ((const char *arg));
extern int pop3d_apop __P ((const char *arg));
extern int pop3d_auth __P ((const char *arg));
extern int pop3d_capa __P ((const char *arg));
extern char *pop3d_args __P ((const char *cmd));
extern char *pop3d_cmd __P ((const char *cmd));
extern int pop3d_abquit __P ((int reason));
extern int pop3d_lock __P ((void));
extern int pop3d_unlock __P ((void));
extern int pop3d_mainloop __P ((int infile, int outfile));
extern void pop3d_daemon __P ((unsigned int maxchildren));
extern void pop3d_usage __P ((char *argv0));
extern void pop3d_signal __P ((int));
extern void pop3d_sigchld __P ((int));
extern void pop3d_daemon_init __P ((void));
extern char *pop3d_apopuser __P ((const char *user));
extern char *pop3d_readline __P ((int fd));
extern volatile size_t children;
extern int pop3d_dele __P ((const char *));
extern int pop3d_list __P ((const char *));
extern int pop3d_noop __P ((const char *));
extern int pop3d_quit __P ((const char *));
extern int pop3d_retr __P ((const char *));
extern int pop3d_rset __P ((const char *));
extern int pop3d_stat __P ((const char *));
extern int pop3d_top __P ((const char *));
extern int pop3d_uidl __P ((const char *));
extern int pop3d_user __P ((const char *));
extern int pop3d_apop __P ((const char *));
extern int pop3d_auth __P ((const char *));
extern int pop3d_capa __P ((const char *));
extern char *pop3d_args __P ((const char *));
extern char *pop3d_cmd __P ((const char *));
extern int pop3d_abquit __P ((int));
extern int pop3d_lock __P ((void));
extern int pop3d_touchlock __P ((void));
extern int pop3d_unlock __P ((void));
extern int pop3d_mainloop __P ((int, int));
extern void pop3d_daemon __P ((size_t, unsigned int));
extern void pop3d_usage __P ((char *));
extern RETSIGTYPE pop3d_signal __P ((int));
extern RETSIGTYPE pop3d_sigchld __P ((int));
extern void pop3d_daemon_init __P ((void));
extern char *pop3d_apopuser __P ((const char *));
extern char *pop3d_readline __P ((int));
#endif /* _POP3D_H */
......
......@@ -32,6 +32,7 @@ pop3d_quit (const char *arg)
if (state == TRANSACTION)
{
pop3d_unlock ();
if (mailbox_expunge (mbox) != 0)
err = ERR_FILE;
if (mailbox_close (mbox) != 0)
......
......@@ -25,9 +25,9 @@ pop3d_retr (const char *arg)
size_t mesgno, n;
char *buf;
size_t buflen = BUFFERSIZE;
message_t msg;
attribute_t attr;
stream_t stream;
message_t msg = NULL;
attribute_t attr = NULL;
stream_t stream = NULL;
off_t off;
if ((strlen (arg) == 0) || (strchr (arg, ' ') != NULL))
......
......@@ -35,8 +35,8 @@ pop3d_rset (const char *arg)
for (i = 1; i <= total; i++)
{
message_t msg;
attribute_t attr;
message_t msg = NULL;
attribute_t attr = NULL;
mailbox_get_message (mbox, i, &msg);
message_get_attribute (msg, &attr);
if (attribute_is_deleted (attr))
......
......@@ -18,21 +18,17 @@
#include "pop3d.h"
void
RETSIGTYPE
pop3d_sigchld (int signo)
{
pid_t pid;
int status;
int old_errno = errno ;
(void)signo;
errno = 0;
while ( (pid = waitpid(-1, &status, WNOHANG)) > 0)
--children;
#ifndef HAVE_SIGACTION
/* On some system, signal implements the unreliabe sematic and
/* On some system, signal implements the unreliable semantic and
has to be rearm. */
signal (SIGCHLD, pop3d_sigchld);
signal (signo, pop3d_sigchld);
#endif
errno = old_errno;
}
......
......@@ -28,8 +28,8 @@ pop3d_stat (const char *arg)
size_t total = 0;
size_t num = 0;
size_t tsize = 0;
message_t msg;
attribute_t attr;
message_t msg = NULL;
attribute_t attr = NULL;
if (strlen (arg) != 0)
return ERR_BAD_ARGS;
......@@ -45,6 +45,8 @@ pop3d_stat (const char *arg)
{
mailbox_get_message (mbox, mesgno, &msg);
message_get_attribute (msg, &attr);
/* rfc1939: Note that messages marked as deleted are not counted in
either total. */
if (!attribute_is_deleted (attr))
{
message_size (msg, &size);
......@@ -53,8 +55,6 @@ pop3d_stat (const char *arg)
num++;
}
}
/* rfc1939: Note that messages marked as deleted are not counted in either
total. */
fprintf (ofile, "+OK %d %d\r\n", num, tsize);
return OK;
......
......@@ -82,10 +82,7 @@ pop3d_user (const char *arg)
char *buf, pass[POP_MAXCMDLEN], *tmp, *cmd;
struct passwd *pw;
int status;
#ifdef USE_LIBPAM
pam_handle_t *pamh;
int pamerror;
#endif /* !USE_LIBPAM */
int lockit = 1;
if (state != AUTHORIZATION)
return ERR_WRONG_STATE;
......@@ -110,6 +107,8 @@ pop3d_user (const char *arg)
else
{
strncpy (pass, tmp, POP_MAXCMDLEN);
/* strncpy () is lame, make sure the string is null terminated. */
pass[POP_MAXCMDLEN - 1] = '\0';
free (tmp);
}
......@@ -151,35 +150,34 @@ pop3d_user (const char *arg)
}
}
#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_errlab:
pam_end (pamh, PAM_SUCCESS);
openlog ("gnu-pop3d", LOG_PID, LOG_FACILITY);
if (pamerror != PAM_SUCCESS)
{
syslog (LOG_INFO, "User '%s': authentication failed", _user);
return ERR_BAD_LOGIN;
}
{
pam_handle_t *pamh;
int pamerror;
_user = (char *) arg;
_pwd = pass;
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_errlab:
pam_end (pamh, PAM_SUCCESS);
if (pamerror != PAM_SUCCESS)
{
syslog (LOG_INFO, "User '%s': authentication failed", _user);
return ERR_BAD_LOGIN;
}
}
#endif /* USE_LIBPAM */
if (pw != NULL && pw->pw_uid > 1)
setuid (pw->pw_uid);
if (mailbox_create_default (&mbox, arg) != 0)
{
state = AUTHORIZATION;
return ERR_UNKNOWN;
}
else if ((status = mailbox_open (mbox, MU_STREAM_RDWR)) != 0)
if ((status = mailbox_create_default (&mbox, arg) != 0)
|| (status = mailbox_open (mbox, MU_STREAM_RDWR) != 0))
{
mailbox_destroy (&mbox);
/* For non existent mailbox, we fake. */
......@@ -197,6 +195,16 @@ pam_errlab:
state = AUTHORIZATION;
return ERR_MBOX_LOCK;
}
lockit = 0; /* Do not attempt to lock /dev/null ! */
}
if (lockit && pop3d_lock())
{
mailbox_close(mbox);
mailbox_destroy(&mbox);
state = AUTHORIZATION;
free (cmd);
return ERR_MBOX_LOCK;
}
username = strdup (arg);
......@@ -204,16 +212,16 @@ pam_errlab:
pop3d_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);
/* mailbox name */
/* mailbox name */
{
url_t url = NULL;
size_t total = 0;
mailbox_get_url (mbox, &url);
syslog (LOG_INFO, "User '%s' logged in with mailbox '%s'",
username, url_to_string (url));
mailbox_messages_count (mbox, &total);
syslog (LOG_INFO, "User '%s' logged in with mailbox '%s' (%d msgs)",
username, url_to_string (url), total);
}
return OK;
}
......