/*****************************************************************************
POPular -- A POP3 server and proxy for large mail systems
$Id: popular.h,v 1.60 2002/11/28 13:56:03 sqrt Exp $
http://www.remote.org/jochen/mail/popular/
******************************************************************************
Copyright (C) 1999-2002 Jochen Topf <jochen@remote.org>
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 of the License, 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*****************************************************************************/
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#ifdef USE_TLS
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/rand.h>
#endif
#ifdef USE_READLINE
# include <readline/readline.h>
# include <readline/history.h>
#endif
#ifndef HAVE_STRLCAT
# include "../lib/strl.h"
#endif
#ifdef HAVE_GETOPT
# include <getopt.h>
#else
# include "../lib/getopt.h"
#endif
#include "pconfig.h"
extern int debug;
#define PP_FLAGS_M 1
#define max(a,b) ((a) > (b) ? (a) : (b))
#define min(a,b) ((a) < (b) ? (a) : (b))
/*****************************************************************************
Results of a mail check from pcheckd.
*****************************************************************************/
typedef enum {
mcrMail = 0,
mcrEmpty = 1,
mcrTimeout = 2,
mcrLoadTooHigh = 3,
mcrMaxSession = 4,
mcrError = -1
} mailcheck_result_t;
/*****************************************************************************
The different types of config parameters.
*****************************************************************************/
typedef enum {
ctNone = 0, /* end-of-list designator */
ctInt, /* integer value */
ctStr, /* string */
ctFile, /* file name */
ctDir, /* directory name */
ctId, /* some kind of id */
ctBool, /* boolean (0=no=off=false, 1=yes=on=true) */
ctTime, /* a time interval (ie. 10h3m4s) */
ctIgn /* unsupported in this configuration */
} config_type_t;
/*****************************************************************************
Format of a mail.
*****************************************************************************/
typedef enum {
mfLF = 0, /* linefeed on end-of-line */
mfCRLF, /* carriage return + linefeed on end-of-line */
mfNET, /* like mfCRLF plus dot stuffing */
} mail_format_t;
/*****************************************************************************
These are the different kinds of protocols that the POPular proxy
supports (or might at some point support).
*****************************************************************************/
typedef enum {
ptPOP3 = 0, /* POP3 (RFC 1939) */
ptIMAP4, /* IMAP4 */
ptXPOP, /* XPOP (see POPular documentation) */
ptCXPOP, /* Check and XPOP (see POPular doc) */
ptPOP3TLS, /* POP3 over TLS */
ptIMAP4TLS, /* IMAP4 over TLS */
ptPOP3STLS, /* POP3 with STLS */
} protocol_t;
struct protocol_info {
protocol_t type; /* type (see above) */
char *name; /* descriptive name */
int tls; /* does this protocol use TLS? */
int port; /* default port for this protocol */
int support_client_side; /* protocol supported on client connection */
int support_backend_side; /* protocol supported on backend connection */
};
/*****************************************************************************
Different kind of states a proxy or server session can be in.
*****************************************************************************/
typedef enum {
sstFree = 0, /* proxy and backend: slot free */
sstNew, /* proxy and backend: new connection */
sstIdle, /* backend: idle */
sstRead, /* backend: reading mail */
sstDone, /* proxy: closing down */
sstAuthPhase, /* proxy: authenticating user */
sstVirtServDisabled, /* proxy: virt server is disabled */
sstVirtServFake, /* proxy: virt server is to be faked */
sstCheck, /* proxy: checking for mails in mailbox */
sstConnecting, /* proxy: connecting to backend */
sstBackendUnreachable, /* proxy: backend unreachable */
sstBackendDisabled, /* proxy: backend disabled */
sstBackendFake, /* proxy: backend is to be faked */
sstProxy, /* proxy: transfering data back and forth */
sstMailboxEmpty, /* proxy: mailbox is empty */
sstUnknownBackend, /* proxy: unknown backend */
sstConnQuit, /* backend: connection properly closed */
sstConnBroken, /* backend: connection not properly closed */
} session_state_t;
struct session_state_info {
session_state_t type; /* type (see above) */
char *name; /* descriptive name */
};
/*****************************************************************************
States a virtual server can be in.
*****************************************************************************/
typedef enum {
vsstFree = 0, /* this virtual server slot is unused */
vsstOffline, /* virtual server doesn't listen on port */
vsstDisabled, /* server listens, but sends error msg on */
/* connect */
vsstFake, /* server listens, all connections are faked */
vsstOnline /* virtual server is online */
} virt_serv_state_t;
struct virt_serv_state_info {
virt_serv_state_t type; /* type (see above) */
char *name; /* descriptive name */
int listen; /* listen on port in this state ? */
};
/*****************************************************************************
States a backend can be in.
*****************************************************************************/
typedef enum {
bstFree = 0, /* this backend slot is unused */
bstOffline, /* backend is offline, send error msg */
bstFake, /* backend is offline, fake connection */
bstOnline /* backend is online */
} backend_state_t;
struct backend_state_info {
backend_state_t type; /* type (see above) */
char *name; /* descriptive name */
};
/*****************************************************************************
Capability types for virtual servers.
*****************************************************************************/
typedef enum {
capa_error,
capa_none,
capa_default,
capa_user
} capa_t;
/*****************************************************************************
STARTTLS types for virtual servers.
*****************************************************************************/
typedef enum {
starttls_off,
starttls_optional,
starttls_force
} starttls_t;
/*****************************************************************************
Description of a virtual server.
*****************************************************************************/
struct virt_serv {
char id[MAXLEN_ID+1];
protocol_t prot;
struct sockaddr_in local_addr;
char namespace[MAXLEN_ID+1];
virt_serv_state_t state;
capa_t capa_type;
starttls_t starttls_type;
struct capa *capa_ptr;
char banner_ok[MAXLEN_BANNER+1];
char banner_err[MAXLEN_BANNER+1];
int fd; /* file descriptor for listen */
#if USE_TLS
SSL_CTX *ssl_ctx;
#endif
};
/*****************************************************************************
Description of a backend.
*****************************************************************************/
struct backend {
char id[MAXLEN_ID+1];
protocol_t prot;
struct sockaddr_in backend_addr;
backend_state_t state;
};
/*****************************************************************************
struct proxy_session
*****************************************************************************/
struct proxy_session {
session_state_t state; /* state of this session */
pid_t pid; /* process id of child process
handling this session */
time_t starttime; /* start time of this session */
time_t statetime; /* time when the server switched
into the current state */
long mailcheck_time; /* time in usecs for mail check */
int mailcheck_retry; /* number of retries for mail check */
struct sockaddr_in sin_client_remote; /* remote side of conn. to client */
struct sockaddr_in sin_client_local; /* local side of conn. to client */
struct sockaddr_in sin_backend_remote; /* remote side of conn. to backend */
struct sockaddr_in sin_backend_local; /* local side of conn. to backend */
int fd_client; /* file descriptor to client */
struct io_ctx *ioc_client; /* IO context to client */
struct io_ctx *ioc_backend; /* IO context to backend */
struct virt_serv vs; /* virtual server for this session */
struct backend backend; /* backend for this session */
char namespace[MAXLEN_ID+1]; /* namespace for this session */
char username[MAXLEN_USERNAME+1]; /* username sent by client */
char password[MAXLEN_PASSWORD+1]; /* password sent by client */
char mailbox[MAXLEN_MAILBOX+1]; /* name of mailbox for backend */
char id[MAXLEN_SESSION_ID+1]; /* session id */
unsigned long bytesin; /* bytes from client to backend */
unsigned long bytesout; /* bytes from backend to client */
};
/*****************************************************************************
struct backend_session
*****************************************************************************/
struct backend_session {
session_state_t state; /* state of this session */
pid_t pid; /* process id of child process
handling this session */
time_t starttime; /* start time */
time_t statetime; /* time when the server switched
into the current state */
struct sockaddr_in sin_proxy; /* remote side of conn. to proxy */
char username[MAXLEN_USERNAME+1]; /* username sent by client */
char mailbox[MAXLEN_MAILBOX+1]; /* name of mailbox for backend */
char id[MAXLEN_SESSION_ID+1]; /* session id */
char flags[MAXLEN_FLAGS+1]; /* flags for this session */
unsigned long msgnum; /* number of mails in mailbox */
unsigned long msgnew; /* number of new mails in mailbox */
unsigned long msgread; /* number of messages read */
unsigned long msgdel; /* number of messages deleted */
};
/*****************************************************************************
struct capa
*****************************************************************************/
struct capa {
struct capa *next; /* next capa struct in linked list */
char name[MAXLEN_ID+1]; /* name of this capability list */
char text[MAXLEN_CAPA+1]; /* text of capabilities */
};
struct pserv_capa {
capa_t capa_type;
char name[MAXLEN_ID+1]; /* name of this capability list */
char text[MAXLEN_CAPA+1]; /* text of capabilities */
};
/*****************************************************************************
*****************************************************************************/
struct auth_request {
char *user;
char *pass;
char *peer;
char *namespace;
};
struct auth_result_data {
int flags;
char backend[MAXLEN_ID];
char user[MAXLEN_USERNAME];
char pass[MAXLEN_PASSWORD];
};
/*****************************************************************************
struct configdesc
*****************************************************************************/
struct configdesc {
char *tag;
int readwrite;
config_type_t type;
void *ptr;
int min, max, def;
char *defstr;
};
/*****************************************************************************
struct pproxyconfig
All the config options for the pop proxy are saved in here.
*****************************************************************************/
struct pproxyconfig {
int allowsslv2;
int authtimeout;
int backlog;
char capadir[MAX_FILE_LEN];
int checkport;
int checktimeout;
char defaultns[MAXLEN_ID+1];
char fallback[MAXLEN_ID+1];
char id[20];
int idletimeout;
char logfile[80];
int maxlocalload;
int maxsession;
char pdmdir[MAX_FILE_LEN];
pid_t pid;
int proxytimeout;
char rundir[MAX_FILE_LEN];
int sessionlimit;
int sessiontimeout;
char sidprefix[32];
char tlsdir[MAX_FILE_LEN];
char version[20];
};
/*****************************************************************************
struct pservconfig
All the config options for the pop server are saved in here.
*****************************************************************************/
struct pservconfig {
int backlog;
char capadir[MAX_FILE_LEN];
char id[20];
int idletimeout;
char localip[16];
int logeachmsg;
char logfile[80];
int maxlocalload;
int maxsession;
pid_t pid;
char popdir[MAX_FILE_LEN];
char rundir[MAX_FILE_LEN];
int servport;
int sessionlimit;
int sessiontimeout;
int statusheader;
char version[20];
};
/*****************************************************************************
struct shmem_desc
*****************************************************************************/
struct shmem_desc {
char magic[8]; /* magic 'POPULAR\0' */
char type[8]; /* type 'PROXY\0' oder 'SERVER\0' */
int version;
long starttime;
};
/*****************************************************************************
struct shmem_proxy_stat
*****************************************************************************/
struct shmem_proxy_stat {
unsigned long connections; /* number of client connections */
unsigned long bytesin; /* bytes from client to backend */
unsigned long bytesout; /* bytes from backend to client */
unsigned long mailcheck_time; /* accumulated time for all mail checks */
unsigned long mailcheck_retry[MAILCHECK_MAX_REQUESTS+1];
};
/*****************************************************************************
struct shmem_proxy
*****************************************************************************/
struct shmem_proxy {
char magic[8]; /* magic string 'POPULAR\0' */
char type[8]; /* magic string 'PROXY\0\0\0' */
int version;
long starttime;
int max_virt_serv;
int max_backend;
int max_sessions, n_sessions, used_sessions;
struct shmem_proxy_stat stat;
struct proxy_session session[MAX_SESSION];
};
/*****************************************************************************
struct shmem_backend_stat
*****************************************************************************/
struct shmem_backend_stat {
unsigned long connections; /* number of connections from proxy */
unsigned long bytesin; /* bytes from proxy to backend */
unsigned long bytesout; /* bytes from backend to proxy */
unsigned long msgread; /* number of messages read */
unsigned long msgdel; /* number of messages deleted */
unsigned long connquit; /* number of properly closed connections */
unsigned long connbroken; /* number of not properly closed connections */
};
/*****************************************************************************
struct shmem_backend
*****************************************************************************/
struct shmem_backend {
char magic[8]; /* magic string 'POPULAR\0' */
char type[8]; /* magic string 'SERVER\0\0' */
int version;
long starttime;
struct pservconfig conf;
struct shmem_backend_stat stat;
int max_sessions, n_sessions, used_sessions;
struct backend_session session[MAX_SESSION];
};
/*****************************************************************************
for shutdown
*****************************************************************************/
#define SHUTDOWN_SERVER 1
#define SHUTDOWN_CHILDREN 2
#define SHUTDOWN_DELAYED 4
/*****************************************************************************
for debug
*****************************************************************************/
#define DG_MAIN 0x0001
#define DG_AUTH 0x0002
#define DG_PASS 0x0004
#define DG_POP 0x0008
#define DG_CTRL 0x0010
#define DG_NET 0x0020
#define DG_RINGD 0x0040
#define DG_TLS 0x0080
#define DG_IO 0x0100
#define DG_ALL 0x01ff
struct debug_info {
int type;
char *name;
};
/*****************************************************************************
Debugging Macros
Use like this:
DEBUG0(DG_MISC, "main", "misc");
DEBUGX(DG_NET, "main", "net %d", 1);
DEBUGX(DG_AUTH, "main", "auth %d %s", 1, "xx");
*****************************************************************************/
#define DEBUG0(type, func, text) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__); \
} while (0)
/* this isn't supported by older gccs :-(
#define DEBUGX(type, func, text, ...) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, __VA_ARGS__); \
} while (0)
*/
#define DEBUG1(type, func, text, a1) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1)); \
} while (0)
#define DEBUG2(type, func, text, a1, a2) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2)); \
} while (0)
#define DEBUG3(type, func, text, a1, a2, a3) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3)); \
} while (0)
#define DEBUG4(type, func, text, a1, a2, a3, a4) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4)); \
} while (0)
#define DEBUG5(type, func, text, a1, a2, a3, a4, a5) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4), (a5)); \
} while (0)
#define DEBUG6(type, func, text, a1, a2, a3, a4, a5, a6) \
if (debug & (type)) do { \
xlog_printf(xlog_dbg, 0x0000, #type ":" func ":" __FILE__ ":%d " text, __LINE__, (a1), (a2), (a3), (a4), (a5), (a6)); \
} while (0)
/*****************************************************************************
*****************************************************************************/
#include "util.h"
#include "io.h"
#include "info.h"
#include "pdm.h"
#include "pop3.h"
#include "xlog.h"
#include "sig.h"
#include "uds.h"
#include "mailbox.h"
#include "smtp_after_pop.h"
/** THE END *****************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1