static int
open_noinherit (char const *name, int flags)
{
  int fd;
#if O_CLOEXEC
  /* 0 = unknown, 1 = yes, -1 = no.  */
  static int have_cloexec;
  if (have_cloexec >= 0)
    {
      fd = open (name, flags | O_CLOEXEC);
      if (have_cloexec == 0 && (0 <= fd || errno == EINVAL))
        have_cloexec = (0 <= fd ? 1 : -1);
      if (have_cloexec == 1)
        return fd;
    }
#endif

  fd = open (name, flags);
  if (0 <= fd && set_cloexec_flag (fd, true) != 0)
    {
      int saved_errno = errno;
      close (fd);
      fd = -1;
      errno = saved_errno;
    }
  return fd;
}
Exemplo n.º 2
0
Arquivo: util.c Projeto: ccache/ccache
static bool
init_log(void)
{
	extern struct conf *conf;

	if (debug_log_buffer || logfile || use_syslog) {
		return true;
	}
	assert(conf);
	if (conf->debug) {
		debug_log_buffer_capacity = DEBUG_LOG_BUFFER_MARGIN;
		debug_log_buffer = x_malloc(debug_log_buffer_capacity);
		debug_log_size = 0;
	}
	if (str_eq(conf->log_file, "")) {
		return conf->debug;
	}
#ifdef HAVE_SYSLOG
	if (str_eq(conf->log_file, "syslog")) {
		use_syslog = true;
		openlog("ccache", LOG_PID, LOG_USER);
		return true;
	}
#endif
	logfile = fopen(conf->log_file, "a");
	if (logfile) {
#ifndef _WIN32
		set_cloexec_flag(fileno(logfile));
#endif
		return true;
	} else {
		return false;
	}
}
Exemplo n.º 3
0
Arquivo: path.c Projeto: Distrotech/m4
/* Attempt to open FILE; if it opens, verify that it is not a
   directory, and ensure it does not leak across execs.  */
FILE *
m4_fopen (m4 *context, const char *file, const char *mode)
{
  FILE *fp = NULL;

  if (file)
    {
      struct stat st;
      int fd;

      fp = fopen (file, mode);
      fd = fileno (fp);

      if (fstat (fd, &st) == 0 && S_ISDIR (st.st_mode))
        {
          fclose (fp);
          errno = EISDIR;
          return NULL;
        }
      if (set_cloexec_flag (fileno (fp), true) != 0)
        m4_error (context, 0, errno, NULL,
                  _("cannot protect input file across forks"));
    }
  return fp;
}
Exemplo n.º 4
0
/*
 * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)).
 */
static int
open_device ( const char *name )
{
  int fd;

  fd = open ( name, O_RDONLY );
  if ( fd == -1 )
    log_fatal ("can't open %s: %s\n", name, strerror(errno) );

  if (set_cloexec_flag (fd))
    log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
               fd, strerror (errno));

  /* We used to do the following check, however it turned out that this
     is not portable since more OSes provide a random device which is
     sometimes implemented as another device type.

     struct stat sb;

     if( fstat( fd, &sb ) )
        log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
     if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
        log_fatal("invalid random device!\n" );
  */
  return fd;
}
Exemplo n.º 5
0
static int init_raw_sock_v4(int proto)
{
    int on = 1, off = 0, err = 0;
    int sock;

    sock = socket(AF_INET, SOCK_RAW, proto);
    set_cloexec_flag(sock, 1);
    HIP_IFEL(sock <= 0, 1, "Raw socket v4 creation failed. Not root?\n");

    /* RECV_ERR is off because it is not handled properly by hipd
     * (message length is -1 and this causes msg reading problems) */
    err = setsockopt(sock, IPPROTO_IP, IP_RECVERR, &off, sizeof(on));
    HIP_IFEL(err, -1, "setsockopt v4 recverr failed\n");
    err = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
    HIP_IFEL(err, -1, "setsockopt v4 failed to set broadcast \n");
    err = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));
    HIP_IFEL(err, -1, "setsockopt v4 pktinfo failed\n");
    err = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    HIP_IFEL(err, -1, "setsockopt v4 reuseaddr failed\n");

    return sock;

out_err:
    return -1;
}
Exemplo n.º 6
0
/* Initialise exec->wd_for_exec.

   We save in exec->wd_for_exec the directory whose path relative to
   cwd_df is dir.
 */
static bool
initialise_wd_for_exec (struct exec_val *execp, int cwd_fd, const char *dir)
{
  execp->wd_for_exec = xmalloc (sizeof (*execp->wd_for_exec));
  execp->wd_for_exec->name = NULL;
  execp->wd_for_exec->desc = openat (cwd_fd, dir, O_RDONLY);
  if (execp->wd_for_exec->desc < 0)
    return false;
  set_cloexec_flag (execp->wd_for_exec->desc, true);
  return true;
}
Exemplo n.º 7
0
int
save_cwd (struct saved_cwd *cwd)
{
  cwd->name = NULL;

  cwd->desc = open (".", O_SEARCH);
  if (!GNULIB_FCNTL_SAFER)
    cwd->desc = fd_safer (cwd->desc);
  if (cwd->desc < 0)
    {
      cwd->name = getcwd (NULL, 0);
      return cwd->name ? 0 : -1;
    }

  set_cloexec_flag (cwd->desc, true);
  return 0;
}
Exemplo n.º 8
0
Arquivo: debug.c Projeto: ezc/m4
bool
debug_set_output (const char *name)
{
  FILE *fp;

  if (name == NULL)
    debug_set_file (stderr);
  else if (*name == '\0')
    debug_set_file (NULL);
  else
    {
      fp = fopen (name, "a");
      if (fp == NULL)
	return false;

      if (set_cloexec_flag (fileno (fp), true) != 0)
	M4ERROR ((warning_status, errno,
		  "Warning: cannot protect debug file across forks"));
      debug_set_file (fp);
    }
  return true;
}
Exemplo n.º 9
0
/*
 * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
 * exists)).  If RETRY is true, the function does not terminate with
 * a fatal error but retries until it is able to reopen the device.
 */
static int
open_device (const char *name, int retry)
{
  int fd;

  if (retry)
    _gcry_random_progress ("open_dev_random", 'X', 1, 0);
 again:
  fd = open (name, O_RDONLY);
  if (fd == -1 && retry)
    {
      struct timeval tv;

      tv.tv_sec = 5;
      tv.tv_usec = 0;
      _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
      select (0, NULL, NULL, NULL, &tv);
      goto again;
    }
  if (fd == -1)
    log_fatal ("can't open %s: %s\n", name, strerror(errno) );

  if (set_cloexec_flag (fd))
    log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
               fd, strerror (errno));

  /* We used to do the following check, however it turned out that this
     is not portable since more OSes provide a random device which is
     sometimes implemented as another device type.

     struct stat sb;

     if( fstat( fd, &sb ) )
        log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
     if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
        log_fatal("invalid random device!\n" );
  */
  return fd;
}
Exemplo n.º 10
0
/* Change the debug output to file NAME.  If NAME is NULL, debug
   output is reverted to stderr, and if empty debug output is
   discarded.  Return true iff the output stream was changed.  Report
   errors on behalf of CALLER.  */
