summaryrefslogtreecommitdiff
path: root/progs/old/sucap.c
diff options
context:
space:
mode:
Diffstat (limited to 'progs/old/sucap.c')
-rw-r--r--progs/old/sucap.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/progs/old/sucap.c b/progs/old/sucap.c
new file mode 100644
index 0000000..366a093
--- /dev/null
+++ b/progs/old/sucap.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: sucap.c,v 1.1.1.1 1999/04/17 22:16:31 morgan Exp $
+ *
+ * This was written by Finn Arne Gangstad <finnag@guardian.no>
+ *
+ * This is a program that is intended to exec a subsequent program.
+ * The purpose of this 'sucap' wrapper is to change uid but keep all
+ * privileges. All environment variables are inherited.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdio.h>
+#undef _POSIX_SOURCE
+#include <sys/capability.h>
+#include <pwd.h>
+#define __USE_BSD
+#include <grp.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void usage(void)
+{
+ fprintf(stderr,
+"usage: sucap <user> <group> <command-path> [command-args...]\n\n"
+" This program is a wrapper that change UID but not privileges of a\n"
+" program to be executed.\n"
+" Note, this wrapper is intended to assist in overcoming a lack of support\n"
+" for filesystem capability attributes and should be used to launch other\n"
+" files. This program should _NOT_ be made setuid-0.\n\n"
+"[Copyright (c) 1998 Finn Arne Gangstad <finnag@guardian.no>]\n");
+
+ exit(1);
+}
+
+
+static void
+wait_on_fd(int fd)
+{
+ /* Wait until some data is available on a file descriptor, or until
+ * end of file or an error is detected */
+ char buf[1];
+ while (read(fd, buf, sizeof(buf)) == -1 && errno == EINTR) {
+ /* empty loop */
+ }
+}
+
+
+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;
+}