[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