bool
m4_debug_set_output (m4 *context, const m4_call_info *caller, const char *name)
{
  FILE *fp;

  assert (context);

  if (name == NULL)
    set_debug_file (context, caller, stderr);
  else if (*name == '\0')
    set_debug_file (context, caller, NULL);
  else
    {
      fp = fopen (name, "a");
      if (fp == NULL)
        return false;

      if (set_cloexec_flag (fileno (fp), true) != 0)
        m4_warn (context, errno, caller,
                 _("cannot protect debug file across forks"));
      set_debug_file (context, caller, fp);
    }
  return true;
}
Exemplo n.º 11
0
/* recvfd receives a file descriptor through the socket.
   The flags are a bitmask, possibly including O_CLOEXEC (defined in <fcntl.h>).

   Return the fd on success, or -1 with errno set in case of error.
*/
int
recvfd (int sock, int flags)
{
  char byte = 0;
  struct iovec iov;
  struct msghdr msg;
  int fd = -1;
# ifdef CMSG_FIRSTHDR
  struct cmsghdr *cmsg;
  char buf[CMSG_SPACE (sizeof fd)];
  int flags_recvmsg = flags & O_CLOEXEC ? MSG_CMSG_CLOEXEC : 0;
# endif

  if ((flags & ~O_CLOEXEC) != 0)
    {
      errno = EINVAL;
      return -1;
    }

  /* send at least one char */
  memset (&msg, 0, sizeof msg);
  iov.iov_base = &byte;
  iov.iov_len = 1;
  msg.msg_iov = &iov;
  msg.msg_iovlen = 1;
  msg.msg_name = NULL;
  msg.msg_namelen = 0;

# ifdef CMSG_FIRSTHDR
  msg.msg_control = buf;
  msg.msg_controllen = sizeof buf;
  cmsg = CMSG_FIRSTHDR (&msg);
  cmsg->cmsg_level = SOL_SOCKET;
  cmsg->cmsg_type = SCM_RIGHTS;
  cmsg->cmsg_len = CMSG_LEN (sizeof fd);
  /* Initialize the payload: */
  memcpy (CMSG_DATA (cmsg), &fd, sizeof fd);
  msg.msg_controllen = cmsg->cmsg_len;

  if (recvmsg (sock, &msg, flags_recvmsg) < 0)
    return -1;

  cmsg = CMSG_FIRSTHDR (&msg);
  /* be paranoiac */
  if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN (sizeof fd)
      || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
    {
      /* fake errno: at end the file is not available */
      errno = EACCES;
      return -1;
    }

  memcpy (&fd, CMSG_DATA (cmsg), sizeof fd);

  /* set close-on-exec flag */
  if (!MSG_CMSG_CLOEXEC && (flags & O_CLOEXEC))
    {
      if (set_cloexec_flag (fd, true) < 0)
        {
          int saved_errno = errno;
          (void) close (fd);
          errno = saved_errno;
          return -1;
        }
    }

# elif HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS
  msg.msg_accrights = &fd;
  msg.msg_accrightslen = sizeof fd;
  if (recvmsg (sock, &msg, 0) < 0)
    return -1;

  /* set close-on-exec flag */
  if (flags & O_CLOEXEC)
    {
      if (set_cloexec_flag (fd, true) < 0)
        {
          int saved_errno = errno;
          close (fd);
          errno = saved_errno;
          return -1;
        }
    }
# else
  errno = ENOSYS;
# endif

  return fd;
}
Exemplo n.º 12
0
static int
launch_uml (guestfs_h *g, void *datav, const char *arg)
{
  struct backend_uml_data *data = datav;
  CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (cmdline);
  int console_sock = -1, daemon_sock = -1;
  int r;
  int csv[2], dsv[2];
  CLEANUP_FREE char *kernel = NULL, *dtb = NULL,
    *initrd = NULL, *appliance = NULL;
  int has_appliance_drive;
  CLEANUP_FREE char *appliance_cow = NULL;
  uint32_t size;
  CLEANUP_FREE void *buf = NULL;
  struct drive *drv;
  size_t i;
  struct hv_param *hp;
  char *term = getenv ("TERM");

  if (!uml_supported (g))
    return -1;

  if (!g->nr_drives) {
    error (g, _("you must call guestfs_add_drive before guestfs_launch"));
    return -1;
  }

  /* Assign a random unique ID to this run. */
  if (guestfs___random_string (data->umid, UML_UMID_LEN) == -1) {
    perrorf (g, "guestfs___random_string");
    return -1;
  }

  /* Locate and/or build the appliance. */
  if (guestfs___build_appliance (g, &kernel, &dtb, &initrd, &appliance) == -1)
    return -1;
  has_appliance_drive = appliance != NULL;

  /* Create COW overlays for the appliance.  Note that the documented
   * syntax ubd0=cow,orig does not work since kernel 3.3.  See:
   * http://thread.gmane.org/gmane.linux.uml.devel/13556
   */
  if (has_appliance_drive) {
    appliance_cow = make_cow_overlay (g, appliance);
    if (!appliance_cow)
      goto cleanup0;
  }

  /* The socket that the daemon will talk to us on.
   */
  if (socketpair (AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, dsv) == -1) {
    perrorf (g, "socketpair");
    goto cleanup0;
  }

  /* The console socket. */
  if (!g->direct_mode) {
    if (socketpair (AF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, csv) == -1) {
      perrorf (g, "socketpair");
      close (dsv[0]);
      close (dsv[1]);
      goto cleanup0;
    }
  }

  /* Construct the vmlinux command line.  We have to do this before
   * forking, because after fork we are not allowed to use
   * non-signal-safe functions such as malloc.
   */
#define ADD_CMDLINE(str) \
  guestfs___add_string (g, &cmdline, (str))
#define ADD_CMDLINE_PRINTF(fs,...) \
  guestfs___add_sprintf (g, &cmdline, (fs), ##__VA_ARGS__)

  ADD_CMDLINE (g->hv);

  /* Give this instance a unique random ID. */
  ADD_CMDLINE_PRINTF ("umid=%s", data->umid);

  /* Set memory size. */
  ADD_CMDLINE_PRINTF ("mem=%dM", g->memsize);

  /* vmlinux appears to ignore this, but let's add it anyway. */
  ADD_CMDLINE_PRINTF ("initrd=%s", initrd);

  /* Make sure our appliance init script runs first. */
  ADD_CMDLINE ("init=/init");

  /* This tells the /init script not to reboot at the end. */
  ADD_CMDLINE ("guestfs_noreboot=1");

  /* Root filesystem should be mounted read-write (default seems to
   * be "ro").
   */
  ADD_CMDLINE ("rw");

  /* See also guestfs___appliance_command_line. */
  if (g->verbose)
    ADD_CMDLINE ("guestfs_verbose=1");

  ADD_CMDLINE ("panic=1");

  ADD_CMDLINE_PRINTF ("TERM=%s", term ? term : "linux");

  if (g->selinux)
    ADD_CMDLINE ("selinux=1 enforcing=0");
  else
    ADD_CMDLINE ("selinux=0");

  /* XXX This isn't quite right.  Multiple append args won't work. */
  if (g->append)
    ADD_CMDLINE (g->append);

  /* Add the drives. */
  ITER_DRIVES (g, i, drv) {
    if (!drv->overlay)
      ADD_CMDLINE_PRINTF ("ubd%zu=%s", i, drv->src.u.path);
    else
      ADD_CMDLINE_PRINTF ("ubd%zu=%s", i, drv->overlay);
  }

  /* Add the ext2 appliance drive (after all the drives). */
  if (has_appliance_drive) {
    char drv_name[64] = "ubd";
    guestfs___drive_name (g->nr_drives, &drv_name[3]);

    ADD_CMDLINE_PRINTF ("ubd%zu=%s", g->nr_drives, appliance_cow);
    ADD_CMDLINE_PRINTF ("root=/dev/%s", drv_name);
  }

  /* Create the daemon socket. */
  ADD_CMDLINE_PRINTF ("ssl3=fd:%d", dsv[1]);
  ADD_CMDLINE ("guestfs_channel=/dev/ttyS3");

#if 0 /* XXX This could be made to work. */
#ifdef VALGRIND_DAEMON
  /* Set up virtio-serial channel for valgrind messages. */
  ADD_CMDLINE ("-chardev");
  ADD_CMDLINE_PRINTF ("file,path=%s/valgrind.log.%d,id=valgrind",
                      VALGRIND_LOG_PATH, getpid ());
  ADD_CMDLINE ("-device");
  ADD_CMDLINE ("virtserialport,chardev=valgrind,name=org.libguestfs.valgrind");
#endif
#endif

  /* Add any vmlinux parameters. */
  for (hp = g->hv_params; hp; hp = hp->next) {
    ADD_CMDLINE (hp->hv_param);
    if (hp->hv_value)
      ADD_CMDLINE (hp->hv_value);
    }

  /* Finish off the command line. */
  guestfs___end_stringsbuf (g, &cmdline);

  r = fork ();
  if (r == -1) {
    perrorf (g, "fork");
    if (!g->direct_mode) {
      close (csv[0]);
      close (csv[1]);
    }
    close (dsv[0]);
    close (dsv[1]);
    goto cleanup0;
  }

  if (r == 0) {                 /* Child (vmlinux). */
    /* Set up the daemon socket for the child. */
    close (dsv[0]);
    set_cloexec_flag (dsv[1], 0); /* so it doesn't close across exec */

    if (!g->direct_mode) {
      /* Set up stdin, stdout, stderr. */
      close (0);
      close (1);
      close (csv[0]);

      /* We set the FD_CLOEXEC flag on the socket above, but now (in
       * the child) it's safe to unset this flag so vmlinux can use the
       * socket.
       */
      set_cloexec_flag (csv[1], 0);

      /* Stdin. */
      if (dup (csv[1]) == -1) {
      dup_failed:
        perror ("dup failed");
        _exit (EXIT_FAILURE);
      }
      /* Stdout. */
      if (dup (csv[1]) == -1)
        goto dup_failed;

      /* Send stderr to the pipe as well. */
      close (2);
      if (dup (csv[1]) == -1)
        goto dup_failed;

      close (csv[1]);
    }

    /* Dump the command line (after setting up stderr above). */
    if (g->verbose)
      print_vmlinux_command_line (g, cmdline.argv);

    /* Put vmlinux in a new process group. */
    if (g->pgroup)
      setpgid (0, 0);

    setenv ("LC_ALL", "C", 1);

    execv (g->hv, cmdline.argv); /* Run vmlinux. */
    perror (g->hv);
    _exit (EXIT_FAILURE);
  }

  /* Parent (library). */
  data->pid = r;

  /* Fork the recovery process off which will kill vmlinux if the
   * parent process fails to do so (eg. if the parent segfaults).
   */
  data->recoverypid = -1;
  if (g->recovery_proc) {
    r = fork ();
    if (r == 0) {
      int i, fd, max_fd;
      struct sigaction sa;
      pid_t vmlinux_pid = data->pid;
      pid_t parent_pid = getppid ();

      /* Remove all signal handlers.  See the justification here:
       * https://www.redhat.com/archives/libvir-list/2008-August/msg00303.html
       * We don't mask signal handlers yet, so this isn't completely
       * race-free, but better than not doing it at all.
       */
      memset (&sa, 0, sizeof sa);
      sa.sa_handler = SIG_DFL;
      sa.sa_flags = 0;
      sigemptyset (&sa.sa_mask);
      for (i = 1; i < NSIG; ++i)
        sigaction (i, &sa, NULL);

      /* Close all other file descriptors.  This ensures that we don't
       * hold open (eg) pipes from the parent process.
       */
      max_fd = sysconf (_SC_OPEN_MAX);
      if (max_fd == -1)
        max_fd = 1024;
      if (max_fd > 65536)
        max_fd = 65536; /* bound the amount of work we do here */
      for (fd = 0; fd < max_fd; ++fd)
        close (fd);

      /* It would be nice to be able to put this in the same process
       * group as vmlinux (ie. setpgid (0, vmlinux_pid)).  However
       * this is not possible because we don't have any guarantee here
       * that the vmlinux process has started yet.
       */
      if (g->pgroup)
        setpgid (0, 0);

      /* Writing to argv is hideously complicated and error prone.  See:
       * http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/misc/ps_status.c;hb=HEAD
       */

      /* Loop around waiting for one or both of the other processes to
       * disappear.  It's fair to say this is very hairy.  The PIDs that
       * we are looking at might be reused by another process.  We are
       * effectively polling.  Is the cure worse than the disease?
       */
      for (;;) {
        if (kill (vmlinux_pid, 0) == -1)
          /* vmlinux's gone away, we aren't needed */
          _exit (EXIT_SUCCESS);
        if (kill (parent_pid, 0) == -1) {
          /* Parent's gone away, vmlinux still around, so kill vmlinux. */
          kill (data->pid, SIGKILL);
          _exit (EXIT_SUCCESS);
        }
        sleep (2);
      }
    }

    /* Don't worry, if the fork failed, this will be -1.  The recovery
     * process isn't essential.
     */
    data->recoverypid = r;
  }

  if (!g->direct_mode) {
    /* Close the other end of the console socketpair. */
    close (csv[1]);

    console_sock = csv[0];      /* stdin of child */
    csv[0] = -1;
  }

  daemon_sock = dsv[0];
  close (dsv[1]);
  dsv[0] = -1;

  g->state = LAUNCHING;

  /* Wait for vmlinux to start and to connect back to us via
   * virtio-serial and send the GUESTFS_LAUNCH_FLAG message.
   */
  g->conn =
    guestfs___new_conn_socket_connected (g, daemon_sock, console_sock);
  if (!g->conn)
    goto cleanup1;

  /* g->conn now owns these sockets. */
  daemon_sock = console_sock = -1;

  /* We now have to wait for vmlinux to start up, the daemon to start
   * running, and for it to send the GUESTFS_LAUNCH_FLAG to us.
   */
  r = guestfs___recv_from_daemon (g, &size, &buf);

  if (r == -1) {
    guestfs___launch_failed_error (g);
    goto cleanup1;
  }

  if (size != GUESTFS_LAUNCH_FLAG) {
    guestfs___launch_failed_error (g);
    goto cleanup1;
  }

  if (g->verbose)
    guestfs___print_timestamped_message (g, "appliance is up");

  /* This is possible in some really strange situations, such as
   * guestfsd starts up OK but then vmlinux immediately exits.  Check
   * for it because the caller is probably expecting to be able to
   * send commands after this function returns.
   */
  if (g->state != READY) {
    error (g, _("vmlinux launched and contacted daemon, but state != READY"));
    goto cleanup1;
  }

  if (has_appliance_drive)
    guestfs___add_dummy_appliance_drive (g);

  return 0;

 cleanup1:
  if (!g->direct_mode && csv[0] >= 0)
    close (csv[0]);
  if (dsv[0] >= 0)
    close (dsv[0]);
  if (data->pid > 0) kill (data->pid, SIGKILL);
  if (data->recoverypid > 0) kill (data->recoverypid, SIGKILL);
  if (data->pid > 0) waitpid (data->pid, NULL, 0);
  if (data->recoverypid > 0) waitpid (data->recoverypid, NULL, 0);
  data->pid = 0;
  data->recoverypid = 0;
  memset (&g->launch_t, 0, sizeof g->launch_t);

 cleanup0:
  if (daemon_sock >= 0)
    close (daemon_sock);
  if (console_sock >= 0)
    close (console_sock);
  if (g->conn) {
    g->conn->ops->free_connection (g, g->conn);
    g->conn = NULL;
  }
  g->state = CONFIG;
  return -1;
}
Exemplo n.º 13
0
/* Registration function. Needs to be called once by each process (not thread)
* process_name is argv[0] or whatever you'd like.
* assert_buf_ptr needs to point to the 128 byte assert buffer.
*/
int register_crash_handler(const char* process_name,unsigned char* assert_buf_ptr) {
	struct sigaction act; /* Signal handler register struct */
	int ret; /* Return value for various calls */
	int pfd[2]; /* Pipe file descriptor array */

	/* See ahead about these two: */
	void * dummy_trace_array[1];
	unsigned int dummy_trace_size;

	assert(sizeof(g_crash_msg)<=CRASH_MAX_MSG_SIZE);

	if(!process_name || !assert_buf_ptr) {
		return EINVAL;
	}
	#ifdef USE_THREADS
	ret=pthread_spin_init(&g_thread_lock, PTHREAD_PROCESS_PRIVATE);
	if(ret) {
		return ret;
	}
	#endif /* USE_THREADS */
	/* If we're called again (perhaps after a fork() ), the pipe is already open.
	* That's just fine with us */
	if(-1==g_logfd) {
		/* Grab us a pipe to communicate with our crash daemon */
		ret=pipe(pfd);
		if(-1==ret) {
			return errno;
		}
		g_logfd=pfd[1]; /* Grab the write end of the pipe */

		/* If the caller program execs, we want the pipe to close,
		* because it's not likely a random program will have the
		* right signal handler set to use the crash daemon. */
		ret=set_cloexec_flag(g_logfd,1);
		if(-1==ret) {
			return errno;
		}
		/* Set our daemon up */
		crashd_main(1,process_name,pfd);
		close(pfd[0]);
	}
	/* This requires some explaining:
	* In theory, neither backtrace nor backtrace_symbold_fd call malloc and friends so
	* we are able to use them in a an exception handler safely.
	*
	* In practice recent glibc versions put these function in a seperate shared library
	* called libgcc_s.so when gets loaded automagically by the dynamic linker when any these
	* of these functions are first used and, you guessed it, the dynamic linker uses malloc
	* in the process to get some internal buffer.
	*
	* We therefore give these a dummy call here during registration to assure that the library
	* gets loaded where it's safe to malloc.
	*/
	dummy_trace_size=backtrace(dummy_trace_array, 1);
	backtrace_symbols_fd(dummy_trace_array, dummy_trace_size,-1);

	/* This data we can already grab during registration, not need to wait for crash */
	g_crash_msg.magic=CRASH_MSG_MAGIC;
	memcpy(g_crash_msg.process_name, process_name, strnlen(process_name, CRASH_MAX_PROCESS_NAME_SIZE)+1);
	g_crash_msg.process_id=getpid();

	g_assert_buf_ptr=assert_buf_ptr;

	/* Prepare a sigaction struct for exception handler registrations */
	memset(&act,0,sizeof(act));
	act.sa_sigaction=fault_handler;
	/* No signals during handler run, please */
	sigfillset(&act.sa_mask);
	/* We want the 3 parameter form of the handler with the siginfo_t addtional data */
	act.sa_flags=SA_SIGINFO;

	/* Register the handler for all exception signals. */
	ret=sigaction(SIGSEGV,&act,NULL);
	ret|=sigaction(SIGILL,&act,NULL);
	ret|=sigaction(SIGFPE,&act,NULL);
	ret|=sigaction(SIGBUS,&act,NULL);
	ret|=sigaction(SIGQUIT,&act,NULL);

	return ret;
}
Exemplo n.º 14
0
int
guestfs_impl_mount_local (guestfs_h *g, const char *localmountpoint,
			  const struct guestfs_mount_local_argv *optargs)
{
  const char *t;
  struct fuse_args args = FUSE_ARGS_INIT (0, NULL);
  struct fuse_chan *ch;
  int fd;

  /* You can only mount each handle in one place in one thread. */
  gl_lock_lock (mount_local_lock);
  t = g->localmountpoint;
  gl_lock_unlock (mount_local_lock);
  if (t) {
    error (g, _("filesystem is already mounted in another thread"));
    return -1;
  }

  if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_READONLY_BITMASK)
    g->ml_read_only = optargs->readonly;
  else
    g->ml_read_only = 0;
  if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_CACHETIMEOUT_BITMASK)
    g->ml_dir_cache_timeout = optargs->cachetimeout;
  else
    g->ml_dir_cache_timeout = 60;
  if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_DEBUGCALLS_BITMASK)
    g->ml_debug_calls = optargs->debugcalls;
  else
    g->ml_debug_calls = 0;

  /* Initialize the directory caches in the handle. */
  if (init_dir_caches (g) == -1)
    return -1;

  /* Create the FUSE 'args'. */
  /* XXX we don't have a program name */
  if (fuse_opt_add_arg (&args, "guestfs_mount_local") == -1) {
  arg_error:
    perrorf (g, _("fuse_opt_add_arg: %s"), localmountpoint);
    fuse_opt_free_args (&args);
    guestfs_int_free_fuse (g);
    return -1;
  }

  if (optargs->bitmask & GUESTFS_MOUNT_LOCAL_OPTIONS_BITMASK) {
    if (fuse_opt_add_arg (&args, "-o") == -1 ||
        fuse_opt_add_arg (&args, optargs->options) == -1)
      goto arg_error;
  }

  debug (g, "%s: fuse_mount %s", __func__, localmountpoint);

  /* Create the FUSE mountpoint. */
  ch = fuse_mount (localmountpoint, &args);
  if (ch == NULL) {
    perrorf (g, _("fuse_mount: %s"), localmountpoint);
    fuse_opt_free_args (&args);
    guestfs_int_free_fuse (g);
    return -1;
  }

  /* Set F_CLOEXEC on the channel.  XXX libfuse should do this. */
  fd = fuse_chan_fd (ch);
  if (fd >= 0)
    set_cloexec_flag (fd, 1);

  debug (g, "%s: fuse_new", __func__);

  /* Create the FUSE handle. */
  g->fuse = fuse_new (ch, &args,
                      &mount_local_operations, sizeof mount_local_operations,
                      g);
  if (!g->fuse) {
    perrorf (g, _("fuse_new: %s"), localmountpoint);
    fuse_unmount (localmountpoint, ch);
    fuse_opt_free_args (&args);
    guestfs_int_free_fuse (g);
    return -1;
  }

  fuse_opt_free_args (&args);

  debug (g, "%s: leaving fuse_mount_local", __func__);

  /* Set g->localmountpoint in the handle. */
  gl_lock_lock (mount_local_lock);
  g->localmountpoint = localmountpoint;
  gl_lock_unlock (mount_local_lock);

  return 0;
}
Exemplo n.º 15
0
FILE *
sharefile_fopen (sharefile_handle h, const char *filename)
{
  struct sharefile *p = h;
  struct SharefileEntry *new_entry;

  new_entry = malloc (sizeof (struct SharefileEntry));
  if (!new_entry)
    return NULL;

  new_entry->name = strdup (filename);
  if (NULL == new_entry->name)
    {
      free (new_entry);
      return NULL;
    }

  if (NULL == (new_entry->fp = fopen_safer (filename, p->mode)))
    {
      free (new_entry);
      return NULL;
    }
  else
    {
      struct stat st;
      const int fd = fileno (new_entry->fp);
      assert (fd >= 0);

      set_cloexec_flag (fd, true);
      if (fstat (fd, &st) < 0)
        {
	  entry_free (new_entry);
          return NULL;
        }
      else
        {
	  void *existing;

          new_entry->device = st.st_dev;
          new_entry->inode = st.st_ino;

          existing = hash_lookup (p->table, new_entry);
          if (existing)	    /* We have previously opened that file. */
	    {
	      entry_free (new_entry); /* don't need new_entry. */
	      return ((const struct SharefileEntry*)existing)->fp;
	    }
          else /* We didn't open it already */
	    {
	      if (hash_insert (p->table, new_entry))
		{
		  return new_entry->fp;
		}
	      else			/* failed to insert in hashtable. */
		{
		  const int save_errno = errno;
		  entry_free (new_entry);
		  errno = save_errno;
		  return NULL;
		}
	    }
        }
    }
}
Exemplo n.º 16
0
int
open (const char *filename, int flags, ...)
{
  /* 0 = unknown, 1 = yes, -1 = no.  */
#if GNULIB_defined_O_CLOEXEC
  int have_cloexec = -1;
#else
  static int have_cloexec;
#endif

  mode_t mode;
  int fd;

  mode = 0;
  if (flags & O_CREAT)
    {
      va_list arg;
      va_start (arg, flags);

      /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4
         creates crashing code when 'mode_t' is smaller than 'int'.  */
      mode = va_arg (arg, PROMOTED_MODE_T);

      va_end (arg);
    }

#if GNULIB_defined_O_NONBLOCK
  /* The only known platform that lacks O_NONBLOCK is mingw, but it
     also lacks named pipes and Unix sockets, which are the only two
     file types that require non-blocking handling in open().
     Therefore, it is safe to ignore O_NONBLOCK here.  It is handy
     that mingw also lacks openat(), so that is also covered here.  */
  flags &= ~O_NONBLOCK;
#endif

#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
  if (strcmp (filename, "/dev/null") == 0)
    filename = "NUL";
#endif

#if OPEN_TRAILING_SLASH_BUG
  /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR
     is specified, then fail.
     Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
     says that
       "A pathname that contains at least one non-slash character and that
        ends with one or more trailing slashes shall be resolved as if a
        single dot character ( '.' ) were appended to the pathname."
     and
       "The special filename dot shall refer to the directory specified by
        its predecessor."
     If the named file already exists as a directory, then
       - if O_CREAT is specified, open() must fail because of the semantics
         of O_CREAT,
       - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX
         <http://www.opengroup.org/susv3/functions/open.html> says that it
         fails with errno = EISDIR in this case.
     If the named file does not exist or does not name a directory, then
       - if O_CREAT is specified, open() must fail since open() cannot create
         directories,
       - if O_WRONLY or O_RDWR is specified, open() must fail because the
         file does not contain a '.' directory.  */
  if (flags & (O_CREAT | O_WRONLY | O_RDWR))
    {
      size_t len = strlen (filename);
      if (len > 0 && filename[len - 1] == '/')
        {
          errno = EISDIR;
          return -1;
        }
    }
#endif

  fd = orig_open (filename,
                  flags & ~(have_cloexec <= 0 ? O_CLOEXEC : 0), mode);

  if (flags & O_CLOEXEC)
    {
      if (! have_cloexec)
        {
          if (0 <= fd)
            have_cloexec = 1;
          else if (errno == EINVAL)
            {
              fd = orig_open (filename, flags & ~O_CLOEXEC, mode);
              have_cloexec = -1;
            }
        }
      if (have_cloexec < 0 && 0 <= fd)
        set_cloexec_flag (fd, true);
    }


#if REPLACE_FCHDIR
  /* Implementing fchdir and fdopendir requires the ability to open a
     directory file descriptor.  If open doesn't support that (as on
     mingw), we use a dummy file that behaves the same as directories
     on Linux (ie. always reports EOF on attempts to read()), and
     override fstat() in fchdir.c to hide the fact that we have a
     dummy.  */
  if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
      && ((flags & O_ACCMODE) == O_RDONLY
          || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH)))
    {
      struct stat statbuf;
      if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
        {
          /* Maximum recursion depth of 1.  */
          fd = open ("/dev/null", flags, mode);
          if (0 <= fd)
            fd = _gl_register_fd (fd, filename);
        }
      else
        errno = EACCES;
    }
