lib:talloc. Fix memory leak when destructors reparent children.
[Samba.git] / lib / uid_wrapper / uid_wrapper.c
blob743d590b68767675345e74c501c7a86fa55695f3
1 /*
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/>.
19 #include "config.h"
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <grp.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
32 #endif
33 #ifdef HAVE_SYSCALL_H
34 #include <syscall.h>
35 #endif
36 #include <dlfcn.h>
38 #include <pthread.h>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
42 #else
43 # define UWRAP_THREAD
44 #endif
46 # define UWRAP_LOCK(m) do { \
47 pthread_mutex_lock(&( m ## _mutex)); \
48 } while(0)
50 # define UWRAP_UNLOCK(m) do { \
51 pthread_mutex_unlock(&( m ## _mutex)); \
52 } while(0)
54 /* Add new global locks here please */
55 # define UWRAP_LOCK_ALL \
56 UWRAP_LOCK(uwrap_id); \
57 UWRAP_LOCK(libc_symbol_binding); \
58 UWRAP_LOCK(libpthread_symbol_binding)
60 # define UWRAP_UNLOCK_ALL \
61 UWRAP_UNLOCK(libpthread_symbol_binding); \
62 UWRAP_UNLOCK(libc_symbol_binding); \
63 UWRAP_UNLOCK(uwrap_id)
65 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
66 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
67 #else
68 #define CONSTRUCTOR_ATTRIBUTE
69 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
71 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
72 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
73 #else
74 #define DESTRUCTOR_ATTRIBUTE
75 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
77 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
78 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
79 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
80 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
81 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
83 /* GCC have printf type attribute check. */
84 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
85 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
86 #else
87 #define PRINTF_ATTRIBUTE(a,b)
88 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
90 #define UWRAP_DLIST_ADD(list,item) do { \
91 if (!(list)) { \
92 (item)->prev = NULL; \
93 (item)->next = NULL; \
94 (list) = (item); \
95 } else { \
96 (item)->prev = NULL; \
97 (item)->next = (list); \
98 (list)->prev = (item); \
99 (list) = (item); \
101 } while (0)
103 #define UWRAP_DLIST_REMOVE(list,item) do { \
104 if ((list) == (item)) { \
105 (list) = (item)->next; \
106 if (list) { \
107 (list)->prev = NULL; \
109 } else { \
110 if ((item)->prev) { \
111 (item)->prev->next = (item)->next; \
113 if ((item)->next) { \
114 (item)->next->prev = (item)->prev; \
117 (item)->prev = NULL; \
118 (item)->next = NULL; \
119 } while (0)
121 #ifndef SAFE_FREE
122 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
123 #endif
125 /*****************
126 * LOGGING
127 *****************/
129 enum uwrap_dbglvl_e {
130 UWRAP_LOG_ERROR = 0,
131 UWRAP_LOG_WARN,
132 UWRAP_LOG_DEBUG,
133 UWRAP_LOG_TRACE
136 #ifdef NDEBUG
137 # define UWRAP_LOG(...)
138 #else /* NDEBUG */
139 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
140 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
142 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
144 char buffer[1024];
145 va_list va;
146 const char *d;
147 unsigned int lvl = 0;
149 d = getenv("UID_WRAPPER_DEBUGLEVEL");
150 if (d != NULL) {
151 lvl = atoi(d);
154 va_start(va, format);
155 vsnprintf(buffer, sizeof(buffer), format, va);
156 va_end(va);
158 if (lvl >= dbglvl) {
159 const char *prefix = "UWRAP";
160 switch (dbglvl) {
161 case UWRAP_LOG_ERROR:
162 prefix = "UWRAP_ERROR";
163 break;
164 case UWRAP_LOG_WARN:
165 prefix = "UWRAP_WARN";
166 break;
167 case UWRAP_LOG_DEBUG:
168 prefix = "UWRAP_DEBUG";
169 break;
170 case UWRAP_LOG_TRACE:
171 prefix = "UWRAP_TRACE";
172 break;
175 fprintf(stderr,
176 "%s(%d) - %s: %s\n",
177 prefix,
178 (int)getpid(),
179 function,
180 buffer);
183 #endif /* NDEBUG */
185 /*****************
186 * LIBC
187 *****************/
189 #define LIBC_NAME "libc.so"
191 typedef int (*__libc_setuid)(uid_t uid);
193 typedef uid_t (*__libc_getuid)(void);
195 #ifdef HAVE_SETEUID
196 typedef int (*__libc_seteuid)(uid_t euid);
197 #endif
199 #ifdef HAVE_SETREUID
200 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
201 #endif
203 #ifdef HAVE_SETRESUID
204 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
205 #endif
207 #ifdef HAVE_GETRESUID
208 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
209 #endif
211 typedef uid_t (*__libc_geteuid)(void);
213 typedef int (*__libc_setgid)(gid_t gid);
215 typedef gid_t (*__libc_getgid)(void);
217 #ifdef HAVE_SETEGID
218 typedef int (*__libc_setegid)(uid_t egid);
219 #endif
221 #ifdef HAVE_SETREGID
222 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
223 #endif
225 #ifdef HAVE_SETRESGID
226 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
227 #endif
229 #ifdef HAVE_GETRESGID
230 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
231 #endif
233 typedef gid_t (*__libc_getegid)(void);
235 typedef int (*__libc_getgroups)(int size, gid_t list[]);
237 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
239 #ifdef HAVE_SYSCALL
240 typedef long int (*__libc_syscall)(long int sysno, ...);
241 #endif
243 #define UWRAP_SYMBOL_ENTRY(i) \
244 union { \
245 __libc_##i f; \
246 void *obj; \
247 } _libc_##i
249 struct uwrap_libc_symbols {
250 UWRAP_SYMBOL_ENTRY(setuid);
251 UWRAP_SYMBOL_ENTRY(getuid);
252 #ifdef HAVE_SETEUID
253 UWRAP_SYMBOL_ENTRY(seteuid);
254 #endif
255 #ifdef HAVE_SETREUID
256 UWRAP_SYMBOL_ENTRY(setreuid);
257 #endif
258 #ifdef HAVE_SETRESUID
259 UWRAP_SYMBOL_ENTRY(setresuid);
260 #endif
261 #ifdef HAVE_GETRESUID
262 UWRAP_SYMBOL_ENTRY(getresuid);
263 #endif
264 UWRAP_SYMBOL_ENTRY(geteuid);
265 UWRAP_SYMBOL_ENTRY(setgid);
266 UWRAP_SYMBOL_ENTRY(getgid);
267 #ifdef HAVE_SETEGID
268 UWRAP_SYMBOL_ENTRY(setegid);
269 #endif
270 #ifdef HAVE_SETREGID
271 UWRAP_SYMBOL_ENTRY(setregid);
272 #endif
273 #ifdef HAVE_SETRESGID
274 UWRAP_SYMBOL_ENTRY(setresgid);
275 #endif
276 #ifdef HAVE_GETRESGID
277 UWRAP_SYMBOL_ENTRY(getresgid);
278 #endif
279 UWRAP_SYMBOL_ENTRY(getegid);
280 UWRAP_SYMBOL_ENTRY(getgroups);
281 UWRAP_SYMBOL_ENTRY(setgroups);
282 #ifdef HAVE_SYSCALL
283 UWRAP_SYMBOL_ENTRY(syscall);
284 #endif
286 #undef UWRAP_SYMBOL_ENTRY
288 /*****************
289 * LIBPTHREAD
290 *****************/
291 /* Yeah... I'm pig. I overloading macro here... So what? */
292 #define UWRAP_SYMBOL_ENTRY(i) \
293 union { \
294 __libpthread_##i f; \
295 void *obj; \
296 } _libpthread_##i
298 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
299 const pthread_attr_t *attr,
300 void *(*start_routine) (void *),
301 void *arg);
302 typedef void (*__libpthread_pthread_exit)(void *retval);
304 struct uwrap_libpthread_symbols {
305 UWRAP_SYMBOL_ENTRY(pthread_create);
306 UWRAP_SYMBOL_ENTRY(pthread_exit);
308 #undef UWRAP_SYMBOL_ENTRY
311 * We keep the virtualised euid/egid/groups information here
313 struct uwrap_thread {
314 bool enabled;
316 uid_t ruid;
317 uid_t euid;
318 uid_t suid;
320 gid_t rgid;
321 gid_t egid;
322 gid_t sgid;
324 int ngroups;
325 gid_t *groups;
327 struct uwrap_thread *next;
328 struct uwrap_thread *prev;
331 struct uwrap {
332 struct {
333 void *handle;
334 struct uwrap_libc_symbols symbols;
335 } libc;
337 struct {
338 void *handle;
339 struct uwrap_libpthread_symbols symbols;
340 } libpthread;
342 bool initialised;
344 /* Real uid and gid of user who run uid wrapper */
345 uid_t myuid;
346 gid_t mygid;
348 struct uwrap_thread *ids;
351 static struct uwrap uwrap;
353 /* Shortcut to the list item */
354 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
356 /* The mutex or accessing the id */
357 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
359 /* The mutex for accessing the global libc.symbols */
360 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
362 /* The mutex for accessing the global libpthread.symbols */
363 static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
365 /*********************************************************
366 * UWRAP PROTOTYPES
367 *********************************************************/
369 bool uid_wrapper_enabled(void);
370 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
371 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
373 /*********************************************************
374 * UWRAP LIBC LOADER FUNCTIONS
375 *********************************************************/
377 enum uwrap_lib {
378 UWRAP_LIBC,
379 UWRAP_LIBNSL,
380 UWRAP_LIBSOCKET,
381 UWRAP_LIBPTHREAD,
384 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
386 int flags = RTLD_LAZY;
387 void *handle = NULL;
388 int i;
390 #ifdef RTLD_DEEPBIND
391 flags |= RTLD_DEEPBIND;
392 #endif
394 switch (lib) {
395 case UWRAP_LIBNSL:
396 /* FALL TROUGH */
397 case UWRAP_LIBSOCKET:
398 /* FALL TROUGH */
399 case UWRAP_LIBC:
400 handle = uwrap.libc.handle;
401 if (handle == NULL) {
402 for (i = 10; i >= 0; i--) {
403 char soname[256] = {0};
405 snprintf(soname, sizeof(soname), "libc.so.%d", i);
406 handle = dlopen(soname, flags);
407 if (handle != NULL) {
408 break;
412 uwrap.libc.handle = handle;
414 break;
415 case UWRAP_LIBPTHREAD:
416 handle = uwrap.libpthread.handle;
417 if (handle == NULL) {
418 handle = dlopen("libpthread.so.0", flags);
419 if (handle != NULL) {
420 break;
423 break;
426 if (handle == NULL) {
427 #ifdef RTLD_NEXT
428 handle = uwrap.libc.handle = RTLD_NEXT;
429 #else
430 fprintf(stderr,
431 "Failed to dlopen library: %s\n",
432 dlerror());
433 exit(-1);
434 #endif
437 return handle;
440 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
442 void *handle;
443 void *func;
445 handle = uwrap_load_lib_handle(lib);
447 func = dlsym(handle, fn_name);
448 if (func == NULL) {
449 fprintf(stderr,
450 "Failed to find %s: %s\n",
451 fn_name, dlerror());
452 exit(-1);
455 return func;
458 #define uwrap_bind_symbol_libc(sym_name) \
459 UWRAP_LOCK(libc_symbol_binding); \
460 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
461 uwrap.libc.symbols._libc_##sym_name.obj = \
462 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
464 UWRAP_UNLOCK(libc_symbol_binding)
466 #define uwrap_bind_symbol_libpthread(sym_name) \
467 UWRAP_LOCK(libpthread_symbol_binding); \
468 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
469 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
470 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
472 UWRAP_UNLOCK(libpthread_symbol_binding)
475 * IMPORTANT
477 * Functions expeciall from libc need to be loaded individually, you can't load
478 * all at once or gdb will segfault at startup. The same applies to valgrind and
479 * has probably something todo with with the linker.
480 * So we need load each function at the point it is called the first time.
482 static int libc_setuid(uid_t uid)
484 uwrap_bind_symbol_libc(setuid);
486 return uwrap.libc.symbols._libc_setuid.f(uid);
489 static uid_t libc_getuid(void)
491 uwrap_bind_symbol_libc(getuid);
493 return uwrap.libc.symbols._libc_getuid.f();
496 #ifdef HAVE_SETEUID
497 static int libc_seteuid(uid_t euid)
499 uwrap_bind_symbol_libc(seteuid);
501 return uwrap.libc.symbols._libc_seteuid.f(euid);
503 #endif
505 #ifdef HAVE_SETREUID
506 static int libc_setreuid(uid_t ruid, uid_t euid)
508 uwrap_bind_symbol_libc(setreuid);
510 return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
512 #endif
514 #ifdef HAVE_SETRESUID
515 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
517 uwrap_bind_symbol_libc(setresuid);
519 return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
521 #endif
523 #ifdef HAVE_GETRESUID
524 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
526 uwrap_bind_symbol_libc(getresuid);
528 return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
530 #endif
532 static uid_t libc_geteuid(void)
534 uwrap_bind_symbol_libc(geteuid);
536 return uwrap.libc.symbols._libc_geteuid.f();
539 static int libc_setgid(gid_t gid)
541 uwrap_bind_symbol_libc(setgid);
543 return uwrap.libc.symbols._libc_setgid.f(gid);
546 static gid_t libc_getgid(void)
548 uwrap_bind_symbol_libc(getgid);
550 return uwrap.libc.symbols._libc_getgid.f();
553 #ifdef HAVE_SETEGID
554 static int libc_setegid(gid_t egid)
556 uwrap_bind_symbol_libc(setegid);
558 return uwrap.libc.symbols._libc_setegid.f(egid);
560 #endif
562 #ifdef HAVE_SETREGID
563 static int libc_setregid(gid_t rgid, gid_t egid)
565 uwrap_bind_symbol_libc(setregid);
567 return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
569 #endif
571 #ifdef HAVE_SETRESGID
572 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
574 uwrap_bind_symbol_libc(setresgid);
576 return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
578 #endif
580 #ifdef HAVE_GETRESGID
581 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
583 uwrap_bind_symbol_libc(setresgid);
585 return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
587 #endif
589 static gid_t libc_getegid(void)
591 uwrap_bind_symbol_libc(getegid);
593 return uwrap.libc.symbols._libc_getegid.f();
596 static int libc_getgroups(int size, gid_t list[])
598 uwrap_bind_symbol_libc(getgroups);
600 return uwrap.libc.symbols._libc_getgroups.f(size, list);
603 static int libc_setgroups(size_t size, const gid_t *list)
605 uwrap_bind_symbol_libc(setgroups);
607 return uwrap.libc.symbols._libc_setgroups.f(size, list);
610 #ifdef HAVE_SYSCALL
611 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
612 static long int libc_vsyscall(long int sysno, va_list va)
614 long int args[8];
615 long int rc;
616 int i;
618 uwrap_bind_symbol_libc(syscall);
620 for (i = 0; i < 8; i++) {
621 args[i] = va_arg(va, long int);
624 rc = uwrap.libc.symbols._libc_syscall.f(sysno,
625 args[0],
626 args[1],
627 args[2],
628 args[3],
629 args[4],
630 args[5],
631 args[6],
632 args[7]);
634 return rc;
636 #endif
639 * This part is "optimistic".
640 * Thread can ends without pthread_exit call.
642 static void libpthread_pthread_exit(void *retval)
644 uwrap_bind_symbol_libpthread(pthread_exit);
646 uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
649 static void uwrap_pthread_exit(void *retval)
651 struct uwrap_thread *id = uwrap_tls_id;
653 UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
655 UWRAP_LOCK(uwrap_id);
656 if (id == NULL) {
657 UWRAP_UNLOCK(uwrap_id);
658 libpthread_pthread_exit(retval);
659 return;
662 UWRAP_DLIST_REMOVE(uwrap.ids, id);
663 SAFE_FREE(id->groups);
664 SAFE_FREE(id);
665 uwrap_tls_id = NULL;
667 UWRAP_UNLOCK(uwrap_id);
669 libpthread_pthread_exit(retval);
672 void pthread_exit(void *retval)
674 if (!uid_wrapper_enabled()) {
675 libpthread_pthread_exit(retval);
678 uwrap_pthread_exit(retval);
680 /* Calm down gcc warning. */
681 exit(666);
684 static int libpthread_pthread_create(pthread_t *thread,
685 const pthread_attr_t *attr,
686 void *(*start_routine) (void *),
687 void *arg)
689 uwrap_bind_symbol_libpthread(pthread_create);
690 return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
691 attr,
692 start_routine,
693 arg);
696 struct uwrap_pthread_create_args {
697 struct uwrap_thread *id;
698 void *(*start_routine) (void *);
699 void *arg;
702 static void *uwrap_pthread_create_start(void *_a)
704 struct uwrap_pthread_create_args *a =
705 (struct uwrap_pthread_create_args *)_a;
706 void *(*start_routine) (void *) = a->start_routine;
707 void *arg = a->arg;
708 struct uwrap_thread *id = a->id;
710 SAFE_FREE(a);
712 uwrap_tls_id = id;
714 return start_routine(arg);
717 static int uwrap_pthread_create(pthread_t *thread,
718 const pthread_attr_t *attr,
719 void *(*start_routine) (void *),
720 void *arg)
722 struct uwrap_pthread_create_args *args;
723 struct uwrap_thread *src_id = uwrap_tls_id;
724 int ret;
726 args = malloc(sizeof(struct uwrap_pthread_create_args));
727 if (args == NULL) {
728 UWRAP_LOG(UWRAP_LOG_ERROR,
729 "uwrap_pthread_create: Unable to allocate memory");
730 errno = ENOMEM;
731 return -1;
733 args->start_routine = start_routine;
734 args->arg = arg;
736 args->id = calloc(1, sizeof(struct uwrap_thread));
737 if (args->id == NULL) {
738 SAFE_FREE(args);
739 UWRAP_LOG(UWRAP_LOG_ERROR,
740 "uwrap_pthread_create: Unable to allocate memory");
741 errno = ENOMEM;
742 return -1;
745 UWRAP_LOCK(uwrap_id);
747 args->id->groups = malloc(sizeof(gid_t) * src_id->ngroups);
748 if (args->id->groups == NULL) {
749 UWRAP_UNLOCK(uwrap_id);
750 SAFE_FREE(args->id);
751 SAFE_FREE(args);
752 UWRAP_LOG(UWRAP_LOG_ERROR,
753 "uwrap_pthread_create: Unable to allocate memory again");
754 errno = ENOMEM;
755 return -1;
758 args->id->ruid = src_id->ruid;
759 args->id->euid = src_id->euid;
760 args->id->suid = src_id->suid;
762 args->id->rgid = src_id->rgid;
763 args->id->egid = src_id->egid;
764 args->id->sgid = src_id->sgid;
766 args->id->enabled = src_id->enabled;
768 args->id->ngroups = src_id->ngroups;
769 if (src_id->groups != NULL) {
770 memcpy(args->id->groups, src_id->groups,
771 sizeof(gid_t) * src_id->ngroups);
772 } else {
773 SAFE_FREE(args->id->groups);
776 UWRAP_DLIST_ADD(uwrap.ids, args->id);
777 UWRAP_UNLOCK(uwrap_id);
779 ret = libpthread_pthread_create(thread, attr,
780 uwrap_pthread_create_start,
781 args);
782 if (ret != 0) {
783 return ret;
786 return ret;
789 int pthread_create(pthread_t *thread,
790 const pthread_attr_t *attr,
791 void *(*start_routine) (void *),
792 void *arg)
794 if (!uid_wrapper_enabled()) {
795 return libpthread_pthread_create(thread,
796 attr,
797 start_routine,
798 arg);
801 return uwrap_pthread_create(thread,
802 attr,
803 start_routine,
804 arg);
807 /*********************************************************
808 * UWRAP ID HANDLING
809 *********************************************************/
811 static void uwrap_thread_prepare(void)
813 struct uwrap_thread *id = uwrap_tls_id;
815 /* uid_wrapper is loaded but not enabled */
816 if (id == NULL) {
817 return;
820 UWRAP_LOCK_ALL;
823 * What happens if another atfork prepare functions calls a uwrap
824 * function? So disable it in case another atfork prepare function
825 * calls a (s)uid function. We disable uid_wrapper only for thread
826 * (process) which called fork.
828 id->enabled = false;
831 static void uwrap_thread_parent(void)
833 struct uwrap_thread *id = uwrap_tls_id;
835 /* uid_wrapper is loaded but not enabled */
836 if (id == NULL) {
837 return;
840 id->enabled = true;
842 UWRAP_UNLOCK_ALL;
845 static void uwrap_thread_child(void)
847 struct uwrap_thread *id = uwrap_tls_id;
848 struct uwrap_thread *u = uwrap.ids;
850 /* uid_wrapper is loaded but not enabled */
851 if (id == NULL) {
852 return;
856 * "Garbage collector" - Inspired by DESTRUCTOR.
857 * All threads (except one which called fork()) are dead now.. Dave
858 * That's what posix said...
860 while (u != NULL) {
861 if (u == id) {
862 /* Skip this item. */
863 u = uwrap.ids->next;
864 continue;
867 UWRAP_DLIST_REMOVE(uwrap.ids, u);
869 SAFE_FREE(u->groups);
870 SAFE_FREE(u);
872 u = uwrap.ids;
875 id->enabled = true;
877 UWRAP_UNLOCK_ALL;
880 static void uwrap_init(void)
882 const char *env;
884 UWRAP_LOCK(uwrap_id);
886 if (uwrap.initialised) {
887 struct uwrap_thread *id = uwrap_tls_id;
889 if (uwrap.ids == NULL) {
890 UWRAP_UNLOCK(uwrap_id);
891 return;
894 if (id == NULL) {
895 UWRAP_LOG(UWRAP_LOG_ERROR,
896 "Invalid id for thread");
897 exit(-1);
900 UWRAP_UNLOCK(uwrap_id);
901 return;
904 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
906 uwrap.initialised = true;
908 env = getenv("UID_WRAPPER");
909 if (env != NULL && env[0] == '1') {
910 const char *root = getenv("UID_WRAPPER_ROOT");
911 struct uwrap_thread *id;
913 id = calloc(1, sizeof(struct uwrap_thread));
914 if (id == NULL) {
915 UWRAP_LOG(UWRAP_LOG_ERROR,
916 "Unable to allocate memory for main id");
917 exit(-1);
920 UWRAP_DLIST_ADD(uwrap.ids, id);
921 uwrap_tls_id = id;
923 uwrap.myuid = libc_geteuid();
924 uwrap.mygid = libc_getegid();
926 /* put us in one group */
927 if (root != NULL && root[0] == '1') {
928 id->ruid = id->euid = id->suid = 0;
929 id->rgid = id->egid = id->sgid = 0;
931 id->groups = malloc(sizeof(gid_t) * 1);
932 if (id->groups == NULL) {
933 UWRAP_LOG(UWRAP_LOG_ERROR,
934 "Unable to allocate memory");
935 exit(-1);
938 id->ngroups = 1;
939 id->groups[0] = 0;
941 } else {
942 id->ruid = id->euid = id->suid = uwrap.myuid;
943 id->rgid = id->egid = id->sgid = uwrap.mygid;
945 id->ngroups = libc_getgroups(0, NULL);
946 if (id->ngroups == -1) {
947 UWRAP_LOG(UWRAP_LOG_ERROR,
948 "Unable to call libc_getgroups in uwrap_init.");
949 exit(-1);
951 id->groups = malloc(sizeof(gid_t) * id->ngroups);
952 if (id->groups == NULL) {
953 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
954 exit(-1);
956 if (libc_getgroups(id->ngroups, id->groups) == -1) {
957 UWRAP_LOG(UWRAP_LOG_ERROR,
958 "Unable to call libc_getgroups again in uwrap_init.");
959 id->groups = 0;
961 * Deallocation of uwrap.groups is handled by
962 * library destructor.
964 exit(-1);
968 id->enabled = true;
970 UWRAP_LOG(UWRAP_LOG_DEBUG,
971 "Enabled uid_wrapper as %s (real uid=%u)",
972 id->ruid == 0 ? "root" : "user",
973 (unsigned int)uwrap.myuid);
976 UWRAP_UNLOCK(uwrap_id);
978 UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
981 bool uid_wrapper_enabled(void)
983 struct uwrap_thread *id = uwrap_tls_id;
984 bool enabled;
986 if (id == NULL) {
987 return false;
990 UWRAP_LOCK(uwrap_id);
991 enabled = id->enabled;
992 UWRAP_UNLOCK(uwrap_id);
994 return enabled;
998 * UWRAP_SETxUID FUNCTIONS
1001 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1003 struct uwrap_thread *id = uwrap_tls_id;
1005 UWRAP_LOG(UWRAP_LOG_TRACE,
1006 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1007 id->ruid, ruid, id->euid, euid, id->suid, suid);
1009 if (id->euid != 0) {
1010 if (ruid != (uid_t)-1 &&
1011 ruid != id->ruid &&
1012 ruid != id->euid &&
1013 ruid != id->suid) {
1014 errno = EPERM;
1015 return -1;
1017 if (euid != (uid_t)-1 &&
1018 euid != id->ruid &&
1019 euid != id->euid &&
1020 euid != id->suid) {
1021 errno = EPERM;
1022 return -1;
1024 if (suid != (uid_t)-1 &&
1025 suid != id->ruid &&
1026 suid != id->euid &&
1027 suid != id->suid) {
1028 errno = EPERM;
1029 return -1;
1033 return 0;
1036 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1038 struct uwrap_thread *id = uwrap_tls_id;
1039 int rc;
1041 UWRAP_LOG(UWRAP_LOG_TRACE,
1042 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1043 id->ruid, ruid, id->euid, euid, id->suid, suid);
1045 rc = uwrap_setresuid_args(ruid, euid, suid);
1046 if (rc != 0) {
1047 return rc;
1050 UWRAP_LOCK(uwrap_id);
1052 if (ruid != (uid_t)-1) {
1053 id->ruid = ruid;
1056 if (euid != (uid_t)-1) {
1057 id->euid = euid;
1060 if (suid != (uid_t)-1) {
1061 id->suid = suid;
1064 UWRAP_UNLOCK(uwrap_id);
1066 return 0;
1069 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1071 struct uwrap_thread *id = uwrap_tls_id;
1072 int rc;
1074 UWRAP_LOG(UWRAP_LOG_TRACE,
1075 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1076 id->ruid, ruid, id->euid, euid, id->suid, suid);
1078 rc = uwrap_setresuid_args(ruid, euid, suid);
1079 if (rc != 0) {
1080 return rc;
1083 UWRAP_LOCK(uwrap_id);
1085 for (id = uwrap.ids; id; id = id->next) {
1086 if (ruid != (uid_t)-1) {
1087 id->ruid = ruid;
1090 if (euid != (uid_t)-1) {
1091 id->euid = euid;
1094 if (suid != (uid_t)-1) {
1095 id->suid = suid;
1099 UWRAP_UNLOCK(uwrap_id);
1101 return 0;
1104 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1105 uid_t *_new_ruid,
1106 uid_t *_new_euid,
1107 uid_t *_new_suid)
1109 struct uwrap_thread *id = uwrap_tls_id;
1110 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1112 UWRAP_LOG(UWRAP_LOG_TRACE,
1113 "ruid %d -> %d, euid %d -> %d",
1114 id->ruid, ruid, id->euid, euid);
1116 if (ruid != (uid_t)-1) {
1117 new_ruid = ruid;
1118 if (ruid != id->ruid &&
1119 ruid != id->euid &&
1120 id->euid != 0) {
1121 errno = EPERM;
1122 return -1;
1126 if (euid != (uid_t)-1) {
1127 new_euid = euid;
1128 if (euid != id->ruid &&
1129 euid != id->euid &&
1130 euid != id->suid &&
1131 id->euid != 0) {
1132 errno = EPERM;
1133 return -1;
1137 if (ruid != (uid_t) -1 ||
1138 (euid != (uid_t)-1 && id->ruid != euid)) {
1139 new_suid = new_euid;
1142 *_new_ruid = new_ruid;
1143 *_new_euid = new_euid;
1144 *_new_suid = new_suid;
1146 return 0;
1149 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1151 #ifndef NDEBUG
1152 struct uwrap_thread *id = uwrap_tls_id;
1153 #endif
1154 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1155 int rc;
1157 UWRAP_LOG(UWRAP_LOG_TRACE,
1158 "ruid %d -> %d, euid %d -> %d",
1159 id->ruid, ruid, id->euid, euid);
1161 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1162 if (rc != 0) {
1163 return rc;
1166 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1169 #ifdef HAVE_SETREUID
1170 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1172 #ifndef NDEBUG
1173 struct uwrap_thread *id = uwrap_tls_id;
1174 #endif
1175 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1176 int rc;
1178 UWRAP_LOG(UWRAP_LOG_TRACE,
1179 "ruid %d -> %d, euid %d -> %d",
1180 id->ruid, ruid, id->euid, euid);
1182 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1183 if (rc != 0) {
1184 return rc;
1187 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1189 #endif
1191 static int uwrap_setuid_args(uid_t uid,
1192 uid_t *new_ruid,
1193 uid_t *new_euid,
1194 uid_t *new_suid)
1196 struct uwrap_thread *id = uwrap_tls_id;
1198 UWRAP_LOG(UWRAP_LOG_TRACE,
1199 "uid %d -> %d",
1200 id->ruid, uid);
1202 if (uid == (uid_t)-1) {
1203 errno = EINVAL;
1204 return -1;
1207 if (id->euid == 0) {
1208 *new_suid = *new_ruid = uid;
1209 } else if (uid != id->ruid &&
1210 uid != id->suid) {
1211 errno = EPERM;
1212 return -1;
1215 *new_euid = uid;
1217 return 0;
1220 static int uwrap_setuid_thread(uid_t uid)
1222 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1223 int rc;
1225 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1226 if (rc != 0) {
1227 return rc;
1230 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1233 static int uwrap_setuid(uid_t uid)
1235 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1236 int rc;
1238 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1239 if (rc != 0) {
1240 return rc;
1243 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1247 * UWRAP_GETxUID FUNCTIONS
1250 #ifdef HAVE_GETRESUID
1251 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1253 struct uwrap_thread *id = uwrap_tls_id;
1255 UWRAP_LOCK(uwrap_id);
1257 *ruid = id->ruid;
1258 *euid = id->euid;
1259 *suid = id->suid;
1261 UWRAP_UNLOCK(uwrap_id);
1263 return 0;
1265 #endif
1267 #ifdef HAVE_GETRESGID
1268 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1270 struct uwrap_thread *id = uwrap_tls_id;
1272 UWRAP_LOCK(uwrap_id);
1274 *rgid = id->rgid;
1275 *egid = id->egid;
1276 *sgid = id->sgid;
1278 UWRAP_UNLOCK(uwrap_id);
1280 return 0;
1282 #endif
1285 * UWRAP_SETxGID FUNCTIONS
1288 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1290 struct uwrap_thread *id = uwrap_tls_id;
1292 UWRAP_LOG(UWRAP_LOG_TRACE,
1293 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1294 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1296 if (id->euid != 0) {
1297 if (rgid != (gid_t)-1 &&
1298 rgid != id->rgid &&
1299 rgid != id->egid &&
1300 rgid != id->sgid) {
1301 errno = EPERM;
1302 return -1;
1304 if (egid != (gid_t)-1 &&
1305 egid != id->rgid &&
1306 egid != id->egid &&
1307 egid != id->sgid) {
1308 errno = EPERM;
1309 return -1;
1311 if (sgid != (gid_t)-1 &&
1312 sgid != id->rgid &&
1313 sgid != id->egid &&
1314 sgid != id->sgid) {
1315 errno = EPERM;
1316 return -1;
1320 return 0;
1323 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1325 struct uwrap_thread *id = uwrap_tls_id;
1326 int rc;
1328 UWRAP_LOG(UWRAP_LOG_TRACE,
1329 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1330 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1332 rc = uwrap_setresgid_args(rgid, egid, sgid);
1333 if (rc != 0) {
1334 return rc;
1337 UWRAP_LOCK(uwrap_id);
1339 if (rgid != (gid_t)-1) {
1340 id->rgid = rgid;
1343 if (egid != (gid_t)-1) {
1344 id->egid = egid;
1347 if (sgid != (gid_t)-1) {
1348 id->sgid = sgid;
1351 UWRAP_UNLOCK(uwrap_id);
1353 return 0;
1356 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1358 struct uwrap_thread *id = uwrap_tls_id;
1359 int rc;
1361 UWRAP_LOG(UWRAP_LOG_TRACE,
1362 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1363 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1365 rc = uwrap_setresgid_args(rgid, egid, sgid);
1366 if (rc != 0) {
1367 return rc;
1370 UWRAP_LOCK(uwrap_id);
1372 for (id = uwrap.ids; id; id = id->next) {
1373 if (rgid != (gid_t)-1) {
1374 id->rgid = rgid;
1377 if (egid != (gid_t)-1) {
1378 id->egid = egid;
1381 if (sgid != (gid_t)-1) {
1382 id->sgid = sgid;
1386 UWRAP_UNLOCK(uwrap_id);
1388 return 0;
1391 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1392 gid_t *_new_rgid,
1393 gid_t *_new_egid,
1394 gid_t *_new_sgid)
1396 struct uwrap_thread *id = uwrap_tls_id;
1397 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1399 UWRAP_LOG(UWRAP_LOG_TRACE,
1400 "rgid %d -> %d, egid %d -> %d",
1401 id->rgid, rgid, id->egid, egid);
1403 if (rgid != (gid_t)-1) {
1404 new_rgid = rgid;
1405 if (rgid != id->rgid &&
1406 rgid != id->egid &&
1407 id->euid != 0) {
1408 errno = EPERM;
1409 return -1;
1413 if (egid != (gid_t)-1) {
1414 new_egid = egid;
1415 if (egid != id->rgid &&
1416 egid != id->egid &&
1417 egid != id->sgid &&
1418 id->euid != 0) {
1419 errno = EPERM;
1420 return -1;
1424 if (rgid != (gid_t) -1 ||
1425 (egid != (gid_t)-1 && id->rgid != egid)) {
1426 new_sgid = new_egid;
1429 *_new_rgid = new_rgid;
1430 *_new_egid = new_egid;
1431 *_new_sgid = new_sgid;
1433 return 0;
1436 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1438 #ifndef NDEBUG
1439 struct uwrap_thread *id = uwrap_tls_id;
1440 #endif
1441 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1442 int rc;
1444 UWRAP_LOG(UWRAP_LOG_TRACE,
1445 "rgid %d -> %d, egid %d -> %d",
1446 id->rgid, rgid, id->egid, egid);
1448 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1449 if (rc != 0) {
1450 return rc;
1453 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1456 #ifdef HAVE_SETREGID
1457 static int uwrap_setregid(gid_t rgid, gid_t egid)
1459 #ifndef NDEBUG
1460 struct uwrap_thread *id = uwrap_tls_id;
1461 #endif
1462 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1463 int rc;
1465 UWRAP_LOG(UWRAP_LOG_TRACE,
1466 "rgid %d -> %d, egid %d -> %d",
1467 id->rgid, rgid, id->egid, egid);
1469 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1470 if (rc != 0) {
1471 return rc;
1474 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1476 #endif
1478 static int uwrap_setgid_args(gid_t gid,
1479 gid_t *new_rgid,
1480 gid_t *new_egid,
1481 gid_t *new_sgid)
1483 struct uwrap_thread *id = uwrap_tls_id;
1485 UWRAP_LOG(UWRAP_LOG_TRACE,
1486 "gid %d -> %d",
1487 id->rgid, gid);
1489 if (gid == (gid_t)-1) {
1490 errno = EINVAL;
1491 return -1;
1494 if (id->euid == 0) {
1495 *new_sgid = *new_rgid = gid;
1496 } else if (gid != id->rgid &&
1497 gid != id->sgid) {
1498 errno = EPERM;
1499 return -1;
1502 *new_egid = gid;
1504 return 0;
1507 static int uwrap_setgid_thread(gid_t gid)
1509 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1510 int rc;
1512 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1513 if (rc != 0) {
1514 return rc;
1517 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1520 static int uwrap_setgid(gid_t gid)
1522 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1523 int rc;
1525 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1526 if (rc != 0) {
1527 return rc;
1530 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1534 * SETUID
1536 int setuid(uid_t uid)
1538 if (!uid_wrapper_enabled()) {
1539 return libc_setuid(uid);
1542 uwrap_init();
1543 return uwrap_setuid(uid);
1546 #ifdef HAVE_SETEUID
1547 int seteuid(uid_t euid)
1549 if (!uid_wrapper_enabled()) {
1550 return libc_seteuid(euid);
1553 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1554 if (euid == (uid_t)-1) {
1555 errno = EINVAL;
1556 return -1;
1559 uwrap_init();
1560 return uwrap_setresuid(-1, euid, -1);
1562 #endif
1564 #ifdef HAVE_SETREUID
1565 int setreuid(uid_t ruid, uid_t euid)
1567 if (!uid_wrapper_enabled()) {
1568 return libc_setreuid(ruid, euid);
1571 uwrap_init();
1572 return uwrap_setreuid(ruid, euid);
1574 #endif
1576 #ifdef HAVE_SETRESUID
1577 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1579 if (!uid_wrapper_enabled()) {
1580 return libc_setresuid(ruid, euid, suid);
1583 uwrap_init();
1584 return uwrap_setresuid(ruid, euid, suid);
1586 #endif
1588 #ifdef HAVE_GETRESUID
1589 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1591 if (!uid_wrapper_enabled()) {
1592 return libc_getresuid(ruid, euid, suid);
1595 uwrap_init();
1596 return uwrap_getresuid(ruid, euid, suid);
1598 #endif
1601 * GETUID
1603 static uid_t uwrap_getuid(void)
1605 struct uwrap_thread *id = uwrap_tls_id;
1606 uid_t uid;
1608 UWRAP_LOCK(uwrap_id);
1609 uid = id->ruid;
1610 UWRAP_UNLOCK(uwrap_id);
1612 return uid;
1615 uid_t getuid(void)
1617 if (!uid_wrapper_enabled()) {
1618 return libc_getuid();
1621 uwrap_init();
1622 return uwrap_getuid();
1626 * GETEUID
1628 static uid_t uwrap_geteuid(void)
1630 const char *env = getenv("UID_WRAPPER_MYUID");
1631 struct uwrap_thread *id = uwrap_tls_id;
1632 uid_t uid;
1634 UWRAP_LOCK(uwrap_id);
1635 uid = id->euid;
1636 UWRAP_UNLOCK(uwrap_id);
1638 /* Disable root and return myuid */
1639 if (env != NULL && env[0] == '1') {
1640 uid = uwrap.myuid;
1643 return uid;
1646 uid_t geteuid(void)
1648 if (!uid_wrapper_enabled()) {
1649 return libc_geteuid();
1652 uwrap_init();
1653 return uwrap_geteuid();
1657 * SETGID
1659 int setgid(gid_t gid)
1661 if (!uid_wrapper_enabled()) {
1662 return libc_setgid(gid);
1665 uwrap_init();
1666 return uwrap_setgid(gid);
1669 #ifdef HAVE_SETEGID
1670 int setegid(gid_t egid)
1672 if (!uid_wrapper_enabled()) {
1673 return libc_setegid(egid);
1676 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1677 if (egid == (gid_t)-1) {
1678 errno = EINVAL;
1679 return -1;
1682 uwrap_init();
1683 return uwrap_setresgid(-1, egid, -1);
1685 #endif
1687 #ifdef HAVE_SETREGID
1688 int setregid(gid_t rgid, gid_t egid)
1690 if (!uid_wrapper_enabled()) {
1691 return libc_setregid(rgid, egid);
1694 uwrap_init();
1695 return uwrap_setregid(rgid, egid);
1697 #endif
1699 #ifdef HAVE_SETRESGID
1700 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1702 if (!uid_wrapper_enabled()) {
1703 return libc_setresgid(rgid, egid, sgid);
1706 uwrap_init();
1707 return uwrap_setresgid(rgid, egid, sgid);
1709 #endif
1711 #ifdef HAVE_GETRESGID
1712 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1714 if (!uid_wrapper_enabled()) {
1715 return libc_getresgid(rgid, egid, sgid);
1718 uwrap_init();
1719 return uwrap_getresgid(rgid, egid, sgid);
1721 #endif
1724 * GETGID
1726 static gid_t uwrap_getgid(void)
1728 struct uwrap_thread *id = uwrap_tls_id;
1729 gid_t gid;
1731 UWRAP_LOCK(uwrap_id);
1732 gid = id->rgid;
1733 UWRAP_UNLOCK(uwrap_id);
1735 return gid;
1738 gid_t getgid(void)
1740 if (!uid_wrapper_enabled()) {
1741 return libc_getgid();
1744 uwrap_init();
1745 return uwrap_getgid();
1749 * GETEGID
1751 static uid_t uwrap_getegid(void)
1753 struct uwrap_thread *id = uwrap_tls_id;
1754 gid_t gid;
1756 UWRAP_LOCK(uwrap_id);
1757 gid = id->egid;
1758 UWRAP_UNLOCK(uwrap_id);
1760 return gid;
1763 uid_t getegid(void)
1765 if (!uid_wrapper_enabled()) {
1766 return libc_getegid();
1769 uwrap_init();
1770 return uwrap_getegid();
1773 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1775 struct uwrap_thread *id = uwrap_tls_id;
1776 int rc = -1;
1778 UWRAP_LOCK(uwrap_id);
1780 if (size == 0) {
1781 SAFE_FREE(id->groups);
1782 id->ngroups = 0;
1783 } else if (size > 0) {
1784 gid_t *tmp;
1786 tmp = realloc(id->groups, sizeof(gid_t) * size);
1787 if (tmp == NULL) {
1788 errno = ENOMEM;
1789 goto out;
1791 id->groups = tmp;
1792 id->ngroups = size;
1793 memcpy(id->groups, list, size * sizeof(gid_t));
1796 rc = 0;
1797 out:
1798 UWRAP_UNLOCK(uwrap_id);
1800 return rc;
1803 static int uwrap_setgroups(size_t size, const gid_t *list)
1805 struct uwrap_thread *id;
1806 int rc = -1;
1808 UWRAP_LOCK(uwrap_id);
1810 if (size == 0) {
1811 for (id = uwrap.ids; id; id = id->next) {
1812 SAFE_FREE(id->groups);
1813 id->ngroups = 0;
1816 } else if (size > 0) {
1817 gid_t *tmp;
1819 for (id = uwrap.ids; id; id = id->next) {
1820 tmp = realloc(id->groups, sizeof(gid_t) * size);
1821 if (tmp == NULL) {
1822 errno = ENOMEM;
1823 goto out;
1825 id->groups = tmp;
1827 id->ngroups = size;
1828 memcpy(id->groups, list, size * sizeof(gid_t));
1832 rc = 0;
1833 out:
1834 UWRAP_UNLOCK(uwrap_id);
1836 return rc;
1839 #ifdef HAVE_SETGROUPS_INT
1840 int setgroups(int size, const gid_t *list)
1841 #else
1842 int setgroups(size_t size, const gid_t *list)
1843 #endif
1845 if (!uid_wrapper_enabled()) {
1846 return libc_setgroups(size, list);
1849 uwrap_init();
1850 return uwrap_setgroups(size, list);
1853 static int uwrap_getgroups(int size, gid_t *list)
1855 struct uwrap_thread *id = uwrap_tls_id;
1856 int ngroups;
1858 UWRAP_LOCK(uwrap_id);
1859 ngroups = id->ngroups;
1861 if (size > ngroups) {
1862 size = ngroups;
1864 if (size == 0) {
1865 goto out;
1867 if (size < ngroups) {
1868 errno = EINVAL;
1869 ngroups = -1;
1871 memcpy(list, id->groups, size * sizeof(gid_t));
1873 out:
1874 UWRAP_UNLOCK(uwrap_id);
1876 return ngroups;
1879 int getgroups(int size, gid_t *list)
1881 if (!uid_wrapper_enabled()) {
1882 return libc_getgroups(size, list);
1885 uwrap_init();
1886 return uwrap_getgroups(size, list);
1889 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1890 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1891 static long int uwrap_syscall (long int sysno, va_list vp)
1893 long int rc;
1895 switch (sysno) {
1896 /* gid */
1897 case SYS_getgid:
1898 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1899 case SYS_getgid32:
1900 #endif
1902 rc = uwrap_getgid();
1904 break;
1905 #ifdef SYS_getegid
1906 case SYS_getegid:
1907 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1908 case SYS_getegid32:
1909 #endif
1911 rc = uwrap_getegid();
1913 break;
1914 #endif /* SYS_getegid */
1915 case SYS_setgid:
1916 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1917 case SYS_setgid32:
1918 #endif
1920 gid_t gid = (gid_t) va_arg(vp, gid_t);
1922 rc = uwrap_setgid_thread(gid);
1924 break;
1925 case SYS_setregid:
1926 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1927 case SYS_setregid32:
1928 #endif
1930 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1931 gid_t egid = (gid_t) va_arg(vp, gid_t);
1933 rc = uwrap_setregid_thread(rgid, egid);
1935 break;
1936 #ifdef SYS_setresgid
1937 case SYS_setresgid:
1938 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1939 case SYS_setresgid32:
1940 #endif
1942 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1943 gid_t egid = (gid_t) va_arg(vp, gid_t);
1944 gid_t sgid = (gid_t) va_arg(vp, gid_t);
1946 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1948 break;
1949 #endif /* SYS_setresgid */
1950 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
1951 case SYS_getresgid:
1952 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1953 case SYS_getresgid32:
1954 #endif
1956 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
1957 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
1958 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
1960 rc = uwrap_getresgid(rgid, egid, sgid);
1962 break;
1963 #endif /* SYS_getresgid && HAVE_GETRESGID */
1965 /* uid */
1966 case SYS_getuid:
1967 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1968 case SYS_getuid32:
1969 #endif
1971 rc = uwrap_getuid();
1973 break;
1974 #ifdef SYS_geteuid
1975 case SYS_geteuid:
1976 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1977 case SYS_geteuid32:
1978 #endif
1980 rc = uwrap_geteuid();
1982 break;
1983 #endif /* SYS_geteuid */
1984 case SYS_setuid:
1985 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1986 case SYS_setuid32:
1987 #endif
1989 uid_t uid = (uid_t) va_arg(vp, uid_t);
1991 rc = uwrap_setuid_thread(uid);
1993 break;
1994 case SYS_setreuid:
1995 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1996 case SYS_setreuid32:
1997 #endif
1999 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2000 uid_t euid = (uid_t) va_arg(vp, uid_t);
2002 rc = uwrap_setreuid_thread(ruid, euid);
2004 break;
2005 #ifdef SYS_setresuid
2006 case SYS_setresuid:
2007 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2008 case SYS_setresuid32:
2009 #endif
2011 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2012 uid_t euid = (uid_t) va_arg(vp, uid_t);
2013 uid_t suid = (uid_t) va_arg(vp, uid_t);
2015 rc = uwrap_setresuid_thread(ruid, euid, suid);
2017 break;
2018 #endif /* SYS_setresuid */
2019 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2020 case SYS_getresuid:
2021 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2022 case SYS_getresuid32:
2023 #endif
2025 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2026 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2027 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2029 rc = uwrap_getresuid(ruid, euid, suid);
2031 break;
2032 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2033 /* groups */
2034 case SYS_setgroups:
2035 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2036 case SYS_setgroups32:
2037 #endif
2039 size_t size = (size_t) va_arg(vp, size_t);
2040 gid_t *list = (gid_t *) va_arg(vp, int *);
2042 rc = uwrap_setgroups_thread(size, list);
2044 break;
2045 default:
2046 UWRAP_LOG(UWRAP_LOG_DEBUG,
2047 "UID_WRAPPER calling non-wrapped syscall %lu",
2048 sysno);
2050 rc = libc_vsyscall(sysno, vp);
2051 break;
2054 return rc;
2057 #ifdef HAVE_SYSCALL
2058 #ifdef HAVE_SYSCALL_INT
2059 int syscall (int sysno, ...)
2060 #else
2061 long int syscall (long int sysno, ...)
2062 #endif
2064 #ifdef HAVE_SYSCALL_INT
2065 int rc;
2066 #else
2067 long int rc;
2068 #endif
2069 va_list va;
2071 va_start(va, sysno);
2073 if (!uid_wrapper_enabled()) {
2074 rc = libc_vsyscall(sysno, va);
2075 va_end(va);
2076 return rc;
2079 uwrap_init();
2080 rc = uwrap_syscall(sysno, va);
2081 va_end(va);
2083 return rc;
2085 #endif /* HAVE_SYSCALL */
2086 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2088 /****************************
2089 * CONSTRUCTOR
2090 ***************************/
2091 void uwrap_constructor(void)
2094 * If we hold a lock and the application forks, then the child
2095 * is not able to unlock the mutex and we are in a deadlock.
2096 * This should prevent such deadlocks.
2098 pthread_atfork(&uwrap_thread_prepare,
2099 &uwrap_thread_parent,
2100 &uwrap_thread_child);
2102 /* Here is safe place to call uwrap_init() and initialize data
2103 * for main process.
2105 uwrap_init();
2108 /****************************
2109 * DESTRUCTOR
2110 ***************************/
2113 * This function is called when the library is unloaded and makes sure that
2114 * resources are freed.
2116 void uwrap_destructor(void)
2118 struct uwrap_thread *u = uwrap.ids;
2120 UWRAP_LOCK_ALL;
2122 while (u != NULL) {
2123 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2125 SAFE_FREE(u->groups);
2126 SAFE_FREE(u);
2128 u = uwrap.ids;
2132 if (uwrap.libc.handle != NULL) {
2133 dlclose(uwrap.libc.handle);
2136 if (uwrap.libpthread.handle != NULL) {
2137 dlclose(uwrap.libpthread.handle);
2140 UWRAP_UNLOCK_ALL;