]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/proc.c
Check and call arc4random_stir() if present
[ngircd-alex.git] / src / ngircd / proc.c
index 5f3cadeb5f7eef30ba99d249f62fe00d2f789abd..a5afb5011cb1c468732561d5944fa9f685c1c4e4 100644 (file)
@@ -1,29 +1,35 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
  *
  * 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
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  * Please read the file COPYING, README and AUTHORS for more information.
- *
- * Process management
  */
 
 #include "portab.h"
 
+/**
+ * @file
+ * Process management
+ */
+
 #include "imp.h"
 #include <assert.h>
 #include <errno.h>
 #include <signal.h>
 #include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 #include "log.h"
 #include "io.h"
+#include "conn.h"
 
 #include "exp.h"
+#include "sighandlers.h"
 #include "proc.h"
 
 /**
@@ -41,9 +47,12 @@ Proc_InitStruct (PROC_STAT *proc)
  * Fork a child process.
  */
 GLOBAL pid_t
-Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short))
+Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short), int timeout)
 {
        pid_t pid;
+#ifndef HAVE_ARC4RANDOM
+       unsigned int seed;
+#endif
 
        assert(proc != NULL);
        assert(pipefds != NULL);
@@ -55,6 +64,9 @@ Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short))
                return -1;
        }
 
+#ifndef HAVE_ARC4RANDOM
+       seed = (unsigned int)rand();
+#endif
        pid = fork();
        switch (pid) {
        case -1:
@@ -65,7 +77,17 @@ Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short))
                return -1;
        case 0:
                /* New child process: */
+#ifdef HAVE_ARC4RANDOM_STIR
+               arc4random_stir();
+#endif
+#ifndef HAVE_ARC4RANDOM
+               srand(seed ^ (unsigned int)time(NULL) ^ getpid());
+#endif
+               Signals_Exit();
+               signal(SIGTERM, Proc_GenericSignalHandler);
+               signal(SIGALRM, Proc_GenericSignalHandler);
                close(pipefds[0]);
+               alarm(timeout);
                return 0;
        }
 
@@ -86,16 +108,65 @@ Proc_Fork(PROC_STAT *proc, int *pipefds, void (*cbfunc)(int, short))
 }
 
 /**
- * Kill forked child process.
+ * Generic signal handler for forked child processes.
  */
 GLOBAL void
-Proc_Kill(PROC_STAT *proc)
+Proc_GenericSignalHandler(int Signal)
 {
-       assert(proc != NULL);
-       assert(proc->pipe_fd >= 0);
+       switch(Signal) {
+       case SIGTERM:
+#ifdef DEBUG
+               Log_Subprocess(LOG_DEBUG, "Child got TERM signal, exiting.");
+#endif
+               exit(1);
+       case SIGALRM:
+#ifdef DEBUG
+               Log_Subprocess(LOG_DEBUG, "Child got ALARM signal, exiting.");
+#endif
+               exit(1);
+       }
+}
+
+/**
+ * Read bytes from a pipe of a forked child process.
+ * In addition, this function makes sure that the child process is ignored
+ * after all data has been read or a fatal error occurred.
+ */
+GLOBAL size_t
+Proc_Read(PROC_STAT *proc, void *buffer, size_t buflen)
+{
+       ssize_t bytes_read = 0;
+
+       assert(buffer != NULL);
+       assert(buflen > 0);
+
+       bytes_read = read(proc->pipe_fd, buffer, buflen);
+       if (bytes_read < 0) {
+               if (errno == EAGAIN)
+                       return 0;
+               Log(LOG_CRIT, "Can't read from child process %ld: %s",
+                   proc->pid, strerror(errno));
+               Proc_Close(proc);
+               bytes_read = 0;
+       } else if (bytes_read == 0) {
+               /* EOF: clean up */
+               LogDebug("Child process %ld: EOF reached, closing pipe.",
+                        proc->pid);
+               Proc_Close(proc);
+       }
+       return (size_t)bytes_read;
+}
+
+/**
+ * Close pipe to a forked child process.
+ */
+GLOBAL void
+Proc_Close(PROC_STAT *proc)
+{
+       /* Close socket, if it exists */
+       if (proc->pipe_fd >= 0)
+               io_close(proc->pipe_fd);
 
-       io_close(proc->pipe_fd);
-       kill(proc->pid, SIGTERM);
        Proc_InitStruct(proc);
 }