#endif

#if OPEN_TRAILING_SLASH_BUG
  /* If the filename ends in a slash and fd does not refer to a directory,
     then fail.
     Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html>
     says that
       "A pathname that contains at least one non-slash character and that
        ends with one or more trailing slashes shall be resolved as if a
        single dot character ( '.' ) were appended to the pathname."
     and
       "The special filename dot shall refer to the directory specified by
        its predecessor."
     If the named file without the slash is not a directory, open() must fail
     with ENOTDIR.  */
  if (fd >= 0)
    {
      /* We know len is positive, since open did not fail with ENOENT.  */
      size_t len = strlen (filename);
      if (filename[len - 1] == '/')
        {
          struct stat statbuf;

          if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
            {
              close (fd);
              errno = ENOTDIR;
              return -1;
            }
        }
    }
#endif

#if REPLACE_FCHDIR
  if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
    fd = _gl_register_fd (fd, filename);
#endif

  return fd;
}
Exemplo n.º 17
0
/**
 * Be a standalone server, with responsibility for sockets and forking
 * children.  Puts the daemon in the background and detaches from the
 * controlling tty.
 **/
int dcc_standalone_server(void)
{
    int listen_fd;
    int n_cpus;
    int ret;
#ifdef HAVE_AVAHI
    void *avahi = NULL;
#endif

    if ((ret = dcc_socket_listen(arg_port, &listen_fd, opt_listen_addr)) != 0)
        return ret;

    dcc_defer_accept(listen_fd);

    set_cloexec_flag(listen_fd, 1);

    if (dcc_ncpus(&n_cpus) == 0)
        rs_log_info("%d CPU%s online on this server", n_cpus, n_cpus == 1 ? "" : "s");

    /* By default, allow one job per CPU, plus two for the pot.  The extra
     * ones are started to allow for a bit of extra concurrency so that the
     * machine is not idle waiting for disk or network IO. */
    if (arg_max_jobs)
        dcc_max_kids = arg_max_jobs;
    else
        dcc_max_kids = 2 + n_cpus;

    rs_log_info("allowing up to %d active jobs", dcc_max_kids);

    if (!opt_no_detach) {
        /* Don't go into the background until we're listening and
         * ready.  This is useful for testing -- when the daemon
         * detaches, we know we can go ahead and try to connect.  */
        dcc_detach();
    } else {
        /* Still create a new process group, even if not detached */
        rs_trace("not detaching");
        if ((ret = dcc_new_pgrp()) != 0)
            return ret;
        dcc_save_pid(getpid());
    }

    /* Don't catch signals until we've detached or created a process group. */
    dcc_daemon_catch_signals();

#ifdef HAVE_AVAHI
    /* Zeroconf registration */
    if (opt_zeroconf) {
        if (!(avahi = dcc_zeroconf_register((uint16_t) arg_port, n_cpus, dcc_max_kids)))
            return EXIT_CONNECT_FAILED;
    }
#endif

    /* This is called in the master daemon, whether that is detached or
     * not.  */
    dcc_master_pid = getpid();

    if (opt_no_fork) {
        dcc_log_daemon_started("non-forking daemon");
        dcc_nofork_parent(listen_fd);
        ret = 0;
    } else {
        dcc_log_daemon_started("preforking daemon");
        ret = dcc_preforking_parent(listen_fd);
    }

#ifdef HAVE_AVAHI
    /* Remove zeroconf registration */
    if (opt_zeroconf) {
        if (dcc_zeroconf_unregister(avahi) != 0)
            return EXIT_CONNECT_FAILED;
    }
#endif

    return ret;
}
Exemplo n.º 18
0
int
main (void)
{
  int i;
  int fd;

  /* We close fd 2 later, so save it in fd 10.  */
  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
    return 2;

  /* Create file for later checks.  */
  fd = creat (witness, 0600);
  ASSERT (STDERR_FILENO < fd);

  /* Four iterations, with progressively more standard descriptors
     closed.  */
  for (i = -1; i <= STDERR_FILENO; i++)
    {
      if (0 <= i)
        ASSERT (close (i) == 0);

      /* Detect errors.  */
      errno = 0;
      ASSERT (dup (-1) == -1);
      ASSERT (errno == EBADF);
      errno = 0;
      ASSERT (dup (10000000) == -1);
      ASSERT (errno == EBADF);
      close (fd + 1);
      errno = 0;
      ASSERT (dup (fd + 1) == -1);
      ASSERT (errno == EBADF);

      /* Preserve text vs. binary.  */
      setmode (fd, O_BINARY);
      ASSERT (dup (fd) == fd + 1);
      ASSERT (is_open (fd + 1));
      ASSERT (is_inheritable (fd + 1));
      ASSERT (is_mode (fd + 1, O_BINARY));

      ASSERT (close (fd + 1) == 0);
      setmode (fd, O_TEXT);
      ASSERT (dup (fd) == fd + 1);
      ASSERT (is_open (fd + 1));
      ASSERT (is_inheritable (fd + 1));
      ASSERT (is_mode (fd + 1, O_TEXT));

      /* Create cloexec copy.  */
      ASSERT (close (fd + 1) == 0);
      ASSERT (fd_safer_flag (dup_cloexec (fd), O_CLOEXEC) == fd + 1);
      ASSERT (set_cloexec_flag (fd + 1, true) == 0);
      ASSERT (is_open (fd + 1));
      ASSERT (!is_inheritable (fd + 1));
      ASSERT (close (fd) == 0);

      /* dup always creates inheritable copies.  Also, check that
         earliest slot past std fds is used.  */
      ASSERT (dup (fd + 1) == fd);
      ASSERT (is_open (fd));
      ASSERT (is_inheritable (fd));
      ASSERT (close (fd + 1) == 0);
    }

  /* Cleanup.  */
  ASSERT (close (fd) == 0);
  ASSERT (unlink (witness) == 0);

  return 0;
}
Exemplo n.º 19
0
int
main (void)
{
  const char *file = "test-cloexec.tmp";
  int fd = creat (file, 0600);
  int fd2;

  /* Assume std descriptors were provided by invoker.  */
  ASSERT (STDERR_FILENO < fd);
  ASSERT (is_inheritable (fd));

  /* Normal use of set_cloexec_flag.  */
  ASSERT (set_cloexec_flag (fd, true) == 0);
#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
  ASSERT (!is_inheritable (fd));
#endif
  ASSERT (set_cloexec_flag (fd, false) == 0);
  ASSERT (is_inheritable (fd));

  /* Normal use of dup_cloexec.  */
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (!is_inheritable (fd2));
  ASSERT (close (fd) == 0);
  ASSERT (dup_cloexec (fd2) == fd);
  ASSERT (!is_inheritable (fd));
  ASSERT (close (fd2) == 0);

  /* On systems that distinguish between text and binary mode,
     dup_cloexec reuses the mode of the source.  */
  setmode (fd, O_BINARY);
  ASSERT (is_mode (fd, O_BINARY));
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (is_mode (fd2, O_BINARY));
  ASSERT (close (fd2) == 0);
  setmode (fd, O_TEXT);
  ASSERT (is_mode (fd, O_TEXT));
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (is_mode (fd2, O_TEXT));
  ASSERT (close (fd2) == 0);

  /* Test error handling.  */
  errno = 0;
  ASSERT (set_cloexec_flag (-1, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (set_cloexec_flag (10000000, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (set_cloexec_flag (fd2, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (-1) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (10000000) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (fd2) == -1);
  ASSERT (errno == EBADF);

  /* Clean up.  */
  ASSERT (close (fd) == 0);
  ASSERT (unlink (file) == 0);

  return 0;
}
Exemplo n.º 20
0
/* sec_mod_server:
 * @config: server configuration
 * @socket_file: the name of the socket
 * @cmd_fd: socket to exchange commands with main
 * @cmd_fd_sync: socket to received sync commands from main
 *
 * This is the main part of the security module.
 * It creates the unix domain socket identified by @socket_file
 * and then accepts connections from the workers to it. Then 
 * it serves commands requested on the server's private key.
 *
 * When the operation is decrypt the provided data are
 * decrypted and sent back to worker. The sign operation
 * signs the provided data.
 *
 * The security module's reply to the worker has the
 * following format:
 * byte[0-5]: length (uint32_t)
 * byte[5-total]: data (signature or decrypted data)
 *
 * The reason for having this as a separate process
 * is to avoid any bug on the workers to leak the key.
 * It is not part of main because workers are spawned
 * from main, and thus should be prevented from accessing
 * parts the key in stack or heap that was not zeroized.
 * Other than that it allows the main server to spawn
 * clients fast without becoming a bottleneck due to private 
 * key operations.
 */
void sec_mod_server(void *main_pool, struct perm_cfg_st *perm_config, const char *socket_file,
		    int cmd_fd, int cmd_fd_sync)
{
	struct sockaddr_un sa;
	socklen_t sa_len;
	int cfd, ret, e, n;
	unsigned buffer_size;
	uid_t uid;
	uint8_t *buffer;
	int sd;
	sec_mod_st *sec;
	void *sec_mod_pool;
	fd_set rd_set;
	pid_t pid;
#ifdef HAVE_PSELECT
	struct timespec ts;
#else
	struct timeval ts;
#endif
	sigset_t emptyset, blockset;

#ifdef DEBUG_LEAKS
	talloc_enable_leak_report_full();
#endif
	sigemptyset(&blockset);
	sigemptyset(&emptyset);
	sigaddset(&blockset, SIGALRM);
	sigaddset(&blockset, SIGTERM);
	sigaddset(&blockset, SIGINT);
	sigaddset(&blockset, SIGHUP);

	sec_mod_pool = talloc_init("sec-mod");
	if (sec_mod_pool == NULL) {
		seclog(sec, LOG_ERR, "error in memory allocation");
		exit(1);
	}

	sec = talloc_zero(sec_mod_pool, sec_mod_st);
	if (sec == NULL) {
		seclog(sec, LOG_ERR, "error in memory allocation");
		exit(1);
	}

	sec->perm_config = talloc_steal(sec, perm_config);
	sec->config = sec->perm_config->config;

	tls_cache_init(sec, &sec->tls_db);
	sup_config_init(sec);

	memset(&sa, 0, sizeof(sa));
	sa.sun_family = AF_UNIX;
	strlcpy(sa.sun_path, socket_file, sizeof(sa.sun_path));
	remove(socket_file);

#define SOCKET_FILE sa.sun_path

	/* we no longer need the main pool after this point. */
	talloc_free(main_pool);

	ocsignal(SIGHUP, handle_sighup);
	ocsignal(SIGINT, handle_sigterm);
	ocsignal(SIGTERM, handle_sigterm);
	ocsignal(SIGALRM, handle_alarm);

	sec_auth_init(sec, perm_config);
	sec->cmd_fd = cmd_fd;
	sec->cmd_fd_sync = cmd_fd_sync;

#ifdef HAVE_PKCS11
	ret = gnutls_pkcs11_reinit();
	if (ret < 0) {
		seclog(sec, LOG_WARNING, "error in PKCS #11 reinitialization: %s",
		       gnutls_strerror(ret));
	}
#endif

	if (sec_mod_client_db_init(sec) == NULL) {
		seclog(sec, LOG_ERR, "error in client db initialization");
		exit(1);
	}

	sd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sd == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not create socket '%s': %s", SOCKET_FILE,
		       strerror(e));
		exit(1);
	}
	set_cloexec_flag(sd, 1);

	umask(066);
	ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa));
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not bind socket '%s': %s", SOCKET_FILE,
		       strerror(e));
		exit(1);
	}

	ret = chown(SOCKET_FILE, perm_config->uid, perm_config->gid);
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_INFO, "could not chown socket '%s': %s", SOCKET_FILE,
		       strerror(e));
	}

	ret = listen(sd, 1024);
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not listen to socket '%s': %s",
		       SOCKET_FILE, strerror(e));
		exit(1);
	}

	ret = load_keys(sec, 1);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error loading private key files");
		exit(1);
	}

	sigprocmask(SIG_BLOCK, &blockset, &sig_default_set);
	alarm(MAINTAINANCE_TIME);
	seclog(sec, LOG_INFO, "sec-mod initialized (socket: %s)", SOCKET_FILE);


	for (;;) {
		check_other_work(sec);

		FD_ZERO(&rd_set);
		n = 0;

		FD_SET(cmd_fd, &rd_set);
		n = MAX(n, cmd_fd);

		FD_SET(cmd_fd_sync, &rd_set);
		n = MAX(n, cmd_fd_sync);

		FD_SET(sd, &rd_set);
		n = MAX(n, sd);

#ifdef HAVE_PSELECT
		ts.tv_nsec = 0;
		ts.tv_sec = 120;
		ret = pselect(n + 1, &rd_set, NULL, NULL, &ts, &emptyset);
#else
		ts.tv_usec = 0;
		ts.tv_sec = 120;
		sigprocmask(SIG_UNBLOCK, &blockset, NULL);
		ret = select(n + 1, &rd_set, NULL, NULL, &ts);
		sigprocmask(SIG_BLOCK, &blockset, NULL);
#endif
		if (ret == 0 || (ret == -1 && errno == EINTR))
			continue;

		if (ret < 0) {
			e = errno;
			seclog(sec, LOG_ERR, "Error in pselect(): %s",
			       strerror(e));
			exit(1);
		}

		/* we do a new allocation, to also use it as pool for the
		 * parsers to use */
		buffer_size = MAX_MSG_SIZE;
		buffer = talloc_size(sec, buffer_size);
		if (buffer == NULL) {
			seclog(sec, LOG_ERR, "error in memory allocation");
			exit(1);
		}

		/* we use two fds for communication with main. The synchronous is for
		 * ping-pong communication which each request is answered immediated. The
		 * async is for messages sent back and forth in no particular order */
		if (FD_ISSET(cmd_fd_sync, &rd_set)) {
			ret = serve_request_main(sec, cmd_fd_sync, buffer, buffer_size);
			if (ret < 0 && ret == ERR_BAD_COMMAND) {
				seclog(sec, LOG_ERR, "error processing sync command from main");
				exit(1);
			}
		}

		if (FD_ISSET(cmd_fd, &rd_set)) {
			ret = serve_request_main(sec, cmd_fd, buffer, buffer_size);
			if (ret < 0 && ret == ERR_BAD_COMMAND) {
				seclog(sec, LOG_ERR, "error processing async command from main");
				exit(1);
			}
		}
		
		if (FD_ISSET(sd, &rd_set)) {
			sa_len = sizeof(sa);
			cfd = accept(sd, (struct sockaddr *)&sa, &sa_len);
			if (cfd == -1) {
				e = errno;
				if (e != EINTR) {
					seclog(sec, LOG_DEBUG,
					       "sec-mod error accepting connection: %s",
					       strerror(e));
					goto cont;
				}
			}
			set_cloexec_flag (cfd, 1);

			/* do not allow unauthorized processes to issue commands
			 */
			ret = check_upeer_id("sec-mod", sec->perm_config->debug, cfd, perm_config->uid, perm_config->gid, &uid, &pid);
			if (ret < 0) {
				seclog(sec, LOG_INFO, "rejected unauthorized connection");
			} else {
				memset(buffer, 0, buffer_size);
				serve_request_worker(sec, cfd, pid, buffer, buffer_size);
			}
			close(cfd);
		}
 cont:
		talloc_free(buffer);
#ifdef DEBUG_LEAKS
		talloc_report_full(sec, stderr);
#endif
	}
}
Exemplo n.º 21
0
int
getloadavg (double loadavg[], int nelem)
{
  int elem = 0;                 /* Return value.  */

# ifdef NO_GET_LOAD_AVG
#  define LDAV_DONE
  /* Set errno to zero to indicate that there was no particular error;
     this function just can't work at all on this system.  */
  errno = 0;
  elem = -1;
# endif

# if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT)
/* Use libkstat because we don't have to be root.  */
#  define LDAV_DONE
  kstat_ctl_t *kc;
  kstat_t *ksp;
  kstat_named_t *kn;

  kc = kstat_open ();
  if (kc == 0)
    return -1;
  ksp = kstat_lookup (kc, "unix", 0, "system_misc");
  if (ksp == 0)
    return -1;
  if (kstat_read (kc, ksp, 0) == -1)
    return -1;


  kn = kstat_data_lookup (ksp, "avenrun_1min");
  if (kn == 0)
    {
      /* Return -1 if no load average information is available.  */
      nelem = 0;
      elem = -1;
    }

  if (nelem >= 1)
    loadavg[elem++] = (double) kn->value.ul / FSCALE;

  if (nelem >= 2)
    {
      kn = kstat_data_lookup (ksp, "avenrun_5min");
      if (kn != 0)
        {
          loadavg[elem++] = (double) kn->value.ul / FSCALE;

          if (nelem >= 3)
            {
              kn = kstat_data_lookup (ksp, "avenrun_15min");
              if (kn != 0)
                loadavg[elem++] = (double) kn->value.ul / FSCALE;
            }
        }
    }

  kstat_close (kc);
# endif /* HAVE_LIBKSTAT */

# if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC)
/* Use pstat_getdynamic() because we don't have to be root.  */
#  define LDAV_DONE
#  undef LOAD_AVE_TYPE

  struct pst_dynamic dyn_info;
  if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0)
    return -1;
  if (nelem > 0)
    loadavg[elem++] = dyn_info.psd_avg_1_min;
  if (nelem > 1)
    loadavg[elem++] = dyn_info.psd_avg_5_min;
  if (nelem > 2)
    loadavg[elem++] = dyn_info.psd_avg_15_min;

