2 * Copyright (c) 2009 Andrew Tridgell
3 * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
46 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
47 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
49 #define DESTRUCTOR_ATTRIBUTE
50 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
53 #define UWRAP_DEBUG(...)
55 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
58 #define UWRAP_DLIST_ADD(list,item) do { \
60 (item)->prev = NULL; \
61 (item)->next = NULL; \
64 (item)->prev = NULL; \
65 (item)->next = (list); \
66 (list)->prev = (item); \
71 #define UWRAP_DLIST_REMOVE(list,item) do { \
72 if ((list) == (item)) { \
73 (list) = (item)->next; \
75 (list)->prev = NULL; \
79 (item)->prev->next = (item)->next; \
82 (item)->next->prev = (item)->prev; \
85 (item)->prev = NULL; \
86 (item)->next = NULL; \
90 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
93 #define LIBC_NAME "libc.so"
95 struct uwrap_libc_fns {
96 int (*_libc_setuid)(uid_t uid);
97 uid_t (*_libc_getuid)(void);
100 int (*_libc_seteuid)(uid_t euid);
103 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
105 #ifdef HAVE_SETRESUID
106 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
108 uid_t (*_libc_geteuid)(void);
110 int (*_libc_setgid)(gid_t gid);
111 gid_t (*_libc_getgid)(void);
113 int (*_libc_setegid)(uid_t egid);
116 int (*_libc_setregid)(uid_t rgid, uid_t egid);
118 #ifdef HAVE_SETRESGID
119 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
121 gid_t (*_libc_getegid)(void);
122 int (*_libc_getgroups)(int size, gid_t list[]);
123 int (*_libc_setgroups)(size_t size, const gid_t *list);
125 long int (*_libc_syscall)(long int sysno, ...);
130 * We keep the virtualised euid/egid/groups information here
132 struct uwrap_thread {
147 struct uwrap_thread *next;
148 struct uwrap_thread *prev;
154 struct uwrap_libc_fns fns;
163 struct uwrap_thread *ids;
166 static struct uwrap uwrap;
168 /* Shortcut to the list item */
169 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
171 /* The mutex or accessing the id */
172 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
174 /*********************************************************
176 *********************************************************/
178 bool uid_wrapper_enabled(void);
179 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
181 /*********************************************************
182 * UWRAP LIBC LOADER FUNCTIONS
183 *********************************************************/
191 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
193 int flags = RTLD_LAZY;
202 flags |= RTLD_DEEPBIND;
208 case UWRAP_LIBSOCKET:
211 handle = uwrap.libc.handle;
212 if (handle == NULL) {
213 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
214 char soname[256] = {0};
216 snprintf(soname, sizeof(soname), "libc.so.%d", i);
217 handle = dlopen(soname, flags);
220 uwrap.libc.handle = handle;
225 if (handle == NULL) {
227 "Failed to dlopen library: %s\n",
235 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
240 handle = uwrap_load_lib_handle(lib);
242 func = dlsym(handle, fn_name);
245 "Failed to find %s: %s\n",
253 #define uwrap_load_lib_function(lib, fn_name) \
254 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
255 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
256 _uwrap_load_lib_function(lib, #fn_name); \
262 * Functions expeciall from libc need to be loaded individually, you can't load
263 * all at once or gdb will segfault at startup. The same applies to valgrind and
264 * has probably something todo with with the linker.
265 * So we need load each function at the point it is called the first time.
267 static int libc_setuid(uid_t uid)
269 uwrap_load_lib_function(UWRAP_LIBC, setuid);
271 return uwrap.libc.fns._libc_setuid(uid);
274 static uid_t libc_getuid(void)
276 uwrap_load_lib_function(UWRAP_LIBC, getuid);
278 return uwrap.libc.fns._libc_getuid();
282 static int libc_seteuid(uid_t euid)
284 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
286 return uwrap.libc.fns._libc_seteuid(euid);
291 static int libc_setreuid(uid_t ruid, uid_t euid)
293 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
295 return uwrap.libc.fns._libc_setreuid(ruid, euid);
299 #ifdef HAVE_SETRESUID
300 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
302 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
304 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
308 static uid_t libc_geteuid(void)
310 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
312 return uwrap.libc.fns._libc_geteuid();
315 static int libc_setgid(gid_t gid)
317 uwrap_load_lib_function(UWRAP_LIBC, setgid);
319 return uwrap.libc.fns._libc_setgid(gid);
322 static gid_t libc_getgid(void)
324 uwrap_load_lib_function(UWRAP_LIBC, getgid);
326 return uwrap.libc.fns._libc_getgid();
330 static int libc_setegid(gid_t egid)
332 uwrap_load_lib_function(UWRAP_LIBC, setegid);
334 return uwrap.libc.fns._libc_setegid(egid);
339 static int libc_setregid(gid_t rgid, gid_t egid)
341 uwrap_load_lib_function(UWRAP_LIBC, setregid);
343 return uwrap.libc.fns._libc_setregid(rgid, egid);
347 #ifdef HAVE_SETRESGID
348 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
350 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
352 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
356 static gid_t libc_getegid(void)
358 uwrap_load_lib_function(UWRAP_LIBC, getegid);
360 return uwrap.libc.fns._libc_getegid();
363 static int libc_getgroups(int size, gid_t list[])
365 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
367 return uwrap.libc.fns._libc_getgroups(size, list);
370 static int libc_setgroups(size_t size, const gid_t *list)
372 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
374 return uwrap.libc.fns._libc_setgroups(size, list);
378 static long int libc_vsyscall(long int sysno, va_list va)
384 uwrap_load_lib_function(UWRAP_LIBC, syscall);
386 for (i = 0; i < 8; i++) {
387 args[i] = va_arg(va, long int);
390 rc = uwrap.libc.fns._libc_syscall(sysno,
404 /*********************************************************
406 *********************************************************/
408 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
410 struct uwrap_thread *id;
412 for (id = uwrap.ids; id; id = id->next) {
413 if (pthread_equal(id->tid, tid)) {
421 static int uwrap_new_id(pthread_t tid, bool do_alloc)
423 struct uwrap_thread *id = uwrap_tls_id;
426 id = malloc(sizeof(struct uwrap_thread));
432 id->groups = malloc(sizeof(gid_t) * 1);
433 if (id->groups == NULL) {
439 UWRAP_DLIST_ADD(uwrap.ids, id);
446 id->ruid = id->euid = id->suid = uwrap.myuid;
447 id->rgid = id->egid = id->sgid = uwrap.mygid;
450 id->groups[0] = uwrap.mygid;
455 static void uwrap_thread_prepare(void)
457 pthread_mutex_lock(&uwrap_id_mutex);
460 * What happens if another atfork prepare functions calls a uwrap
461 * function? So disable it in case another atfork prepare function
462 * calls a (s)uid function.
464 uwrap.enabled = false;
467 static void uwrap_thread_parent(void)
469 uwrap.enabled = true;
471 pthread_mutex_unlock(&uwrap_id_mutex);
474 static void uwrap_thread_child(void)
476 uwrap.enabled = true;
478 pthread_mutex_unlock(&uwrap_id_mutex);
481 static void uwrap_init(void)
483 const char *env = getenv("UID_WRAPPER");
484 pthread_t tid = pthread_self();
488 if (uwrap.initialised) {
489 struct uwrap_thread *id = uwrap_tls_id;
496 pthread_mutex_lock(&uwrap_id_mutex);
497 id = find_uwrap_id(tid);
499 rc = uwrap_new_id(tid, true);
504 /* We reuse an old thread id */
507 uwrap_new_id(tid, false);
509 pthread_mutex_unlock(&uwrap_id_mutex);
515 * If we hold a lock and the application forks, then the child
516 * is not able to unlock the mutex and we are in a deadlock.
517 * This should prevent such deadlocks.
519 pthread_atfork(&uwrap_thread_prepare,
520 &uwrap_thread_parent,
521 &uwrap_thread_child);
523 pthread_mutex_lock(&uwrap_id_mutex);
525 uwrap.initialised = true;
526 uwrap.enabled = false;
528 if (env != NULL && env[0] == '1') {
529 const char *root = getenv("UID_WRAPPER_ROOT");
532 /* put us in one group */
533 if (root != NULL && root[0] == '1') {
537 uwrap.myuid = libc_geteuid();
538 uwrap.mygid = libc_getegid();
541 rc = uwrap_new_id(tid, true);
546 uwrap.enabled = true;
549 pthread_mutex_unlock(&uwrap_id_mutex);
552 bool uid_wrapper_enabled(void)
556 return uwrap.enabled ? true : false;
559 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
561 struct uwrap_thread *id = uwrap_tls_id;
563 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
568 pthread_mutex_lock(&uwrap_id_mutex);
569 if (ruid != (uid_t)-1) {
573 if (euid != (uid_t)-1) {
577 if (suid != (uid_t)-1) {
580 pthread_mutex_unlock(&uwrap_id_mutex);
585 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
587 struct uwrap_thread *id;
589 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
594 pthread_mutex_lock(&uwrap_id_mutex);
595 for (id = uwrap.ids; id; id = id->next) {
600 if (ruid != (uid_t)-1) {
604 if (euid != (uid_t)-1) {
608 if (suid != (uid_t)-1) {
612 pthread_mutex_unlock(&uwrap_id_mutex);
620 int setuid(uid_t uid)
622 if (!uid_wrapper_enabled()) {
623 return libc_setuid(uid);
626 return uwrap_setresuid(uid, -1, -1);
630 int seteuid(uid_t euid)
632 if (euid == (uid_t)-1) {
637 if (!uid_wrapper_enabled()) {
638 return libc_seteuid(euid);
641 return uwrap_setresuid(-1, euid, -1);
646 int setreuid(uid_t ruid, uid_t euid)
648 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
653 if (!uid_wrapper_enabled()) {
654 return libc_setreuid(ruid, euid);
657 return uwrap_setresuid(ruid, euid, -1);
661 #ifdef HAVE_SETRESUID
662 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
664 if (!uid_wrapper_enabled()) {
665 return libc_setresuid(ruid, euid, suid);
668 return uwrap_setresuid(ruid, euid, suid);
675 static uid_t uwrap_getuid(void)
677 struct uwrap_thread *id = uwrap_tls_id;
680 pthread_mutex_lock(&uwrap_id_mutex);
682 pthread_mutex_unlock(&uwrap_id_mutex);
689 if (!uid_wrapper_enabled()) {
690 return libc_getuid();
693 return uwrap_getuid();
699 static uid_t uwrap_geteuid(void)
701 const char *env = getenv("UID_WRAPPER_MYUID");
702 struct uwrap_thread *id = uwrap_tls_id;
705 pthread_mutex_lock(&uwrap_id_mutex);
707 pthread_mutex_unlock(&uwrap_id_mutex);
709 /* Disable root and return myuid */
710 if (env != NULL && env[0] == '1') {
719 if (!uid_wrapper_enabled()) {
720 return libc_geteuid();
723 return uwrap_geteuid();
726 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
728 struct uwrap_thread *id = uwrap_tls_id;
730 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
735 pthread_mutex_lock(&uwrap_id_mutex);
736 if (rgid != (gid_t)-1) {
740 if (egid != (gid_t)-1) {
744 if (sgid != (gid_t)-1) {
747 pthread_mutex_unlock(&uwrap_id_mutex);
752 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
754 struct uwrap_thread *id;
756 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
761 pthread_mutex_lock(&uwrap_id_mutex);
762 for (id = uwrap.ids; id; id = id->next) {
767 if (rgid != (gid_t)-1) {
771 if (egid != (gid_t)-1) {
775 if (sgid != (gid_t)-1) {
779 pthread_mutex_unlock(&uwrap_id_mutex);
787 int setgid(gid_t gid)
789 if (!uid_wrapper_enabled()) {
790 return libc_setgid(gid);
793 return uwrap_setresgid(gid, -1, -1);
797 int setegid(gid_t egid)
799 if (!uid_wrapper_enabled()) {
800 return libc_setegid(egid);
803 return uwrap_setresgid(-1, egid, -1);
808 int setregid(gid_t rgid, gid_t egid)
810 if (!uid_wrapper_enabled()) {
811 return libc_setregid(rgid, egid);
814 return uwrap_setresgid(rgid, egid, -1);
818 #ifdef HAVE_SETRESGID
819 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
821 if (!uid_wrapper_enabled()) {
822 return libc_setresgid(rgid, egid, sgid);
825 return uwrap_setresgid(rgid, egid, sgid);
832 static gid_t uwrap_getgid(void)
834 struct uwrap_thread *id = uwrap_tls_id;
837 pthread_mutex_lock(&uwrap_id_mutex);
839 pthread_mutex_unlock(&uwrap_id_mutex);
846 if (!uid_wrapper_enabled()) {
847 return libc_getgid();
850 return uwrap_getgid();
856 static uid_t uwrap_getegid(void)
858 struct uwrap_thread *id = uwrap_tls_id;
861 pthread_mutex_lock(&uwrap_id_mutex);
863 pthread_mutex_unlock(&uwrap_id_mutex);
870 if (!uid_wrapper_enabled()) {
871 return libc_getegid();
874 return uwrap_getegid();
877 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
879 struct uwrap_thread *id = uwrap_tls_id;
882 pthread_mutex_lock(&uwrap_id_mutex);
887 tmp = realloc(id->groups, sizeof(gid_t) * size);
895 memcpy(id->groups, list, size * sizeof(gid_t));
900 pthread_mutex_unlock(&uwrap_id_mutex);
905 static int uwrap_setgroups(size_t size, const gid_t *list)
907 struct uwrap_thread *id;
910 pthread_mutex_lock(&uwrap_id_mutex);
913 for (id = uwrap.ids; id; id = id->next) {
916 tmp = realloc(id->groups, sizeof(gid_t) * size);
924 memcpy(id->groups, list, size * sizeof(gid_t));
930 pthread_mutex_unlock(&uwrap_id_mutex);
935 #ifdef HAVE_SETGROUPS_INT
936 int setgroups(int size, const gid_t *list)
938 int setgroups(size_t size, const gid_t *list)
941 if (!uid_wrapper_enabled()) {
942 return libc_setgroups(size, list);
945 return uwrap_setgroups(size, list);
948 static int uwrap_getgroups(int size, gid_t *list)
950 struct uwrap_thread *id = uwrap_tls_id;
953 pthread_mutex_lock(&uwrap_id_mutex);
954 ngroups = id->ngroups;
956 if (size > ngroups) {
962 if (size < ngroups) {
966 memcpy(list, id->groups, size * sizeof(gid_t));
969 pthread_mutex_unlock(&uwrap_id_mutex);
974 int getgroups(int size, gid_t *list)
976 if (!uid_wrapper_enabled()) {
977 return libc_getgroups(size, list);
980 return uwrap_getgroups(size, list);
983 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
984 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
985 static long int uwrap_syscall (long int sysno, va_list vp)
992 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1001 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1005 rc = uwrap_getegid();
1008 #endif /* SYS_getegid */
1010 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1014 gid_t gid = (gid_t) va_arg(vp, int);
1016 rc = uwrap_setresgid_thread(gid, -1, -1);
1020 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1021 case SYS_setregid32:
1024 uid_t rgid = (uid_t) va_arg(vp, int);
1025 uid_t egid = (uid_t) va_arg(vp, int);
1027 rc = uwrap_setresgid_thread(rgid, egid, -1);
1030 #ifdef SYS_setresgid
1032 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1033 case SYS_setresgid32:
1036 uid_t rgid = (uid_t) va_arg(vp, int);
1037 uid_t egid = (uid_t) va_arg(vp, int);
1038 uid_t sgid = (uid_t) va_arg(vp, int);
1040 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1043 #endif /* SYS_setresgid */
1047 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1051 rc = uwrap_getuid();
1056 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1060 rc = uwrap_geteuid();
1063 #endif /* SYS_geteuid */
1065 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1069 uid_t uid = (uid_t) va_arg(vp, int);
1071 rc = uwrap_setresuid_thread(uid, -1, -1);
1075 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1076 case SYS_setreuid32:
1079 uid_t ruid = (uid_t) va_arg(vp, int);
1080 uid_t euid = (uid_t) va_arg(vp, int);
1082 rc = uwrap_setresuid_thread(ruid, euid, -1);
1085 #ifdef SYS_setresuid
1087 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1088 case SYS_setresuid32:
1091 uid_t ruid = (uid_t) va_arg(vp, int);
1092 uid_t euid = (uid_t) va_arg(vp, int);
1093 uid_t suid = (uid_t) va_arg(vp, int);
1095 rc = uwrap_setresuid_thread(ruid, euid, suid);
1098 #endif /* SYS_setresuid */
1102 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1103 case SYS_setgroups32:
1106 size_t size = (size_t) va_arg(vp, size_t);
1107 gid_t *list = (gid_t *) va_arg(vp, int *);
1109 rc = uwrap_setgroups_thread(size, list);
1113 UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
1116 rc = libc_vsyscall(sysno, vp);
1124 #ifdef HAVE_SYSCALL_INT
1125 int syscall (int sysno, ...)
1127 long int syscall (long int sysno, ...)
1130 #ifdef HAVE_SYSCALL_INT
1137 va_start(va, sysno);
1139 if (!uid_wrapper_enabled()) {
1140 rc = libc_vsyscall(sysno, va);
1145 rc = uwrap_syscall(sysno, va);
1150 #endif /* HAVE_SYSCALL */
1151 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1153 /****************************
1155 ***************************/
1158 * This function is called when the library is unloaded and makes sure that
1159 * resources are freed.
1161 void uwrap_destructor(void)
1163 struct uwrap_thread *u = uwrap.ids;
1165 pthread_mutex_lock(&uwrap_id_mutex);
1167 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1169 SAFE_FREE(u->groups);
1174 pthread_mutex_unlock(&uwrap_id_mutex);
1176 if (uwrap.libc.handle != NULL) {
1177 dlclose(uwrap.libc.handle);