Beispiel #1
0
/* This function is similar to pipe_connect but uses a socketpair and
   sets the I/O up to use sendmsg/recvmsg. */
static gpg_error_t
socketpair_connect (assuan_context_t ctx,
                    const char *name, const char **argv,
                    assuan_fd_t *fd_child_list,
                    void (*atfork) (void *opaque, int reserved),
                    void *atforkvalue)
{
  gpg_error_t err;
  int idx;
  int fds[2];
  char mypidstr[50];
  pid_t pid;
  int *child_fds = NULL;
  int child_fds_cnt = 0;
  struct at_socketpair_fork atp;
  int rc;

  TRACE_BEG3 (ctx, ASSUAN_LOG_CTX, "socketpair_connect", ctx,
	      "name=%s,atfork=%p,atforkvalue=%p", name ? name : "(null)",
	      atfork, atforkvalue);

  atp.user_atfork = atfork;
  atp.user_atforkvalue = atforkvalue;
  atp.parent_pid = getpid ();

  if (!ctx
      || (name && (!argv || !argv[0]))
      || (!name && !argv))
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (! ctx->flags.no_fixsignals)
    fix_signals ();

  sprintf (mypidstr, "%lu", (unsigned long)getpid ());

  if (fd_child_list)
    while (fd_child_list[child_fds_cnt] != ASSUAN_INVALID_FD)
      child_fds_cnt++;
  child_fds = _assuan_malloc (ctx, (child_fds_cnt + 2) * sizeof (int));
  if (! child_fds)
    return TRACE_ERR (gpg_err_code_from_syserror ());
  child_fds[1] = ASSUAN_INVALID_FD;
  if (fd_child_list)
    memcpy (&child_fds[1], fd_child_list, (child_fds_cnt + 1) * sizeof (int));

  if (_assuan_socketpair (ctx, AF_LOCAL, SOCK_STREAM, 0, fds))
    {
      TRACE_LOG1 ("socketpair failed: %s", strerror (errno));
      _assuan_free (ctx, child_fds);
      return TRACE_ERR (GPG_ERR_ASS_GENERAL);
    }
  atp.peer_fd = fds[1];
  child_fds[0] = fds[1];

  rc = _assuan_spawn (ctx, &pid, name, argv, ASSUAN_INVALID_FD,
		      ASSUAN_INVALID_FD, child_fds, at_socketpair_fork_cb,
		      &atp, 0);
  if (rc < 0)
    {
      err = gpg_err_code_from_syserror ();
      _assuan_close (ctx, fds[0]);
      _assuan_close (ctx, fds[1]);
      _assuan_free (ctx, child_fds);
      return TRACE_ERR (err);
    }

  /* For W32, the user needs to know the server-local names of the
     inherited handles.  Return them here.  Note that the translation
     of the peer socketpair fd (fd_child_list[0]) must be done by the
     wrapper program based on the environment variable
     _assuan_connection_fd.  */
  if (fd_child_list)
    {
      for (idx = 0; fd_child_list[idx] != -1; idx++)
	/* We add 1 to skip over the socketpair end.  */
	fd_child_list[idx] = child_fds[idx + 1];
    }

  _assuan_free (ctx, child_fds);

  /* If this is the server child process, exit early.  */
  if (! name && (*argv)[0] == 's')
    {
      _assuan_close (ctx, fds[0]);
      return 0;
    }

  _assuan_close (ctx, fds[1]);

  ctx->engine.release = _assuan_client_release;
  ctx->finish_handler = _assuan_client_finish;
  ctx->max_accepts = 1;
  ctx->inbound.fd  = fds[0];
  ctx->outbound.fd = fds[0];
  _assuan_init_uds_io (ctx);

  err = initial_handshake (ctx);
  if (err)
    _assuan_reset (ctx);
  return err;
}
Beispiel #2
0
int main(int argc, char** argv)
{
    int c, read_cfg = 0;

    init_config();

    while (1) {
        int option_index = 0;
        static struct option long_options[] = {
            {"detach", 0, 0, 'd'},
            {"nodetach", 0, 0, 'n'},
            {"pidfile", 1, 0, 'p'},
            {"quiet", 0, 0, 'q'},
            {"chroot", 1, 0, 'c'},
            {"disable-chroot", 0, 0, 'x'},
            {"file", 1, 0, 'f'},
            {"cfg-stdin", 0, 0, 'F'},
            {"user", 1, 0, 'u'},
            {"group", 1, 0, 'g'},
            {"interface", 1, 0, 'i'},
            {"remote", 0, 0, 'r'},
            {"help", 0, 0, 'h'},
            {"version", 0, 0, 'v'},
            {0, 0, 0, 0}
        };

        c = getopt_long(argc, argv, "rdnp:qc:xf:Fu:g:i:hv", long_options, &option_index);
        if (c == -1) break;

        switch (c) {

            case 'h':
                printf(
"ndyndns " PACKAGE_VERSION ", dyndns update client.  Licensed under 2-clause BSD.\n"
"Copyright (c) 2005-2013 Nicholas J. Kain\n"
"Usage: ndyndns [OPTIONS]\n"
"  -d, --detach                detach from TTY and daemonize\n"
"  -n, --nodetach              stay attached to TTY\n"
"  -q, --quiet                 don't print to std(out|err) or log\n"
"  -c, --chroot                path where ndyndns should chroot\n"
"  -x, --disable-chroot        do not actually chroot (not recommended)\n"
"  -f, --file                  configuration file\n"
"  -F, --cfg-stdin             read configuration file from standard input\n"
"  -p, --pidfile               pidfile path\n"
"  -u, --user                  user name that ndyndns should run as\n"
"  -g, --group                 group name that ndyndns should run as\n"
"  -i, --interface             interface ip to check (default: ppp0)\n"
"  -r, --remote                get ip from remote dyndns host (overrides -i)\n"
"  -h, --help                  print this help and exit\n"
"  -v, --version               print version and license info and exit\n"
                );
                exit(EXIT_FAILURE);
                break;

            case 'v':
                printf("ndyndns %s, dhcp client.\n", PACKAGE_VERSION);
                printf("Copyright (c) 2005-2013 Nicholas J. Kain\n"
                       "All rights reserved.\n\n"
                       "Redistribution and use in source and binary forms, with or without\n"
                       "modification, are permitted provided that the following conditions are met:\n\n"
                       "- Redistributions of source code must retain the above copyright notice,\n"
                       "  this list of conditions and the following disclaimer.\n"
                       "- Redistributions in binary form must reproduce the above copyright notice,\n"
                       "  this list of conditions and the following disclaimer in the documentation\n"
                       "  and/or other materials provided with the distribution.\n\n"
                       "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
                       "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
                       "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
                       "ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\n"
                       "LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
                       "CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
                       "SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
                       "INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
                       "CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
                       "ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
                       "POSSIBILITY OF SUCH DAMAGE.\n");
                exit(EXIT_FAILURE);
                break;

            case 'r':
                cfg_set_remote();
                break;

            case 'd':
                cfg_set_detach();
                break;

            case 'n':
                cfg_set_nodetach();
                break;

            case 'q':
                cfg_set_quiet();
                break;

            case 'x':
                disable_chroot();
                break;

            case 'c':
                update_chroot(optarg);
                break;

            case 'f':
                if (read_cfg) {
                    suicide("FATAL: duplicate configuration file data specified");
                } else {
                    read_cfg = 1;
                    if (parse_config(optarg) != 1)
                        suicide("FATAL: bad configuration data");
                }
                break;

            case 'F':
                if (read_cfg) {
                    suicide("ERROR: duplicate configuration file data specified");
                } else {
                    read_cfg = 1;
                    if (parse_config(NULL) != 1)
                        suicide("FATAL: bad configuration data");
                }
                break;

            case 'p':
                cfg_set_pidfile(optarg);
                break;

            case 'u':
                cfg_set_user(optarg);
                break;

            case 'g':
                cfg_set_group(optarg);
                break;

            case 'i':
                cfg_set_interface(optarg);
                break;
        }
    }

    if (!read_cfg)
        suicide("FATAL - no configuration file, exiting.");

    /* This is tricky -- we *must* use a name that will not be in hosts,
     * otherwise, at least with eglibc, the resolve and NSS libraries will not
     * be properly loaded.  The '.invalid' label is RFC-guaranteed to never
     * be installed into the root zone, so we use that to avoid harassing
     * DNS servers at start.
     */
    (void) gethostbyname("fail.invalid");

    if (chroot_enabled() && getuid())
        suicide("FATAL - I need root for chroot!");

    if (gflags_detach)
        if (daemon(0,0))
            suicide("FATAL - detaching fork failed");

    if (file_exists(pidfile, "w") == -1)
        suicide("FATAL - cannot open pidfile for write");
    write_pid(pidfile);

    umask(077);
    fix_signals();

    if (!chroot_exists())
        suicide("FATAL - No chroot path specified.  Refusing to run.");

    /* Note that failure cases are handled by called fns. */
    imprison(get_chroot());
    drop_root(cfg_uid, cfg_gid);

    /* Cover our tracks... */
    wipe_chroot();
    memset(pidfile, '\0', sizeof pidfile);

    curl_global_init(CURL_GLOBAL_ALL);
    use_ssl = check_ssl();

    do_work();

    exit(EXIT_SUCCESS);
}
Beispiel #3
0
static gpg_error_t
pipe_connect (assuan_context_t ctx,
	      const char *name, const char **argv,
	      assuan_fd_t *fd_child_list,
	      void (*atfork) (void *opaque, int reserved),
	      void *atforkvalue, unsigned int flags)
{
  gpg_error_t rc;
  assuan_fd_t rp[2];
  assuan_fd_t wp[2];
  pid_t pid;
  int res;
  struct at_pipe_fork atp;
  unsigned int spawn_flags;

  atp.user_atfork = atfork;
  atp.user_atforkvalue = atforkvalue;
  atp.parent_pid = getpid ();

  if (!ctx || !name || !argv || !argv[0])
    return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);

  if (! ctx->flags.no_fixsignals)
    fix_signals ();

  if (_assuan_pipe (ctx, rp, 1) < 0)
    return _assuan_error (ctx, gpg_err_code_from_syserror ());

  if (_assuan_pipe (ctx, wp, 0) < 0)
    {
      _assuan_close (ctx, rp[0]);
      _assuan_close_inheritable (ctx, rp[1]);
      return _assuan_error (ctx, gpg_err_code_from_syserror ());
    }

  spawn_flags = 0;
  if (flags & ASSUAN_PIPE_CONNECT_DETACHED)
    spawn_flags |= ASSUAN_SPAWN_DETACHED;

  /* FIXME: Use atfork handler that closes child fds on Unix.  */
  res = _assuan_spawn (ctx, &pid, name, argv, wp[0], rp[1],
		       fd_child_list, at_pipe_fork_cb, &atp, spawn_flags);
  if (res < 0)
    {
      rc = gpg_err_code_from_syserror ();
      _assuan_close (ctx, rp[0]);
      _assuan_close_inheritable (ctx, rp[1]);
      _assuan_close_inheritable (ctx, wp[0]);
      _assuan_close (ctx, wp[1]);
      return _assuan_error (ctx, rc);
    }

  /* Close the stdin/stdout child fds in the parent.  */
  _assuan_close_inheritable (ctx, rp[1]);
  _assuan_close_inheritable (ctx, wp[0]);

  ctx->engine.release = _assuan_client_release;
  ctx->engine.readfnc = _assuan_simple_read;
  ctx->engine.writefnc = _assuan_simple_write;
  ctx->engine.sendfd = NULL;
  ctx->engine.receivefd = NULL;
  ctx->finish_handler = _assuan_client_finish;
  ctx->max_accepts = 1;
  ctx->accept_handler = NULL;
  ctx->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
  ctx->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
  ctx->pid = pid;

  rc = initial_handshake (ctx);
  if (rc)
    _assuan_reset (ctx);
  return rc;
}