# endif /* hpux && HAVE_PSTAT_GETDYNAMIC */

# if ! defined LDAV_DONE && defined HAVE_LIBPERFSTAT
#  define LDAV_DONE
#  undef LOAD_AVE_TYPE
/* Use perfstat_cpu_total because we don't have to be root. */
  {
    perfstat_cpu_total_t cpu_stats;
    int result = perfstat_cpu_total (NULL, &cpu_stats, sizeof cpu_stats, 1);
    if (result == -1)
      return result;
    loadavg[0] = cpu_stats.loadavg[0] / (double)(1 << SBITS);
    loadavg[1] = cpu_stats.loadavg[1] / (double)(1 << SBITS);
    loadavg[2] = cpu_stats.loadavg[2] / (double)(1 << SBITS);
    elem = 3;
  }
# endif

# if !defined (LDAV_DONE) && (defined (__linux__) || defined (__CYGWIN__))
#  define LDAV_DONE
#  undef LOAD_AVE_TYPE

#  ifndef LINUX_LDAV_FILE
#   define LINUX_LDAV_FILE "/proc/loadavg"
#  endif

  char ldavgbuf[3 * (INT_STRLEN_BOUND (int) + sizeof ".00 ")];
  char const *ptr = ldavgbuf;
  int fd, count;

  fd = open (LINUX_LDAV_FILE, O_RDONLY);
  if (fd == -1)
    return -1;
  count = read (fd, ldavgbuf, sizeof ldavgbuf - 1);
  (void) close (fd);
  if (count <= 0)
    return -1;
  ldavgbuf[count] = '\0';

  for (elem = 0; elem < nelem; elem++)
    {
      char *endptr;
      double d;

      errno = 0;
      d = c_strtod (ptr, &endptr);
      if (ptr == endptr || (d == 0 && errno != 0))
        {
          if (elem == 0)
            return -1;
          break;
        }
      loadavg[elem] = d;
      ptr = endptr;
    }

  return elem;

