Exemple #1
0
int main(int argc, const char **argv)
{
  int c, len;
#ifdef HAVE_LIBPQ
  char *pass_replace = "--pg-pass=WITHHELD", *conninfo_replace = "--pg-connect=WITHHELD";
#endif

  oml_setup(&argc, argv);

  poptContext optCon = poptGetContext(NULL, argc, (const char**) argv, options, 0);

  while ((c = poptGetNextOpt(optCon)) >= 0) {
    switch (c) {
    case 'v':
      printf(V_STRING, VERSION);
      printf("OML Protocol V%d--%d\n", MIN_PROTOCOL_VERSION, MAX_PROTOCOL_VERSION);
      printf(COPYRIGHT);
      return 0;
    }
  }

#ifdef HAVE_LIBPQ
  /* Cleanup command line to avoid showing credentials in ps(1) output, amongst
   * others.
   *
   * XXX: This is a poor man's security measure, as this creates a race
   * condition where, prior to doing the following, the credentials are still
   * visible to everybody.
   */
  if (pg_pass || pg_conninfo) {
    for(c=1; c<argc; c++) {
      len = strlen(argv[c]);
      if(pg_pass && !strncmp(argv[c],"--pg-pass", 9)) {
        strncpy((char*)argv[c], pass_replace, len);
        ((char*)argv[c])[len] = 0;
      }

      if(pg_conninfo && !strncmp(argv[c],"--pg-connect", 12)) {
        strncpy((char*)argv[c], conninfo_replace, len);
        ((char*)argv[c])[len] = 0;
      }
    }
  }
#endif /* HAVE_LIBPQ */

  logging_setup (logfile_name, log_level);

  if (c < -1) {
    die ("%s: %s\n", poptBadOption (optCon, POPT_BADOPTION_NOALIAS), poptStrerror (c));
  }

  loginfo(V_STRING, VERSION);
  loginfo("OML Protocol V%d--%d\n", MIN_PROTOCOL_VERSION, MAX_PROTOCOL_VERSION);
  loginfo(COPYRIGHT);

  eventloop_init();
  eventloop_set_socket_timeout(socket_timeout);

  Socket* server_sock;
  server_sock = socket_server_new("server", NULL, listen_service, on_connect, NULL);

  if (!server_sock) {
    die ("Failed to create listening socket for service %s\n", listen_service);
  }

  drop_privileges (uidstr, gidstr);

  /* Important that this comes after drop_privileges(). */
  if(database_setup_backend(dbbackend)) {
      die("Failed to setup database backend '%s'\n", dbbackend);
  }

  signal_setup();

  hook_setup();

  eventloop_run();

  signal_cleanup();

  hook_cleanup();

  oml_cleanup();

  oml_memreport(O_LOG_INFO);

  return 0;
}
Exemple #2
0
/** Initialise the event hook if specified.
 *
 * This function creates two pipes, forks, redirects the child's stdin and
 * stdout to/from these pipes, then executes the hook program
 *
 * The hook program is expected to first print an identifying banner (\see
 * HOOK_BANNER), then wait for commands on stdin.
 *
 * Though a reverse pipe is also created for the hook's stdout to be available
 * to the main server process, it is not currently used for anything else than
 * getting the banner. Also, a read(2) on it from the main process is blocking.
 */
void
hook_setup (void)
{
  int pto[2], pfrom[2];
  fd_set readfds;
  struct timeval timeout = { .tv_sec=5, .tv_usec=0, };
  char buf[sizeof(HOOK_BANNER)];

  if (!hook)
    return;

  if (pipe(pto) || pipe(pfrom)) {
    logwarn("hook: Cannot create pipes to `%s': %s\n", hook, strerror(errno));
    goto clean_pipes;
  }

  hookpid = fork();
  if (hookpid < 0) {
    logwarn("hook: Cannot fork for `%s': %s\n", hook, strerror(errno));
    hookpid = -1;
    goto clean_pipes;

  } else if (0 == hookpid) {            /* Child process */
    close(pto[1]);
    close(pfrom[0]);
    dup2(pto[0], STDIN_FILENO);
    dup2(pfrom[1], STDOUT_FILENO);
    execlp(hook, hook, NULL);
    logwarn("hook: Cannot execute `%s': %s\n", hook, strerror(errno));
    exit(1);

  } else {                              /* Parent process */
    close(pto[0]);
    close(pfrom[1]);
    hookpipe[0] = pfrom[0];
    hookpipe[1] = pto[1];

    /* Wait for banner or timeout */
    FD_ZERO(&readfds);
    FD_SET(hookpipe[0], &readfds);
    logdebug("hook: Waiting for `%s' to respond...\n", hook);

    if(select(hookpipe[0]+1, &readfds, NULL, NULL, &timeout) < 1) {
      logwarn("hook: `%s' (PID %d) not responding\n", hook, hookpid);
      hook_cleanup();
      goto clean_pipes;
    }

    /* Only hookpipe[0] was in readfds, so we know why we're here */
    if(hook_read(&buf, sizeof(buf)) <= 0) {
      logwarn("hook: Cannot get banner from `%s' (PID %d): %s\n", hook, hookpid, strerror(errno));
    } else if (strncmp(buf, HOOK_BANNER, sizeof(HOOK_BANNER)-1)) {  /* XXX: Ignore final '\n' instead of '\0' */
      buf[sizeof(buf)-1]=0;
      logwarn("hook: Incorrect banner from `%s' (PID %d): `%s'\n", hook, hookpid, buf);
      goto clean_pipes;
    }
    loginfo("hook: `%s' in place\n", hook);
  }

  return;

clean_pipes:
  logdebug("hook: Giving up on `%s'\n", hook);
  close(pto[0]);
  close(pfrom[0]);
  close(pto[1]);
  close(pfrom[1]);
  hook_clean_pipes();
}

/** Determine whether an event hook has been enabled
 * \return 1 if hook enabled, 0 otherwise
 */
int
hook_enabled(void) {
 return hookpipe[0] >= 0 && hookpipe[1] >= 0;
}

/** Write commands to the event hook.
 * 
 * This function writes commands into the pipe connected to the event hook's
 * stdin. It takes the same parameters as write(2), but skips the file
 * descriptor.
 *
 * \param buf buffer from which +count+ bytes of data will be read out andwritten into event hook's +stdin+
 * \param count the number of bytes from +buf+ to write into the hook's +stdin+
 * \return the same as write(2), and sets +errno+ accordingly
 */
ssize_t
hook_write (const void *buf, size_t count)
{
  int n;
  if (-1 == hookpipe[1])
    return -1;
  logdebug("hook: Sending command fd %d: '%s'\n", hookpipe[1], buf);
  n = write(hookpipe[1], buf, count);
  return n;
}