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 #ifdef HAVE_GETRESUID
194 int (*_libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
196 uid_t (*_libc_geteuid)(void);
198 int (*_libc_setgid)(gid_t gid);
199 gid_t (*_libc_getgid)(void);
201 int (*_libc_setegid)(uid_t egid);
204 int (*_libc_setregid)(uid_t rgid, uid_t egid);
206 #ifdef HAVE_SETRESGID
207 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
209 #ifdef HAVE_GETRESGID
210 int (*_libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
212 gid_t (*_libc_getegid)(void);
213 int (*_libc_getgroups)(int size, gid_t list[]);
214 int (*_libc_setgroups)(size_t size, const gid_t *list);
216 long int (*_libc_syscall)(long int sysno, ...);
221 * We keep the virtualised euid/egid/groups information here
223 struct uwrap_thread {
238 struct uwrap_thread *next;
239 struct uwrap_thread *prev;
247 struct uwrap_libc_fns fns;
264 /* Real uid and gid of user who run uid wrapper */
268 struct uwrap_thread *ids;
271 static struct uwrap uwrap;
273 /* Shortcut to the list item */
274 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
276 /* The mutex or accessing the id */
277 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
279 /* The mutex for accessing the global libc.fns */
280 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
282 /*********************************************************
284 *********************************************************/
286 bool uid_wrapper_enabled(void);
287 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
288 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
290 /*********************************************************
291 * UWRAP LIBC LOADER FUNCTIONS
292 *********************************************************/
300 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
302 int flags = RTLD_LAZY;
307 flags |= RTLD_DEEPBIND;
313 case UWRAP_LIBSOCKET:
316 handle = uwrap.libc.handle;
317 if (handle == NULL) {
318 for (i = 10; i >= 0; i--) {
319 char soname[256] = {0};
321 snprintf(soname, sizeof(soname), "libc.so.%d", i);
322 handle = dlopen(soname, flags);
323 if (handle != NULL) {
328 uwrap.libc.handle = handle;
333 if (handle == NULL) {
335 handle = uwrap.libc.handle = RTLD_NEXT;
338 "Failed to dlopen library: %s\n",
347 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
352 handle = uwrap_load_lib_handle(lib);
354 func = dlsym(handle, fn_name);
357 "Failed to find %s: %s\n",
365 #define uwrap_load_lib_function(lib, fn_name) \
366 UWRAP_LOCK(libc_symbol_binding); \
367 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
368 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
369 _uwrap_load_lib_function(lib, #fn_name); \
371 UWRAP_UNLOCK(libc_symbol_binding)
376 * Functions expeciall from libc need to be loaded individually, you can't load
377 * all at once or gdb will segfault at startup. The same applies to valgrind and
378 * has probably something todo with with the linker.
379 * So we need load each function at the point it is called the first time.
381 static int libc_setuid(uid_t uid)
383 uwrap_load_lib_function(UWRAP_LIBC, setuid);
385 return uwrap.libc.fns._libc_setuid(uid);
388 static uid_t libc_getuid(void)
390 uwrap_load_lib_function(UWRAP_LIBC, getuid);
392 return uwrap.libc.fns._libc_getuid();
396 static int libc_seteuid(uid_t euid)
398 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
400 return uwrap.libc.fns._libc_seteuid(euid);
405 static int libc_setreuid(uid_t ruid, uid_t euid)
407 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
409 return uwrap.libc.fns._libc_setreuid(ruid, euid);
413 #ifdef HAVE_SETRESUID
414 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
416 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
418 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
422 #ifdef HAVE_GETRESUID
423 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
425 uwrap_load_lib_function(UWRAP_LIBC, getresuid);
427 return uwrap.libc.fns._libc_getresuid(ruid, euid, suid);
431 static uid_t libc_geteuid(void)
433 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
435 return uwrap.libc.fns._libc_geteuid();
438 static int libc_setgid(gid_t gid)
440 uwrap_load_lib_function(UWRAP_LIBC, setgid);
442 return uwrap.libc.fns._libc_setgid(gid);
445 static gid_t libc_getgid(void)
447 uwrap_load_lib_function(UWRAP_LIBC, getgid);
449 return uwrap.libc.fns._libc_getgid();
453 static int libc_setegid(gid_t egid)
455 uwrap_load_lib_function(UWRAP_LIBC, setegid);
457 return uwrap.libc.fns._libc_setegid(egid);
462 static int libc_setregid(gid_t rgid, gid_t egid)
464 uwrap_load_lib_function(UWRAP_LIBC, setregid);
466 return uwrap.libc.fns._libc_setregid(rgid, egid);
470 #ifdef HAVE_SETRESGID
471 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
473 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
475 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
479 #ifdef HAVE_GETRESGID
480 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
482 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
484 return uwrap.libc.fns._libc_getresgid(rgid, egid, sgid);
488 static gid_t libc_getegid(void)
490 uwrap_load_lib_function(UWRAP_LIBC, getegid);
492 return uwrap.libc.fns._libc_getegid();
495 static int libc_getgroups(int size, gid_t list[])
497 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
499 return uwrap.libc.fns._libc_getgroups(size, list);
502 static int libc_setgroups(size_t size, const gid_t *list)
504 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
506 return uwrap.libc.fns._libc_setgroups(size, list);
510 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
511 static long int libc_vsyscall(long int sysno, va_list va)
517 uwrap_load_lib_function(UWRAP_LIBC, syscall);
519 for (i = 0; i < 8; i++) {
520 args[i] = va_arg(va, long int);
523 rc = uwrap.libc.fns._libc_syscall(sysno,
537 /*********************************************************
539 *********************************************************/
541 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
543 struct uwrap_thread *id;
545 for (id = uwrap.ids; id; id = id->next) {
546 if (pthread_equal(id->tid, tid)) {
554 static int uwrap_new_id(pthread_t tid, bool do_alloc)
556 struct uwrap_thread *id = uwrap_tls_id;
559 id = malloc(sizeof(struct uwrap_thread));
561 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
566 id->groups = malloc(sizeof(gid_t) * uwrap.ngroups);
567 if (id->groups == NULL) {
568 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
574 UWRAP_DLIST_ADD(uwrap.ids, id);
581 id->ruid = uwrap.ruid;
582 id->euid = uwrap.euid;
583 id->suid = uwrap.suid;
585 id->rgid = uwrap.rgid;
586 id->egid = uwrap.egid;
587 id->sgid = uwrap.sgid;
589 id->ngroups = uwrap.ngroups;
590 if (uwrap.groups != NULL) {
591 memcpy(id->groups, uwrap.groups, sizeof(gid_t) * uwrap.ngroups);
599 static void uwrap_thread_prepare(void)
601 UWRAP_LOCK(uwrap_id);
602 UWRAP_LOCK(libc_symbol_binding);
604 * What happens if another atfork prepare functions calls a uwrap
605 * function? So disable it in case another atfork prepare function
606 * calls a (s)uid function.
608 uwrap.enabled = false;
611 static void uwrap_thread_parent(void)
613 uwrap.enabled = true;
615 UWRAP_UNLOCK(libc_symbol_binding);
616 UWRAP_UNLOCK(uwrap_id);
619 static void uwrap_thread_child(void)
621 uwrap.enabled = true;
623 /* We need to update to the new tid if we fork */
624 uwrap.tid = pthread_self();
626 UWRAP_UNLOCK(libc_symbol_binding);
627 UWRAP_UNLOCK(uwrap_id);
630 static void uwrap_init(void)
633 pthread_t tid = pthread_self();
635 UWRAP_LOCK(uwrap_id);
636 if (uwrap.initialised) {
637 struct uwrap_thread *id = uwrap_tls_id;
641 UWRAP_UNLOCK(uwrap_id);
645 id = find_uwrap_id(tid);
647 rc = uwrap_new_id(tid, true);
652 /* We reuse an old thread id */
655 uwrap_new_id(tid, false);
657 UWRAP_UNLOCK(uwrap_id);
662 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
664 uwrap.initialised = true;
665 uwrap.enabled = false;
667 env = getenv("UID_WRAPPER");
668 if (env != NULL && env[0] == '1') {
669 const char *root = getenv("UID_WRAPPER_ROOT");
672 uwrap.myuid = libc_geteuid();
673 uwrap.mygid = libc_getegid();
674 /* put us in one group */
675 if (root != NULL && root[0] == '1') {
676 uwrap.ruid = uwrap.euid = uwrap.suid = 0;
677 uwrap.rgid = uwrap.egid = uwrap.sgid = 0;
679 uwrap.groups = malloc(sizeof(gid_t) * 1);
680 if (uwrap.groups == NULL) {
681 UWRAP_LOG(UWRAP_LOG_ERROR,
682 "Unable to allocate memory");
690 uwrap.ruid = uwrap.euid = uwrap.suid = uwrap.myuid;
691 uwrap.rgid = uwrap.egid = uwrap.sgid = uwrap.mygid;
693 uwrap.ngroups = libc_getgroups(0, NULL);
694 if (uwrap.ngroups == -1) {
695 UWRAP_LOG(UWRAP_LOG_ERROR,
696 "Unable to call libc_getgroups in uwrap_init.");
699 uwrap.groups = malloc(sizeof(gid_t) * uwrap.ngroups);
700 if (uwrap.groups == NULL) {
701 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
704 if (libc_getgroups(uwrap.ngroups, uwrap.groups) == -1) {
705 UWRAP_LOG(UWRAP_LOG_ERROR,
706 "Unable to call libc_getgroups again in uwrap_init.");
709 * Deallocation of uwrap.groups is handled by
710 * library destructor.
716 rc = uwrap_new_id(tid, true);
722 uwrap.enabled = true;
724 UWRAP_LOG(UWRAP_LOG_DEBUG,
725 "Enabled uid_wrapper as %s",
726 uwrap.myuid == 0 ? "root" : "user");
729 UWRAP_UNLOCK(uwrap_id);
731 UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
734 bool uid_wrapper_enabled(void)
736 bool enabled = false;
737 #ifdef HAVE_GCC_ATOMIC_BUILTINS
738 __atomic_load(&uwrap.enabled, &enabled, __ATOMIC_RELAXED);
740 UWRAP_LOCK(uwrap_id);
741 enabled = uwrap.enabled;
742 UWRAP_UNLOCK(uwrap_id);
747 #ifdef HAVE_GETRESUID
748 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
750 struct uwrap_thread *id = uwrap_tls_id;
752 UWRAP_LOCK(uwrap_id);
758 UWRAP_UNLOCK(uwrap_id);
764 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
766 struct uwrap_thread *id = uwrap_tls_id;
768 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
773 UWRAP_LOCK(uwrap_id);
774 if (ruid != (uid_t)-1) {
778 if (euid != (uid_t)-1) {
782 if (suid != (uid_t)-1) {
786 /* Check If syscall is called from main thread. */
787 if (pthread_equal(id->tid, uwrap.tid)) {
788 if (ruid != (uid_t)-1) {
792 if (euid != (uid_t)-1) {
796 if (suid != (uid_t)-1) {
801 UWRAP_UNLOCK(uwrap_id);
806 #ifdef HAVE_GETRESGID
807 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
809 struct uwrap_thread *id = uwrap_tls_id;
811 UWRAP_LOCK(uwrap_id);
817 UWRAP_UNLOCK(uwrap_id);
823 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
825 struct uwrap_thread *id;
827 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
832 UWRAP_LOCK(uwrap_id);
833 for (id = uwrap.ids; id; id = id->next) {
838 if (ruid != (uid_t)-1) {
842 if (euid != (uid_t)-1) {
846 if (suid != (uid_t)-1) {
851 /* Reflect changes in thread to main process. */
852 if (ruid != (uid_t)-1) {
856 if (euid != (uid_t)-1) {
860 if (suid != (uid_t)-1) {
864 UWRAP_UNLOCK(uwrap_id);
872 int setuid(uid_t uid)
874 if (!uid_wrapper_enabled()) {
875 return libc_setuid(uid);
879 return uwrap_setresuid(uid, -1, -1);
883 int seteuid(uid_t euid)
885 if (euid == (uid_t)-1) {
890 if (!uid_wrapper_enabled()) {
891 return libc_seteuid(euid);
895 return uwrap_setresuid(-1, euid, -1);
900 int setreuid(uid_t ruid, uid_t euid)
902 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
907 if (!uid_wrapper_enabled()) {
908 return libc_setreuid(ruid, euid);
912 return uwrap_setresuid(ruid, euid, -1);
916 #ifdef HAVE_SETRESUID
917 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
919 if (!uid_wrapper_enabled()) {
920 return libc_setresuid(ruid, euid, suid);
924 return uwrap_setresuid(ruid, euid, suid);
928 #ifdef HAVE_GETRESUID
929 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
931 if (!uid_wrapper_enabled()) {
932 return libc_getresuid(ruid, euid, suid);
936 return uwrap_getresuid(ruid, euid, suid);
943 static uid_t uwrap_getuid(void)
945 struct uwrap_thread *id = uwrap_tls_id;
948 UWRAP_LOCK(uwrap_id);
950 UWRAP_UNLOCK(uwrap_id);
957 if (!uid_wrapper_enabled()) {
958 return libc_getuid();
962 return uwrap_getuid();
968 static uid_t uwrap_geteuid(void)
970 const char *env = getenv("UID_WRAPPER_MYUID");
971 struct uwrap_thread *id = uwrap_tls_id;
974 UWRAP_LOCK(uwrap_id);
976 UWRAP_UNLOCK(uwrap_id);
978 /* Disable root and return myuid */
979 if (env != NULL && env[0] == '1') {
988 if (!uid_wrapper_enabled()) {
989 return libc_geteuid();
993 return uwrap_geteuid();
996 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
998 struct uwrap_thread *id = uwrap_tls_id;
1000 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
1005 UWRAP_LOCK(uwrap_id);
1006 if (rgid != (gid_t)-1) {
1010 if (egid != (gid_t)-1) {
1014 if (sgid != (gid_t)-1) {
1018 if (pthread_equal(id->tid, uwrap.tid)) {
1019 if (rgid != (gid_t)-1) {
1023 if (egid != (gid_t)-1) {
1027 if (sgid != (gid_t)-1) {
1031 UWRAP_UNLOCK(uwrap_id);
1036 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1038 struct uwrap_thread *id;
1040 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
1045 UWRAP_LOCK(uwrap_id);
1046 for (id = uwrap.ids; id; id = id->next) {
1051 if (rgid != (gid_t)-1) {
1055 if (egid != (gid_t)-1) {
1059 if (sgid != (gid_t)-1) {
1064 /* Reflect changes in thread to main process. */
1065 if (rgid != (gid_t)-1) {
1069 if (egid != (gid_t)-1) {
1073 if (sgid != (gid_t)-1) {
1076 UWRAP_UNLOCK(uwrap_id);
1084 int setgid(gid_t gid)
1086 if (!uid_wrapper_enabled()) {
1087 return libc_setgid(gid);
1091 return uwrap_setresgid(gid, -1, -1);
1095 int setegid(gid_t egid)
1097 if (!uid_wrapper_enabled()) {
1098 return libc_setegid(egid);
1102 return uwrap_setresgid(-1, egid, -1);
1106 #ifdef HAVE_SETREGID
1107 int setregid(gid_t rgid, gid_t egid)
1109 if (!uid_wrapper_enabled()) {
1110 return libc_setregid(rgid, egid);
1114 return uwrap_setresgid(rgid, egid, -1);
1118 #ifdef HAVE_SETRESGID
1119 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1121 if (!uid_wrapper_enabled()) {
1122 return libc_setresgid(rgid, egid, sgid);
1126 return uwrap_setresgid(rgid, egid, sgid);
1130 #ifdef HAVE_GETRESGID
1131 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1133 if (!uid_wrapper_enabled()) {
1134 return libc_getresgid(rgid, egid, sgid);
1138 return uwrap_getresgid(rgid, egid, sgid);
1145 static gid_t uwrap_getgid(void)
1147 struct uwrap_thread *id = uwrap_tls_id;
1150 UWRAP_LOCK(uwrap_id);
1152 UWRAP_UNLOCK(uwrap_id);
1159 if (!uid_wrapper_enabled()) {
1160 return libc_getgid();
1164 return uwrap_getgid();
1170 static uid_t uwrap_getegid(void)
1172 struct uwrap_thread *id = uwrap_tls_id;
1175 UWRAP_LOCK(uwrap_id);
1177 UWRAP_UNLOCK(uwrap_id);
1184 if (!uid_wrapper_enabled()) {
1185 return libc_getegid();
1189 return uwrap_getegid();
1192 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1194 struct uwrap_thread *id = uwrap_tls_id;
1197 UWRAP_LOCK(uwrap_id);
1200 SAFE_FREE(id->groups);
1202 if (pthread_equal(id->tid, uwrap.tid)) {
1203 SAFE_FREE(uwrap.groups);
1206 } else if (size > 0) {
1209 tmp = realloc(id->groups, sizeof(gid_t) * size);
1216 memcpy(id->groups, list, size * sizeof(gid_t));
1218 if (pthread_equal(id->tid, uwrap.tid)) {
1219 tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1221 /* How to return back id->groups? */
1227 uwrap.ngroups = size;
1228 memcpy(uwrap.groups, list, size * sizeof(gid_t));
1234 UWRAP_UNLOCK(uwrap_id);
1239 static int uwrap_setgroups(size_t size, const gid_t *list)
1241 struct uwrap_thread *id;
1244 UWRAP_LOCK(uwrap_id);
1247 for (id = uwrap.ids; id; id = id->next) {
1248 SAFE_FREE(id->groups);
1252 SAFE_FREE(uwrap.groups);
1254 } else if (size > 0) {
1257 for (id = uwrap.ids; id; id = id->next) {
1258 tmp = realloc(id->groups, sizeof(gid_t) * size);
1266 memcpy(id->groups, list, size * sizeof(gid_t));
1269 tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1271 /* How to return back id->groups? */
1277 uwrap.ngroups = size;
1278 memcpy(uwrap.groups, list, size * sizeof(gid_t));
1284 UWRAP_UNLOCK(uwrap_id);
1289 #ifdef HAVE_SETGROUPS_INT
1290 int setgroups(int size, const gid_t *list)
1292 int setgroups(size_t size, const gid_t *list)
1295 if (!uid_wrapper_enabled()) {
1296 return libc_setgroups(size, list);
1300 return uwrap_setgroups(size, list);
1303 static int uwrap_getgroups(int size, gid_t *list)
1305 struct uwrap_thread *id = uwrap_tls_id;
1308 UWRAP_LOCK(uwrap_id);
1309 ngroups = id->ngroups;
1311 if (size > ngroups) {
1317 if (size < ngroups) {
1321 memcpy(list, id->groups, size * sizeof(gid_t));
1324 UWRAP_UNLOCK(uwrap_id);
1329 int getgroups(int size, gid_t *list)
1331 if (!uid_wrapper_enabled()) {
1332 return libc_getgroups(size, list);
1336 return uwrap_getgroups(size, list);
1339 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1340 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1341 static long int uwrap_syscall (long int sysno, va_list vp)
1348 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1352 rc = uwrap_getgid();
1357 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1361 rc = uwrap_getegid();
1364 #endif /* SYS_getegid */
1366 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1370 gid_t gid = (gid_t) va_arg(vp, gid_t);
1372 rc = uwrap_setresgid_thread(gid, -1, -1);
1376 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1377 case SYS_setregid32:
1380 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1381 gid_t egid = (gid_t) va_arg(vp, gid_t);
1383 rc = uwrap_setresgid_thread(rgid, egid, -1);
1386 #ifdef SYS_setresgid
1388 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1389 case SYS_setresgid32:
1392 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1393 gid_t egid = (gid_t) va_arg(vp, gid_t);
1394 gid_t sgid = (gid_t) va_arg(vp, gid_t);
1396 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1399 #endif /* SYS_setresgid */
1400 #ifdef SYS_getresgid
1402 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1403 case SYS_getresgid32:
1406 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
1407 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
1408 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
1410 rc = uwrap_getresgid(rgid, egid, sgid);
1413 #endif /* SYS_getresgid */
1417 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1421 rc = uwrap_getuid();
1426 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1430 rc = uwrap_geteuid();
1433 #endif /* SYS_geteuid */
1435 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1439 uid_t uid = (uid_t) va_arg(vp, uid_t);
1441 rc = uwrap_setresuid_thread(uid, -1, -1);
1445 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1446 case SYS_setreuid32:
1449 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1450 uid_t euid = (uid_t) va_arg(vp, uid_t);
1452 rc = uwrap_setresuid_thread(ruid, euid, -1);
1455 #ifdef SYS_setresuid
1457 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1458 case SYS_setresuid32:
1461 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1462 uid_t euid = (uid_t) va_arg(vp, uid_t);
1463 uid_t suid = (uid_t) va_arg(vp, uid_t);
1465 rc = uwrap_setresuid_thread(ruid, euid, suid);
1468 #endif /* SYS_setresuid */
1469 #ifdef SYS_getresuid
1471 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1472 case SYS_getresuid32:
1475 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
1476 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
1477 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
1479 rc = uwrap_getresuid(ruid, euid, suid);
1482 #endif /* SYS_getresuid */
1485 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1486 case SYS_setgroups32:
1489 size_t size = (size_t) va_arg(vp, size_t);
1490 gid_t *list = (gid_t *) va_arg(vp, int *);
1492 rc = uwrap_setgroups_thread(size, list);
1496 UWRAP_LOG(UWRAP_LOG_DEBUG,
1497 "UID_WRAPPER calling non-wrapped syscall %lu\n",
1500 rc = libc_vsyscall(sysno, vp);
1508 #ifdef HAVE_SYSCALL_INT
1509 int syscall (int sysno, ...)
1511 long int syscall (long int sysno, ...)
1514 #ifdef HAVE_SYSCALL_INT
1521 va_start(va, sysno);
1523 if (!uid_wrapper_enabled()) {
1524 rc = libc_vsyscall(sysno, va);
1530 rc = uwrap_syscall(sysno, va);
1535 #endif /* HAVE_SYSCALL */
1536 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1538 /****************************
1540 ***************************/
1541 void uwrap_constructor(void)
1544 * If we hold a lock and the application forks, then the child
1545 * is not able to unlock the mutex and we are in a deadlock.
1546 * This should prevent such deadlocks.
1548 pthread_atfork(&uwrap_thread_prepare,
1549 &uwrap_thread_parent,
1550 &uwrap_thread_child);
1552 /* Here is safe place to call uwrap_init() and initialize data
1558 /****************************
1560 ***************************/
1563 * This function is called when the library is unloaded and makes sure that
1564 * resources are freed.
1566 void uwrap_destructor(void)
1568 struct uwrap_thread *u = uwrap.ids;
1570 UWRAP_LOCK(uwrap_id);
1571 UWRAP_LOCK(libc_symbol_binding);
1574 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1576 SAFE_FREE(u->groups);
1582 SAFE_FREE(uwrap.groups);
1584 if (uwrap.libc.handle != NULL) {
1585 dlclose(uwrap.libc.handle);
1588 UWRAP_UNLOCK(libc_symbol_binding);
1589 UWRAP_UNLOCK(uwrap_id);