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 */
52 /* GCC have printf type attribute check. */
53 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
54 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
56 #define PRINTF_ATTRIBUTE(a,b)
57 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
60 #define UWRAP_DEBUG(...)
62 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
65 #define UWRAP_DLIST_ADD(list,item) do { \
67 (item)->prev = NULL; \
68 (item)->next = NULL; \
71 (item)->prev = NULL; \
72 (item)->next = (list); \
73 (list)->prev = (item); \
78 #define UWRAP_DLIST_REMOVE(list,item) do { \
79 if ((list) == (item)) { \
80 (list) = (item)->next; \
82 (list)->prev = NULL; \
86 (item)->prev->next = (item)->next; \
89 (item)->next->prev = (item)->prev; \
92 (item)->prev = NULL; \
93 (item)->next = NULL; \
97 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
100 #define LIBC_NAME "libc.so"
102 struct uwrap_libc_fns {
103 int (*_libc_setuid)(uid_t uid);
104 uid_t (*_libc_getuid)(void);
107 int (*_libc_seteuid)(uid_t euid);
110 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
112 #ifdef HAVE_SETRESUID
113 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
115 uid_t (*_libc_geteuid)(void);
117 int (*_libc_setgid)(gid_t gid);
118 gid_t (*_libc_getgid)(void);
120 int (*_libc_setegid)(uid_t egid);
123 int (*_libc_setregid)(uid_t rgid, uid_t egid);
125 #ifdef HAVE_SETRESGID
126 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
128 gid_t (*_libc_getegid)(void);
129 int (*_libc_getgroups)(int size, gid_t list[]);
130 int (*_libc_setgroups)(size_t size, const gid_t *list);
132 long int (*_libc_syscall)(long int sysno, ...);
137 * We keep the virtualised euid/egid/groups information here
139 struct uwrap_thread {
154 struct uwrap_thread *next;
155 struct uwrap_thread *prev;
161 struct uwrap_libc_fns fns;
170 struct uwrap_thread *ids;
173 static struct uwrap uwrap;
175 /* Shortcut to the list item */
176 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
178 /* The mutex or accessing the id */
179 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
181 /*********************************************************
183 *********************************************************/
185 bool uid_wrapper_enabled(void);
186 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
188 /*********************************************************
189 * UWRAP LIBC LOADER FUNCTIONS
190 *********************************************************/
198 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
200 int flags = RTLD_LAZY;
205 flags |= RTLD_DEEPBIND;
211 case UWRAP_LIBSOCKET:
214 handle = uwrap.libc.handle;
215 if (handle == NULL) {
216 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
217 char soname[256] = {0};
219 snprintf(soname, sizeof(soname), "libc.so.%d", i);
220 handle = dlopen(soname, flags);
223 uwrap.libc.handle = handle;
228 if (handle == NULL) {
230 handle = uwrap.libc.handle = RTLD_NEXT;
233 "Failed to dlopen library: %s\n",
242 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
247 handle = uwrap_load_lib_handle(lib);
249 func = dlsym(handle, fn_name);
252 "Failed to find %s: %s\n",
260 #define uwrap_load_lib_function(lib, fn_name) \
261 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
262 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
263 _uwrap_load_lib_function(lib, #fn_name); \
269 * Functions expeciall from libc need to be loaded individually, you can't load
270 * all at once or gdb will segfault at startup. The same applies to valgrind and
271 * has probably something todo with with the linker.
272 * So we need load each function at the point it is called the first time.
274 static int libc_setuid(uid_t uid)
276 uwrap_load_lib_function(UWRAP_LIBC, setuid);
278 return uwrap.libc.fns._libc_setuid(uid);
281 static uid_t libc_getuid(void)
283 uwrap_load_lib_function(UWRAP_LIBC, getuid);
285 return uwrap.libc.fns._libc_getuid();
289 static int libc_seteuid(uid_t euid)
291 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
293 return uwrap.libc.fns._libc_seteuid(euid);
298 static int libc_setreuid(uid_t ruid, uid_t euid)
300 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
302 return uwrap.libc.fns._libc_setreuid(ruid, euid);
306 #ifdef HAVE_SETRESUID
307 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
309 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
311 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
315 static uid_t libc_geteuid(void)
317 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
319 return uwrap.libc.fns._libc_geteuid();
322 static int libc_setgid(gid_t gid)
324 uwrap_load_lib_function(UWRAP_LIBC, setgid);
326 return uwrap.libc.fns._libc_setgid(gid);
329 static gid_t libc_getgid(void)
331 uwrap_load_lib_function(UWRAP_LIBC, getgid);
333 return uwrap.libc.fns._libc_getgid();
337 static int libc_setegid(gid_t egid)
339 uwrap_load_lib_function(UWRAP_LIBC, setegid);
341 return uwrap.libc.fns._libc_setegid(egid);
346 static int libc_setregid(gid_t rgid, gid_t egid)
348 uwrap_load_lib_function(UWRAP_LIBC, setregid);
350 return uwrap.libc.fns._libc_setregid(rgid, egid);
354 #ifdef HAVE_SETRESGID
355 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
357 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
359 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
363 static gid_t libc_getegid(void)
365 uwrap_load_lib_function(UWRAP_LIBC, getegid);
367 return uwrap.libc.fns._libc_getegid();
370 static int libc_getgroups(int size, gid_t list[])
372 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
374 return uwrap.libc.fns._libc_getgroups(size, list);
377 static int libc_setgroups(size_t size, const gid_t *list)
379 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
381 return uwrap.libc.fns._libc_setgroups(size, list);
385 static long int libc_vsyscall(long int sysno, va_list va)
391 uwrap_load_lib_function(UWRAP_LIBC, syscall);
393 for (i = 0; i < 8; i++) {
394 args[i] = va_arg(va, long int);
397 rc = uwrap.libc.fns._libc_syscall(sysno,
411 /*********************************************************
413 *********************************************************/
415 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
417 struct uwrap_thread *id;
419 for (id = uwrap.ids; id; id = id->next) {
420 if (pthread_equal(id->tid, tid)) {
428 static int uwrap_new_id(pthread_t tid, bool do_alloc)
430 struct uwrap_thread *id = uwrap_tls_id;
433 id = malloc(sizeof(struct uwrap_thread));
439 id->groups = malloc(sizeof(gid_t) * 1);
440 if (id->groups == NULL) {
446 UWRAP_DLIST_ADD(uwrap.ids, id);
453 id->ruid = id->euid = id->suid = uwrap.myuid;
454 id->rgid = id->egid = id->sgid = uwrap.mygid;
457 id->groups[0] = uwrap.mygid;
462 static void uwrap_thread_prepare(void)
464 pthread_mutex_lock(&uwrap_id_mutex);
467 * What happens if another atfork prepare functions calls a uwrap
468 * function? So disable it in case another atfork prepare function
469 * calls a (s)uid function.
471 uwrap.enabled = false;
474 static void uwrap_thread_parent(void)
476 uwrap.enabled = true;
478 pthread_mutex_unlock(&uwrap_id_mutex);
481 static void uwrap_thread_child(void)
483 uwrap.enabled = true;
485 pthread_mutex_unlock(&uwrap_id_mutex);
488 static void uwrap_init(void)
490 const char *env = getenv("UID_WRAPPER");
491 pthread_t tid = pthread_self();
495 if (uwrap.initialised) {
496 struct uwrap_thread *id = uwrap_tls_id;
503 pthread_mutex_lock(&uwrap_id_mutex);
504 id = find_uwrap_id(tid);
506 rc = uwrap_new_id(tid, true);
511 /* We reuse an old thread id */
514 uwrap_new_id(tid, false);
516 pthread_mutex_unlock(&uwrap_id_mutex);
522 * If we hold a lock and the application forks, then the child
523 * is not able to unlock the mutex and we are in a deadlock.
524 * This should prevent such deadlocks.
526 pthread_atfork(&uwrap_thread_prepare,
527 &uwrap_thread_parent,
528 &uwrap_thread_child);
530 pthread_mutex_lock(&uwrap_id_mutex);
532 uwrap.initialised = true;
533 uwrap.enabled = false;
535 if (env != NULL && env[0] == '1') {
536 const char *root = getenv("UID_WRAPPER_ROOT");
539 /* put us in one group */
540 if (root != NULL && root[0] == '1') {
544 uwrap.myuid = libc_geteuid();
545 uwrap.mygid = libc_getegid();
548 rc = uwrap_new_id(tid, true);
553 uwrap.enabled = true;
556 pthread_mutex_unlock(&uwrap_id_mutex);
559 bool uid_wrapper_enabled(void)
563 return uwrap.enabled ? true : false;
566 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
568 struct uwrap_thread *id = uwrap_tls_id;
570 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
575 pthread_mutex_lock(&uwrap_id_mutex);
576 if (ruid != (uid_t)-1) {
580 if (euid != (uid_t)-1) {
584 if (suid != (uid_t)-1) {
587 pthread_mutex_unlock(&uwrap_id_mutex);
592 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
594 struct uwrap_thread *id;
596 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
601 pthread_mutex_lock(&uwrap_id_mutex);
602 for (id = uwrap.ids; id; id = id->next) {
607 if (ruid != (uid_t)-1) {
611 if (euid != (uid_t)-1) {
615 if (suid != (uid_t)-1) {
619 pthread_mutex_unlock(&uwrap_id_mutex);
627 int setuid(uid_t uid)
629 if (!uid_wrapper_enabled()) {
630 return libc_setuid(uid);
633 return uwrap_setresuid(uid, -1, -1);
637 int seteuid(uid_t euid)
639 if (euid == (uid_t)-1) {
644 if (!uid_wrapper_enabled()) {
645 return libc_seteuid(euid);
648 return uwrap_setresuid(-1, euid, -1);
653 int setreuid(uid_t ruid, uid_t euid)
655 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
660 if (!uid_wrapper_enabled()) {
661 return libc_setreuid(ruid, euid);
664 return uwrap_setresuid(ruid, euid, -1);
668 #ifdef HAVE_SETRESUID
669 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
671 if (!uid_wrapper_enabled()) {
672 return libc_setresuid(ruid, euid, suid);
675 return uwrap_setresuid(ruid, euid, suid);
682 static uid_t uwrap_getuid(void)
684 struct uwrap_thread *id = uwrap_tls_id;
687 pthread_mutex_lock(&uwrap_id_mutex);
689 pthread_mutex_unlock(&uwrap_id_mutex);
696 if (!uid_wrapper_enabled()) {
697 return libc_getuid();
700 return uwrap_getuid();
706 static uid_t uwrap_geteuid(void)
708 const char *env = getenv("UID_WRAPPER_MYUID");
709 struct uwrap_thread *id = uwrap_tls_id;
712 pthread_mutex_lock(&uwrap_id_mutex);
714 pthread_mutex_unlock(&uwrap_id_mutex);
716 /* Disable root and return myuid */
717 if (env != NULL && env[0] == '1') {
726 if (!uid_wrapper_enabled()) {
727 return libc_geteuid();
730 return uwrap_geteuid();
733 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
735 struct uwrap_thread *id = uwrap_tls_id;
737 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
742 pthread_mutex_lock(&uwrap_id_mutex);
743 if (rgid != (gid_t)-1) {
747 if (egid != (gid_t)-1) {
751 if (sgid != (gid_t)-1) {
754 pthread_mutex_unlock(&uwrap_id_mutex);
759 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
761 struct uwrap_thread *id;
763 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
768 pthread_mutex_lock(&uwrap_id_mutex);
769 for (id = uwrap.ids; id; id = id->next) {
774 if (rgid != (gid_t)-1) {
778 if (egid != (gid_t)-1) {
782 if (sgid != (gid_t)-1) {
786 pthread_mutex_unlock(&uwrap_id_mutex);
794 int setgid(gid_t gid)
796 if (!uid_wrapper_enabled()) {
797 return libc_setgid(gid);
800 return uwrap_setresgid(gid, -1, -1);
804 int setegid(gid_t egid)
806 if (!uid_wrapper_enabled()) {
807 return libc_setegid(egid);
810 return uwrap_setresgid(-1, egid, -1);
815 int setregid(gid_t rgid, gid_t egid)
817 if (!uid_wrapper_enabled()) {
818 return libc_setregid(rgid, egid);
821 return uwrap_setresgid(rgid, egid, -1);
825 #ifdef HAVE_SETRESGID
826 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
828 if (!uid_wrapper_enabled()) {
829 return libc_setresgid(rgid, egid, sgid);
832 return uwrap_setresgid(rgid, egid, sgid);
839 static gid_t uwrap_getgid(void)
841 struct uwrap_thread *id = uwrap_tls_id;
844 pthread_mutex_lock(&uwrap_id_mutex);
846 pthread_mutex_unlock(&uwrap_id_mutex);
853 if (!uid_wrapper_enabled()) {
854 return libc_getgid();
857 return uwrap_getgid();
863 static uid_t uwrap_getegid(void)
865 struct uwrap_thread *id = uwrap_tls_id;
868 pthread_mutex_lock(&uwrap_id_mutex);
870 pthread_mutex_unlock(&uwrap_id_mutex);
877 if (!uid_wrapper_enabled()) {
878 return libc_getegid();
881 return uwrap_getegid();
884 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
886 struct uwrap_thread *id = uwrap_tls_id;
889 pthread_mutex_lock(&uwrap_id_mutex);
894 tmp = realloc(id->groups, sizeof(gid_t) * size);
902 memcpy(id->groups, list, size * sizeof(gid_t));
907 pthread_mutex_unlock(&uwrap_id_mutex);
912 static int uwrap_setgroups(size_t size, const gid_t *list)
914 struct uwrap_thread *id;
917 pthread_mutex_lock(&uwrap_id_mutex);
920 for (id = uwrap.ids; id; id = id->next) {
923 tmp = realloc(id->groups, sizeof(gid_t) * size);
931 memcpy(id->groups, list, size * sizeof(gid_t));
937 pthread_mutex_unlock(&uwrap_id_mutex);
942 #ifdef HAVE_SETGROUPS_INT
943 int setgroups(int size, const gid_t *list)
945 int setgroups(size_t size, const gid_t *list)
948 if (!uid_wrapper_enabled()) {
949 return libc_setgroups(size, list);
952 return uwrap_setgroups(size, list);
955 static int uwrap_getgroups(int size, gid_t *list)
957 struct uwrap_thread *id = uwrap_tls_id;
960 pthread_mutex_lock(&uwrap_id_mutex);
961 ngroups = id->ngroups;
963 if (size > ngroups) {
969 if (size < ngroups) {
973 memcpy(list, id->groups, size * sizeof(gid_t));
976 pthread_mutex_unlock(&uwrap_id_mutex);
981 int getgroups(int size, gid_t *list)
983 if (!uid_wrapper_enabled()) {
984 return libc_getgroups(size, list);
987 return uwrap_getgroups(size, list);
990 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
991 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
992 static long int uwrap_syscall (long int sysno, va_list vp)
999 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1003 rc = uwrap_getgid();
1008 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1012 rc = uwrap_getegid();
1015 #endif /* SYS_getegid */
1017 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1021 gid_t gid = (gid_t) va_arg(vp, int);
1023 rc = uwrap_setresgid_thread(gid, -1, -1);
1027 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1028 case SYS_setregid32:
1031 uid_t rgid = (uid_t) va_arg(vp, int);
1032 uid_t egid = (uid_t) va_arg(vp, int);
1034 rc = uwrap_setresgid_thread(rgid, egid, -1);
1037 #ifdef SYS_setresgid
1039 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1040 case SYS_setresgid32:
1043 uid_t rgid = (uid_t) va_arg(vp, int);
1044 uid_t egid = (uid_t) va_arg(vp, int);
1045 uid_t sgid = (uid_t) va_arg(vp, int);
1047 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1050 #endif /* SYS_setresgid */
1054 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1058 rc = uwrap_getuid();
1063 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1067 rc = uwrap_geteuid();
1070 #endif /* SYS_geteuid */
1072 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1076 uid_t uid = (uid_t) va_arg(vp, int);
1078 rc = uwrap_setresuid_thread(uid, -1, -1);
1082 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1083 case SYS_setreuid32:
1086 uid_t ruid = (uid_t) va_arg(vp, int);
1087 uid_t euid = (uid_t) va_arg(vp, int);
1089 rc = uwrap_setresuid_thread(ruid, euid, -1);
1092 #ifdef SYS_setresuid
1094 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1095 case SYS_setresuid32:
1098 uid_t ruid = (uid_t) va_arg(vp, int);
1099 uid_t euid = (uid_t) va_arg(vp, int);
1100 uid_t suid = (uid_t) va_arg(vp, int);
1102 rc = uwrap_setresuid_thread(ruid, euid, suid);
1105 #endif /* SYS_setresuid */
1109 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1110 case SYS_setgroups32:
1113 size_t size = (size_t) va_arg(vp, size_t);
1114 gid_t *list = (gid_t *) va_arg(vp, int *);
1116 rc = uwrap_setgroups_thread(size, list);
1120 UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
1123 rc = libc_vsyscall(sysno, vp);
1131 #ifdef HAVE_SYSCALL_INT
1132 int syscall (int sysno, ...)
1134 long int syscall (long int sysno, ...)
1137 #ifdef HAVE_SYSCALL_INT
1144 va_start(va, sysno);
1146 if (!uid_wrapper_enabled()) {
1147 rc = libc_vsyscall(sysno, va);
1152 rc = uwrap_syscall(sysno, va);
1157 #endif /* HAVE_SYSCALL */
1158 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1160 /****************************
1162 ***************************/
1165 * This function is called when the library is unloaded and makes sure that
1166 * resources are freed.
1168 void uwrap_destructor(void)
1170 struct uwrap_thread *u = uwrap.ids;
1172 pthread_mutex_lock(&uwrap_id_mutex);
1174 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1176 SAFE_FREE(u->groups);
1181 pthread_mutex_unlock(&uwrap_id_mutex);
1183 if (uwrap.libc.handle != NULL) {
1184 dlclose(uwrap.libc.handle);