Back to index

citadel  8.12
sysdep.c
Go to the documentation of this file.
00001 /*
00002  * Citadel "system dependent" stuff.
00003  *
00004  * Here's where we (hopefully) have most parts of the Citadel server that
00005  * would need to be altered to run the server in a non-POSIX environment.
00006  * 
00007  * If we ever port to a different platform and either have multiple
00008  * variants of this file or simply load it up with #ifdefs.
00009  *
00010  * Copyright (c) 1987-2011 by the citadel.org team
00011  *
00012  * This program is open source software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 3 of the License, or
00015  * (at your option) any later version.
00016  *
00017  * This program is distributed in the hope that it will be useful,
00018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  * GNU General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with this program; if not, write to the Free Software
00024  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00025  */
00026 
00027 #include "sysdep.h"
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <stdio.h>
00031 #include <fcntl.h>
00032 #include <ctype.h>
00033 #include <signal.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <sys/wait.h>
00037 #include <sys/socket.h>
00038 #include <syslog.h>
00039 #include <sys/syslog.h>
00040 
00041 #if TIME_WITH_SYS_TIME
00042 # include <sys/time.h>
00043 # include <time.h>
00044 #else
00045 # if HAVE_SYS_TIME_H
00046 #  include <sys/time.h>
00047 # else
00048 #  include <time.h>
00049 # endif
00050 #endif
00051 
00052 #include <limits.h>
00053 #include <sys/resource.h>
00054 #include <netinet/in.h>
00055 #include <netinet/tcp.h>
00056 #include <arpa/inet.h>
00057 #include <netdb.h>
00058 #include <sys/un.h>
00059 #include <string.h>
00060 #include <pwd.h>
00061 #include <errno.h>
00062 #include <stdarg.h>
00063 #include <grp.h>
00064 #define SHOW_ME_VAPPEND_PRINTF
00065 #include <libcitadel.h>
00066 #include "citadel.h"
00067 #include "server.h"
00068 #include "sysdep_decls.h"
00069 #include "citserver.h"
00070 #include "support.h"
00071 #include "config.h"
00072 #include "database.h"
00073 #include "housekeeping.h"
00074 #include "modules/crypto/serv_crypto.h"   /* Needed for init_ssl, client_write_ssl, client_read_ssl, destruct_ssl */
00075 #include "ecrash.h"
00076 #include "context.h"
00077 
00078 #ifdef HAVE_SYS_SELECT_H
00079 #include <sys/select.h>
00080 #endif
00081 
00082 #ifndef HAVE_SNPRINTF
00083 #include "snprintf.h"
00084 #endif
00085 
00086 #include "ctdl_module.h"
00087 #include "threads.h"
00088 #include "user_ops.h"
00089 #include "control.h"
00090 
00091 
00092 /*
00093  * Signal handler to shut down the server.
00094  */
00095 
00096 volatile int exit_signal = 0;
00097 volatile int shutdown_and_halt = 0;
00098 volatile int restart_server = 0;
00099 volatile int running_as_daemon = 0;
00100 
00101 static RETSIGTYPE signal_cleanup(int signum) {
00102        syslog(LOG_DEBUG, "Caught signal %d; shutting down.", signum);
00103        exit_signal = signum;
00104        server_shutting_down = 1;
00105 }
00106 
00107 static RETSIGTYPE signal_exit(int signum) {
00108        exit(1);
00109 }
00110 
00111 
00112 
00113 /*
00114  * Some initialization stuff...
00115  */
00116 void init_sysdep(void) {
00117        sigset_t set;
00118 
00119        /* Avoid vulnerabilities related to FD_SETSIZE if we can. */
00120 #ifdef FD_SETSIZE
00121 #ifdef RLIMIT_NOFILE
00122        struct rlimit rl;
00123        getrlimit(RLIMIT_NOFILE, &rl);
00124        rl.rlim_cur = FD_SETSIZE;
00125        rl.rlim_max = FD_SETSIZE;
00126        setrlimit(RLIMIT_NOFILE, &rl);
00127 #endif
00128 #endif
00129 
00130        /* If we've got OpenSSL, we're going to use it. */
00131 #ifdef HAVE_OPENSSL
00132        init_ssl();
00133 #endif
00134 
00135        /*
00136         * Set up a place to put thread-specific data.
00137         * We only need a single pointer per thread - it points to the
00138         * CitContext structure (in the ContextList linked list) of the
00139         * session to which the calling thread is currently bound.
00140         */
00141        if (pthread_key_create(&MyConKey, NULL) != 0) {
00142               syslog(LOG_CRIT, "Can't create TSD key: %s", strerror(errno));
00143        }
00144 
00145        /*
00146         * Interript, hangup, and terminate signals should cause the server
00147         * to gracefully clean up and shut down.
00148         */
00149        sigemptyset(&set);
00150        sigaddset(&set, SIGINT);
00151        sigaddset(&set, SIGHUP);
00152        sigaddset(&set, SIGTERM);
00153        sigprocmask(SIG_UNBLOCK, &set, NULL);
00154 
00155        signal(SIGINT, signal_cleanup);
00156        signal(SIGHUP, signal_cleanup);
00157        signal(SIGTERM, signal_cleanup);
00158        signal(SIGUSR2, signal_exit);
00159 
00160        /*
00161         * Do not shut down the server on broken pipe signals, otherwise the
00162         * whole Citadel service would come down whenever a single client
00163         * socket breaks.
00164         */
00165        signal(SIGPIPE, SIG_IGN);
00166 }
00167 
00168 
00169 /* 
00170  * This is a generic function to set up a master socket for listening on
00171  * a TCP port.  The server shuts down if the bind fails.  (IPv4/IPv6 version)
00172  *
00173  * ip_addr    IP address to bind
00174  * port_number       port number to bind
00175  * queue_len  number of incoming connections to allow in the queue
00176  */
00177 int ctdl_tcp_server(char *ip_addr, int port_number, int queue_len, char *errormessage)
00178 {
00179        struct protoent *p;
00180        struct sockaddr_in6 sin6;
00181        struct sockaddr_in sin4;
00182        int s, i, b;
00183        int ip_version = 6;
00184 
00185        memset(&sin6, 0, sizeof(sin6));
00186        memset(&sin4, 0, sizeof(sin4));
00187        sin6.sin6_family = AF_INET6;
00188        sin4.sin_family = AF_INET;
00189 
00190        if (   (ip_addr == NULL)                                              /* any IPv6 */
00191               || (IsEmptyStr(ip_addr))
00192               || (!strcmp(ip_addr, "*"))
00193        ) {
00194               ip_version = 6;
00195               sin6.sin6_addr = in6addr_any;
00196        }
00197        else if (!strcmp(ip_addr, "0.0.0.0"))                                        /* any IPv4 */
00198        {
00199               ip_version = 4;
00200               sin4.sin_addr.s_addr = INADDR_ANY;
00201        }
00202        else if ((strchr(ip_addr, '.')) && (!strchr(ip_addr, ':')))                  /* specific IPv4 */
00203        {
00204               ip_version = 4;
00205               if (inet_pton(AF_INET, ip_addr, &sin4.sin_addr) <= 0) {
00206                      snprintf(errormessage, SIZ,
00207                              "Error binding to [%s] : %s", ip_addr, strerror(errno)
00208                      );
00209                      syslog(LOG_ALERT, "%s", errormessage);
00210                      return (-1);
00211               }
00212        }
00213        else                                                                  /* specific IPv6 */
00214        {
00215               ip_version = 6;
00216               if (inet_pton(AF_INET6, ip_addr, &sin6.sin6_addr) <= 0) {
00217                      snprintf(errormessage, SIZ,
00218                              "Error binding to [%s] : %s", ip_addr, strerror(errno)
00219                      );
00220                      syslog(LOG_ALERT, "%s", errormessage);
00221                      return (-1);
00222               }
00223        }
00224 
00225        if (port_number == 0) {
00226               snprintf(errormessage, SIZ, "Can't start: no port number specified.");
00227               syslog(LOG_ALERT, "%s", errormessage);
00228               return (-1);
00229        }
00230        sin6.sin6_port = htons((u_short) port_number);
00231        sin4.sin_port = htons((u_short) port_number);
00232 
00233        p = getprotobyname("tcp");
00234 
00235        s = socket( ((ip_version == 6) ? PF_INET6 : PF_INET), SOCK_STREAM, (p->p_proto));
00236        if (s < 0) {
00237               snprintf(errormessage, SIZ,
00238                       "Can't create a listening socket: %s", strerror(errno)
00239               );
00240               syslog(LOG_ALERT, "%s", errormessage);
00241               return (-1);
00242        }
00243        /* Set some socket options that make sense. */
00244        i = 1;
00245        setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
00246 
00247        if (ip_version == 6) {
00248               b = bind(s, (struct sockaddr *) &sin6, sizeof(sin6));
00249        }
00250        else {
00251               b = bind(s, (struct sockaddr *) &sin4, sizeof(sin4));
00252        }
00253 
00254        if (b < 0) {
00255               snprintf(errormessage, SIZ,
00256                       "Can't bind: %s", strerror(errno)
00257               );
00258               syslog(LOG_ALERT, "%s", errormessage);
00259               return (-1);
00260        }
00261 
00262        fcntl(s, F_SETFL, O_NONBLOCK);
00263 
00264        if (listen(s, ((queue_len >= 5) ? queue_len : 5) ) < 0) {
00265               snprintf(errormessage, SIZ,
00266                       "Can't listen: %s", strerror(errno)
00267               );
00268               syslog(LOG_ALERT, "%s", errormessage);
00269               return (-1);
00270        }
00271        return (s);
00272 }
00273 
00274 
00275 
00276 
00277 
00278 /*
00279  * Create a Unix domain socket and listen on it
00280  */
00281 int ctdl_uds_server(char *sockpath, int queue_len, char *errormessage)
00282 {
00283        struct sockaddr_un addr;
00284        int s;
00285        int i;
00286        int actual_queue_len;
00287 #ifdef HAVE_STRUCT_UCRED
00288        int passcred = 1;
00289 #endif
00290 
00291        actual_queue_len = queue_len;
00292        if (actual_queue_len < 5) actual_queue_len = 5;
00293 
00294        i = unlink(sockpath);
00295        if ((i != 0) && (errno != ENOENT)) {
00296               snprintf(errormessage, SIZ, "citserver: can't unlink %s: %s",
00297                      sockpath, strerror(errno)
00298               );
00299               syslog(LOG_EMERG, "%s", errormessage);
00300               return(-1);
00301        }
00302 
00303        memset(&addr, 0, sizeof(addr));
00304        addr.sun_family = AF_UNIX;
00305        safestrncpy(addr.sun_path, sockpath, sizeof addr.sun_path);
00306 
00307        s = socket(AF_UNIX, SOCK_STREAM, 0);
00308        if (s < 0) {
00309               snprintf(errormessage, SIZ, 
00310                       "citserver: Can't create a socket: %s",
00311                       strerror(errno));
00312               syslog(LOG_EMERG, "%s", errormessage);
00313               return(-1);
00314        }
00315 
00316        if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
00317               snprintf(errormessage, SIZ, 
00318                       "citserver: Can't bind: %s",
00319                       strerror(errno));
00320               syslog(LOG_EMERG, "%s", errormessage);
00321               return(-1);
00322        }
00323 
00324        /* set to nonblock - we need this for some obscure situations */
00325        if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) {
00326               snprintf(errormessage, SIZ, 
00327                       "citserver: Can't set socket to non-blocking: %s",
00328                       strerror(errno));
00329               syslog(LOG_EMERG, "%s", errormessage);
00330               close(s);
00331               return(-1);
00332        }
00333 
00334        if (listen(s, actual_queue_len) < 0) {
00335               snprintf(errormessage, SIZ, 
00336                       "citserver: Can't listen: %s",
00337                       strerror(errno));
00338               syslog(LOG_EMERG, "%s", errormessage);
00339               return(-1);
00340        }
00341 
00342 #ifdef HAVE_STRUCT_UCRED
00343        setsockopt(s, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred));
00344 #endif
00345 
00346        chmod(sockpath, S_ISGID|S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
00347        return(s);
00348 }
00349 
00350 
00351 
00352 /*
00353  * The following functions implement output buffering on operating systems which
00354  * support it (such as Linux and various BSD flavors).
00355  */
00356 #ifndef HAVE_DARWIN
00357 #ifdef TCP_CORK
00358 #      define HAVE_TCP_BUFFERING
00359 #else
00360 #      ifdef TCP_NOPUSH
00361 #             define HAVE_TCP_BUFFERING
00362 #             define TCP_CORK TCP_NOPUSH
00363 #      endif
00364 #endif /* TCP_CORK */
00365 #endif /* HAVE_DARWIN */
00366 
00367 static unsigned on = 1, off = 0;
00368 
00369 void buffer_output(void) {
00370 #ifdef HAVE_TCP_BUFFERING
00371 #ifdef HAVE_OPENSSL
00372        if (!CC->redirect_ssl)
00373 #endif
00374               setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
00375 #endif
00376 }
00377 
00378 void unbuffer_output(void) {
00379 #ifdef HAVE_TCP_BUFFERING
00380 #ifdef HAVE_OPENSSL
00381        if (!CC->redirect_ssl)
00382 #endif
00383               setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
00384 #endif
00385 }
00386 
00387 void flush_output(void) {
00388 #ifdef HAVE_TCP_BUFFERING
00389        struct CitContext *CCC = CC;
00390        setsockopt(CCC->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
00391        setsockopt(CCC->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
00392 #endif
00393 }
00394 
00395 /*
00396 static void flush_client_inbuf(void)
00397 {
00398        CitContext *CCC=CC;
00399 
00400        FlushStrBuf(CCC->ReadBuf);
00401        CCC->RecvBuf->ReadWritePointer = NULL;
00402 
00403 }
00404 */
00405 
00406 
00407 /*
00408  * client_close()    ...    close the client socket
00409  */
00410 void client_close(void) {
00411        CitContext *CCC = CC;
00412 
00413        if (!CCC) return;
00414        if (CCC->client_socket <= 0) return;
00415        syslog(LOG_DEBUG, "Closing socket %d", CCC->client_socket);
00416 
00417        close(CCC->client_socket);
00418        CCC->client_socket = -1 ;
00419 }
00420 
00421 
00422 
00423 
00424 /*
00425  * client_write()   ...    Send binary data to the client.
00426  */
00427 int client_write(const char *buf, int nbytes)
00428 {
00429        int bytes_written = 0;
00430        int retval;
00431 #ifndef HAVE_TCP_BUFFERING
00432        int old_buffer_len = 0;
00433 #endif
00434        fd_set wset;
00435        CitContext *Ctx;
00436        int fdflags;
00437 
00438        if (nbytes < 1) return(0);
00439 
00440        Ctx = CC;
00441 
00442 #ifdef BIGBAD_IODBG
00443        {
00444               int rv = 0;
00445               char fn [SIZ];
00446               FILE *fd;
00447               
00448               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", Ctx->ServiceName, Ctx->cs_pid);
00449               
00450               fd = fopen(fn, "a+");
00451               if (fd)
00452               {
00453                   fprintf(fd, "Sending: BufSize: %d BufContent: [",
00454                          nbytes);
00455                   rv = fwrite(buf, nbytes, 1, fd);
00456                   fprintf(fd, "]\n");
00457                   fclose(fd);
00458               }
00459        }
00460 #endif
00461 //     flush_client_inbuf();
00462        if (Ctx->redirect_buffer != NULL) {
00463               StrBufAppendBufPlain(Ctx->redirect_buffer,
00464                                  buf, nbytes, 0);
00465               return 0;
00466        }
00467 
00468 #ifdef HAVE_OPENSSL
00469        if (Ctx->redirect_ssl) {
00470               client_write_ssl(buf, nbytes);
00471               return 0;
00472        }
00473 #endif
00474        if (Ctx->client_socket == -1) return -1;
00475 
00476        fdflags = fcntl(Ctx->client_socket, F_GETFL);
00477 
00478        while ((bytes_written < nbytes) && (Ctx->client_socket != -1)){
00479               if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
00480                      FD_ZERO(&wset);
00481                      FD_SET(Ctx->client_socket, &wset);
00482                      if (select(1, NULL, &wset, NULL, NULL) == -1) {
00483                             if (errno == EINTR)
00484                             {
00485                                    syslog(LOG_DEBUG, "client_write(%d bytes) select() interrupted.",
00486                                           nbytes-bytes_written
00487                                    );
00488                                    if (server_shutting_down) {
00489                                           CC->kill_me = KILLME_SELECT_INTERRUPTED;
00490                                           return (-1);
00491                                    } else {
00492                                           /* can't trust fd's and stuff so we need to re-create them */
00493                                           continue;
00494                                    }
00495                             } else {
00496                                    syslog(LOG_ERR,
00497                                           "client_write(%d bytes) select failed: %s (%d)",
00498                                           nbytes - bytes_written,
00499                                           strerror(errno), errno
00500                                    );
00501                                    cit_backtrace();
00502                                    client_close();
00503                                    Ctx->kill_me = KILLME_SELECT_FAILED;
00504                                    return -1;
00505                             }
00506                      }
00507               }
00508 
00509               retval = write(Ctx->client_socket, &buf[bytes_written], nbytes - bytes_written);
00510               if (retval < 1) {
00511                      syslog(LOG_ERR,
00512                             "client_write(%d bytes) failed: %s (%d)",
00513                             nbytes - bytes_written,
00514                             strerror(errno), errno
00515                      );
00516                      cit_backtrace();
00517                      client_close();
00518                      Ctx->kill_me = KILLME_WRITE_FAILED;
00519                      return -1;
00520               }
00521               bytes_written = bytes_written + retval;
00522        }
00523        return 0;
00524 }
00525 
00526 void cputbuf(const StrBuf *Buf) {   
00527        client_write(ChrPtr(Buf), StrLength(Buf)); 
00528 }   
00529 
00530 
00531 /*
00532  * cprintf()  Send formatted printable data to the client.
00533  *            Implemented in terms of client_write() so it's technically not sysdep...
00534  */
00535 void cprintf(const char *format, ...) {   
00536        va_list arg_ptr;   
00537        char buf[1024];
00538    
00539        va_start(arg_ptr, format);   
00540        if (vsnprintf(buf, sizeof buf, format, arg_ptr) == -1)
00541               buf[sizeof buf - 2] = '\n';
00542        client_write(buf, strlen(buf)); 
00543        va_end(arg_ptr);
00544 }   
00545 
00546 
00547 /*
00548  * Read data from the client socket.
00549  *
00550  * sock              socket fd to read from
00551  * buf        buffer to read into 
00552  * bytes      number of bytes to read
00553  * timeout    Number of seconds to wait before timing out
00554  *
00555  * Possible return values:
00556  *      1       Requested number of bytes has been read.
00557  *      0       Request timed out.
00558  *     -1     Connection is broken, or other error.
00559  */
00560 int client_read_blob(StrBuf *Target, int bytes, int timeout)
00561 {
00562        CitContext *CCC=CC;
00563        const char *Error;
00564        int retval = 0;
00565 
00566 #ifdef HAVE_OPENSSL
00567        if (CCC->redirect_ssl) {
00568 #ifdef BIGBAD_IODBG
00569               int rv = 0;
00570               char fn [SIZ];
00571               FILE *fd;
00572               
00573               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00574                      
00575               fd = fopen(fn, "a+");
00576               fprintf(fd, "Reading BLOB: BufSize: %d ",
00577                      bytes);
00578               rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
00579               fprintf(fd, "]\n");
00580               
00581                      
00582               fclose(fd);
00583 #endif
00584               retval = client_read_sslblob(Target, bytes, timeout);
00585               if (retval < 0) {
00586                      syslog(LOG_CRIT, "client_read_blob() failed");
00587               }
00588 #ifdef BIGBAD_IODBG
00589               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00590               
00591               fd = fopen(fn, "a+");
00592               fprintf(fd, "Read: %d BufContent: [",
00593                      StrLength(Target));
00594               rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
00595               fprintf(fd, "]\n");
00596               
00597               
00598               fclose(fd);
00599 #endif
00600        }
00601        else 
00602 #endif
00603        {
00604 #ifdef BIGBAD_IODBG
00605               int rv = 0;
00606               char fn [SIZ];
00607               FILE *fd;
00608               
00609               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00610                      
00611               fd = fopen(fn, "a+");
00612               fprintf(fd, "Reading BLOB: BufSize: %d ",
00613                      bytes);
00614               rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
00615               fprintf(fd, "]\n");
00616               
00617                      
00618               fclose(fd);
00619 #endif
00620               retval = StrBufReadBLOBBuffered(Target, 
00621                                           CCC->RecvBuf.Buf,
00622                                           &CCC->RecvBuf.ReadWritePointer,
00623                                           &CCC->client_socket,
00624                                           1, 
00625                                           bytes,
00626                                           O_TERM,
00627                                           &Error);
00628               if (retval < 0) {
00629                      syslog(LOG_CRIT, "client_read_blob() failed: %s", Error);
00630                      client_close();
00631                      return retval;
00632               }
00633 #ifdef BIGBAD_IODBG
00634               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00635               
00636               fd = fopen(fn, "a+");
00637               fprintf(fd, "Read: %d BufContent: [",
00638                      StrLength(Target));
00639               rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
00640               fprintf(fd, "]\n");
00641               fclose(fd);
00642 #endif
00643        }
00644        return retval;
00645 }
00646 
00647 
00648 /*
00649  * to make client_read_random_blob() more efficient, increase buffer size.
00650  * just use in greeting function, else your buffer may be flushed
00651  */
00652 void client_set_inbound_buf(long N)
00653 {
00654        CitContext *CCC=CC;
00655        FlushStrBuf(CCC->RecvBuf.Buf);
00656        ReAdjustEmptyBuf(CCC->RecvBuf.Buf, N * SIZ, N * SIZ);
00657 }
00658 
00659 int client_read_random_blob(StrBuf *Target, int timeout)
00660 {
00661        CitContext *CCC=CC;
00662        int rc;
00663 
00664        rc =  client_read_blob(Target, 1, timeout);
00665        if (rc > 0)
00666        {
00667               long len;
00668               const char *pch;
00669               
00670               len = StrLength(CCC->RecvBuf.Buf);
00671               pch = ChrPtr(CCC->RecvBuf.Buf);
00672 
00673               if (len > 0)
00674               {
00675                      if (CCC->RecvBuf.ReadWritePointer != NULL) {
00676                             len -= CCC->RecvBuf.ReadWritePointer - pch;
00677                             pch = CCC->RecvBuf.ReadWritePointer;
00678                      }
00679                      StrBufAppendBufPlain(Target, pch, len, 0);
00680                      FlushStrBuf(CCC->RecvBuf.Buf);
00681                      CCC->RecvBuf.ReadWritePointer = NULL;
00682 #ifdef BIGBAD_IODBG
00683                      {
00684                             int rv = 0;
00685                             char fn [SIZ];
00686                             FILE *fd;
00687                      
00688                             snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00689                      
00690                             fd = fopen(fn, "a+");
00691                             fprintf(fd, "Read: BufSize: %d BufContent: [",
00692                                    StrLength(Target));
00693                             rv = fwrite(ChrPtr(Target), StrLength(Target), 1, fd);
00694                             fprintf(fd, "]\n");
00695                      
00696                      
00697                             fclose(fd);
00698                      }
00699 #endif
00700        
00701                      return StrLength(Target);
00702               }
00703               return rc;
00704        }
00705        else
00706               return rc;
00707 }
00708 
00709 int client_read_to(char *buf, int bytes, int timeout)
00710 {
00711        CitContext *CCC=CC;
00712        int rc;
00713 
00714        rc = client_read_blob(CCC->MigrateBuf, bytes, timeout);
00715        if (rc < 0)
00716        {
00717               *buf = '\0';
00718               return rc;
00719        }
00720        else
00721        {
00722               memcpy(buf, 
00723                      ChrPtr(CCC->MigrateBuf),
00724                      StrLength(CCC->MigrateBuf) + 1);
00725               FlushStrBuf(CCC->MigrateBuf);
00726               return rc;
00727        }
00728 }
00729 
00730 
00731 int HaveMoreLinesWaiting(CitContext *CCC)
00732 {
00733        if ((CCC->kill_me != 0) ||
00734            ( (CCC->RecvBuf.ReadWritePointer == NULL) && 
00735              (StrLength(CCC->RecvBuf.Buf) == 0) && 
00736              (CCC->client_socket != -1)) )
00737               return 0;
00738        else
00739               return 1;
00740 }
00741 
00742 
00743 /*
00744  * Read data from the client socket with default timeout.
00745  * (This is implemented in terms of client_read_to() and could be
00746  * justifiably moved out of sysdep.c)
00747  */
00748 INLINE int client_read(char *buf, int bytes)
00749 {
00750        return(client_read_to(buf, bytes, config.c_sleeping));
00751 }
00752 
00753 int CtdlClientGetLine(StrBuf *Target)
00754 {
00755        CitContext *CCC=CC;
00756        const char *Error;
00757        int rc;
00758 
00759        FlushStrBuf(Target);
00760 #ifdef HAVE_OPENSSL
00761        if (CCC->redirect_ssl) {
00762 #ifdef BIGBAD_IODBG
00763               char fn [SIZ];
00764               FILE *fd;
00765               int len = 0;
00766               int rlen = 0;
00767               int  nlen = 0;
00768               int nrlen = 0;
00769               const char *pch;
00770 
00771               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00772 
00773               fd = fopen(fn, "a+");
00774               pch = ChrPtr(CCC->RecvBuf.Buf);
00775               len = StrLength(CCC->RecvBuf.Buf);
00776               if (CCC->RecvBuf.ReadWritePointer != NULL)
00777                      rlen = CCC->RecvBuf.ReadWritePointer - pch;
00778               else
00779                      rlen = 0;
00780 
00781 /*            fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \nBufContent: [%s]\n\n_____________________\n",
00782                      len, rlen, pch);
00783 */
00784               fprintf(fd, "\n\n\nSSL1: BufSize: %d BufPos: %d \n_____________________\n",
00785                      len, rlen);
00786 #endif
00787               rc = client_readline_sslbuffer(Target,
00788                                           CCC->RecvBuf.Buf,
00789                                           &CCC->RecvBuf.ReadWritePointer,
00790                                           1);
00791 #ifdef BIGBAD_IODBG
00792                 pch = ChrPtr(CCC->RecvBuf.Buf);
00793                 nlen = StrLength(CCC->RecvBuf.Buf);
00794                 if (CCC->RecvBuf.ReadWritePointer != NULL)
00795                         nrlen = CCC->RecvBuf.ReadWritePointer - pch;
00796                 else
00797                         nrlen = 0;
00798 /*
00799                 fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \nBufContent: [%s]\n\n_____________________\n",
00800                         len, nlen, rlen, nrlen, pch);
00801 */
00802                 fprintf(fd, "\n\n\nSSL2: BufSize: was: %d is: %d BufPos: was: %d is: %d \n",
00803                         len, nlen, rlen, nrlen);
00804 
00805                 fprintf(fd, "SSL3: Read: BufSize: %d BufContent: [%s]\n\n*************\n",
00806                         StrLength(Target), ChrPtr(Target));
00807                 fclose(fd);
00808 
00809               if (rc < 0) {
00810                      syslog(LOG_CRIT, "CtdlClientGetLine() failed");
00811               }
00812 #endif
00813               return rc;
00814        }
00815        else 
00816 #endif
00817        {
00818 #ifdef BIGBAD_IODBG
00819               char fn [SIZ];
00820               FILE *fd;
00821               int len, rlen, nlen, nrlen;
00822               const char *pch;
00823 
00824               snprintf(fn, SIZ, "/tmp/foolog_%s.%d", CCC->ServiceName, CCC->cs_pid);
00825 
00826               fd = fopen(fn, "a+");
00827               pch = ChrPtr(CCC->RecvBuf.Buf);
00828               len = StrLength(CCC->RecvBuf.Buf);
00829               if (CCC->RecvBuf.ReadWritePointer != NULL)
00830                      rlen = CCC->RecvBuf.ReadWritePointer - pch;
00831               else
00832                      rlen = 0;
00833 
00834 /*            fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \nBufContent: [%s]\n\n_____________________\n",
00835                      len, rlen, pch);
00836 */
00837               fprintf(fd, "\n\n\nBufSize: %d BufPos: %d \n_____________________\n",
00838                      len, rlen);
00839 #endif
00840               rc = StrBufTCP_read_buffered_line_fast(Target, 
00841                                                  CCC->RecvBuf.Buf,
00842                                                  &CCC->RecvBuf.ReadWritePointer,
00843                                                  &CCC->client_socket,
00844                                                  5,
00845                                                  1,
00846                                                  &Error);
00847 
00848 #ifdef BIGBAD_IODBG
00849                 pch = ChrPtr(CCC->RecvBuf.Buf);
00850                 nlen = StrLength(CCC->RecvBuf.Buf);
00851                 if (CCC->RecvBuf.ReadWritePointer != NULL)
00852                         nrlen = CCC->RecvBuf.ReadWritePointer - pch;
00853                 else
00854                         nrlen = 0;
00855 /*
00856                 fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \nBufContent: [%s]\n\n_____________________\n",
00857                         len, nlen, rlen, nrlen, pch);
00858 */
00859                 fprintf(fd, "\n\n\nBufSize: was: %d is: %d BufPos: was: %d is: %d \n",
00860                         len, nlen, rlen, nrlen);
00861 
00862                 fprintf(fd, "Read: BufSize: %d BufContent: [%s]\n\n*************\n",
00863                         StrLength(Target), ChrPtr(Target));
00864                 fclose(fd);
00865 
00866               if ((rc < 0) && (Error != NULL)) {
00867                      syslog(LOG_CRIT, "CtdlClientGetLine() failed: %s", Error);
00868               }
00869 #endif
00870               return rc;
00871        }
00872 }
00873 
00874 
00875 /*
00876  * client_getln()   ...   Get a LF-terminated line of text from the client.
00877  * (This is implemented in terms of client_read() and could be
00878  * justifiably moved out of sysdep.c)
00879  */
00880 int client_getln(char *buf, int bufsize)
00881 {
00882        int i, retval;
00883        CitContext *CCC=CC;
00884        const char *pCh;
00885 
00886        retval = CtdlClientGetLine(CCC->MigrateBuf);
00887        if (retval < 0)
00888          return(retval >= 0);
00889 
00890 
00891        i = StrLength(CCC->MigrateBuf);
00892        pCh = ChrPtr(CCC->MigrateBuf);
00893        /* Strip the trailing LF, and the trailing CR if present.
00894         */
00895        if (bufsize <= i)
00896               i = bufsize - 1;
00897        while ( (i > 0)
00898               && ( (pCh[i - 1]==13)
00899                    || ( pCh[i - 1]==10)) ) {
00900               i--;
00901        }
00902        memcpy(buf, pCh, i);
00903        buf[i] = 0;
00904 
00905        FlushStrBuf(CCC->MigrateBuf);
00906        if (retval < 0) {
00907               safestrncpy(&buf[i], "000", bufsize - i);
00908        }
00909        return(retval >= 0);
00910 }
00911 
00912 
00913 /*
00914  * Cleanup any contexts that are left lying around
00915  */
00916 
00917 
00918 void close_masters (void)
00919 {
00920        struct ServiceFunctionHook *serviceptr;
00921        
00922        /*
00923         * close all protocol master sockets
00924         */
00925        for (serviceptr = ServiceHookTable; serviceptr != NULL;
00926            serviceptr = serviceptr->next ) {
00927 
00928               if (serviceptr->tcp_port > 0)
00929               {
00930                      syslog(LOG_INFO, "Closing %d listener on port %d\n",
00931                             serviceptr->msock,
00932                             serviceptr->tcp_port);
00933                      serviceptr->tcp_port = 0;
00934               }
00935               
00936               if (serviceptr->sockpath != NULL)
00937                      syslog(LOG_INFO, "Closing %d listener on '%s'\n",
00938                             serviceptr->msock,
00939                             serviceptr->sockpath);
00940                 if (serviceptr->msock != -1)
00941                      close(serviceptr->msock);
00942               /* If it's a Unix domain socket, remove the file. */
00943               if (serviceptr->sockpath != NULL) {
00944                      unlink(serviceptr->sockpath);
00945                      serviceptr->sockpath = NULL;
00946               }
00947        }
00948 }
00949 
00950 
00951 /*
00952  * The system-dependent part of master_cleanup() - close the master socket.
00953  */
00954 void sysdep_master_cleanup(void) {
00955        
00956        close_masters();
00957        
00958        context_cleanup();
00959        
00960 #ifdef HAVE_OPENSSL
00961        destruct_ssl();
00962 #endif
00963        CtdlDestroyProtoHooks();
00964        CtdlDestroyDeleteHooks();
00965        CtdlDestroyXmsgHooks();
00966        CtdlDestroyNetprocHooks();
00967        CtdlDestroyUserHooks();
00968        CtdlDestroyMessageHook();
00969        CtdlDestroyCleanupHooks();
00970        CtdlDestroyFixedOutputHooks();     
00971        CtdlDestroySessionHooks();
00972        CtdlDestroyServiceHook();
00973        CtdlDestroyRoomHooks();
00974        CtdlDestroySearchHooks();
00975        CtdlDestroyDebugTable();
00976        #ifdef HAVE_BACKTRACE
00977 
00978        #endif
00979 }
00980 
00981 
00982 
00983 pid_t current_child;
00984 void graceful_shutdown(int signum) {
00985        kill(current_child, signum);
00986        unlink(file_pid_file);
00987        exit(0);
00988 }
00989 
00990 int nFireUps = 0;
00991 int nFireUpsNonRestart = 0;
00992 pid_t ForkedPid = 1;
00993 
00994 /*
00995  * Start running as a daemon.
00996  */
00997 void start_daemon(int unused) {
00998        int status = 0;
00999        pid_t child = 0;
01000        FILE *fp;
01001        int do_restart = 0;
01002 
01003        current_child = 0;
01004 
01005        /* Close stdin/stdout/stderr and replace them with /dev/null.
01006         * We don't just call close() because we don't want these fd's
01007         * to be reused for other files.
01008         */
01009        if (chdir(ctdl_run_dir) != 0)
01010               syslog(LOG_EMERG, 
01011                            "unable to change into directory [%s]: %s", 
01012                            ctdl_run_dir, strerror(errno));
01013 
01014        child = fork();
01015        if (child != 0) {
01016               exit(0);
01017        }
01018        
01019        signal(SIGHUP, SIG_IGN);
01020        signal(SIGINT, SIG_IGN);
01021        signal(SIGQUIT, SIG_IGN);
01022 
01023        setsid();
01024        umask(0);
01025         if ((freopen("/dev/null", "r", stdin) != stdin) || 
01026            (freopen("/dev/null", "w", stdout) != stdout) || 
01027            (freopen("/dev/null", "w", stderr) != stderr))
01028               syslog(LOG_EMERG, 
01029                            "unable to reopen stdin/out/err %s", 
01030                            strerror(errno));
01031               
01032 
01033        do {
01034               current_child = fork();
01035 
01036               signal(SIGTERM, graceful_shutdown);
01037        
01038               if (current_child < 0) {
01039                      perror("fork");
01040                      exit(errno);
01041               }
01042        
01043               else if (current_child == 0) {
01044                      return; /* continue starting citadel. */
01045               }
01046        
01047               else {
01048                      fp = fopen(file_pid_file, "w");
01049                      if (fp != NULL) {
01050                             fprintf(fp, ""F_PID_T"\n", getpid());
01051                             fclose(fp);
01052                      }
01053                      waitpid(current_child, &status, 0);
01054               }
01055 
01056               nFireUpsNonRestart = nFireUps;
01057               
01058               /* Exit code 0 means the watcher should exit */
01059               if (WIFEXITED(status) && (WEXITSTATUS(status) == CTDLEXIT_SHUTDOWN)) {
01060                      do_restart = 0;
01061               }
01062 
01063               /* Exit code 101-109 means the watcher should exit */
01064               else if (WIFEXITED(status) && (WEXITSTATUS(status) >= 101) && (WEXITSTATUS(status) <= 109)) {
01065                      do_restart = 0;
01066               }
01067 
01068               /* Any other exit code, or no exit code, means we should restart. */
01069               else {
01070                      do_restart = 1;
01071                      nFireUps++;
01072                      ForkedPid = current_child;
01073               }
01074 
01075        } while (do_restart);
01076 
01077        unlink(file_pid_file);
01078        exit(WEXITSTATUS(status));
01079 }
01080 
01081 
01082 
01083 void checkcrash(void)
01084 {
01085        if (nFireUpsNonRestart != nFireUps)
01086        {
01087               StrBuf *CrashMail;
01088 
01089               CrashMail = NewStrBuf();
01090               syslog(LOG_ALERT, "Posting crash message\n");
01091               StrBufPrintf(CrashMail, 
01092                      " \n"
01093                      " The Citadel server process (citserver) terminated unexpectedly."
01094                      "\n \n"
01095                      " This could be the result of a bug in the server program, or some external "
01096                      "factor.\n \n"
01097                      " You can obtain more information about this by enabling core dumps.\n \n"
01098                      " For more information, please see:\n \n"
01099                      " http://citadel.org/doku.php?id=faq:mastering_your_os:gdb#how.do.i.make.my.system.produce.core-files"
01100                      "\n \n"
01101 
01102                      " If you have already done this, the core dump is likely to be found at %score.%d\n"
01103                      ,
01104                      ctdl_run_dir, ForkedPid);
01105               CtdlAideMessage(ChrPtr(CrashMail), "Citadel server process terminated unexpectedly");
01106               FreeStrBuf(&CrashMail);
01107        }
01108 }
01109 
01110 
01111 /*
01112  * Generic routine to convert a login name to a full name (gecos)
01113  * Returns nonzero if a conversion took place
01114  */
01115 int convert_login(char NameToConvert[]) {
01116        struct passwd *pw;
01117        int a;
01118 
01119        pw = getpwnam(NameToConvert);
01120        if (pw == NULL) {
01121               return(0);
01122        }
01123        else {
01124               strcpy(NameToConvert, pw->pw_gecos);
01125               for (a=0; a<strlen(NameToConvert); ++a) {
01126                      if (NameToConvert[a] == ',') NameToConvert[a] = 0;
01127               }
01128               return(1);
01129        }
01130 }
01131 
01132 
01133 
01134 /* 
01135  * This loop just keeps going and going and going...
01136  */
01137 void *worker_thread(void *blah) {
01138        int highest;
01139        CitContext *ptr;
01140        CitContext *bind_me = NULL;
01141        fd_set readfds;
01142        int retval = 0;
01143        struct timeval tv;
01144        int force_purge = 0;
01145        struct ServiceFunctionHook *serviceptr;
01146        int ssock;                      /* Descriptor for client socket */
01147        CitContext *con = NULL;         /* Temporary context pointer */
01148        int i;
01149 
01150        ++num_workers;
01151 
01152        while (!server_shutting_down) {
01153 
01154               /* make doubly sure we're not holding any stale db handles
01155                * which might cause a deadlock.
01156                */
01157               cdb_check_handles();
01158 do_select:    force_purge = 0;
01159               bind_me = NULL;             /* Which session shall we handle? */
01160 
01161               /* Initialize the fdset. */
01162               FD_ZERO(&readfds);
01163               highest = 0;
01164 
01165               /* First, add the various master sockets to the fdset. */
01166               for (serviceptr = ServiceHookTable; serviceptr != NULL; serviceptr = serviceptr->next ) {
01167                      FD_SET(serviceptr->msock, &readfds);
01168                      if (serviceptr->msock > highest) {
01169                             highest = serviceptr->msock;
01170                      }
01171               }
01172 
01173               /* Next, add all of the client sockets. */
01174               begin_critical_section(S_SESSION_TABLE);
01175               for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
01176                      if ((ptr->state == CON_SYS) && (ptr->client_socket == 0))
01177                          continue;
01178 
01179                      /* Don't select on dead sessions, only truly idle ones */
01180                      if (   (ptr->state == CON_IDLE)
01181                             && (ptr->kill_me == 0)
01182                             && (ptr->client_socket > 0)
01183                      ) {
01184                             FD_SET(ptr->client_socket, &readfds);
01185                             if (ptr->client_socket > highest)
01186                                    highest = ptr->client_socket;
01187                      }
01188                      if ((bind_me == NULL) && (ptr->state == CON_READY)) {
01189                             bind_me = ptr;
01190                             ptr->state = CON_EXECUTING;
01191                             break;
01192                      }
01193                      if ((bind_me == NULL) && (ptr->state == CON_GREETING)) {
01194                             bind_me = ptr;
01195                             ptr->state = CON_STARTING;
01196                             break;
01197                      }
01198               }
01199               end_critical_section(S_SESSION_TABLE);
01200 
01201               if (bind_me) {
01202                      goto SKIP_SELECT;
01203               }
01204 
01205               /* If we got this far, it means that there are no sessions
01206                * which a previous thread marked for attention, so we go
01207                * ahead and get ready to select().
01208                */
01209 
01210               if (!server_shutting_down) {
01211                      tv.tv_sec = 1;              /* wake up every second if no input */
01212                      tv.tv_usec = 0;
01213                      retval = select(highest + 1, &readfds, NULL, NULL, &tv);
01214               }
01215               else {
01216                      --num_workers;
01217                      return NULL;
01218               }
01219 
01220               /* Now figure out who made this select() unblock.
01221                * First, check for an error or exit condition.
01222                */
01223               if (retval < 0) {
01224                      if (errno == EBADF) {
01225                             syslog(LOG_NOTICE, "select() failed: (%s)\n", strerror(errno));
01226                             goto do_select;
01227                      }
01228                      if (errno != EINTR) {
01229                             syslog(LOG_EMERG, "Exiting (%s)\n", strerror(errno));
01230                             server_shutting_down = 1;
01231                             continue;
01232                      } else {
01233 #if 0
01234                             syslog(LOG_DEBUG, "Interrupted select()\n");
01235 #endif
01236                             if (server_shutting_down) {
01237                                    --num_workers;
01238                                    return(NULL);
01239                             }
01240                             goto do_select;
01241                      }
01242               }
01243               else if (retval == 0) {
01244                      if (server_shutting_down) {
01245                             --num_workers;
01246                             return(NULL);
01247                      }
01248               }
01249 
01250               /* Next, check to see if it's a new client connecting * on a master socket. */
01251 
01252               else if ((retval > 0) && (!server_shutting_down)) for (serviceptr = ServiceHookTable; serviceptr != NULL; serviceptr = serviceptr->next) {
01253 
01254                      if (FD_ISSET(serviceptr->msock, &readfds)) {
01255                             ssock = accept(serviceptr->msock, NULL, 0);
01256                             if (ssock >= 0) {
01257                                    syslog(LOG_DEBUG, "New client socket %d", ssock);
01258 
01259                                    /* The master socket is non-blocking but the client
01260                                     * sockets need to be blocking, otherwise certain
01261                                     * operations barf on FreeBSD.  Not a fatal error.
01262                                     */
01263                                    if (fcntl(ssock, F_SETFL, 0) < 0) {
01264                                           syslog(LOG_EMERG,
01265                                                  "citserver: Can't set socket to blocking: %s\n",
01266                                                  strerror(errno));
01267                                    }
01268 
01269                                    /* New context will be created already
01270                                     * set up in the CON_EXECUTING state.
01271                                     */
01272                                    con = CreateNewContext();
01273 
01274                                    /* Assign our new socket number to it. */
01275                                    con->tcp_port = serviceptr->tcp_port;
01276                                    con->client_socket = ssock;
01277                                    con->h_command_function = serviceptr->h_command_function;
01278                                    con->h_async_function = serviceptr->h_async_function;
01279                                    con->h_greeting_function = serviceptr->h_greeting_function;
01280                                    con->ServiceName = serviceptr->ServiceName;
01281                                    
01282                                    /* Determine whether it's a local socket */
01283                                    if (serviceptr->sockpath != NULL) {
01284                                           con->is_local_socket = 1;
01285                                    }
01286        
01287                                    /* Set the SO_REUSEADDR socket option */
01288                                    i = 1;
01289                                    setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
01290                                    con->state = CON_GREETING;
01291                                    retval--;
01292                                    if (retval == 0)
01293                                           break;
01294                             }
01295                      }
01296               }
01297 
01298               /* It must be a client socket.  Find a context that has data
01299                * waiting on its socket *and* is in the CON_IDLE state.  Any
01300                * active sockets other than our chosen one are marked as
01301                * CON_READY so the next thread that comes around can just bind
01302                * to one without having to select() again.
01303                */
01304               begin_critical_section(S_SESSION_TABLE);
01305               for (ptr = ContextList; ptr != NULL; ptr = ptr->next) {
01306                      int checkfd = ptr->client_socket;
01307                      if ((checkfd != -1) && (ptr->state == CON_IDLE) ){
01308                             if (FD_ISSET(checkfd, &readfds)) {
01309                                    ptr->input_waiting = 1;
01310                                    if (!bind_me) {
01311                                           bind_me = ptr;       /* I choose you! */
01312                                           bind_me->state = CON_EXECUTING;
01313                                    }
01314                                    else {
01315                                           ptr->state = CON_READY;
01316                                    }
01317                             } else if ((ptr->is_async) && (ptr->async_waiting) && (ptr->h_async_function)) {
01318                                    if (!bind_me) {
01319                                           bind_me = ptr;       /* I choose you! */
01320                                           bind_me->state = CON_EXECUTING;
01321                                    }
01322                                    else {
01323                                           ptr->state = CON_READY;
01324                                    }
01325                             }
01326                      }
01327               }
01328               end_critical_section(S_SESSION_TABLE);
01329 
01330 SKIP_SELECT:
01331               /* We're bound to a session */
01332               ++active_workers;
01333               if (bind_me != NULL) {
01334                      become_session(bind_me);
01335 
01336                      if (bind_me->state == CON_STARTING) {
01337                             bind_me->state = CON_EXECUTING;
01338                             begin_session(bind_me);
01339                             bind_me->h_greeting_function();
01340                      }
01341                      /* If the client has sent a command, execute it. */
01342                      if (CC->input_waiting) {
01343                             CC->h_command_function();
01344 
01345                             while (HaveMoreLinesWaiting(CC))
01346                                    CC->h_command_function();
01347 
01348                             CC->input_waiting = 0;
01349                      }
01350 
01351                      /* If there are asynchronous messages waiting and the
01352                       * client supports it, do those now */
01353                      if ((CC->is_async) && (CC->async_waiting)
01354                         && (CC->h_async_function != NULL)) {
01355                             CC->h_async_function();
01356                             CC->async_waiting = 0;
01357                      }
01358                      
01359                      force_purge = CC->kill_me;
01360                      become_session(NULL);
01361                      bind_me->state = CON_IDLE;
01362               }
01363 
01364               dead_session_purge(force_purge);
01365               do_housekeeping();
01366               --active_workers;
01367        }
01368 
01369        /* If control reaches this point, the server is shutting down */
01370        --num_workers;
01371        return(NULL);
01372 }
01373 
01374 
01375 
01376 /*
01377  * SyslogFacility()
01378  * Translate text facility name to syslog.h defined value.
01379  */
01380 int SyslogFacility(char *name)
01381 {
01382        int i;
01383        struct
01384        {
01385               int facility;
01386               char *name;
01387        }   facTbl[] =
01388        {
01389               {   LOG_KERN,   "kern"             },
01390               {   LOG_USER,   "user"             },
01391               {   LOG_MAIL,   "mail"             },
01392               {   LOG_DAEMON, "daemon"    },
01393               {   LOG_AUTH,   "auth"             },
01394               {   LOG_SYSLOG, "syslog"    },
01395               {   LOG_LPR,  "lpr"         },
01396               {   LOG_NEWS,   "news"             },
01397               {   LOG_UUCP,   "uucp"             },
01398               {   LOG_LOCAL0, "local0"    },
01399               {   LOG_LOCAL1, "local1"    },
01400               {   LOG_LOCAL2, "local2"    },
01401               {   LOG_LOCAL3, "local3"    },
01402               {   LOG_LOCAL4, "local4"    },
01403               {   LOG_LOCAL5, "local5"    },
01404               {   LOG_LOCAL6, "local6"    },
01405               {   LOG_LOCAL7, "local7"    },
01406               {   0,          NULL        }
01407        };
01408        for(i = 0; facTbl[i].name != NULL; i++) {
01409               if(!strcasecmp(name, facTbl[i].name))
01410                      return facTbl[i].facility;
01411        }
01412        return LOG_DAEMON;
01413 }