# endif /* __linux__ || __CYGWIN__ */

# if !defined (LDAV_DONE) && defined (__NetBSD__)
#  define LDAV_DONE
#  undef LOAD_AVE_TYPE

#  ifndef NETBSD_LDAV_FILE
#   define NETBSD_LDAV_FILE "/kern/loadavg"
#  endif

  unsigned long int load_ave[3], scale;
  int count;
  FILE *fp;

  fp = fopen (NETBSD_LDAV_FILE, "r");
  if (fp == NULL)
    return -1;
  count = fscanf (fp, "%lu %lu %lu %lu\n",
                  &load_ave[0], &load_ave[1], &load_ave[2],
                  &scale);
  (void) fclose (fp);
  if (count != 4)
    return -1;

  for (elem = 0; elem < nelem; elem++)
    loadavg[elem] = (double) load_ave[elem] / (double) scale;

  return elem;

# endif /* __NetBSD__ */

# if !defined (LDAV_DONE) && defined (NeXT)
#  define LDAV_DONE
  /* The NeXT code was adapted from iscreen 3.2.  */

  host_t host;
  struct processor_set_basic_info info;
  unsigned int info_count;

  /* We only know how to get the 1-minute average for this system,
     so even if the caller asks for more than 1, we only return 1.  */

  if (!getloadavg_initialized)
    {
      if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
        getloadavg_initialized = true;
    }

  if (getloadavg_initialized)
    {
      info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
      if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
                              (processor_set_info_t) &info, &info_count)
          != KERN_SUCCESS)
        getloadavg_initialized = false;
      else
        {
          if (nelem > 0)
            loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
        }
    }

  if (!getloadavg_initialized)
    return -1;
