Merge pull request #86 from painless-security/jennifer/aaa_server_port
[trust_router.git] / tid / tids.c
index 74e790e..f600d66 100644 (file)
@@ -49,6 +49,7 @@
 #include <tr_socket.h>
 #include <tr_gss.h>
 #include <tr_event.h>
+#include <sys/resource.h>
 
 /**
  * Create a response with minimal fields filled in
@@ -355,7 +356,7 @@ nfds_t tids_get_listener(TIDS_INSTANCE *tids,
                          TIDS_REQ_FUNC *req_handler,
                          tids_auth_func *auth_handler,
                          const char *hostname,
-                         unsigned int port,
+                         int port,
                          void *cookie,
                          int *fd_out,
                          size_t max_fd)
@@ -367,7 +368,7 @@ nfds_t tids_get_listener(TIDS_INSTANCE *tids,
   n_fd = tr_sock_listen_all(port, fd_out, max_fd);
 
   if (n_fd == 0)
-    tr_err("tids_get_listener: Error opening port %d");
+    tr_err("tids_get_listener: Error opening port %d", port);
   else {
     /* opening port succeeded */
     tr_info("tids_get_listener: Opened port %d.", port);
@@ -397,6 +398,63 @@ nfds_t tids_get_listener(TIDS_INSTANCE *tids,
   return (int)n_fd;
 }
 
+/* Strings used to report results from the handler process. The
+ * TIDS_MAX_MESSAGE_LEN must be longer than the longest message, including
+ * null termination (i.e., strlen() + 1) */
+#define TIDS_MAX_MESSAGE_LEN (10)
+#define TIDS_SUCCESS_MESSAGE "OK"
+#define TIDS_ERROR_MESSAGE   "ERR"
+
+/**
+ * Process to handle an incoming TIDS request
+ *
+ * This should be run in the child process after a fork(). Handles
+ * the request, writes the result to result_fd, and terminates.
+ * Never returns to the caller.
+ *
+ * @param tids TID server instance
+ * @param conn_fd file descriptor for the incoming connection
+ * @param result_fd writable file descriptor for the result, or 0 to disable reporting
+ */
+static void tids_handle_proc(TIDS_INSTANCE *tids, int conn_fd, int result_fd)
+{
+  const char *response_message = NULL;
+  struct rlimit rlim; /* for disabling core dump */
+
+  switch(tr_gss_handle_connection(conn_fd,
+                                  "trustidentity", tids->hostname, /* acceptor name */
+                                  tids->auth_handler, tids->cookie, /* auth callback and cookie */
+                                  tids_req_cb, tids /* req callback and cookie */
+  )) {
+    case TR_GSS_SUCCESS:
+      response_message = TIDS_SUCCESS_MESSAGE;
+      break;
+
+    case TR_GSS_ERROR:
+    default:
+      response_message = TIDS_ERROR_MESSAGE;
+      break;
+  }
+
+  if (0 != result_fd) {
+    /* write strlen + 1 to include the null termination */
+    if (write(result_fd, response_message, strlen(response_message) + 1) < 0)
+      tr_err("tids_accept: child process unable to write to pipe");
+  }
+
+  close(result_fd);
+  close(conn_fd);
+
+  /* This ought to be an exit(0), but log4shib does not play well with fork() due to
+   * threading issues. To ensure we do not get stuck in the exit handler, we will
+   * abort. First disable core dump for this subprocess (the main process will still
+   * dump core if the environment allows). */
+  rlim.rlim_cur = 0; /* max core size of 0 */
+  rlim.rlim_max = 0; /* prevent the core size limit from being raised later */
+  setrlimit(RLIMIT_CORE, &rlim);
+  abort(); /* exit hard */
+}
+
 /* Accept and process a connection on a port opened with tids_get_listener() */
 int tids_accept(TIDS_INSTANCE *tids, int listen)
 {
@@ -422,26 +480,22 @@ int tids_accept(TIDS_INSTANCE *tids, int listen)
   }
 
   if (pid == 0) {
-    close(pipe_fd[0]); /* child only writes */
-    close(listen);
-    tr_gss_handle_connection(conn,
-                             "trustidentity", tids->hostname, /* acceptor name */
-                             tids->auth_handler, tids->cookie, /* auth callback and cookie */
-                             tids_req_cb, tids /* req callback and cookie */
-    );
-    if (write(pipe_fd[1], "OK\0", 3) < 0)
-      tr_crit("tids_accept: child process unable to write to pipe");
-    close(pipe_fd[1]);
-    close(conn);
-    exit(0); /* exit to kill forked child process */
+    /* Only the child process gets here */
+    close(pipe_fd[0]); /* close the read end of the pipe, the child only writes */
+    close(listen); /* close the child process's handle on the listen port */
+
+    tids_handle_proc(tids, conn, pipe_fd[1]); /* never returns */
   }
 
   /* Only the parent process gets here */
-  close(pipe_fd[1]); /* parent only listens */
-  close(conn); /* connection belongs to the child */
+  close(pipe_fd[1]); /* close the write end of the pipe, the parent only listens */
+  close(conn); /* connection belongs to the child, so close parent's handle */
+
+  /* remember the PID of our child process */
+  tr_info("tids_accept: Spawned TID process %d to handle incoming connection.", pid);
   tp.pid = pid;
   tp.read_fd = pipe_fd[0];
-  g_array_append_val(tids->pids, tp); /* remember the PID of our child process */
+  g_array_append_val(tids->pids, tp);
 
   /* clean up any processes that have completed */
   tids_sweep_procs(tids);
@@ -463,7 +517,7 @@ void tids_sweep_procs(TIDS_INSTANCE *tids)
 {
   guint ii;
   struct tid_process tp = {0};
-  char result[10] = {0};
+  char result[TIDS_MAX_MESSAGE_LEN] = {0};
   ssize_t result_len;
   int status;
   int wait_rc;
@@ -506,26 +560,26 @@ void tids_sweep_procs(TIDS_INSTANCE *tids)
     }
 
     /* read the pipe - if the TID request worked, it will have written status before terminating */
-    result_len = read(tp.read_fd, result, sizeof(result)/sizeof(result[0]));
+    result_len = read(tp.read_fd, result, TIDS_MAX_MESSAGE_LEN);
     close(tp.read_fd);
 
-    if ((result_len > 0) && (strcmp(result, "OK") == 0)) {
+    if ((result_len > 0) && (strcmp(result, TIDS_SUCCESS_MESSAGE) == 0)) {
       tids->req_count++;
-      tr_debug("tids_sweep_procs: TID process %d succeeded", tp.pid);
+      tr_info("tids_sweep_procs: TID process %d exited successfully.", tp.pid);
     } else {
       tids->error_count++;
-      tr_debug("tids_sweep_procs: TID process %d failed", tp.pid);
+      tr_info("tids_sweep_procs: TID process %d exited with an error.", tp.pid);
     }
   }
 }
 
 /* Process tids requests forever. Should not return except on error. */
-int tids_start (TIDS_INSTANCE *tids,
-                TIDS_REQ_FUNC *req_handler,
-                tids_auth_func *auth_handler,
-                const char *hostname,
-                unsigned int port,
-                void *cookie)
+int tids_start(TIDS_INSTANCE *tids,
+               TIDS_REQ_FUNC *req_handler,
+               tids_auth_func *auth_handler,
+               const char *hostname,
+               int port,
+               void *cookie)
 {
   int fd[TR_MAX_SOCKETS]={0};
   nfds_t n_fd=0;