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 # define UWRAP_LOCK(m) do { \
47 pthread_mutex_lock(&( m ## _mutex)); \
50 # define UWRAP_UNLOCK(m) do { \
51 pthread_mutex_unlock(&( m ## _mutex)); \
54 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
55 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
57 #define CONSTRUCTOR_ATTRIBUTE
58 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
60 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
61 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
63 #define DESTRUCTOR_ATTRIBUTE
64 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
66 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
67 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
68 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
69 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
70 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
72 /* GCC have printf type attribute check. */
73 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
74 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
76 #define PRINTF_ATTRIBUTE(a,b)
77 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
79 #define UWRAP_DLIST_ADD(list,item) do { \
81 (item)->prev = NULL; \
82 (item)->next = NULL; \
85 (item)->prev = NULL; \
86 (item)->next = (list); \
87 (list)->prev = (item); \
92 #define UWRAP_DLIST_REMOVE(list,item) do { \
93 if ((list) == (item)) { \
94 (list) = (item)->next; \
96 (list)->prev = NULL; \
100 (item)->prev->next = (item)->next; \
102 if ((item)->next) { \
103 (item)->next->prev = (item)->prev; \
106 (item)->prev = NULL; \
107 (item)->next = NULL; \
111 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
118 enum uwrap_dbglvl_e {
126 # define UWRAP_LOG(...)
128 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
129 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __VA_ARGS__)
131 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
136 unsigned int lvl = 0;
138 d = getenv("UID_WRAPPER_DEBUGLEVEL");
143 va_start(va, format);
144 vsnprintf(buffer, sizeof(buffer), format, va);
149 case UWRAP_LOG_ERROR:
151 "UWRAP_ERROR(%d): %s\n",
152 (int)getpid(), buffer);
156 "UWRAP_WARN(%d): %s\n",
157 (int)getpid(), buffer);
159 case UWRAP_LOG_DEBUG:
161 "UWRAP_DEBUG(%d): %s\n",
162 (int)getpid(), buffer);
164 case UWRAP_LOG_TRACE:
166 "UWRAP_TRACE(%d): %s\n",
167 (int)getpid(), buffer);
178 #define LIBC_NAME "libc.so"
180 struct uwrap_libc_fns {
181 int (*_libc_setuid)(uid_t uid);
182 uid_t (*_libc_getuid)(void);
185 int (*_libc_seteuid)(uid_t euid);
188 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
190 #ifdef HAVE_SETRESUID
191 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
193 uid_t (*_libc_geteuid)(void);
195 int (*_libc_setgid)(gid_t gid);
196 gid_t (*_libc_getgid)(void);
198 int (*_libc_setegid)(uid_t egid);
201 int (*_libc_setregid)(uid_t rgid, uid_t egid);
203 #ifdef HAVE_SETRESGID
204 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
206 gid_t (*_libc_getegid)(void);
207 int (*_libc_getgroups)(int size, gid_t list[]);
208 int (*_libc_setgroups)(size_t size, const gid_t *list);
210 long int (*_libc_syscall)(long int sysno, ...);
215 * We keep the virtualised euid/egid/groups information here
217 struct uwrap_thread {
232 struct uwrap_thread *next;
233 struct uwrap_thread *prev;
241 struct uwrap_libc_fns fns;
258 /* Real uid and gid of user who run uid wrapper */
262 struct uwrap_thread *ids;
265 static struct uwrap uwrap;
267 /* Shortcut to the list item */
268 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
270 /* The mutex or accessing the id */
271 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
273 /* The mutex for accessing the global libc.fns */
274 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
276 /*********************************************************
278 *********************************************************/
280 bool uid_wrapper_enabled(void);
281 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
282 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
284 /*********************************************************
285 * UWRAP LIBC LOADER FUNCTIONS
286 *********************************************************/
294 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
296 int flags = RTLD_LAZY;
301 flags |= RTLD_DEEPBIND;
307 case UWRAP_LIBSOCKET:
310 handle = uwrap.libc.handle;
311 if (handle == NULL) {
312 for (i = 10; i >= 0; i--) {
313 char soname[256] = {0};
315 snprintf(soname, sizeof(soname), "libc.so.%d", i);
316 handle = dlopen(soname, flags);
317 if (handle != NULL) {
322 uwrap.libc.handle = handle;
327 if (handle == NULL) {
329 handle = uwrap.libc.handle = RTLD_NEXT;
332 "Failed to dlopen library: %s\n",
341 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
346 handle = uwrap_load_lib_handle(lib);
348 func = dlsym(handle, fn_name);
351 "Failed to find %s: %s\n",
359 #define uwrap_load_lib_function(lib, fn_name) \
360 UWRAP_LOCK(libc_symbol_binding); \
361 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
362 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
363 _uwrap_load_lib_function(lib, #fn_name); \
365 UWRAP_UNLOCK(libc_symbol_binding)
370 * Functions expeciall from libc need to be loaded individually, you can't load
371 * all at once or gdb will segfault at startup. The same applies to valgrind and
372 * has probably something todo with with the linker.
373 * So we need load each function at the point it is called the first time.
375 static int libc_setuid(uid_t uid)
377 uwrap_load_lib_function(UWRAP_LIBC, setuid);
379 return uwrap.libc.fns._libc_setuid(uid);
382 static uid_t libc_getuid(void)
384 uwrap_load_lib_function(UWRAP_LIBC, getuid);
386 return uwrap.libc.fns._libc_getuid();
390 static int libc_seteuid(uid_t euid)
392 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
394 return uwrap.libc.fns._libc_seteuid(euid);
399 static int libc_setreuid(uid_t ruid, uid_t euid)
401 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
403 return uwrap.libc.fns._libc_setreuid(ruid, euid);
407 #ifdef HAVE_SETRESUID
408 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
410 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
412 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
416 static uid_t libc_geteuid(void)
418 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
420 return uwrap.libc.fns._libc_geteuid();
423 static int libc_setgid(gid_t gid)
425 uwrap_load_lib_function(UWRAP_LIBC, setgid);
427 return uwrap.libc.fns._libc_setgid(gid);
430 static gid_t libc_getgid(void)
432 uwrap_load_lib_function(UWRAP_LIBC, getgid);
434 return uwrap.libc.fns._libc_getgid();
438 static int libc_setegid(gid_t egid)
440 uwrap_load_lib_function(UWRAP_LIBC, setegid);
442 return uwrap.libc.fns._libc_setegid(egid);
447 static int libc_setregid(gid_t rgid, gid_t egid)
449 uwrap_load_lib_function(UWRAP_LIBC, setregid);
451 return uwrap.libc.fns._libc_setregid(rgid, egid);
455 #ifdef HAVE_SETRESGID
456 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
458 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
460 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
464 static gid_t libc_getegid(void)
466 uwrap_load_lib_function(UWRAP_LIBC, getegid);
468 return uwrap.libc.fns._libc_getegid();
471 static int libc_getgroups(int size, gid_t list[])
473 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
475 return uwrap.libc.fns._libc_getgroups(size, list);
478 static int libc_setgroups(size_t size, const gid_t *list)
480 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
482 return uwrap.libc.fns._libc_setgroups(size, list);
486 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
487 static long int libc_vsyscall(long int sysno, va_list va)
493 uwrap_load_lib_function(UWRAP_LIBC, syscall);
495 for (i = 0; i < 8; i++) {
496 args[i] = va_arg(va, long int);
499 rc = uwrap.libc.fns._libc_syscall(sysno,
513 /*********************************************************
515 *********************************************************/
517 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
519 struct uwrap_thread *id;
521 for (id = uwrap.ids; id; id = id->next) {
522 if (pthread_equal(id->tid, tid)) {
530 static int uwrap_new_id(pthread_t tid, bool do_alloc)
532 struct uwrap_thread *id = uwrap_tls_id;
535 id = malloc(sizeof(struct uwrap_thread));
537 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
542 id->groups = malloc(sizeof(gid_t) * uwrap.ngroups);
543 if (id->groups == NULL) {
544 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
550 UWRAP_DLIST_ADD(uwrap.ids, id);
557 id->ruid = uwrap.ruid;
558 id->euid = uwrap.euid;
559 id->suid = uwrap.suid;
561 id->rgid = uwrap.rgid;
562 id->egid = uwrap.egid;
563 id->sgid = uwrap.sgid;
565 id->ngroups = uwrap.ngroups;
566 if (uwrap.groups != NULL) {
567 memcpy(id->groups, uwrap.groups, sizeof(gid_t) * uwrap.ngroups);
575 static void uwrap_thread_prepare(void)
577 UWRAP_LOCK(uwrap_id);
578 UWRAP_LOCK(libc_symbol_binding);
580 * What happens if another atfork prepare functions calls a uwrap
581 * function? So disable it in case another atfork prepare function
582 * calls a (s)uid function.
584 uwrap.enabled = false;
587 static void uwrap_thread_parent(void)
589 uwrap.enabled = true;
591 UWRAP_UNLOCK(libc_symbol_binding);
592 UWRAP_UNLOCK(uwrap_id);
595 static void uwrap_thread_child(void)
597 uwrap.enabled = true;
599 /* We need to update to the new tid if we fork */
600 uwrap.tid = pthread_self();
602 UWRAP_UNLOCK(libc_symbol_binding);
603 UWRAP_UNLOCK(uwrap_id);
606 static void uwrap_init(void)
609 pthread_t tid = pthread_self();
611 UWRAP_LOCK(uwrap_id);
612 if (uwrap.initialised) {
613 struct uwrap_thread *id = uwrap_tls_id;
617 UWRAP_UNLOCK(uwrap_id);
621 id = find_uwrap_id(tid);
623 rc = uwrap_new_id(tid, true);
628 /* We reuse an old thread id */
631 uwrap_new_id(tid, false);
633 UWRAP_UNLOCK(uwrap_id);
638 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
640 uwrap.initialised = true;
641 uwrap.enabled = false;
643 env = getenv("UID_WRAPPER");
644 if (env != NULL && env[0] == '1') {
645 const char *root = getenv("UID_WRAPPER_ROOT");
648 uwrap.myuid = libc_geteuid();
649 uwrap.mygid = libc_getegid();
650 /* put us in one group */
651 if (root != NULL && root[0] == '1') {
652 uwrap.ruid = uwrap.euid = uwrap.suid = 0;
653 uwrap.rgid = uwrap.egid = uwrap.sgid = 0;
655 uwrap.groups = malloc(sizeof(gid_t) * 1);
656 if (uwrap.groups == NULL) {
657 UWRAP_LOG(UWRAP_LOG_ERROR,
658 "Unable to allocate memory");
666 uwrap.ruid = uwrap.euid = uwrap.suid = uwrap.myuid;
667 uwrap.rgid = uwrap.egid = uwrap.sgid = uwrap.mygid;
669 uwrap.ngroups = libc_getgroups(0, NULL);
670 if (uwrap.ngroups == -1) {
671 UWRAP_LOG(UWRAP_LOG_ERROR,
672 "Unable to call libc_getgroups in uwrap_init.");
675 uwrap.groups = malloc(sizeof(gid_t) * uwrap.ngroups);
676 if (uwrap.groups == NULL) {
677 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
680 if (libc_getgroups(uwrap.ngroups, uwrap.groups) == -1) {
681 UWRAP_LOG(UWRAP_LOG_ERROR,
682 "Unable to call libc_getgroups again in uwrap_init.");
685 * Deallocation of uwrap.groups is handled by
686 * library destructor.
692 rc = uwrap_new_id(tid, true);
698 uwrap.enabled = true;
700 UWRAP_LOG(UWRAP_LOG_DEBUG,
701 "Enabled uid_wrapper as %s",
702 uwrap.myuid == 0 ? "root" : "user");
705 UWRAP_UNLOCK(uwrap_id);
707 UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
710 bool uid_wrapper_enabled(void)
712 bool enabled = false;
713 #ifdef HAVE_GCC_ATOMIC_BUILTINS
714 __atomic_load(&uwrap.enabled, &enabled, __ATOMIC_RELAXED);
716 UWRAP_LOCK(uwrap_id);
717 enabled = uwrap.enabled;
718 UWRAP_UNLOCK(uwrap_id);
723 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
725 struct uwrap_thread *id = uwrap_tls_id;
727 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
732 UWRAP_LOCK(uwrap_id);
733 if (ruid != (uid_t)-1) {
737 if (euid != (uid_t)-1) {
741 if (suid != (uid_t)-1) {
745 /* Check If syscall is called from main thread. */
746 if (pthread_equal(id->tid, uwrap.tid)) {
747 if (ruid != (uid_t)-1) {
751 if (euid != (uid_t)-1) {
755 if (suid != (uid_t)-1) {
760 UWRAP_UNLOCK(uwrap_id);
765 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
767 struct uwrap_thread *id;
769 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
774 UWRAP_LOCK(uwrap_id);
775 for (id = uwrap.ids; id; id = id->next) {
780 if (ruid != (uid_t)-1) {
784 if (euid != (uid_t)-1) {
788 if (suid != (uid_t)-1) {
793 /* Reflect changes in thread to main process. */
794 if (ruid != (uid_t)-1) {
798 if (euid != (uid_t)-1) {
802 if (suid != (uid_t)-1) {
806 UWRAP_UNLOCK(uwrap_id);
814 int setuid(uid_t uid)
816 if (!uid_wrapper_enabled()) {
817 return libc_setuid(uid);
821 return uwrap_setresuid(uid, -1, -1);
825 int seteuid(uid_t euid)
827 if (euid == (uid_t)-1) {
832 if (!uid_wrapper_enabled()) {
833 return libc_seteuid(euid);
837 return uwrap_setresuid(-1, euid, -1);
842 int setreuid(uid_t ruid, uid_t euid)
844 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
849 if (!uid_wrapper_enabled()) {
850 return libc_setreuid(ruid, euid);
854 return uwrap_setresuid(ruid, euid, -1);
858 #ifdef HAVE_SETRESUID
859 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
861 if (!uid_wrapper_enabled()) {
862 return libc_setresuid(ruid, euid, suid);
866 return uwrap_setresuid(ruid, euid, suid);
873 static uid_t uwrap_getuid(void)
875 struct uwrap_thread *id = uwrap_tls_id;
878 UWRAP_LOCK(uwrap_id);
880 UWRAP_UNLOCK(uwrap_id);
887 if (!uid_wrapper_enabled()) {
888 return libc_getuid();
892 return uwrap_getuid();
898 static uid_t uwrap_geteuid(void)
900 const char *env = getenv("UID_WRAPPER_MYUID");
901 struct uwrap_thread *id = uwrap_tls_id;
904 UWRAP_LOCK(uwrap_id);
906 UWRAP_UNLOCK(uwrap_id);
908 /* Disable root and return myuid */
909 if (env != NULL && env[0] == '1') {
918 if (!uid_wrapper_enabled()) {
919 return libc_geteuid();
923 return uwrap_geteuid();
926 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
928 struct uwrap_thread *id = uwrap_tls_id;
930 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
935 UWRAP_LOCK(uwrap_id);
936 if (rgid != (gid_t)-1) {
940 if (egid != (gid_t)-1) {
944 if (sgid != (gid_t)-1) {
948 if (pthread_equal(id->tid, uwrap.tid)) {
949 if (rgid != (gid_t)-1) {
953 if (egid != (gid_t)-1) {
957 if (sgid != (gid_t)-1) {
961 UWRAP_UNLOCK(uwrap_id);
966 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
968 struct uwrap_thread *id;
970 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
975 UWRAP_LOCK(uwrap_id);
976 for (id = uwrap.ids; id; id = id->next) {
981 if (rgid != (gid_t)-1) {
985 if (egid != (gid_t)-1) {
989 if (sgid != (gid_t)-1) {
994 /* Reflect changes in thread to main process. */
995 if (rgid != (gid_t)-1) {
999 if (egid != (gid_t)-1) {
1003 if (sgid != (gid_t)-1) {
1006 UWRAP_UNLOCK(uwrap_id);
1014 int setgid(gid_t gid)
1016 if (!uid_wrapper_enabled()) {
1017 return libc_setgid(gid);
1021 return uwrap_setresgid(gid, -1, -1);
1025 int setegid(gid_t egid)
1027 if (!uid_wrapper_enabled()) {
1028 return libc_setegid(egid);
1032 return uwrap_setresgid(-1, egid, -1);
1036 #ifdef HAVE_SETREGID
1037 int setregid(gid_t rgid, gid_t egid)
1039 if (!uid_wrapper_enabled()) {
1040 return libc_setregid(rgid, egid);
1044 return uwrap_setresgid(rgid, egid, -1);
1048 #ifdef HAVE_SETRESGID
1049 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1051 if (!uid_wrapper_enabled()) {
1052 return libc_setresgid(rgid, egid, sgid);
1056 return uwrap_setresgid(rgid, egid, sgid);
1063 static gid_t uwrap_getgid(void)
1065 struct uwrap_thread *id = uwrap_tls_id;
1068 UWRAP_LOCK(uwrap_id);
1070 UWRAP_UNLOCK(uwrap_id);
1077 if (!uid_wrapper_enabled()) {
1078 return libc_getgid();
1082 return uwrap_getgid();
1088 static uid_t uwrap_getegid(void)
1090 struct uwrap_thread *id = uwrap_tls_id;
1093 UWRAP_LOCK(uwrap_id);
1095 UWRAP_UNLOCK(uwrap_id);
1102 if (!uid_wrapper_enabled()) {
1103 return libc_getegid();
1107 return uwrap_getegid();
1110 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1112 struct uwrap_thread *id = uwrap_tls_id;
1115 UWRAP_LOCK(uwrap_id);
1118 SAFE_FREE(id->groups);
1120 if (pthread_equal(id->tid, uwrap.tid)) {
1121 SAFE_FREE(uwrap.groups);
1124 } else if (size > 0) {
1127 tmp = realloc(id->groups, sizeof(gid_t) * size);
1134 memcpy(id->groups, list, size * sizeof(gid_t));
1136 if (pthread_equal(id->tid, uwrap.tid)) {
1137 tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1139 /* How to return back id->groups? */
1145 uwrap.ngroups = size;
1146 memcpy(uwrap.groups, list, size * sizeof(gid_t));
1152 UWRAP_UNLOCK(uwrap_id);
1157 static int uwrap_setgroups(size_t size, const gid_t *list)
1159 struct uwrap_thread *id;
1162 UWRAP_LOCK(uwrap_id);
1165 for (id = uwrap.ids; id; id = id->next) {
1166 SAFE_FREE(id->groups);
1170 SAFE_FREE(uwrap.groups);
1172 } else if (size > 0) {
1175 for (id = uwrap.ids; id; id = id->next) {
1176 tmp = realloc(id->groups, sizeof(gid_t) * size);
1184 memcpy(id->groups, list, size * sizeof(gid_t));
1187 tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1189 /* How to return back id->groups? */
1195 uwrap.ngroups = size;
1196 memcpy(uwrap.groups, list, size * sizeof(gid_t));
1202 UWRAP_UNLOCK(uwrap_id);
1207 #ifdef HAVE_SETGROUPS_INT
1208 int setgroups(int size, const gid_t *list)
1210 int setgroups(size_t size, const gid_t *list)
1213 if (!uid_wrapper_enabled()) {
1214 return libc_setgroups(size, list);
1218 return uwrap_setgroups(size, list);
1221 static int uwrap_getgroups(int size, gid_t *list)
1223 struct uwrap_thread *id = uwrap_tls_id;
1226 UWRAP_LOCK(uwrap_id);
1227 ngroups = id->ngroups;
1229 if (size > ngroups) {
1235 if (size < ngroups) {
1239 memcpy(list, id->groups, size * sizeof(gid_t));
1242 UWRAP_UNLOCK(uwrap_id);
1247 int getgroups(int size, gid_t *list)
1249 if (!uid_wrapper_enabled()) {
1250 return libc_getgroups(size, list);
1254 return uwrap_getgroups(size, list);
1257 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1258 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1259 static long int uwrap_syscall (long int sysno, va_list vp)
1266 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1270 rc = uwrap_getgid();
1275 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1279 rc = uwrap_getegid();
1282 #endif /* SYS_getegid */
1284 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1288 gid_t gid = (gid_t) va_arg(vp, int);
1290 rc = uwrap_setresgid_thread(gid, -1, -1);
1294 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1295 case SYS_setregid32:
1298 uid_t rgid = (uid_t) va_arg(vp, int);
1299 uid_t egid = (uid_t) va_arg(vp, int);
1301 rc = uwrap_setresgid_thread(rgid, egid, -1);
1304 #ifdef SYS_setresgid
1306 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1307 case SYS_setresgid32:
1310 uid_t rgid = (uid_t) va_arg(vp, int);
1311 uid_t egid = (uid_t) va_arg(vp, int);
1312 uid_t sgid = (uid_t) va_arg(vp, int);
1314 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1317 #endif /* SYS_setresgid */
1321 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1325 rc = uwrap_getuid();
1330 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1334 rc = uwrap_geteuid();
1337 #endif /* SYS_geteuid */
1339 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1343 uid_t uid = (uid_t) va_arg(vp, int);
1345 rc = uwrap_setresuid_thread(uid, -1, -1);
1349 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1350 case SYS_setreuid32:
1353 uid_t ruid = (uid_t) va_arg(vp, int);
1354 uid_t euid = (uid_t) va_arg(vp, int);
1356 rc = uwrap_setresuid_thread(ruid, euid, -1);
1359 #ifdef SYS_setresuid
1361 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1362 case SYS_setresuid32:
1365 uid_t ruid = (uid_t) va_arg(vp, int);
1366 uid_t euid = (uid_t) va_arg(vp, int);
1367 uid_t suid = (uid_t) va_arg(vp, int);
1369 rc = uwrap_setresuid_thread(ruid, euid, suid);
1372 #endif /* SYS_setresuid */
1376 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1377 case SYS_setgroups32:
1380 size_t size = (size_t) va_arg(vp, size_t);
1381 gid_t *list = (gid_t *) va_arg(vp, int *);
1383 rc = uwrap_setgroups_thread(size, list);
1387 UWRAP_LOG(UWRAP_LOG_DEBUG,
1388 "UID_WRAPPER calling non-wrapped syscall %lu\n",
1391 rc = libc_vsyscall(sysno, vp);
1399 #ifdef HAVE_SYSCALL_INT
1400 int syscall (int sysno, ...)
1402 long int syscall (long int sysno, ...)
1405 #ifdef HAVE_SYSCALL_INT
1412 va_start(va, sysno);
1414 if (!uid_wrapper_enabled()) {
1415 rc = libc_vsyscall(sysno, va);
1421 rc = uwrap_syscall(sysno, va);
1426 #endif /* HAVE_SYSCALL */
1427 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1429 /****************************
1431 ***************************/
1432 void uwrap_constructor(void)
1435 * If we hold a lock and the application forks, then the child
1436 * is not able to unlock the mutex and we are in a deadlock.
1437 * This should prevent such deadlocks.
1439 pthread_atfork(&uwrap_thread_prepare,
1440 &uwrap_thread_parent,
1441 &uwrap_thread_child);
1443 /* Here is safe place to call uwrap_init() and initialize data
1449 /****************************
1451 ***************************/
1454 * This function is called when the library is unloaded and makes sure that
1455 * resources are freed.
1457 void uwrap_destructor(void)
1459 struct uwrap_thread *u = uwrap.ids;
1461 UWRAP_LOCK(uwrap_id);
1462 UWRAP_LOCK(libc_symbol_binding);
1465 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1467 SAFE_FREE(u->groups);
1473 SAFE_FREE(uwrap.groups);
1475 if (uwrap.libc.handle != NULL) {
1476 dlclose(uwrap.libc.handle);
1479 UWRAP_UNLOCK(libc_symbol_binding);
1480 UWRAP_UNLOCK(uwrap_id);