* port our setuid function from citserver to webcit; -u can now specify the UID...
[citadel.git] / webcit / webserver.c
index 8488020effca4a1cae9f12ea8aed938d4de86b5a..c70419b3be0d405c982abfbf537168a50109ca49 100644 (file)
@@ -5,7 +5,7 @@
  * waiting on the specified port for incoming HTTP connections.  When a
  * connection is established, it calls context_loop() from context_loop.c.
  *
- * Copyright (c) 1996-2009 by the citadel.org developers.
+ * Copyright (c) 1996-2010 by the citadel.org developers.
  * This program is released under the terms of the GNU General Public License v3.
  *
  */
@@ -28,7 +28,7 @@ int follow_xff = 0;           /* Follow X-Forwarded-For: header */
 int home_specified = 0;                /* did the user specify a homedir? */
 int time_to_die = 0;            /* Nonzero if server is shutting down */
 int DisableGzip = 0;
-extern void *context_loop(int*);
+extern void *context_loop(ParsedHttpHdrs *Hdr);
 extern void *housekeeping_loop(void);
 extern pthread_mutex_t SessionListMutex;
 extern pthread_key_t MyConKey;
@@ -36,6 +36,7 @@ extern pthread_key_t MyConKey;
 extern int ig_tcp_server(char *ip_addr, int port_number, int queue_len);
 extern int ig_uds_server(char *sockpath, int queue_len);
 
+extern void drop_root(uid_t UID);
 
 char ctdl_key_dir[PATH_MAX]=SSL_DIR;
 char file_crpt_file_key[PATH_MAX]="";
