Beispiel #1
0
int
main(int argc, char *argv[])
{
	cap_t caps;
	pid_t pid;
	int r;

	/* Create child; child commences execution in childFunc() */
	printf("******* info of the parent process - start ********\n");
	caps = cap_get_proc();
	printf("Before unshare, the capabilities are:\n");
	printf("capabilities: %s\n", cap_to_text(caps, NULL));

	r = unshare(CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWNET | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER );
	if(r == -1) {
		printf("unshare failed: %s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}
	caps = cap_get_proc();
	printf("After unshare, the capabilities are:\n");
	printf("capabilities: %s\n", cap_to_text(caps, NULL));

	printf("the process pid is: %ld\n", (long)getpid());

	r = execlp("sh", "sh", (char *)0);
	if(r == -1) {
		printf("execlp failed: %s\n", strerror(errno));
		exit(EXIT_FAILURE);
	}
	exit(EXIT_SUCCESS);
}
int fork_drop_and_exec(int keepperms, cap_t expected_caps)
{

	int pid;
	int ret = 0;
	char buf[200], *p;
	char *capstxt;
	cap_t actual_caps;
	static int seqno;

	pid = fork();
	if (pid < 0)
		tst_brkm(TFAIL | TERRNO, NULL, "%s: failed fork\n", __func__);
	if (pid == 0) {
		drop_root(keepperms);
		print_my_caps();
		sprintf(buf, "%d", seqno);
		ret = execlp(TSTPATH, TSTPATH, buf, NULL);
		capstxt = cap_to_text(expected_caps, NULL);
		snprintf(buf, 200, "failed to run as %s\n", capstxt);
		cap_free(capstxt);
		write_to_fifo(buf);
		tst_brkm(TFAIL, NULL, "%s: exec failed\n", __func__);
	} else {
		p = buf;
		while (1) {
			int c, s;
			read_from_fifo(buf);
			c = sscanf(buf, "%d", &s);
			if (c == 1 && s == seqno)
				break;
			tst_resm(TINFO,
				 "got a bad seqno (c=%d, s=%d, seqno=%d)", c, s,
				 seqno);
		}
		p = index(buf, '.');
		if (!p)
			tst_brkm(TFAIL, NULL,
				 "got a bad message from print_caps\n");
		p += 1;
		actual_caps = cap_from_text(p);
		if (cap_compare(actual_caps, expected_caps) != 0) {
			capstxt = cap_to_text(expected_caps, NULL);
			tst_resm(TINFO,
				 "Expected to run as .%s., ran as .%s..\n",
				 capstxt, p);
			tst_resm(TINFO, "those are not the same\n");
			cap_free(capstxt);
			ret = -1;
		}
		cap_free(actual_caps);
		seqno++;
	}
	return ret;
}
Beispiel #3
0
/**
 * cap_restore:
 * @r: capability set saved by cap_save()
 *
 * Restore the set of current capabilities specified by @r.
 *
 * Returns: whether the operation was successful.
 **/
void
g_process_cap_restore(cap_t r)
{
  gboolean rc;

  if (!process_opts.caps)
    return;

  rc = cap_set_proc(r) != -1;
  cap_free(r);
  if (!rc)
    {
      gchar *cap_text;

      cap_text = cap_to_text(r, NULL);
      msg_error("Error managing capability set, cap_set_proc returned an error",
                evt_tag_str("caps", cap_text),
                evt_tag_errno("error", errno),
                NULL);
      cap_free(cap_text);
      return;
    }
  
  return;
}
Beispiel #4
0
static PyObject *
strcaps_get_file(PyObject *self, PyObject *args) { // (int) fd / (str) path / (file) file
	PyObject *file;
	if (!PyArg_ParseTuple(args, "O", &file)) return NULL;
	cap_t caps;
	if (PyFile_Check(file)) caps = cap_get_fd(PyObject_AsFileDescriptor(file));
	else if (PyInt_Check(file)) caps = cap_get_fd(PyInt_AsLong(file));
	else if (PyString_Check(file)) caps = cap_get_file(PyString_AsString(file));
	else if (PyUnicode_Check(file)) {
		PyObject *file_dec = PyUnicode_AsEncodedString(
			file, Py_FileSystemDefaultEncoding, "strict" );
		if (file_dec == NULL) return NULL;
		caps = cap_get_file(PyString_AsString(file_dec));
		Py_DECREF(file_dec); }
	else {
		PyErr_SetString( PyExc_TypeError,
			"Expecting file object, descriptor int or path string" );
		return NULL; }
	size_t strcaps_len; char *strcaps;
	if (caps == NULL) {
		if (errno == ENODATA) { strcaps = "\0"; strcaps_len = 0; }
		else {
			PyErr_SetFromErrno(PyExc_OSError);
			return NULL; } }
	else strcaps = cap_to_text(caps, &strcaps_len);
	cap_free(caps);
	return Py_BuildValue("s#", strcaps, strcaps_len); }; // (str) caps
Beispiel #5
0
int main(int argc, char *argv[])
{
#ifdef HAVE_LIBCAP
	cap_t cap = cap_get_proc();
	int fd;
	int seqno = 0;
	char buf[2000];

	if (argc > 1)
		seqno = atoi(argv[1]);

	if (!cap) {
		perror("print_caps - cap_get_proc");
		exit(1);
	}

	fd = open(FIFOFILE, O_WRONLY);
	if (!fd) {
		perror("print_caps: open fifo");
		exit(2);
	}

	snprintf(buf, 2000, "%d.%s", seqno, cap_to_text(cap, NULL));
	write(fd, buf, strlen(buf)+1);
	close(fd);

	cap_free(cap);
#endif
	return 0;
}
Beispiel #6
0
Datei: cap.c Projekt: AMDmi3/zsh
static int
bin_cap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
{
    int ret = 0;
    cap_t caps;
    if(*argv) {
	unmetafy(*argv, NULL);
	caps = cap_from_text(*argv);
	if(!caps) {
	    zwarnnam(nam, "invalid capability string");
	    return 1;
	}
	if(cap_set_proc(caps)) {
	    zwarnnam(nam, "can't change capabilities: %e", errno);
	    ret = 1;
	}
    } else {
	char *result = NULL;
	ssize_t length;
	caps = cap_get_proc();
	if(caps)
	    result = cap_to_text(caps, &length);
	if(!caps || !result) {
	    zwarnnam(nam, "can't get capabilities: %e", errno);
	    ret = 1;
	} else
	    puts(result);
    }
    cap_free(caps);
    return ret;
}
Beispiel #7
0
void debug_print_caps(char *when)
{
	char buf[2000];
	tst_resm(TINFO, "%s", when);
	snprintf(buf, 2000, "%s", cap_to_text(cap_get_proc(), NULL));
	tst_resm(TINFO, "%s", buf);
}
void print_my_caps()
{
	cap_t cap = cap_get_proc();
	char *txt = cap_to_text(cap, NULL);
	tst_resm(TINFO, "\ncaps are %s\n", txt);
	cap_free(cap);
	cap_free(txt);
}
Beispiel #9
0
static void lower_my_caps(void)
{
	struct __user_cap_header_struct caphdr = {
		.version = _LINUX_CAPABILITY_VERSION
	};
	cap_user_data_t capdata;
	ssize_t capstrlen = 0;
	cap_t my_cap;
	char *cap_text;
	int capsz;

	(void) capget(&caphdr, NULL);
	switch (caphdr.version) {
	case _LINUX_CAPABILITY_VERSION_1:
		capsz = _LINUX_CAPABILITY_U32S_1;
		break;
	case _LINUX_CAPABILITY_VERSION_2:
		capsz = _LINUX_CAPABILITY_U32S_2;
		break;
	default:
		abort(); /* can't happen */
	}

	capdata = gsh_calloc(capsz, sizeof(struct __user_cap_data_struct));
	caphdr.pid = getpid();

	if (capget(&caphdr, capdata) != 0)
		LogFatal(COMPONENT_INIT,
			 "Failed to query capabilities for process, errno=%u",
			 errno);

	/* Set the capability bitmask to remove CAP_SYS_RESOURCE */
	if (capdata->effective & CAP_TO_MASK(CAP_SYS_RESOURCE))
		capdata->effective &= ~CAP_TO_MASK(CAP_SYS_RESOURCE);

	if (capdata->permitted & CAP_TO_MASK(CAP_SYS_RESOURCE))
		capdata->permitted &= ~CAP_TO_MASK(CAP_SYS_RESOURCE);

	if (capdata->inheritable & CAP_TO_MASK(CAP_SYS_RESOURCE))
		capdata->inheritable &= ~CAP_TO_MASK(CAP_SYS_RESOURCE);

	if (capset(&caphdr, capdata) != 0)
		LogFatal(COMPONENT_INIT,
			 "Failed to set capabilities for process, errno=%u",
			 errno);
	else
		LogEvent(COMPONENT_INIT,
			 "CAP_SYS_RESOURCE was successfully removed for proper quota management in FSAL");

	/* Print newly set capabilities (same as what CLI "getpcaps" displays */
	my_cap = cap_get_proc();
	cap_text = cap_to_text(my_cap, &capstrlen);
	LogEvent(COMPONENT_INIT, "currenty set capabilities are: %s",
		 cap_text);
	cap_free(cap_text);
	cap_free(my_cap);
	gsh_free(capdata);
}
Beispiel #10
0
static EVTTAG *
evt_tag_cap_t(const char *tag, cap_t cap)
{
  gchar *cap_text = cap_to_text(cap, NULL);
  EVTTAG *evt_tag = evt_tag_str(tag, cap_text);

  cap_free(cap_text);

  return evt_tag;
}
Beispiel #11
0
static void
display_creds_and_caps(char *msg)
{
    cap_t caps;

    printf("%seUID = %ld;  eGID = %ld;  ", msg,
            (long) geteuid(), (long) getegid());

    caps = cap_get_proc();
    printf("capabilities: %s\n", cap_to_text(caps, NULL));
}
void *chg_uid_gid(void *arg)
{
	cap_t newcaps;
	cap_t mycaps;
	int ret;

	test_msg("Aux thread runs as UID: %d; GID: %d\n", getuid(), getgid());

	newcaps = cap_from_text("cap_setgid,cap_setuid=+eip");
	if (!newcaps) {
		pr_perror("Failed to get capability struct\n");
		exit(1);
	}

	ret = cap_set_proc(newcaps);
	if (ret) {
		pr_perror("Failed to set capabilities for the process\n");
		exit(1);
	}

	mycaps = cap_get_proc();
	if (!mycaps) {
		pr_perror("Failed to get child thread capabilities\n");
		exit_group(2);
	}

	test_msg("Child capabilities: %s\n", cap_to_text(mycaps, NULL));
	test_msg("Changing UID/GID in child thread to %d:%d\n", uid, gid);

	ret = syscall(SYS_setresgid, gid, gid, gid);
	if (ret >= 0) {
		syscall(SYS_setresuid, uid, uid, uid);
	} else if (ret < 0) {
		pr_perror("Failed to change UID/GID\n");
		exit_group(2);
	}

	gid = getgid();
	uid = getuid();
	test_msg("Now aux thread runs as UID: %d; GID: %d\n", uid, gid);

	test_msg("Child thread is waiting for main thread's signal\n");
	task_waiter_complete(&t, 1);

	pthread_mutex_lock(&mutex);
	while (!done) {
		pthread_cond_wait(&cond, &mutex);
	}
	pthread_mutex_unlock(&mutex);

	test_msg("Child thread returns\n");
	return NULL;
}
Beispiel #13
0
static int child_exec(void *stuff) {
  cap_t caps;
  printf("eUID=%ld; eGID=%ld; ", (long)geteuid(), (long)getegid());
  caps = cap_get_proc();
  printf("capabilities: %s\n", cap_to_text(caps, NULL));
  struct clone_args *args = (struct clone_args *)stuff;
  if (execvp(args->argv[0], args->argv) != 0) {
    fprintf(stderr, "failed to execvp argments %d\n", strerror(errno));
    exit(-1);
  }
  // We should never reach here!
  exit(-1);
}
Beispiel #14
0
static void show_capabilities(void) {
        cap_t caps;
        char *text;

        caps = cap_get_proc();
        assert_se(caps);

        text = cap_to_text(caps, NULL);
        assert_se(text);

        log_info("Capabilities:%s", text);
        cap_free(caps);
        cap_free(text);
}
Beispiel #15
0
static
void dropCapability(cap_value_t capability)
{
    cap_t caps;
    cap_value_t cap_list[] = { capability };

    caps = cap_get_proc();
    if (caps == nullptr)
    {
        Log::error("Error: cap_get_proc() failed.");
        std::exit(1);
    }

    char *capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities first: " + std::string(capText));
    cap_free(capText);

    if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 ||
        cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1)
    {
        Log::error("Error: cap_set_flag() failed.");
        std::exit(1);
    }

    if (cap_set_proc(caps) == -1)
    {
        Log::error("Error: cap_set_proc() failed.");
        std::exit(1);
    }

    capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities now: " + std::string(capText));
    cap_free(capText);

    cap_free(caps);
}
Beispiel #16
0
static PyObject *
strcaps_get_process(PyObject *self, PyObject *args) { // (int) pid or None
	int pid = 0;
	if (!PyArg_ParseTuple(args, "|i", &pid)) return NULL;
	cap_t caps;
	if (!pid) caps = cap_get_proc();
	else caps = cap_get_pid(pid);
	size_t strcaps_len; char *strcaps;
	if (caps == NULL) {
		if (errno == ENODATA) { strcaps = "\0"; strcaps_len = 0; }
		else {
			PyErr_SetFromErrno(PyExc_OSError);
			return NULL; } }
	else strcaps = cap_to_text(caps, &strcaps_len);
	cap_free(caps);
	return Py_BuildValue("s#", strcaps, strcaps_len); }; // (str) caps
Beispiel #17
0
/**
 * g_process_cap_modify:
 * @capability: capability to turn off or on
 * @onoff: specifies whether the capability should be enabled or disabled
 *
 * This function modifies the current permitted set of capabilities by
 * enabling or disabling the capability specified in @capability.
 *
 * Returns: whether the operation was successful.
 **/
gboolean 
g_process_cap_modify(int capability, int onoff)
{
  cap_t caps;

  if (!process_opts.caps)
    return TRUE;

  /*
   * if libcap or kernel doesn't support cap_syslog, then resort to
   * cap_sys_admin
   */
  if (capability == CAP_SYSLOG && (!have_capsyslog || CAP_SYSLOG == -1))
    capability = CAP_SYS_ADMIN;

  caps = cap_get_proc();
  if (!caps)
    return FALSE;

  if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &capability, onoff) == -1)
    {
      msg_error("Error managing capability set, cap_set_flag returned an error",
                evt_tag_errno("error", errno),
                NULL);
      cap_free(caps);
      return FALSE;
    }

  if (cap_set_proc(caps) == -1)
    {
      gchar *cap_text;

      cap_text = cap_to_text(caps, NULL);
      msg_error("Error managing capability set, cap_set_proc returned an error",
                evt_tag_str("caps", cap_text),
                evt_tag_errno("error", errno),
                NULL);
      cap_free(cap_text);
      cap_free(caps);
      return FALSE;
    }
  cap_free(caps);
  return TRUE;
}
Beispiel #18
0
static int                      /* Startup function for cloned child */
childFunc(void *arg)
{
    cap_t caps;

    for (;;) {
        printf("eUID = %ld; eGID = %ld; ",
                (long) geteuid(), (long) getegid());

        caps = cap_get_proc();
        printf("capabilities: %s\n", cap_to_text(caps, NULL));

        if (arg == NULL)
            break;

        sleep(5);
    }

    return 0;
}
Beispiel #19
0
static PyObject *
pycap_get_proc(PyObject *self, PyObject *noargs) {
    char *cap_str;
    cap_t cap;
    ssize_t cap_str_len;

    if ((cap = cap_get_proc()) == NULL) {
        PyErr_SetFromErrno(PyExc_OSError);
        return NULL;
    }

    if ((cap_str = cap_to_text(cap, &cap_str_len)) == NULL) {
        PyErr_SetFromErrno(PyExc_OSError);
        cap_free(cap);
        return NULL;
    }
    cap_free(cap);

    return PyString_FromStringAndSize(cap_str, cap_str_len);
}
Beispiel #20
0
Datei: cap.c Projekt: AMDmi3/zsh
static int
bin_getcap(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
{
    int ret = 0;

    do {
	char *result = NULL;
	ssize_t length;
	cap_t caps;

	caps = cap_get_file(unmetafy(dupstring(*argv), NULL));
	if(caps)
	    result = cap_to_text(caps, &length);
	if (!caps || !result) {
	    zwarnnam(nam, "%s: %e", *argv, errno);
	    ret = 1;
	} else
	    printf("%s %s\n", *argv, result);
	cap_free(caps);
    } while(*++argv);
    return ret;
}
Beispiel #21
0
char *
do_cap_get_file (const char *path)
{
  cap_t cap;
  char *r, *ret;

  CHROOT_IN;
  cap = cap_get_file (path);
  CHROOT_OUT;

  if (cap == NULL) {
    reply_with_perror ("%s", path);
    return NULL;
  }

  r = cap_to_text (cap, NULL);
  if (r == NULL) {
    reply_with_perror ("cap_to_text");
    cap_free (cap);
    return NULL;
  }

  cap_free (cap);

  /* 'r' is not an ordinary pointer that can be freed with free(3)!
   * In the current implementation of libcap, if you try to do that it
   * will segfault.  We have to duplicate this into an ordinary
   * buffer, then call cap_free (r).
   */
  ret = strdup (r);
  if (ret == NULL) {
    reply_with_perror ("strdup");
    cap_free (r);
    return NULL;
  }
  cap_free (r);

  return ret;                   /* caller frees */
}
Beispiel #22
0
int main(int, char **)
{
    cap_t cap = cap_get_proc();
    const char *text = cap_to_text(cap, 0);
    return 0;
}
Beispiel #23
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);
}
Beispiel #24
0
static
void dropCapability(
#ifdef __linux
                    cap_value_t capability
#endif
                    )
{
#ifdef __linux
    cap_t caps;
    cap_value_t cap_list[] = { capability };

    caps = cap_get_proc();
    if (caps == nullptr)
    {
        Log::error("Error: cap_get_proc() failed.");
        exit(1);
    }

    if (cap_set_flag(caps, CAP_EFFECTIVE, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1 ||
        cap_set_flag(caps, CAP_PERMITTED, sizeof(cap_list)/sizeof(cap_list[0]), cap_list, CAP_CLEAR) == -1)
    {
        Log::error("Error: cap_set_flag() failed.");
        exit(1);
    }

    if (cap_set_proc(caps) == -1)
    {
        Log::error("Error: cap_set_proc() failed.");
        exit(1);
    }

    char *capText = cap_to_text(caps, nullptr);
    Log::info("Capabilities now: " + std::string(capText));
    cap_free(capText);

    cap_free(caps);
#endif
    // We assume that on non-Linux we don't need to be root to be able to hardlink to files we
    // don't own, so drop root.
    if (geteuid() == 0 && getuid() != 0)
    {
        // The program is setuid root. Not normal on Linux where we use setcap, but if this
        // needs to run on non-Linux Unixes, setuid root is what it will bneed to be to be able
        // to do chroot().
        if (setuid(getuid()) != 0)
        {
            Log::error("Error: setuid() failed.");
        }
    }
#if ENABLE_DEBUG
    if (geteuid() == 0 && getuid() == 0)
    {
#ifdef __linux
        // Argh, awful hack
        if (capability == CAP_FOWNER)
            return;
#endif

        // Running under sudo, probably because being debugged? Let's drop super-user rights.
        if (uid == 0)
        {
            struct passwd *nobody = getpwnam("nobody");
            if (nobody)
                uid = nobody->pw_uid;
            else
                uid = 65534;
        }
        if (setuid(uid) != 0)
        {
            Log::error("setuid() failed.");
        }
    }
#endif
}
Beispiel #25
0
int main(int argc, char *argv[], char *envp[])
{
    pid_t child;
    unsigned i;

    child = 0;

    for (i=1; i<argc; ++i) {
	if (!memcmp("--drop=", argv[i], 4)) {
	    char *ptr;
	    cap_t orig, raised_for_setpcap;

	    /*
	     * We need to do this here because --inh=XXX may have reset
	     * orig and it isn't until we are within the --drop code that
	     * we know what the prevailing (orig) pI value is.
	     */
	    orig = cap_get_proc();
	    if (orig == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    raised_for_setpcap = cap_dup(orig);
	    if (raised_for_setpcap == NULL) {
		fprintf(stderr, "BSET modification requires CAP_SETPCAP\n");
		exit(1);
	    }

	    if (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
			     raise_setpcap, CAP_SET) != 0) {
		perror("unable to select CAP_SETPCAP");
		exit(1);
	    }

	    if (strcmp("all", argv[i]+7) == 0) {
		unsigned j = 0;
		while (CAP_IS_SUPPORTED(j)) {
		    if (cap_drop_bound(j) != 0) {
			char *name_ptr;

			name_ptr = cap_to_name(j);
			fprintf(stderr,
				"Unable to drop bounding capability [%s]\n",
				name_ptr);
			cap_free(name_ptr);
			exit(1);
		    }
		    j++;
		}
	    } else {
		for (ptr = argv[i]+7; (ptr = strtok(ptr, ",")); ptr = NULL) {
		    /* find name for token */
		    cap_value_t cap;
		    int status;

		    if (cap_from_name(ptr, &cap) != 0) {
			fprintf(stderr,
				"capability [%s] is unknown to libcap\n",
				ptr);
			exit(1);
		    }
		    if (cap_set_proc(raised_for_setpcap) != 0) {
			perror("unable to raise CAP_SETPCAP for BSET changes");
			exit(1);
		    }
		    status = prctl(PR_CAPBSET_DROP, cap);
		    if (cap_set_proc(orig) != 0) {
			perror("unable to lower CAP_SETPCAP post BSET change");
			exit(1);
		    }
		    if (status) {
			fprintf(stderr, "failed to drop [%s=%u]\n", ptr, cap);
			exit(1);
		    }
		}
	    }
	    cap_free(raised_for_setpcap);
	    cap_free(orig);
	} else if (!memcmp("--inh=", argv[i], 6)) {
	    cap_t all, raised_for_setpcap;
	    char *text;
	    char *ptr;

	    all = cap_get_proc();
	    if (all == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }
	    if (cap_clear_flag(all, CAP_INHERITABLE) != 0) {
		perror("libcap:cap_clear_flag() internal error");
		exit(1);
	    }

	    raised_for_setpcap = cap_dup(all);
	    if ((raised_for_setpcap != NULL)
		&& (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
				 raise_setpcap, CAP_SET) != 0)) {
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    text = cap_to_text(all, NULL);
	    cap_free(all);
	    if (text == NULL) {
		perror("Fatal error concerning process capabilities");
		exit(1);
	    }
	    ptr = malloc(10 + strlen(argv[i]+6) + strlen(text));
	    if (ptr == NULL) {
		perror("Out of memory for inh set");
		exit(1);
	    }
	    if (argv[i][6] && strcmp("none", argv[i]+6)) {
		sprintf(ptr, "%s %s+i", text, argv[i]+6);
	    } else {
		strcpy(ptr, text);
	    }

	    all = cap_from_text(ptr);
	    if (all == NULL) {
		perror("Fatal error internalizing capabilities");
		exit(1);
	    }
	    cap_free(text);
	    free(ptr);

	    if (raised_for_setpcap != NULL) {
		/*
		 * This is only for the case that pP does not contain
		 * the requested change to pI.. Failing here is not
		 * indicative of the cap_set_proc(all) failing (always).
		 */
		(void) cap_set_proc(raised_for_setpcap);
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    if (cap_set_proc(all) != 0) {
		perror("Unable to set inheritable capabilities");
		exit(1);
	    }
	    /*
	     * Since status is based on orig, we don't want to restore
	     * the previous value of 'all' again here!
	     */

	    cap_free(all);
	} else if (!memcmp("--caps=", argv[i], 7)) {
	    cap_t all, raised_for_setpcap;

	    raised_for_setpcap = cap_get_proc();
	    if (raised_for_setpcap == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    if ((raised_for_setpcap != NULL)
		&& (cap_set_flag(raised_for_setpcap, CAP_EFFECTIVE, 1,
				 raise_setpcap, CAP_SET) != 0)) {
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    all = cap_from_text(argv[i]+7);
	    if (all == NULL) {
		fprintf(stderr, "unable to interpret [%s]\n", argv[i]);
		exit(1);
	    }

	    if (raised_for_setpcap != NULL) {
		/*
		 * This is only for the case that pP does not contain
		 * the requested change to pI.. Failing here is not
		 * indicative of the cap_set_proc(all) failing (always).
		 */
		(void) cap_set_proc(raised_for_setpcap);
		cap_free(raised_for_setpcap);
		raised_for_setpcap = NULL;
	    }

	    if (cap_set_proc(all) != 0) {
		fprintf(stderr, "Unable to set capabilities [%s]\n", argv[i]);
		exit(1);
	    }
	    /*
	     * Since status is based on orig, we don't want to restore
	     * the previous value of 'all' again here!
	     */

	    cap_free(all);
	} else if (!memcmp("--keep=", argv[i], 7)) {
	    unsigned value;
	    int set;

	    value = strtoul(argv[i]+7, NULL, 0);
	    set = prctl(PR_SET_KEEPCAPS, value);
	    if (set < 0) {
		fprintf(stderr, "prctl(PR_SET_KEEPCAPS, %u) failed: %s\n",
			value, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--chroot=", argv[i], 9)) {
	    int status;
	    cap_t orig, raised_for_chroot;

	    orig = cap_get_proc();
	    if (orig == NULL) {
		perror("Capabilities not available");
		exit(1);
	    }

	    raised_for_chroot = cap_dup(orig);
	    if (raised_for_chroot == NULL) {
		perror("Unable to duplicate capabilities");
		exit(1);
	    }

	    if (cap_set_flag(raised_for_chroot, CAP_EFFECTIVE, 1, raise_chroot,
			     CAP_SET) != 0) {
		perror("unable to select CAP_SET_SYS_CHROOT");
		exit(1);
	    }

	    if (cap_set_proc(raised_for_chroot) != 0) {
		perror("unable to raise CAP_SYS_CHROOT");
		exit(1);
	    }
	    cap_free(raised_for_chroot);

	    status = chroot(argv[i]+9);
	    if (cap_set_proc(orig) != 0) {
		perror("unable to lower CAP_SYS_CHROOT");
		exit(1);
	    }
	    /*
	     * Given we are now in a new directory tree, its good practice
	     * to start off in a sane location
	     */
	    status = chdir("/");

	    cap_free(orig);

	    if (status != 0) {
		fprintf(stderr, "Unable to chroot/chdir to [%s]", argv[i]+9);
		exit(1);
	    }
	} else if (!memcmp("--secbits=", argv[i], 10)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+10, NULL, 0);
	    status = prctl(PR_SET_SECUREBITS, value);
	    if (status < 0) {
		fprintf(stderr, "failed to set securebits to 0%o/0x%x\n",
			value, value);
		exit(1);
	    }
	} else if (!memcmp("--forkfor=", argv[i], 10)) {
	    unsigned value;

	    value = strtoul(argv[i]+10, NULL, 0);
	    if (value == 0) {
		goto usage;
	    }
	    child = fork();
	    if (child < 0) {
		perror("unable to fork()");
	    } else if (!child) {
		sleep(value);
		exit(0);
	    }
	} else if (!memcmp("--killit=", argv[i], 9)) {
	    int retval, status;
	    pid_t result;
	    unsigned value;

	    value = strtoul(argv[i]+9, NULL, 0);
	    if (!child) {
		fprintf(stderr, "no forked process to kill\n");
		exit(1);
	    }
	    retval = kill(child, value);
	    if (retval != 0) {
		perror("Unable to kill child process");
		exit(1);
	    }
	    result = waitpid(child, &status, 0);
	    if (result != child) {
		fprintf(stderr, "waitpid didn't match child: %u != %u\n",
			child, result);
		exit(1);
	    }
	    if (WTERMSIG(status) != value) {
		fprintf(stderr, "child terminated with odd signal (%d != %d)\n"
			, value, WTERMSIG(status));
		exit(1);
	    }
	} else if (!memcmp("--uid=", argv[i], 6)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+6, NULL, 0);
	    status = setuid(value);
	    if (status < 0) {
		fprintf(stderr, "Failed to set uid=%u: %s\n",
			value, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--gid=", argv[i], 6)) {
	    unsigned value;
	    int status;

	    value = strtoul(argv[i]+6, NULL, 0);
	    status = setgid(value);
	    if (status < 0) {
		fprintf(stderr, "Failed to set gid=%u: %s\n",
			value, strerror(errno));
		exit(1);
	    }
        } else if (!memcmp("--groups=", argv[i], 9)) {
	  char *ptr, *buf;
	  long length, max_groups;
	  gid_t *group_list;
	  int g_count;

	  length = sysconf(_SC_GETGR_R_SIZE_MAX);
	  buf = calloc(1, length);
	  if (NULL == buf) {
	    fprintf(stderr, "No memory for [%s] operation\n", argv[i]);
	    exit(1);
	  }

	  max_groups = sysconf(_SC_NGROUPS_MAX);
	  group_list = calloc(max_groups, sizeof(gid_t));
	  if (NULL == group_list) {
	    fprintf(stderr, "No memory for gid list\n");
	    exit(1);
	  }

	  g_count = 0;
	  for (ptr = argv[i] + 9; (ptr = strtok(ptr, ","));
	       ptr = NULL, g_count++) {
	    if (max_groups <= g_count) {
	      fprintf(stderr, "Too many groups specified (%d)\n", g_count);
	      exit(1);
	    }
	    if (!isdigit(*ptr)) {
	      struct group *g, grp;
	      getgrnam_r(ptr, &grp, buf, length, &g);
	      if (NULL == g) {
		fprintf(stderr, "Failed to identify gid for group [%s]\n", ptr);
		exit(1);
	      }
	      group_list[g_count] = g->gr_gid;
	    } else {
	      group_list[g_count] = strtoul(ptr, NULL, 0);
	    }
	  }
	  free(buf);
	  if (setgroups(g_count, group_list) != 0) {
	    fprintf(stderr, "Failed to setgroups.\n");
	    exit(1);
	  }
	  free(group_list);
	} else if (!memcmp("--user="******"User [%s] not known\n", user);
	      exit(1);
	    }
	    ngroups = MAX_GROUPS;
	    status = getgrouplist(user, pwd->pw_gid, groups, &ngroups);
	    if (status < 1) {
	      perror("Unable to get group list for user");
	      exit(1);
	    }
	    status = setgroups(ngroups, groups);
	    if (status != 0) {
	      perror("Unable to set group list for user");
	      exit(1);
	    }
	    status = setgid(pwd->pw_gid);
	    if (status < 0) {
		fprintf(stderr, "Failed to set gid=%u(user=%s): %s\n",
			pwd->pw_gid, user, strerror(errno));
		exit(1);
	    }
	    status = setuid(pwd->pw_uid);
	    if (status < 0) {
		fprintf(stderr, "Failed to set uid=%u(user=%s): %s\n",
			pwd->pw_uid, user, strerror(errno));
		exit(1);
	    }
	} else if (!memcmp("--decode=", argv[i], 9)) {
	    unsigned long long value;
	    unsigned cap;
	    const char *sep = "";

	    /* Note, if capabilities become longer than 64-bits we'll need
	       to fixup the following code.. */
	    value = strtoull(argv[i]+9, NULL, 16);
	    printf("0x%016llx=", value);

	    for (cap=0; (cap < 64) && (value >> cap); ++cap) {
		if (value & (1ULL << cap)) {
		    char *ptr;

		    ptr = cap_to_name(cap);
		    if (ptr != NULL) {
			printf("%s%s", sep, ptr);
			cap_free(ptr);
		    } else {
			printf("%s%u", sep, cap);
		    }
		    sep = ",";
		}
	    }
	    printf("\n");
        } else if (!memcmp("--supports=", argv[i], 11)) {
Beispiel #26
0
int main(int argc, char **argv)
{
    int tried_to_cap_setfcap = 0;
    char buffer[MAXCAP+1];
    int retval, quiet=0, verify=0;
    cap_t mycaps;
    cap_value_t capflag;

    if (argc < 3) {
	usage();
    }

    mycaps = cap_get_proc();
    if (mycaps == NULL) {
	fprintf(stderr, "warning - unable to get process capabilities"
		" (old libcap?)\n");
    }

    while (--argc > 0) {
	const char *text;
	cap_t cap_d;

	if (!strcmp(*++argv, "-q")) {
	    quiet = 1;
	    continue;
	}
	if (!strcmp(*argv, "-v")) {
	    verify = 1;
	    continue;
	}

	if (!strcmp(*argv, "-r")) {
	    cap_d = NULL;
	} else {
	    if (!strcmp(*argv,"-")) {
		retval = read_caps(quiet, *argv, buffer);
		if (retval)
		    usage();
		text = buffer;
	    } else {
		text = *argv;
	    }

	    cap_d = cap_from_text(text);
	    if (cap_d == NULL) {
		perror("fatal error");
		usage();
	    }
#ifdef DEBUG
	    {
		ssize_t length;
		const char *result;

		result = cap_to_text(cap_d, &length);
		fprintf(stderr, "caps set to: [%s]\n", result);
	    }
#endif
	}

	if (--argc <= 0)
	    usage();
	/*
	 * Set the filesystem capability for this file.
	 */
	if (verify) {
	    cap_t cap_on_file;
	    int cmp;

	    if (cap_d == NULL) {
		cap_d = cap_from_text("=");
	    }

	    cap_on_file = cap_get_file(*++argv);

	    if (cap_on_file == NULL) {
		cap_on_file = cap_from_text("=");
	    }

	    cmp = cap_compare(cap_on_file, cap_d);
	    cap_free(cap_on_file);

	    if (cmp != 0) {
		if (!quiet) {
		    printf("%s differs in [%s%s%s]\n", *argv,
			   CAP_DIFFERS(cmp, CAP_PERMITTED) ? "p" : "",
			   CAP_DIFFERS(cmp, CAP_INHERITABLE) ? "i" : "",
			   CAP_DIFFERS(cmp, CAP_EFFECTIVE) ? "e" : "");
		}
		exit(1);
	    }
	    if (!quiet) {
		printf("%s: OK\n", *argv);
	    }
	} else {
	    if (!tried_to_cap_setfcap) {
		capflag = CAP_SETFCAP;

		/*
		 * Raise the effective CAP_SETFCAP.
		 */
		if (cap_set_flag(mycaps, CAP_EFFECTIVE, 1, &capflag, CAP_SET)
		    != 0) {
		    perror("unable to manipulate CAP_SETFCAP - "
			   "try a newer libcap?");
		    exit(1);
		}
		if (cap_set_proc(mycaps) != 0) {
		    perror("unable to set CAP_SETFCAP effective capability");
		    exit(1);
		}
		tried_to_cap_setfcap = 1;
	    }
	    retval = cap_set_file(*++argv, cap_d);
	    if (retval != 0) {
		fprintf(stderr,
			"Failed to set capabilities on file `%s' (%s)\n",
			argv[0], strerror(errno));
		usage();
	    }
	}
	if (cap_d) {
	    cap_free(cap_d);
	}
    }

    exit(0);
}
Beispiel #27
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;
}
Beispiel #28
0
int
main(int argc, char **argv)
{
  char *opt, *p, *str;
  int told = 0;
  int use_checklist = 0;
  int systemmode = 0;
  int suseconfig = 0;
  FILE *fp;
  char line[512];
  char *part[4];
  int i, pcnt, lcnt;
  int inpart;
  mode_t mode;
  struct perm *e;
  struct stat stb, stb2;
  struct passwd *pwd = 0;
  struct group *grp = 0;
  uid_t uid;
  gid_t gid;
  int fd, r;
  int errors = 0;
  cap_t caps = NULL;

  while (argc > 1)
    {
      opt = argv[1];
      if (!strcmp(opt, "--"))
	break;
      if (*opt == '-' && opt[1] == '-')
	opt++;
      if (!strcmp(opt, "-system"))
	{
	  argc--;
	  argv++;
	  systemmode = 1;
	  continue;
	}
      // hidden option for use by suseconfig only
      if (!strcmp(opt, "-suseconfig"))
	{
	  argc--;
	  argv++;
	  suseconfig = 1;
	  systemmode = 1;
	  continue;
	}
      if (!strcmp(opt, "-fscaps"))
	{
	  argc--;
	  argv++;
	  have_fscaps = 1;
	  continue;
	}
      if (!strcmp(opt, "-no-fscaps"))
	{
	  argc--;
	  argv++;
	  have_fscaps = 0;
	  continue;
	}
      if (!strcmp(opt, "-s") || !strcmp(opt, "-set"))
	{
	  do_set=1;
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-warn"))
	{
	  do_set=0;
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-n") || !strcmp(opt, "-noheader"))
	{
	  told = 1;
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-e") || !strcmp(opt, "-examine"))
	{
	  argc--;
	  argv++;
	  if (argc == 1)
	    {
	      fprintf(stderr, "examine: argument required\n");
	      exit(1);
	    }
	  add_checklist(argv[1]);
	  use_checklist = 1;
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-level"))
	{
	  argc--;
	  argv++;
	  if (argc == 1)
	    {
	      fprintf(stderr, "level: argument required\n");
	      exit(1);
	    }
	  force_level = argv[1];
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-f") || !strcmp(opt, "-files"))
	{
	  argc--;
	  argv++;
	  if (argc == 1)
	    {
	      fprintf(stderr, "files: argument required\n");
	      exit(1);
	    }
	  if ((fp = fopen(argv[1], "r")) == 0)
	    {
	      fprintf(stderr, "files: %s: %s\n", argv[1], strerror(errno));
	      exit(1);
	    }
	  while (readline(fp, line, sizeof(line)))
	    {
	      if (!*line)
		continue;
	      add_checklist(line);
	    }
	  fclose(fp);
	  use_checklist = 1;
	  argc--;
	  argv++;
	  continue;
	}
      if (!strcmp(opt, "-r") || !strcmp(opt, "-root"))
	{
	  argc--;
	  argv++;
	  if (argc == 1)
	    {
	      fprintf(stderr, "root: argument required\n");
	      exit(1);
	    }
	  root = argv[1];
	  rootl = strlen(root);
	  if (*root != '/')
	    {
	      fprintf(stderr, "root: must begin with '/'\n");
	      exit(1);
	    }
	  argc--;
	  argv++;
	  continue;
	}
      if (*opt == '-')
	usage(!strcmp(opt, "-h") || !strcmp(opt, "-help") ? 0 : 1);
      break;
    }

  if (systemmode)
    {
      const char file[] = "/etc/sysconfig/security";
      parse_sysconf(file);
      if(do_set == -1)
	{
	  if (default_set < 0)
	    {
	      fprintf(stderr, "permissions handling disabled in %s\n", file);
	      exit(0);
	    }
	  if (suseconfig && default_set)
	    {
	      char* module = getenv("ONLY_MODULE");
	      if (!module || strcmp(module, "permissions"))
		{
		  puts("no permissions will be changed if not called explicitly");
		  default_set = 0;
		}
	    }
	  do_set = default_set;
	}
      if (force_level)
	{
	  char *p = strtok(force_level, " ");
	  do
	    {
	      add_level(p);
	    }
	  while ((p = strtok(NULL, " ")));
	}

      if (!nlevel)
	add_level("secure");
      add_level("local"); // always add local

      for (i = 1; i < argc; i++)
	{
	  add_checklist(argv[i]);
	  use_checklist = 1;
	  continue;
	}
      collect_permfiles();
    }
  else if (argc <= 1)
    usage(1);
  else
    {
      npermfiles = argc-1;
      permfiles = &argv[1];
    }

  if (have_fscaps == 1 && !check_fscaps_enabled())
    {
      fprintf(stderr, "Warning: running kernel does not support fscaps\n");
    }

  if  (do_set == -1)
    do_set = 0;

  // add fake list entries for all files to check
  for (i = 0; i < nchecklist; i++)
    add_permlist(checklist[i], "unknown", "unknown", 0);

  for (i = 0; i < npermfiles; i++)
    {
      if ((fp = fopen(permfiles[i], "r")) == 0)
	{
	  perror(argv[i]);
	  exit(1);
	}
      lcnt = 0;
      struct perm* last = NULL;
      int extline;
      while (readline(fp, line, sizeof(line)))
	{
	  extline = 0;
	  lcnt++;
	  if (*line == 0 || *line == '#' || *line == '$')
	    continue;
	  inpart = 0;
	  pcnt = 0;
	  for (p = line; *p; p++)
	    {
	      if (*p == ' ' || *p == '\t')
		{
		  *p = 0;
		  if (inpart)
		    {
		      pcnt++;
		      inpart = 0;
		    }
		  continue;
		}
	      if (pcnt == 0 && !inpart && *p == '+')
		{
		  extline = 1;
		  break;
		}
	      if (!inpart)
		{
		  inpart = 1;
		  if (pcnt == 3)
		    break;
		  part[pcnt] = p;
		}
	    }
	  if (extline)
	    {
	      if (!last)
		{
		  BAD_LINE();
		  continue;
		}
	      if (!strncmp(p, "+capabilities ", 14))
		{
		  if (have_fscaps != 1)
		    continue;
		  p += 14;
		  caps = cap_from_text(p);
		  if (caps)
		    {
		      cap_free(last->caps);
		      last->caps = caps;
		    }
		  continue;
		}
	      BAD_LINE();
	      continue;
	    }
	  if (inpart)
	    pcnt++;
	  if (pcnt != 3)
	    {
	      BAD_LINE();
	      continue;
	    }
	  part[3] = part[2];
	  part[2] = strchr(part[1], ':');
	  if (!part[2])
	    part[2] = strchr(part[1], '.');
	  if (!part[2])
	    {
	      BAD_LINE();
	      continue;
	    }
	  *part[2]++ = 0;
          mode = strtoul(part[3], part + 3, 8);
	  if (mode > 07777 || part[3][0])
	    {
	      BAD_LINE();
	      continue;
	    }
	  last = add_permlist(part[0], part[1], part[2], mode);
	}
      fclose(fp);
    }

  euid = geteuid();
  for (e = permlist; e; e = e->next)
    {
      if (use_checklist && !in_checklist(e->file+rootl))
	continue;
      if (lstat(e->file, &stb))
	continue;
      if (S_ISLNK(stb.st_mode))
	continue;
      if (!e->mode && !strcmp(e->owner, "unknown"))
	{
	  char uids[16], gids[16];
	  pwd = getpwuid(stb.st_uid);
	  grp = getgrgid(stb.st_gid);
	  if (!pwd)
	    sprintf(uids, "%d", stb.st_uid);
	  if (!grp)
	    sprintf(gids, "%d", stb.st_gid);
	  fprintf(stderr, "%s: cannot verify %s:%s %04o - not listed in /etc/permissions\n",
		  e->file+rootl,
		  pwd?pwd->pw_name:uids,
		  grp?grp->gr_name:gids,
		  (int)(stb.st_mode&07777));
	  pwd = 0;
	  grp = 0;
	  continue;
	}
      if ((!pwd || strcmp(pwd->pw_name, e->owner)) && (pwd = getpwnam(e->owner)) == 0)
	{
	  fprintf(stderr, "%s: unknown user %s\n", e->file+rootl, e->owner);
	  continue;
	}
      if ((!grp || strcmp(grp->gr_name, e->group)) && (grp = getgrnam(e->group)) == 0)
	{
	  fprintf(stderr, "%s: unknown group %s\n", e->file+rootl, e->group);
	  continue;
	}
      uid = pwd->pw_uid;
      gid = grp->gr_gid;
      caps = cap_get_file(e->file);
      if (!caps)
	{
	  cap_free(caps);
	  caps = NULL;
	  if (errno == EOPNOTSUPP)
	    {
	      //fprintf(stderr, "%s: fscaps not supported\n", e->file+rootl);
	      cap_free(e->caps);
	      e->caps = NULL;
	    }
	}
      if (e->caps)
	{
	  e->mode &= 0777;
	}

      int perm_ok = (stb.st_mode & 07777) == e->mode;
      int owner_ok = stb.st_uid == uid && stb.st_gid == gid;
      int caps_ok = 0;

      if (!caps && !e->caps)
	caps_ok = 1;
      else if (caps && e->caps && !cap_compare(e->caps, caps))
	caps_ok = 1;

      if (perm_ok && owner_ok && caps_ok)
	continue;

      if (!told)
	{
	  told = 1;
	  printf("Checking permissions and ownerships - using the permissions files\n");
	  for (i = 0; i < npermfiles; i++)
	    printf("\t%s\n", permfiles[i]);
	  if (rootl)
	    {
	      printf("Using root %s\n", root);
	    }
	}

      if (!do_set)
	printf("%s should be %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode);
      else
	printf("setting %s to %s:%s %04o", e->file+rootl, e->owner, e->group, e->mode);

      if (!caps_ok && e->caps)
        {
	  str = cap_to_text(e->caps, NULL);
	  printf(" \"%s\"", str);
	  cap_free(str);
        }
      printf(". (wrong");
      if (!owner_ok)
	{
	  pwd = getpwuid(stb.st_uid);
	  grp = getgrgid(stb.st_gid);
	  if (pwd)
	    printf(" owner/group %s", pwd->pw_name);
	  else
	    printf(" owner/group %d", stb.st_uid);
	  if (grp)
	    printf(":%s", grp->gr_name);
	  else
	    printf(":%d", stb.st_gid);
	  pwd = 0;
	  grp = 0;
	}

      if (!perm_ok)
	printf(" permissions %04o", (int)(stb.st_mode & 07777));

      if (!caps_ok)
        {
	  if (!perm_ok || !owner_ok)
	    {
	      fputc(',', stdout);
	    }
	  if (caps)
	    {
	      str = cap_to_text(caps, NULL);
	      printf(" capabilities \"%s\"", str);
	      cap_free(str);
	    }
	  else
	    fputs(" missing capabilities", stdout);
        }
      putchar(')');
      putchar('\n');

      if (!do_set)
	continue;

      fd = -1;
      if (S_ISDIR(stb.st_mode))
	{
	  fd = open(e->file, O_RDONLY|O_DIRECTORY|O_NONBLOCK|O_NOFOLLOW);
	  if (fd == -1)
	    {
	      perror(e->file);
	      errors++;
	      continue;
	    }
	}
      else if (S_ISREG(stb.st_mode))
	{
	  fd = open(e->file, O_RDONLY|O_NONBLOCK|O_NOFOLLOW);
	  if (fd == -1)
	    {
	      perror(e->file);
	      errors++;
	      continue;
	    }
	  if (fstat(fd, &stb2))
	    continue;
	  if (stb.st_mode != stb2.st_mode || stb.st_nlink != stb2.st_nlink || stb.st_dev != stb2.st_dev || stb.st_ino != stb2.st_ino)
	    {
	      fprintf(stderr, "%s: too fluctuating\n", e->file+rootl);
	      errors++;
	      continue;
	    }
	  if (stb.st_nlink > 1 && !safepath(e->file, 0, 0))
	    {
	      fprintf(stderr, "%s: on an insecure path\n", e->file+rootl);
	      errors++;
	      continue;
	    }
	  else if (e->mode & 06000)
	    {
	      /* extra checks for s-bits */
	      if (!safepath(e->file, (e->mode & 02000) == 0 ? uid : 0, (e->mode & 04000) == 0 ? gid : 0))
		{
		  fprintf(stderr, "%s: will not give away s-bits on an insecure path\n", e->file+rootl);
		  errors++;
		  continue;
		}
	    }
	}
      else if (strncmp(e->file, "/dev/", 5) != 0) // handle special files only in /dev
	{
	  fprintf(stderr, "%s: don't know what to do with that type of file\n", e->file+rootl);
	  errors++;
	  continue;
	}
      if (euid == 0 && !owner_ok)
	{
	 /* if we change owner or group of a setuid file the bit gets reset so
	    also set perms again */
	  if (e->mode & 06000)
	      perm_ok = 0;
	  if (fd >= 0)
	    r = fchown(fd, uid, gid);
	  else
	    r = chown(e->file, uid, gid);
	  if (r)
	    {
	      fprintf(stderr, "%s: chown: %s\n", e->file+rootl, strerror(errno));
	      errors++;
	    }
	  if (fd >= 0)
	    r = fstat(fd, &stb);
	  else
	    r = lstat(e->file, &stb);
	  if (r)
	    {
	      fprintf(stderr, "%s: too fluctuating\n", e->file+rootl);
	      errors++;
	      continue;
	    }
	}
      if (!perm_ok)
	{
	  if (fd >= 0)
	    r = fchmod(fd, e->mode);
	  else
	    r = chmod(e->file, e->mode);
	  if (r)
	    {
	      fprintf(stderr, "%s: chmod: %s\n", e->file+rootl, strerror(errno));
	      errors++;
	    }
	}
      if (!caps_ok)
	{
	  if (fd >= 0)
	    r = cap_set_fd(fd, e->caps);
	  else
	    r = cap_set_file(e->file, e->caps);
	  if (r)
	    {
	      fprintf(stderr, "%s: cap_set_file: %s\n", e->file+rootl, strerror(errno));
	      errors++;
	    }
	}
      if (fd >= 0)
	close(fd);
    }
  if (errors)
    {
      fprintf(stderr, "ERROR: not all operations were successful.\n");
      exit(1);
    }
  exit(0);
}
Beispiel #29
0
// Given the path to this program, fetch its configured capability set
// (as set by `setcap ... /path/to/file`) and raise those capabilities
// into the Ambient set.
static int make_caps_ambient(const char *selfPath)
{
    cap_t caps = cap_get_file(selfPath);

    if(!caps)
    {
        if(getenv(wrapperDebug))
            fprintf(stderr, "no caps set or could not retrieve the caps for this file, not doing anything...");

        return 1;
    }

    // We use `cap_to_text` and iteration over the tokenized result
    // string because, as of libcap's current release, there is no
    // facility for retrieving an array of `cap_value_t`'s that can be
    // given to `prctl` in order to lift that capability into the
    // Ambient set.
    //
    // Some discussion was had around shot-gunning all of the
    // capabilities we know about into the Ambient set but that has a
    // security smell and I deemed the risk of the current
    // implementation crashing the program to be lower than the risk
    // of a privilege escalation security hole being introduced by
    // raising all capabilities, even ones we didn't intend for the
    // program, into the Ambient set.
    //
    // `cap_t` which is returned by `cap_get_*` is an opaque type and
    // even if we could retrieve the bitmasks (which, as far as I can
    // tell we cannot) in order to get the `cap_value_t`
    // representation for each capability we would have to take the
    // total number of capabilities supported and iterate over the
    // sequence of integers up-to that maximum total, testing each one
    // against the bitmask ((bitmask >> n) & 1) to see if it's set and
    // aggregating each "capability integer n" that is set in the
    // bitmask.
    //
    // That, combined with the fact that we can't easily get the
    // bitmask anyway seemed much more brittle than fetching the
    // `cap_t`, transforming it into a textual representation,
    // tokenizing the string, and using `cap_from_name` on the token
    // to get the `cap_value_t` that we need for `prctl`. There is
    // indeed risk involved if the output string format of
    // `cap_to_text` ever changes but at this time the combination of
    // factors involving the below list have led me to the conclusion
    // that the best implementation at this time is reading then
    // parsing with *lots of documentation* about why we're doing it
    // this way.
    //
    // 1. No explicit API for fetching an array of `cap_value_t`'s or
    //    for transforming a `cap_t` into such a representation
    // 2. The risk of a crash is lower than lifting all capabilities
    //    into the Ambient set
    // 3. libcap is depended on heavily in the Linux ecosystem so
    //    there is a high chance that the output representation of
    //    `cap_to_text` will not change which reduces our risk that
    //    this parsing step will cause a crash
    //
    // The preferred method, should it ever be available in the
    // future, would be to use libcap API's to transform the result
    // from a `cap_get_*` into an array of `cap_value_t`'s that can
    // then be given to prctl.
    //
    // - Parnell
    ssize_t capLen;
    char* capstr = cap_to_text(caps, &capLen);
    cap_free(caps);
    
    // TODO: For now, we assume that cap_to_text always starts its
    // result string with " =" and that the first capability is listed
    // immediately after that. We should verify this.
    assert(capLen >= 2);
    capstr += 2;

    char* saveptr = NULL;
    for(char* tok = strtok_r(capstr, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr))
    {
      cap_value_t capnum;
      if (cap_from_name(tok, &capnum))
      {
          if(getenv(wrapperDebug))
              fprintf(stderr, "cap_from_name failed, skipping: %s", tok);
      }
      else if (capnum == CAP_SETPCAP)
      {
          // Check for the cap_setpcap capability, we set this on the
          // wrapper so it can elevate the capabilities to the Ambient
          // set but we do not want to propagate it down into the
          // wrapped program.
          //
          // TODO: what happens if that's the behavior you want
          // though???? I'm preferring a strict vs. loose policy here.
          if(getenv(wrapperDebug))
              fprintf(stderr, "cap_setpcap in set, skipping it\n");
      }
      else
      {
          set_ambient_cap(capnum);

          if(getenv(wrapperDebug))
              fprintf(stderr, "raised %s into the Ambient capability set\n", tok);
      }
    }
    cap_free(capstr);

    return 0;
}