Fixed HTTP-client query-string handling bug.
[doldaconnect.git] / daemon / main.c
index 1c19101..463d8be 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Dolda Connect - Modular multiuser Direct Connect-style client
- *  Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com)
+ *  Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 #include <stdarg.h>
 #include <fcntl.h>
+#include <sys/select.h>
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #include "sysevents.h"
 #include "auth.h"
 
+#ifdef HAVE_KEYUTILS
+#include <keyutils.h>
+#endif
+
 struct module *modchain = NULL;
 static struct timer *timers = NULL;
 static struct child *children = NULL;
@@ -86,7 +91,6 @@ void childcallback(pid_t pid, void (*func)(pid_t, int, void *), void *data)
     new->pid = pid;
     new->callback = func;
     new->data = data;
-    new->finished = 0;
     new->prev = NULL;
     new->next = children;
     if(children != NULL)
@@ -134,9 +138,6 @@ static void terminate(void)
 
 static void handler(int signum)
 {
-    pid_t pid;
-    int status;
-    struct child *child;
     FILE *dumpfile;
     extern int numfnetnodes, numtransfers, numdcpeers;
     
@@ -150,18 +151,7 @@ static void handler(int signum)
        running = 0;
        break;
     case SIGCHLD:
-       while((pid = waitpid(-1, &status, WNOHANG)) > 0)
-       {
-           for(child = children; child != NULL; child = child->next)
-           {
-               if(child->pid == pid)
-               {
-                   child->finished = 1;
-                   child->status = status;
-               }
-           }
-           childrendone = 1;
-       }
+       childrendone = 1;
        break;
     case SIGUSR1:
        flog(LOG_NOTICE, "forking and dumping core upon SIGUSR1");
@@ -180,6 +170,32 @@ static void handler(int signum)
     }
 }
 
+static void checkchildren(void)
+{
+    pid_t pid;
+    int status;
+    struct child *child;
+
+    while((pid = waitpid(-1, &status, WNOHANG)) > 0)
+    {
+       for(child = children; child != NULL; child = child->next)
+       {
+           if(child->pid == pid)
+           {
+               child->callback(pid, status, child->data);
+               if(child == children)
+                   children = child->next;
+               if(child->prev != NULL)
+                   child->prev->next = child->next;
+               if(child->next != NULL)
+                   child->next->prev = child->prev;
+               free(child);
+               break;
+           }
+       }
+    }
+}
+
 pid_t forksess(uid_t user, struct authhandle *auth, void (*ccbfunc)(pid_t, int, void *), void *data, ...)
 {
     int i, o;
@@ -300,9 +316,13 @@ pid_t forksess(uid_t user, struct authhandle *auth, void (*ccbfunc)(pid_t, int,
                close(i);
            }
        }
-       setpgrp();
+       setpgid(0, 0);
        signal(SIGHUP, SIG_IGN);
        errno = 0;
+#ifdef HAVE_KEYUTILS
+       keyctl_join_session_keyring(NULL);
+       keyctl_chown(KEY_SPEC_SESSION_KEYRING, pwent->pw_uid, pwent->pw_gid);
+#endif
        if((authopensess(auth)) != AUTH_SUCCESS)
        {
            flog(LOG_WARNING, "could not open session for user %s: %s", pwent->pw_name, (errno == 0)?"Unknown error - should be logged above":strerror(errno));
@@ -332,12 +352,12 @@ pid_t forksess(uid_t user, struct authhandle *auth, void (*ccbfunc)(pid_t, int,
                    flog(LOG_WARNING, "could not setuid: %s", strerror(errno));
                    exit(127);
                }
+               putenv(sprintf2("HOME=%s", pwent->pw_dir));
+               putenv(sprintf2("SHELL=%s", pwent->pw_shell));
+               putenv(sprintf2("PATH=%s/bin:/usr/local/bin:/bin:/usr/bin", pwent->pw_dir));
            }
-           putenv(sprintf2("HOME=%s", pwent->pw_dir));
-           putenv(sprintf2("SHELL=%s", pwent->pw_shell));
            putenv(sprintf2("USER=%s", pwent->pw_name));
            putenv(sprintf2("LOGNAME=%s", pwent->pw_name));
-           putenv(sprintf2("PATH=%s/bin:/usr/local/bin:/bin:/usr/bin", pwent->pw_dir));
            chdir(pwent->pw_dir);
            return(0);
        }
@@ -373,15 +393,15 @@ int main(int argc, char **argv)
     FILE *pfstream, *confstream;
     int delay, immsyslog;
     struct module *mod;
-    struct timer *timer, *ntimer;
-    struct child *child;
+    struct timer *timer;
     double now;
     
+    now = ntime();
     immsyslog = nofork = 0;
     syslogfac = LOG_DAEMON;
     configfile = NULL;
     pidfile = NULL;
-    while((c = getopt(argc, argv, "p:C:f:hns")) != -1)
+    while((c = getopt(argc, argv, "p:C:f:hnsV")) != -1)
     {
        switch(c)
        {
@@ -427,11 +447,14 @@ int main(int argc, char **argv)
        case 's':
            immsyslog = 1;
            break;
+       case 'V':
+           printf("%s", RELEASEINFO);
+           exit(0);
        case 'h':
        case ':':
        case '?':
        default:
-           printf("usage: doldacond [-hns] [-C configfile] [-p pidfile] [-f facility]\n");
+           printf("usage: doldacond [-hnsV] [-C configfile] [-p pidfile] [-f facility]\n");
            exit(c != 'h');
        }
     }
@@ -452,7 +475,7 @@ int main(int argc, char **argv)
     preinit(0);
     if(configfile == NULL)
     {
-       if((configfile = findconfigfile()) == NULL)
+       if((configfile = findfile("doldacond.conf", NULL, 0)) == NULL)
        {
            flog(LOG_CRIT, "could not find a configuration file");
            exit(1);
@@ -486,6 +509,7 @@ int main(int argc, char **argv)
        fprintf(pfstream, "%i\n", getpid());
        fclose(pfstream);
     }
+    flog(LOG_INFO, "startup took %f seconds", ntime() - now);
     running = 1;
     reinit = 0;
     while(running)
@@ -520,47 +544,38 @@ int main(int argc, char **argv)
                    delay = (int)((timer->at - now) * 1000.0);
            }
        }