# endif /* NeXT */

# if !defined (LDAV_DONE) && defined (UMAX)
#  define LDAV_DONE
/* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
   have a /dev/kmem.  Information about the workings of the running kernel
   can be gathered with inq_stats system calls.
   We only know how to get the 1-minute average for this system.  */

  struct proc_summary proc_sum_data;
  struct stat_descr proc_info;
  double load;
  register unsigned int i, j;

  if (cpus == 0)
    {
      register unsigned int c, i;
      struct cpu_config conf;
      struct stat_descr desc;

      desc.sd_next = 0;
      desc.sd_subsys = SUBSYS_CPU;
      desc.sd_type = CPUTYPE_CONFIG;
      desc.sd_addr = (char *) &conf;
      desc.sd_size = sizeof conf;

      if (inq_stats (1, &desc))
        return -1;

      c = 0;
      for (i = 0; i < conf.config_maxclass; ++i)
        {
          struct class_stats stats;
          bzero ((char *) &stats, sizeof stats);

          desc.sd_type = CPUTYPE_CLASS;
          desc.sd_objid = i;
          desc.sd_addr = (char *) &stats;
          desc.sd_size = sizeof stats;

          if (inq_stats (1, &desc))
            return -1;

          c += stats.class_numcpus;
        }
      cpus = c;
      samples = cpus < 2 ? 3 : (2 * cpus / 3);
    }

  proc_info.sd_next = 0;
  proc_info.sd_subsys = SUBSYS_PROC;
  proc_info.sd_type = PROCTYPE_SUMMARY;
  proc_info.sd_addr = (char *) &proc_sum_data;
  proc_info.sd_size = sizeof (struct proc_summary);
  proc_info.sd_sizeused = 0;

  if (inq_stats (1, &proc_info) != 0)
    return -1;

  load = proc_sum_data.ps_nrunnable;
  j = 0;
  for (i = samples - 1; i > 0; --i)
    {
      load += proc_sum_data.ps_nrun[j];
      if (j++ == PS_NRUNSIZE)
        j = 0;
    }

  if (nelem > 0)
    loadavg[elem++] = load / samples / cpus;
