# define UWRAP_THREAD
#endif
-#ifdef NDEBUG
-#define UWRAP_DEBUG(...)
+# define UWRAP_LOCK(m) do { \
+ pthread_mutex_lock(&( m ## _mutex)); \
+} while(0)
+
+# define UWRAP_UNLOCK(m) do { \
+ pthread_mutex_unlock(&( m ## _mutex)); \
+} while(0)
+
+/* Add new global locks here please */
+# define UWRAP_LOCK_ALL \
+ UWRAP_LOCK(uwrap_id); \
+ UWRAP_LOCK(libc_symbol_binding); \
+ UWRAP_LOCK(libpthread_symbol_binding)
+
+# define UWRAP_UNLOCK_ALL \
+ UWRAP_UNLOCK(libpthread_symbol_binding); \
+ UWRAP_UNLOCK(libc_symbol_binding); \
+ UWRAP_UNLOCK(uwrap_id)
+
+#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
+#define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
#else
-#define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
-#endif
+#define CONSTRUCTOR_ATTRIBUTE
+#endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
+
+#ifdef HAVE_DESTRUCTOR_ATTRIBUTE
+#define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
+#else
+#define DESTRUCTOR_ATTRIBUTE
+#endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
+
+#ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
+#else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
+#define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+#endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
+
+/* GCC have printf type attribute check. */
+#ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
+#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
+#else
+#define PRINTF_ATTRIBUTE(a,b)
+#endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
#define UWRAP_DLIST_ADD(list,item) do { \
if (!(list)) { \
(item)->next = NULL; \
} while (0)
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
+#endif
+
+/*****************
+ * LOGGING
+ *****************/
+
+enum uwrap_dbglvl_e {
+ UWRAP_LOG_ERROR = 0,
+ UWRAP_LOG_WARN,
+ UWRAP_LOG_DEBUG,
+ UWRAP_LOG_TRACE
+};
+
+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 *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);
+
+ 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);
+}
+
+/*****************
+ * LIBC
+ *****************/
+
#define LIBC_NAME "libc.so"
-struct uwrap_libc_fns {
- int (*_libc_setuid)(uid_t uid);
- uid_t (*_libc_getuid)(void);
+typedef int (*__libc_setuid)(uid_t uid);
+
+typedef uid_t (*__libc_getuid)(void);
#ifdef HAVE_SETEUID
- int (*_libc_seteuid)(uid_t euid);
+typedef int (*__libc_seteuid)(uid_t euid);
#endif
+
#ifdef HAVE_SETREUID
- int (*_libc_setreuid)(uid_t ruid, uid_t euid);
+typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
#endif
-#ifdef HAVE_SETREUID
- int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
+
+#ifdef HAVE_SETRESUID
+typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
+#endif
+
+#ifdef HAVE_GETRESUID
+typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
#endif
- uid_t (*_libc_geteuid)(void);
- int (*_libc_setgid)(gid_t gid);
- gid_t (*_libc_getgid)(void);
+typedef uid_t (*__libc_geteuid)(void);
+
+typedef int (*__libc_setgid)(gid_t gid);
+
+typedef gid_t (*__libc_getgid)(void);
+
#ifdef HAVE_SETEGID
- int (*_libc_setegid)(uid_t egid);
+typedef int (*__libc_setegid)(uid_t egid);
#endif
+
#ifdef HAVE_SETREGID
- int (*_libc_setregid)(uid_t rgid, uid_t egid);
+typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
+#endif
+
+#ifdef HAVE_SETRESGID
+typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
+#endif
+
+#ifdef HAVE_GETRESGID
+typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
+#endif
+
+typedef gid_t (*__libc_getegid)(void);
+
+typedef int (*__libc_getgroups)(int size, gid_t list[]);
+
+typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
+
+#ifdef HAVE_SYSCALL
+typedef long int (*__libc_syscall)(long int sysno, ...);
+#endif
+
+#define UWRAP_SYMBOL_ENTRY(i) \
+ union { \
+ __libc_##i f; \
+ void *obj; \
+ } _libc_##i
+
+struct uwrap_libc_symbols {
+ UWRAP_SYMBOL_ENTRY(setuid);
+ UWRAP_SYMBOL_ENTRY(getuid);
+#ifdef HAVE_SETEUID
+ UWRAP_SYMBOL_ENTRY(seteuid);
+#endif
+#ifdef HAVE_SETREUID
+ UWRAP_SYMBOL_ENTRY(setreuid);
+#endif
+#ifdef HAVE_SETRESUID
+ UWRAP_SYMBOL_ENTRY(setresuid);
+#endif
+#ifdef HAVE_GETRESUID
+ UWRAP_SYMBOL_ENTRY(getresuid);
+#endif
+ UWRAP_SYMBOL_ENTRY(geteuid);
+ UWRAP_SYMBOL_ENTRY(setgid);
+ UWRAP_SYMBOL_ENTRY(getgid);
+#ifdef HAVE_SETEGID
+ UWRAP_SYMBOL_ENTRY(setegid);
#endif
#ifdef HAVE_SETREGID
- int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
+ UWRAP_SYMBOL_ENTRY(setregid);
+#endif
+#ifdef HAVE_SETRESGID
+ UWRAP_SYMBOL_ENTRY(setresgid);
#endif
- gid_t (*_libc_getegid)(void);
- int (*_libc_getgroups)(int size, gid_t list[]);
- int (*_libc_setgroups)(size_t size, const gid_t *list);
+#ifdef HAVE_GETRESGID
+ UWRAP_SYMBOL_ENTRY(getresgid);
+#endif
+ UWRAP_SYMBOL_ENTRY(getegid);
+ UWRAP_SYMBOL_ENTRY(getgroups);
+ UWRAP_SYMBOL_ENTRY(setgroups);
#ifdef HAVE_SYSCALL
- long int (*_libc_syscall)(long int sysno, ...);
+ UWRAP_SYMBOL_ENTRY(syscall);
#endif
};
+#undef UWRAP_SYMBOL_ENTRY
+
+/*****************
+ * LIBPTHREAD
+ *****************/
+/* Yeah... I'm pig. I overloading macro here... So what? */
+#define UWRAP_SYMBOL_ENTRY(i) \
+ union { \
+ __libpthread_##i f; \
+ void *obj; \
+ } _libpthread_##i
+
+typedef int (*__libpthread_pthread_create)(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine) (void *),
+ void *arg);
+typedef void (*__libpthread_pthread_exit)(void *retval);
+
+struct uwrap_libpthread_symbols {
+ UWRAP_SYMBOL_ENTRY(pthread_create);
+ UWRAP_SYMBOL_ENTRY(pthread_exit);
+};
+#undef UWRAP_SYMBOL_ENTRY
/*
* We keep the virtualised euid/egid/groups information here
*/
struct uwrap_thread {
- pthread_t tid;
- bool dead;
+ bool enabled;
uid_t ruid;
uid_t euid;
gid_t egid;
gid_t sgid;
- gid_t *groups;
int ngroups;
+ gid_t *groups;
struct uwrap_thread *next;
struct uwrap_thread *prev;
struct uwrap {
struct {
void *handle;
- struct uwrap_libc_fns fns;
+ struct uwrap_libc_symbols symbols;
} libc;
+ struct {
+ void *handle;
+ struct uwrap_libpthread_symbols symbols;
+ } libpthread;
+
bool initialised;
- bool enabled;
+ /* Real uid and gid of user who run uid wrapper */
uid_t myuid;
- uid_t mygid;
+ gid_t mygid;
struct uwrap_thread *ids;
};
/* The mutex or accessing the id */
static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
+/* The mutex for accessing the global libc.symbols */
+static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* The mutex for accessing the global libpthread.symbols */
+static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*********************************************************
+ * UWRAP PROTOTYPES
+ *********************************************************/
+
+bool uid_wrapper_enabled(void);
+void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
+void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
+
/*********************************************************
* UWRAP LIBC LOADER FUNCTIONS
*********************************************************/
UWRAP_LIBC,
UWRAP_LIBNSL,
UWRAP_LIBSOCKET,
+ UWRAP_LIBPTHREAD,
};
static void *uwrap_load_lib_handle(enum uwrap_lib lib)
void *handle = NULL;
int i;
-#ifdef HAVE_APPLE
- return RTLD_NEXT;
-#endif
-
#ifdef RTLD_DEEPBIND
flags |= RTLD_DEEPBIND;
#endif
case UWRAP_LIBSOCKET:
/* FALL TROUGH */
case UWRAP_LIBC:
+ handle = uwrap.libc.handle;
if (handle == NULL) {
- for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
+ for (i = 10; i >= 0; i--) {
char soname[256] = {0};
snprintf(soname, sizeof(soname), "libc.so.%d", i);
handle = dlopen(soname, flags);
+ 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;
- } else {
- handle = uwrap.libc.handle;
+ }
+ break;
+ case UWRAP_LIBPTHREAD:
+ handle = uwrap.libpthread.handle;
+ if (handle == NULL) {
+ handle = dlopen("libpthread.so.0", flags);
+ if (handle != NULL) {
+ break;
+ }
}
break;
}
if (handle == NULL) {
+#ifdef RTLD_NEXT
+ handle = uwrap.libc.handle = RTLD_NEXT;
+#else
fprintf(stderr,
"Failed to dlopen library: %s\n",
dlerror());
exit(-1);
+#endif
}
return handle;
}
-static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
+static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
{
void *handle;
void *func;
return func;
}
-#define uwrap_load_lib_function(lib, fn_name) \
- if (uwrap.libc.fns._libc_##fn_name == NULL) { \
- *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
- _uwrap_load_lib_function(lib, #fn_name); \
- }
+#define uwrap_bind_symbol_libc(sym_name) \
+ UWRAP_LOCK(libc_symbol_binding); \
+ if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
+ uwrap.libc.symbols._libc_##sym_name.obj = \
+ _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
+ } \
+ UWRAP_UNLOCK(libc_symbol_binding)
+
+#define uwrap_bind_symbol_libpthread(sym_name) \
+ UWRAP_LOCK(libpthread_symbol_binding); \
+ if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
+ uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
+ _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
+ } \
+ UWRAP_UNLOCK(libpthread_symbol_binding)
/*
* IMPORTANT
*/
static int libc_setuid(uid_t uid)
{
- uwrap_load_lib_function(UWRAP_LIBC, setuid);
+ uwrap_bind_symbol_libc(setuid);
- return uwrap.libc.fns._libc_setuid(uid);
+ return uwrap.libc.symbols._libc_setuid.f(uid);
}
static uid_t libc_getuid(void)
{
- uwrap_load_lib_function(UWRAP_LIBC, getuid);
+ uwrap_bind_symbol_libc(getuid);
- return uwrap.libc.fns._libc_getuid();
+ return uwrap.libc.symbols._libc_getuid.f();
}
#ifdef HAVE_SETEUID
static int libc_seteuid(uid_t euid)
{
- uwrap_load_lib_function(UWRAP_LIBC, seteuid);
+ uwrap_bind_symbol_libc(seteuid);
- return uwrap.libc.fns._libc_seteuid(euid);
+ return uwrap.libc.symbols._libc_seteuid.f(euid);
}
#endif
-static void *uwrap_libc_fn(struct uwrap *u, const char *fn_name)
+#ifdef HAVE_SETREUID
+static int libc_setreuid(uid_t ruid, uid_t euid)
{
- void *func;
+ uwrap_bind_symbol_libc(setreuid);
-#ifdef HAVE_APPLE
- func = dlsym(RTLD_NEXT, fn_name);
-#else
- if (u->libc.handle == NULL) {
- return NULL;
- }
-
- func = dlsym(u->libc.handle, fn_name);
+ return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
+}
#endif
- if (func == NULL) {
- printf("Failed to find %s in %s: %s\n",
- fn_name, LIBC_NAME, dlerror());
- exit(-1);
- }
- return func;
+#ifdef HAVE_SETRESUID
+static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+ uwrap_bind_symbol_libc(setresuid);
+
+ return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
}
+#endif
-static void uwrap_libc_init(struct uwrap *u)
+#ifdef HAVE_GETRESUID
+static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
{
- unsigned int i = 0;
-#ifndef HAVE_APPLE
- int flags = RTLD_LAZY;
+ uwrap_bind_symbol_libc(getresuid);
-#ifdef RTLD_DEEPBIND
- flags |= RTLD_DEEPBIND;
+ return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
+}
#endif
- for (u->libc.handle = NULL, i = 10; u->libc.handle == NULL; i--) {
- char soname[256] = {0};
+static uid_t libc_geteuid(void)
+{
+ uwrap_bind_symbol_libc(geteuid);
- snprintf(soname, sizeof(soname), "%s.%u", LIBC_NAME, i);
- u->libc.handle = dlopen(soname, flags);
- }
+ return uwrap.libc.symbols._libc_geteuid.f();
+}
- if (u->libc.handle == NULL) {
- printf("Failed to dlopen %s.%u: %s\n", LIBC_NAME, i, dlerror());
- exit(-1);
- }
-#endif
+static int libc_setgid(gid_t gid)
+{
+ uwrap_bind_symbol_libc(setgid);
-#ifdef HAVE_SETREUID
- *(void **) (&u->libc.fns._libc_setreuid) = uwrap_libc_fn(u, "setreuid");
-#endif
-#ifdef HAVE_SETRESUID
- *(void **) (&u->libc.fns._libc_setresuid) = uwrap_libc_fn(u, "setresuid");
-#endif
- *(void **) (&u->libc.fns._libc_geteuid) = uwrap_libc_fn(u, "geteuid");
+ return uwrap.libc.symbols._libc_setgid.f(gid);
+}
+
+static gid_t libc_getgid(void)
+{
+ uwrap_bind_symbol_libc(getgid);
+
+ return uwrap.libc.symbols._libc_getgid.f();
+}
- *(void **) (&u->libc.fns._libc_setgid) = uwrap_libc_fn(u, "setgid");
- *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
#ifdef HAVE_SETEGID
- *(void **) (&u->libc.fns._libc_setegid) = uwrap_libc_fn(u, "setegid");
+static int libc_setegid(gid_t egid)
+{
+ uwrap_bind_symbol_libc(setegid);
+
+ return uwrap.libc.symbols._libc_setegid.f(egid);
+}
#endif
+
#ifdef HAVE_SETREGID
- *(void **) (&u->libc.fns._libc_setregid) = uwrap_libc_fn(u, "setregid");
+static int libc_setregid(gid_t rgid, gid_t egid)
+{
+ uwrap_bind_symbol_libc(setregid);
+
+ return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
+}
#endif
+
#ifdef HAVE_SETRESGID
- *(void **) (&u->libc.fns._libc_setresgid) = uwrap_libc_fn(u, "setresgid");
+static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ uwrap_bind_symbol_libc(setresgid);
+
+ return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
+}
#endif
- *(void **) (&u->libc.fns._libc_getegid) = uwrap_libc_fn(u, "getegid");
- *(void **) (&u->libc.fns._libc_getgroups) = uwrap_libc_fn(u, "getgroups");
- *(void **) (&u->libc.fns._libc_setgroups) = uwrap_libc_fn(u, "setgroups");
- *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
-#ifdef HAVE_SYSCALL
- *(void **) (&u->libc.fns._libc_syscall) = uwrap_libc_fn(u, "syscall");
+
+#ifdef HAVE_GETRESGID
+static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
+{
+ uwrap_bind_symbol_libc(setresgid);
+
+ return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
+}
#endif
+
+static gid_t libc_getegid(void)
+{
+ uwrap_bind_symbol_libc(getegid);
+
+ return uwrap.libc.symbols._libc_getegid.f();
}
-static struct uwrap_thread *find_uwrap_id(pthread_t tid)
+static int libc_getgroups(int size, gid_t list[])
{
- struct uwrap_thread *id;
+ uwrap_bind_symbol_libc(getgroups);
- for (id = uwrap.ids; id; id = id->next) {
- if (pthread_equal(id->tid, tid)) {
- return id;
- }
- }
+ return uwrap.libc.symbols._libc_getgroups.f(size, list);
+}
- return NULL;
+static int libc_setgroups(size_t size, const gid_t *list)
+{
+ uwrap_bind_symbol_libc(setgroups);
+
+ return uwrap.libc.symbols._libc_setgroups.f(size, list);
}
-static int uwrap_new_id(pthread_t tid, bool do_alloc)
+#ifdef HAVE_SYSCALL
+DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
+static long int libc_vsyscall(long int sysno, va_list va)
{
- struct uwrap_thread *id = uwrap_tls_id;
+ long int args[8];
+ long int rc;
+ int i;
- if (do_alloc) {
- id = malloc(sizeof(struct uwrap_thread));
- if (id == NULL) {
- errno = ENOMEM;
- return -1;
- }
+ uwrap_bind_symbol_libc(syscall);
+
+ for (i = 0; i < 8; i++) {
+ args[i] = va_arg(va, long int);
}
- id->tid = tid;
- id->dead = false;
+ rc = uwrap.libc.symbols._libc_syscall.f(sysno,
+ args[0],
+ args[1],
+ args[2],
+ args[3],
+ args[4],
+ args[5],
+ args[6],
+ args[7]);
+
+ return rc;
+}
+#endif
- id->ruid = id->euid = id->suid = uwrap.myuid;
- id->rgid = id->egid = id->sgid = uwrap.mygid;
+/*
+ * This part is "optimistic".
+ * Thread can ends without pthread_exit call.
+ */
+static void libpthread_pthread_exit(void *retval)
+{
+ uwrap_bind_symbol_libpthread(pthread_exit);
- id->ngroups = 1;
- id->groups = malloc(sizeof(gid_t) * id->ngroups);
- id->groups[0] = uwrap.mygid;
+ uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
+}
- if (do_alloc) {
- UWRAP_DLIST_ADD(uwrap.ids, id);
- uwrap_tls_id = id;
+static void uwrap_pthread_exit(void *retval)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
+
+ UWRAP_LOCK(uwrap_id);
+ if (id == NULL) {
+ UWRAP_UNLOCK(uwrap_id);
+ libpthread_pthread_exit(retval);
+ return;
}
- return 0;
+ UWRAP_DLIST_REMOVE(uwrap.ids, id);
+ SAFE_FREE(id->groups);
+ SAFE_FREE(id);
+ uwrap_tls_id = NULL;
+
+ UWRAP_UNLOCK(uwrap_id);
+
+ libpthread_pthread_exit(retval);
}
-static void uwrap_thread_prepare(void)
+void pthread_exit(void *retval)
{
- pthread_mutex_lock(&uwrap_id_mutex);
+ if (!uid_wrapper_enabled()) {
+ libpthread_pthread_exit(retval);
+ };
- /*
- * What happens if another atfork prepare functions calls a uwrap
- * function? So disable it in case another atfork prepare function
- * calls a (s)uid function.
- */
- uwrap.enabled = false;
+ uwrap_pthread_exit(retval);
+
+ /* Calm down gcc warning. */
+ exit(666);
}
-static void uwrap_thread_parent(void)
+static int libpthread_pthread_create(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine) (void *),
+ void *arg)
{
- uwrap.enabled = true;
+ uwrap_bind_symbol_libpthread(pthread_create);
+ return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
+ attr,
+ start_routine,
+ arg);
+}
+
+struct uwrap_pthread_create_args {
+ struct uwrap_thread *id;
+ void *(*start_routine) (void *);
+ void *arg;
+};
+
+static void *uwrap_pthread_create_start(void *_a)
+{
+ struct uwrap_pthread_create_args *a =
+ (struct uwrap_pthread_create_args *)_a;
+ void *(*start_routine) (void *) = a->start_routine;
+ void *arg = a->arg;
+ struct uwrap_thread *id = a->id;
+
+ SAFE_FREE(a);
+
+ uwrap_tls_id = id;
- pthread_mutex_unlock(&uwrap_id_mutex);
+ return start_routine(arg);
}
-static void uwrap_thread_child(void)
+static int uwrap_pthread_create(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine) (void *),
+ void *arg)
{
- uwrap.enabled = true;
+ struct uwrap_pthread_create_args *args;
+ struct uwrap_thread *src_id = uwrap_tls_id;
+ int ret;
+
+ args = malloc(sizeof(struct uwrap_pthread_create_args));
+ if (args == NULL) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "uwrap_pthread_create: Unable to allocate memory");
+ errno = ENOMEM;
+ return -1;
+ }
+ args->start_routine = start_routine;
+ args->arg = arg;
+
+ args->id = calloc(1, sizeof(struct uwrap_thread));
+ if (args->id == NULL) {
+ SAFE_FREE(args);
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "uwrap_pthread_create: Unable to allocate memory");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ UWRAP_LOCK(uwrap_id);
+
+ args->id->groups = malloc(sizeof(gid_t) * src_id->ngroups);
+ if (args->id->groups == NULL) {
+ UWRAP_UNLOCK(uwrap_id);
+ SAFE_FREE(args->id);
+ SAFE_FREE(args);
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "uwrap_pthread_create: Unable to allocate memory again");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ args->id->ruid = src_id->ruid;
+ args->id->euid = src_id->euid;
+ args->id->suid = src_id->suid;
+
+ args->id->rgid = src_id->rgid;
+ args->id->egid = src_id->egid;
+ args->id->sgid = src_id->sgid;
+
+ args->id->enabled = src_id->enabled;
+
+ args->id->ngroups = src_id->ngroups;
+ if (src_id->groups != NULL) {
+ memcpy(args->id->groups, src_id->groups,
+ sizeof(gid_t) * src_id->ngroups);
+ } else {
+ SAFE_FREE(args->id->groups);
+ }
+
+ UWRAP_DLIST_ADD(uwrap.ids, args->id);
+ UWRAP_UNLOCK(uwrap_id);
+
+ ret = libpthread_pthread_create(thread, attr,
+ uwrap_pthread_create_start,
+ args);
+ if (ret != 0) {
+ return ret;
+ }
- pthread_mutex_unlock(&uwrap_id_mutex);
+ return ret;
}
-static void uwrap_init(void)
+int pthread_create(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine) (void *),
+ void *arg)
{
- const char *env = getenv("UID_WRAPPER");
- pthread_t tid = pthread_self();
+ if (!uid_wrapper_enabled()) {
+ return libpthread_pthread_create(thread,
+ attr,
+ start_routine,
+ arg);
+ };
+
+ return uwrap_pthread_create(thread,
+ attr,
+ start_routine,
+ arg);
+}
+/*********************************************************
+ * UWRAP ID HANDLING
+ *********************************************************/
+#define GROUP_STRING_SIZE 16384
+#define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
- if (uwrap.initialised) {
- struct uwrap_thread *id = uwrap_tls_id;
- int rc;
+/**
+ * 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;
- if (id != NULL) {
- return;
+ /* 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;
}
- pthread_mutex_lock(&uwrap_id_mutex);
- id = find_uwrap_id(tid);
- if (id == NULL) {
- rc = uwrap_new_id(tid, 1);
- if (rc < 0) {
- exit(-1);
- }
- } else {
- /* We reuse an old thread id */
- uwrap_tls_id = id;
+ 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;
+ }
+ }
- uwrap_new_id(tid, 0);
+ 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
+ * calls a (s)uid function. We disable uid_wrapper only for thread
+ * (process) which called fork.
+ */
+ id->enabled = false;
+}
+
+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;
+}
+
+static void uwrap_thread_child(void)
+{
+ 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
+ * That's what posix said...
+ */
+ while (u != NULL) {
+ if (u == id) {
+ /* Skip this item. */
+ u = uwrap.ids->next;
+ continue;
+ }
+
+ UWRAP_DLIST_REMOVE(uwrap.ids, u);
+
+ SAFE_FREE(u->groups);
+ SAFE_FREE(u);
+
+ 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_LOCK(uwrap_id);
+
+ if (uwrap.initialised) {
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ if (uwrap.ids == NULL) {
+ UWRAP_UNLOCK(uwrap_id);
+ return;
+ }
+
+ if (id == NULL) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "Invalid id for thread");
+ exit(-1);
+ }
+
+ UWRAP_UNLOCK(uwrap_id);
+ return;
+ }
+
+ UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
+
+ uwrap.initialised = true;
+
+ env = getenv("UID_WRAPPER");
+ if (env != NULL && env[0] == '1') {
+ const char *root = getenv("UID_WRAPPER_ROOT");
+ struct uwrap_thread *id;
+
+ id = calloc(1, sizeof(struct uwrap_thread));
+ if (id == NULL) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "Unable to allocate memory for main id");
+ exit(-1);
+ }
+
+ UWRAP_DLIST_ADD(uwrap.ids, id);
+ uwrap_tls_id = id;
+
+ uwrap.myuid = libc_geteuid();
+ uwrap.mygid = libc_getegid();
+
+ /* put us in one group */
+ if (root != NULL && root[0] == '1') {
+ id->ruid = id->euid = id->suid = 0;
+ id->rgid = id->egid = id->sgid = 0;
+
+ id->groups = malloc(sizeof(gid_t) * 1);
+ if (id->groups == NULL) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "Unable to allocate memory");
+ exit(-1);
+ }
+
+ id->ngroups = 1;
+ id->groups[0] = 0;
+
+ } else {
+ id->ruid = id->euid = id->suid = uwrap.myuid;
+ id->rgid = id->egid = id->sgid = uwrap.mygid;
+
+ id->ngroups = libc_getgroups(0, NULL);
+ if (id->ngroups == -1) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "Unable to call libc_getgroups in uwrap_init.");
+ exit(-1);
+ }
+ id->groups = malloc(sizeof(gid_t) * id->ngroups);
+ if (id->groups == NULL) {
+ UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
+ exit(-1);
+ }
+ if (libc_getgroups(id->ngroups, id->groups) == -1) {
+ UWRAP_LOG(UWRAP_LOG_ERROR,
+ "Unable to call libc_getgroups again in uwrap_init.");
+ id->groups = 0;
+ /*
+ * Deallocation of uwrap.groups is handled by
+ * library destructor.
+ */
+ exit(-1);
+ }
+ }
+
+ uwrap_init_env(id);
+
+ id->enabled = true;
+
+ UWRAP_LOG(UWRAP_LOG_DEBUG,
+ "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, "Successfully initialized uid_wrapper");
+}
+
+bool uid_wrapper_enabled(void)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+ bool enabled;
+
+ if (id == NULL) {
+ return false;
+ }
+
+ UWRAP_LOCK(uwrap_id);
+ enabled = id->enabled;
+ UWRAP_UNLOCK(uwrap_id);
+
+ return enabled;
+}
+
+/*
+ * 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_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;
+}
+
+static int uwrap_setresuid_thread(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);
+
+ 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_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)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ UWRAP_LOCK(uwrap_id);
+
+ *rgid = id->rgid;
+ *egid = id->egid;
+ *sgid = id->sgid;
+
+ UWRAP_UNLOCK(uwrap_id);
+
+ return 0;
+}
+#endif
+
+/*
+ * UWRAP_SETxGID FUNCTIONS
+ */
+
+static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
+{
+ struct uwrap_thread *id = uwrap_tls_id;
+
+ 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 (rgid != (gid_t)-1) {
+ id->rgid = rgid;
+ }
+
+ if (egid != (gid_t)-1) {
+ id->egid = egid;
}
- pthread_mutex_unlock(&uwrap_id_mutex);
- return;
+ if (sgid != (gid_t)-1) {
+ id->sgid = sgid;
+ }
}
- /*
- * If we hold a lock and the application forks, then the child
- * is not able to unlock the mutex and we are in a deadlock.
- * This should prevent such deadlocks.
- */
- pthread_atfork(&uwrap_thread_prepare,
- &uwrap_thread_parent,
- &uwrap_thread_child);
-
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
- uwrap_libc_init(&uwrap);
+ return 0;
+}
- uwrap.initialised = true;
- uwrap.enabled = false;
+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;
- if (env != NULL && env[0] == '1') {
- const char *root = getenv("UID_WRAPPER_ROOT");
- int rc;
+ UWRAP_LOG(UWRAP_LOG_TRACE,
+ "rgid %d -> %d, egid %d -> %d",
+ id->rgid, rgid, id->egid, egid);
- /* put us in one group */
- if (root != NULL && root[0] == '1') {
- uwrap.myuid = 0;
- uwrap.mygid = 0;
- } else {
- uwrap.myuid = uwrap.libc.fns._libc_geteuid();
- uwrap.mygid = uwrap.libc.fns._libc_getegid();
+ if (rgid != (gid_t)-1) {
+ new_rgid = rgid;
+ if (rgid != id->rgid &&
+ rgid != id->egid &&
+ id->euid != 0) {
+ errno = EPERM;
+ return -1;
}
+ }
- rc = uwrap_new_id(tid, 1);
- if (rc < 0) {
- exit(-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;
}
+ }
- uwrap.enabled = true;
+ if (rgid != (gid_t) -1 ||
+ (egid != (gid_t)-1 && id->rgid != egid)) {
+ new_sgid = new_egid;
}
- pthread_mutex_unlock(&uwrap_id_mutex);
+ *_new_rgid = new_rgid;
+ *_new_egid = new_egid;
+ *_new_sgid = new_sgid;
+
+ return 0;
}
-static int uwrap_enabled(void)
+static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
{
- uwrap_init();
+ struct uwrap_thread *id = uwrap_tls_id;
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
- return uwrap.enabled ? 1 : 0;
+ 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);
}
-static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
+#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;
- 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",
+ id->rgid, rgid, id->egid, egid);
- pthread_mutex_lock(&uwrap_id_mutex);
- if (ruid != (uid_t)-1) {
- id->ruid = ruid;
+ rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
}
- if (euid != (uid_t)-1) {
- id->euid = euid;
+ 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 (suid != (uid_t)-1) {
- id->suid = suid;
+ if (id->euid == 0) {
+ *new_sgid = *new_rgid = gid;
+ } else if (gid != id->rgid &&
+ gid != id->sgid) {
+ errno = EPERM;
+ return -1;
}
- pthread_mutex_unlock(&uwrap_id_mutex);
+
+ *new_egid = gid;
return 0;
}
-static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+static int uwrap_setgid_thread(gid_t gid)
{
- struct uwrap_thread *id;
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
- if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
- errno = EINVAL;
- return -1;
+ rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
}
- pthread_mutex_lock(&uwrap_id_mutex);
- for (id = uwrap.ids; id; id = id->next) {
- if (id->dead) {
- continue;
- }
-
- if (ruid != (uid_t)-1) {
- id->ruid = ruid;
- }
+ return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
+}
- if (euid != (uid_t)-1) {
- id->euid = euid;
- }
+static int uwrap_setgid(gid_t gid)
+{
+ gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
+ int rc;
- if (suid != (uid_t)-1) {
- id->suid = suid;
- }
+ rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
+ if (rc != 0) {
+ return rc;
}
- pthread_mutex_unlock(&uwrap_id_mutex);
- return 0;
+ return uwrap_setresgid(new_rgid, new_egid, new_sgid);
}
/*
*/
int setuid(uid_t uid)
{
- if (!uwrap_enabled()) {
+ if (!uid_wrapper_enabled()) {
return libc_setuid(uid);
}
- return uwrap_setresuid(uid, -1, -1);
+ uwrap_init();
+ 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 (!uwrap_enabled()) {
- return libc_seteuid(euid);
- }
-
+ uwrap_init();
return uwrap_setresuid(-1, euid, -1);
}
#endif
#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 (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setreuid(ruid, euid);
+ if (!uid_wrapper_enabled()) {
+ return libc_setreuid(ruid, euid);
}
- return uwrap_setresuid(ruid, euid, -1);
+ uwrap_init();
+ return uwrap_setreuid(ruid, euid);
}
#endif
#ifdef HAVE_SETRESUID
int setresuid(uid_t ruid, uid_t euid, uid_t suid)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
+ if (!uid_wrapper_enabled()) {
+ return libc_setresuid(ruid, euid, suid);
}
+ uwrap_init();
return uwrap_setresuid(ruid, euid, suid);
}
#endif
+#ifdef HAVE_GETRESUID
+int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
+{
+ if (!uid_wrapper_enabled()) {
+ return libc_getresuid(ruid, euid, suid);
+ }
+
+ uwrap_init();
+ return uwrap_getresuid(ruid, euid, suid);
+}
+#endif
+
/*
* GETUID
*/
struct uwrap_thread *id = uwrap_tls_id;
uid_t uid;
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_LOCK(uwrap_id);
uid = id->ruid;
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return uid;
}
uid_t getuid(void)
{
- if (!uwrap_enabled()) {
+ if (!uid_wrapper_enabled()) {
return libc_getuid();
}
+ uwrap_init();
return uwrap_getuid();
}
*/
static uid_t uwrap_geteuid(void)
{
- const char *env = getenv("UID_WRAPPER_ROOT");
+ const char *env = getenv("UID_WRAPPER_MYUID");
struct uwrap_thread *id = uwrap_tls_id;
uid_t uid;
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_LOCK(uwrap_id);
uid = id->euid;
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
/* Disable root and return myuid */
- if (env != NULL && env[0] == '2') {
+ if (env != NULL && env[0] == '1') {
uid = uwrap.myuid;
}
uid_t geteuid(void)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_geteuid();
+ if (!uid_wrapper_enabled()) {
+ return libc_geteuid();
}
+ uwrap_init();
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;
- }
-
- pthread_mutex_lock(&uwrap_id_mutex);
- if (rgid != (gid_t)-1) {
- id->rgid = rgid;
- }
-
- if (egid != (gid_t)-1) {
- id->egid = egid;
- }
-
- if (sgid != (gid_t)-1) {
- id->sgid = sgid;
- }
- pthread_mutex_unlock(&uwrap_id_mutex);
-
- 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;
- }
-
- pthread_mutex_lock(&uwrap_id_mutex);
- for (id = uwrap.ids; id; id = id->next) {
- if (id->dead) {
- continue;
- }
-
- if (rgid != (gid_t)-1) {
- id->rgid = rgid;
- }
-
- if (egid != (gid_t)-1) {
- id->egid = egid;
- }
-
- if (sgid != (gid_t)-1) {
- id->sgid = sgid;
- }
- }
- pthread_mutex_unlock(&uwrap_id_mutex);
-
- return 0;
-}
-
/*
* SETGID
*/
int setgid(gid_t gid)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setgid(gid);
+ if (!uid_wrapper_enabled()) {
+ return libc_setgid(gid);
}
- return uwrap_setresgid(gid, -1, -1);
+ uwrap_init();
+ return uwrap_setgid(gid);
}
#ifdef HAVE_SETEGID
int setegid(gid_t egid)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setegid(egid);
+ if (!uid_wrapper_enabled()) {
+ 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);
}
#endif
#ifdef HAVE_SETREGID
int setregid(gid_t rgid, gid_t egid)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setregid(rgid, egid);
+ if (!uid_wrapper_enabled()) {
+ return libc_setregid(rgid, egid);
}
- return uwrap_setresgid(rgid, egid, -1);
+ uwrap_init();
+ return uwrap_setregid(rgid, egid);
}
#endif
#ifdef HAVE_SETRESGID
int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setregid(rgid, egid, sgid);
+ if (!uid_wrapper_enabled()) {
+ return libc_setresgid(rgid, egid, sgid);
}
+ uwrap_init();
return uwrap_setresgid(rgid, egid, sgid);
}
#endif
+#ifdef HAVE_GETRESGID
+int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
+{
+ if (!uid_wrapper_enabled()) {
+ return libc_getresgid(rgid, egid, sgid);
+ }
+
+ uwrap_init();
+ return uwrap_getresgid(rgid, egid, sgid);
+}
+#endif
+
/*
* GETGID
*/
struct uwrap_thread *id = uwrap_tls_id;
gid_t gid;
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_LOCK(uwrap_id);
gid = id->rgid;
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return gid;
}
gid_t getgid(void)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_getgid();
+ if (!uid_wrapper_enabled()) {
+ return libc_getgid();
}
+ uwrap_init();
return uwrap_getgid();
}
struct uwrap_thread *id = uwrap_tls_id;
gid_t gid;
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_LOCK(uwrap_id);
gid = id->egid;
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return gid;
}
uid_t getegid(void)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_getegid();
+ if (!uid_wrapper_enabled()) {
+ return libc_getegid();
}
+ uwrap_init();
return uwrap_getegid();
}
struct uwrap_thread *id = uwrap_tls_id;
int rc = -1;
- pthread_mutex_lock(&uwrap_id_mutex);
- free(id->groups);
- id->groups = NULL;
- id->ngroups = 0;
+ UWRAP_LOCK(uwrap_id);
- if (size != 0) {
- id->groups = malloc(sizeof(gid_t) * size);
- if (id->groups == NULL) {
+ if (size == 0) {
+ SAFE_FREE(id->groups);
+ id->ngroups = 0;
+ } else if (size > 0) {
+ gid_t *tmp;
+
+ tmp = realloc(id->groups, sizeof(gid_t) * size);
+ if (tmp == NULL) {
errno = ENOMEM;
goto out;
}
+ id->groups = tmp;
id->ngroups = size;
memcpy(id->groups, list, size * sizeof(gid_t));
}
rc = 0;
out:
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return rc;
}
struct uwrap_thread *id;
int rc = -1;
- pthread_mutex_lock(&uwrap_id_mutex);
- for (id = uwrap.ids; id; id = id->next) {
- free(id->groups);
- id->groups = NULL;
- id->ngroups = 0;
+ UWRAP_LOCK(uwrap_id);
- if (size != 0) {
- id->groups = malloc(sizeof(gid_t) * size);
- if (id->groups == NULL) {
+ if (size == 0) {
+ for (id = uwrap.ids; id; id = id->next) {
+ SAFE_FREE(id->groups);
+ id->ngroups = 0;
+
+ }
+ } else if (size > 0) {
+ gid_t *tmp;
+
+ for (id = uwrap.ids; id; id = id->next) {
+ tmp = realloc(id->groups, sizeof(gid_t) * size);
+ if (tmp == NULL) {
errno = ENOMEM;
goto out;
}
+ id->groups = tmp;
+
id->ngroups = size;
memcpy(id->groups, list, size * sizeof(gid_t));
}
rc = 0;
out:
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return rc;
}
int setgroups(size_t size, const gid_t *list)
#endif
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_setgroups(size, list);
+ if (!uid_wrapper_enabled()) {
+ return libc_setgroups(size, list);
}
+ uwrap_init();
return uwrap_setgroups(size, list);
}
struct uwrap_thread *id = uwrap_tls_id;
int ngroups;
- pthread_mutex_lock(&uwrap_id_mutex);
+ UWRAP_LOCK(uwrap_id);
ngroups = id->ngroups;
if (size > ngroups) {
memcpy(list, id->groups, size * sizeof(gid_t));
out:
- pthread_mutex_unlock(&uwrap_id_mutex);
+ UWRAP_UNLOCK(uwrap_id);
return ngroups;
}
int getgroups(int size, gid_t *list)
{
- if (!uwrap_enabled()) {
- return uwrap.libc.fns._libc_getgroups(size, list);
+ if (!uid_wrapper_enabled()) {
+ return libc_getgroups(size, list);
}
+ uwrap_init();
return uwrap_getgroups(size, list);
}
-static long int libc_vsyscall(long int sysno, va_list va)
-{
- long int args[8];
- long int rc;
- int i;
-
- for (i = 0; i < 8; i++) {
- args[i] = va_arg(va, long int);
- }
-
- rc = uwrap.libc.fns._libc_syscall(sysno,
- args[0],
- args[1],
- args[2],
- args[3],
- args[4],
- args[5],
- args[6],
- args[7]);
-
- return rc;
-}
-
#if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
&& (defined(SYS_setreuid) || defined(SYS_setreuid32))
static long int uwrap_syscall (long int sysno, va_list vp)
switch (sysno) {
/* gid */
+#ifdef __alpha__
+ case SYS_getxgid:
+#else
case SYS_getgid:
+#endif
#ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getgid32:
#endif
case SYS_setgid32:
#endif
{
- gid_t gid = (gid_t) va_arg(vp, int);
+ 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:
case SYS_setregid32:
#endif
{
- uid_t rgid = (uid_t) va_arg(vp, int);
- uid_t egid = (uid_t) va_arg(vp, int);
+ 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
case SYS_setresgid32:
#endif
{
- uid_t rgid = (uid_t) va_arg(vp, int);
- uid_t egid = (uid_t) va_arg(vp, int);
- uid_t sgid = (uid_t) va_arg(vp, int);
+ gid_t rgid = (gid_t) va_arg(vp, gid_t);
+ gid_t egid = (gid_t) va_arg(vp, gid_t);
+ gid_t sgid = (gid_t) va_arg(vp, gid_t);
rc = uwrap_setresgid_thread(rgid, egid, sgid);
}
break;
#endif /* SYS_setresgid */
+#if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
+ case SYS_getresgid:
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+ case SYS_getresgid32:
+#endif
+ {
+ gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
+ gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
+ gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
+
+ rc = uwrap_getresgid(rgid, egid, sgid);
+ }
+ break;
+#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
case SYS_setuid32:
#endif
{
- uid_t uid = (uid_t) va_arg(vp, int);
+ 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:
case SYS_setreuid32:
#endif
{
- uid_t ruid = (uid_t) va_arg(vp, int);
- uid_t euid = (uid_t) va_arg(vp, int);
+ 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
case SYS_setresuid32:
#endif
{
- uid_t ruid = (uid_t) va_arg(vp, int);
- uid_t euid = (uid_t) va_arg(vp, int);
- uid_t suid = (uid_t) va_arg(vp, int);
+ uid_t ruid = (uid_t) va_arg(vp, uid_t);
+ uid_t euid = (uid_t) va_arg(vp, uid_t);
+ uid_t suid = (uid_t) va_arg(vp, uid_t);
rc = uwrap_setresuid_thread(ruid, euid, suid);
}
break;
#endif /* SYS_setresuid */
+#if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
+ case SYS_getresuid:
+#ifdef HAVE_LINUX_32BIT_SYSCALLS
+ case SYS_getresuid32:
+#endif
+ {
+ uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
+ uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
+ uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
+ rc = uwrap_getresuid(ruid, euid, suid);
+ }
+ break;
+#endif /* SYS_getresuid && HAVE_GETRESUID*/
/* groups */
case SYS_setgroups:
#ifdef HAVE_LINUX_32BIT_SYSCALLS
}
break;
default:
- UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
- "%lu\n", sysno);
+ UWRAP_LOG(UWRAP_LOG_DEBUG,
+ "UID_WRAPPER calling non-wrapped syscall %lu",
+ sysno);
rc = libc_vsyscall(sysno, vp);
break;
va_start(va, sysno);
- if (!uwrap_enabled()) {
+ if (!uid_wrapper_enabled()) {
rc = libc_vsyscall(sysno, va);
va_end(va);
return rc;
}
+ uwrap_init();
rc = uwrap_syscall(sysno, va);
va_end(va);
}
#endif /* HAVE_SYSCALL */
#endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
+
+/****************************
+ * CONSTRUCTOR
+ ***************************/
+void uwrap_constructor(void)
+{
+ /*
+ * If we hold a lock and the application forks, then the child
+ * is not able to unlock the mutex and we are in a deadlock.
+ * This should prevent such deadlocks.
+ */
+ pthread_atfork(&uwrap_thread_prepare,
+ &uwrap_thread_parent,
+ &uwrap_thread_child);
+
+ /* Here is safe place to call uwrap_init() and initialize data
+ * for main process.
+ */
+ uwrap_init();
+}
+
+/****************************
+ * DESTRUCTOR
+ ***************************/
+
+/*
+ * This function is called when the library is unloaded and makes sure that
+ * resources are freed.
+ */
+void uwrap_destructor(void)
+{
+ struct uwrap_thread *u = uwrap.ids;
+
+ UWRAP_LOCK_ALL;
+
+ while (u != NULL) {
+ UWRAP_DLIST_REMOVE(uwrap.ids, u);
+
+ SAFE_FREE(u->groups);
+ SAFE_FREE(u);
+
+ u = uwrap.ids;
+ }
+
+
+ if (uwrap.libc.handle != NULL) {
+ dlclose(uwrap.libc.handle);
+ }
+
+ if (uwrap.libpthread.handle != NULL) {
+ dlclose(uwrap.libpthread.handle);
+ }
+
+ UWRAP_UNLOCK_ALL;
+}