diff options
author | eelco <eelco@7b491191-dbf0-0310-aff6-d879d4d69008> | 2002-12-02 17:59:19 +0000 |
---|---|---|
committer | eelco <eelco@7b491191-dbf0-0310-aff6-d879d4d69008> | 2002-12-02 17:59:19 +0000 |
commit | ebcaa9ef270d5d1700163e088f32b33ef1d6ccfb (patch) | |
tree | 19f1e2fd8e56db39e963f9efbe5fe5d8801dbde8 /pop3d.c | |
parent | 89441d3d4295835ef95a78c28f75d96dbd1561be (diff) |
New server code in popserver
git-svn-id: https://svn.ic-s.nl/svn/dbmail/trunk/dbmail@636 7b491191-dbf0-0310-aff6-d879d4d69008
Diffstat (limited to 'pop3d.c')
-rw-r--r-- | pop3d.c | 982 |
1 files changed, 243 insertions, 739 deletions
@@ -1,29 +1,33 @@ /* $Id$ - * (c) 2000-2001 IC&S, The Netherlands - * - * pop3 daemon */ +* (c) 2000-2001 IC&S, The Netherlands +* +* pop3d.c +* +* main prg for pop3 daemon +*/ +#include <stdio.h> #include <string.h> -#include "pop3.h" -#include "db.h" -#include "debug.h" -#include "auth.h" +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <signal.h> #include <errno.h> +#include "imap4.h" +#include "server.h" +#include "debug.h" +#include "misc.h" #include "config.h" +#include "clientinfo.h" +#include "pop3.h" -#define INCOMING_BUFFER_SIZE 512 -#define IP_ADDR_MAXSIZE 16 -#define APOP_STAMP_SIZE 255 -/* default timeout for server daemon */ -#define DEFAULT_SERVER_TIMEOUT 100 - -#ifndef SHUT_RDWR -#define SHUR_RDWR 3 -#endif -/* syslog */ #define PNAME "dbmail/pop3d" +/* server timeout error */ +#define POP_TIMEOUT_MSG "-ERR I'm leaving, you're tooo slow" + + char *configFile = "dbmail.conf"; /* set up database login data */ @@ -32,768 +36,268 @@ extern field_t _db_db; extern field_t _db_user; extern field_t _db_pass; +int error_count = 0; + +void SetConfigItems(serverConfig_t *config, struct list *items); +void Daemonize(); +int SetMainSigHandler(); +void MainSigHandler(int sig, siginfo_t *info, void *data); + -int state; +int pop_before_smtp = 0; +int mainRestart = 0; +int mainStop = 0; + +int state; /* current pop state */ char *username=NULL, *password=NULL; struct session curr_session; char *myhostname; char *apop_stamp; char *timeout_setting; +int main(int argc, char *argv[]) +{ + serverConfig_t config; + struct list popItems, sysItems; + int result, status; + pid_t pid; + + openlog(PNAME, LOG_PID, LOG_MAIL); -char *buffer; + if (argc >= 2 && strcmp(argv[1], "-f") == 0) + { + if (!argv[2]) + trace(TRACE_FATAL,"main(): no file specified for -f option. Fatal."); -int resolve_client; -int pop_before_smtp = 0; -char *client_ip = NULL; + configFile = argv[2]; + } -int server_timeout; -int server_pid; + SetMainSigHandler(); + Daemonize(); + result = 0; -int error_count; + do + { + mainStop = 0; + mainRestart = 0; + + trace(TRACE_DEBUG, "main(): reading config"); + + ReadConfig("POP", configFile, &popItems); + ReadConfig("DBMAIL", configFile, &sysItems); + SetConfigItems(&config, &popItems); + SetTraceLevel(&popItems); + GetDBParams(_db_host, _db_db, _db_user, _db_pass, &sysItems); + + config.ClientHandler = pop3_handle_connection; + config.timeoutMsg = POP_TIMEOUT_MSG; + + CreateSocket(&config); + trace(TRACE_DEBUG, "main(): socket created, starting server"); + + switch ( (pid = fork()) ) + { + case -1: + close(config.listenSocket); + trace(TRACE_FATAL, "main(): fork failed [%s]", strerror(errno)); -FILE *tx = NULL; /* write socket */ -FILE *rx = NULL; /* read socket */ + case 0: + /* child process */ + drop_priviledges(config.serverUser, config.serverGroup); + result = StartServer(&config); -int *default_children; /* # of default children in use */ -int defchld; /* # of default children as specified in conf */ -int maxchld; /* max. # of children */ -int total_children = 0; -pid_t *xtrachild_pids; -int done; -/* 'dcu' stands for 'default children used' */ -/* 'dcp' stands for 'default children pids' */ -key_t shmkey_dcu=0,shmkey_dcp=0; -int shmid_dcu,shmid_dcp; -key_t shmkey_xtrachilds=0; -int shmid_xtrachilds; + trace(TRACE_INFO, "main(): server done, exit."); + exit(result); -#define SHM_ALLOC_SIZE (sizeof(int)) + default: + /* parent process, wait for child to exit */ + while (waitpid(pid, &status, WNOHANG|WUNTRACED) == 0) + { + if (mainStop) + kill(pid, SIGTERM); -/* list of PID's of the default-children */ -pid_t *default_child_pids; -int n_default_children; + if (mainRestart) + kill(pid, SIGHUP); + sleep(2); + } -/* signal handler */ -static void signal_handler (int signo, siginfo_t *info, void *data) + if (WIFEXITED(status)) + { + /* child process terminated neatly */ + result = WEXITSTATUS(status); + trace(TRACE_DEBUG, "main(): server has exited, exit status [%d]", result); + } + else + { + /* child stopped or signaled, don't like */ + /* make sure it is dead */ + trace(TRACE_DEBUG, "main(): server has not exited normally. Killing.."); + + kill(pid, SIGKILL); + result = 0; + } + } + + list_freelist(&popItems.start); + list_freelist(&sysItems.start); + close(config.listenSocket); + + } while (result == 1 && !mainStop) ; /* 1 means reread-config and restart */ + + trace(TRACE_INFO, "main(): exit"); + return 0; +} + + +void MainSigHandler(int sig, siginfo_t *info, void *data) { - pid_t PID; - int status,i; - int saved_errno = errno; /* save error status */ - - if (signo == SIGUSR1) - { - trace(TRACE_DEBUG, "signal_handler(): caught SIGUSR1, assuming ping"); - errno = saved_errno; - return; - } - - if (signo == SIGALRM) - { - done = -1; - trace (TRACE_DEBUG,"signal_handler(): received ALRM signal. Timeout"); - - if (tx) - { - fprintf (tx,"-ERR i cannot wait forever\r\n"); - fflush (tx); - shutdown(fileno(tx),SHUT_RDWR); - } - - if (rx) - shutdown(fileno(rx),SHUT_RDWR); - - tx = NULL; - rx = NULL; - - errno = saved_errno; - return; - } - else - if (signo == SIGCHLD) - { - trace (TRACE_DEBUG,"signal_handler(): sigCHLD, cleaning up zombies for PID %d",info->si_pid); - - PID = waitpid (info->si_pid, &status, WNOHANG | WUNTRACED); - - /* a default child that as done a normal exit() or caught a fatal signal will have reset - * it's own entry in default_child_pids[] - * an extra check is needed for uncaught signals - */ - if (WIFSIGNALED(status)) - { - /* child died because of an uncaught signal, check children */ - - for (i=0; i<defchld; i++) - { - if (default_child_pids[i] == 0) /* only allow real PID's (> 0) */ - continue; - - trace(TRACE_DEBUG,"signal_handler(): pinging to [%u]\n",default_child_pids[i]); - - if (kill(default_child_pids[i], 0) == -1 && errno == ESRCH) - { - /* this child no longer exists */ - trace(TRACE_DEBUG, "signal_handler(): cleaning up PID %u", default_child_pids[i]); - default_child_pids[i] = 0; - (*default_children)--; - break; - } - } - } - - /* check if an extra child died. if so, reset its entry in xtra_child_pids[] */ - for (i=0; i<maxchld; i++) - { - if (xtrachild_pids[i] == PID) - { - xtrachild_pids[i] = 0; - total_children--; - break; - } - } - - trace (TRACE_DEBUG,"signal_handler(): sigCHLD, cleaned"); - errno = saved_errno; - return; - } - else - { - /* reset the entry of this process if it is a default child (so it can be restored) */ - for (i=0; i<defchld; i++) - if (getpid() == default_child_pids[i]) - { - default_child_pids[i] = 0; - (*default_children)--; - break; - } - - trace (TRACE_STOP,"signal_handler(): received fatal signal [%d]",signo); - } + trace(TRACE_DEBUG, "MainSigHandler(): got signal [%d]", sig); + + if (sig == SIGHUP) + mainRestart = 1; + else + mainStop = 1; } -int handle_client(char *myhostname, int c, struct sockaddr_in adr_clnt) +void Daemonize() { - /* returns 0 when a connection was successfull - * returns -1 when a connection was unsuccessfull (continue in loop) - */ - - char *theiraddress; - char *buffer; - int cnt; - - struct hostent *clientinfo; - - time_t timestamp; - - /* reset */ - done = 1; - - theiraddress = inet_ntoa(adr_clnt.sin_addr); - client_ip = theiraddress; - - if (resolve_client==1) - { - clientinfo=gethostbyaddr((char *)&adr_clnt.sin_addr, - sizeof(adr_clnt.sin_addr), - adr_clnt.sin_family); - - - if (theiraddress != NULL) - trace (TRACE_MESSAGE,"handle_client(): incoming connection from [%s (%s)]", - theiraddress, clientinfo ? - (clientinfo->h_name ? clientinfo->h_name: "NULL") : "Lookup failed"); - else - { - trace (TRACE_ERROR,"handle_client(): error: could not get address of client"); - close(c); - return -1; - } - } - else - { - if (theiraddress != NULL) - trace (TRACE_MESSAGE,"handle_client(): incoming connection from [%s]", - theiraddress); - else - trace (TRACE_ERROR,"handle_client(): error: could not get address of client"); - } - - /* duplicate descriptor and open it */ - rx = fdopen(dup(c), "r"); - if (!rx) - { - /* opening of descriptor failed */ - close(c); - return -1; - } - - tx = fdopen(c, "w"); - if (!tx) - { - /* opening of descriptor failed */ - fclose(rx); - return -1; - } - - /* set stream to line buffered mode - * this way when we send a newline the buffer is flushed */ - setlinebuf(rx); - setlinebuf(tx); - - /* connect to the database */ - if (db_connect()< 0) - { - trace(TRACE_ERROR,"handle_client(): could not connect to database"); - fclose(rx); - fclose(tx); - return -1; - } - -/* Use same connection for auth; FIXME should have some #ifdef here - if (auth_connect()< 0) - { - trace(TRACE_ERROR,"handle_client(): could not connect to user database"); - fclose(rx); - fclose(tx); - db_disconnect(); - return -1; - } -*/ - - /* first initiate AUTHORIZATION state */ - state = AUTHORIZATION; - - memtst((buffer=(char *)my_malloc(INCOMING_BUFFER_SIZE))==NULL); - - /* create an unique timestamp + processid for APOP authentication */ - memtst((apop_stamp=(char *)my_malloc(APOP_STAMP_SIZE))==NULL); - - timestamp=time(NULL); - - sprintf (apop_stamp,"<%d.%lu@%s>",getpid(),timestamp,myhostname); - - /* sending greeting */ - fprintf (tx,"+OK DBMAIL pop3 server ready %s\r\n",apop_stamp); - fflush (tx); - - /* no errors yet */ - error_count = 0; - - trace (TRACE_DEBUG,"handle_client(): setting timeout timer at %d seconds",server_timeout); - /* setting time for timeout counter */ - alarm (server_timeout); - - /* scanning for commands */ - while (done>0) - { - memset(buffer, 0, INCOMING_BUFFER_SIZE); - for (cnt=0; cnt < INCOMING_BUFFER_SIZE-1; cnt++) - { - do - { - clearerr(rx); - fread(&buffer[cnt], 1, 1, rx); - } while (ferror(rx) && errno == EINTR); - - if (buffer[cnt] == '\n' || feof(rx) || ferror(rx)) - { - buffer[cnt+1] = '\0'; - break; - } - } - - if (feof(rx) || ferror(rx)) - done = -1; /* check of client eof */ - else - { - alarm (0); - /* handle pop3 commands */ - done = pop3(tx,buffer); - /* cleanup the buffer */ - memset (buffer, '\0', INCOMING_BUFFER_SIZE); - /* reset the timeout counter */ - alarm (server_timeout); - } - fflush (tx); - } - - /* we've reached the update state */ - state = UPDATE; - - /* memory cleanup */ - my_free(buffer); - buffer = NULL; - my_free(apop_stamp); - apop_stamp = NULL; - - if (done == -3) - { - trace (TRACE_ERROR,"handle_client(): alert: possible flood attempt, closing connection."); - if (tx) - { - fclose (tx); - tx = NULL; - } - if (rx) - { - shutdown (fileno(rx), SHUT_RDWR); - fclose(rx); - rx = NULL; - } + if (fork()) + exit(0); + setsid(); - db_disconnect(); -// auth_disconnect(); - } - else if (done < 0) - { - trace (TRACE_ERROR,"handle_client(): client EOF, connection terminated"); - if (tx) - { - fclose(tx); - tx = NULL; - } - if (rx) - { - shutdown (fileno(rx), SHUT_RDWR); - fclose(rx); - rx = NULL; - } + if (fork()) + exit(0); +} - db_disconnect(); -// auth_disconnect(); - } - else - { - if (username == NULL) - trace (TRACE_ERROR,"handle_client(): error, uncomplete session"); - else - trace(TRACE_MESSAGE,"handle_client(): user %s logging out [message=%llu, octets=%llu]", - username, curr_session.virtual_totalmessages, - curr_session.virtual_totalsize); - - /* if everything went well, write down everything and do a cleanup */ - db_update_pop(&curr_session); - db_disconnect(); -// auth_disconnect(); - - fclose(tx); - shutdown (fileno(rx), SHUT_RDWR); - fclose(rx); - } - - /* clean this session */ - db_session_cleanup(&curr_session); - - if (username!=NULL) - { - /* username cleanup */ - my_free(username); - username=NULL; - } - - if (password!=NULL) - { - /* password cleanup */ - my_free(password); - password=NULL; - } - - /* reset timers */ - alarm (0); - __debug_dumpallocs(); - return 0; +int SetMainSigHandler() +{ + struct sigaction act; + + /* init & install signal handlers */ + memset(&act, 0, sizeof(act)); + + act.sa_sigaction = MainSigHandler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + + sigaction(SIGINT, &act, 0); + sigaction(SIGQUIT, &act, 0); + sigaction(SIGTERM, &act, 0); + sigaction(SIGHUP, &act, 0); + + return 0; } -int main (int argc, char *argv[]) +void SetConfigItems(serverConfig_t *config, struct list *items) { - struct sockaddr_in adr_srvr; - struct sockaddr_in adr_clnt; - struct sigaction act; - char myhostname[64]; - struct list popItems, sysItems; - field_t val, newuser, newgroup; - pid_t childpid = 0; - - int len_inet; - int reuseaddress; - int s = -1; - int c = -1; - int z, i, j; /* counters */ - pid_t deadchildpid; - int n_connects = 0,n_max_connects=0; - - /* open logs */ - openlog(PNAME, LOG_PID, LOG_MAIL); - - if (argc >= 2 && strcmp(argv[1], "-f") == 0) - { - if (!argv[2]) - trace(TRACE_FATAL,"main(): no file specified for -f option. Fatal."); + field_t val; - configFile = argv[2]; - } - - ReadConfig("POP", configFile, &popItems); - ReadConfig("DBMAIL", configFile, &sysItems); - SetTraceLevel(&popItems); - GetDBParams(_db_host, _db_db, _db_user, _db_pass, &sysItems); - - GetConfigValue("TIMEOUT", &popItems, val); - server_timeout = atoi(val); - if (server_timeout < 10) - server_timeout = DEFAULT_SERVER_TIMEOUT; - - GetConfigValue("RESOLVE_IP", &popItems, val); - if (strcasecmp(val,"yes")==0) - resolve_client = 1; - else - resolve_client = 0; - - GetConfigValue("POP_BEFORE_SMTP", &popItems, val); - if (strcasecmp(val,"yes") == 0) - pop_before_smtp = 1; - else - pop_before_smtp = 0; - - - GetConfigValue("BINDIP", &popItems, val); - if (val[0] == '\0') - trace(TRACE_FATAL,"main(): no IP to bind to specified. Fatal."); - - if (val[0] == '*') /* bind to all interfaces */ - adr_srvr.sin_addr.s_addr = htonl (INADDR_ANY); - else - { - if (!inet_aton(val, &adr_srvr.sin_addr)) - trace (TRACE_FATAL, "main(): [%s] is not a valid ipaddress", val); - } - - GetConfigValue("PORT", &popItems, val); - if (val[0] != '\0') - adr_srvr.sin_port = htons (atoi(val)); - else - trace (TRACE_FATAL,"main(): no PORT in config. fatal."); - - - /* get child config */ - GetConfigValue("NCHILDREN", &popItems, val); - if (val[0] == '\0') - trace(TRACE_FATAL, "main(): no value for NCHILDREN in config. Fatal."); - defchld = atoi(val); - - GetConfigValue("MAXCHILDREN", &popItems, val); - if (val[0] == '\0') - trace(TRACE_FATAL, "main(): no value for MAXCHILDREN in config. Fatal."); - maxchld = atoi(val); - - GetConfigValue("MAXCONNECTS", &popItems, val); - n_max_connects = atoi(val); - if (n_max_connects <= 1) - n_max_connects = POP3_DEF_MAXCONNECT; - - GetConfigValue("EFFECTIVE_USER", &popItems, newuser); - GetConfigValue("EFFECTIVE_GROUP", &popItems, newgroup); - if (!newuser[0] || !newgroup[0]) - trace(TRACE_FATAL,"main(): no newuser and newgroup in config"); - - - /* daemonize */ - if (fork ()) - exit (0); - - - close (fileno(stdin)); - close (fileno(stdout)); - close (fileno(stderr)); - - - /* getting hostname */ - gethostname (myhostname,64); - myhostname[63] = 0; /* make sure string is terminated */ - - /* init & install signal handlers */ - memset(&act, 0, sizeof(act)); - - act.sa_sigaction = signal_handler; - sigemptyset(&act.sa_mask); - act.sa_flags = SA_SIGINFO; - - sigaction(SIGCHLD, &act, 0); -/* sigaction(SIGPIPE, &act, 0);*/ - sigaction(SIGINT, &act, 0); - sigaction(SIGQUIT, &act, 0); - sigaction(SIGILL, &act, 0); - sigaction(SIGBUS, &act, 0); - sigaction(SIGFPE, &act, 0); - sigaction(SIGSEGV, &act, 0); - sigaction(SIGTERM, &act, 0); - sigaction(SIGSTOP, &act, 0); - sigaction(SIGALRM, &act, 0); - sigaction(SIGUSR1, &act, 0); - - adr_srvr.sin_family = PF_INET; - - s = socket (PF_INET, SOCK_STREAM, 0); /* creating the socket */ - if (s == -1 ) - trace (TRACE_FATAL,"main(): call socket(2) failed"); - - - setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuseaddress, sizeof(reuseaddress)); - - len_inet = sizeof (adr_srvr); - - z = bind (s, (struct sockaddr *)&adr_srvr, len_inet); /* bind to socket */ - if (z == -1 ) - trace (TRACE_FATAL,"main(): call bind(2) failed"); - - z = listen (s, BACKLOG); /* make the socket listen */ - if (z == -1 ) - trace (TRACE_FATAL,"main(): call listen(2) failed"); - - /* drop priviledges */ - trace (TRACE_MESSAGE,"main(): Dropping priviledges"); - - if (drop_priviledges (newuser, newgroup) != 0) - trace (TRACE_FATAL,"main(): could not set uid %s, gid %s",newuser,newgroup); - - /* getting shared memory children counter */ - shmkey_dcu = time (NULL); /* get an unique key */ - shmid_dcu = shmget (shmkey_dcu, sizeof (int), 0666 | IPC_CREAT); - - shmkey_dcp = time (NULL)+1; /* get an unique key */ - shmid_dcp = shmget (shmkey_dcp, sizeof (pid_t) * defchld, 0666 | IPC_CREAT); - - shmkey_xtrachilds = time (NULL)+2; /* get an unique key */ - shmid_xtrachilds = shmget (shmkey_xtrachilds, sizeof (pid_t) * maxchld, 0666 | IPC_CREAT); - - if (shmid_dcu == -1 || shmid_dcp == -1 || shmid_xtrachilds == -1) - trace (TRACE_FATAL,"main(): could not allocate shared memory: %s",strerror(errno)); - - - /* server loop */ - trace (TRACE_MESSAGE,"main(): DBmail pop3 server ready"); - - - /* remember this pid, we're the father process */ - server_pid = getpid(); - - - /* attach to shared mem */ - default_children = (int *)shmat(shmid_dcu, 0, 0); - if (default_children == (int *)-1) - trace (TRACE_FATAL,"main(): could not attach to shared memory block (dcu)"); - - default_child_pids = (pid_t*)shmat(shmid_dcp, 0, 0); - if (default_child_pids == (pid_t*)-1) - trace (TRACE_FATAL,"main(): could not attach to shared memory block (dcp)"); - - xtrachild_pids = (pid_t*)shmat(shmid_xtrachilds, 0, 0); - memset(xtrachild_pids, 0, sizeof(pid_t)*maxchld); - if (xtrachild_pids == (pid_t*)-1) - trace (TRACE_FATAL,"main(): could not attach to shared memory block (xtrachild_pids)"); - - - /* we don't have any children yet so no active children neither */ - *default_children = 0; - - /* spawn the default children */ - for (i=0; i<defchld; i++) - { - switch ( (childpid = fork()) ) + /* read items: NCHILDREN */ + GetConfigValue("NCHILDREN", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for NCHILDREN in config file"); + + if ( (config->nChildren = atoi(val)) <= 0) + trace(TRACE_FATAL, "SetConfigItems(): value for NCHILDREN is invalid: [%d]", config->nChildren); + + trace(TRACE_DEBUG, "SetConfigItems(): server will create [%d] children", config->nChildren); + + + /* read items: MAXCONNECTS */ + GetConfigValue("MAXCONNECTS", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for MAXCONNECTS in config file"); + + if ( (config->childMaxConnect = atoi(val)) <= 0) + trace(TRACE_FATAL, "SetConfigItems(): value for MAXCONNECTS is invalid: [%d]", config->childMaxConnect); + + trace(TRACE_DEBUG, "SetConfigItems(): children will make max. [%d] connections", config->childMaxConnect); + + + /* read items: TIMEOUT */ + GetConfigValue("TIMEOUT", items, val); + if (strlen(val) == 0) { - case 0: - n_connects = 0; - break; - case -1: - perror("main(): fork failed"); - break; - default: - default_child_pids[i] = childpid; - total_children++; + trace(TRACE_DEBUG, "SetConfigItems(): no value for TIMEOUT in config file"); + config->timeout = 0; } + else if ( (config->timeout = atoi(val)) <= 30) + trace(TRACE_FATAL, "SetConfigItems(): value for TIMEOUT is invalid: [%d]", config->timeout); - if (childpid == 0) - break; - } + trace(TRACE_DEBUG, "SetConfigItems(): timeout [%d] seconds", config->timeout); - /* this infinite loop is needed for killed default-children: - * they should re-enter at the following if-statement - */ - for ( ;; ) - { - /* split up in the 'server' part and the client part */ + /* read items: PORT */ + GetConfigValue("PORT", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for PORT in config file"); - /* - * Client loop - */ - if (getpid() != server_pid) - { - for (;;) - { - /* wait for a connection */ - len_inet = sizeof (adr_clnt); - c = accept (s, (struct sockaddr *)&adr_clnt, - &len_inet); /* incoming connection */ - - /* failure won't cause a quit forking is too expensive */ - if (c == -1) - { - trace (TRACE_ERROR,"main(): call accept(2) failed [%s]", strerror(errno)); - continue; - } - - (*default_children)++; - n_connects++; + if ( (config->port = atoi(val)) <= 0) + trace(TRACE_FATAL, "SetConfigItems(): value for PORT is invalid: [%d]", config->port); - handle_client(myhostname, c, adr_clnt); - - (*default_children)--; + trace(TRACE_DEBUG, "SetConfigItems(): binding to PORT [%d]", config->port); - if (n_connects >= n_max_connects) - { - trace(TRACE_ERROR,"Maximum # of connections reached, committing suicide...\n"); - for (i=0; i<defchld; i++) - if (default_child_pids[i] == getpid()) - { - sleep(1); /* allow father process to catch up */ - default_child_pids[i] = 0; - exit(0); - } - } - } - } - else - for (;;) - { - /* check if default-child have died - * (their entries have been set to zero in default_child_pids[]) - */ - for (i=0; i<defchld; i++) - { - if (default_child_pids[i] == 0 || (kill(default_child_pids[i],0) == -1 && errno == ESRCH) ) - { - /* def-child has died, re-create */ - if (!fork()) - { - default_child_pids[i] = getpid(); - n_connects = 0; - break; - /* after this break the if (getpid() == server_pid) will be re-executed */ - } - else - { - j=0; - while (default_child_pids[i] == 0 && ++j<100) usleep(100); - } - } - } - - if (getpid() != server_pid) - break; - - - while ((deadchildpid = waitpid (-1, NULL, WNOHANG | WUNTRACED)) > 0) - { - trace(TRACE_DEBUG,"main(): got %ld from waitpid",deadchildpid); - for (i=0; i<maxchld; i++) - { - if (xtrachild_pids[i] == deadchildpid) - { - xtrachild_pids[i] = 0; - total_children--; - break; - } - } - - for (i=0; i<defchld; i++) - { - if (default_child_pids[i] == deadchildpid) - { - trace(TRACE_DEBUG, "main(): got dead default child"); - default_child_pids[i] = 0; - } - } - } - - /* clean up list */ - for (i=0; i<maxchld; i++) - if (xtrachild_pids[i] && - waitpid(xtrachild_pids[i], NULL, WNOHANG | WUNTRACED) == -1 && - errno == ECHILD) - { - xtrachild_pids[i] = 0; - total_children--; - } - if ((*default_children) < defchld) - { - /* not all the def-childs are in use, continue */ - sleep(1); /* don't hog cpu */ - continue; - } - - if (total_children >= maxchld) - { - sleep(1); - continue; - } - - /* wait for a connection */ - len_inet = sizeof (adr_clnt); - c = accept (s, (struct sockaddr *)&adr_clnt, - &len_inet); /* incoming connection */ - - /* failure won't cause a quit forking is too expensive */ - if (c == -1 && errno != EINTR) /* dont show failure for EINTR */ - { - trace (TRACE_ERROR,"main(): call accept(2) failed [%s]", strerror(errno)); - continue; - } - - for (i=0; i<maxchld; i++) - if (!xtrachild_pids[i]) - break; - - if (i == maxchld) - { - /* no free places ?? */ - close(c); - continue; - } - - if ( (childpid = fork()) ) - { - if (childpid != -1) - { - xtrachild_pids[i] = childpid; /* save pid */ - total_children++; - } - else - { - trace(TRACE_ERROR, "main(): forked failed [%s]", strerror(errno)); - } - - close(c); - continue; - } - else - { - /* handle client connection */ - handle_client(myhostname, c, adr_clnt); - exit(0); - } - } - } + /* read items: BINDIP */ + GetConfigValue("BINDIP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for BINDIP in config file"); - /* nothing will ever get here */ - return 0; -} + strncpy(config->ip, val, IPLEN); + config->ip[IPLEN-1] = '\0'; + + trace(TRACE_DEBUG, "SetConfigItems(): binding to IP [%s]", config->ip); + + + /* read items: RESOLVE_IP */ + GetConfigValue("RESOLVE_IP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, "SetConfigItems(): no value for RESOLVE_IP in config file"); + + config->resolveIP = (strcasecmp(val, "yes") == 0); + + trace(TRACE_DEBUG, "SetConfigItems(): %sresolving client IP", config->resolveIP ? "" : "not "); + + + /* read items: IMAP-BEFORE-SMTP */ + GetConfigValue("POP_BEFORE_SMTP", items, val); + if (strlen(val) == 0) + trace(TRACE_DEBUG, "SetConfigItems(): no value for POP_BEFORE_SMTP in config file"); + + pop_before_smtp = (strcasecmp(val, "yes") == 0); + + trace(TRACE_DEBUG, "SetConfigItems(): %s POP-before-SMTP", + pop_before_smtp ? "Enabling" : "Disabling"); + + + /* read items: EFFECTIVE-USER */ + GetConfigValue("EFFECTIVE_USER", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_USER in config file"); + + strncpy(config->serverUser, val, FIELDLEN); + config->serverUser[FIELDLEN-1] = '\0'; + + trace(TRACE_DEBUG, "SetConfigItems(): effective user shall be [%s]", config->serverUser); + + + /* read items: EFFECTIVE-GROUP */ + GetConfigValue("EFFECTIVE_GROUP", items, val); + if (strlen(val) == 0) + trace(TRACE_FATAL, "SetConfigItems(): no value for EFFECTIVE_GROUP in config file"); + + strncpy(config->serverGroup, val, FIELDLEN); + config->serverGroup[FIELDLEN-1] = '\0'; + + trace(TRACE_DEBUG, "SetConfigItems(): effective group shall be [%s]", config->serverGroup); + + + +} |