示例#1
0
static int give_capabilities (pid_t pid)
{
	cap_t caps = cap_init();
	const unsigned caps_size = 4;
	cap_value_t cap_list[] =
		{ CAP_SETPCAP, CAP_SYS_NICE, CAP_SYS_RESOURCE, CAP_IPC_LOCK} ;

	if (caps == NULL) {
		fprintf (stderr, "jackstart: could not allocate capability working storage\n");
		return -1;
	}
	cap_clear(caps);
	if (capgetp (pid, caps)) {
		fprintf (stderr, "jackstart: could not get capabilities for process %d\n", pid);
		cap_clear(caps);
	}
	cap_set_flag(caps, CAP_EFFECTIVE, caps_size, cap_list , CAP_SET);
	cap_set_flag(caps, CAP_INHERITABLE, caps_size, cap_list , CAP_SET);
	cap_set_flag(caps, CAP_PERMITTED, caps_size, cap_list , CAP_SET);
	if (capsetp (pid, caps)) {
		fprintf (stderr, "jackstart: could not give capabilities: %s\n", strerror (errno));
		cap_free (caps);
		return -1;
	}
	cap_free (caps);
	return 0;
}
示例#2
0
static int check_capabilities (void)
{
	cap_t caps = cap_init();
	cap_flag_value_t cap;
	pid_t pid;
	int have_all_caps = 1;

	if (caps == NULL) {
		fprintf (stderr, "jackstart: could not allocate capability working storage\n");
		return 0;
	}
	pid = getpid ();
	cap_clear (caps);
	if (capgetp (pid, caps)) {
		fprintf (stderr, "jackstart: could not get capabilities for process %d\n", pid);
		return 0;
	}
	/* check that we are able to give capabilites to other processes */
	cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &cap);
	if (cap == CAP_CLEAR) {
		have_all_caps = 0;
		goto done;
	}
	/* check that we have the capabilities we want to transfer */
	cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &cap);
	if (cap == CAP_CLEAR) {
		have_all_caps = 0;
		goto done;
	}
	cap_get_flag(caps, CAP_SYS_RESOURCE, CAP_EFFECTIVE, &cap);
	if (cap == CAP_CLEAR) {
		have_all_caps = 0;
		goto done;
	}
	cap_get_flag(caps, CAP_IPC_LOCK, CAP_EFFECTIVE, &cap);
	if (cap == CAP_CLEAR) {
		have_all_caps = 0;
		goto done;
	}
  done:
	cap_free (caps);
	return have_all_caps;
}
示例#3
0
int main(int argc, char **argv)
{
    cap_t old_caps;
    uid_t uid;
    pid_t pid, parent_pid;
    gid_t gid;
    int pipe_fds[2];

    /* this program should not be made setuid-0 */
    if (getuid() && !geteuid()) {
        usage();
    }

    /* check that we have at least 3 arguments */
    if (argc < 4) {
        usage();
    }

    /* Convert username to uid */
    {
	struct passwd *pw = getpwnam(argv[1]);
	if (!pw) {
	    fprintf(stderr, "sucap: No such user: %s\n", argv[1]);
	    exit(1);
	}
	uid = pw->pw_uid;
    }

    /* Convert groupname to gid */
    {
	struct group *gr = getgrnam(argv[2]);
	if (!gr) {
	    fprintf(stderr, "sucap: No such group: %s\n", argv[2]);
	    exit(1);
	}
	gid = gr->gr_gid;
    }
    
    /* set process group to current pid */
    if (setpgid(0, getpid())) {
	perror("sucap: Failed to set process group");
	exit(1);
    }
    
    if (pipe(pipe_fds)) {
	perror("sucap: pipe() failed");
	exit(1);
    }
    
    parent_pid = getpid();

    old_caps = cap_init();
    if (capgetp(0, old_caps)) {
	perror("sucap: capgetp");
	exit(1);
    }
    
    {
	ssize_t x;
	printf("Caps: %s\n", cap_to_text(old_caps, &x));
    }


    /* fork off a child to do the hard work */
    fflush(NULL);
    pid = fork();
    if (pid == -1) {
	perror("sucap: fork failed");
	exit(1);
    }

    /* 1. mother process sets gid and uid
     * 2. child process sets capabilities of mother process
     * 3. mother process execs whatever is to be executed
     */

    if (pid) {
	/* Mother process. */
	close(pipe_fds[0]);

	/* Get rid of any supplemental groups */
	if (!getuid() && setgroups(0, 0)) {
	    perror("sucap: setgroups failed");
	    exit(1);
	}

	/* Set gid and uid (this probably clears capabilities) */
	setregid(gid, gid);
	setreuid(uid, uid);

	{
	    ssize_t x;
	    cap_t cap = cap_init();
	    capgetp(0, cap);
	    printf("Caps: %s\n", cap_to_text(cap, &x));
	}
	
	printf("[debug] uid:%d, real uid:%d\n", geteuid(), getuid());

	/* Signal child that we want our privileges updated */
	close(pipe_fds[1]); /* Child hangs in blocking read */

	/* Wait for child process to set our privileges */
	{
	    int status = 0;
	    if (wait(&status) == -1) {
		perror("sucap: wait failed");
	    }
	    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
		fprintf(stderr, "sucap: child did not exit cleanly.\n");
		exit(1);
	    }
	}

	{
	    ssize_t x;
	    cap_t cap = cap_init();
	    capgetp(0, cap);
	    printf("Caps: %s\n", cap_to_text(cap, &x));
	}

/*	printf("[debug] uid:%d, real uid:%d\n", geteuid(), getuid()); */
	/* exec the program indicated by args 2 ... */
	execvp(argv[3], argv+3);
	
	/* if we fall through to here, our exec failed -- announce the fact */
	fprintf(stderr, "Unable to execute command: %s\n", strerror(errno));
	
	usage();
    } else {
	/* Child process */
	close(pipe_fds[1]);

	/* Wait for mother process to setuid */
	wait_on_fd(pipe_fds[0]);

	/* Set privileges on mother process */
	if (capsetp(parent_pid, old_caps)) {
	    perror("sucaps: capsetp");
	    _exit(1);
	}

	/* exit to signal mother process that we are ready */
	_exit(0);
    }

    return 0;
}
示例#4
0
int main(int argc, char **argv)
{
	uid_t uid, euid;
	pid_t pid, parent_pid;
	gid_t gid;
	int pipe_fds[2];
	int err;

	parent_pid = getpid ();

	/* get real user and group ids, effective user id */
	uid = getuid ();
	gid = getgid ();
	euid = geteuid ();

	/* are we running suid root? */
	if (uid != 0) {
		if (euid != 0) {
			fprintf (stderr, "jackstart: not running suid root, can't use capabilities\n");
			fprintf (stderr, "    (currently running with uid=%d and euid=%d),\n", uid, euid);
			fprintf (stderr, "    make jackstart suid root or start jackd directly\n\n");
		}
	}
	/* see if we can get the required capabilities */
	if (check_capabilities () == 0) {
		size_t size;
		cap_t cap = cap_init();
		capgetp(0, cap);
		fprintf (stderr, "jackstart: cannot get realtime capabilities, current capabilities are:\n");
		fprintf (stderr, "           %s\n", cap_to_text(cap, &size));
		fprintf (stderr, "    probably running under a kernel with capabilities disabled,\n");
		fprintf (stderr, "    a suitable kernel would have printed something like \"=eip\"\n\n");
	}

	/* check the executable, owner, permissions, md5 checksum */
	if (check_binary(jackd_bin_path)) {
		exit(1);
	}

	/* set process group to current pid */
	if (setpgid (0, getpid())) {
		fprintf (stderr, "jackstart: failed to set process group: %s\n", 
			 strerror(errno));
		exit (1);
	}

	/* create pipe to synchronize with jackd */
	if (pipe (pipe_fds)) {
		fprintf (stderr, "jackstart: could not create pipe: %s\n",
			 strerror(errno));
		exit (1);
	}

	/* make sure the file descriptors are the right ones,
	   otherwise dup them, this is to make sure that both
	   jackstart and jackd use the same fds
	*/
	if (pipe_fds[0] != PIPE_READ_FD) {
		if (dup2 (pipe_fds[0], PIPE_READ_FD) != PIPE_READ_FD) {
			fprintf (stderr, "jackstart: could not dup pipe read file descriptor: %s\n",
				 strerror(errno));
			exit (1);
		}
	}
	if (pipe_fds[1] != PIPE_WRITE_FD) {
		if (dup2(pipe_fds[1], PIPE_WRITE_FD)!=PIPE_WRITE_FD) {
			fprintf (stderr, "jackstart: could not dup pipe write file descriptor: %s\n",
				 strerror(errno));
			exit (1);
		}
	}
	/* fork off a child to wait for jackd to start */
	fflush(NULL);
	pid = fork();
	if (pid == -1) {
		fprintf (stderr, "jackstart: fork failed\n");
		exit (1);
	}
	if (pid) {
		/* mother process: drops privileges, execs jackd */
		close(PIPE_READ_FD);

		/* get rid of any supplemental groups */
		if (!getuid () && setgroups (0, 0)) {
			fprintf (stderr, "jackstart: setgroups failed: %s\n", strerror(errno));
			exit (1);
		}

		/* set gid and uid */
		setregid(gid, gid);
		setreuid(uid, uid);
		execvp(jackd_bin_path, argv);
	
		/* we could not start jackd, clean up and exit */
		fprintf(stderr, "jackstart: unable to execute %s: %s\n", jackd_bin_path, strerror(errno));
		close (PIPE_WRITE_FD);
		wait (&err);
		exit (1);
	} else {
		/* child process: grants privileges to jackd */
		close(PIPE_WRITE_FD);

		/* wait for jackd to start */
		while (1) {
		  	int ret;
			char c;

			/* picking up pipe closure is a tricky business. 
			   this seems to work as well as anything else.
			*/

			ret = read(PIPE_READ_FD, &c, 1);
			fprintf (stderr, "back from read, ret = %d errno == %s\n", ret, strerror (errno));
			if (ret == 1) {
			  break;
			} else if (errno != EINTR) {
			  break;
			}
		}

		/* set privileges on jackd process */
		give_capabilities (parent_pid);
	}
	exit (0);
}