Back to index

webcit  8.12-dfsg
webserver.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-2012 by the citadel.org team
00003  *
00004  * This program is open source software.  You can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License version 3.
00006  *
00007  * This program is distributed in the hope that it will be useful,
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  * GNU General Public License for more details.
00011  */
00012 
00013 #include "webcit.h"
00014 #include "webserver.h"
00015 
00016 #include "modules_init.h"
00017 #ifndef HAVE_SNPRINTF
00018 int vsnprintf(char *buf, size_t max, const char *fmt, va_list argp);
00019 #endif
00020 
00021 extern int msock;                         /* master listening socket */
00022 extern char static_icon_dir[PATH_MAX];          /* where should we find our mime icons */
00023 int is_https = 0;                         /* Nonzero if I am an HTTPS service */
00024 int follow_xff = 0;                       /* Follow X-Forwarded-For: header? */
00025 int DisableGzip = 0;
00026 char *default_landing_page = NULL;
00027 extern pthread_mutex_t SessionListMutex;
00028 extern pthread_key_t MyConKey;
00029 
00030 extern void *housekeeping_loop(void);
00031 extern int webcit_tcp_server(char *ip_addr, int port_number, int queue_len);
00032 extern int webcit_uds_server(char *sockpath, int queue_len);
00033 extern void graceful_shutdown_watcher(int signum);
00034 extern void graceful_shutdown(int signum);
00035 extern void start_daemon(char *pid_file);
00036 extern void webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome);
00037 extern void worker_entry(void);
00038 extern void drop_root(uid_t UID);
00039 
00040 char socket_dir[PATH_MAX];  /* where to talk to our citadel server */
00041 char *server_cookie = NULL; /* our Cookie connection to the client */
00042 int http_port = PORT_NUM;   /* Port to listen on */
00043 char *ctdlhost = DEFAULT_HOST;     /* Host name or IP address of Citadel server */
00044 char *ctdlport = DEFAULT_PORT;     /* Port number of Citadel server */
00045 int setup_wizard = 0;              /* should we run the setup wizard? */
00046 char wizard_filename[PATH_MAX];    /* location of file containing the last webcit version against which we ran setup wizard */
00047 int running_as_daemon = 0;  /* should we deamonize on startup? */
00048 
00049 /* #define DBG_PRINNT_HOOKS_AT_START */
00050 #ifdef DBG_PRINNT_HOOKS_AT_START
00051 extern HashList *HandlerHash;
00052 const char foobuf[32];
00053 const char *nix(void *vptr) {snprintf(foobuf, 32, "%0x", (long) vptr); return foobuf;}
00054 #endif 
00055 extern int dbg_analyze_msg;
00056 extern int dbg_backtrace_template_errors;
00057 extern int DumpTemplateI18NStrings;
00058 extern StrBuf *I18nDump;
00059 void InitTemplateCache(void);
00060 extern int LoadTemplates;
00061 
00062 
00063 /*
00064  * Here's where it all begins.
00065  */
00066 int main(int argc, char **argv)
00067 {
00068        uid_t UID = -1;
00069        size_t basesize = 2;            /* how big should strbufs be on creation? */
00070        pthread_t SessThread;              /* Thread descriptor */
00071        pthread_attr_t attr;        /* Thread attributes */
00072        int a;                      /* General-purpose variable */
00073        char ip_addr[256]="*";
00074        int relh=0;
00075        int home=0;
00076        char relhome[PATH_MAX]="";
00077        char webcitdir[PATH_MAX] = DATADIR;
00078        char *pidfile = NULL;
00079        char *hdir;
00080        const char *basedir = NULL;
00081        char uds_listen_path[PATH_MAX];    /* listen on a unix domain socket? */
00082        const char *I18nDumpFile = NULL;
00083 
00084        WildFireInitBacktrace(argv[0], 2);
00085 
00086        start_modules();
00087 
00088 #ifdef DBG_PRINNT_HOOKS_AT_START
00089 /*     dbg_PrintHash(HandlerHash, nix, NULL);*/
00090 #endif
00091 
00092        /* Ensure that we are linked to the correct version of libcitadel */
00093        if (libcitadel_version_number() < LIBCITADEL_VERSION_NUMBER) {
00094               fprintf(stderr, " You are running libcitadel version %d.%02d\n",
00095                      (libcitadel_version_number() / 100), (libcitadel_version_number() % 100));
00096               fprintf(stderr, "WebCit was compiled against version %d.%02d\n",
00097                      (LIBCITADEL_VERSION_NUMBER / 100), (LIBCITADEL_VERSION_NUMBER % 100));
00098               return(1);
00099        }
00100 
00101        strcpy(uds_listen_path, "");
00102 
00103        /* Parse command line */
00104 #ifdef HAVE_OPENSSL
00105        while ((a = getopt(argc, argv, "u:h:i:p:t:T:B:x:g:dD:G:cfsS:Z")) != EOF)
00106 #else
00107        while ((a = getopt(argc, argv, "u:h:i:p:t:T:B:x:g:dD:G:cfZ")) != EOF)
00108 #endif
00109               switch (a) {
00110               case 'u':
00111                      UID = atol(optarg);
00112                      break;
00113               case 'h':
00114                      hdir = strdup(optarg);
00115                      relh=hdir[0]!='/';
00116                      if (!relh) {
00117                             safestrncpy(webcitdir, hdir, sizeof webcitdir);
00118                      }
00119                      else {
00120                             safestrncpy(relhome, relhome, sizeof relhome);
00121                      }
00122                      /* free(hdir); TODO: SHOULD WE DO THIS? */
00123                      home=1;
00124                      break;
00125               case 'd':
00126                      running_as_daemon = 1;
00127                      break;
00128               case 'D':
00129                      pidfile = strdup(optarg);
00130                      running_as_daemon = 1;
00131                      break;
00132               case 'g':
00133                      default_landing_page = strdup(optarg);
00134                      break;
00135               case 'B': /* Basesize */
00136                      basesize = atoi(optarg);
00137                      if (basesize > 2)
00138                             StartLibCitadel(basesize);
00139                      break;
00140               case 'i':
00141                      safestrncpy(ip_addr, optarg, sizeof ip_addr);
00142                      break;
00143               case 'p':
00144                      http_port = atoi(optarg);
00145                      if (http_port == 0) {
00146                             safestrncpy(uds_listen_path, optarg, sizeof uds_listen_path);
00147                      }
00148                      break;
00149               case 't':
00150                      /* no longer used, but ignored so old scripts don't break */
00151                      break;
00152               case 'T':
00153                      LoadTemplates = atoi(optarg);
00154                      dbg_analyze_msg = (LoadTemplates && (1<<1)) != 0;
00155                      dbg_backtrace_template_errors = (LoadTemplates && (1<<2)) != 0;
00156                      break;
00157               case 'Z':
00158                      DisableGzip = 1;
00159                      break;
00160               case 'x':
00161                      /* no longer used, but ignored so old scripts don't break */
00162                      break;
00163               case 'f':
00164                      follow_xff = 1;
00165                      break;
00166               case 'c':
00167                      server_cookie = malloc(256);
00168                      if (server_cookie != NULL) {
00169                             safestrncpy(server_cookie,
00170                                    "Set-cookie: wcserver=",
00171                                    256);
00172                             if (gethostname
00173                                 (&server_cookie[strlen(server_cookie)],
00174                                  200) != 0) {
00175                                    syslog(2, "gethostname: %s", strerror(errno));
00176                                    free(server_cookie);
00177                             }
00178                      }
00179                      break;
00180 #ifdef HAVE_OPENSSL
00181               case 's':
00182                      is_https = 1;
00183                      break;
00184               case 'S':
00185                      is_https = 1;
00186                      ssl_cipher_list = strdup(optarg);
00187                      break;
00188 #endif
00189               case 'G':
00190                      DumpTemplateI18NStrings = 1;
00191                      I18nDump = NewStrBufPlain(HKEY("int templatestrings(void)\n{\n"));
00192                      I18nDumpFile = optarg;
00193                      break;
00194               default:
00195                      fprintf(stderr, "usage: webcit "
00196                             "[-i ip_addr] [-p http_port] "
00197                             "[-c] [-f] "
00198                             "[-T Templatedebuglevel] "
00199                             "[-d] [-Z] [-G i18ndumpfile] "
00200 #ifdef HAVE_OPENSSL
00201                             "[-s] [-S cipher_suites]"
00202 #endif
00203                             "[remotehost [remoteport]]\n");
00204                      return 1;
00205               }
00206 
00207        /* Start the logger */
00208        openlog("webcit",
00209               ( running_as_daemon ? (LOG_PID) : (LOG_PID | LOG_PERROR) ),
00210               LOG_DAEMON
00211        );
00212 
00213        if (optind < argc) {
00214               ctdlhost = argv[optind];
00215               if (++optind < argc)
00216                      ctdlport = argv[optind];
00217        }
00218 
00219        /* daemonize, if we were asked to */
00220        if (!DumpTemplateI18NStrings && running_as_daemon) {
00221               start_daemon(pidfile);
00222        }
00223        else {
00224               signal(SIGINT, graceful_shutdown);
00225               signal(SIGHUP, graceful_shutdown);
00226        }
00227 
00228        webcit_calc_dirs_n_files(relh, basedir, home, webcitdir, relhome);
00229        LoadIconDir(static_icon_dir);
00230 
00231        /* Tell 'em who's in da house */
00232        syslog(1, "%s", PACKAGE_STRING);
00233        syslog(1, "Copyright (C) 1996-2012 by the citadel.org team");
00234        syslog(1, " ");
00235        syslog(1, "This program is open source software: you can redistribute it and/or");
00236        syslog(1, "modify it under the terms of the GNU General Public License, version 3.");
00237        syslog(1, " ");
00238        syslog(1, "This program is distributed in the hope that it will be useful,");
00239        syslog(1, "but WITHOUT ANY WARRANTY; without even the implied warranty of");
00240        syslog(1, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the");
00241        syslog(1, "GNU General Public License for more details.");
00242        syslog(1, " ");
00243 
00244        /* initialize various subsystems */
00245 
00246        initialise_modules();
00247        initialise2_modules();
00248        InitTemplateCache();
00249        if (DumpTemplateI18NStrings) {
00250               FILE *fd;
00251               StrBufAppendBufPlain(I18nDump, HKEY("}\n"), 0);
00252                if (StrLength(I18nDump) < 50) {
00253                      syslog(1, "*******************************************************************\n");
00254                      syslog(1, "*   No strings found in templates!  Are you sure they're there?   *\n");
00255                      syslog(1, "*******************************************************************\n");
00256                      return -1;
00257               }
00258               fd = fopen(I18nDumpFile, "w");
00259                if (fd == NULL) {
00260                      syslog(1, "***********************************************\n");
00261                      syslog(1, "*   unable to open I18N dumpfile [%s]         *\n", I18nDumpFile);
00262                      syslog(1, "***********************************************\n");
00263                      return -1;
00264               }
00265               fwrite(ChrPtr(I18nDump), 1, StrLength(I18nDump), fd);
00266               fclose(fd);
00267               return 0;
00268        }
00269 
00270        /* Tell libical to return an error instead of aborting if it sees badly formed iCalendar data. */
00271        icalerror_errors_are_fatal = 0;
00272 
00273        /* Use our own prefix on tzid's generated from system tzdata */
00274        icaltimezone_set_tzid_prefix("/citadel.org/");
00275 
00276        /*
00277         * Set up a place to put thread-specific data.
00278         * We only need a single pointer per thread - it points to the
00279         * wcsession struct to which the thread is currently bound.
00280         */
00281        if (pthread_key_create(&MyConKey, NULL) != 0) {
00282               syslog(1, "Can't create TSD key: %s", strerror(errno));
00283        }
00284        InitialiseSemaphores();
00285 
00286        /*
00287         * Set up a place to put thread-specific SSL data.
00288         * We don't stick this in the wcsession struct because SSL starts
00289         * up before the session is bound, and it gets torn down between
00290         * transactions.
00291         */
00292 #ifdef HAVE_OPENSSL
00293        if (pthread_key_create(&ThreadSSL, NULL) != 0) {
00294               syslog(1, "Can't create TSD key: %s", strerror(errno));
00295        }
00296 #endif
00297 
00298        /*
00299         * Bind the server to our favorite port.
00300         * There is no need to check for errors, because webcit_tcp_server()
00301         * exits if it doesn't succeed.
00302         */
00303 
00304        if (!IsEmptyStr(uds_listen_path)) {
00305               syslog(2, "Attempting to create listener socket at %s...", uds_listen_path);
00306               msock = webcit_uds_server(uds_listen_path, LISTEN_QUEUE_LENGTH);
00307        }
00308        else {
00309               syslog(2, "Attempting to bind to port %d...", http_port);
00310               msock = webcit_tcp_server(ip_addr, http_port, LISTEN_QUEUE_LENGTH);
00311        }
00312        if (msock < 0)
00313        {
00314               ShutDownWebcit();
00315               return -msock;
00316        }
00317 
00318        syslog(2, "Listening on socket %d", msock);
00319        signal(SIGPIPE, SIG_IGN);
00320 
00321        pthread_mutex_init(&SessionListMutex, NULL);
00322 
00323        /*
00324         * Start up the housekeeping thread
00325         */
00326        pthread_attr_init(&attr);
00327        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00328        pthread_create(&SessThread, &attr, (void *(*)(void *)) housekeeping_loop, NULL);
00329 
00330        /*
00331         * If this is an HTTPS server, fire up SSL
00332         */
00333 #ifdef HAVE_OPENSSL
00334        if (is_https) {
00335               init_ssl();
00336        }
00337 #endif
00338        drop_root(UID);
00339 
00340        /* Become a worker thread.  More worker threads will be spawned as they are needed. */
00341        worker_entry();
00342        ShutDownLibCitadel();
00343        return 0;
00344 }
00345 
00346 
00347 
00348 
00349 
00350 
00351