[SCM] UID Wrapper Repository - branch master updated

Andreas Schneider asn at samba.org
Thu Jul 13 06:52:28 UTC 2017


The branch, master has been updated
       via  27e9f76 Bump version to 1.2.2
       via  6d69fef tests: Add a fork and exec test
       via  b5168be uwrap: Add support to initialize groups while forking
      from  0580449 tests: fix a comment typo

https://git.samba.org/?p=uid_wrapper.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 27e9f76f1ddc72987f0323f19341b2b6afefa5cd
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Jul 12 13:03:35 2017 +0200

    Bump version to 1.2.2
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 6d69fefcc5b39cf2007ad9b43fe4972c3b835d80
Author: Andreas Schneider <asn at samba.org>
Date:   Wed Jul 12 09:16:30 2017 +0200

    tests: Add a fork and exec test
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit b5168be4128d7585c30ba98da31926cd3d0066e5
Author: Andreas Schneider <asn at samba.org>
Date:   Tue Jul 11 11:59:33 2017 +0200

    uwrap: Add support to initialize groups while forking
    
    Signed-off-by: Andreas Schneider <asn at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 CMakeLists.txt         |   2 +-
 ChangeLog              |   4 ++
 src/uid_wrapper.c      | 163 +++++++++++++++++++++++++++++++++++++++++++++++++
 tests/CMakeLists.txt   |   4 +-
 tests/mock_exec_uid.c  | 157 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/test_fork_exec.c |  88 ++++++++++++++++++++++++++
 6 files changed, 416 insertions(+), 2 deletions(-)
 create mode 100644 tests/mock_exec_uid.c
 create mode 100644 tests/test_fork_exec.c


Changeset truncated at 500 lines:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 898440e..4dc42f2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ set(APPLICATION_NAME ${PROJECT_NAME})
 
 set(APPLICATION_VERSION_MAJOR "1")
 set(APPLICATION_VERSION_MINOR "2")
-set(APPLICATION_VERSION_PATCH "1")
+set(APPLICATION_VERSION_PATCH "2")
 
 set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}.${APPLICATION_VERSION_MINOR}.${APPLICATION_VERSION_PATCH}")
 
diff --git a/ChangeLog b/ChangeLog
index 6f776de..cc02554 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,10 @@
 ChangeLog
 ==========
 
+version 1.2.2 (released 2107-07-13)
+  * Added support for fork'ed and then exec'ed processes
+  * Added support for Alpha
+
 version 1.2.1 (released 2016-03-16)
   * Documented missing options.
   * Fixed a comipilation issue with -O3.
