Exemple #1
0
/* a checkpoint completed, process the images files */
static int _on_ckpt_complete(uint32_t group_id, uint32_t user_id,
			     uint32_t job_id, uint32_t step_id,
			     char *image_dir, uint32_t error_code)
{
	int status;
	pid_t cpid;

	if (access(scch_path, R_OK | X_OK) < 0) {
		if (errno == ENOENT)
			debug("checkpoint/blcr: file %s not found", scch_path);
		else
			info("Access denied for %s: %m", scch_path);
		return SLURM_ERROR;
	}

	if ((cpid = fork()) < 0) {
		error ("_on_ckpt_complete: fork: %m");
		return SLURM_ERROR;
	}

	if (cpid == 0) {
		/*
		 * We don't fork and wait the child process because the job
		 * read lock is held. It could take minutes to delete/move
		 * the checkpoint image files. So there is a race condition
		 * of the user requesting another checkpoint before SCCH
		 * finishes.
		 */
		/* fork twice to avoid zombies */
		if ((cpid = fork()) < 0) {
			error("_on_ckpt_complete: second fork: %m");
			exit(127);
		}
		/* grand child execs */
		if (cpid == 0) {
			char *args[6];
			char str_job[11];
			char str_step[11];
			char str_err[11];

			/*
			 * XXX: if slurmctld is running as root, we must setuid here.
			 * But what if slurmctld is running as SlurmUser?
			 * How about we make scch setuid and pass the user/group to it?
			 */
			if (geteuid() == 0) { /* root */
				if (setgid(group_id) < 0) {
					error("_on_ckpt_complete: failed to "
					      "setgid: %m");
					exit(127);
				}
				if (setuid(user_id) < 0) {
					error("_on_ckpt_complete: failed to "
					      "setuid: %m");
					exit(127);
				}
			}
			snprintf(str_job,  sizeof(str_job),  "%u", job_id);
			snprintf(str_step, sizeof(str_step), "%u", step_id);
			snprintf(str_err,  sizeof(str_err),  "%u", error_code);

			args[0] = (char *)scch_path;
			args[1] = str_job;
			args[2] = str_step;
			args[3] = str_err;
			args[4] = image_dir;
			args[5] = NULL;

			execv(scch_path, args);
			error("execv failure: %m");
			exit(127);
		}
		/* child just exits */
		exit(0);
	}

	while(1) {
		if (waitpid(cpid, &status, 0) < 0 && errno == EINTR)
			continue;
		break;
	}

	return SLURM_SUCCESS;
}
Exemple #2
0
int main(int argc, char **argv) {
  char *gidmap = NULL, *inside = NULL, *outside = NULL, *uidmap = NULL;
  char *bind = NULL;
  int hostnet = 0, master, option, stdio = 0;
  pid_t child, parent;

  while ((option = getopt(argc, argv, "+:b:cg:i:no:u:")) > 0)
    switch (option) {
      case 'b':
        bind = optarg;
        break;
      case 'c':
        stdio++;
        break;
      case 'g':
        gidmap = optarg;
        break;
      case 'i':
        inside = optarg;
        break;
      case 'n':
        hostnet++;
        break;
      case 'o':
        outside = optarg;
        break;
      case 'u':
        uidmap = optarg;
        break;
      default:
        usage(argv[0]);
    }

  if (argc <= optind)
    usage(argv[0]);

  parent = getpid();
  switch (child = fork()) {
    case -1:
      error(1, errno, "fork");
    case 0:
      raise(SIGSTOP);
//      if (geteuid() != 0)
//        denysetgroups(parent);
      writemap(parent, GID, gidmap);
      writemap(parent, UID, uidmap);

      if (outside) {
        if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
          error(1, 0, "Failed to drop privileges");
        execlp(SHELL, SHELL, "-c", outside, NULL);
        error(1, errno, "exec %s", outside);
      }

      exit(EXIT_SUCCESS);
  }

  if (setgid(getgid()) < 0 || setuid(getuid()) < 0)
    error(1, 0, "Failed to drop privileges");

  if (unshare(CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWUTS) < 0)
    error(1, 0, "Failed to unshare namespaces");

  if (!hostnet && unshare(CLONE_NEWNET) < 0)
      error(1, 0, "Failed to unshare network namespace");

  waitforstop(child);
  kill(child, SIGCONT);
  waitforexit(child);

  setgid(0);
  setgroups(0, NULL);
  setuid(0);

  master = stdio ? -1 : getconsole();
  createroot(argv[optind], master, inside, bind);

  unshare(CLONE_NEWPID);
  switch (child = fork()) {
    case -1:
      error(1, errno, "fork");
    case 0:
      mountproc();
      if (!hostnet)
        mountsys();
      enterroot();

      if (master >= 0) {
        close(master);
        setconsole("/dev/console");
      }

      clearenv();
      putenv("container=contain");

      if (argv[optind + 1])
        execv(argv[optind + 1], argv + optind + 1);
      else
        execl(SHELL, SHELL, NULL);
      error(1, errno, "exec");
  }

  return supervise(child, master);
}
Exemple #3
0
static int attach_child_main(void* data)
{
	struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
	int ipc_socket = payload->ipc_socket;
	lxc_attach_options_t* options = payload->options;
	struct lxc_proc_context_info* init_ctx = payload->init_ctx;
#if HAVE_SYS_PERSONALITY_H
	long new_personality;
#endif
	int ret;
	int status;
	int expected;
	long flags;
	int fd;
	uid_t new_uid;
	gid_t new_gid;

	/* wait for the initial thread to signal us that it's ready
	 * for us to start initializing
	 */
	expected = 0;
	status = -1;
	ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
	if (ret <= 0) {
		ERROR("error using IPC to receive notification from initial process (0)");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* A description of the purpose of this functionality is
	 * provided in the lxc-attach(1) manual page. We have to
	 * remount here and not in the parent process, otherwise
	 * /proc may not properly reflect the new pid namespace.
	 */
	if (!(options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_REMOUNT_PROC_SYS)) {
		ret = lxc_attach_remount_sys_proc();
		if (ret < 0) {
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}

	/* now perform additional attachments*/
#if HAVE_SYS_PERSONALITY_H
	if (options->personality < 0)
		new_personality = init_ctx->personality;
	else
		new_personality = options->personality;

	if (options->attach_flags & LXC_ATTACH_SET_PERSONALITY) {
		ret = personality(new_personality);
		if (ret < 0) {
			SYSERROR("could not ensure correct architecture");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}
#endif

	if (options->attach_flags & LXC_ATTACH_DROP_CAPABILITIES) {
		ret = lxc_attach_drop_privs(init_ctx);
		if (ret < 0) {
			ERROR("could not drop privileges");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}

	/* always set the environment (specify (LXC_ATTACH_KEEP_ENV, NULL, NULL) if you want this to be a no-op) */
	ret = lxc_attach_set_environment(options->env_policy, options->extra_env_vars, options->extra_keep_env);
	if (ret < 0) {
		ERROR("could not set initial environment for attached process");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* set user / group id */
	new_uid = 0;
	new_gid = 0;
	/* ignore errors, we will fall back to root in that case
	 * (/proc was not mounted etc.)
	 */
	if (options->namespaces & CLONE_NEWUSER)
		lxc_attach_get_init_uidgid(&new_uid, &new_gid);

	if (options->uid != (uid_t)-1)
		new_uid = options->uid;
	if (options->gid != (gid_t)-1)
		new_gid = options->gid;

	/* try to set the uid/gid combination */
	if ((new_gid != 0 || options->namespaces & CLONE_NEWUSER)) {
		if (setgid(new_gid) || setgroups(0, NULL)) {
			SYSERROR("switching to container gid");
			shutdown(ipc_socket, SHUT_RDWR);
			rexit(-1);
		}
	}
	if ((new_uid != 0 || options->namespaces & CLONE_NEWUSER) && setuid(new_uid)) {
		SYSERROR("switching to container uid");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* tell initial process it may now put us into the cgroups */
	status = 1;
	ret = lxc_write_nointr(ipc_socket, &status, sizeof(status));
	if (ret != sizeof(status)) {
		ERROR("error using IPC to notify initial process for initialization (1)");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	/* wait for the initial thread to signal us that it has done
	 * everything for us when it comes to cgroups etc.
	 */
	expected = 2;
	status = -1;
	ret = lxc_read_nointr_expect(ipc_socket, &status, sizeof(status), &expected);
	if (ret <= 0) {
		ERROR("error using IPC to receive final notification from initial process (2)");
		shutdown(ipc_socket, SHUT_RDWR);
		rexit(-1);
	}

	shutdown(ipc_socket, SHUT_RDWR);
	close(ipc_socket);

	/* set new apparmor profile/selinux context */
	if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) {
		int on_exec;

		on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
		ret = lsm_process_label_set(init_ctx->lsm_label,
				init_ctx->container->lxc_conf, 0, on_exec);
		if (ret < 0) {
			rexit(-1);
		}
	}

	if (init_ctx->container && init_ctx->container->lxc_conf &&
			lxc_seccomp_load(init_ctx->container->lxc_conf) != 0) {
		ERROR("Loading seccomp policy");
		rexit(-1);
	}

	lxc_proc_put_context_info(init_ctx);

	/* The following is done after the communication socket is
	 * shut down. That way, all errors that might (though
	 * unlikely) occur up until this point will have their messages
	 * printed to the original stderr (if logging is so configured)
	 * and not the fd the user supplied, if any.
	 */

	/* fd handling for stdin, stdout and stderr;
	 * ignore errors here, user may want to make sure
	 * the fds are closed, for example */
	if (options->stdin_fd >= 0 && options->stdin_fd != 0)
		dup2(options->stdin_fd, 0);
	if (options->stdout_fd >= 0 && options->stdout_fd != 1)
		dup2(options->stdout_fd, 1);
	if (options->stderr_fd >= 0 && options->stderr_fd != 2)
		dup2(options->stderr_fd, 2);

	/* close the old fds */
	if (options->stdin_fd > 2)
		close(options->stdin_fd);
	if (options->stdout_fd > 2)
		close(options->stdout_fd);
	if (options->stderr_fd > 2)
		close(options->stderr_fd);

	/* try to remove CLOEXEC flag from stdin/stdout/stderr,
	 * but also here, ignore errors */
	for (fd = 0; fd <= 2; fd++) {
		flags = fcntl(fd, F_GETFL);
		if (flags < 0)
			continue;
		if (flags & FD_CLOEXEC) {
			if (fcntl(fd, F_SETFL, flags & ~FD_CLOEXEC) < 0) {
				SYSERROR("Unable to clear CLOEXEC from fd");
			}
		}
	}

	/* we're done, so we can now do whatever the user intended us to do */
	rexit(payload->exec_function(payload->exec_payload));
}
Exemple #4
0
void
edit_file(char *buf)
    /* copy file to a temp file, edit that file, and install it
       if necessary */
{
    char *cureditor = NULL;
    char editorcmd[PATH_LEN];
    pid_t pid;
    int status;
    struct stat st;
    time_t mtime = 0;
    char *tmp_str;
    FILE *f, *fi;
    int file = 0;
    int c;
    char correction = 0;
    short return_val = EXIT_OK;

    explain("fcrontab : editing %s's fcrontab", user);	

    if ((cureditor=getenv("VISUAL")) == NULL || strcmp(cureditor, "\0") == 0 )
	if((cureditor=getenv("EDITOR"))==NULL || strcmp(cureditor, "\0") == 0 )
	    cureditor = editor;
	
    file = temp_file(&tmp_str);
    if ( (fi = fdopen(file, "w")) == NULL ) {
	error_e("could not fdopen");
	goto exiterr;
    }
#ifndef USE_SETE_ID
    if (fchown(file, asuid, asgid) != 0) {
	error_e("Could not fchown %s to asuid and asgid", tmp_str);
	goto exiterr;
    }
#endif
    /* copy user's fcrontab (if any) to a temp file */
    if ( (f = fopen(buf, "r")) == NULL ) {
	if ( errno != ENOENT ) {
	    error_e("could not open file %s", buf);
	    goto exiterr;
	}
	else
	    fprintf(stderr, "no fcrontab for %s - using an empty one\n",
		    user);
    }
    else { 
	/* copy original file to temp file */
	while ( (c=getc(f)) != EOF )
	    putc(c, fi);
	fclose(f);
    }

    fclose(fi);
    close(file);

    do {

	if ( stat(tmp_str, &st) == 0 )
	    mtime = st.st_mtime;
	else {
	    error_e("could not stat \"%s\"", buf);
	    goto exiterr;
	}

	switch ( pid = fork() ) {
	case 0:
	    /* child */
	    if ( uid != ROOTUID ) {
		if (setgid(asgid) < 0) {
		    error_e("setgid(asgid)");
		    goto exiterr;
		}
		if (setuid(asuid) < 0) {
		    error_e("setuid(asuid)");
		    goto exiterr;
		}
	    }
	    else {
		/* Some programs, like perl, require gid=egid : */
		if ( setgid(getgid()) < 0 ) {
		    error_e("setgid(getgid())");
		    goto exiterr;
		}
	    }
	    snprintf(editorcmd, sizeof(editorcmd), "%s %s", cureditor, tmp_str);
	    execlp(shell, shell, "-c", editorcmd, tmp_str, NULL);
	    error_e("Error while running \"%s\"", cureditor);
	    goto exiterr;

	case -1:
	    error_e("fork");
	    goto exiterr;

	default:
	    /* parent */
	    break ;
	}
	    
	/* only reached by parent */
	waitpid(pid, &status, 0);
	if ( ! WIFEXITED(status) ) {
	    fprintf(stderr, "Editor exited abnormally:"
		    " fcrontab is unchanged.\n");
	    goto exiterr;
	}

#ifndef USE_SETE_ID
	/* we have chown the tmp file to user's name : user may have
	 * linked the tmp file to a file owned by root. In that case, as
	 * fcrontab is setuid root, user may read some informations he is not
	 * allowed to read :
	 * we *must* check that the tmp file is not a link. */

	/* open the tmp file, chown it to root and chmod it to avoid race
	 * conditions */
	/* make sure that the tmp file is not a link */
	{
	    int fd = 0;
	    if ( (fd = open(tmp_str, O_RDONLY)) <= 0 ||
		 fstat(fd, &st) != 0 || ! S_ISREG(st.st_mode) ||
		 S_ISLNK(st.st_mode) || st.st_uid != asuid || st.st_nlink > 1){
		fprintf(stderr, "%s is not a valid regular file.\n", tmp_str);
		close(fd);
		goto exiterr;
	    }
	    if ( fchown(fd, ROOTUID, ROOTGID) != 0 || fchmod(fd, S_IRUSR|S_IWUSR) != 0 ){
		fprintf(stderr, "Can't chown or chmod %s.\n", tmp_str);
		close(fd);
		goto exiterr;
	    }
	    close(fd);
	}
#endif
	
	/* check if file has been modified */
	if ( stat(tmp_str, &st) != 0 ) {
	    error_e("could not stat %s", tmp_str);
	    goto exiterr;
	}    

	else if ( st.st_mtime > mtime || correction == 1) {

	    correction = 0;

	    switch ( read_file(tmp_str) ) {
	    case ERR:
		goto exiterr;
	    case 2:
		fprintf(stderr, "\nFile contains some errors. "
			"Ignore [i] or Correct [c] ? ");
		/* the 2nd getchar() is for the newline char (\n) */
		while ( (c = getchar())	&& c != 'i' && c != 'c' ) {
		    fprintf(stderr, "Please press c to correct, "
			    "or i to ignore: ");
		    while (c != '\n')
			c = getchar();
		}
		if ( c == 'c' ) {
		    /* free memory used to store the list */
		    delete_file(user);
		    correction = 1;
		}
		break;
	    default:
		break;
	    }

	}
	else {
	    fprintf(stderr, "Fcrontab is unchanged :"
		    " no need to install it.\n"); 
	    goto end;
	}

    } while ( correction == 1);

    if ( write_file(tmp_str) != OK )
	return_val = EXIT_ERR;
    
    /* free memory used to store the list */
    delete_file(user);
    
    /* tell daemon to update the conf */
    need_sig = 1;
    
  end:
    if ( remove(tmp_str) != 0 )
	error_e("could not remove %s", tmp_str);
    free(tmp_str);
    xexit (return_val);

  exiterr:
    if ( remove(tmp_str) != 0 )
	error_e("could not remove %s", tmp_str);
    free(tmp_str);
    xexit (EXIT_ERR);

}
Exemple #5
0
int
main(int argc, char *argv[])
{
    struct servent *se;
    struct sockaddr_in taddr, laddr;
    struct sockaddr_in saddr, daddr;
    int trap_s, serv_s, rc, i;
    socklen_t dlen, llen;
    fd_set fds;
    static int cl_addr[FD_SETSIZE];
    char buf[8192];
    int go_on;
    int mcast_s = -1;
    char *name;
    unsigned short port;
    const int on = 1;

    /* 
     * Check the number of arguments. We accept an optional argument
     * which specifies the port number we are listening on.
     */

    if (argc > 2) {
	fprintf(stderr, "usage: nmtrapd [port]\n");
	exit(1);
    }

    if (argc == 2) {
	name = argv[1];
	port = atoi(argv[1]);
    } else {
	name = SNMP_TRAP_NAME;
	port = SNMP_TRAP_PORT;
    }
    
    /*
     * Get the port that we are going to listen to. Check that
     * we do not try to open a priviledged port number, with
     * the exception of the SNMP trap port.
     */

    if ((se = getservbyname(name, "udp"))) {
	port = ntohs(se->s_port);
    }

    if (port != SNMP_TRAP_PORT && port < 1024) {
	fprintf(stderr, "nmtrapd: access to port %d denied\n", port);
	exit(1);
    }

    /* 
     * Fork a new process so that the calling process returns
     * immediately. This makes sure that Tcl is not waiting for
     * this process to terminate when it exits.
     */

    switch (fork()) {
    case -1:
	PosixError("unable to fork daemon (ignored)");
	break;
    case 0:
	break;
    default:
	exit(0);
    }

    /*
     * Close any "leftover" FDs from the parent. There is a relatively
     * high probability that the parent will be scotty, and that the
     * client side of the scotty-nmtrapd connection is among the open
     * FDs. This is bad news if the parent scotty goes away, since
     * this will eventually cause nmtrapd to "block against itself" in
     * the "forward data to client" write() calls below, since nmtrapd
     * itself is not consuming data from the client side of the
     * leftover open socket.
     */

    for (i = 0; i < FD_SETSIZE; i++) {
	(void) close(i);
    }
    setsid();

    /*
     * Open the connection to the system logger. Beware: some old BSD
     * systems have an old syslog interface.
     */

#ifdef ultrix
    openlog("nmtrapd", LOG_PID);
#else
    openlog("nmtrapd", LOG_PID, LOG_USER);
#endif

    /*
     * Open and bind the normal trap socket: 
     */

    if ((trap_s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	PosixError("unable to open trap socket");
	exit(1);
    }
    
    taddr.sin_family = AF_INET;
    taddr.sin_port = htons(port);
    taddr.sin_addr.s_addr = INADDR_ANY;

#ifdef SO_REUSEADDR
    setsockopt(trap_s, SOL_SOCKET, SO_REUSEADDR, 
	       (char *) &on, sizeof(on));
#endif

    if (bind(trap_s, (struct sockaddr *) &taddr, sizeof(taddr)) < 0) {
	PosixError("unable to bind trap socket");
	exit(1);
    }

#ifdef HAVE_MULTICAST
    if ((mcast_s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	PosixError("unable to open multicast trap socket");
    }

    if (mcast_s > 0) {
        struct ip_mreq mreq;
        mreq.imr_multiaddr.s_addr = inet_addr(SNMP_TRAP_MCIP);
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	if (setsockopt(mcast_s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*) &mreq,
		       sizeof(mreq)) == -1) {
	    PosixError("unable to join multicast group");
	    close(mcast_s);
	    mcast_s = -1;
	}
    }

#ifdef SO_REUSEADDR
    if (mcast_s > 0) {
	setsockopt(mcast_s, SOL_SOCKET, SO_REUSEADDR, 
		   (char *) &on, sizeof(on));
    }
#endif

    if (mcast_s > 0) {
        struct sockaddr_in maddr;
        maddr.sin_family = AF_INET;
	maddr.sin_port = htons(port);
	maddr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(mcast_s, (struct sockaddr*) &maddr, sizeof(maddr)) == -1) {
	    PosixError("unable to bind multicast trap socket");
	    close(mcast_s);
	    mcast_s = -1;
	}
    }
#endif

    /* 
     * Switch back to normal user rights: 
     */

    setuid(getuid ());

    if ((serv_s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
	PosixError("unable to open server socket");
	exit(1);
    }

    memset((char *) &saddr, 0, sizeof(saddr));

    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(SNMP_FRWD_PORT);
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(serv_s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
	PosixError("unable to bind server socket");
	exit(1);
    }

    if (listen(serv_s, 5) < 0) {
	PosixError("unable to listen on server socket");
	exit(1);
    }

#ifdef SIGPIPE
    signal(SIGPIPE, IgnorePipe);
#endif
    
    /*
     * If there is a steady stream of traps bound for this host, we
     * need to allow some time for the client (scotty) to connect to
     * us. Otherwise, nmtrapd will just exit when the first trap
     * message arrives. The client does 5 retries with 1 second
     * in-between, so sleeping for 3 should be enough to let the
     * client connect. There really ought to be a better way to do
     * this.
     */

    sleep(3);

    /*
     * Fine everything is ready; lets listen for events: 
     * the for(;;) loop aborts, if the last client went away.
     */

    for (go_on = 1; go_on; ) {

	FD_ZERO(&fds);
	FD_SET(trap_s, &fds);
	FD_SET(serv_s, &fds);
	if (mcast_s > 0) {
	    FD_SET(mcast_s, &fds);
	}
	
	/* fd's connected from clients. listen for EOF's: */
	for (i = 0; i < FD_SETSIZE; i++) {
	    if (cl_addr[i] > 0) {
		FD_SET(i, &fds);
	    }
	}
	
	rc = select(FD_SETSIZE, &fds, (fd_set *) 0, (fd_set *) 0, 
		    (struct timeval *) 0);
	if (rc < 0) {
	    if (errno == EINTR || errno == EAGAIN) continue;
	    PosixError("select failed");
	}
	
	if (FD_ISSET(serv_s, &fds)) {
	    memset((char *) &daddr, 0, sizeof(daddr));
	    dlen = sizeof(daddr);
	    rc = accept(serv_s, (struct sockaddr *) &daddr, &dlen);
	    if (rc < 0) {
		PosixError("accept failed");
		continue;
	    }

	    /*
	     * Check for a potential buffer overflow if the accept()
	     * call returns a file descriptor larger than FD_SETSIZE.
	     */
	    
	    if (rc >= FD_SETSIZE) {
		InternalError("too many clients");
		close(rc);
		continue;
	    }
	    
	    cl_addr[rc] = 1;
	    
	} else if (FD_ISSET(trap_s, &fds)) {
	    llen = sizeof(laddr);
	    if ((rc = recvfrom(trap_s, buf, sizeof(buf), 0, 
			       (struct sockaddr *) &laddr, &llen)) < 0) {
		PosixError("unable to receive trap");
		continue;
	    }
	    
	    for (i = 0; i < FD_SETSIZE; i++) {
		if (cl_addr[i] > 0) {
		    if (! ForwardTrap(i, &laddr, buf, rc)) {
			cl_addr[i] = 0;
			close(i);
		    }
		}
	    }
	    
	    /* should we go on ? */
	    for (go_on = 0, i = 0; i < FD_SETSIZE; i++) {
		go_on += cl_addr[i] > 0;
	    }
	    
	} else if (mcast_s > 0 && FD_ISSET(mcast_s, &fds)) {
	    llen = sizeof(laddr);
	    if ((rc = recvfrom(mcast_s, buf, sizeof(buf), 0, 
			       (struct sockaddr *) &laddr, &llen)) < 0) {
		PosixError("unable to receive trap");
		continue;
	    }
	    
	    for (i = 0; i < FD_SETSIZE; i++) {
		if (cl_addr[i] > 0) {
		    if (! ForwardTrap(i, &laddr, buf, rc)) {
			cl_addr[i] = 0;
			close(i);
		    }
		}
	    }
	    
	    /* should we go on ? */
	    for (go_on = 0, i = 0; i < FD_SETSIZE; i++) {
		go_on += cl_addr[i] > 0;
	    }
	    
	} else {
	    /* fd's connected from clients. (XXX: should check for EOF): */
	    for (i = 0; i < FD_SETSIZE; i++) {
		if (cl_addr[i] > 0 && FD_ISSET(i, &fds)) {
		    cl_addr[i] = 0;
		    close(i);
		}
	    }
	    
	    /* should we go on ? */
	    for (go_on = 0, i = 0; i < FD_SETSIZE; i++) {
		go_on += cl_addr[i] > 0;
	    }
	}
	
    } /* end for (;;) */

    closelog();

    return 0;
}
Exemple #6
0
/**
 * Initialize ngIRCd daemon.
 *
 * @param NGIRCd_NoDaemon Set to true if ngIRCd should run in the
 *		foreground (and not as a daemon).
 * @return true on success.
 */
static bool
NGIRCd_Init(bool NGIRCd_NoDaemon)
{
	static bool initialized;
	bool chrooted = false;
	struct passwd *pwd;
	struct group *grp;
	int real_errno, fd = -1;
	pid_t pid;

	if (initialized)
		return true;

	if (!NGIRCd_NoDaemon) {
		/* open /dev/null before chroot() */
		fd = open( "/dev/null", O_RDWR);
		if (fd < 0)
			Log(LOG_WARNING, "Could not open /dev/null: %s",
			    strerror(errno));
	}

	/* SSL initialization */
	if (!ConnSSL_InitLibrary()) {
		Log(LOG_ERR, "Error during SSL initialization!");
		goto out;
	}

	/* Change root */
	if (Conf_Chroot[0]) {
		if (chdir(Conf_Chroot) != 0) {
			Log(LOG_ERR, "Can't chdir() in ChrootDir (%s): %s!",
			    Conf_Chroot, strerror(errno));
			goto out;
		}

		if (chroot(Conf_Chroot) != 0) {
			Log(LOG_ERR,
			    "Can't change root directory to \"%s\": %s!",
			    Conf_Chroot, strerror(errno));
			goto out;
		} else {
			chrooted = true;
			Log(LOG_INFO,
			    "Changed root and working directory to \"%s\".",
			    Conf_Chroot);
		}
	}

#if !defined(SINGLE_USER_OS)
	/* Check user ID */
	if (Conf_UID == 0) {
		pwd = getpwuid(0);
		Log(LOG_INFO,
		    "ServerUID must not be %s(0), using \"nobody\" instead.",
		    pwd ? pwd->pw_name : "?");
		if (!NGIRCd_getNobodyID(&Conf_UID, &Conf_GID)) {
			Log(LOG_WARNING,
			    "Could not get user/group ID of user \"nobody\": %s",
			    errno ? strerror(errno) : "not found" );
			goto out;
		}
	}

	/* Change group ID */
	if (getgid() != Conf_GID) {
		if (setgid(Conf_GID) != 0) {
			real_errno = errno;
			grp = getgrgid(Conf_GID);
			Log(LOG_ERR, "Can't change group ID to %s(%u): %s!",
			    grp ? grp->gr_name : "?", Conf_GID,
			    strerror(real_errno));
			if (real_errno != EPERM)
				goto out;
		}
#ifdef HAVE_SETGROUPS
		if (setgroups(0, NULL) != 0) {
			real_errno = errno;
			Log(LOG_ERR, "Can't drop supplementary group IDs: %s!",
					strerror(errno));
			if (real_errno != EPERM)
				goto out;
		}
#else
		Log(LOG_WARNING,
		    "Can't drop supplementary group IDs: setgroups(3) missing!");
#endif
	}
#endif

	/* Change user ID */
	if (getuid() != Conf_UID) {
		if (setuid(Conf_UID) != 0) {
			real_errno = errno;
			pwd = getpwuid(Conf_UID);
			Log(LOG_ERR, "Can't change user ID to %s(%u): %s!",
			    pwd ? pwd->pw_name : "?", Conf_UID,
			    strerror(real_errno));
			if (real_errno != EPERM)
				goto out;
		}
	}

	initialized = true;

	/* Normally a child process is forked which isn't any longer
	 * connected to ther controlling terminal. Use "--nodaemon"
	 * to disable this "daemon mode" (useful for debugging). */
	if (!NGIRCd_NoDaemon) {
		pid = fork();
		if (pid > 0) {
			/* "Old" process: exit. */
			exit(0);
		}
		if (pid < 0) {
			/* Error!? */
			fprintf(stderr,
				"%s: Can't fork: %s!\nFatal error, exiting now ...\n",
				PACKAGE_NAME, strerror(errno));
			exit(1);
		}

		/* New child process */
#ifdef HAVE_SETSID
		(void)setsid();
#else
		setpgrp(0, getpid());
#endif
		if (chdir("/") != 0)
			Log(LOG_ERR, "Can't change directory to '/': %s!",
				     strerror(errno));

		/* Detach stdin, stdout and stderr */
		Setup_FDStreams(fd);
		if (fd > 2)
			close(fd);
	}
	pid = getpid();

	Pidfile_Create(pid);

	/* Check UID/GID we are running as, can be different from values
	 * configured (e. g. if we were already started with a UID>0. */
	Conf_UID = getuid();
	Conf_GID = getgid();

	pwd = getpwuid(Conf_UID);
	grp = getgrgid(Conf_GID);

	Log(LOG_INFO, "Running as user %s(%ld), group %s(%ld), with PID %ld.",
	    pwd ? pwd->pw_name : "unknown", (long)Conf_UID,
	    grp ? grp->gr_name : "unknown", (long)Conf_GID, (long)pid);

	if (chrooted) {
		Log(LOG_INFO, "Running with root directory \"%s\".",
		    Conf_Chroot );
		return true;
	} else
		Log(LOG_INFO, "Not running with changed root directory.");

	/* Change working directory to home directory of the user we are
	 * running as (only when running in daemon mode and not in chroot) */

	if (NGIRCd_NoDaemon)
		return true;

	if (pwd) {
		if (chdir(pwd->pw_dir) == 0)
			Log(LOG_DEBUG,
			    "Changed working directory to \"%s\" ...",
			    pwd->pw_dir);
		else
			Log(LOG_ERR,
			    "Can't change working directory to \"%s\": %s!",
			    pwd->pw_dir, strerror(errno));
	} else
		Log(LOG_ERR, "Can't get user informaton for UID %d!?", Conf_UID);

	return true;
 out:
	if (fd > 2)
		close(fd);
	return false;
} /* NGIRCd_Init */
Exemple #7
0
int ds_daemon(http_conf * conf, int t)
{  
    int uid = getuid();
    int gid = getgid();
    int status = 0;


    if(conf->user && strlen(conf->user)) {
        struct passwd * pw  = getpwnam(conf->user);
        if(!pw) {
            printf(" user[%s] no found\n", conf->user);
            exit(0);
        }
        uid = pw->pw_uid;
        gid = pw->pw_gid;
        printf("\n user:%s\n", conf->user);
    }


    if(t == 0 ) {
        ds_init_daemon(conf);
    }
   

   if( t == 0 || t == 1) {
       ds_init_children(conf);

       //ds_pid = getpid();

        if(setsid() == -1) {  //setsid创建一个新会话
            printf("setsid() failed!" DS_LINEEND);
            exit(0);
        }
        
        umask(0);
        setuid(uid);
        setgid(gid);
        ds_init(conf);
   }

   /*if( t == 2) {
       conf->work_mode = FORK_PROCESS_WORK_HTTP_MODE;
   }*/
   if(t == 2) {
       //使用两个pipe 完成accept 和cgi进程的通信,pipe 0read, 1write
       int pipHttp[2], pipCgi[2];
       pipe(pipHttp);
       pipe(pipCgi);
       int forkCgiPid = fork();
       if(forkCgiPid == 0) {
            conf->child_pip.in = pipCgi[0];
            conf->child_pip.out = pipHttp[1];
            close(pipHttp[0]);
            close(pipCgi[1]);
            conf->work_mode = FORK_PROCESS_WORK_CGI_MODE;
        } else {
            conf->child_pip.in = pipHttp[0];
            conf->child_pip.out = pipCgi[1];
            close(pipHttp[1]);
            close(pipCgi[0]);
            conf->work_mode = FORK_PROCESS_WORK_HTTP_MODE;
        }
   }
 

    


    return OK;
}
int main(int argc, char *argv[]) {
  char *user, *dirname, *spoolfile, *outfile, *gscall, *ppcall;
  cp_string title;
  int size;
  mode_t mode;
  struct passwd *passwd;
  gid_t *groups;
  int ngroups;
  pid_t pid;
/*
  puts("s0");
  int ff = open("/home/cww/t3", O_CREAT | O_RDWR, 0777);
  if (ff == -1) {
	  perror("13");
  }*/
  //close(ff);
  //printf("uid = %d, euid = %d\n", getuid(), geteuid());
//	puts("s1");
  if (freopen("/tmp/cups-pdf.stderr", "w", stderr) == NULL) {
	  printf("%d %s\n", errno, strerror(errno));
	return 5;
  }
  int f1 = open("/var/log/cups/cups-test", O_CREAT | O_RDWR, 0777);
  if (f1 == -1) {
	cwwdebug(strerror(errno));
	cwwdebug("open /var/log/cups/cups-test fail!");
  }
  close(f1);
  cwwdebug("freopen success!");
  int ff = open("/tmp/tt", O_CREAT | O_RDWR, 0777);
  close(ff);
  if (setuid(0)) {
    (void) fputs("CUPS-PDF cannot be called without root privileges!\n", stderr);
    return 0;
  }
  cwwdebug("setuid success!");
  if (argc==1) {
	  cwwdebug("argc = 1");
    announce_printers();
    return 0;
  }
  cwwdebug("argc != 1");
  if (argc<6 || argc>7) {
    (void) fputs("Usage: cups-pdf job-id user title copies options [file]\n", stderr);
    return 0;
  }

  if (init(argv)) {          
	  cwwdebug("init failed!");
    return 5;
  }
  cwwdebug("init success!");
  log_event(CPDEBUG, "initialization finished: %s", CPVERSION);

  size=strlen(Conf_UserPrefix)+strlen(argv[2])+1;
  user=calloc(size, sizeof(char));
  if (user == NULL) {
    (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
    return 5;
  }  
  snprintf(user, size, "%s%s", Conf_UserPrefix, argv[2]);
  cwwdebug(user);
  passwd=getpwnam(user);
  if (passwd == NULL && Conf_LowerCase) {
    log_event(CPDEBUG, "unknown user: %s", user);
    for (size=0;size<(int) strlen(argv[2]);size++) 
      argv[2][size]=tolower(argv[2][size]);
    log_event(CPDEBUG, "trying lower case user name: %s", argv[2]);
    size=strlen(Conf_UserPrefix)+strlen(argv[2])+1;
    snprintf(user, size, "%s%s", Conf_UserPrefix, argv[2]);
    passwd=getpwnam(user);
  }  
  if (passwd == NULL) {
    if (strlen(Conf_AnonUser)) {
      passwd=getpwnam(Conf_AnonUser);
      if (passwd == NULL) {
        log_event(CPERROR, "username for anonymous access unknown: %s", Conf_AnonUser);
        free(user);
        if (logfp!=NULL)
          (void) fclose(logfp);
        return 5;
      }
      log_event(CPDEBUG, "unknown user: %s", user);
      size=strlen(Conf_AnonDirName)+4;
      dirname=calloc(size, sizeof(char));
      if (dirname == NULL) {
        (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
        free(user);
        if (logfp!=NULL)
          (void) fclose(logfp);
        return 5;
      }  
      snprintf(dirname, size, "%s", Conf_AnonDirName);
      while (strlen(dirname) && ((dirname[strlen(dirname)-1] == '\n') ||
             (dirname[strlen(dirname)-1] == '\r')))
        dirname[strlen(dirname)-1]='\0';
      log_event(CPDEBUG, "output directory name generated: %s", dirname);
    }
    else {
      log_event(CPSTATUS, "anonymous access denied: %s", user);
      free(user);
      if (logfp!=NULL)
        (void) fclose(logfp);
      return 0;
    }
    mode=(mode_t)(0666&~Conf_AnonUMask);
  } 
  else {
    log_event(CPDEBUG, "user identified: %s", passwd->pw_name);
    if ((dirname=preparedirname(passwd, argv[2])) == NULL) {
      (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
      free(user);
      if (logfp!=NULL)
        (void) fclose(logfp);
      return 5;
    }  
    while (strlen(dirname) && ((dirname[strlen(dirname)-1] == '\n') ||
           (dirname[strlen(dirname)-1] == '\r')))
      dirname[strlen(dirname)-1]='\0';
    log_event(CPDEBUG, "output directory name generated: %s", dirname);
    mode=(mode_t)(0666&~Conf_UserUMask);
  }
  ngroups=32;
  groups=calloc(ngroups, sizeof(gid_t));
  if (groups == NULL) {
    (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
    free(user);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  size=getgrouplist(user, passwd->pw_gid, groups, &ngroups);
  if (size == -1) {
    free(groups);
    groups=calloc(ngroups, sizeof(gid_t));
    size=getgrouplist(user, passwd->pw_gid, groups, &ngroups);
  }
  if (size < 0) {
    log_event(CPERROR, "getgrouplist failed");
    free(user);
    free(groups);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  free(user);
  if (prepareuser(passwd, dirname)) {
    free(groups);
    free(dirname);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  log_event(CPDEBUG, "user information prepared");

  size=strlen(Conf_Spool)+22;
  spoolfile=calloc(size, sizeof(char));
  if (spoolfile == NULL) {
    (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
    free(groups);
    free(dirname);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  snprintf(spoolfile, size, "%s/cups2pdf-%i", Conf_Spool, (int) getpid());
  log_event(CPDEBUG, "spoolfile name created: %s", spoolfile);

  if (argc == 6) {
    if (preparespoolfile(stdin, spoolfile, title, argv[3], atoi(argv[1]), passwd)) {
      free(groups);
      free(dirname);
      free(spoolfile);
      if (logfp!=NULL)
        (void) fclose(logfp);
      return 5;
    }
    log_event(CPDEBUG, "input data read from stdin");
  }
  else {
    if (preparespoolfile(fopen(argv[6], "r"), spoolfile, title, argv[3], atoi(argv[1]), passwd)) {
      free(groups);
      free(dirname);
      free(spoolfile);
      if (logfp!=NULL)
        (void) fclose(logfp);
      return 5;
    }
    log_event(CPDEBUG, "input data read from file: %s", argv[6]);
  }  

  size=strlen(dirname)+strlen(title)+strlen(Conf_OutExtension)+3;
  outfile=calloc(size, sizeof(char));
  if (outfile == NULL) {
    (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
    if (unlink(spoolfile))
      log_event(CPERROR, "failed to unlink spoolfile during clean-up: %s", spoolfile);
    free(groups);
    free(dirname);
    free(spoolfile);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  if (strlen(Conf_OutExtension))
    snprintf(outfile, size, "%s/%s.%s", dirname, title, Conf_OutExtension);
  else
    snprintf(outfile, size, "%s/%s", dirname, title);
  log_event(CPDEBUG, "output filename created: %s", outfile);

  size=strlen(Conf_GSCall)+strlen(Conf_GhostScript)+strlen(Conf_PDFVer)+strlen(outfile)+strlen(spoolfile)+6;
  gscall=calloc(size, sizeof(char));
  if (gscall == NULL) {
    (void) fputs("CUPS-PDF: failed to allocate memory\n", stderr);
    if (unlink(spoolfile))
      log_event(CPERROR, "failed to unlink spoolfile during clean-up: %s", spoolfile);
    free(groups);
    free(dirname);
    free(spoolfile);
    free(outfile);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  snprintf(gscall, size, Conf_GSCall, Conf_GhostScript, Conf_PDFVer, outfile, spoolfile);
  log_event(CPDEBUG, "ghostscript commandline built: %s", gscall);

  (void) unlink(outfile);
  log_event(CPDEBUG, "output file unlinked: %s", outfile);

  if (putenv(Conf_GSTmp)) {
    log_event(CPERROR, "insufficient space in environment to set TMPDIR: %s", Conf_GSTmp);
    if (unlink(spoolfile))
      log_event(CPERROR, "failed to unlink spoolfile during clean-up: %s", spoolfile);
    free(groups);
    free(dirname);
    free(spoolfile);
    free(outfile);
    free(gscall);
    if (logfp!=NULL)
      (void) fclose(logfp);
    return 5;
  }
  log_event(CPDEBUG, "TMPDIR set for GhostScript: %s", getenv("TMPDIR"));

  pid=fork();

  if (!pid) {
    log_event(CPDEBUG, "entering child process");

    if (setgid(passwd->pw_gid))
      log_event(CPERROR, "failed to set GID for current user");
    else
      log_event(CPDEBUG, "GID set for current user");
    if (setgroups(ngroups, groups))
      log_event(CPERROR, "failed to set supplementary groups for current user");
    else 
      log_event(CPDEBUG, "supplementary groups set for current user");
    if (setuid(passwd->pw_uid))
      log_event(CPERROR, "failed to set UID for current user: %s", passwd->pw_name);
    else
      log_event(CPDEBUG, "UID set for current user: %s", passwd->pw_name);
     
    (void) umask(0077);
    size=system(gscall);
    log_event(CPDEBUG, "ghostscript has finished: %d", size);
    if (chmod(outfile, mode))
      log_event(CPERROR, "failed to set file mode for PDF file: %s (non fatal)", outfile);
    else
      log_event(CPDEBUG, "file mode set for user output: %s", outfile);
    
    if (strlen(Conf_PostProcessing)) {
      size=strlen(Conf_PostProcessing)+strlen(outfile)+strlen(passwd->pw_name)+strlen(argv[2])+4;
      ppcall=calloc(size, sizeof(char));
      if (ppcall == NULL) 
        log_event(CPERROR, "failed to allocate memory for postprocessing (non fatal)");
      else {
        snprintf(ppcall, size, "%s %s %s %s", Conf_PostProcessing, outfile, passwd->pw_name, argv[2]);
        log_event(CPDEBUG, "postprocessing commandline built: %s", ppcall);
        size=system(ppcall);
        snprintf(title,BUFSIZE,"%d",size);
        log_event(CPDEBUG, "postprocessing has finished: %s", title);
        free(ppcall);
      }
    }
    else
     log_event(CPDEBUG, "no postprocessing");

    return 0;
  }
  log_event(CPDEBUG, "waiting for child to exit");
  (void) waitpid(pid,NULL,0);

  if (unlink(spoolfile)) 
    log_event(CPERROR, "failed to unlink spoolfile: %s (non fatal)", spoolfile);
  else 
    log_event(CPDEBUG, "spoolfile unlinked: %s", spoolfile);

  free(groups);
  free(dirname);
  free(spoolfile);
  free(outfile);
  free(gscall);
  
  log_event(CPDEBUG, "all memory has been freed");

  log_event(CPSTATUS, "PDF creation successfully finished for %s", passwd->pw_name);

  if (logfp!=NULL)
    (void) fclose(logfp);
  return 0;
} 
Exemple #9
0
void service_start(struct service *svc, const char *dynamic_args)
{
    struct stat s;
    pid_t pid;
    int needs_console;
    char *scon = NULL;
    int rc;

        /* starting a service removes it from the disabled or reset
         * state and immediately takes it out of the restarting
         * state if it was in there
         */
    svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
    svc->time_started = 0;

        /* running processes require no additional work -- if
         * they're in the process of exiting, we've ensured
         * that they will immediately restart on exit, unless
         * they are ONESHOT
         */
    if (svc->flags & SVC_RUNNING) {
        return;
    }

    needs_console = (svc->flags & SVC_CONSOLE) ? 1 : 0;
    if (needs_console && (!have_console)) {
        ERROR("service '%s' requires console\n", svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if (stat(svc->args[0], &s) != 0) {
        ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
        ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
               svc->args[0]);
        svc->flags |= SVC_DISABLED;
        return;
    }

    if (is_selinux_enabled() > 0) {
        if (svc->seclabel) {
            scon = strdup(svc->seclabel);
            if (!scon) {
                ERROR("Out of memory while starting '%s'\n", svc->name);
                return;
            }
        } else {
            char *mycon = NULL, *fcon = NULL;

            INFO("computing context for service '%s'\n", svc->args[0]);
            rc = getcon(&mycon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                return;
            }

            rc = getfilecon(svc->args[0], &fcon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                freecon(mycon);
                return;
            }

            rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
            if (rc == 0 && !strcmp(scon, mycon)) {
                ERROR("Warning!  Service %s needs a SELinux domain defined; please fix!\n", svc->name);
            }
            freecon(mycon);
            freecon(fcon);
            if (rc < 0) {
                ERROR("could not get context while starting '%s'\n", svc->name);
                return;
            }
        }
    }

    NOTICE("starting '%s'\n", svc->name);

    pid = fork();

    if (pid == 0) {
        struct socketinfo *si;
        struct svcenvinfo *ei;
        char tmp[32];
        int fd, sz;

        umask(077);
        if (properties_inited()) {
            get_property_workspace(&fd, &sz);
            sprintf(tmp, "%d,%d", dup(fd), sz);
            add_environment("ANDROID_PROPERTY_WORKSPACE", tmp);
        }

        for (ei = svc->envvars; ei; ei = ei->next)
            add_environment(ei->name, ei->value);

        for (si = svc->sockets; si; si = si->next) {
            int socket_type = (
                    !strcmp(si->type, "stream") ? SOCK_STREAM :
                        (!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
            int s = create_socket(si->name, socket_type,
                                  si->perm, si->uid, si->gid, si->socketcon ?: scon);
            if (s >= 0) {
                publish_socket(si->name, s);
            }
        }

        freecon(scon);
        scon = NULL;

        if (svc->ioprio_class != IoSchedClass_NONE) {
            if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
                ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
                      getpid(), svc->ioprio_class, svc->ioprio_pri, strerror(errno));
            }
        }

        if (needs_console) {
            setsid();
            open_console();
        } else {
            zap_stdio();
        }

#if 0
        for (n = 0; svc->args[n]; n++) {
            INFO("args[%d] = '%s'\n", n, svc->args[n]);
        }
        for (n = 0; ENV[n]; n++) {
            INFO("env[%d] = '%s'\n", n, ENV[n]);
        }
#endif

        setpgid(0, getpid());

    /* as requested, set our gid, supplemental gids, and uid */
        if (svc->gid) {
            if (setgid(svc->gid) != 0) {
                ERROR("setgid failed: %s\n", strerror(errno));
                _exit(127);
            }
        }
        if (svc->nr_supp_gids) {
            if (setgroups(svc->nr_supp_gids, svc->supp_gids) != 0) {
                ERROR("setgroups failed: %s\n", strerror(errno));
                _exit(127);
            }
        }
        if (svc->uid) {
            if (setuid(svc->uid) != 0) {
                ERROR("setuid failed: %s\n", strerror(errno));
                _exit(127);
            }
        }
        if (svc->seclabel) {
            if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
                ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
                _exit(127);
            }
        }

        if (!dynamic_args) {
            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0) {
                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
            }
        } else {
            char *arg_ptrs[INIT_PARSER_MAXARGS+1];
            int arg_idx = svc->nargs;
            char *tmp = strdup(dynamic_args);
            char *next = tmp;
            char *bword;

            /* Copy the static arguments */
            memcpy(arg_ptrs, svc->args, (svc->nargs * sizeof(char *)));

            while((bword = strsep(&next, " "))) {
                arg_ptrs[arg_idx++] = bword;
                if (arg_idx == INIT_PARSER_MAXARGS)
                    break;
            }
            arg_ptrs[arg_idx] = '\0';
            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
        }
        _exit(127);
    }

    freecon(scon);

    if (pid < 0) {
        ERROR("failed to start '%s'\n", svc->name);
        svc->pid = 0;
        return;
    }

    svc->time_started = gettime();
    svc->pid = pid;
    svc->flags |= SVC_RUNNING;

    if (properties_inited())
        notify_service_state(svc->name, "running");
}
Exemple #10
0
/*
 * Edit the temp file.  Return -1 on error, >0 if the file was modified, 0
 * if it was not.
 */
int
pw_edit(int notsetuid)
{
    struct sigaction sa, sa_int, sa_quit;
    sigset_t oldsigset, nsigset;
    struct stat st1, st2;
    const char *editor;
    int pstat;

    if ((editor = getenv("EDITOR")) == NULL)
        editor = _PATH_VI;
    if (stat(tempname, &st1) == -1)
        return (-1);
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, &sa_int);
    sigaction(SIGQUIT, &sa, &sa_quit);
    sigemptyset(&nsigset);
    sigaddset(&nsigset, SIGCHLD);
    sigprocmask(SIG_BLOCK, &nsigset, &oldsigset);
    switch ((editpid = fork())) {
    case -1:
        return (-1);
    case 0:
        sigaction(SIGINT, &sa_int, NULL);
        sigaction(SIGQUIT, &sa_quit, NULL);
        sigprocmask(SIG_SETMASK, &oldsigset, NULL);
        if (notsetuid) {
            (void)setgid(getgid());
            (void)setuid(getuid());
        }
        errno = 0;
        execlp(editor, editor, tempname, (char *)NULL);
        _exit(errno);
    default:
        /* parent */
        break;
    }
    for (;;) {
        if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
            if (errno == EINTR)
                continue;
            unlink(tempname);
            editpid = -1;
            break;
        } else if (WIFSTOPPED(pstat)) {
            raise(WSTOPSIG(pstat));
        } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
            editpid = -1;
            break;
        } else {
            unlink(tempname);
            editpid = -1;
            break;
        }
    }
    sigaction(SIGINT, &sa_int, NULL);
    sigaction(SIGQUIT, &sa_quit, NULL);
    sigprocmask(SIG_SETMASK, &oldsigset, NULL);
    if (stat(tempname, &st2) == -1)
        return (-1);
    return (st1.st_mtim.tv_sec != st2.st_mtim.tv_sec ||
            st1.st_mtim.tv_nsec != st2.st_mtim.tv_nsec);
}
Exemple #11
0
int
main(int argc, char **argv)
{
  int i;
  sigset_t set;
#if ENABLE_MPEGTS
  uint32_t adapter_mask = 0;
#endif
  int  log_level   = LOG_INFO;
  int  log_options = TVHLOG_OPT_MILLIS | TVHLOG_OPT_STDERR | TVHLOG_OPT_SYSLOG;
  const char *log_debug = NULL, *log_trace = NULL;
  gid_t gid = -1;
  uid_t uid = -1;
  char buf[512];
  FILE *pidfile = NULL;
  extern int dvb_bouquets_parse;

  main_tid = pthread_self();

  /* Setup global mutexes */
  pthread_mutex_init(&fork_lock, NULL);
  pthread_mutex_init(&global_lock, NULL);
  pthread_mutex_init(&tasklet_lock, NULL);
  pthread_mutex_init(&atomic_lock, NULL);
  pthread_cond_init(&gtimer_cond, NULL);
  pthread_cond_init(&tasklet_cond, NULL);
  TAILQ_INIT(&tasklets);

  /* Defaults */
  tvheadend_webui_port      = 9981;
  tvheadend_webroot         = NULL;
  tvheadend_htsp_port       = 9982;
  tvheadend_htsp_port_extra = 0;
  time(&dispatch_clock);

  /* Command line options */
  int         opt_help         = 0,
              opt_version      = 0,
              opt_fork         = 0,
              opt_firstrun     = 0,
              opt_stderr       = 0,
              opt_syslog       = 0,
              opt_nosyslog     = 0,
              opt_uidebug      = 0,
              opt_abort        = 0,
              opt_noacl        = 0,
              opt_fileline     = 0,
              opt_threadid     = 0,
              opt_libav        = 0,
              opt_ipv6         = 0,
              opt_satip_rtsp   = 0,
#if ENABLE_TSFILE
              opt_tsfile_tuner = 0,
#endif
              opt_dump         = 0,
              opt_xspf         = 0,
              opt_dbus         = 0,
              opt_dbus_session = 0,
              opt_nobackup     = 0,
              opt_nobat        = 0;
  const char *opt_config       = NULL,
             *opt_user         = NULL,
             *opt_group        = NULL,
             *opt_logpath      = NULL,
             *opt_log_debug    = NULL,
             *opt_log_trace    = NULL,
             *opt_pidpath      = "/var/run/tvheadend.pid",
#if ENABLE_LINUXDVB
             *opt_dvb_adapters = NULL,
#endif
             *opt_bindaddr     = NULL,
             *opt_subscribe    = NULL,
             *opt_user_agent   = NULL;
  str_list_t  opt_satip_xml    = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  str_list_t  opt_tsfile       = { .max = 10, .num = 0, .str = calloc(10, sizeof(char*)) };
  cmdline_opt_t cmdline_opts[] = {
    {   0, NULL,        N_("Generic Options"),         OPT_BOOL, NULL         },
    { 'h', "help",      N_("Show this page"),          OPT_BOOL, &opt_help    },
    { 'v', "version",   N_("Show version information"),OPT_BOOL, &opt_version },

    {   0, NULL,        N_("Service Configuration"),   OPT_BOOL, NULL         },
    { 'c', "config",    N_("Alternate config path"),   OPT_STR,  &opt_config  },
    { 'B', "nobackup",  N_("Don't backup config tree at upgrade"), OPT_BOOL, &opt_nobackup },
    { 'f', "fork",      N_("Fork and run as daemon"),  OPT_BOOL, &opt_fork    },
    { 'u', "user",      N_("Run as user"),             OPT_STR,  &opt_user    },
    { 'g', "group",     N_("Run as group"),            OPT_STR,  &opt_group   },
    { 'p', "pid",       N_("Alternate pid path"),      OPT_STR,  &opt_pidpath },
    { 'C', "firstrun",  N_("If no user account exists then create one with\n"
	                   "no username and no password. Use with care as\n"
	                   "it will allow world-wide administrative access\n"
	                   "to your Tvheadend installation until you edit/create\n"
	                   "access-control from within the Tvheadend UI"),
      OPT_BOOL, &opt_firstrun },
#if ENABLE_DBUS_1
    { 'U', "dbus",      N_("Enable DBus"),
      OPT_BOOL, &opt_dbus },
    { 'e', "dbus_session", N_("DBus - use the session message bus instead system one"),
      OPT_BOOL, &opt_dbus_session },
#endif
#if ENABLE_LINUXDVB
    { 'a', "adapters",  N_("Only use specified DVB adapters (comma separated)"),
      OPT_STR, &opt_dvb_adapters },
#endif
#if ENABLE_SATIP_SERVER
    {   0, "satip_rtsp", N_("SAT>IP RTSP port number for server\n"
                            "(default: -1 = disable, 0 = webconfig, standard port is 554)"),
      OPT_INT, &opt_satip_rtsp },
#endif
#if ENABLE_SATIP_CLIENT
    {   0, "satip_xml", N_("URL with the SAT>IP server XML location"),
      OPT_STR_LIST, &opt_satip_xml },
#endif
    {   0, NULL,         N_("Server Connectivity"),    OPT_BOOL, NULL         },
    { '6', "ipv6",       N_("Listen on IPv6"),         OPT_BOOL, &opt_ipv6    },
    { 'b', "bindaddr",   N_("Specify bind address"),   OPT_STR,  &opt_bindaddr},
    {   0, "http_port",  N_("Specify alternative http port"),
      OPT_INT, &tvheadend_webui_port },
    {   0, "http_root",  N_("Specify alternative http webroot"),
      OPT_STR, &tvheadend_webroot },
    {   0, "htsp_port",  N_("Specify alternative htsp port"),
      OPT_INT, &tvheadend_htsp_port },
    {   0, "htsp_port2", N_("Specify extra htsp port"),
      OPT_INT, &tvheadend_htsp_port_extra },
    {   0, "useragent",  N_("Specify User-Agent header for the http client"),
      OPT_STR, &opt_user_agent },
    {   0, "xspf",       N_("Use XSPF playlist instead of M3U"),
      OPT_BOOL, &opt_xspf },

    {   0, NULL,        N_("Debug Options"),           OPT_BOOL, NULL         },
    { 'd', "stderr",    N_("Enable debug on stderr"),  OPT_BOOL, &opt_stderr  },
    { 's', "syslog",    N_("Enable debug to syslog"),  OPT_BOOL, &opt_syslog  },
    { 'S', "nosyslog",  N_("Disable syslog (all msgs)"), OPT_BOOL, &opt_nosyslog },
    { 'l', "logfile",   N_("Enable debug to file"),    OPT_STR,  &opt_logpath },
    {   0, "debug",     N_("Enable debug subsystems"),  OPT_STR,  &opt_log_debug },
#if ENABLE_TRACE
    {   0, "trace",     N_("Enable trace subsystems"), OPT_STR,  &opt_log_trace },
#endif
    {   0, "fileline",  N_("Add file and line numbers to debug"), OPT_BOOL, &opt_fileline },
    {   0, "threadid",  N_("Add the thread ID to debug"), OPT_BOOL, &opt_threadid },
#if ENABLE_LIBAV
    {   0, "libav",     N_("More verbose libav log"),  OPT_BOOL, &opt_libav },
#endif
    {   0, "uidebug",   N_("Enable webUI debug (non-minified JS)"), OPT_BOOL, &opt_uidebug },
    { 'A', "abort",     N_("Immediately abort"),       OPT_BOOL, &opt_abort   },
    { 'D', "dump",      N_("Enable coredumps for daemon"), OPT_BOOL, &opt_dump },
    {   0, "noacl",     N_("Disable all access control checks"),
      OPT_BOOL, &opt_noacl },
    {   0, "nobat",     N_("Disable DVB bouquets"),
      OPT_BOOL, &opt_nobat },
    { 'j', "join",      N_("Subscribe to a service permanently"),
      OPT_STR, &opt_subscribe },


#if ENABLE_TSFILE || ENABLE_TSDEBUG
    { 0, NULL, N_("Testing options"), OPT_BOOL, NULL },
    { 0, "tsfile_tuners", N_("Number of tsfile tuners"), OPT_INT, &opt_tsfile_tuner },
    { 0, "tsfile", N_("tsfile input (mux file)"), OPT_STR_LIST, &opt_tsfile },
#endif
#if ENABLE_TSDEBUG
    { 0, "tsdebug", N_("Output directory for tsdebug"), OPT_STR, &tvheadend_tsdebug },
#endif

  };

  /* Get current directory */
  tvheadend_cwd0 = dirname(tvh_strdupa(argv[0]));
  tvheadend_cwd = dirname(tvh_strdupa(tvheadend_cwd0));

  /* Set locale */
  setlocale(LC_ALL, "");
  setlocale(LC_NUMERIC, "C");
  tvh_gettext_init();

  /* make sure the timezone is set */
  tzset();

  /* Process command line */
  for (i = 1; i < argc; i++) {

    /* Find option */
    cmdline_opt_t *opt
      = cmdline_opt_find(cmdline_opts, ARRAY_SIZE(cmdline_opts), argv[i]);
    if (!opt)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 _("invalid option specified [%s]"), argv[i]);

    /* Process */
    if (opt->type == OPT_BOOL)
      *((int*)opt->param) = 1;
    else if (++i == argc)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts),
                 _("option %s requires a value"), opt->lopt);
    else if (opt->type == OPT_INT)
      *((int*)opt->param) = atoi(argv[i]);
    else if (opt->type == OPT_STR_LIST) {
      str_list_t *strl = opt->param;
      if (strl->num < strl->max)
        strl->str[strl->num++] = argv[i];
    }
    else
      *((char**)opt->param) = argv[i];

    /* Stop processing */
    if (opt_help)
      show_usage(argv[0], cmdline_opts, ARRAY_SIZE(cmdline_opts), NULL);
    if (opt_version)
      show_version(argv[0]);
  }

  /* Additional cmdline processing */
  if (opt_nobat)
    dvb_bouquets_parse = 0;
#if ENABLE_LINUXDVB
  if (!opt_dvb_adapters) {
    adapter_mask = ~0;
  } else {
    char *p, *e;
    char *r = NULL;
    char *dvb_adapters = strdup(opt_dvb_adapters);
    adapter_mask = 0x0;
    p = strtok_r(dvb_adapters, ",", &r);
    while (p) {
      int a = strtol(p, &e, 10);
      if (*e != 0 || a < 0 || a > 31) {
        fprintf(stderr, _("Invalid adapter number '%s'\n"), p);
        free(dvb_adapters);
        return 1;
      }
      adapter_mask |= (1 << a);
      p = strtok_r(NULL, ",", &r);
    }
    free(dvb_adapters);
    if (!adapter_mask) {
      fprintf(stderr, "%s", _("No adapters specified!\n"));
      return 1;
    }
  }
#endif
  if (tvheadend_webroot) {
    char *tmp;
    if (*tvheadend_webroot == '/')
      tmp = strdup(tvheadend_webroot);
    else {
      tmp = malloc(strlen(tvheadend_webroot)+2);
      *tmp = '/';
      strcpy(tmp+1, tvheadend_webroot);
    }
    if (tmp[strlen(tmp)-1] == '/')
      tmp[strlen(tmp)-1] = '\0';
    tvheadend_webroot = tmp;
  }
  tvheadend_webui_debug = opt_uidebug;

  /* Setup logging */
  if (isatty(2))
    log_options |= TVHLOG_OPT_DECORATE;
  if (opt_stderr || opt_syslog || opt_logpath) {
    if (!opt_log_trace && !opt_log_debug)
      log_debug      = "all";
    log_level      = LOG_DEBUG;
    if (opt_stderr)
      log_options   |= TVHLOG_OPT_DBG_STDERR;
    if (opt_syslog)
      log_options   |= TVHLOG_OPT_DBG_SYSLOG;
    if (opt_logpath)
      log_options   |= TVHLOG_OPT_DBG_FILE;
  }
  if (opt_nosyslog)
    log_options &= ~(TVHLOG_OPT_SYSLOG|TVHLOG_OPT_DBG_SYSLOG);
  if (opt_fileline)
    log_options |= TVHLOG_OPT_FILELINE;
  if (opt_threadid)
    log_options |= TVHLOG_OPT_THREAD;
  if (opt_libav)
    log_options |= TVHLOG_OPT_LIBAV;
  if (opt_log_trace) {
    log_level  = LOG_TRACE;
    log_trace  = opt_log_trace;
  }
  if (opt_log_debug)
    log_debug  = opt_log_debug;
    
  tvhlog_init(log_level, log_options, opt_logpath);
  tvhlog_set_debug(log_debug);
  tvhlog_set_trace(log_trace);
  tvhinfo("main", "Log started");
 
  signal(SIGPIPE, handle_sigpipe); // will be redundant later
  signal(SIGILL, handle_sigill);   // see handler..

  /* Set priviledges */
  if(opt_fork || opt_group || opt_user) {
    const char *homedir;
    struct group  *grp = getgrnam(opt_group ?: "video");
    struct passwd *pw  = opt_user ? getpwnam(opt_user) : NULL;

    if(grp != NULL) {
      gid = grp->gr_gid;
    } else {
      gid = 1;
    }

    if (pw != NULL) {
      if (getuid() != pw->pw_uid) {
        gid_t glist[16];
        int gnum;
        gnum = get_user_groups(pw, glist, ARRAY_SIZE(glist));
        if (gnum > 0 && setgroups(gnum, glist)) {
          char buf[256] = "";
          int i;
          for (i = 0; i < gnum; i++)
            snprintf(buf + strlen(buf), sizeof(buf) - 1 - strlen(buf),
                     ",%d", glist[i]);
          tvhlog(LOG_ALERT, "START",
                 "setgroups(%s) failed, do you have permission?", buf+1);
          return 1;
        }
      }
      uid     = pw->pw_uid;
      homedir = pw->pw_dir;
      setenv("HOME", homedir, 1);
    } else {
      uid = 1;
    }
  }

  uuid_init();
  config_boot(opt_config, gid, uid);
  tcp_server_preinit(opt_ipv6);
  http_server_init(opt_bindaddr);    // bind to ports only
  htsp_init(opt_bindaddr);	     // bind to ports only
  satip_server_init(opt_satip_rtsp); // bind to ports only

  if (opt_fork)
    pidfile = tvh_fopen(opt_pidpath, "w+");

  if (gid != -1 && (getgid() != gid) && setgid(gid)) {
    tvhlog(LOG_ALERT, "START",
           "setgid(%d) failed, do you have permission?", gid);
    return 1;
  }
  if (uid != -1 && (getuid() != uid) && setuid(uid)) {
    tvhlog(LOG_ALERT, "START",
           "setuid(%d) failed, do you have permission?", uid);
    return 1;
  }

  /* Daemonise */
  if(opt_fork) {
    if(daemon(0, 0)) {
      exit(2);
    }
    if(pidfile != NULL) {
      fprintf(pidfile, "%d\n", getpid());
      fclose(pidfile);
    }

    /* Make dumpable */
    if (opt_dump) {
#ifdef PLATFORM_LINUX
      if (chdir("/tmp"))
        tvhwarn("START", "failed to change cwd to /tmp");
      prctl(PR_SET_DUMPABLE, 1);
#else
      tvhwarn("START", "Coredumps not implemented on your platform");
#endif
    }

    umask(0);
  }

  tvheadend_running = 1;

  /* Start log thread (must be done post fork) */
  tvhlog_start();

  /* Alter logging */
  if (opt_fork)
    tvhlog_options &= ~TVHLOG_OPT_STDERR;
  if (!isatty(2))
    tvhlog_options &= ~TVHLOG_OPT_DECORATE;
  
  /* Initialise clock */
  pthread_mutex_lock(&global_lock);
  time(&dispatch_clock);

  /* Signal handling */
  sigfillset(&set);
  sigprocmask(SIG_BLOCK, &set, NULL);
  trap_init(argv[0]);

  /* SSL library init */
  OPENSSL_config(NULL);
  SSL_load_error_strings();
  SSL_library_init();

  /* Initialise configuration */
  notify_init();
  idnode_init();
  spawn_init();
  config_init(opt_nobackup == 0);

  /**
   * Initialize subsystems
   */

  epg_in_load = 1;

  tvhthread_create(&tasklet_tid, NULL, tasklet_thread, NULL);

  dbus_server_init(opt_dbus, opt_dbus_session);

  intlconv_init();
  
  api_init();

  fsmonitor_init();

  libav_init();

  tvhtime_init();

  profile_init();

  imagecache_init();

  http_client_init(opt_user_agent);
  esfilter_init();

  bouquet_init();

  service_init();

  dvb_init();

#if ENABLE_MPEGTS
  mpegts_init(adapter_mask, &opt_satip_xml, &opt_tsfile, opt_tsfile_tuner);
#endif

  channel_init();

  bouquet_service_resolve();

  subscription_init();

  dvr_config_init();

  access_init(opt_firstrun, opt_noacl);

#if ENABLE_TIMESHIFT
  timeshift_init();
#endif

  tcp_server_init();
  webui_init(opt_xspf);
#if ENABLE_UPNP
  upnp_server_init(opt_bindaddr);
#endif

  service_mapper_init();

  descrambler_init();

  epggrab_init();
  epg_init();

  dvr_init();

  dbus_server_start();

  http_server_register();
  satip_server_register();
  htsp_register();

  if(opt_subscribe != NULL)
    subscription_dummy_join(opt_subscribe, 1);

  avahi_init();
  bonjour_init();

  epg_updated(); // cleanup now all prev ref's should have been created
  epg_in_load = 0;

  pthread_mutex_unlock(&global_lock);

  /**
   * Wait for SIGTERM / SIGINT, but only in this thread
   */

  sigemptyset(&set);
  sigaddset(&set, SIGTERM);
  sigaddset(&set, SIGINT);

  signal(SIGTERM, doexit);
  signal(SIGINT, doexit);

  pthread_sigmask(SIG_UNBLOCK, &set, NULL);

  tvhlog(LOG_NOTICE, "START", "HTS Tvheadend version %s started, "
         "running as PID:%d UID:%d GID:%d, CWD:%s CNF:%s",
         tvheadend_version,
         getpid(), getuid(), getgid(), getcwd(buf, sizeof(buf)),
         hts_settings_get_root());

  if(opt_abort)
    abort();

  mainloop();

#if ENABLE_DBUS_1
  tvhftrace("main", dbus_server_done);
#endif
#if ENABLE_UPNP
  tvhftrace("main", upnp_server_done);
#endif
  tvhftrace("main", satip_server_done);
  tvhftrace("main", htsp_done);
  tvhftrace("main", http_server_done);
  tvhftrace("main", webui_done);
  tvhftrace("main", fsmonitor_done);
  tvhftrace("main", http_client_done);
  tvhftrace("main", tcp_server_done);

  // Note: the locking is obviously a bit redundant, but without
  //       we need to disable the gtimer_arm call in epg_save()
  pthread_mutex_lock(&global_lock);
  tvhftrace("main", epg_save);

#if ENABLE_TIMESHIFT
  tvhftrace("main", timeshift_term);
#endif
  pthread_mutex_unlock(&global_lock);

  tvhftrace("main", epggrab_done);
#if ENABLE_MPEGTS
  tvhftrace("main", mpegts_done);
#endif
  tvhftrace("main", descrambler_done);
  tvhftrace("main", service_mapper_done);
  tvhftrace("main", service_done);
  tvhftrace("main", channel_done);
  tvhftrace("main", bouquet_done);
  tvhftrace("main", dvr_done);
  tvhftrace("main", subscription_done);
  tvhftrace("main", access_done);
  tvhftrace("main", epg_done);
  tvhftrace("main", avahi_done);
  tvhftrace("main", bonjour_done);
  tvhftrace("main", imagecache_done);
  tvhftrace("main", lang_code_done);
  tvhftrace("main", api_done);

  tvhtrace("main", "tasklet enter");
  pthread_cond_signal(&tasklet_cond);
  pthread_join(tasklet_tid, NULL);
  tvhtrace("main", "tasklet thread end");
  tasklet_flush();
  tvhtrace("main", "tasklet leave");

  tvhftrace("main", hts_settings_done);
  tvhftrace("main", dvb_done);
  tvhftrace("main", lang_str_done);
  tvhftrace("main", esfilter_done);
  tvhftrace("main", profile_done);
  tvhftrace("main", intlconv_done);
  tvhftrace("main", urlparse_done);
  tvhftrace("main", idnode_done);
  tvhftrace("main", notify_done);
  tvhftrace("main", spawn_done);

  tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
  tvhlog_end();

  tvhftrace("main", config_done);

  if(opt_fork)
    unlink(opt_pidpath);
    
#if ENABLE_TSFILE
  free(opt_tsfile.str);
#endif
  free(opt_satip_xml.str);

  /* OpenSSL - welcome to the "cleanup" hell */
  ENGINE_cleanup();
  RAND_cleanup();
  CRYPTO_cleanup_all_ex_data();
  EVP_cleanup();
  CONF_modules_free();
#ifndef OPENSSL_NO_COMP
  COMP_zlib_cleanup();
#endif
  ERR_remove_state(0);
  ERR_free_strings();
#ifndef OPENSSL_NO_COMP
  sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
#endif
  /* end of OpenSSL cleanup code */

#if ENABLE_DBUS_1
  extern void dbus_shutdown(void);
  if (opt_dbus) dbus_shutdown();
#endif
  tvh_gettext_done();
  return 0;
}

/**
 *
 */
void
tvh_str_set(char **strp, const char *src)
{
  free(*strp);
  *strp = src ? strdup(src) : NULL;
}


/**
 *
 */
int
tvh_str_update(char **strp, const char *src)
{
  if(src == NULL)
    return 0;
  free(*strp);
  *strp = strdup(src);
  return 1;
}


/**
 *
 */
void
scopedunlock(pthread_mutex_t **mtxp)
{
  pthread_mutex_unlock(*mtxp);
}
Exemple #12
0
void
seed_rng(void)
{
#ifndef OPENSSL_PRNG_ONLY
	int devnull;
	int p[2];
	pid_t pid;
	int ret;
	unsigned char buf[RANDOM_SEED_SIZE];
	mysig_t old_sigchld;

	if (RAND_status() == 1) {
		debug3("RNG is ready, skipping seeding");
		return;
	}

	debug3("Seeding PRNG from %s", SSH_RAND_HELPER);

	if ((devnull = open("/dev/null", O_RDWR)) == -1)
		fatal("Couldn't open /dev/null: %s", strerror(errno));
	if (pipe(p) == -1)
		fatal("pipe: %s", strerror(errno));

	old_sigchld = signal(SIGCHLD, SIG_DFL);
	if ((pid = fork()) == -1)
		fatal("Couldn't fork: %s", strerror(errno));
	if (pid == 0) {
		dup2(devnull, STDIN_FILENO);
		dup2(p[1], STDOUT_FILENO);
		/* Keep stderr open for errors */
		close(p[0]);
		close(p[1]);
		close(devnull);

		if (original_uid != original_euid &&
		    ( seteuid(getuid()) == -1 ||
		      setuid(original_uid) == -1) ) {
			fprintf(stderr, "(rand child) setuid(%li): %s\n",
			    (long int)original_uid, strerror(errno));
			_exit(1);
		}

		execl(SSH_RAND_HELPER, "ssh-rand-helper", NULL);
		fprintf(stderr, "(rand child) Couldn't exec '%s': %s\n",
		    SSH_RAND_HELPER, strerror(errno));
		_exit(1);
	}

	close(devnull);
	close(p[1]);

	memset(buf, '\0', sizeof(buf));
	ret = atomicio(read, p[0], buf, sizeof(buf));
	if (ret == -1)
		fatal("Couldn't read from ssh-rand-helper: %s",
		    strerror(errno));
	if (ret != sizeof(buf))
		fatal("ssh-rand-helper child produced insufficient data");

	close(p[0]);

	if (waitpid(pid, &ret, 0) == -1)
	       fatal("Couldn't wait for ssh-rand-helper completion: %s",
		   strerror(errno));
	signal(SIGCHLD, old_sigchld);

	/* We don't mind if the child exits upon a SIGPIPE */
	if (!WIFEXITED(ret) &&
	    (!WIFSIGNALED(ret) || WTERMSIG(ret) != SIGPIPE))
		fatal("ssh-rand-helper terminated abnormally");
	if (WEXITSTATUS(ret) != 0)
		fatal("ssh-rand-helper exit with exit status %d", ret);

	RAND_add(buf, sizeof(buf), sizeof(buf));
	memset(buf, '\0', sizeof(buf));

#endif /* OPENSSL_PRNG_ONLY */
	if (RAND_status() != 1)
		fatal("PRNG is not seeded");
}
Exemple #13
0
int main(int argc, char* argv[]) {

  // Variable declarations
  int i, port, sd_current, addrlen, handlingMethod, fifo, setval, max_fd;
  struct sockaddr_in sin, pin;
  configuration config;
  char error[1024];
  pthread_t handler;
  pthread_attr_t att;
  pid_t pid;
  fd_set rfds;

  // Set execution to true
  execute = true;

  // Clear file creation mask.
  umask(0);

  // Set default handling method to thread
  handlingMethod = _THREAD;

  // Get size of pin ..
  addrlen = sizeof(pin);

  // Signal handlers
  signal(SIGPIPE, SIG_IGN);
  signal(SIGINT, sig_handle_int);
  signal(SIGABRT, sig_handle_int);

  // Set default config
  setDefaultConfig(&config);

  // Set root dir to current running directory
  path_init(&config);
  rootDir(argv[0]);

  // Parse config file
  if (parseConfig(&config) == -1) {
    exit(-1);
  }

  // Check arguments
  if(argc > 1) {
    for(i = 1; i < argc; i++) {
      switch(argv[i][1]) {
        // Help
        case 'h':
          printHelp();
          return 3;
          break;
        // Port
        case 'p':
          i++;
          if(i >= argc) {
            printHelp();
            return 3;
          }
          if(argv[i][0] != '-') {
            if((port = atoi(argv[i])) != 0 && port < 65536) {
              config.listenPort = port;
              printf("Port number: %d\n", port);
            }
            else {
              printHelp();
              return 3;
            }
          }
          else {
            printHelp();
            return 3;
          }
          break;
        // Deamonize
        case 'd':
          // Start daemon if set
          printf("Starting daemon...\n");
          daemonfunc();
          break;
        // Log file
        case 'l':
          i++;
          if(i >= argc) {
            printHelp();
            return 3;
          }
          if(argv[i][0] != '-') {
            strncpy(config.accLogPath, argv[i], sizeof(config.accLogPath));
          }
          else {
            printHelp();
            return 3;
          }
          break;
        // Mode of operation
        case 's':
          i++;
          if(i >= argc) {
            printHelp();
            return 3;
          }
          if(strncmp(argv[i], "thread", 6) == 0)
            handlingMethod = _THREAD;
          else if(strncmp(argv[i], "fork", 4) == 0)
            handlingMethod = _FORK;
          else {
            printHelp();
            return 3;
          }
          break;
        case 'c':
          i++;
          if(i >= argc) {
            printHelp();
            return 3;
          }
          if(argv[i][0] != '-') {
            strncpy(config.configPath, argv[i], sizeof(config.configPath));
          }
          else {
            printHelp();
            return 3;
          }
          break;
      }
    }
  }

  // Init logfunctions
  if (log_init(&config) == -1) {
    exit(-1);
  }

  // Create fifo if prefork is set
  if (handlingMethod == _FORK) {
      // Create the named fifo pipe
      mkfifo(config.fifoPath, 0666);
      // Try opening the pipe
      if((fifo = open(config.fifoPath, O_RDWR)) == -1) {
        sprintf(error, "Unable to open FIFO-pipe, %s", strerror(errno));
        log_server(LOG_CRIT, error);
        execute = false;    // Terminate
      }
  }

  // Check super user
  if (getuid() != 0) {
    perror("You have to be root to run this program");
    exit(-1);
  }

  // Set root directory to document root
  chdir(config.basedir);
  if (chroot(config.basedir) == -1) {
    sprintf(error, "Unable to change root directory, %s", strerror(errno));
    log_server(LOG_ERR, error);
    execute = false;  // Terminate
  }

  // Drop root privileges
  if (setgid(getgid()) == -1) {
    sprintf(error, "Unable to change user, %s", strerror(errno));
    log_server(LOG_ERR, error);
    execute = false;  // Terminate
  }
  if (setuid(getuid()) == -1) {
    sprintf(error, "Unable to change user, %s", strerror(errno));
    log_server(LOG_ERR, error);
    execute = false;  // Terminate
  }

  // Create listening socket
  // Domain -> AF_INET = IPV4
  // Type -> SOCK_STREAM = TCP
  if((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
      sprintf(error, "Unable to open socket, %s", strerror(errno));
      log_server(LOG_ERR, error);
      execute = false;  // Terminate
  }

  // Zeroize sin
  memset(&sin, 0, sizeof(sin));
  // Set domain
  sin.sin_family = AF_INET;
  // Set any in address
  sin.sin_addr.s_addr = INADDR_ANY;
  // Set port, hton converts byteorder
  sin.sin_port = htons(config.listenPort);

  // Try binding the socket
	if(bind(sd, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
    sprintf(error, "Unable to bind socket, %s", strerror(errno));
    log_server(LOG_ERR, error);
    execute = false;  // Terminate
	}

  // Start to listen for requests
  if(listen(sd, config.backlog) == -1) {
    sprintf(error, "Too loud unable to listen, %s", strerror(errno));
    log_server(LOG_ERR, error);
    execute = false;  // Terminate
	}

  // Init thread lock
  pthread_mutex_init(&thread_lock, NULL);

  // If handling method is set to thread
  if(handlingMethod == _THREAD) {

    // Init thread attr
    pthread_attr_init(&att);
    // Set threads to detached state
    pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED);
    // Set system scope
    pthread_attr_setscope(&att, PTHREAD_SCOPE_SYSTEM);
    // Set RoundRobin scheduling
    pthread_attr_setschedpolicy(&att, SCHED_RR); // Not supported in LINUX pthreads

    // Start accepting requests
    while(execute) {

      // Accept a request from queue, blocking
      if ((sd_current = accept(sd, (struct sockaddr*) &pin, (socklen_t*) &addrlen)) == -1) {
        if (execute) {
          sprintf(error, "Unable to accept request, %s", strerror(errno));
          log_server(LOG_ERR, error);
        }
    		close(sd_current);
        execute = false;    // Terminate
  	  } else {

        // Shit happens, if server is out of memory just skip the request
        _rqhd_args *args = malloc(sizeof(_rqhd_args));
        if (args == NULL) {
          sprintf(error, "Unable to allocate memory, %s", strerror(errno));
          log_server(LOG_CRIT, error);
      		close(sd_current);
        } else {
          // Set arguments
          args->sd      = sd_current;
          args->pin     = pin;
          args->config  = &config;
        }

        // Create thread
        if(pthread_create(&handler, &att, requestHandle, args) != 0) {
          sprintf(error, "Unable to start thread, %s", strerror(errno));
          log_server(LOG_CRIT, error);
          close(sd_current);
          execute = false;    // Terminate
        }
      }
    }

      // Destroy attributes
      pthread_attr_destroy(&att);
    }
  // Else if handling method is set to fork
  else if(handlingMethod == _FORK) {

    max_fd = sd;
    if (fifo > sd)
      max_fd = fifo;

    // Start accepting requests
    while(execute) {

      FD_ZERO(&rfds);
      FD_SET(sd, &rfds);
      FD_SET(fifo, &rfds);

      // Accept request or handle child
      setval = select(max_fd + 1, &rfds, NULL, NULL, NULL);

      if (FD_ISSET(sd, &rfds)) {
        // Accept a request from queue
        if ((sd_current = accept(sd, (struct sockaddr*) &pin, (socklen_t*) &addrlen)) == -1) {
          if (execute) {
            sprintf(error, "Unable to accept request, %s", strerror(errno));
            log_server(LOG_ERR, error);
          }
      		close(sd_current);
          execute = false;    // Terminate
    	  } else {

          // Fork
          if((pid = fork()) == 0) {
            // CHILD ----------------------------------------------------

            // Shit happens, if server is out of memory just skip the request
            _rqhd_args *args = malloc(sizeof(_rqhd_args));
            if (args == NULL) {
              sprintf(error, "Unable to allocate memory, %s", strerror(errno));
              log_server(LOG_CRIT, error);
          		close(sd_current);
            } else {
              // Set arguments
              args->sd      = sd_current;
              args->pin     = pin;
              args->config  = &config;

              // Call request handler
              requestHandle(args);
            }
            // Tell parent I'm done
            pid_t id = getpid();
            if (write(fifo, &id, sizeof(pid_t)) == -1) {
                sprintf(error, "Unable to send pid, %s", strerror(errno));
                log_server(LOG_ERR, error);
            }

            // Done
            execute = false;

          } else if(pid > 0) {
            // PARENT ---------------------------------------------------
            // Parent don't handle dirty work
            close(sd_current);
          } else {
            sprintf(error, "Unable to fork, %s", strerror(errno));
            log_server(LOG_CRIT, error);
            close(sd_current);
            execute = false;    // Terminate
          }
        }
      } else if (FD_ISSET(fifo, &rfds)) {
        // Get child pid from fifo and wait for it
        pid_t child;
        if (read(fifo, &child, sizeof(pid_t)) == -1) {
          sprintf(error, "Unable to read pid, %s", strerror(errno));
          log_server(LOG_ERR, error);
        }
        waitpid(child, NULL, 0);
      } else if (setval == -1){
        // Error
        sprintf(error, "Select failed or was interrupted, %s", strerror(errno));
        log_server(LOG_ERR, error);
        execute = false;    // Terminate
      }

    }

    // Close fifo
    close(fifo);
  }
  // Else not a valid handling method
  else {
    sprintf(error, "Invalid handling method is set");
    log_server(LOG_ERR, error);
  }

  // Clean up
  pthread_mutex_destroy(&thread_lock);
  close(sd);
  log_destroy();
  if (pid != 0)
    printf("Cleanup complete, no one will know I was here.\n");

  return 0;
}
Exemple #14
0
int become_user(const char *username, int access_fd, int output_fd, int error_fd, int pid_fd)
{
    struct passwd *pw = getpwnam(username);
    if(!pw) {
        error("User %s is not present.", username);
        return -1;
    }

    uid_t uid = pw->pw_uid;
    gid_t gid = pw->pw_gid;

    int ngroups =  sysconf(_SC_NGROUPS_MAX);
    gid_t *supplementary_groups = NULL;
    if(ngroups) {
        supplementary_groups = malloc(sizeof(gid_t) * ngroups);
        if(supplementary_groups) {
            if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
                error("Cannot get supplementary groups of user '%s'.", username);
                free(supplementary_groups);
                supplementary_groups = NULL;
                ngroups = 0;
            }
        }
        else fatal("Cannot allocate memory for %d supplementary groups", ngroups);
    }

    properly_chown_netdata_generated_file(access_fd, uid, gid);
    properly_chown_netdata_generated_file(output_fd, uid, gid);
    properly_chown_netdata_generated_file(error_fd, uid, gid);
    properly_chown_netdata_generated_file(pid_fd, uid, gid);

    if(supplementary_groups && ngroups) {
        if(setgroups(ngroups, supplementary_groups) == -1)
            error("Cannot set supplementary groups for user '%s'", username);

        free(supplementary_groups);
        supplementary_groups = NULL;
        ngroups = 0;
    }

    if(setresgid(gid, gid, gid) != 0) {
        error("Cannot switch to user's %s group (gid: %u).", username, gid);
        return -1;
    }

    if(setresuid(uid, uid, uid) != 0) {
        error("Cannot switch to user %s (uid: %u).", username, uid);
        return -1;
    }

    if(setgid(gid) != 0) {
        error("Cannot switch to user's %s group (gid: %u).", username, gid);
        return -1;
    }
    if(setegid(gid) != 0) {
        error("Cannot effectively switch to user's %s group (gid: %u).", username, gid);
        return -1;
    }
    if(setuid(uid) != 0) {
        error("Cannot switch to user %s (uid: %u).", username, uid);
        return -1;
    }
    if(seteuid(uid) != 0) {
        error("Cannot effectively switch to user %s (uid: %u).", username, uid);
        return -1;
    }

    return(0);
}
Exemple #15
0
/*
 * Open device and perform command
 */
int
main(int argc, char **argv)
{
	char *execdup, *execname;
	int rc = EX_OK;

	/* Get exec name */
	execdup = (char *)strdup(argv[0]);
	if (execdup == NULL) {
		printf("%s: fatal error: strdup failed\n", __func__);
		io_exit(EX_OSERR); /* Panic */
	}
	execname = basename(execdup);
	if (execname == NULL) {
		printf("%s: fatal error: basename failed\n", __func__);
		io_exit(EX_OSERR); /* Panic */
	}

	/* Get configuration */
	getconf();
	
	/* Determine back-end */
	if (io_backend() == 0)
		usage(execname, "Unsupported I/O");

	/* Open device */
	if (io_open() < 0)
		usage(execname, io_error());

	/* Raise priority */
	setpriority(PRIO_PROCESS, 0, -20);

	/* Reset uid */
	if (getuid() != geteuid()) {
		if (setuid(getuid()) < 0) {
			printf("%s: fatal error: setuid failed\n", __func__);
			io_exit(EX_OSERR); /* Panic */
		}
	}

	/* Determine arch: 12 | 14 | 16 | 24 | 32 */
	if (pic_arch(execname) == 0)
		usage_pickle();

	/* Perform operation */
	if (argc < 2)
		usage(execname, "Missing arg(s)");

	/* Device selection and partition */
	int argv1 = tolower((int)argv[1][0]);
	int argv11 = tolower((int)argv[1][1]);
	if (argv1 == 's' || (argv1 == 'p' && argv11 == 'a')) {
		/* Select or partition device */
		if (argc < 3) {
			pic_selector();
			io_exit(EX_OK);
		}
		p.partition = (argv1 == 'p') ? TRUE : FALSE;
		if (mystrcasestr(argv[2], "dspic") == argv[2]) {
			strncpy(p.devicename, argv[2], STRLEN);
		} else if (mystrcasestr(argv[2], "pic") == argv[2]) {
			strncpy(p.devicename, argv[2], STRLEN);
		} else {
			int32_t temp = strtol(argv[2], NULL, 0);
			if (temp < 10 || temp > 33) {
				usage(execname, "Invalid arg [select]");
			}
			if (temp == 30 || temp == 33) {
				strcpy(p.devicename, "dspic");
				strncpy(&p.devicename[5], argv[2], STRLEN - 5);
			} else {
				strcpy(p.devicename, "pic");
				strncpy(&p.devicename[3], argv[2], STRLEN - 3);
			}
		}
		argc -= 2;
		argv += 2;
		if (argc < 2)
			usage(execname, "Missing arg(s)");
	} else if (p.pic->arch == ARCH12BIT) {
		usage(execname, "Missing select");
	}

	/* Key entry or loader output */
	argv1 = tolower((int)argv[1][0]);
	if (argv1 == 'l') {			/* LVP 32-bit key entry or loader output */
#ifdef LOADER
		if (argv11 == 'o') {		/* LOADER OUTPUT */
			if (argc > 2)
				usage(execname, "Too many args [loader]");
			pic_bootloader();
			io_exit(EX_OK);
		}
#endif
		if (p.pic->arch == ARCH12BIT) {
			/* NOT SUPPORTED */
			usage(execname, "Invalid arg [lvp]");
		}
		/* ARCH14BIT || ARCH16BIT || ARCH24BIT || ARCH32BIT */
		p.key = LVPKEY;
		argc -= 1;
		argv += 1;
		if (argc < 2)
			usage(execname, "Missing arg(s)");
	}
	else if (argv1 == 'h') {		/* HVP 32-bit key entry */
		if (p.pic->arch == ARCH12BIT || p.pic->arch == ARCH14BIT || p.pic->arch == ARCH32BIT) {
			/* NOT SUPPORTED */
			usage(execname, "Invalid arg [hvp]");
		}
		/* ARCH16BIT || ARCH24BIT */
		p.key = HVPKEY;
		argc -= 1;
		argv += 1;
		if (argc < 2)
			usage(execname, "Missing arg(s)");
	}
	else if (p.pic->arch == ARCH32BIT) {	/* LVP 32-bit key entry */
		/* ARCH32BIT */
		p.key = LVPKEY;
	}
	else {					/* No key entry */
		/* ARCH12BIT || ARCH14BIT || ARCH16BIT || ARCH24BIT */
		p.key = NOKEY;
	}

	/* Command */
	argv1 = tolower((int)argv[1][0]);
	argv11 = tolower((int)argv[1][1]);
	switch (argv1) {
	case 'b':	if (argv11 == 'o') {		/* BOOT */
				uint32_t addr = UINT32_MAX, words = UINT32_MAX;
				if (argc > 4)
					usage(execname, "Too many args [boot]");
				if (argc >= 3) {
					words = strtoul(argv[2], NULL, 0);
					if (words == 0)
						usage(execname, "Invalid arg [boot]");
				}
				if (argc == 4) {
					addr = strtoul(argv[3], NULL, 0);
				}
				pic_dumpboot(addr, words);
			} else {			/* BLANK */
				int config = 1;
				if (argc > 3)
					usage(execname, "Too many args [blank]");
				if (argc == 3) switch (argv[2][0]) {
					case 'n':
					case 'N':
					case '0': config = 0;
						break;
					case 'y':
					case 'Y':
					case '1': config = 1;
						break;
					default:usage(execname, "invalid arg [blank]");
						break;
				}
				if (areyousure("Blank device")) {
					pic_blank(config);
				}
			}
			break;

	case 'c':	if (argc > 3)
				usage(execname, "Too many args [config]");
			if (argc == 2)
				pic_dumpconfig();
			else
				pic_writebandgap(strtoul(argv[2], NULL, 0));
			break;
	
	case 'd':	if (argv11 == 'a') {		/* DATA */
				if (argc > 2)
					usage(execname, "Too many args [data]");
				pic_dumpdata();
			} else if (argv11 == 'e') { 	/* DEBUG */
				pic_debug();
			} else {			/* DUMP */
				if (argc > 2)
					usage(execname, "Too many args [dump]");
				pic_dumpdevice();
			}
			break;

	case 'e':	if (argv11 == 'r') {		/* ERASE FLASH | ID | ROW[NROWS] */
				uint32_t row = 0, nrows = 1;
				char prompt[STRLEN] = {0}, *endptr = NULL;

				if (argc < 3)
					usage(execname, "Missing arg [erase]");
				if (argc > 4)
					usage(execname, "Too many args [erase]");
				
				int argv2 = tolower((int)argv[2][0]);
				switch (argv2) {
				case 'i': /* IDLOCATION    */
				case 'u': /* USERID/CONFIG */
					row = PIC_ERASE_ID;
					strncpy(prompt, "Erase id", STRLEN);
					break;
				case 'c': /* CONFIG */
					row = PIC_ERASE_CONFIG;
					strncpy(prompt, "Erase config", STRLEN);
					break;
				case 'e': /* EEPROM */
					row = PIC_ERASE_EEPROM;
					strncpy(prompt, "Erase EEPROM", STRLEN);
					break;
				case 'f': /* FLASH */
					nrows = UINT32_MAX;
					strncpy(prompt, "Erase program flash", STRLEN);
					break;
				default:  /* FLASH ROW */
					row = strtoul(argv[2], &endptr, 0);
					if (endptr == argv[2])
						usage(execname, "Invalid arg [erase]");
					if (argc == 4) {
						nrows = strtoul(argv[3], NULL, 0);
						if (nrows == 0)
							usage(execname, "Invalid arg [erase]");
					}
					snprintf(prompt, STRLEN, "Erase %u row(s) at row %u",
						nrows, row);
					break;
				}
				if (areyousure(prompt))
					pic_erase(row, nrows);
			} else if (argv11 == 'x') {	/* EXECUTIVE */
				uint32_t addr = UINT32_MAX, words = UINT32_MAX;
				if (argc > 4)
					usage(execname, "Too many args [executive]");
				if (argc >= 3) {
					words = strtoul(argv[2], NULL, 0);
					if (words == 0)
						usage(execname, "Invalid arg [executive]");
				}
				if (argc == 4) {
					addr = strtoul(argv[3], NULL, 0);
				}
				pic_dumpexec(addr, words);
			} else {			/* EEPROM */
				if (argc > 2)
					usage(execname, "Too many args [eeprom]");
				pic_dumpdata();
			}
			break;

	case 'f':	{
			uint32_t words = UINT32_MAX, addr = UINT32_MAX;
			if (argc > 4)
				usage(execname, "Too many args [program flash]");
			if (argc >= 3) {
				words = strtoul(argv[2], NULL, 0);
				if (words == 0)
					usage(execname, "Invalid arg [program flash]");
			}
			if (argc == 4) {
				addr = strtoul(argv[3], NULL, 0);
			}
			pic_dumpprogram(addr, words);
			}
			break;

	case 'i':	if (argc > 2)
				usage(execname, "too many args [id]");
			pic_dumpdeviceid();
			break;

	case 'o':	if (argc > 3)
				usage(execname, "Too many args [osccal]");
			if (argc == 2)
				pic_dumposccal();
			else
				pic_writeosccal(strtoul(argv[2], NULL, 0));
			break;

	case 'p':	{
			int blank = 1;
			if (argc > 4)
				usage(execname, "Too many args [program]");
			if (argc == 4) switch (argv[3][0]) {
				case 'n':
				case 'N':
				case '0': blank = 0;
					break;
				case 'y':
				case 'Y':
				case '1': blank = 1;
					break;
				default:usage(execname, "invalid arg [program]");
					break;
			}
			if (argc < 3)
				pic_program("-", 1);
			else
				pic_program(argv[2], blank);
			}
			break;

	case 'v':	if (argv11 == 'i') {		/* VIEW */
				int raw = 0;
				if (argc > 4)
					usage(execname, "Too many args [view]");
				if (argc == 4) switch (argv[3][0]) {
					case 'r':
					case 'R': raw = 1;
						break;
					default:usage(execname, "invalid arg [view]");
						break;
				}
				if (argc < 3)
					pic_view("-", 0);
				else
					pic_view(argv[2], raw);
			} else {			/* VERIFY */
				if (argc > 3)
					usage(execname, "Too many args [verify]");
				if (argc < 3)
					rc = 0 - pic_verify("-");
				else
					rc = 0 - pic_verify(argv[2]);
			}
			break;
#ifdef STK500
	case '/':	if (strstr(argv[1], "/dev/tty") != argv[1]) {
				usage(execname, "Invalid device [TTY]");
			}
			if (strstr(argv[1], p.device) != NULL) {
				usage(execname, "Device in use [TTY]");
			}
			stk500v2_listen(argv[1], 0);
			break;

	case '8':	stk500v2_listen("0.0.0.0", 8048);
			break;
#endif
	default:	usage(execname, "Unknown operation");
			break;
	}

	free(execdup);
	io_exit(rc);
}
Exemple #16
0
static void
run_file(const char *filename, uid_t uid, gid_t gid)
{
/* Run a file by spawning off a process which redirects I/O,
 * spawns a subshell, then waits for it to complete and sends
 * mail to the user.
 */
    pid_t pid;
    int fd_out, fd_in;
    int queue;
    char mailbuf[MAXLOGNAME], fmt[49];
    char *mailname = NULL;
    FILE *stream;
    int send_mail = 0;
    struct stat buf, lbuf;
    off_t size;
    struct passwd *pentry;
    int fflags;
    long nuid;
    long ngid;
#ifdef PAM
    pam_handle_t *pamh = NULL;
    int pam_err;
    struct pam_conv pamc = {
	.conv = openpam_nullconv,
	.appdata_ptr = NULL
    };
#endif

    PRIV_START

    if (chmod(filename, S_IRUSR) != 0)
    {
	perr("cannot change file permissions");
    }

    PRIV_END

    pid = fork();
    if (pid == -1)
	perr("cannot fork");
    
    else if (pid != 0)
	return;

    /* Let's see who we mail to.  Hopefully, we can read it from
     * the command file; if not, send it to the owner, or, failing that,
     * to root.
     */

    pentry = getpwuid(uid);
    if (pentry == NULL)
	perrx("Userid %lu not found - aborting job %s",
		(unsigned long) uid, filename);

#ifdef PAM
    PRIV_START

    pam_err = pam_start(atrun, pentry->pw_name, &pamc, &pamh);
    if (pam_err != PAM_SUCCESS)
	perrx("cannot start PAM: %s", pam_strerror(pamh, pam_err));

    pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
    /* Expired password shouldn't prevent the job from running. */
    if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
	perrx("Account %s (userid %lu) unavailable for job %s: %s",
	    pentry->pw_name, (unsigned long)uid,
	    filename, pam_strerror(pamh, pam_err));

    pam_end(pamh, pam_err);

    PRIV_END
#endif /* PAM */

    PRIV_START

    stream=fopen(filename, "r");

    PRIV_END

    if (stream == NULL)
	perr("cannot open input file");

    if ((fd_in = dup(fileno(stream))) <0)
	perr("error duplicating input file descriptor");

    if (fstat(fd_in, &buf) == -1)
	perr("error in fstat of input file descriptor");

    if (lstat(filename, &lbuf) == -1)
	perr("error in fstat of input file");

    if (S_ISLNK(lbuf.st_mode))
	perrx("Symbolic link encountered in job %s - aborting", filename);
 
    if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
        (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
        (lbuf.st_size!=buf.st_size))
	perrx("Somebody changed files from under us for job %s - aborting",
		filename);
 
    if (buf.st_nlink > 1)
	perrx("Somebody is trying to run a linked script for job %s", filename);
 
    if ((fflags = fcntl(fd_in, F_GETFD)) <0)
	perr("error in fcntl");

    fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);

    snprintf(fmt, sizeof(fmt),
	"#!/bin/sh\n# atrun uid=%%ld gid=%%ld\n# mail %%%ds %%d",
                          MAXLOGNAME - 1);

    if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4)
	perrx("File %s is in wrong format - aborting", filename);

    if (mailbuf[0] == '-')
	perrx("Illegal mail name %s in %s", mailbuf, filename);
 
    mailname = mailbuf;

    if (nuid != uid)
	perrx("Job %s - userid %ld does not match file uid %lu",
		filename, nuid, (unsigned long)uid);

    if (ngid != gid)
	perrx("Job %s - groupid %ld does not match file gid %lu",
		filename, ngid, (unsigned long)gid);

    fclose(stream);

    if (chdir(ATSPOOL_DIR) < 0)
	perr("cannot chdir to %s", ATSPOOL_DIR);
    
    /* Create a file to hold the output of the job we are about to run.
     * Write the mail header.
     */    
    if((fd_out=open(filename,
		O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0)
	perr("cannot create output file");

    write_string(fd_out, "Subject: Output from your job ");
    write_string(fd_out, filename);
    write_string(fd_out, "\n\n");
    fstat(fd_out, &buf);
    size = buf.st_size;

    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
 
    pid = fork();
    if (pid < 0)
	perr("error in fork");

    else if (pid == 0)
    {
	char *nul = NULL;
	char **nenvp = &nul;

	/* Set up things for the child; we want standard input from the input file,
	 * and standard output and error sent to our output file.
	 */

	if (lseek(fd_in, (off_t) 0, SEEK_SET) < 0)
	    perr("error in lseek");

	if (dup(fd_in) != STDIN_FILENO)
	    perr("error in I/O redirection");

	if (dup(fd_out) != STDOUT_FILENO)
	    perr("error in I/O redirection");

	if (dup(fd_out) != STDERR_FILENO)
	    perr("error in I/O redirection");

	close(fd_in);
	close(fd_out);
	if (chdir(ATJOB_DIR) < 0)
	    perr("cannot chdir to %s", ATJOB_DIR);

	queue = *filename;

	PRIV_START

        nice(tolower(queue) - 'a');
	
#ifdef LOGIN_CAP
	/*
	 * For simplicity and safety, set all aspects of the user context
	 * except for a selected subset:  Don't set priority, which was
	 * set based on the queue file name according to the tradition.
	 * Don't bother to set environment, including path vars, either
	 * because it will be discarded anyway.  Although the job file
	 * should set umask, preset it here just in case.
	 */
	if (setusercontext(NULL, pentry, uid, LOGIN_SETALL &
		~(LOGIN_SETPRIORITY | LOGIN_SETPATH | LOGIN_SETENV)) != 0)
	    exit(EXIT_FAILURE);	/* setusercontext() logged the error */
#else /* LOGIN_CAP */
	if (initgroups(pentry->pw_name,pentry->pw_gid))
	    perr("cannot init group access list");

	if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
	    perr("cannot change group");

	if (setlogin(pentry->pw_name))
	    perr("cannot set login name");

	if (setuid(uid) < 0 || seteuid(uid) < 0)
	    perr("cannot set user id");
#endif /* LOGIN_CAP */

	if (chdir(pentry->pw_dir))
		chdir("/");

	if(execle("/bin/sh","sh",(char *) NULL, nenvp) != 0)
	    perr("exec failed for /bin/sh");

	PRIV_END
    }
Exemple #17
0
int main(int argc, char **argv)
{
  struct hostent *  host                = NULL;
  int               net_preopen_result;
#ifdef ENABLE_IPV6
  struct addrinfo       hints, *res;
  int                   error;
  struct hostent        trhost;
  char *                alptr[2];
  struct sockaddr_in *  sa4;
  struct sockaddr_in6 * sa6;
#endif

  /*  Get the raw sockets first thing, so we can drop to user euid immediately  */

  if ( ( net_preopen_result = net_preopen () ) ) {
    fprintf( stderr, "mtr: unable to get raw sockets.\n" );
    exit( EXIT_FAILURE );
  }

  /*  Now drop to user permissions  */
  if (setgid(getgid()) || setuid(getuid())) {
    fprintf (stderr, "mtr: Unable to drop permissions.\n");
    exit(1);
  }

  /*  Double check, just in case  */
  if ((geteuid() != getuid()) || (getegid() != getgid())) {
    fprintf (stderr, "mtr: Unable to drop permissions.\n");
    exit(1);
  }

  /* reset the random seed */
  srand (getpid());

  display_detect(&argc, &argv);
  display_mode = 0;

  /* The field options are now in a static array all together,
     but that requires a run-time initialization. */
  init_fld_options ();

  parse_mtr_options (getenv ("MTR_OPTIONS"));

  parse_arg (argc, argv);

  while (optind < argc) {
    char* name = argv[optind++];
    append_to_names(argv[0], name);
  }

  /* Now that we know mtrtype we can select which socket to use */
  if (net_selectsocket() != 0) {
    fprintf( stderr, "mtr: Couldn't determine raw socket type.\n" );
    exit( EXIT_FAILURE );
  }

  if (PrintVersion) {
    printf ("mtr " MTR_VERSION "\n");
    exit(0);
  }

  if (PrintHelp) {
       printf("usage: %s [--help] [--version] [-4|-6] [-F FILENAME]\n"
              "\t\t[--report] [--report-wide] [--displaymode MODE]\n"
              "\t\t[--xml] [--gtk] [--curses] [--raw] [--csv] [--split]\n"
              "\t\t[--no-dns] [--show-ips] [-o FIELDS] [-y IPINFO] [--aslookup]\n"
              "\t\t[-i INTERVAL] [-c COUNT] [-s PACKETSIZE] [-B BITPATTERN]\n"
              "\t\t[-Q TOS] [--mpls]\n"
              "\t\t[-a ADDRESS] [-f FIRST-TTL] [-m MAX-TTL] [-U MAX_UNKNOWN]\n"
              "\t\t[--udp] [--tcp] [--sctp] [-P PORT] [-L LOCALPORT] [-Z TIMEOUT]\n"
              "\t\t[-G GRACEPERIOD] [-M MARK] HOSTNAME\n", argv[0]);
       printf("See the man page for details.\n");
    exit(0);
  }

  time_t now = time(NULL);

  if (!names) append_to_names (argv[0], "localhost"); // default: localhost. 

  names_t* head = names;
  while (names != NULL) {

    Hostname = names->name;
    //  if (Hostname == NULL) Hostname = "localhost"; // no longer necessary.
    if (gethostname(LocalHostname, sizeof(LocalHostname))) {
      strcpy(LocalHostname, "UNKNOWNHOST");
    }

    if (net_preopen_result != 0) {
      fprintf(stderr, "mtr: Unable to get raw socket.  (Executable not suid?)\n");
      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }

#ifdef ENABLE_IPV6
    /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */
    bzero( &hints, sizeof hints );
    hints.ai_family = af;
    hints.ai_socktype = SOCK_DGRAM;
    error = getaddrinfo( Hostname, NULL, &hints, &res );
    if ( error ) {
      if (error == EAI_SYSTEM)
         perror ("Failed to resolve host");
      else
         fprintf (stderr, "Failed to resolve host: %s\n", gai_strerror(error));

      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }
    /* Convert the first addrinfo into a hostent. */
    host = &trhost;
    bzero( host, sizeof trhost );
    host->h_name = res->ai_canonname;
    host->h_aliases = NULL;
    host->h_addrtype = res->ai_family;
    af = res->ai_family;
    host->h_length = res->ai_addrlen;
    host->h_addr_list = alptr;
    switch ( af ) {
    case AF_INET:
      sa4 = (struct sockaddr_in *) res->ai_addr;
      alptr[0] = (void *) &(sa4->sin_addr);
      break;
    case AF_INET6:
      sa6 = (struct sockaddr_in6 *) res->ai_addr;
      alptr[0] = (void *) &(sa6->sin6_addr);
      break;
    default:
      fprintf( stderr, "mtr unknown address type\n" );
      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }
    alptr[1] = NULL;
#else
      host = gethostbyname(Hostname);
    if (host == NULL) {
      herror("mtr gethostbyname");
      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }
    af = host->h_addrtype;
#endif

    if (net_open(host) != 0) {
      fprintf(stderr, "mtr: Unable to start net module.\n");
      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }

    if (net_set_interfaceaddress (InterfaceAddress) != 0) {
      fprintf( stderr, "mtr: Couldn't set interface address.\n" );
      if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE);
      else {
        names = names->next;
        continue;
      }
    }


    lock(argv[0], stdout);
      display_open();
      dns_open();

      display_loop();

      net_end_transit();
      display_close(now);
    unlock(argv[0], stdout);

    if ( DisplayMode != DisplayCSV ) break;
    else names = names->next;

  }

  net_close();

  while (head != NULL) {
    names_t* item = head;
    free(item->name); item->name = NULL;
    head = head->next;
    free(item); item = NULL;
  }
  head=NULL;

  return 0;
}
Exemple #18
0
// private mode (--private-home=list):
// 	mount homedir on top of /home/user,
// 	tmpfs on top of  /root in nonroot mode,
// 	tmpfs on top of /tmp in root mode,
// 	set skel files,
// 	restore .Xauthority
void fs_private_home_list(void) {
	char *homedir = cfg.homedir;
	char *private_list = cfg.home_private_keep;
	assert(homedir);
	assert(private_list);
	
	int xflag = store_xauthority();
	
	uid_t u = getuid();
	gid_t g = getgid();
	struct stat s;
	if (stat(homedir, &s) == -1) {
		fprintf(stderr, "Error: cannot find user home directory\n");
		exit(1);
	}

	// create /tmp/firejail/mnt/home directory
	fs_build_mnt_dir();
	int rv = mkdir(HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
	if (rv == -1)
		errExit("mkdir");
	if (chown(HOME_DIR, u, g) < 0)
		errExit("chown");
	if (chmod(HOME_DIR, 0755) < 0)
		errExit("chmod");
	
	// copy the list of files in the new home directory
	// using a new child process without root privileges
	pid_t child = fork();
	if (child < 0)
		errExit("fork");
	if (child == 0) {
		if (arg_debug)
			printf("Copying files in the new home:\n");
		
		// drop privileges
		if (setgroups(0, NULL) < 0)
			errExit("setgroups");
		if (setgid(getgid()) < 0)
			errExit("setgid/getgid");
		if (setuid(getuid()) < 0)
			errExit("setuid/getuid");
		
		// copy the list of files in the new home directory
		char *dlist = strdup(cfg.home_private_keep);
		if (!dlist)
			errExit("strdup");
	
		char *ptr = strtok(dlist, ",");
		duplicate(ptr);
	
		while ((ptr = strtok(NULL, ",")) != NULL)
			duplicate(ptr);
		free(dlist);	
		exit(0);
	}
	// wait for the child to finish
	waitpid(child, NULL, 0);

	// mount bind private_homedir on top of homedir
	char *newhome;
	if (asprintf(&newhome, "%s%s", HOME_DIR, cfg.homedir) == -1)
		errExit("asprintf");

	if (arg_debug)
		printf("Mount-bind %s on top of %s\n", newhome, homedir);
	if (mount(newhome, homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
		errExit("mount bind");
// preserve mode and ownership
//	if (chown(homedir, s.st_uid, s.st_gid) == -1)
//		errExit("mount-bind chown");
//	if (chmod(homedir, s.st_mode) == -1)
//		errExit("mount-bind chmod");

	if (u != 0) {
		// mask /root
		if (arg_debug)
			printf("Mounting a new /root directory\n");
		if (mount("tmpfs", "/root", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=700,gid=0") < 0)
			errExit("mounting home directory");
	}
	else {
		// mask /home
		if (arg_debug)
			printf("Mounting a new /home directory\n");
		if (mount("tmpfs", "/home", "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME | MS_REC,  "mode=755,gid=0") < 0)
			errExit("mounting home directory");
	}

	skel(homedir, u, g);
	if (xflag)
		copy_xauthority();

}
Exemple #19
0
void UserTable::OnEvent(InotifyEvent& rEvt)
{
    InotifyWatch* pW = rEvt.GetWatch();
    InCronTabEntry* pE = FindEntry(pW);

    if (pE == NULL)
        return;

    std::string cmd;
    const std::string& cs = pE->GetCmd();
    size_t pos = 0;
    size_t oldpos = 0;
    size_t len = cs.length();
    while ((pos = cs.find('$', oldpos)) != std::string::npos) {
        if (pos < len - 1) {
            size_t px = pos + 1;
            if (cs[px] == '$') {
                cmd.append(cs.substr(oldpos, pos-oldpos+1));
                oldpos = pos + 2;
            }
            else if (cs[px] == '@') {
                cmd.append(cs.substr(oldpos, pos-oldpos));
                cmd.append(pW->GetPath());
                oldpos = pos + 2;
            }
            else if (cs[px] == '#') {
                cmd.append(cs.substr(oldpos, pos-oldpos));
                cmd.append(rEvt.GetName());
                oldpos = pos + 2;
            }
            else {
                cmd.append(cs.substr(oldpos, pos-oldpos));
                oldpos = pos + 1;
            }
        }
        else {
            cmd.append(cs.substr(oldpos, pos-oldpos));
            oldpos = pos + 1;
        }
    }
    cmd.append(cs.substr(oldpos));

    int argc;
    char** argv;
    if (!PrepareArgs(cmd, argc, argv)) {
        syslog(LOG_ERR, "cannot prepare command arguments");
        return;
    }

    syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());

    pid_t pid = fork();
    if (pid == 0) {

        struct passwd* pwd = getpwnam(m_user.c_str());
        if (pwd == NULL)
            _exit(1);

        if (setuid(pwd->pw_uid) != 0)
            _exit(1);

        if (execvp(argv[0], argv) != 0) {
            _exit(1);
        }
    }
    else if (pid > 0) {

    }
    else {
        syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
    }
}
Exemple #20
0
static void drop_privileges(struct credentials *cred)
{
	if (cred && (initgroups(cred->pass->pw_name, cred->gid) ||
	    setgid (cred->gid) || setuid(cred->pass->pw_uid)))
		die("cannot drop privileges");
}
Exemple #21
0
FILE *Popen(char * const parameters[], const char *type)
{
  FILE *iop;

  struct pid *cur;
  int pdes[2], pid;

  if (parameters == NULL || type == NULL)
  {
    return NULL;
  }

  if ((*type != 'r' && *type != 'w') || type[1])
  {
    return NULL;
  }

  if ((cur = (struct pid *) malloc(sizeof(struct pid))) == NULL)
  {
    return NULL;
  }

  if (pipe(pdes) < 0)
  {
    free(cur);

    return NULL;
  }

  //
  // Block all signals until command is exited.
  // We need to gather information about the
  // child in Pclose().
  //

  DisableSignals();

  switch (pid = Fork())
  {
    case -1:
    {
      //
      // Error.
      //

      #ifdef PANIC
      *logofs << "Popen: PANIC! Function fork failed. "
              << "Error is " << EGET() << " '" << ESTR()
              << "'.\n" << logofs_flush;
      #endif

      cerr << "Error" << ": Function fork failed. "
           << "Error is " << EGET() << " '" << ESTR()
           << "'.\n";

      close(pdes[0]);
      close(pdes[1]);

      free(cur);

      return NULL;
    }
    case 0:
    {
      //
      // Child.
      //

      setgid(getgid());
      setuid(getuid());

      if (*type == 'r')
      {
        if (pdes[1] != 1)
        {
          //
          // Set up stdout.
          //

          dup2(pdes[1], 1);
          close(pdes[1]);
        }

        close(pdes[0]);
      }
      else
      {
        if (pdes[0] != 0)
        {
          //
          // Set up stdin.
          //

          dup2(pdes[0], 0);
          close(pdes[0]);
        }

        close(pdes[1]);
      }

      execvp(parameters[0], parameters + 1);

      exit(127);
    }
  }

  //
  // Parent. Save data about the child.
  //

  RegisterChild(pid);

  if (*type == 'r')
  {
    iop = fdopen(pdes[0], type);

    close(pdes[1]);
  }
  else
  {
    iop = fdopen(pdes[1], type);

    close(pdes[0]);
  }

  cur -> fp = iop;
  cur -> self = pid;
  cur -> next = pidlist;

  pidlist = cur;

  #ifdef TEST
  *logofs << "Popen: Executing ";

  for (int i = 0; i < 256 && parameters[i] != NULL; i++)
  {
    *logofs << "[" << parameters[i] << "]";
  }

  *logofs << " with descriptor " << fileno(iop)
          << ".\n" << logofs_flush;
  #endif

  return iop;
}
Exemple #22
0
int daemon_AuthUserPwd(char *username, char *password, char *errbuf)
{
#ifdef WIN32
	/*
		Warning: the user which launches the process must have the SE_TCB_NAME right.
		This corresponds to have the "Act as part of the Operating System" turined on
		(administrative tools, local security settings, local policies, user right assignment)
		However, it seems to me that if you run it as a service, this right should be
		provided by default.
	*/
	HANDLE Token;
	if (LogonUser(username, ".", password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &Token) == 0)
	{
	int error;

		error = GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
			PCAP_ERRBUF_SIZE, NULL);

		return -1;
	}

	// This call should change the current thread to the selected user.
	// I didn't test it.
	if (ImpersonateLoggedOnUser(Token) == 0)
	{
	int error;

		error = GetLastError();
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, errbuf,
			PCAP_ERRBUF_SIZE, NULL);

		return -1;
	}

	return 0;

#else
/*	Standard user authentication:
		http://www.unixpapa.com/incnote/passwd.html
	Problem: it is not able to merge the standard pwd file with the shadow one

	Shadow user authentication:
		http://www.tldp.org/HOWTO/Shadow-Password-HOWTO-8.html
	Problem: the program must either (1) run as root, or (2) run as user, but it
	must be owned by root and must be SUID root (chmod u+s rpcapd)
*/

	struct passwd *user;
	struct spwd *usersp;

	// This call is needed to get the uid
	if ((user= getpwnam(username)) == NULL)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
		return -1;
	}

	// This call is needed to get the password; otherwise 'x' is returned
	if ((usersp= getspnam(username)) == NULL)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: no such user");
		return -1;
	}
	
	if (strcmp(usersp->sp_pwdp, (char *) crypt(password, usersp->sp_pwdp) ) != 0)
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "Authentication failed: password incorrect");
		return -1;
	}

	if (setuid(user->pw_uid) )
	{
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
		return -1;
	}

/*	if (setgid(user->pw_gid) )
	{
		SOCK_ASSERT("setgid failed", 1);
		snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s", pcap_strerror(errno) );
		return -1;
	}
*/
	return 0;

#endif

}
Exemple #23
0
int
main(int argc, char **argv)
{

#ifdef HAVE_LIBPAM
    int    retcode = 0;
    const char * const * env;
#endif
#ifdef USE_SETE_ID
    struct passwd *pass;
#endif

    memset(buf, 0, sizeof(buf));
    memset(file, 0, sizeof(file));

    if (strrchr(argv[0],'/')==NULL) prog_name = argv[0];
    else prog_name = strrchr(argv[0],'/')+1;
    
    uid = getuid();

    /* get current dir */
    if ( getcwd(orig_dir, sizeof(orig_dir)) == NULL )
	die_e("getcwd");

    /* interpret command line options */
    parseopt(argc, argv);

#ifdef USE_SETE_ID
    if ( ! (pass = getpwnam(USERNAME)) )
	die("user \"%s\" is not in passwd file. Aborting.", USERNAME);
    fcrontab_uid = pass->pw_uid;
    fcrontab_gid = pass->pw_gid;

#ifdef HAVE_LIBPAM
    /* Open PAM session for the user and obtain any security
       credentials we might need */

    debug("username: %s", user);
    retcode = pam_start("fcrontab", user, &apamconv, &pamh);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not start PAM");
    retcode = pam_authenticate(pamh, 0);    /* is user really user? */
    if (retcode != PAM_SUCCESS)
	die_pame(pamh, retcode, "Could not authenticate user using PAM (%d)", retcode);
    retcode = pam_acct_mgmt(pamh, 0); /* permitted access? */
    if (retcode != PAM_SUCCESS)
	die_pame(pamh, retcode, "Could not init PAM account management (%d)", retcode);
    retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not set PAM credentials");
    retcode = pam_open_session(pamh, 0);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not open PAM session");

    env = (const char * const *) pam_getenvlist(pamh);
    while (env && *env) {
	if (putenv((char*) *env)) die_e("Could not copy PAM environment");
	env++;
    }

    /* Close the log here, because PAM calls openlog(3) and
       our log messages could go to the wrong facility */
    xcloselog();
#endif /* USE_PAM */

    if (uid != fcrontab_uid)
	if (seteuid(fcrontab_uid) != 0) 
	    die_e("Couldn't change euid to fcrontab_uid[%d]",fcrontab_uid);
    /* change directory */
    if (chdir(fcrontabs) != 0) {
	error_e("Could not chdir to %s", fcrontabs);
	xexit (EXIT_ERR);
    }
    /* get user's permissions */
    if (seteuid(uid) != 0) 
	die_e("Could not change euid to %d", uid); 
    if (setegid(fcrontab_gid) != 0) 
	die_e("Could not change egid to " GROUPNAME "[%d]", fcrontab_gid); 

#else /* USE_SETE_ID */

    if (setuid(ROOTUID) != 0 ) 
	die_e("Could not change uid to ROOTUID"); 
    if (setgid(ROOTGID) != 0)
    	die_e("Could not change gid to ROOTGID");
    /* change directory */
    if (chdir(fcrontabs) != 0) {
	error_e("Could not chdir to %s", fcrontabs);
	xexit (EXIT_ERR);
    }
#endif /* USE_SETE_ID */
    
    /* this program is seteuid : we set default permission mode
     * to 640 for a normal user, 600 for root, for security reasons */
    if ( asuid == ROOTUID )
	umask(066);  /* octal : '0' + number in octal notation */
    else
	umask(026);

    snprintf(buf, sizeof(buf), "%s.orig", user);

    /* determine what action should be taken */
    if ( file_opt ) {

	if ( strcmp(argv[file_opt], "-") == 0 )

	    xexit(install_stdin());

	else {

	    if ( *argv[file_opt] != '/' )
		/* this is just the file name, not the path : complete it */
		snprintf(file, sizeof(file), "%s/%s", orig_dir, argv[file_opt]);
	    else {
		strncpy(file, argv[file_opt], sizeof(file) - 1);
		file[sizeof(file)-1] = '\0';
	    }

	    if (make_file(file) == OK)
		xexit(EXIT_OK);
	    else
		xexit(EXIT_ERR);

	}

    } 

    /* remove user's entries */
    if ( rm_opt == 1 ) {
	if ( remove_fcrontab(1) == ENOENT )
	    fprintf(stderr, "no fcrontab for %s\n", user);
	xexit (EXIT_OK);
    }

    /* list user's entries */
    if ( list_opt == 1 ) {
	list_file(buf);
	xexit(EXIT_OK);
    }


    /* edit user's entries */
    if ( edit_opt == 1 ) {
	edit_file(buf);
	xexit(EXIT_OK);
    }

    /* reinstall user's entries */
    if ( reinstall_opt == 1 ) {
	reinstall(buf);
	xexit(EXIT_OK);
    }

    /* never reached */
    return EXIT_OK;
}
Exemple #24
0
static void uv__process_child_init(const uv_process_options_t* options,
                                   int stdio_count,
                                   int (*pipes)[2],
                                   int error_fd) {
  int close_fd;
  int use_fd;
  int fd;

  if (options->flags & UV_PROCESS_DETACHED)
    setsid();

  /* First duplicate low numbered fds, since it's not safe to duplicate them,
   * they could get replaced. Example: swapping stdout and stderr; without
   * this fd 2 (stderr) would be duplicated into fd 1, thus making both
   * stdout and stderr go to the same fd, which was not the intention. */
  for (fd = 0; fd < stdio_count; fd++) {
    use_fd = pipes[fd][1];
    if (use_fd < 0 || use_fd >= fd)
      continue;
    pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
    if (pipes[fd][1] == -1) {
      uv__write_int(error_fd, -errno);
      _exit(127);
    }
  }

  for (fd = 0; fd < stdio_count; fd++) {
    close_fd = pipes[fd][0];
    use_fd = pipes[fd][1];

    if (use_fd < 0) {
      if (fd >= 3)
        continue;
      else {
        /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
         * set
         */
        use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
        close_fd = use_fd;

        if (use_fd == -1) {
          uv__write_int(error_fd, -errno);
          _exit(127);
        }
      }
    }

    if (fd == use_fd)
      uv__cloexec(use_fd, 0);
    else
      fd = dup2(use_fd, fd);

    if (fd == -1) {
      uv__write_int(error_fd, -errno);
      _exit(127);
    }

    if (fd <= 2)
      uv__nonblock(fd, 0);

    if (close_fd >= stdio_count)
      uv__close(close_fd);
  }

  for (fd = 0; fd < stdio_count; fd++) {
    use_fd = pipes[fd][1];

    if (use_fd >= stdio_count)
      uv__close(use_fd);
  }

  if (options->cwd != NULL && chdir(options->cwd)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
    /* When dropping privileges from root, the `setgroups` call will
     * remove any extraneous groups. If we don't call this, then
     * even though our uid has dropped, we may still have groups
     * that enable us to do super-user things. This will fail if we
     * aren't root, so don't bother checking the return value, this
     * is just done as an optimistic privilege dropping function.
     */
    SAVE_ERRNO(setgroups(0, NULL));
  }

  if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
    uv__write_int(error_fd, -errno);
    _exit(127);
  }

  if (options->env != NULL) {
    environ = options->env;
  }

  execvp(options->file, options->args);
  uv__write_int(error_fd, -errno);
  _exit(127);
}
Exemple #25
0
void selfCheck() {
    // 'access' function tests based on uid, 'eaccess' ignores ACLs, have to set uid/gid.
    setgid(xware_gid);
    setuid(xware_uid); // uid after gid, otherwise fail on setting gid.

    if (verbose_mode) {
        printf("# [DEBUG] uid=%d, euid=%d, xware_uid=%d\n", getuid(), geteuid(), xware_uid);
    }
    // check uid
    if (getuid() != xware_uid) {
        fprintf(stderr, "Not running as xware user.\n");
        exit(EXIT_FAILURE);
    }

    // check euid
    if (geteuid() != xware_uid) {
        fprintf(stderr, "Not running as xware user.\n");
        exit(EXIT_FAILURE);
    }


    if (verbose_mode) {
        printf("# [DEBUG] gid=%d, egid=%d, xware_gid=%d\n", getgid(), getegid(), xware_gid);
    }
    // check gid
    if (getgid() != xware_gid) {
        fprintf(stderr, "Not running as xware group.\n");
        exit(EXIT_FAILURE);
    }
    // check egid
    if (getegid() != xware_gid) {
        fprintf(stderr, "Not running as xware group.\n");
        exit(EXIT_FAILURE);
    }

    // check supplementary groups
    nGrpList2 = getgroups(NGROUPS_MAX, grpList2);
    if (nGrpList2 == -1) {
        perror("getgroups");
        exit(EXIT_FAILURE);
    }
    if (verbose_mode) {
        printf("# [DEBUG] xware is a member of: ");
        int i = 0;
        for (i = 0; i < nGrpList1; i++) {
            printf("%d\t", grpList1[i]);
        }
        printf("\n");

        printf("# [DEBUG] post-setgroups, calling process groups: ");
        for (i = 0; i < nGrpList2; i++) {
            printf("%d\t", grpList2[i]);
        }
        printf("\n");
    }
    if ( (nGrpList1 != nGrpList2) ||
         (memcmp(grpList1, grpList2, nGrpList2 * sizeof(gid_t)) != 0)) {
        fprintf(stderr, "Failed to clear supplementary groups.\n");
        exit(EXIT_FAILURE);
    }
}
Exemple #26
0
void
slap_init_user( char *user, char *group )
{
    uid_t	uid = 0;
    gid_t	gid = 0;
    int		got_uid = 0, got_gid = 0;

    if ( user ) {
	struct passwd *pwd;
	if ( isdigit( (unsigned char) *user ) ) {
	    unsigned u;

	    got_uid = 1;
	    if ( lutil_atou( &u, user ) != 0 ) {
		Debug( LDAP_DEBUG_ANY, "Unble to parse user %s\n",
		       user, 0, 0 );

		exit( EXIT_FAILURE );
	    }
	    uid = (uid_t)u;
#ifdef HAVE_GETPWUID
	    pwd = getpwuid( uid );
	    goto did_getpw;
#else
	    free( user );
	    user = NULL;
#endif
	} else {
	    pwd = getpwnam( user );
	did_getpw:
	    if ( pwd == NULL ) {
		Debug( LDAP_DEBUG_ANY, "No passwd entry for user %s\n",
		       user, 0, 0 );

		exit( EXIT_FAILURE );
	    }
	    if ( got_uid ) {
		free( user );
		user = (pwd != NULL ? ch_strdup( pwd->pw_name ) : NULL);
	    } else {
		got_uid = 1;
		uid = pwd->pw_uid;
	    }
	    got_gid = 1;
	    gid = pwd->pw_gid;
#ifdef HAVE_ENDPWENT
	    endpwent();
#endif
	}
    }

    if ( group ) {
	struct group *grp;
	if ( isdigit( (unsigned char) *group )) {
	    unsigned g;

	    if ( lutil_atou( &g, group ) != 0 ) {
		Debug( LDAP_DEBUG_ANY, "Unble to parse group %s\n",
		       group, 0, 0 );

		exit( EXIT_FAILURE );
	    }
	    gid = (uid_t)g;
#ifdef HAVE_GETGRGID
	    grp = getgrgid( gid );
	    goto did_group;
#endif
	} else {
	    grp = getgrnam( group );
	    if ( grp != NULL )
		gid = grp->gr_gid;
	did_group:
	    if ( grp == NULL ) {
		Debug( LDAP_DEBUG_ANY, "No group entry for group %s\n",
		       group, 0, 0 );

		exit( EXIT_FAILURE );
	    }
	}
	free( group );
	got_gid = 1;
    }

    if ( user ) {
	if ( getuid() == 0 && initgroups( user, gid ) != 0 ) {
	    Debug( LDAP_DEBUG_ANY,
		   "Could not set the group access (gid) list\n", 0, 0, 0 );

	    exit( EXIT_FAILURE );
	}
	free( user );
    }

#ifdef HAVE_ENDGRENT
    endgrent();
#endif

    if ( got_gid ) {
	if ( setgid( gid ) != 0 ) {
	    Debug( LDAP_DEBUG_ANY, "Could not set real group id to %d\n",
		       (int) gid, 0, 0 );

	    exit( EXIT_FAILURE );
	}
#ifdef HAVE_SETEGID
	if ( setegid( gid ) != 0 ) {
	    Debug( LDAP_DEBUG_ANY, "Could not set effective group id to %d\n",
		       (int) gid, 0, 0 );

	    exit( EXIT_FAILURE );
	}
#endif
    }

    if ( got_uid ) {
	if ( setuid( uid ) != 0 ) {
	    Debug( LDAP_DEBUG_ANY, "Could not set real user id to %d\n",
		       (int) uid, 0, 0 );

	    exit( EXIT_FAILURE );
	}
#ifdef HAVE_SETEUID
	if ( seteuid( uid ) != 0 ) {
	    Debug( LDAP_DEBUG_ANY, "Could not set effective user id to %d\n",
		       (int) uid, 0, 0 );

	    exit( EXIT_FAILURE );
	}
#endif
    }
}
Exemple #27
0
/*
 * setuid() and setgid() for a specified user.
 */
int run_as(const char *user)
{
#ifndef __MINGW32__
    if (user[0])
    {
#ifdef HAVE_GETPWNAM_R
        struct passwd pwdbuf, *pwd;
        size_t buflen;
        int err;

        for (buflen = 128;; buflen *= 2)
        {
            char buf[buflen];  /* variable length array */

            /* Note that we use getpwnam_r() instead of getpwnam(),
               which returns its result in a statically allocated buffer and
               cannot be considered thread safe. */
            err = getpwnam_r(user, &pwdbuf, buf, buflen, &pwd);
            if(err == 0 && pwd)
            {
                /* setgid first, because we may not be allowed to do it anymore after setuid */
                if (setgid(pwd->pw_gid) != 0)
                {
                    LOGE("Could not change group id to that of run_as user '%s': %s",
                         user,strerror(errno));
                    return 0;
                }

                if (setuid(pwd->pw_uid) != 0)
                {
                    LOGE("Could not change user id to that of run_as user '%s': %s",
                         user,strerror(errno));
                    return 0;
                }
                break;
            }
            else if (err != ERANGE)
            {
                if(err)
                    LOGE("run_as user '%s' could not be found: %s",user,strerror(err));
                else
                    LOGE("run_as user '%s' could not be found.",user);
                return 0;
            }
            else if (buflen >= 16*1024)
            {
                /* If getpwnam_r() seems defective, call it quits rather than
                   keep on allocating ever larger buffers until we crash. */
                LOGE("getpwnam_r() requires more than %u bytes of buffer space.",(unsigned)buflen);
                return 0;
            }
            /* Else try again with larger buffer. */
        }
#else
        /* No getpwnam_r() :-(  We'll use getpwnam() and hope for the best. */
        struct passwd *pwd;

        if (!(pwd=getpwnam(user)))
        {
            LOGE("run_as user %s could not be found.",user);
            return 0;
        }
        /* setgid first, because we may not allowed to do it anymore after setuid */
        if (setgid(pwd->pw_gid) != 0)
        {
            LOGE("Could not change group id to that of run_as user '%s': %s",
                 user,strerror(errno));
            return 0;
        }
        if (setuid(pwd->pw_uid) != 0)
        {
            LOGE("Could not change user id to that of run_as user '%s': %s",
                 user,strerror(errno));
            return 0;
        }
#endif
    }

#endif //__MINGW32__
    return 1;
}
Exemple #28
0
int main(int argc, char* argv[])
{
// When starting Dr Konqi via kdeinit4, Apple OS X aborts us unconditionally for
// using setgid/setuid, even if the privs were those of the logged-in user.
// Drop privs.
    setgid(getgid());
    if (setuid(getuid()) < 0 && geteuid() != getuid()) {
        exit(255);
    }

    // Prevent KApplication from setting the crash handler. We will set it later...
    setenv("KDE_DEBUG", "true", 1);
    // Session management is not needed, do not even connect in order to survive longer than ksmserver.
    unsetenv("SESSION_MANAGER");

    KAboutData aboutData("drkonqi", 0, ki18n("The KDE Crash Handler"),
                         version, ki18n(description),
                         KAboutData::License_GPL,
                         ki18n("(C) 2000-2009, The DrKonqi Authors"));
    aboutData.addAuthor(ki18nc("@info:credit","Hans Petter Bieker"), KLocalizedString(),
                         "*****@*****.**");
    aboutData.addAuthor(ki18nc("@info:credit","Dario Andres Rodriguez"), KLocalizedString(),
                         "*****@*****.**");
    aboutData.addAuthor(ki18nc("@info:credit","George Kiagiadakis"), KLocalizedString(),
                         "*****@*****.**");
    aboutData.addAuthor(ki18nc("@info:credit","A. L. Spehr"), KLocalizedString(),
                         "*****@*****.**");
    aboutData.setProgramIconName("tools-report-bug");

    KCmdLineArgs::init(argc, argv, &aboutData);

    KCmdLineOptions options;
    options.add("signal <number>", ki18nc("@info:shell","The signal number that was caught"));
    options.add("appname <name>", ki18nc("@info:shell","Name of the program"));
    options.add("apppath <path>", ki18nc("@info:shell","Path to the executable"));
    options.add("appversion <version>", ki18nc("@info:shell","The version of the program"));
    options.add("bugaddress <address>", ki18nc("@info:shell","The bug address to use"));
    options.add("programname <name>", ki18nc("@info:shell","Translated name of the program"));
    options.add("pid <pid>", ki18nc("@info:shell","The PID of the program"));
    options.add("startupid <id>", ki18nc("@info:shell","Startup ID of the program"));
    options.add("kdeinit", ki18nc("@info:shell","The program was started by kdeinit"));
    options.add("safer", ki18nc("@info:shell","Disable arbitrary disk access"));
    options.add("restarted", ki18nc("@info:shell","The program has already been restarted"));
    options.add("keeprunning", ki18nc("@info:shell","Keep the program running and generate "
                                                    "the backtrace at startup"));
    options.add("thread <threadid>", ki18nc("@info:shell","The thread id of the failing thread"));
    KCmdLineArgs::addCmdLineOptions(options);

    KComponentData inst(KCmdLineArgs::aboutData());
    QApplication *qa =
        KCmdLineArgs::parsedArgs()->isSet("safer") ?
        new QApplication(KCmdLineArgs::qtArgc(), KCmdLineArgs::qtArgv()) :
        new KApplication;
    qa->setApplicationName(inst.componentName());

    if (!DrKonqi::init()) {
        delete qa;
        return 1;
    }

    qa->setQuitOnLastWindowClosed(false);
    KGlobal::setAllowQuit(true);

    DrKonqiDialog *w = new DrKonqiDialog();
    w->show();
    // Make sure the Dr Konqi dialog comes to the front, whatever the platform
    // or window manager, but especially on Apple OS X.
    w->raise();
    int ret = qa->exec();

    DrKonqi::cleanup();
    delete qa;
    return ret;
}
Exemple #29
0
int
main(const int argc, char * const argv[])
/*@globals environ, errno@*/
/*@modifies environ, errno@*/
{
    struct passwd *pw;
    char **target_env = environ;
    static char *empty_env[] = { NULL };
    environ = empty_env;
    (void) umask(~(mode_t)0);  /* (no file perms, if signalled to dump core)*/

    /* check that calling UID exists, is not root, and shell matches */
    if (NULL != (pw = getpwuid(getuid()))
	&& 0 != pw->pw_uid
	&& 0 == memcmp(pw->pw_shell,CHROOTING_SHELL,sizeof(CHROOTING_SHELL)) ) {

	/* require commands of the form: "sh" "-c" "command args args args" */
	if (3 == argc && 0 == memcmp(argv[1], "-c", 3)) {
	    const char *chroot_dir = (const char *)pw->pw_dir;
	    const char *home = "/";
	    struct stat st;
	    if (0 == memcmp(pw->pw_dir, GROUP_CHROOT_DIR,
			    sizeof(GROUP_CHROOT_DIR)-1)
		&& getgroups(0, (gid_t *)NULL) > 1) {
		chroot_dir = GROUP_CHROOT_DIR;
		home = (const char *)pw->pw_dir+(sizeof(GROUP_CHROOT_DIR)-2);
		if (*home != '/' && *++home != '/') {
		    home = "/";
		}
	    }
	    if (!(   0 == stat(chroot_dir, &st)
		  && pw->pw_uid != st.st_uid  /* (not caller; typically root) */
		  && 0 == (st.st_mode & (S_IWGRP|S_IWOTH)))) {
		fatal(argc, pw, chroot_dir);
	    }
	    openlog("chressh", LOG_NDELAY|LOG_PID, LOG_AUTHPRIV);
	    if (/*@-superuser@*/
		   0 == chroot(chroot_dir)
		/*@=superuser@*/
		&& 0 == setuid(getuid())
		&& 0 != setuid(0)
		&& 0 == chdir(home)) {

		char **target_argv;
		size_t len;
		errno = 0;  /* (reset errno after expected setuid(0) failure) */

		environ = target_env = env_clean(target_env, pw, home);
		target_argv = shell_parse(argv[2]);
		if (NULL == target_argv || NULL == target_argv[0]) {
		    fatal(argc, pw, NULL);
		}
		(void) umask((mode_t)UMASK);

		if (0 == strcmp(target_argv[0], "scp")) {
		    if (0 == set_limits(NPROC_SCP)) {
			(void) execve(CHROOTED_CMD_DIR "scp",
				      target_argv, target_env);
		    }
		}
		else if (0 == strcmp(target_argv[0], "rsync")) {
		    if (0 == filter_args_rsync(target_argv)
			&& 0 == set_limits(NPROC_RSYNC)) {
			(void) execve(CHROOTED_CMD_DIR "rsync",
				      target_argv, target_env);
		    }
		}
		else if (0 == strcmp(target_argv[0], "unison")) {
		    if (0 == filter_args_unison(target_argv)
			&& 0 == set_limits(NPROC_UNISON)) {
			(void) execve(CHROOTED_CMD_DIR "unison",
				      target_argv, target_env);
		    }
		}
		else {
		    if (  11 <= (len = strlen(target_argv[0]))
			&& 0 == memcmp(target_argv[0]+len-11, "sftp-server", 11)
			&& 0 == set_limits(NPROC_SFTP_SERVER)) {
			/*('chressh -c /usr/local/libexec/sftp-server')*/
			/*(only tests for "sftp-server" suffix, which is fine)*/
			/*(discard additional args to sftp-server, if present)*/
			char sftp_server[] = "sftp-server";
			char *target_argv_static[] = { sftp_server, NULL };
			(void) execve(CHROOTED_CMD_DIR "sftp-server",
				      target_argv_static, target_env);
		    }
		}


#if 0  /* which code do you think is clearer?  above or below? */

		switch ((len = strlen(target_argv[0]))) {
		  case  3:
		    if (0 == memcmp(target_argv[0], "scp", 3)
			&& 0 == set_limits(NPROC_SCP)) {
			(void) execve(CHROOTED_CMD_DIR "scp",
				      target_argv, target_env);
		    }
		    break;
		  case  5:
		    if (0 == memcmp(target_argv[0], "rsync", 5)
			&& 0 == filter_args_rsync(target_argv)
			&& 0 == set_limits(NPROC_RSYNC)) {
			(void) execve(CHROOTED_CMD_DIR "rsync",
				      target_argv, target_env);
		    }
		    break;
		  case  6:
		    if (0 == memcmp(target_argv[0], "unison", 6)
			&& 0 == filter_args_unison(target_argv)
			&& 0 == set_limits(NPROC_UNISON)) {
			(void) execve(CHROOTED_CMD_DIR "unison",
				      target_argv, target_env);
		    }
		    break;
		  default:
		    if (  11 <= len
			&& 0 == memcmp(target_argv[0]+len-11, "sftp-server", 11)
			&& 0 == set_limits(NPROC_SFTP_SERVER)) {
			/*('chressh -c /usr/local/libexec/sftp-server')*/
			/*(only tests for "sftp-server" suffix, which is fine)*/
			/*(discard additional args to sftp-server, if present)*/
			char sftp_server[] = "sftp-server";
			char *target_argv_static[] = { sftp_server, NULL };
			(void) execve(CHROOTED_CMD_DIR "sftp-server",
				      target_argv_static, target_env);
		    }
		    break;
		}
#endif


	    }
	}

      #ifdef PASSWD_PROGRAM
	/* If login attempt (argc == 1), use PASSWD_PROGRAM as 'shell'
	 * (*argv[0] == '-', too, for login shells on most (all?) systems)
	 * (privileges intentionally dropped even if passwd_program setuid)
	 */
	else if (1 == argc && 0 == setuid(getuid()) && 0 != setuid(0)) {
	    char passwd_program[] = PASSWD_PROGRAM;
	    char *target_argv[] = { passwd_program, NULL };
	    errno = 0;  /* (reset errno after expected setuid(0) failure) */
	    target_env = env_clean(target_env, pw, NULL);
	    (void) execve(PASSWD_PROGRAM, target_argv, target_env);
	}
      #endif

    }

    fatal(argc, pw, NULL);
    return 0; /*(UNREACHED)*/
}
Exemple #30
0
extern int slurm_ckpt_signal_tasks(stepd_step_rec_t *job, char *image_dir)
{
	char *argv[4];
	char context_file[MAXPATHLEN];
	char pid[16];
	int status;
	pid_t *children = NULL;
	int *fd = NULL;
	int rc = SLURM_SUCCESS;
	int i;
	char c;

	debug3("checkpoint/blcr: slurm_ckpt_signal_tasks: image_dir=%s",
	       image_dir);
	/*
	 * the tasks must be checkpointed concurrently.
	 */
	children = xmalloc(sizeof(pid_t) * job->node_tasks);
	fd = xmalloc(sizeof(int) * 2 * job->node_tasks);
	if (!children || !fd) {
		error("slurm_ckpt_signal_tasks: memory exhausted");
		rc = SLURM_FAILURE;
		goto out;
	}
	for (i = 0; i < job->node_tasks; i ++) {
		fd[i*2] = -1;
		fd[i*2+1] = -1;
	}

	for (i = 0; i < job->node_tasks; i ++) {
		if (job->batch) {
			sprintf(context_file, "%s/script.ckpt", image_dir);
		} else {
			sprintf(context_file, "%s/task.%d.ckpt",
				image_dir, job->task[i]->gtid);
		}
		sprintf(pid, "%u", (unsigned int)job->task[i]->pid);

		if (pipe(&fd[i*2]) < 0) {
			error("failed to create pipes: %m");
			rc = SLURM_ERROR;
			goto out_wait;
		}

		children[i] = fork();
		if (children[i] < 0) {
			error("error forking cr_checkpoint");
			rc = SLURM_ERROR;
			goto out_wait;
		} else if (children[i] == 0) {
			close(fd[i*2+1]);

			while(read(fd[i*2], &c, 1) < 0 && errno == EINTR);
			if (c)
				exit(-1);

			/* change cred to job owner */
			if (setgid(job->gid) < 0) {
				error ("checkpoint/blcr: "
				       "slurm_ckpt_signal_tasks: "
				       "failed to setgid: %m");
				exit(errno);
			}
			if (setuid(job->uid) < 0) {
				error ("checkpoint/blcr: "
				       "slurm_ckpt_signal_tasks: "
				       "failed to setuid: %m");
				exit(errno);
			}
			if (chdir(job->cwd) < 0) {
				error ("checkpoint/blcr: "
				       "slurm_ckpt_signal_tasks: "
				       "failed to chdir: %m");
				exit(errno);
			}

			argv[0] = (char *)cr_checkpoint_path;
			argv[1] = pid;
			argv[2] = context_file;
			argv[3] = NULL;

			execv(argv[0], argv);
			exit(errno);
		}
		close(fd[i*2]);
	}

 out_wait:
	c = (rc == SLURM_SUCCESS) ? 0 : 1;
	for (i = 0; i < job->node_tasks; i ++) {
		if (fd[i*2+1] >= 0) {
			while(write(fd[i*2+1], &c, 1) < 0 && errno == EINTR);
		}
	}
	/* wait children in sequence is OK */
	for (i = 0; i < job->node_tasks; i ++) {
		if (children[i] == 0)
			continue;
		while(waitpid(children[i], &status, 0) < 0 && errno == EINTR);
		if (! (WIFEXITED(status) && WEXITSTATUS(status))== 0)
			rc = SLURM_ERROR;
	}
 out:
	xfree(children);
	xfree(fd);

	return rc;
}