@@ -99,11 +100,10 @@ void graceful_shutdown_watcher(int signum) {
  */
 pid_t current_child;
 void graceful_shutdown(int signum) {
-       char wd[SIZ];
        FILE *FD;
        int fd;
-       getcwd(wd, SIZ);
-       lprintf (1, "bye going down gracefull.[%d][%s]\n", signum, wd);
+
+       lprintf (1, "WebCit is being shut down on signal %d.\n", signum);
        fd = msock;
        msock = -1;
        time_to_die = 1;
@@ -123,6 +123,8 @@ void start_daemon(char *pid_file)
        pid_t child = 0;
        FILE *fp;
        int do_restart = 0;
+       int rv;
+       FILE *rvfp = NULL;
 
        current_child = 0;
 
@@ -130,7 +132,7 @@ void start_daemon(char *pid_file)
         * We don't just call close() because we don't want these fd's
         * to be reused for other files.
         */
-       chdir("/");
+       rv = chdir("/");
 
        signal(SIGHUP, SIG_IGN);
        signal(SIGINT, SIG_IGN);
@@ -143,9 +145,9 @@ void start_daemon(char *pid_file)
 
        setsid();
        umask(0);
-       freopen("/dev/null", "r", stdin);
-       freopen("/dev/null", "w", stdout);
-       freopen("/dev/null", "w", stderr);
+       rvfp = freopen("/dev/null", "r", stdin);
+       rvfp = freopen("/dev/null", "w", stdout);
+       rvfp = freopen("/dev/null", "w", stderr);
        signal(SIGTERM, graceful_shutdown_watcher);
        signal(SIGHUP, graceful_shutdown_watcher);
 
@@ -219,16 +221,15 @@ void spawn_another_worker_thread()
        pthread_attr_t attr;    /* Thread attributes */
        int ret;
 
-       lprintf(3, "Creating a new thread\n");
+       lprintf(3, "Creating a new thread.  Pool size is now %d\n", ++num_threads);
 
        /* set attributes for the new thread */
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
 
        /*
-        * Our per-thread stacks need to be bigger than the default size, otherwise
-        * the MIME parser crashes on FreeBSD, and the IMAP service crashes on
-        * 64-bit Linux.
+        * Our per-thread stacks need to be bigger than the default size,
+        * otherwise the MIME parser crashes on FreeBSD.
         */
        if ((ret = pthread_attr_setstacksize(&attr, 1024 * 1024))) {
                lprintf(1, "pthread_attr_setstacksize: %s\n",
@@ -262,6 +263,7 @@ extern int LoadTemplates;
 extern HashList *HandlerHash;
 
 
+
 void
 webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdir, char *relhome)
 {
@@ -286,6 +288,9 @@ webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdi
        COMPUTE_DIRECTORY(static_icon_dir);
        basedir=WWWDIR "/static.local";
        COMPUTE_DIRECTORY(static_local_dir);
+       StripSlashes(static_dir, 1);
+       StripSlashes(static_icon_dir, 1);
+       StripSlashes(static_local_dir, 1);
 
        snprintf(file_crpt_file_key,
                 sizeof file_crpt_file_key, 
@@ -311,6 +316,8 @@ webcit_calc_dirs_n_files(int relh, const char *basedir, int home, char *webcitdi
  */
 int main(int argc, char **argv)
 {
+       uid_t UID = -1;
+       size_t basesize = 2;            /* how big should strbufs be on creation? */
        pthread_t SessThread;           /* Thread descriptor */
        pthread_attr_t attr;            /* Thread attributes */
        int a, i;                       /* General-purpose variables */
@@ -323,13 +330,11 @@ int main(int argc, char **argv)
        char webcitdir[PATH_MAX] = DATADIR;
        char *pidfile = NULL;
        char *hdir;
-       const char *basedir;
-#ifdef ENABLE_NLS
-       char *locale = NULL;
-       char *mo = NULL;
-#endif /* ENABLE_NLS */
+       const char *basedir = NULL;
        char uds_listen_path[PATH_MAX]; /* listen on a unix domain socket? */
        const char *I18nDumpFile = NULL;
+       FILE *rvfp = NULL;
+       int rv = 0;
 
        WildFireInitBacktrace(argv[0], 2);
 
@@ -352,19 +357,23 @@ int main(int argc, char **argv)
 
        /* Parse command line */
 #ifdef HAVE_OPENSSL
-       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:G:cfsZ")) != EOF)
+       while ((a = getopt(argc, argv, "u:h:i:p:t:T:B:x:dD:G:cfsS:Z")) != EOF)
 #else
-       while ((a = getopt(argc, argv, "h:i:p:t:T:x:dD:G:cfZ")) != EOF)
+       while ((a = getopt(argc, argv, "u:h:i:p:t:T:B:x:dD:G:cfZ")) != EOF)
 #endif
                switch (a) {
+               case 'u':
+                       UID = atol(optarg);
+                       break;
                case 'h':
                        hdir = strdup(optarg);
                        relh=hdir[0]!='/';
-                       if (!relh) safestrncpy(webcitdir, hdir,
-                                                                  sizeof webcitdir);
-                       else
-                               safestrncpy(relhome, relhome,
-                                                       sizeof relhome);
+                       if (!relh) {
+                               safestrncpy(webcitdir, hdir, sizeof webcitdir);
+                       }
+                       else {
+                               safestrncpy(relhome, relhome, sizeof relhome);
+                       }
                        /* free(hdir); TODO: SHOULD WE DO THIS? */
                        home_specified = 1;
                        home=1;
@@ -376,6 +385,11 @@ int main(int argc, char **argv)
                        pidfile = strdup(optarg);
                        running_as_daemon = 1;
                        break;
+               case 'B': /* Basesize */
+                       basesize = atoi(optarg);
+                       if (basesize > 2)
+                               StartLibCitadel(basesize);
+                       break;
                case 'i':
                        safestrncpy(ip_addr, optarg, sizeof ip_addr);
                        break;
@@ -387,9 +401,9 @@ int main(int argc, char **argv)
                        break;
                case 't':
                        safestrncpy(tracefile, optarg, sizeof tracefile);
-                       freopen(tracefile, "w", stdout);
-                       freopen(tracefile, "w", stderr);
-                       freopen(tracefile, "r", stdin);
+                       rvfp = freopen(tracefile, "w", stdout);
+                       rvfp = freopen(tracefile, "w", stderr);
+                       rvfp = freopen(tracefile, "r", stdin);
                        break;
                case 'T':
                        LoadTemplates = atoi(optarg);
@@ -420,9 +434,15 @@ int main(int argc, char **argv)
                                }
                        }
                        break;
+#ifdef HAVE_OPENSSL
                case 's':
                        is_https = 1;
                        break;
+               case 'S':
+                       is_https = 1;
+                       ssl_cipher_list = strdup(optarg);
+                       break;
+#endif
                case 'G':
                        DumpTemplateI18NStrings = 1;
                        I18nDump = NewStrBufPlain(HKEY("int templatestrings(void)\n{\n"));
@@ -435,7 +455,7 @@ int main(int argc, char **argv)
                                "[-T Templatedebuglevel] "
                                "[-d] [-Z] [-G i18ndumpfile] "
 #ifdef HAVE_OPENSSL
-                               "[-s] "
+                               "[-s] [-S cipher_suites]"
 #endif
                                "[remotehost [remoteport]]\n");
                        return 1;
@@ -460,34 +480,13 @@ int main(int argc, char **argv)
 
        /* Tell 'em who's in da house */
        lprintf(1, PACKAGE_STRING "\n");
-       lprintf(1, "Copyright (C) 1996-2009 by the Citadel development team.\n"
+       lprintf(1, "Copyright (C) 1996-2010 by the Citadel development team.\n"
                "This software is distributed under the terms of the "
                "GNU General Public License.\n\n"
        );
 
 
        /* initialize the International Bright Young Thing */
-#ifdef ENABLE_NLS
-       initialize_locales();
-
-
-       locale = setlocale(LC_ALL, "");
-
-       mo = malloc(strlen(webcitdir) + 20);
-       lprintf(9, "Message catalog directory: %s\n", bindtextdomain("webcit", LOCALEDIR"/locale"));
-       free(mo);
-       lprintf(9, "Text domain: %s\n", textdomain("webcit"));
-       lprintf(9, "Text domain Charset: %s\n", bind_textdomain_codeset("webcit","UTF8"));
-#endif
-
-
-
-
-
-
-
-
-
 
        initialise_modules();
        initialize_viewdefs();
@@ -510,7 +509,7 @@ int main(int argc, char **argv)
                        lprintf(1, "********************************************************************************\n");
                        return -1;
                }
-               fwrite(ChrPtr(I18nDump), 1, StrLength(I18nDump), fd);
+               rv = fwrite(ChrPtr(I18nDump), 1, StrLength(I18nDump), fd);
                fclose(fd);
                return 0;
        }
@@ -558,6 +557,11 @@ int main(int argc, char **argv)
                lprintf(2, "Attempting to bind to port %d...\n", http_port);
                msock = ig_tcp_server(ip_addr, http_port, LISTEN_QUEUE_LENGTH);
        }
+       if (msock < 0)
+       {
+               ShutDownWebcit();
+               return -msock;
+       }
 
        lprintf(2, "Listening on socket %d\n", msock);
        signal(SIGPIPE, SIG_IGN);
@@ -581,6 +585,7 @@ int main(int argc, char **argv)
                init_ssl();
        }
 #endif
+       drop_root(UID);
 
        /* Start a few initial worker threads */
        for (i = 0; i < (MIN_WORKER_THREADS); ++i) {
@@ -601,9 +606,6 @@ void ShutDownWebcit(void)
        icalmemory_free_ring ();
        ShutDownLibCitadel ();
        shutdown_modules ();
-#ifdef ENABLE_NLS
-       ShutdownLocale();
-#endif
 #ifdef HAVE_OPENSSL
        if (is_https) {
                shutdown_ssl();
@@ -622,7 +624,11 @@ void worker_entry(void)
        int ret;
        struct timeval tv;
        fd_set readset, tempset;
+       ParsedHttpHdrs Hdr;
 
+       memset(&Hdr, 0, sizeof(ParsedHttpHdrs));
+       Hdr.HR.eReqType = eGET;
+       http_new_modules(&Hdr); 
        tv.tv_sec = 0;
        tv.tv_usec = 10000;
        FD_ZERO(&readset);
@@ -671,6 +677,7 @@ void worker_entry(void)
                        end_critical_section(S_SHUTDOWN);
                        if (shutdown == 1)
                        {/* we're the one to cleanup the mess. */
+                               http_destroy_modules(&Hdr);
                                lprintf(2, "I'm master shutdown: tagging sessions to be killed.\n");
                                shutdown_sessions();
                                lprintf(2, "master shutdown: waiting for others\n");
@@ -707,6 +714,7 @@ void worker_entry(void)
                                }
                        }
                        else 
+#endif
                        {
                                int fdflags; 
                                fdflags = fcntl(ssock, F_GETFL);
@@ -714,16 +722,16 @@ void worker_entry(void)
                                        lprintf(1, "unable to get server socket flags! %s \n",
                                                strerror(errno));
                                fdflags = fdflags | O_NONBLOCK;
-                               if (fcntl(ssock, F_SETFD, fdflags) < 0)
+                               if (fcntl(ssock, F_SETFL, fdflags) < 0)
                                        lprintf(1, "unable to set server socket nonblocking flags! %s \n",
                                                strerror(errno));
                        }
-#endif
 
                        if (fail_this_transaction == 0) {
+                               Hdr.http_sock = ssock;
 
                                /* Perform an HTTP transaction... */
-                               context_loop(&ssock);
+                               context_loop(&Hdr);
 
                                /* Shut down SSL/TLS if required... */
 #ifdef HAVE_OPENSSL
@@ -733,14 +741,17 @@ void worker_entry(void)
 #endif
 
                                /* ...and close the socket. */
-                               if (ssock > 0)
+                               if (Hdr.http_sock > 0)
                                        lingering_close(ssock);
+                               http_detach_modules(&Hdr);
+
                        }
 
                }
 
        } while (!time_to_die);
 
+       http_destroy_modules(&Hdr);
        lprintf (1, "bye\n");
        pthread_exit(NULL);
 }