diff --git a/src/uid_wrapper.c b/src/uid_wrapper.c
index ded857a..6e39eb6 100644
--- a/src/uid_wrapper.c
+++ b/src/uid_wrapper.c
@@ -815,6 +815,66 @@ int pthread_create(pthread_t *thread,
  * UWRAP ID HANDLING
  *********************************************************/
 
+#define GROUP_STRING_SIZE 16384
+
+/**
+ * This function exports all the IDs of the current user so if
+ * we fork and then exec we can setup uid_wrapper in the new process
+ * with those IDs.
+ */
+static void uwrap_export_ids(struct uwrap_thread *id)
+{
+	char groups_str[GROUP_STRING_SIZE] = {0};
+	size_t groups_str_size = sizeof(groups_str);
+	char unsigned_str[32] = {0};
+	int i;
+
+	/* UIDS */
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
+	setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
+
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
+	setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
+
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
+	setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
+
+	/* GIDS */
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
+	setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
+
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
+	setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
+
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
+	setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
+
+	/* GROUPS */
+	snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
+	setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
+
+	for (i = 0; i < id->ngroups; i++) {
+		size_t groups_str_len = strlen(groups_str);
+		size_t groups_str_avail = groups_str_size - groups_str_len;
+		size_t len;
+
+		len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
+		if (len <= 1) {
+			continue;
+		}
+		if (len < groups_str_avail) {
+			snprintf(groups_str + groups_str_len,
+				 groups_str_size - groups_str_len,
+				 "%s",
+				 i == 0 ? unsigned_str + 1 : unsigned_str);
+		}
+	}
+
+	if (id->ngroups > 0) {
+		setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
+	}
+}
+
 static void uwrap_thread_prepare(void)
 {
 	struct uwrap_thread *id = uwrap_tls_id;
@@ -859,6 +919,8 @@ static void uwrap_thread_child(void)
 		return;
 	}
 
+	uwrap_export_ids(id);
+
 	/*
 	 * "Garbage collector" - Inspired by DESTRUCTOR.
 	 * All threads (except one which called fork()) are dead now.. Dave
@@ -884,6 +946,105 @@ static void uwrap_thread_child(void)
 	UWRAP_UNLOCK_ALL;
 }
 
+/*
+ * This initializes uid_wrapper with the IDs exported to the environment. Those
+ * are normally set after we forked and executed.
+ */
+static void uwrap_init_env(struct uwrap_thread *id)
+{
+	const char *env;
+	int ngroups = 0;
+
+	env = getenv("UID_WRAPPER_INITIAL_RUID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
+		id->ruid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_RUID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_EUID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize euid with %s", env);
+		id->euid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_EUID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_SUID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize suid with %s", env);
+		id->suid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_SUID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_RGID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
+		id->rgid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_RGID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_EGID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize egid with %s", env);
+		id->egid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_EGID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_SGID");
+	if (env != NULL && env[0] != '\0') {
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize sgid with %s", env);
+		id->sgid = strtoul(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_SGID");
+	}
+
+	env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
+	if (env != NULL && env[0] != '\0') {
+		ngroups = strtol(env, (char **)NULL, 10);
+		unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
+	}
+
+	if (ngroups > 0) {
+		int i = 0;
+
+		id->ngroups = 0;
+
+		free(id->groups);
+		id->groups = malloc(sizeof(gid_t) * ngroups);
+		if (id->groups == NULL) {
+			UWRAP_LOG(UWRAP_LOG_ERROR,
+				  "Unable to allocate memory");
+			exit(-1);
+		}
+
+		env = getenv("UID_WRAPPER_INITIAL_GROUPS");
+		if (env != NULL && env[0] != '\0') {
+			char *groups_str = NULL;
+			char *saveptr = NULL;
+			const char *p = NULL;
+
+			groups_str = strdup(env);
+			if (groups_str == NULL) {
+				exit(-1);
+			}
+
+			p = strtok_r(groups_str, ",", &saveptr);
+			while (p != NULL) {
+				id->groups[i] = strtol(p, (char **)NULL, 10);
+				i++;
+
+				p = strtok_r(NULL, ",", &saveptr);
+			}
+		}
+
+		if (i != ngroups) {
+			exit(-1);
+		}
+
+		UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
+		id->ngroups = ngroups;
+	}
+}
+
 static void uwrap_init(void)
 {
 	const char *env;
@@ -972,6 +1133,8 @@ static void uwrap_init(void)
 			}
 		}
 
+		uwrap_init_env(id);
+
 		id->enabled = true;
 
 		UWRAP_LOG(UWRAP_LOG_DEBUG,
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 8201d94..6a6188f 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -21,6 +21,8 @@ if (BSD)
     add_definitions(-DBSD)
 endif (BSD)
 
+add_executable(mock_exec_uid mock_exec_uid.c)
+
 set(UWRAP_UID_TESTS
      test_setuid
      test_seteuid)
@@ -32,7 +34,7 @@ endif (HAVE_SETREUID)
 if (HAVE_SETRESUID)
     list(APPEND UWRAP_UID_TESTS test_setresuid test_setuid_euid1 test_setuid_euid2)
     if (HAVE_GETRESUID)
-        list(APPEND UWRAP_UID_TESTS test_getresuid)
+        list(APPEND UWRAP_UID_TESTS test_getresuid test_fork_exec)
     endif (HAVE_GETRESUID)
 endif (HAVE_SETRESUID)
 
diff --git a/tests/mock_exec_uid.c b/tests/mock_exec_uid.c
new file mode 100644
index 0000000..0e3737b
--- /dev/null
+++ b/tests/mock_exec_uid.c
@@ -0,0 +1,157 @@
+#include "config.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#ifndef discard_const
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
+#endif
+
+#ifndef discard_const_p
+#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
+#endif
+
+struct user_ids {
+	uid_t ruid;
+	uid_t euid;
+	uid_t suid;
+	gid_t gid;
+};
+
+static void print_usage(const char *prog_name)
+{
+	fprintf(stderr,
+		"Usage: %s [-r ruid] [-e euid] [-s suid] [-g gid]\n"
+		"\n"
+		"    -r The ruid to validate\n"
+		"    -e The euid to validate\n"
+		"    -s The suid to validate\n"
+		"    -g The gid to validate\n"
+		"\n",
+		prog_name);
+}
+
+int main(int argc, char *argv[])
+{
+	const struct option long_options[] = {
+		{ discard_const_p(char, "ruid"),  required_argument,  0, 'r' },
+		{ discard_const_p(char, "euid"),  required_argument,  0, 'e' },
+		{ discard_const_p(char, "suid"),  required_argument,  0, 's' },
+		{ discard_const_p(char, "gid"),   required_argument,  0, 'g' },
+		{ 0,                              0,                  0, 0 }
+	};
+	int opt_idx;
+	int opt;
+	struct user_ids expected_ids = {
+		.ruid = (uid_t)-1,
+		.euid = (uid_t)-1,
+		.suid = (uid_t)-1,
+		.gid  = (gid_t)-1,
+	};
+	struct user_ids real_ids = {
+		.ruid = (uid_t)-1,
+		.euid = (uid_t)-1,
+		.suid = (uid_t)-1,
+		.gid  = (gid_t)-1,
+	};
+	int rc;
+
+	for (opt = getopt_long(argc, argv, "r:e:s:g:", long_options, &opt_idx);
+	     opt != -1;
+	     opt = getopt_long(argc, argv, "r:e:s:g:", long_options, &opt_idx)) {
+		errno = 0;
+
+		switch (opt) {
+			case 0:
+				break;
+			case 'r':
+				expected_ids.ruid = strtol(optarg,
+							   (char **)NULL,
+							   10);
+				break;
+			case 'e':
+				expected_ids.euid = strtol(optarg,
+						           (char **)NULL,
+							   10);
+				break;
+			case 's':
+				expected_ids.suid = strtol(optarg,
+						           (char **)NULL,
+							   10);
+				break;
+			case 'g':
+				expected_ids.gid = strtol(optarg,
+						          (char **)NULL,
+							  10);
+				break;
+			default:
+				print_usage(argv[0]);
+				return 1;
+		}
+
+		if (errno == EINVAL || errno == ERANGE) {
+			return 1;
+		}
+	}
+
+	if (expected_ids.ruid == (uid_t)-1 &&
+	    expected_ids.euid == (uid_t)-1 &&
+	    expected_ids.suid == (uid_t)-1) {
+		print_usage(argv[0]);
+		return 1;
+	}
+
+	rc = getresuid(&real_ids.ruid, &real_ids.euid, &real_ids.suid);
+	if (rc != 0) {
+		fprintf(stderr, "getresuid() failed - %s\n", strerror(errno));
+		return 1;
+	}
+
+	if (expected_ids.ruid != (uid_t)-1) {
+		if (expected_ids.ruid != real_ids.ruid) {
+			printf("MOCK_TEST ruid mismatch - ruid=%u, expected ruid=%u\n",
+			       real_ids.ruid,
+			       expected_ids.ruid);
+			return 1;
+		}
+		printf("MOCK_TEST ruid=%d\n", real_ids.ruid);
+	}
+
+	if (expected_ids.euid != (uid_t)-1) {
+		if (expected_ids.euid != real_ids.euid) {
+			printf("MOCK_TEST euid mismatch - euid=%u, expected euid=%u\n",
+			       real_ids.euid,
+			       expected_ids.euid);
+			return 1;
+		}
+		printf("MOCK_TEST euid=%d\n", real_ids.euid);
+	}
+
+	if (expected_ids.suid != (uid_t)-1) {
+		if (expected_ids.suid != real_ids.suid) {
+			printf("MOCK_TEST suid mismatch - suid=%u, expected suid=%u\n",
+			       real_ids.suid,
+			       expected_ids.suid);
+			return 1;
+		}
+		printf("MOCK_TEST suid=%d\n", real_ids.suid);
+	}
+
+	real_ids.gid = getgid();
+	if (real_ids.gid != (gid_t)-1) {
+		if (expected_ids.gid != real_ids.gid) {
+			printf("MOCK_TEST gid mismatch - gid=%u, expected gid=%u\n",
+			       real_ids.gid,
+			       expected_ids.gid);
+			return 1;
+		}
+		printf("MOCK_TEST gid=%d\n", real_ids.gid);
+	}
+
+	return 0;
+}
diff --git a/tests/test_fork_exec.c b/tests/test_fork_exec.c
new file mode 100644
index 0000000..36077c4
--- /dev/null
+++ b/tests/test_fork_exec.c
@@ -0,0 +1,88 @@
+#include "config.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#define TEST_MOCK_EXECUTABLE "mock_exec_uid"
+
+static void test_uwrap_fork_exec(void **state)
+{
+	pid_t pid;
+	int rc;
+	uid_t cp_ruid, cp_euid, cp_suid;
+
+	(void)state; /* unused */
+
+	rc = getresuid(&cp_ruid, &cp_euid, &cp_suid);
+	assert_return_code(rc, errno);
+	assert_int_equal(cp_ruid, 0);
+	assert_int_equal(cp_euid, 0);
+	assert_int_equal(cp_suid, 0);
+
+	rc = setresuid(2000, -1, 4000);
+	assert_return_code(rc, errno);
+
+	rc = setgid(5000);
+	assert_return_code(rc, errno);
+
+	pid = fork();
+	assert_return_code(pid, errno);
+
+	/* child */
+	if (pid == 0) {
+		char const *argv[] = {
+			TEST_MOCK_EXECUTABLE,
+			"-r 2000",
+			"-e 0",
+			"-s 4000",
+			"-g 5000",
+			NULL
+		};
+		char cmd[1024] = {0};
+
+		snprintf(cmd, sizeof(cmd),
+			 "%s/tests/%s",
+			 BINARYDIR,
+			 TEST_MOCK_EXECUTABLE);
+
+		rc = execvp(cmd, (char *const *)argv);
+		exit(rc);
+	}
+
+	/* parent */
+	if (pid > 0) {
+		pid_t child_pid;
+		int wstatus = -1;
+
+		rc = setresuid(cp_ruid, cp_euid, cp_suid);
+		assert_return_code(rc, errno);
+
+		child_pid = waitpid(-1, &wstatus, 0);
+		assert_return_code(child_pid, errno);
+
+		assert_true(WIFEXITED(wstatus));
+
+		assert_int_equal(WEXITSTATUS(wstatus), 0);
+	}
+}
+
+int main(void) {
+	int rc;
+
+	const struct CMUnitTest uwrap_tests[] = {
+		cmocka_unit_test(test_uwrap_fork_exec),
+	};
+
+	rc = cmocka_run_group_tests(uwrap_tests, NULL, NULL);
+


-- 
UID Wrapper Repository



More information about the samba-cvs mailing list