#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include "tcp_listen.h"
#include "signal.h"
#include "ssl.h"
#include "strlcpy.h"
static char * port = NULL;
static int become_daemon = 0;
const char * pidfile = "/var/run/akpop3d.pid";
const char * ssl_certfile = "/etc/akpop3d/cert.pem";
const char * ssl_keyfile = "/etc/akpop3d/key.pem";
const char * authfile = NULL;
const char * local_mbox = NULL;
const char * tmp_dir = "/tmp";
char * mailspool = "/var/mail/";
int use_pop3_allow_deny = 0;
int enable_mysql = 0;
unsigned int timeout = 30;
/* mysql pointers */
extern char *HOSTNAME;
extern char *USERNAME;
extern char *PASSWORD;
extern char *DATABASE;
extern char *TABLE;
int daemonize(void);
void pop3_session(int fd);
static void delete_pid(void);
static void sig_chld(int signo) {
pid_t pid;
int stat;
while ((pid = waitpid(-1,&stat,WNOHANG)) > 0);
}
static void sig_term(int signo) {
if (become_daemon) delete_pid();
exit(0);
}
static void usage(char * argv0) {
printf("Usage: %s [OPTIONS]\n", argv0);
printf("Start a POP3 daemon.\n"
"\n"
" -d run as a daemon (in the background)\n"
" -f <pidfile> store process ID in <pidfile> (must be a full path)\n"
" -s use SSL for all connections\n"
" -c <certfile> use <certfile> for SSL certificate [%s]\n"
" -k <keyfile> use <keyfile> for SSL RSA key [%s]\n"
" -p <port> listen on <port> [default: 110, or 995 if SSL]\n",
ssl_certfile, ssl_keyfile
);
printf(
" -l <address> listen on <address> [default: any]\n"
" -a <authfile> use text file <authfile> for authentication\n"
" -m <spooldir> use directory <spooldir> as mail spool\n"
" -D use /etc/pop3.{allow,deny} files\n"
" -L <mbox> use ~/<mbox> as mail spool\n"
" -t <timeout> use <timeout> seconds as r/w timeout\n"
#ifdef HAVE_LIBMYSQLCLIENT
" -M enable MySQL support\n"
" -H <mysqlhost> MySQL support: connect to <mysqlhost>\n"
" -U <mysqluser> MySQL support: use username <mysqluser>\n"
" -P <mysqlpass> MySQL support: use password <mysqlpass>\n"
" -I <mysqldb> MySQL support: use database <mysqldb>\n"
" -T <mysqltbl> MySQL support: use table <mysqltbl>\n"
#endif /* HAVE_LIBMYSQLCLIENT */
"\n"
"Use `%s -v' to show the program version.\n",
argv0
);
exit(EXIT_SUCCESS);
}
static void write_pid(void) {
FILE * f = fopen(pidfile,"w+");
if (f) {
fprintf(f,"%u",getpid());
fclose(f);
}
/* ignore errors */
}
static void delete_pid(void) {
unlink(pidfile);
}
int main(int argc, char * argv[]) {
int listenfd, connfd;
pid_t childpid;
struct stat sbuf;
socklen_t addrlen;
#ifdef HAVE_LIBMYSQLCLIENT
const char * optstring = "df:sp:c:k:l:a:m:hvDL:MH:U:P:I:T:t:x:";
int len = 0;
#else
const char * optstring = "df:sp:c:k:l:a:m:hvDL:t:x:";
#endif
char * listenhost = NULL;
char * progname;
int c;
socklen_t clen;
struct sockaddr_in client;
#ifdef HAVE_LIBMYSQLCLIENT
struct rlimit memlim, cpulim;
/* ok, set some limits here */
cpulim.rlim_cur = 60;
cpulim.rlim_max = 60;
memlim.rlim_cur = 52428800;
memlim.rlim_max = 52428800;
if ( setrlimit( RLIMIT_CPU, &cpulim ) != 0 )
fprintf( stderr, "cpu limit failed" );
if ( setrlimit( RLIMIT_DATA, &memlim ) != 0 )
fprintf( stderr, "mem limit failed" );
#endif
do {
c = getopt(argc,argv,optstring);
if (c < 0) continue;
switch (c) {
case 'd': become_daemon = 1; break;
case 'f': pidfile = optarg; break;
case 's':
#if HAVE_LIBSSL
set_use_ssl(1);
if (port==NULL)
port = "995"; /* POP3 over SSL */
#else
fprintf(stderr,"%s: %s\n", argv[0], "POP3 over SSL not supported");
exit(EXIT_FAILURE);
#endif
break;
case 'p': port = optarg; break;
case 'c': ssl_certfile = optarg; break;
case 'k': ssl_keyfile = optarg; break;
case 'l': listenhost = optarg; break;
case 'a': authfile = optarg; break;
case 't': sscanf(optarg,"%u",&timeout); break;
case 'x': tmp_dir = optarg; break;
case 'm': if (stat(optarg,&sbuf)!=0) {
fprintf(stderr,"%s: %s: %s\n",argv[0], optarg,strerror(errno));
exit(EXIT_FAILURE);
}
if (!S_ISDIR(sbuf.st_mode)) {
fprintf(stderr,"%s: %s is not a directory\n",argv[0],optarg);
exit(EXIT_FAILURE);
}
/* never allow any acces to optarg[-1] */
if (strlen(optarg)>0 && optarg[strlen(optarg)-1]!='/') {
size_t ms_len = (size_t)strlen(optarg)+2;
mailspool = alloca(ms_len);
if (mailspool) {
snprintf(mailspool,ms_len,"%s/",optarg);
} else {
fprintf(stderr,"%s: unable to allocate memory on the stack\n",argv[0]);
exit(EXIT_FAILURE);
}
} else {
mailspool = optarg;
}
break;
case 'D': use_pop3_allow_deny = 1; break;
case 'L': local_mbox = optarg; break;
case 'h': usage(argv[0]); exit(EXIT_SUCCESS);
case 'v': printf("%s %s\n","akpop3d",VERSION); exit(EXIT_SUCCESS);
#ifdef HAVE_LIBMYSQLCLIENT
case 'M': enable_mysql = 1; break;
case 'H': HOSTNAME = optarg; break;
case 'U': USERNAME = optarg; break;
case 'P':
{
PASSWORD = alloca((size_t)(strlen(optarg)+1));
strlcpy(PASSWORD,optarg,strlen(optarg)+1);
len = strlen(optarg);
memset(optarg,'\0',len);
break;
}
case 'I': DATABASE = optarg; break;
case 'T': TABLE = optarg; break;
#endif
default:
fprintf(stderr,"%s: %s\n",argv[0],"unknown option - try '-h'");
exit(EXIT_FAILURE);
}
} while (c != -1);
#ifdef HAVE_LIBMYSQLCLIENT
if (enable_mysql) {
int found_null = 0;
if (HOSTNAME == NULL) {
fprintf(stderr,"%s: please set a MySQL hostname using -H <host>!\n",argv[0]);
found_null = 1;
}
if (USERNAME == NULL) {
fprintf(stderr,"%s: please set a MySQL username using -U <user>!\n",argv[0]);
found_null = 1;
}
if (DATABASE == NULL) {
fprintf(stderr,"%s: please set a MySQL database using -D <db>!\n",argv[0]);
found_null = 1;
}
if (PASSWORD == NULL) {
fprintf(stderr,"%s: please set a MySQL password using -P <pass>!\n",argv[0]);
found_null = 1;
}
if (TABLE == NULL) {
fprintf(stderr,"%s: please set a MySQL table using -T <table>!\n",argv[0]);
found_null = 1;
}
if (found_null) {
exit(1);
}
}
#endif
if (port==NULL)
port = "110";
if (become_daemon) {
daemonize();
write_pid();
}
progname = strrchr(argv[0], '/');
if (progname == NULL) {
progname = argv[0];
} else {
progname++;
}
openlog(progname, LOG_PID, LOG_MAIL);
listenfd = Tcp_listen(listenhost, port, &addrlen);
Signal(SIGCHLD,sig_chld);
Signal(SIGTERM,sig_term);
Signal(SIGINT,sig_term);
Signal(SIGHUP,sig_term);
Signal(SIGQUIT,sig_term);
for (;;) {
clen = sizeof(struct sockaddr *);
if ((connfd = accept(listenfd,(struct sockaddr *) &client,&clen)) < 0) {
if (errno == EINTR) {
continue;
} else {
syslog(LOG_ERR,"%s: %s","failed to accept connection",strerror(errno));
continue;
}
}
getpeername( connfd, (struct sockaddr *) &client, &clen );
syslog( LOG_INFO, "Connection from %s:%u", inet_ntoa( client.sin_addr ), ntohs( client.sin_port ) );
if ((childpid = fork()) == 0) {
close(listenfd);
pop3_session(connfd);
syslog( LOG_INFO, "Connection closed" );
exit(0);
} else if (childpid == -1) {
syslog(LOG_ERR,"%s: %s","fork failed (aborting)",strerror(errno));
}
close(connfd);
}
/* NOTREACHED */
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1