2 * Dolda Connect - Modular multiuser Direct Connect-style client
3 * Copyright (C) 2004 Fredrik Tolf <fredrik@dolda2000.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include <sys/select.h>
44 #include "sysevents.h"
51 struct module *modchain = NULL;
52 static struct timer *timers = NULL;
53 static struct child *children = NULL;
56 static volatile int childrendone = 0;
58 struct timer *timercallback(double at, void (*func)(int, void *), void *data)
62 new = smalloc(sizeof(*new));
74 void canceltimer(struct timer *timer)
76 if(timer->next != NULL)
77 timer->next->prev = timer->prev;
78 if(timer->prev != NULL)
79 timer->prev->next = timer->next;
82 timer->func(1, timer->data);
86 void childcallback(pid_t pid, void (*func)(pid_t, int, void *), void *data)
90 new = smalloc(sizeof(*new));
101 static void preinit(int hup)
105 for(mod = modchain; mod != NULL; mod = mod->next)
109 if(!hup && ((mod->conf.vars != NULL) || (mod->conf.cmds != NULL)))
110 confregmod(&mod->conf);
114 static void init(int hup)
118 for(mod = modchain; mod != NULL; mod = mod->next)
120 if(mod->init && mod->init(hup))
122 flog(LOG_CRIT, "initialization of \"%s\" failed", mod->name);
128 static void terminate(void)
132 for(mod = modchain; mod != NULL; mod = mod->next)
139 static void handler(int signum)
142 extern int numfnetnodes, numtransfers, numdcpeers;
157 flog(LOG_NOTICE, "forking and dumping core upon SIGUSR1");
162 flog(LOG_NOTICE, "dumping memstats to /tmp/dc-mem upon SIGUSR2");
163 if((dumpfile = fopen("/tmp/dc-mem", "w")) == NULL) {
164 flog(LOG_ERR, "could not dump stats: %s", strerror(errno));
167 fprintf(dumpfile, "%i %i %i\n", numfnetnodes, numtransfers, numdcpeers);
173 static void checkchildren(void)
179 while((pid = waitpid(-1, &status, WNOHANG)) > 0)
181 for(child = children; child != NULL; child = child->next)
183 if(child->pid == pid)
185 child->callback(pid, status, child->data);
186 if(child == children)
187 children = child->next;
188 if(child->prev != NULL)
189 child->prev->next = child->next;
190 if(child->next != NULL)
191 child->next->prev = child->prev;
199 pid_t forksess(uid_t user, struct authhandle *auth, void (*ccbfunc)(pid_t, int, void *), void *data, ...)
208 int maxfd, type, numfiles;
211 struct passwd *pwent;
218 if((pwent = getpwuid(user)) == NULL)
220 flog(LOG_WARNING, "no passwd entry for uid %i, cannot fork session", user);
224 if((geteuid() != 0) && (user != geteuid()))
226 flog(LOG_WARNING, "cannot fork non-owning session when not running as root (EUID is %i, target UID is %i)", geteuid(), user);
230 va_start(args, data);
234 while((type = va_arg(args, int)) != FD_END)
236 files = srealloc(files, sizeof(*files) * (numfiles + 1));
237 files[numfiles].fd = va_arg(args, int);
238 if(files[numfiles].fd > maxfd)
239 maxfd = files[numfiles].fd;
240 acc = va_arg(args, int);
245 flog(LOG_CRIT, "could not create pipe(!): %s", strerror(errno));
246 for(i = 0; i < numfiles; i++)
250 ibuf = va_arg(args, int *);
254 files[numfiles].tfd = cpipe[0];
257 files[numfiles].tfd = cpipe[1];
259 } else if(type == FD_FILE) {
260 buf = va_arg(args, char *);
261 if((files[numfiles].tfd = open(buf, acc)) < 0)
263 flog(LOG_CRIT, "could not open file \"%s\": %s", buf, strerror(errno));
264 for(i = 0; i < numfiles; i++)
269 if(files[numfiles].tfd > maxfd)
270 maxfd = files[numfiles].tfd;
274 sigemptyset(&sigset);
275 sigaddset(&sigset, SIGCHLD);
276 sigprocmask(SIG_BLOCK, &sigset, NULL);
277 if((pid = fork()) < 0)
279 flog(LOG_WARNING, "could not fork(!) in forksess(): %s", strerror(errno));
280 for(i = 0; i < numfiles; i++)
282 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
286 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
287 signal(SIGPIPE, SIG_DFL);
288 signal(SIGCHLD, SIG_DFL);
289 signal(SIGINT, SIG_DFL);
290 signal(SIGTERM, SIG_DFL);
291 signal(SIGHUP, SIG_DFL);
292 for(i = 0; i < numfiles; i++)
294 if(dup2(files[i].tfd, maxfd + i + 1) < 0)
296 files[i].tfd = maxfd + i + 1;
298 for(i = 0; i < numfiles; i++)
300 if(dup2(files[i].tfd, files[i].fd) < 0)
304 for(i = 0; i < FD_SETSIZE; i++)
308 for(o = 0; o < numfiles; o++)
320 signal(SIGHUP, SIG_IGN);
323 keyctl_join_session_keyring(NULL);
324 keyctl_chown(KEY_SPEC_SESSION_KEYRING, pwent->pw_uid, pwent->pw_gid);
326 if((authopensess(auth)) != AUTH_SUCCESS)
328 flog(LOG_WARNING, "could not open session for user %s: %s", pwent->pw_name, (errno == 0)?"Unknown error - should be logged above":strerror(errno));
331 if((pid = fork()) < 0)
340 if(initgroups(pwent->pw_name, pwent->pw_gid))
342 flog(LOG_WARNING, "could not initgroups: %s", strerror(errno));
345 if(setgid(pwent->pw_gid))
347 flog(LOG_WARNING, "could not setgid: %s", strerror(errno));
350 if(setuid(pwent->pw_uid))
352 flog(LOG_WARNING, "could not setuid: %s", strerror(errno));
355 putenv(sprintf2("HOME=%s", pwent->pw_dir));
356 putenv(sprintf2("SHELL=%s", pwent->pw_shell));
357 putenv(sprintf2("PATH=%s/bin:/usr/local/bin:/bin:/usr/bin", pwent->pw_dir));
359 putenv(sprintf2("USER=%s", pwent->pw_name));
360 putenv(sprintf2("LOGNAME=%s", pwent->pw_name));
361 chdir(pwent->pw_dir);
364 for(i = 0; i < numfiles; i++)
366 while(((ret = waitpid(pid, &status, 0)) != pid) && (ret >= 0));
370 flog(LOG_WARNING, "waitpid(%i) said \"%s\"", pid, strerror(errno));
373 if(!WIFEXITED(status))
375 exit(WEXITSTATUS(status));
377 for(i = 0; i < numfiles; i++)
382 childcallback(pid, ccbfunc, data);
383 sigprocmask(SIG_UNBLOCK, &sigset, NULL);
387 int main(int argc, char **argv)
393 FILE *pfstream, *confstream;
394 int delay, immsyslog;
400 immsyslog = nofork = 0;
401 syslogfac = LOG_DAEMON;
404 while((c = getopt(argc, argv, "p:C:f:hnsV")) != -1)
415 if(!strcmp(optarg, "auth"))
416 syslogfac = LOG_AUTH;
417 else if(!strcmp(optarg, "authpriv"))
418 syslogfac = LOG_AUTHPRIV;
419 else if(!strcmp(optarg, "cron"))
420 syslogfac = LOG_CRON;
421 else if(!strcmp(optarg, "daemon"))
422 syslogfac = LOG_DAEMON;
423 else if(!strcmp(optarg, "ftp"))
425 else if(!strcmp(optarg, "kern"))
426 syslogfac = LOG_KERN;
427 else if(!strcmp(optarg, "lpr"))
429 else if(!strcmp(optarg, "mail"))
430 syslogfac = LOG_MAIL;
431 else if(!strcmp(optarg, "news"))
432 syslogfac = LOG_NEWS;
433 else if(!strcmp(optarg, "syslog"))
434 syslogfac = LOG_SYSLOG;
435 else if(!strcmp(optarg, "user"))
436 syslogfac = LOG_USER;
437 else if(!strcmp(optarg, "uucp"))
438 syslogfac = LOG_UUCP;
439 else if(!strncmp(optarg, "local", 5) && (strlen(optarg) == 6))
440 syslogfac = LOG_LOCAL0 + (optarg[5] - '0');
442 fprintf(stderr, "unknown syslog facility %s, using daemon\n", optarg);
451 printf("%s", RELEASEINFO);
457 printf("usage: doldacond [-hnsV] [-C configfile] [-p pidfile] [-f facility]\n");
461 setlocale(LC_ALL, "");
468 signal(SIGPIPE, SIG_IGN);
469 signal(SIGHUP, handler);
470 signal(SIGINT, handler);
471 signal(SIGTERM, handler);
472 signal(SIGCHLD, handler);
473 signal(SIGUSR1, handler);
474 signal(SIGUSR2, handler);
476 if(configfile == NULL)
478 if((configfile = findfile("doldacond.conf", NULL, 0)) == NULL)
480 flog(LOG_CRIT, "could not find a configuration file");
487 if((pfstream = fopen(pidfile, "w")) == NULL)
489 flog(LOG_CRIT, "could not open specified PID file %s: %s", pidfile, strerror(errno));
493 if((confstream = fopen(configfile, "r")) == NULL)
495 flog(LOG_CRIT, "could not open configuration file %s: %s", configfile, strerror(errno));
498 readconfig(confstream);
505 flog(LOG_INFO, "daemonized");
508 if(pfstream != NULL) {
509 fprintf(pfstream, "%i\n", getpid());
512 flog(LOG_INFO, "startup took %f seconds", ntime() - now);
519 if((confstream = fopen(configfile, "r")) == NULL)
521 flog(LOG_ERR, "could not open configuration file %s: %s (ignoring HUP)", configfile, strerror(errno));
524 readconfig(confstream);
530 delay = 1000; /* -1; */
531 for(mod = modchain; mod != NULL; mod = mod->next)
533 if(mod->run && mod->run())
541 for(timer = timers; timer != NULL; timer = timer->next)
543 if((delay == -1) || ((int)((timer->at - now) * 1000.0) < delay))
544 delay = (int)((timer->at - now) * 1000.0);
547 /* Of course, there's a race condition here that should be
548 * solved with pselect, but it doesn't matter a lot. */
555 for(timer = timers; timer != NULL; timer = timer->next)
559 if(timer->prev != NULL)
560 timer->prev->next = timer->next;
561 if(timer->next != NULL)
562 timer->next->prev = timer->prev;
564 timers = timer->next;
565 timer->func(0, timer->data);
569 } while(timer != NULL);
576 flog(LOG_INFO, "terminating...");