# endif /* UMAX */

# if !defined (LDAV_DONE) && defined (DGUX)
#  define LDAV_DONE
  /* This call can return -1 for an error, but with good args
     it's not supposed to fail.  The first argument is for no
     apparent reason of type `long int *'.  */
  dg_sys_info ((long int *) &load_info,
               DG_SYS_INFO_LOAD_INFO_TYPE,
               DG_SYS_INFO_LOAD_VERSION_0);

  if (nelem > 0)
    loadavg[elem++] = load_info.one_minute;
  if (nelem > 1)
    loadavg[elem++] = load_info.five_minute;
  if (nelem > 2)
    loadavg[elem++] = load_info.fifteen_minute;
# endif /* DGUX */

# if !defined (LDAV_DONE) && defined (apollo)
#  define LDAV_DONE
/* Apollo code from [email protected] (Ray Lischner).

   This system call is not documented.  The load average is obtained as
   three long integers, for the load average over the past minute,
   five minutes, and fifteen minutes.  Each value is a scaled integer,
   with 16 bits of integer part and 16 bits of fraction part.

   I'm not sure which operating system first supported this system call,
   but I know that SR10.2 supports it.  */

  extern void proc1_$get_loadav ();
  unsigned long load_ave[3];

  proc1_$get_loadav (load_ave);

  if (nelem > 0)
    loadavg[elem++] = load_ave[0] / 65536.0;
  if (nelem > 1)
    loadavg[elem++] = load_ave[1] / 65536.0;
  if (nelem > 2)
    loadavg[elem++] = load_ave[2] / 65536.0;