+       /* Of course, there's a race condition here that should be
+        * solved with pselect, but it doesn't matter a lot. */
        if(childrendone)
-       {
            delay = 0;
-           childrendone = 0;
-       }
        pollsocks(delay);
        now = ntime();
-       for(timer = timers; timer != NULL; timer = ntimer)
-       {
-           ntimer = timer->next;
-           if(now < timer->at)
-               continue;
-           if(timer->prev != NULL)
-               timer->prev->next = timer->next;
-           if(timer->next != NULL)
-               timer->next->prev = timer->prev;
-           if(timer == timers)
-               timers = timer->next;
-           timer->func(0, timer->data);
-           free(timer);
-       }
        do
        {
-           for(child = children; child != NULL; child = child->next)
+           for(timer = timers; timer != NULL; timer = timer->next)
            {
-               if(child->finished)
-               {
-                   child->callback(child->pid, child->status, child->data);
-                   if(child == children)
-                       children = child->next;
-                   if(child->prev != NULL)
-                       child->prev->next = child->next;
-                   if(child->next != NULL)
-                       child->next->prev = child->prev;
-                   free(child);
-                   break;
-               }
+               if(now < timer->at)
+                   continue;
+               if(timer->prev != NULL)
+                   timer->prev->next = timer->next;
+               if(timer->next != NULL)
+                   timer->next->prev = timer->prev;
+               if(timer == timers)
+                   timers = timer->next;
+               timer->func(0, timer->data);
+               free(timer);
+               break;
            }
-       } while(child != NULL);
+       } while(timer != NULL);
+       if(childrendone)
+       {
+           childrendone = 0;
+           checkchildren();
+       }
     }
     flog(LOG_INFO, "terminating...");
     terminate();
+    if(pidfile != NULL)
+       unlink(pidfile);
     return(0);
 }