UWRAP_LOG_TRACE
};
-#ifdef NDEBUG
-# define UWRAP_LOG(...)
-#else /* NDEBUG */
-static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
-# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __VA_ARGS__)
+static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
+# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
-static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
+static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
{
char buffer[1024];
va_list va;
const char *d;
unsigned int lvl = 0;
+ const char *prefix = "UWRAP";
d = getenv("UID_WRAPPER_DEBUGLEVEL");
if (d != NULL) {
lvl = atoi(d);
}
+ if (lvl < dbglvl) {
+ return;
+ }
+
va_start(va, format);
vsnprintf(buffer, sizeof(buffer), format, va);
va_end(va);
- if (lvl >= dbglvl) {
- switch (dbglvl) {
- case UWRAP_LOG_ERROR:
- fprintf(stderr,
- "UWRAP_ERROR(%d): %s\n",
- (int)getpid(), buffer);
- break;
- case UWRAP_LOG_WARN:
- fprintf(stderr,
- "UWRAP_WARN(%d): %s\n",
- (int)getpid(), buffer);
- break;
- case UWRAP_LOG_DEBUG:
- fprintf(stderr,
- "UWRAP_DEBUG(%d): %s\n",
- (int)getpid(), buffer);
- break;
- case UWRAP_LOG_TRACE:
- fprintf(stderr,
- "UWRAP_TRACE(%d): %s\n",
- (int)getpid(), buffer);
- break;
- }
+ switch (dbglvl) {
+ case UWRAP_LOG_ERROR:
+ prefix = "UWRAP_ERROR";
+ break;
+ case UWRAP_LOG_WARN:
+ prefix = "UWRAP_WARN";
+ break;
+ case UWRAP_LOG_DEBUG:
+ prefix = "UWRAP_DEBUG";
+ break;
+ case UWRAP_LOG_TRACE:
+ prefix = "UWRAP_TRACE";
+ break;
}
+
+ fprintf(stderr,
+ "%s(%d) - %s: %s\n",
+ prefix,
+ (int)getpid(),
+ function,
+ buffer);
}
-#endif /* NDEBUG */
/*****************
* LIBC
if (handle != NULL) {
break;
}
+
+ /* glibc on Alpha and IA64 is libc.so.6.1 */
+ snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
+ handle = dlopen(soname, flags);
+ if (handle != NULL) {
+ break;
+ }
}
uwrap.libc.handle = handle;
if (id == NULL) {
UWRAP_UNLOCK(uwrap_id);
libpthread_pthread_exit(retval);
+ return;
}
UWRAP_DLIST_REMOVE(uwrap.ids, id);
* UWRAP ID HANDLING
*********************************************************/
+#define GROUP_STRING_SIZE 16384
+#define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
+
+/**
+ * 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[16] = {0}; /* We need 10 + 1 (+ 1) */
+ 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);
+
+ if (id->ngroups > GROUP_MAX_COUNT) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "ERROR: Number of groups (%u) exceeds maximum value "
+ "uid_wrapper can handle (%u).",
+ id->ngroups,
+ GROUP_MAX_COUNT);
+ exit(-1);
+ }
+
+ /* GROUPS */
+ 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 - 1;
+ int len;
+
+ len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
+ if (len <= 1) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "snprintf failed for groups[%d]=%u",
+ i,
+ id->groups[i]);
+ break;
+ }
+ if (((size_t)len) >= groups_str_avail) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "groups env string is to small for %d groups",
+ i);
+ break;
+ }
+
+ len = snprintf(groups_str + groups_str_len,
+ groups_str_size - groups_str_len,
+ "%s",
+ i == 0 ? unsigned_str + 1 : unsigned_str);
+ if (len < 1) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "snprintf failed to create groups string at groups[%d]=%u",
+ i,
+ id->groups[i]);
+ break;
+ }
+ }
+
+ if (id->ngroups == i) {
+ setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
+
+ snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
+ setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
+ }
+}
+
static void uwrap_thread_prepare(void)
{
struct uwrap_thread *id = uwrap_tls_id;
UWRAP_LOCK_ALL;
+ /* uid_wrapper is loaded but not enabled */
+ if (id == NULL) {
+ return;
+ }
+
/*
* What happens if another atfork prepare functions calls a uwrap
* function? So disable it in case another atfork prepare function
static void uwrap_thread_parent(void)
{
struct uwrap_thread *id = uwrap_tls_id;
+
+ /* uid_wrapper is loaded but not enabled */
+ if (id == NULL) {
+ UWRAP_UNLOCK_ALL;
+ return;
+ }
+
id->enabled = true;
UWRAP_UNLOCK_ALL;
struct uwrap_thread *id = uwrap_tls_id;
struct uwrap_thread *u = uwrap.ids;
+ /* uid_wrapper is loaded but not enabled */
+ if (id == NULL) {
+ UWRAP_UNLOCK_ALL;
+ return;
+ }
+
/*
* "Garbage collector" - Inspired by DESTRUCTOR.
* All threads (except one which called fork()) are dead now.. Dave
u = uwrap.ids;
}
+ uwrap_export_ids(id);
+
id->enabled = true;
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 && ngroups < GROUP_MAX_COUNT) {
+ 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);
+ }
+ SAFE_FREE(groups_str);
+ }
+
+ if (i != ngroups) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "ERROR: The number of groups (%u) passed, "
+ "does not match the number of groups (%u) "
+ "we parsed.",
+ ngroups,
+ i);
+ exit(-1);
+ }
+
+ UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
+ id->ngroups = ngroups;
+ }
+}
+
static void uwrap_init(void)
{
const char *env;
}
}
+ uwrap_init_env(id);
+
id->enabled = true;
UWRAP_LOG(UWRAP_LOG_DEBUG,
- "Enabled uid_wrapper as %s",
- uwrap.myuid == 0 ? "root" : "user");
+ "Enabled uid_wrapper as %s (real uid=%u)",
+ id->ruid == 0 ? "root" : "user",
+ (unsigned int)uwrap.myuid);
}
UWRAP_UNLOCK(uwrap_id);
- UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
+ UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
}
bool uid_wrapper_enabled(void)
return enabled;
}
-#ifdef HAVE_GETRESUID
-static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+/*
+ * UWRAP_SETxUID FUNCTIONS
+ */
+
+static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
{
struct uwrap_thread *id = uwrap_tls_id;
- UWRAP_LOCK(uwrap_id);
-
- *ruid = id->ruid;
- *euid = id->euid;
- *suid = id->suid;
-
- UWRAP_UNLOCK(uwrap_id);
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+ id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+ if (id->euid != 0) {
+ if (ruid != (uid_t)-1 &&
+ ruid != id->ruid &&
+ ruid != id->euid &&
+ ruid != id->suid) {
+ errno = EPERM;
+ return -1;
+ }
+ if (euid != (uid_t)-1 &&
+ euid != id->ruid &&
+ euid != id->euid &&
+ euid != id->suid) {
+ errno = EPERM;
+ return -1;
+ }
+ if (suid != (uid_t)-1 &&
+ suid != id->ruid &&
+ suid != id->euid &&
+ suid != id->suid) {
+ errno = EPERM;
+ return -1;
+ }
+ }
return 0;
}
-#endif
static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
{
struct uwrap_thread *id = uwrap_tls_id;
+ int rc;
- if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
- errno = EINVAL;
- return -1;
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+ id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+ rc = uwrap_setresuid_args(ruid, euid, suid);
+ if (rc != 0) {
+ return rc;
}
UWRAP_LOCK(uwrap_id);
+
if (ruid != (uid_t)-1) {
id->ruid = ruid;
}
return 0;
}
+static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
+ id->ruid, ruid, id->euid, euid, id->suid, suid);
+
+ rc = uwrap_setresuid_args(ruid, euid, suid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ UWRAP_LOCK(uwrap_id);
+
+ for (id = uwrap.ids; id; id = id->next) {
+ if (ruid != (uid_t)-1) {
+ id->ruid = ruid;
+ }
+
+ if (euid != (uid_t)-1) {
+ id->euid = euid;
+ }
+
+ if (suid != (uid_t)-1) {
+ id->suid = suid;
+ }
+ }
+
+ UWRAP_UNLOCK(uwrap_id);
+
+ return 0;
+}
+
+static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
+ uid_t *_new_ruid,
+ uid_t *_new_euid,
+ uid_t *_new_suid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d",
+ id->ruid, ruid, id->euid, euid);
+
+ if (ruid != (uid_t)-1) {
+ new_ruid = ruid;
+ if (ruid != id->ruid &&
+ ruid != id->euid &&
+ id->euid != 0) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ if (euid != (uid_t)-1) {
+ new_euid = euid;
+ if (euid != id->ruid &&
+ euid != id->euid &&
+ euid != id->suid &&
+ id->euid != 0) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ if (ruid != (uid_t) -1 ||
+ (euid != (uid_t)-1 && id->ruid != euid)) {
+ new_suid = new_euid;
+ }
+
+ *_new_ruid = new_ruid;
+ *_new_euid = new_euid;
+ *_new_suid = new_suid;
+
+ return 0;
+}
+
+static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d",
+ id->ruid, ruid, id->euid, euid);
+
+ rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
+}
+
+#ifdef HAVE_SETREUID
+static int uwrap_setreuid(uid_t ruid, uid_t euid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "ruid %d -> %d, euid %d -> %d",
+ id->ruid, ruid, id->euid, euid);
+
+ rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresuid(new_ruid, new_euid, new_suid);
+}
+#endif
+
+static int uwrap_setuid_args(uid_t uid,
+ uid_t *new_ruid,
+ uid_t *new_euid,
+ uid_t *new_suid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "uid %d -> %d",
+ id->ruid, uid);
+
+ if (uid == (uid_t)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (id->euid == 0) {
+ *new_suid = *new_ruid = uid;
+ } else if (uid != id->ruid &&
+ uid != id->suid) {
+ errno = EPERM;
+ return -1;
+ }
+
+ *new_euid = uid;
+
+ return 0;
+}
+
+static int uwrap_setuid_thread(uid_t uid)
+{
+ uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+ int rc;
+
+ rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
+}
+
+static int uwrap_setuid(uid_t uid)
+{
+ uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
+ int rc;
+
+ rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresuid(new_ruid, new_euid, new_suid);
+}
+
+/*
+ * UWRAP_GETxUID FUNCTIONS
+ */
+
+#ifdef HAVE_GETRESUID
+static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ UWRAP_LOCK(uwrap_id);
+
+ *ruid = id->ruid;
+ *euid = id->euid;
+ *suid = id->suid;
+
+ UWRAP_UNLOCK(uwrap_id);
+
+ return 0;
+}
+#endif
+
#ifdef HAVE_GETRESGID
static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
{
}
#endif
-static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+/*
+ * UWRAP_SETxGID FUNCTIONS
+ */
+
+static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
{
- struct uwrap_thread *id;
+ struct uwrap_thread *id = uwrap_tls_id;
- if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
- errno = EINVAL;
- return -1;
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+ id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+ if (id->euid != 0) {
+ if (rgid != (gid_t)-1 &&
+ rgid != id->rgid &&
+ rgid != id->egid &&
+ rgid != id->sgid) {
+ errno = EPERM;
+ return -1;
+ }
+ if (egid != (gid_t)-1 &&
+ egid != id->rgid &&
+ egid != id->egid &&
+ egid != id->sgid) {
+ errno = EPERM;
+ return -1;
+ }
+ if (sgid != (gid_t)-1 &&
+ sgid != id->rgid &&
+ sgid != id->egid &&
+ sgid != id->sgid) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+ id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+ rc = uwrap_setresgid_args(rgid, egid, sgid);
+ if (rc != 0) {
+ return rc;
}
UWRAP_LOCK(uwrap_id);
+
+ if (rgid != (gid_t)-1) {
+ id->rgid = rgid;
+ }
+
+ if (egid != (gid_t)-1) {
+ id->egid = egid;
+ }
+
+ if (sgid != (gid_t)-1) {
+ id->sgid = sgid;
+ }
+
+ UWRAP_UNLOCK(uwrap_id);
+
+ return 0;
+}
+
+static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
+ id->rgid, rgid, id->egid, egid, id->sgid, sgid);
+
+ rc = uwrap_setresgid_args(rgid, egid, sgid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ UWRAP_LOCK(uwrap_id);
+
for (id = uwrap.ids; id; id = id->next) {
- if (ruid != (uid_t)-1) {
- id->ruid = ruid;
+ if (rgid != (gid_t)-1) {
+ id->rgid = rgid;
}
- if (euid != (uid_t)-1) {
- id->euid = euid;
+ if (egid != (gid_t)-1) {
+ id->egid = egid;
}
- if (suid != (uid_t)-1) {
- id->suid = suid;
+ if (sgid != (gid_t)-1) {
+ id->sgid = sgid;
}
}
return 0;
}
+static int uwrap_setregid_args(gid_t rgid, gid_t egid,
+ gid_t *_new_rgid,
+ gid_t *_new_egid,
+ gid_t *_new_sgid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d",
+ id->rgid, rgid, id->egid, egid);
+
+ if (rgid != (gid_t)-1) {
+ new_rgid = rgid;
+ if (rgid != id->rgid &&
+ rgid != id->egid &&
+ id->euid != 0) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ if (egid != (gid_t)-1) {
+ new_egid = egid;
+ if (egid != id->rgid &&
+ egid != id->egid &&
+ egid != id->sgid &&
+ id->euid != 0) {
+ errno = EPERM;
+ return -1;
+ }
+ }
+
+ if (rgid != (gid_t) -1 ||
+ (egid != (gid_t)-1 && id->rgid != egid)) {
+ new_sgid = new_egid;
+ }
+
+ *_new_rgid = new_rgid;
+ *_new_egid = new_egid;
+ *_new_sgid = new_sgid;
+
+ return 0;
+}
+
+static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d",
+ id->rgid, rgid, id->egid, egid);
+
+ rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
+}
+
+#ifdef HAVE_SETREGID
+static int uwrap_setregid(gid_t rgid, gid_t egid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d",
+ id->rgid, rgid, id->egid, egid);
+
+ rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresgid(new_rgid, new_egid, new_sgid);
+}
+#endif
+
+static int uwrap_setgid_args(gid_t gid,
+ gid_t *new_rgid,
+ gid_t *new_egid,
+ gid_t *new_sgid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "gid %d -> %d",
+ id->rgid, gid);
+
+ if (gid == (gid_t)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (id->euid == 0) {
+ *new_sgid = *new_rgid = gid;
+ } else if (gid != id->rgid &&
+ gid != id->sgid) {
+ errno = EPERM;
+ return -1;
+ }
+
+ *new_egid = gid;
+
+ return 0;
+}
+
+static int uwrap_setgid_thread(gid_t gid)
+{
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
+
+ rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
+}
+
+static int uwrap_setgid(gid_t gid)
+{
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
+
+ rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return uwrap_setresgid(new_rgid, new_egid, new_sgid);
+}
+
/*
* SETUID
*/
}
uwrap_init();
- return uwrap_setresuid(uid, -1, -1);
+ return uwrap_setuid(uid);
}
#ifdef HAVE_SETEUID
int seteuid(uid_t euid)
{
+ if (!uid_wrapper_enabled()) {
+ return libc_seteuid(euid);
+ }
+
+ /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
if (euid == (uid_t)-1) {
errno = EINVAL;
return -1;
}
- if (!uid_wrapper_enabled()) {
- return libc_seteuid(euid);
- }
-
uwrap_init();
return uwrap_setresuid(-1, euid, -1);
}
#ifdef HAVE_SETREUID
int setreuid(uid_t ruid, uid_t euid)
{
- if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
- errno = EINVAL;
- return -1;
- }
-
if (!uid_wrapper_enabled()) {
return libc_setreuid(ruid, euid);
}
uwrap_init();
- return uwrap_setresuid(ruid, euid, -1);
+ return uwrap_setreuid(ruid, euid);
}
#endif
return uwrap_geteuid();
}
-static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
-{
- struct uwrap_thread *id = uwrap_tls_id;
-
- if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
- errno = EINVAL;
- return -1;
- }
-
- UWRAP_LOCK(uwrap_id);
- if (rgid != (gid_t)-1) {
- id->rgid = rgid;
- }
-
- if (egid != (gid_t)-1) {
- id->egid = egid;
- }
-
- if (sgid != (gid_t)-1) {
- id->sgid = sgid;
- }
-
- UWRAP_UNLOCK(uwrap_id);
-
- return 0;
-}
-
-static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
-{
- struct uwrap_thread *id;
-
- if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
- errno = EINVAL;
- return -1;
- }
-
- UWRAP_LOCK(uwrap_id);
- for (id = uwrap.ids; id; id = id->next) {
- if (rgid != (gid_t)-1) {
- id->rgid = rgid;
- }
-
- if (egid != (gid_t)-1) {
- id->egid = egid;
- }
-
- if (sgid != (gid_t)-1) {
- id->sgid = sgid;
- }
- }
- UWRAP_UNLOCK(uwrap_id);
-
- return 0;
-}
-
/*
* SETGID
*/
}
uwrap_init();
- return uwrap_setresgid(gid, -1, -1);
+ return uwrap_setgid(gid);
}
#ifdef HAVE_SETEGID
return libc_setegid(egid);
}
+ /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
+ if (egid == (gid_t)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+
uwrap_init();
return uwrap_setresgid(-1, egid, -1);
}
}
uwrap_init();
- return uwrap_setresgid(rgid, egid, -1);
+ return uwrap_setregid(rgid, egid);
}
#endif
switch (sysno) {
/* gid */
+#ifdef __alpha__
+ case SYS_getxgid:
+#else
case SYS_getgid:
+#endif
#ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getgid32:
#endif
{
gid_t gid = (gid_t) va_arg(vp, gid_t);
- rc = uwrap_setresgid_thread(gid, -1, -1);
+ rc = uwrap_setgid_thread(gid);
}
break;
case SYS_setregid:
gid_t rgid = (gid_t) va_arg(vp, gid_t);
gid_t egid = (gid_t) va_arg(vp, gid_t);
- rc = uwrap_setresgid_thread(rgid, egid, -1);
+ rc = uwrap_setregid_thread(rgid, egid);
}
break;
#ifdef SYS_setresgid
}
break;
#endif /* SYS_setresgid */
-#ifdef SYS_getresgid
+#if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
case SYS_getresgid:
#ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresgid32:
rc = uwrap_getresgid(rgid, egid, sgid);
}
break;
-#endif /* SYS_getresgid */
+#endif /* SYS_getresgid && HAVE_GETRESGID */
/* uid */
+#ifdef __alpha__
+ case SYS_getxuid:
+#else
case SYS_getuid:
+#endif
#ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getuid32:
#endif
{
uid_t uid = (uid_t) va_arg(vp, uid_t);
- rc = uwrap_setresuid_thread(uid, -1, -1);
+ rc = uwrap_setuid_thread(uid);
}
break;
case SYS_setreuid:
uid_t ruid = (uid_t) va_arg(vp, uid_t);
uid_t euid = (uid_t) va_arg(vp, uid_t);
- rc = uwrap_setresuid_thread(ruid, euid, -1);
+ rc = uwrap_setreuid_thread(ruid, euid);
}
break;
#ifdef SYS_setresuid
}
break;
#endif /* SYS_setresuid */
-#ifdef SYS_getresuid
+#if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
case SYS_getresuid:
#ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresuid32:
rc = uwrap_getresuid(ruid, euid, suid);
}
break;
-#endif /* SYS_getresuid */
+#endif /* SYS_getresuid && HAVE_GETRESUID*/
/* groups */
case SYS_setgroups:
#ifdef HAVE_LINUX_32BIT_SYSCALLS
break;
default:
UWRAP_LOG(UWRAP_LOG_DEBUG,
- "UID_WRAPPER calling non-wrapped syscall %lu\n",
+ "UID_WRAPPER calling non-wrapped syscall %lu",
sysno);
rc = libc_vsyscall(sysno, vp);