# endif /* apollo */

# if !defined (LDAV_DONE) && defined (OSF_MIPS)
#  define LDAV_DONE

  struct tbl_loadavg load_ave;
  table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
  loadavg[elem++]
    = (load_ave.tl_lscale == 0
       ? load_ave.tl_avenrun.d[0]
       : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
# endif /* OSF_MIPS */

# if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))
#  define LDAV_DONE

  /* A faithful emulation is going to have to be saved for a rainy day.  */
  for ( ; elem < nelem; elem++)
    {
      loadavg[elem] = 0.0;
    }
# endif  /* __MSDOS__ || WINDOWS32 */

# if !defined (LDAV_DONE) && defined (OSF_ALPHA)
#  define LDAV_DONE

  struct tbl_loadavg load_ave;
  table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
  for (elem = 0; elem < nelem; elem++)
    loadavg[elem]
      = (load_ave.tl_lscale == 0
         ? load_ave.tl_avenrun.d[elem]
         : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
# endif /* OSF_ALPHA */

# if ! defined LDAV_DONE && defined __VMS
  /* VMS specific code -- read from the Load Ave driver.  */

  LOAD_AVE_TYPE load_ave[3];
  static bool getloadavg_initialized;
#  ifdef eunice
  struct
  {
    int dsc$w_length;
    char *dsc$a_pointer;
  } descriptor;
#  endif

  /* Ensure that there is a channel open to the load ave device.  */
  if (!getloadavg_initialized)
    {
      /* Attempt to open the channel.  */
#  ifdef eunice
      descriptor.dsc$w_length = 18;
      descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";
#  else
      $DESCRIPTOR (descriptor, "LAV0:");
#  endif
      if (sys$assign (&descriptor, &channel, 0, 0) & 1)
        getloadavg_initialized = true;
    }

  /* Read the load average vector.  */
  if (getloadavg_initialized
      && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0,
                     load_ave, 12, 0, 0, 0, 0) & 1))
    {
      sys$dassgn (channel);
      getloadavg_initialized = false;
    }

  if (!getloadavg_initialized)
    return -1;
# endif /* ! defined LDAV_DONE && defined __VMS */

# if ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS

  /* UNIX-specific code -- read the average from /dev/kmem.  */

#  define LDAV_PRIVILEGED               /* This code requires special installation.  */

  LOAD_AVE_TYPE load_ave[3];

  /* Get the address of LDAV_SYMBOL.  */
  if (offset == 0)
    {
#  ifndef sgi
#   if ! defined NLIST_STRUCT || ! defined N_NAME_POINTER
      strcpy (nl[0].n_name, LDAV_SYMBOL);
      strcpy (nl[1].n_name, "");
#   else /* NLIST_STRUCT */
#    ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME
      nl[0].n_un.n_name = LDAV_SYMBOL;
      nl[1].n_un.n_name = 0;
#    else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
      nl[0].n_name = LDAV_SYMBOL;
      nl[1].n_name = 0;
#    endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */
#   endif /* NLIST_STRUCT */

#   ifndef SUNOS_5
      if (
#    if !(defined (_AIX) && !defined (ps2))
          nlist (KERNEL_FILE, nl)
#    else  /* _AIX */
          knlist (nl, 1, sizeof (nl[0]))
#    endif
          >= 0)
          /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i.  */
          {
#    ifdef FIXUP_KERNEL_SYMBOL_ADDR
            FIXUP_KERNEL_SYMBOL_ADDR (nl);
#    endif
            offset = nl[0].n_value;
          }
#   endif /* !SUNOS_5 */
#  else  /* sgi */
      int ldav_off;

      ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
      if (ldav_off != -1)
        offset = (long int) ldav_off & 0x7fffffff;
#  endif /* sgi */
    }

  /* Make sure we have /dev/kmem open.  */
  if (!getloadavg_initialized)
    {
#  ifndef SUNOS_5
      channel = open ("/dev/kmem", O_RDONLY);
      if (channel >= 0)
        {
          /* Set the channel to close on exec, so it does not
             litter any child's descriptor table.  */
          set_cloexec_flag (channel, true);
          getloadavg_initialized = true;
        }
#  else /* SUNOS_5 */
      /* We pass 0 for the kernel, corefile, and swapfile names
         to use the currently running kernel.  */
      kd = kvm_open (0, 0, 0, O_RDONLY, 0);
      if (kd != 0)
        {
          /* nlist the currently running kernel.  */
          kvm_nlist (kd, nl);
          offset = nl[0].n_value;
          getloadavg_initialized = true;
        }
#  endif /* SUNOS_5 */
    }

  /* If we can, get the load average values.  */
  if (offset && getloadavg_initialized)
    {
      /* Try to read the load.  */
#  ifndef SUNOS_5
      if (lseek (channel, offset, 0) == -1L
          || read (channel, (char *) load_ave, sizeof (load_ave))
          != sizeof (load_ave))
        {
          close (channel);
          getloadavg_initialized = false;
        }
#  else  /* SUNOS_5 */
      if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
          != sizeof (load_ave))
        {
          kvm_close (kd);
          getloadavg_initialized = false;
        }
#  endif /* SUNOS_5 */
    }

  if (offset == 0 || !getloadavg_initialized)
    return -1;
# endif /* ! defined LDAV_DONE && defined LOAD_AVE_TYPE && ! defined __VMS */

# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS.  */
  if (nelem > 0)
    loadavg[elem++] = LDAV_CVT (load_ave[0]);
  if (nelem > 1)
    loadavg[elem++] = LDAV_CVT (load_ave[1]);
  if (nelem > 2)
    loadavg[elem++] = LDAV_CVT (load_ave[2]);

#  define LDAV_DONE
# endif /* !LDAV_DONE && LOAD_AVE_TYPE */

# if !defined LDAV_DONE
  /* Set errno to zero to indicate that there was no particular error;
     this function just can't work at all on this system.  */
  errno = 0;
  elem = -1;
# endif
  return elem;
}
Exemplo n.º 22
0
int
main (int argc, char *argv[])
{
  char *skip;
  int pipefd[2];
  pid_t pid;
  int r, status;

  /* Allow the test to be skipped. */
  skip = getenv ("SKIP_TEST_FUSE_SH");
  if (skip && guestfs_int_is_true (skip) > 0)
    error (77, 0, "test skipped because environment variable set");

  skip = getenv ("SKIP_TEST_GUESTUNMOUNT_FD");
  if (skip && guestfs_int_is_true (skip) > 0)
    error (77, 0, "test skipped because environment variable set");

  /* Create the pipe. */
  if (pipe (pipefd) == -1)
    error (EXIT_FAILURE, errno, "pipe");

  /* Create the guestunmount subprocess. */
  pid = fork ();
  if (pid == -1)
    error (EXIT_FAILURE, errno, "fork");

  if (pid == 0) {               /* child - guestunmount */
    char fd_str[64];

    close (pipefd[1]);

    snprintf (fd_str, sizeof fd_str, "%d", pipefd[0]);

    execlp ("guestunmount", "guestunmount", "--fd", fd_str, "/", NULL);
    perror ("execlp");
    _exit (EXIT_FAILURE);
  }

  /* Parent continues. */
  close (pipefd[0]);
  ignore_value (set_cloexec_flag (pipefd[1], 1));

  /* Sleep a bit and test that the guestunmount process is still running. */
  sleep (2);

  r = waitpid (pid, &status, WNOHANG);
  if (r == -1)
    error (EXIT_FAILURE, errno, "waitpid");
  if (r != 0) {
    char status_string[80];

    error (EXIT_FAILURE, 0,
           "test failed: %s",
           guestfs_int_exit_status_to_string (r, "guestunmount",
                                              status_string,
                                              sizeof status_string));
  }

  /* Close the write side of the pipe.  This should cause guestunmount
   * to exit.  It should exit with status code _3_ because we gave it
   * a directory which isn't a FUSE mountpoint.
   */
  close (pipefd[1]);

  r = waitpid (pid, &status, 0);
  if (r == -1)
    error (EXIT_FAILURE, errno, "waitpid");
  if (!WIFEXITED (status) || WEXITSTATUS (status) != 3) {
    char status_string[80];

    error (EXIT_FAILURE, 0,
           "test failed: guestunmount didn't return status code 3; %s",
           guestfs_int_exit_status_to_string (status, "guestunmount",
                                              status_string,
                                              sizeof status_string));
  }

  exit (EXIT_SUCCESS);
}