wscript: drop checks for setnetgrent/endnetgrent/getnetgrent
[Samba.git] / third_party / uid_wrapper / uid_wrapper.c
blob8f41ed92cb953b72c10e6a22485abbe5f59339c9
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 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
137 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
139 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
141 char buffer[1024];
142 va_list va;
143 const char *d;
144 unsigned int lvl = 0;
145 const char *prefix = "UWRAP";
147 d = getenv("UID_WRAPPER_DEBUGLEVEL");
148 if (d != NULL) {
149 lvl = atoi(d);
152 if (lvl < dbglvl) {
153 return;
156 va_start(va, format);
157 vsnprintf(buffer, sizeof(buffer), format, va);
158 va_end(va);
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 /*****************
184 * LIBC
185 *****************/
187 #define LIBC_NAME "libc.so"
189 typedef int (*__libc_setuid)(uid_t uid);
191 typedef uid_t (*__libc_getuid)(void);
193 #ifdef HAVE_SETEUID
194 typedef int (*__libc_seteuid)(uid_t euid);
195 #endif
197 #ifdef HAVE_SETREUID
198 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
199 #endif
201 #ifdef HAVE_SETRESUID
202 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
203 #endif
205 #ifdef HAVE_GETRESUID
206 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
207 #endif
209 typedef uid_t (*__libc_geteuid)(void);
211 typedef int (*__libc_setgid)(gid_t gid);
213 typedef gid_t (*__libc_getgid)(void);
215 #ifdef HAVE_SETEGID
216 typedef int (*__libc_setegid)(uid_t egid);
217 #endif
219 #ifdef HAVE_SETREGID
220 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
221 #endif
223 #ifdef HAVE_SETRESGID
224 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
225 #endif
227 #ifdef HAVE_GETRESGID
228 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
229 #endif
231 typedef gid_t (*__libc_getegid)(void);
233 typedef int (*__libc_getgroups)(int size, gid_t list[]);
235 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
237 #ifdef HAVE_SYSCALL
238 typedef long int (*__libc_syscall)(long int sysno, ...);
239 #endif
241 #define UWRAP_SYMBOL_ENTRY(i) \
242 union { \
243 __libc_##i f; \
244 void *obj; \
245 } _libc_##i
247 struct uwrap_libc_symbols {
248 UWRAP_SYMBOL_ENTRY(setuid);
249 UWRAP_SYMBOL_ENTRY(getuid);
250 #ifdef HAVE_SETEUID
251 UWRAP_SYMBOL_ENTRY(seteuid);
252 #endif
253 #ifdef HAVE_SETREUID
254 UWRAP_SYMBOL_ENTRY(setreuid);
255 #endif
256 #ifdef HAVE_SETRESUID
257 UWRAP_SYMBOL_ENTRY(setresuid);
258 #endif
259 #ifdef HAVE_GETRESUID
260 UWRAP_SYMBOL_ENTRY(getresuid);
261 #endif
262 UWRAP_SYMBOL_ENTRY(geteuid);
263 UWRAP_SYMBOL_ENTRY(setgid);
264 UWRAP_SYMBOL_ENTRY(getgid);
265 #ifdef HAVE_SETEGID
266 UWRAP_SYMBOL_ENTRY(setegid);
267 #endif
268 #ifdef HAVE_SETREGID
269 UWRAP_SYMBOL_ENTRY(setregid);
270 #endif
271 #ifdef HAVE_SETRESGID
272 UWRAP_SYMBOL_ENTRY(setresgid);
273 #endif
274 #ifdef HAVE_GETRESGID
275 UWRAP_SYMBOL_ENTRY(getresgid);
276 #endif
277 UWRAP_SYMBOL_ENTRY(getegid);
278 UWRAP_SYMBOL_ENTRY(getgroups);
279 UWRAP_SYMBOL_ENTRY(setgroups);
280 #ifdef HAVE_SYSCALL
281 UWRAP_SYMBOL_ENTRY(syscall);
282 #endif
284 #undef UWRAP_SYMBOL_ENTRY
286 /*****************
287 * LIBPTHREAD
288 *****************/
289 /* Yeah... I'm pig. I overloading macro here... So what? */
290 #define UWRAP_SYMBOL_ENTRY(i) \
291 union { \
292 __libpthread_##i f; \
293 void *obj; \
294 } _libpthread_##i
296 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
297 const pthread_attr_t *attr,
298 void *(*start_routine) (void *),
299 void *arg);
300 typedef void (*__libpthread_pthread_exit)(void *retval);
302 struct uwrap_libpthread_symbols {
303 UWRAP_SYMBOL_ENTRY(pthread_create);
304 UWRAP_SYMBOL_ENTRY(pthread_exit);
306 #undef UWRAP_SYMBOL_ENTRY
309 * We keep the virtualised euid/egid/groups information here
311 struct uwrap_thread {
312 bool enabled;
314 uid_t ruid;
315 uid_t euid;
316 uid_t suid;
318 gid_t rgid;
319 gid_t egid;
320 gid_t sgid;
322 int ngroups;
323 gid_t *groups;
325 struct uwrap_thread *next;
326 struct uwrap_thread *prev;
329 struct uwrap {
330 struct {
331 void *handle;
332 struct uwrap_libc_symbols symbols;
333 } libc;
335 struct {
336 void *handle;
337 struct uwrap_libpthread_symbols symbols;
338 } libpthread;
340 bool initialised;
342 /* Real uid and gid of user who run uid wrapper */
343 uid_t myuid;
344 gid_t mygid;
346 struct uwrap_thread *ids;
349 static struct uwrap uwrap;
351 /* Shortcut to the list item */
352 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
354 /* The mutex or accessing the id */
355 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
357 /* The mutex for accessing the global libc.symbols */
358 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
360 /* The mutex for accessing the global libpthread.symbols */
361 static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
363 /*********************************************************
364 * UWRAP PROTOTYPES
365 *********************************************************/
367 bool uid_wrapper_enabled(void);
368 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
369 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
371 /*********************************************************
372 * UWRAP LIBC LOADER FUNCTIONS
373 *********************************************************/
375 enum uwrap_lib {
376 UWRAP_LIBC,
377 UWRAP_LIBNSL,
378 UWRAP_LIBSOCKET,
379 UWRAP_LIBPTHREAD,
382 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
384 int flags = RTLD_LAZY;
385 void *handle = NULL;
386 int i;
388 #ifdef RTLD_DEEPBIND
389 flags |= RTLD_DEEPBIND;
390 #endif
392 switch (lib) {
393 case UWRAP_LIBNSL:
394 /* FALL TROUGH */
395 case UWRAP_LIBSOCKET:
396 /* FALL TROUGH */
397 case UWRAP_LIBC:
398 handle = uwrap.libc.handle;
399 if (handle == NULL) {
400 for (i = 10; i >= 0; i--) {
401 char soname[256] = {0};
403 snprintf(soname, sizeof(soname), "libc.so.%d", i);
404 handle = dlopen(soname, flags);
405 if (handle != NULL) {
406 break;
409 /* glibc on Alpha and IA64 is libc.so.6.1 */
410 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
411 handle = dlopen(soname, flags);
412 if (handle != NULL) {
413 break;
417 uwrap.libc.handle = handle;
419 break;
420 case UWRAP_LIBPTHREAD:
421 handle = uwrap.libpthread.handle;
422 if (handle == NULL) {
423 handle = dlopen("libpthread.so.0", flags);
424 if (handle != NULL) {
425 break;
428 break;
431 if (handle == NULL) {
432 #ifdef RTLD_NEXT
433 handle = uwrap.libc.handle = RTLD_NEXT;
434 #else
435 fprintf(stderr,
436 "Failed to dlopen library: %s\n",
437 dlerror());
438 exit(-1);
439 #endif
442 return handle;
445 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
447 void *handle;
448 void *func;
450 handle = uwrap_load_lib_handle(lib);
452 func = dlsym(handle, fn_name);
453 if (func == NULL) {
454 fprintf(stderr,
455 "Failed to find %s: %s\n",
456 fn_name, dlerror());
457 exit(-1);
460 return func;
463 #define uwrap_bind_symbol_libc(sym_name) \
464 UWRAP_LOCK(libc_symbol_binding); \
465 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
466 uwrap.libc.symbols._libc_##sym_name.obj = \
467 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
469 UWRAP_UNLOCK(libc_symbol_binding)
471 #define uwrap_bind_symbol_libpthread(sym_name) \
472 UWRAP_LOCK(libpthread_symbol_binding); \
473 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
474 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
475 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
477 UWRAP_UNLOCK(libpthread_symbol_binding)
480 * IMPORTANT
482 * Functions expeciall from libc need to be loaded individually, you can't load
483 * all at once or gdb will segfault at startup. The same applies to valgrind and
484 * has probably something todo with with the linker.
485 * So we need load each function at the point it is called the first time.
487 static int libc_setuid(uid_t uid)
489 uwrap_bind_symbol_libc(setuid);
491 return uwrap.libc.symbols._libc_setuid.f(uid);
494 static uid_t libc_getuid(void)
496 uwrap_bind_symbol_libc(getuid);
498 return uwrap.libc.symbols._libc_getuid.f();
501 #ifdef HAVE_SETEUID
502 static int libc_seteuid(uid_t euid)
504 uwrap_bind_symbol_libc(seteuid);
506 return uwrap.libc.symbols._libc_seteuid.f(euid);
508 #endif
510 #ifdef HAVE_SETREUID
511 static int libc_setreuid(uid_t ruid, uid_t euid)
513 uwrap_bind_symbol_libc(setreuid);
515 return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
517 #endif
519 #ifdef HAVE_SETRESUID
520 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
522 uwrap_bind_symbol_libc(setresuid);
524 return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
526 #endif
528 #ifdef HAVE_GETRESUID
529 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
531 uwrap_bind_symbol_libc(getresuid);
533 return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
535 #endif
537 static uid_t libc_geteuid(void)
539 uwrap_bind_symbol_libc(geteuid);
541 return uwrap.libc.symbols._libc_geteuid.f();
544 static int libc_setgid(gid_t gid)
546 uwrap_bind_symbol_libc(setgid);
548 return uwrap.libc.symbols._libc_setgid.f(gid);
551 static gid_t libc_getgid(void)
553 uwrap_bind_symbol_libc(getgid);
555 return uwrap.libc.symbols._libc_getgid.f();
558 #ifdef HAVE_SETEGID
559 static int libc_setegid(gid_t egid)
561 uwrap_bind_symbol_libc(setegid);
563 return uwrap.libc.symbols._libc_setegid.f(egid);
565 #endif
567 #ifdef HAVE_SETREGID
568 static int libc_setregid(gid_t rgid, gid_t egid)
570 uwrap_bind_symbol_libc(setregid);
572 return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
574 #endif
576 #ifdef HAVE_SETRESGID
577 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
579 uwrap_bind_symbol_libc(setresgid);
581 return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
583 #endif
585 #ifdef HAVE_GETRESGID
586 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
588 uwrap_bind_symbol_libc(setresgid);
590 return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
592 #endif
594 static gid_t libc_getegid(void)
596 uwrap_bind_symbol_libc(getegid);
598 return uwrap.libc.symbols._libc_getegid.f();
601 static int libc_getgroups(int size, gid_t list[])
603 uwrap_bind_symbol_libc(getgroups);
605 return uwrap.libc.symbols._libc_getgroups.f(size, list);
608 static int libc_setgroups(size_t size, const gid_t *list)
610 uwrap_bind_symbol_libc(setgroups);
612 return uwrap.libc.symbols._libc_setgroups.f(size, list);
615 #ifdef HAVE_SYSCALL
616 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
617 static long int libc_vsyscall(long int sysno, va_list va)
619 long int args[8];
620 long int rc;
621 int i;
623 uwrap_bind_symbol_libc(syscall);
625 for (i = 0; i < 8; i++) {
626 args[i] = va_arg(va, long int);
629 rc = uwrap.libc.symbols._libc_syscall.f(sysno,
630 args[0],
631 args[1],
632 args[2],
633 args[3],
634 args[4],
635 args[5],
636 args[6],
637 args[7]);
639 return rc;
641 #endif
644 * This part is "optimistic".
645 * Thread can ends without pthread_exit call.
647 static void libpthread_pthread_exit(void *retval)
649 uwrap_bind_symbol_libpthread(pthread_exit);
651 uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
654 static void uwrap_pthread_exit(void *retval)
656 struct uwrap_thread *id = uwrap_tls_id;
658 UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
660 UWRAP_LOCK(uwrap_id);
661 if (id == NULL) {
662 UWRAP_UNLOCK(uwrap_id);
663 libpthread_pthread_exit(retval);
664 return;
667 UWRAP_DLIST_REMOVE(uwrap.ids, id);
668 SAFE_FREE(id->groups);
669 SAFE_FREE(id);
670 uwrap_tls_id = NULL;
672 UWRAP_UNLOCK(uwrap_id);
674 libpthread_pthread_exit(retval);
677 void pthread_exit(void *retval)
679 if (!uid_wrapper_enabled()) {
680 libpthread_pthread_exit(retval);
683 uwrap_pthread_exit(retval);
685 /* Calm down gcc warning. */
686 exit(666);
689 static int libpthread_pthread_create(pthread_t *thread,
690 const pthread_attr_t *attr,
691 void *(*start_routine) (void *),
692 void *arg)
694 uwrap_bind_symbol_libpthread(pthread_create);
695 return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
696 attr,
697 start_routine,
698 arg);
701 struct uwrap_pthread_create_args {
702 struct uwrap_thread *id;
703 void *(*start_routine) (void *);
704 void *arg;
707 static void *uwrap_pthread_create_start(void *_a)
709 struct uwrap_pthread_create_args *a =
710 (struct uwrap_pthread_create_args *)_a;
711 void *(*start_routine) (void *) = a->start_routine;
712 void *arg = a->arg;
713 struct uwrap_thread *id = a->id;
715 SAFE_FREE(a);
717 uwrap_tls_id = id;
719 return start_routine(arg);
722 static int uwrap_pthread_create(pthread_t *thread,
723 const pthread_attr_t *attr,
724 void *(*start_routine) (void *),
725 void *arg)
727 struct uwrap_pthread_create_args *args;
728 struct uwrap_thread *src_id = uwrap_tls_id;
729 int ret;
731 args = malloc(sizeof(struct uwrap_pthread_create_args));
732 if (args == NULL) {
733 UWRAP_LOG(UWRAP_LOG_ERROR,
734 "uwrap_pthread_create: Unable to allocate memory");
735 errno = ENOMEM;
736 return -1;
738 args->start_routine = start_routine;
739 args->arg = arg;
741 args->id = calloc(1, sizeof(struct uwrap_thread));
742 if (args->id == NULL) {
743 SAFE_FREE(args);
744 UWRAP_LOG(UWRAP_LOG_ERROR,
745 "uwrap_pthread_create: Unable to allocate memory");
746 errno = ENOMEM;
747 return -1;
750 UWRAP_LOCK(uwrap_id);
752 args->id->groups = malloc(sizeof(gid_t) * src_id->ngroups);
753 if (args->id->groups == NULL) {
754 UWRAP_UNLOCK(uwrap_id);
755 SAFE_FREE(args->id);
756 SAFE_FREE(args);
757 UWRAP_LOG(UWRAP_LOG_ERROR,
758 "uwrap_pthread_create: Unable to allocate memory again");
759 errno = ENOMEM;
760 return -1;
763 args->id->ruid = src_id->ruid;
764 args->id->euid = src_id->euid;
765 args->id->suid = src_id->suid;
767 args->id->rgid = src_id->rgid;
768 args->id->egid = src_id->egid;
769 args->id->sgid = src_id->sgid;
771 args->id->enabled = src_id->enabled;
773 args->id->ngroups = src_id->ngroups;
774 if (src_id->groups != NULL) {
775 memcpy(args->id->groups, src_id->groups,
776 sizeof(gid_t) * src_id->ngroups);
777 } else {
778 SAFE_FREE(args->id->groups);
781 UWRAP_DLIST_ADD(uwrap.ids, args->id);
782 UWRAP_UNLOCK(uwrap_id);
784 ret = libpthread_pthread_create(thread, attr,
785 uwrap_pthread_create_start,
786 args);
787 if (ret != 0) {
788 return ret;
791 return ret;
794 int pthread_create(pthread_t *thread,
795 const pthread_attr_t *attr,
796 void *(*start_routine) (void *),
797 void *arg)
799 if (!uid_wrapper_enabled()) {
800 return libpthread_pthread_create(thread,
801 attr,
802 start_routine,
803 arg);
806 return uwrap_pthread_create(thread,
807 attr,
808 start_routine,
809 arg);
812 /*********************************************************
813 * UWRAP ID HANDLING
814 *********************************************************/
816 #define GROUP_STRING_SIZE 16384
817 #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
820 * This function exports all the IDs of the current user so if
821 * we fork and then exec we can setup uid_wrapper in the new process
822 * with those IDs.
824 static void uwrap_export_ids(struct uwrap_thread *id)
826 char groups_str[GROUP_STRING_SIZE] = {0};
827 size_t groups_str_size = sizeof(groups_str);
828 char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
829 int i;
831 /* UIDS */
832 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
833 setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
835 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
836 setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
838 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
839 setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
841 /* GIDS */
842 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
843 setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
845 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
846 setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
848 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
849 setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
851 if (id->ngroups > GROUP_MAX_COUNT) {
852 UWRAP_LOG(UWRAP_LOG_ERROR,
853 "ERROR: Number of groups (%u) exceeds maximum value "
854 "uid_wrapper can handle (%u).",
855 id->ngroups,
856 GROUP_MAX_COUNT);
857 exit(-1);
860 /* GROUPS */
861 for (i = 0; i < id->ngroups; i++) {
862 size_t groups_str_len = strlen(groups_str);
863 size_t groups_str_avail = groups_str_size - groups_str_len - 1;
864 int len;
866 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
867 if (len <= 1) {
868 UWRAP_LOG(UWRAP_LOG_ERROR,
869 "snprintf failed for groups[%d]=%u",
871 id->groups[i]);
872 break;
874 if (((size_t)len) >= groups_str_avail) {
875 UWRAP_LOG(UWRAP_LOG_ERROR,
876 "groups env string is to small for %d groups",
878 break;
881 len = snprintf(groups_str + groups_str_len,
882 groups_str_size - groups_str_len,
883 "%s",
884 i == 0 ? unsigned_str + 1 : unsigned_str);
885 if (len < 1) {
886 UWRAP_LOG(UWRAP_LOG_ERROR,
887 "snprintf failed to create groups string at groups[%d]=%u",
889 id->groups[i]);
890 break;
894 if (id->ngroups == i) {
895 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
897 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
898 setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
902 static void uwrap_thread_prepare(void)
904 struct uwrap_thread *id = uwrap_tls_id;
906 UWRAP_LOCK_ALL;
908 /* uid_wrapper is loaded but not enabled */
909 if (id == NULL) {
910 return;
914 * What happens if another atfork prepare functions calls a uwrap
915 * function? So disable it in case another atfork prepare function
916 * calls a (s)uid function. We disable uid_wrapper only for thread
917 * (process) which called fork.
919 id->enabled = false;
922 static void uwrap_thread_parent(void)
924 struct uwrap_thread *id = uwrap_tls_id;
926 /* uid_wrapper is loaded but not enabled */
927 if (id == NULL) {
928 UWRAP_UNLOCK_ALL;
929 return;
932 id->enabled = true;
934 UWRAP_UNLOCK_ALL;
937 static void uwrap_thread_child(void)
939 struct uwrap_thread *id = uwrap_tls_id;
940 struct uwrap_thread *u = uwrap.ids;
942 /* uid_wrapper is loaded but not enabled */
943 if (id == NULL) {
944 UWRAP_UNLOCK_ALL;
945 return;
949 * "Garbage collector" - Inspired by DESTRUCTOR.
950 * All threads (except one which called fork()) are dead now.. Dave
951 * That's what posix said...
953 while (u != NULL) {
954 if (u == id) {
955 /* Skip this item. */
956 u = uwrap.ids->next;
957 continue;
960 UWRAP_DLIST_REMOVE(uwrap.ids, u);
962 SAFE_FREE(u->groups);
963 SAFE_FREE(u);
965 u = uwrap.ids;
968 uwrap_export_ids(id);
970 id->enabled = true;
972 UWRAP_UNLOCK_ALL;
976 * This initializes uid_wrapper with the IDs exported to the environment. Those
977 * are normally set after we forked and executed.
979 static void uwrap_init_env(struct uwrap_thread *id)
981 const char *env;
982 int ngroups = 0;
984 env = getenv("UID_WRAPPER_INITIAL_RUID");
985 if (env != NULL && env[0] != '\0') {
986 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
987 id->ruid = strtoul(env, (char **)NULL, 10);
988 unsetenv("UID_WRAPPER_INITIAL_RUID");
991 env = getenv("UID_WRAPPER_INITIAL_EUID");
992 if (env != NULL && env[0] != '\0') {
993 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize euid with %s", env);
994 id->euid = strtoul(env, (char **)NULL, 10);
995 unsetenv("UID_WRAPPER_INITIAL_EUID");
998 env = getenv("UID_WRAPPER_INITIAL_SUID");
999 if (env != NULL && env[0] != '\0') {
1000 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize suid with %s", env);
1001 id->suid = strtoul(env, (char **)NULL, 10);
1002 unsetenv("UID_WRAPPER_INITIAL_SUID");
1005 env = getenv("UID_WRAPPER_INITIAL_RGID");
1006 if (env != NULL && env[0] != '\0') {
1007 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
1008 id->rgid = strtoul(env, (char **)NULL, 10);
1009 unsetenv("UID_WRAPPER_INITIAL_RGID");
1012 env = getenv("UID_WRAPPER_INITIAL_EGID");
1013 if (env != NULL && env[0] != '\0') {
1014 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize egid with %s", env);
1015 id->egid = strtoul(env, (char **)NULL, 10);
1016 unsetenv("UID_WRAPPER_INITIAL_EGID");
1019 env = getenv("UID_WRAPPER_INITIAL_SGID");
1020 if (env != NULL && env[0] != '\0') {
1021 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize sgid with %s", env);
1022 id->sgid = strtoul(env, (char **)NULL, 10);
1023 unsetenv("UID_WRAPPER_INITIAL_SGID");
1026 env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1027 if (env != NULL && env[0] != '\0') {
1028 ngroups = strtol(env, (char **)NULL, 10);
1029 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1032 env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1033 if (env != NULL && env[0] != '\0') {
1034 char *endp = NULL;
1035 long n;
1037 n = strtol(env, &endp, 10);
1038 if (env == endp) {
1039 ngroups = 0;
1040 } else if (n > 0 && n < GROUP_MAX_COUNT) {
1041 ngroups = (int)n;
1043 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1046 if (ngroups > 0) {
1047 int i = 0;
1049 id->ngroups = 0;
1051 free(id->groups);
1052 id->groups = calloc(ngroups, sizeof(gid_t));
1053 if (id->groups == NULL) {
1054 UWRAP_LOG(UWRAP_LOG_ERROR,
1055 "Unable to allocate memory");
1056 exit(-1);
1059 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1060 if (env != NULL && env[0] != '\0') {
1061 char *groups_str = NULL;
1062 char *saveptr = NULL;
1063 const char *p = NULL;
1065 groups_str = strdup(env);
1066 if (groups_str == NULL) {
1067 exit(-1);
1070 p = strtok_r(groups_str, ",", &saveptr);
1071 while (p != NULL) {
1072 id->groups[i] = strtol(p, (char **)NULL, 10);
1073 i++;
1075 p = strtok_r(NULL, ",", &saveptr);
1077 SAFE_FREE(groups_str);
1080 if (i != ngroups) {
1081 UWRAP_LOG(UWRAP_LOG_ERROR,
1082 "ERROR: The number of groups (%u) passed, "
1083 "does not match the number of groups (%u) "
1084 "we parsed.",
1085 ngroups,
1087 exit(-1);
1090 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1091 id->ngroups = ngroups;
1095 static void uwrap_init(void)
1097 const char *env;
1099 UWRAP_LOCK(uwrap_id);
1101 if (uwrap.initialised) {
1102 struct uwrap_thread *id = uwrap_tls_id;
1104 if (uwrap.ids == NULL) {
1105 UWRAP_UNLOCK(uwrap_id);
1106 return;
1109 if (id == NULL) {
1110 UWRAP_LOG(UWRAP_LOG_ERROR,
1111 "Invalid id for thread");
1112 exit(-1);
1115 UWRAP_UNLOCK(uwrap_id);
1116 return;
1119 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1121 uwrap.initialised = true;
1123 env = getenv("UID_WRAPPER");
1124 if (env != NULL && env[0] == '1') {
1125 const char *root = getenv("UID_WRAPPER_ROOT");
1126 struct uwrap_thread *id;
1128 id = calloc(1, sizeof(struct uwrap_thread));
1129 if (id == NULL) {
1130 UWRAP_LOG(UWRAP_LOG_ERROR,
1131 "Unable to allocate memory for main id");
1132 exit(-1);
1135 UWRAP_DLIST_ADD(uwrap.ids, id);
1136 uwrap_tls_id = id;
1138 uwrap.myuid = libc_geteuid();
1139 uwrap.mygid = libc_getegid();
1141 /* put us in one group */
1142 if (root != NULL && root[0] == '1') {
1143 id->ruid = id->euid = id->suid = 0;
1144 id->rgid = id->egid = id->sgid = 0;
1146 id->groups = malloc(sizeof(gid_t) * 1);
1147 if (id->groups == NULL) {
1148 UWRAP_LOG(UWRAP_LOG_ERROR,
1149 "Unable to allocate memory");
1150 exit(-1);
1153 id->ngroups = 1;
1154 id->groups[0] = 0;
1156 } else {
1157 id->ruid = id->euid = id->suid = uwrap.myuid;
1158 id->rgid = id->egid = id->sgid = uwrap.mygid;
1160 id->ngroups = libc_getgroups(0, NULL);
1161 if (id->ngroups == -1) {
1162 UWRAP_LOG(UWRAP_LOG_ERROR,
1163 "Unable to call libc_getgroups in uwrap_init.");
1164 exit(-1);
1166 id->groups = malloc(sizeof(gid_t) * id->ngroups);
1167 if (id->groups == NULL) {
1168 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1169 exit(-1);
1171 if (libc_getgroups(id->ngroups, id->groups) == -1) {
1172 UWRAP_LOG(UWRAP_LOG_ERROR,
1173 "Unable to call libc_getgroups again in uwrap_init.");
1174 id->groups = 0;
1176 * Deallocation of uwrap.groups is handled by
1177 * library destructor.
1179 exit(-1);
1183 uwrap_init_env(id);
1185 id->enabled = true;
1187 UWRAP_LOG(UWRAP_LOG_DEBUG,
1188 "Enabled uid_wrapper as %s (real uid=%u)",
1189 id->ruid == 0 ? "root" : "user",
1190 (unsigned int)uwrap.myuid);
1193 UWRAP_UNLOCK(uwrap_id);
1195 UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1198 bool uid_wrapper_enabled(void)
1200 struct uwrap_thread *id = uwrap_tls_id;
1201 bool enabled;
1203 if (id == NULL) {
1204 return false;
1207 UWRAP_LOCK(uwrap_id);
1208 enabled = id->enabled;
1209 UWRAP_UNLOCK(uwrap_id);
1211 return enabled;
1215 * UWRAP_SETxUID FUNCTIONS
1218 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1220 struct uwrap_thread *id = uwrap_tls_id;
1222 UWRAP_LOG(UWRAP_LOG_TRACE,
1223 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1224 id->ruid, ruid, id->euid, euid, id->suid, suid);
1226 if (id->euid != 0) {
1227 if (ruid != (uid_t)-1 &&
1228 ruid != id->ruid &&
1229 ruid != id->euid &&
1230 ruid != id->suid) {
1231 errno = EPERM;
1232 return -1;
1234 if (euid != (uid_t)-1 &&
1235 euid != id->ruid &&
1236 euid != id->euid &&
1237 euid != id->suid) {
1238 errno = EPERM;
1239 return -1;
1241 if (suid != (uid_t)-1 &&
1242 suid != id->ruid &&
1243 suid != id->euid &&
1244 suid != id->suid) {
1245 errno = EPERM;
1246 return -1;
1250 return 0;
1253 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1255 struct uwrap_thread *id = uwrap_tls_id;
1256 int rc;
1258 UWRAP_LOG(UWRAP_LOG_TRACE,
1259 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1260 id->ruid, ruid, id->euid, euid, id->suid, suid);
1262 rc = uwrap_setresuid_args(ruid, euid, suid);
1263 if (rc != 0) {
1264 return rc;
1267 UWRAP_LOCK(uwrap_id);
1269 if (ruid != (uid_t)-1) {
1270 id->ruid = ruid;
1273 if (euid != (uid_t)-1) {
1274 id->euid = euid;
1277 if (suid != (uid_t)-1) {
1278 id->suid = suid;
1281 UWRAP_UNLOCK(uwrap_id);
1283 return 0;
1286 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1288 struct uwrap_thread *id = uwrap_tls_id;
1289 int rc;
1291 UWRAP_LOG(UWRAP_LOG_TRACE,
1292 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1293 id->ruid, ruid, id->euid, euid, id->suid, suid);
1295 rc = uwrap_setresuid_args(ruid, euid, suid);
1296 if (rc != 0) {
1297 return rc;
1300 UWRAP_LOCK(uwrap_id);
1302 for (id = uwrap.ids; id; id = id->next) {
1303 if (ruid != (uid_t)-1) {
1304 id->ruid = ruid;
1307 if (euid != (uid_t)-1) {
1308 id->euid = euid;
1311 if (suid != (uid_t)-1) {
1312 id->suid = suid;
1316 UWRAP_UNLOCK(uwrap_id);
1318 return 0;
1321 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1322 uid_t *_new_ruid,
1323 uid_t *_new_euid,
1324 uid_t *_new_suid)
1326 struct uwrap_thread *id = uwrap_tls_id;
1327 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1329 UWRAP_LOG(UWRAP_LOG_TRACE,
1330 "ruid %d -> %d, euid %d -> %d",
1331 id->ruid, ruid, id->euid, euid);
1333 if (ruid != (uid_t)-1) {
1334 new_ruid = ruid;
1335 if (ruid != id->ruid &&
1336 ruid != id->euid &&
1337 id->euid != 0) {
1338 errno = EPERM;
1339 return -1;
1343 if (euid != (uid_t)-1) {
1344 new_euid = euid;
1345 if (euid != id->ruid &&
1346 euid != id->euid &&
1347 euid != id->suid &&
1348 id->euid != 0) {
1349 errno = EPERM;
1350 return -1;
1354 if (ruid != (uid_t) -1 ||
1355 (euid != (uid_t)-1 && id->ruid != euid)) {
1356 new_suid = new_euid;
1359 *_new_ruid = new_ruid;
1360 *_new_euid = new_euid;
1361 *_new_suid = new_suid;
1363 return 0;
1366 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1368 struct uwrap_thread *id = uwrap_tls_id;
1369 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1370 int rc;
1372 UWRAP_LOG(UWRAP_LOG_TRACE,
1373 "ruid %d -> %d, euid %d -> %d",
1374 id->ruid, ruid, id->euid, euid);
1376 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1377 if (rc != 0) {
1378 return rc;
1381 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1384 #ifdef HAVE_SETREUID
1385 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1387 struct uwrap_thread *id = uwrap_tls_id;
1388 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1389 int rc;
1391 UWRAP_LOG(UWRAP_LOG_TRACE,
1392 "ruid %d -> %d, euid %d -> %d",
1393 id->ruid, ruid, id->euid, euid);
1395 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1396 if (rc != 0) {
1397 return rc;
1400 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1402 #endif
1404 static int uwrap_setuid_args(uid_t uid,
1405 uid_t *new_ruid,
1406 uid_t *new_euid,
1407 uid_t *new_suid)
1409 struct uwrap_thread *id = uwrap_tls_id;
1411 UWRAP_LOG(UWRAP_LOG_TRACE,
1412 "uid %d -> %d",
1413 id->ruid, uid);
1415 if (uid == (uid_t)-1) {
1416 errno = EINVAL;
1417 return -1;
1420 if (id->euid == 0) {
1421 *new_suid = *new_ruid = uid;
1422 } else if (uid != id->ruid &&
1423 uid != id->suid) {
1424 errno = EPERM;
1425 return -1;
1428 *new_euid = uid;
1430 return 0;
1433 static int uwrap_setuid_thread(uid_t uid)
1435 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1436 int rc;
1438 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1439 if (rc != 0) {
1440 return rc;
1443 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1446 static int uwrap_setuid(uid_t uid)
1448 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1449 int rc;
1451 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1452 if (rc != 0) {
1453 return rc;
1456 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1460 * UWRAP_GETxUID FUNCTIONS
1463 #ifdef HAVE_GETRESUID
1464 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1466 struct uwrap_thread *id = uwrap_tls_id;
1468 UWRAP_LOCK(uwrap_id);
1470 *ruid = id->ruid;
1471 *euid = id->euid;
1472 *suid = id->suid;
1474 UWRAP_UNLOCK(uwrap_id);
1476 return 0;
1478 #endif
1480 #ifdef HAVE_GETRESGID
1481 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1483 struct uwrap_thread *id = uwrap_tls_id;
1485 UWRAP_LOCK(uwrap_id);
1487 *rgid = id->rgid;
1488 *egid = id->egid;
1489 *sgid = id->sgid;
1491 UWRAP_UNLOCK(uwrap_id);
1493 return 0;
1495 #endif
1498 * UWRAP_SETxGID FUNCTIONS
1501 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1503 struct uwrap_thread *id = uwrap_tls_id;
1505 UWRAP_LOG(UWRAP_LOG_TRACE,
1506 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1507 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1509 if (id->euid != 0) {
1510 if (rgid != (gid_t)-1 &&
1511 rgid != id->rgid &&
1512 rgid != id->egid &&
1513 rgid != id->sgid) {
1514 errno = EPERM;
1515 return -1;
1517 if (egid != (gid_t)-1 &&
1518 egid != id->rgid &&
1519 egid != id->egid &&
1520 egid != id->sgid) {
1521 errno = EPERM;
1522 return -1;
1524 if (sgid != (gid_t)-1 &&
1525 sgid != id->rgid &&
1526 sgid != id->egid &&
1527 sgid != id->sgid) {
1528 errno = EPERM;
1529 return -1;
1533 return 0;
1536 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1538 struct uwrap_thread *id = uwrap_tls_id;
1539 int rc;
1541 UWRAP_LOG(UWRAP_LOG_TRACE,
1542 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1543 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1545 rc = uwrap_setresgid_args(rgid, egid, sgid);
1546 if (rc != 0) {
1547 return rc;
1550 UWRAP_LOCK(uwrap_id);
1552 if (rgid != (gid_t)-1) {
1553 id->rgid = rgid;
1556 if (egid != (gid_t)-1) {
1557 id->egid = egid;
1560 if (sgid != (gid_t)-1) {
1561 id->sgid = sgid;
1564 UWRAP_UNLOCK(uwrap_id);
1566 return 0;
1569 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1571 struct uwrap_thread *id = uwrap_tls_id;
1572 int rc;
1574 UWRAP_LOG(UWRAP_LOG_TRACE,
1575 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1576 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1578 rc = uwrap_setresgid_args(rgid, egid, sgid);
1579 if (rc != 0) {
1580 return rc;
1583 UWRAP_LOCK(uwrap_id);
1585 for (id = uwrap.ids; id; id = id->next) {
1586 if (rgid != (gid_t)-1) {
1587 id->rgid = rgid;
1590 if (egid != (gid_t)-1) {
1591 id->egid = egid;
1594 if (sgid != (gid_t)-1) {
1595 id->sgid = sgid;
1599 UWRAP_UNLOCK(uwrap_id);
1601 return 0;
1604 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1605 gid_t *_new_rgid,
1606 gid_t *_new_egid,
1607 gid_t *_new_sgid)
1609 struct uwrap_thread *id = uwrap_tls_id;
1610 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1612 UWRAP_LOG(UWRAP_LOG_TRACE,
1613 "rgid %d -> %d, egid %d -> %d",
1614 id->rgid, rgid, id->egid, egid);
1616 if (rgid != (gid_t)-1) {
1617 new_rgid = rgid;
1618 if (rgid != id->rgid &&
1619 rgid != id->egid &&
1620 id->euid != 0) {
1621 errno = EPERM;
1622 return -1;
1626 if (egid != (gid_t)-1) {
1627 new_egid = egid;
1628 if (egid != id->rgid &&
1629 egid != id->egid &&
1630 egid != id->sgid &&
1631 id->euid != 0) {
1632 errno = EPERM;
1633 return -1;
1637 if (rgid != (gid_t) -1 ||
1638 (egid != (gid_t)-1 && id->rgid != egid)) {
1639 new_sgid = new_egid;
1642 *_new_rgid = new_rgid;
1643 *_new_egid = new_egid;
1644 *_new_sgid = new_sgid;
1646 return 0;
1649 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1651 struct uwrap_thread *id = uwrap_tls_id;
1652 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1653 int rc;
1655 UWRAP_LOG(UWRAP_LOG_TRACE,
1656 "rgid %d -> %d, egid %d -> %d",
1657 id->rgid, rgid, id->egid, egid);
1659 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1660 if (rc != 0) {
1661 return rc;
1664 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1667 #ifdef HAVE_SETREGID
1668 static int uwrap_setregid(gid_t rgid, gid_t egid)
1670 struct uwrap_thread *id = uwrap_tls_id;
1671 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1672 int rc;
1674 UWRAP_LOG(UWRAP_LOG_TRACE,
1675 "rgid %d -> %d, egid %d -> %d",
1676 id->rgid, rgid, id->egid, egid);
1678 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1679 if (rc != 0) {
1680 return rc;
1683 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1685 #endif
1687 static int uwrap_setgid_args(gid_t gid,
1688 gid_t *new_rgid,
1689 gid_t *new_egid,
1690 gid_t *new_sgid)
1692 struct uwrap_thread *id = uwrap_tls_id;
1694 UWRAP_LOG(UWRAP_LOG_TRACE,
1695 "gid %d -> %d",
1696 id->rgid, gid);
1698 if (gid == (gid_t)-1) {
1699 errno = EINVAL;
1700 return -1;
1703 if (id->euid == 0) {
1704 *new_sgid = *new_rgid = gid;
1705 } else if (gid != id->rgid &&
1706 gid != id->sgid) {
1707 errno = EPERM;
1708 return -1;
1711 *new_egid = gid;
1713 return 0;
1716 static int uwrap_setgid_thread(gid_t gid)
1718 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1719 int rc;
1721 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1722 if (rc != 0) {
1723 return rc;
1726 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1729 static int uwrap_setgid(gid_t gid)
1731 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1732 int rc;
1734 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1735 if (rc != 0) {
1736 return rc;
1739 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1743 * SETUID
1745 int setuid(uid_t uid)
1747 if (!uid_wrapper_enabled()) {
1748 return libc_setuid(uid);
1751 uwrap_init();
1752 return uwrap_setuid(uid);
1755 #ifdef HAVE_SETEUID
1756 int seteuid(uid_t euid)
1758 if (!uid_wrapper_enabled()) {
1759 return libc_seteuid(euid);
1762 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1763 if (euid == (uid_t)-1) {
1764 errno = EINVAL;
1765 return -1;
1768 uwrap_init();
1769 return uwrap_setresuid(-1, euid, -1);
1771 #endif
1773 #ifdef HAVE_SETREUID
1774 int setreuid(uid_t ruid, uid_t euid)
1776 if (!uid_wrapper_enabled()) {
1777 return libc_setreuid(ruid, euid);
1780 uwrap_init();
1781 return uwrap_setreuid(ruid, euid);
1783 #endif
1785 #ifdef HAVE_SETRESUID
1786 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1788 if (!uid_wrapper_enabled()) {
1789 return libc_setresuid(ruid, euid, suid);
1792 uwrap_init();
1793 return uwrap_setresuid(ruid, euid, suid);
1795 #endif
1797 #ifdef HAVE_GETRESUID
1798 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1800 if (!uid_wrapper_enabled()) {
1801 return libc_getresuid(ruid, euid, suid);
1804 uwrap_init();
1805 return uwrap_getresuid(ruid, euid, suid);
1807 #endif
1810 * GETUID
1812 static uid_t uwrap_getuid(void)
1814 struct uwrap_thread *id = uwrap_tls_id;
1815 uid_t uid;
1817 UWRAP_LOCK(uwrap_id);
1818 uid = id->ruid;
1819 UWRAP_UNLOCK(uwrap_id);
1821 return uid;
1824 uid_t getuid(void)
1826 if (!uid_wrapper_enabled()) {
1827 return libc_getuid();
1830 uwrap_init();
1831 return uwrap_getuid();
1835 * GETEUID
1837 static uid_t uwrap_geteuid(void)
1839 const char *env = getenv("UID_WRAPPER_MYUID");
1840 struct uwrap_thread *id = uwrap_tls_id;
1841 uid_t uid;
1843 UWRAP_LOCK(uwrap_id);
1844 uid = id->euid;
1845 UWRAP_UNLOCK(uwrap_id);
1847 /* Disable root and return myuid */
1848 if (env != NULL && env[0] == '1') {
1849 uid = uwrap.myuid;
1852 return uid;
1855 uid_t geteuid(void)
1857 if (!uid_wrapper_enabled()) {
1858 return libc_geteuid();
1861 uwrap_init();
1862 return uwrap_geteuid();
1866 * SETGID
1868 int setgid(gid_t gid)
1870 if (!uid_wrapper_enabled()) {
1871 return libc_setgid(gid);
1874 uwrap_init();
1875 return uwrap_setgid(gid);
1878 #ifdef HAVE_SETEGID
1879 int setegid(gid_t egid)
1881 if (!uid_wrapper_enabled()) {
1882 return libc_setegid(egid);
1885 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1886 if (egid == (gid_t)-1) {
1887 errno = EINVAL;
1888 return -1;
1891 uwrap_init();
1892 return uwrap_setresgid(-1, egid, -1);
1894 #endif
1896 #ifdef HAVE_SETREGID
1897 int setregid(gid_t rgid, gid_t egid)
1899 if (!uid_wrapper_enabled()) {
1900 return libc_setregid(rgid, egid);
1903 uwrap_init();
1904 return uwrap_setregid(rgid, egid);
1906 #endif
1908 #ifdef HAVE_SETRESGID
1909 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1911 if (!uid_wrapper_enabled()) {
1912 return libc_setresgid(rgid, egid, sgid);
1915 uwrap_init();
1916 return uwrap_setresgid(rgid, egid, sgid);
1918 #endif
1920 #ifdef HAVE_GETRESGID
1921 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1923 if (!uid_wrapper_enabled()) {
1924 return libc_getresgid(rgid, egid, sgid);
1927 uwrap_init();
1928 return uwrap_getresgid(rgid, egid, sgid);
1930 #endif
1933 * GETGID
1935 static gid_t uwrap_getgid(void)
1937 struct uwrap_thread *id = uwrap_tls_id;
1938 gid_t gid;
1940 UWRAP_LOCK(uwrap_id);
1941 gid = id->rgid;
1942 UWRAP_UNLOCK(uwrap_id);
1944 return gid;
1947 gid_t getgid(void)
1949 if (!uid_wrapper_enabled()) {
1950 return libc_getgid();
1953 uwrap_init();
1954 return uwrap_getgid();
1958 * GETEGID
1960 static uid_t uwrap_getegid(void)
1962 struct uwrap_thread *id = uwrap_tls_id;
1963 gid_t gid;
1965 UWRAP_LOCK(uwrap_id);
1966 gid = id->egid;
1967 UWRAP_UNLOCK(uwrap_id);
1969 return gid;
1972 uid_t getegid(void)
1974 if (!uid_wrapper_enabled()) {
1975 return libc_getegid();
1978 uwrap_init();
1979 return uwrap_getegid();
1982 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1984 struct uwrap_thread *id = uwrap_tls_id;
1985 int rc = -1;
1987 UWRAP_LOCK(uwrap_id);
1989 if (size == 0) {
1990 SAFE_FREE(id->groups);
1991 id->ngroups = 0;
1992 } else if (size > 0) {
1993 gid_t *tmp;
1995 tmp = realloc(id->groups, sizeof(gid_t) * size);
1996 if (tmp == NULL) {
1997 errno = ENOMEM;
1998 goto out;
2000 id->groups = tmp;
2001 id->ngroups = size;
2002 memcpy(id->groups, list, size * sizeof(gid_t));
2005 rc = 0;
2006 out:
2007 UWRAP_UNLOCK(uwrap_id);
2009 return rc;
2012 static int uwrap_setgroups(size_t size, const gid_t *list)
2014 struct uwrap_thread *id;
2015 int rc = -1;
2017 UWRAP_LOCK(uwrap_id);
2019 if (size == 0) {
2020 for (id = uwrap.ids; id; id = id->next) {
2021 SAFE_FREE(id->groups);
2022 id->ngroups = 0;
2025 } else if (size > 0) {
2026 gid_t *tmp;
2028 for (id = uwrap.ids; id; id = id->next) {
2029 tmp = realloc(id->groups, sizeof(gid_t) * size);
2030 if (tmp == NULL) {
2031 errno = ENOMEM;
2032 goto out;
2034 id->groups = tmp;
2036 id->ngroups = size;
2037 memcpy(id->groups, list, size * sizeof(gid_t));
2041 rc = 0;
2042 out:
2043 UWRAP_UNLOCK(uwrap_id);
2045 return rc;
2048 #ifdef HAVE_SETGROUPS_INT
2049 int setgroups(int size, const gid_t *list)
2050 #else
2051 int setgroups(size_t size, const gid_t *list)
2052 #endif
2054 if (!uid_wrapper_enabled()) {
2055 return libc_setgroups(size, list);
2058 uwrap_init();
2059 return uwrap_setgroups(size, list);
2062 static int uwrap_getgroups(int size, gid_t *list)
2064 struct uwrap_thread *id = uwrap_tls_id;
2065 int ngroups;
2067 UWRAP_LOCK(uwrap_id);
2068 ngroups = id->ngroups;
2070 if (size > ngroups) {
2071 size = ngroups;
2073 if (size == 0) {
2074 goto out;
2076 if (size < ngroups) {
2077 errno = EINVAL;
2078 ngroups = -1;
2080 memcpy(list, id->groups, size * sizeof(gid_t));
2082 out:
2083 UWRAP_UNLOCK(uwrap_id);
2085 return ngroups;
2088 int getgroups(int size, gid_t *list)
2090 if (!uid_wrapper_enabled()) {
2091 return libc_getgroups(size, list);
2094 uwrap_init();
2095 return uwrap_getgroups(size, list);
2098 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2099 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2100 static long int uwrap_syscall (long int sysno, va_list vp)
2102 long int rc;
2104 switch (sysno) {
2105 /* gid */
2106 #ifdef __alpha__
2107 case SYS_getxgid:
2108 #else
2109 case SYS_getgid:
2110 #endif
2111 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2112 case SYS_getgid32:
2113 #endif
2115 rc = uwrap_getgid();
2117 break;
2118 #ifdef SYS_getegid
2119 case SYS_getegid:
2120 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2121 case SYS_getegid32:
2122 #endif
2124 rc = uwrap_getegid();
2126 break;
2127 #endif /* SYS_getegid */
2128 case SYS_setgid:
2129 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2130 case SYS_setgid32:
2131 #endif
2133 gid_t gid = (gid_t) va_arg(vp, gid_t);
2135 rc = uwrap_setgid_thread(gid);
2137 break;
2138 case SYS_setregid:
2139 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2140 case SYS_setregid32:
2141 #endif
2143 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2144 gid_t egid = (gid_t) va_arg(vp, gid_t);
2146 rc = uwrap_setregid_thread(rgid, egid);
2148 break;
2149 #ifdef SYS_setresgid
2150 case SYS_setresgid:
2151 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2152 case SYS_setresgid32:
2153 #endif
2155 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2156 gid_t egid = (gid_t) va_arg(vp, gid_t);
2157 gid_t sgid = (gid_t) va_arg(vp, gid_t);
2159 rc = uwrap_setresgid_thread(rgid, egid, sgid);
2161 break;
2162 #endif /* SYS_setresgid */
2163 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2164 case SYS_getresgid:
2165 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2166 case SYS_getresgid32:
2167 #endif
2169 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2170 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2171 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2173 rc = uwrap_getresgid(rgid, egid, sgid);
2175 break;
2176 #endif /* SYS_getresgid && HAVE_GETRESGID */
2178 /* uid */
2179 #ifdef __alpha__
2180 case SYS_getxuid:
2181 #else
2182 case SYS_getuid:
2183 #endif
2184 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2185 case SYS_getuid32:
2186 #endif
2188 rc = uwrap_getuid();
2190 break;
2191 #ifdef SYS_geteuid
2192 case SYS_geteuid:
2193 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2194 case SYS_geteuid32:
2195 #endif
2197 rc = uwrap_geteuid();
2199 break;
2200 #endif /* SYS_geteuid */
2201 case SYS_setuid:
2202 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2203 case SYS_setuid32:
2204 #endif
2206 uid_t uid = (uid_t) va_arg(vp, uid_t);
2208 rc = uwrap_setuid_thread(uid);
2210 break;
2211 case SYS_setreuid:
2212 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2213 case SYS_setreuid32:
2214 #endif
2216 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2217 uid_t euid = (uid_t) va_arg(vp, uid_t);
2219 rc = uwrap_setreuid_thread(ruid, euid);
2221 break;
2222 #ifdef SYS_setresuid
2223 case SYS_setresuid:
2224 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2225 case SYS_setresuid32:
2226 #endif
2228 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2229 uid_t euid = (uid_t) va_arg(vp, uid_t);
2230 uid_t suid = (uid_t) va_arg(vp, uid_t);
2232 rc = uwrap_setresuid_thread(ruid, euid, suid);
2234 break;
2235 #endif /* SYS_setresuid */
2236 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2237 case SYS_getresuid:
2238 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2239 case SYS_getresuid32:
2240 #endif
2242 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2243 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2244 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2246 rc = uwrap_getresuid(ruid, euid, suid);
2248 break;
2249 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2250 /* groups */
2251 case SYS_setgroups:
2252 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2253 case SYS_setgroups32:
2254 #endif
2256 size_t size = (size_t) va_arg(vp, size_t);
2257 gid_t *list = (gid_t *) va_arg(vp, int *);
2259 rc = uwrap_setgroups_thread(size, list);
2261 break;
2262 default:
2263 UWRAP_LOG(UWRAP_LOG_DEBUG,
2264 "UID_WRAPPER calling non-wrapped syscall %lu",
2265 sysno);
2267 rc = libc_vsyscall(sysno, vp);
2268 break;
2271 return rc;
2274 #ifdef HAVE_SYSCALL
2275 #ifdef HAVE_SYSCALL_INT
2276 int syscall (int sysno, ...)
2277 #else
2278 long int syscall (long int sysno, ...)
2279 #endif
2281 #ifdef HAVE_SYSCALL_INT
2282 int rc;
2283 #else
2284 long int rc;
2285 #endif
2286 va_list va;
2288 va_start(va, sysno);
2290 if (!uid_wrapper_enabled()) {
2291 rc = libc_vsyscall(sysno, va);
2292 va_end(va);
2293 return rc;
2296 uwrap_init();
2297 rc = uwrap_syscall(sysno, va);
2298 va_end(va);
2300 return rc;
2302 #endif /* HAVE_SYSCALL */
2303 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2305 /****************************
2306 * CONSTRUCTOR
2307 ***************************/
2309 void uwrap_constructor(void)
2311 char *glibc_malloc_lock_bug;
2314 * This is a workaround for a bug in glibc < 2.24:
2316 * The child handler for the malloc() function is called and locks the
2317 * mutex. Then our child handler is called and we try to call setenv().
2318 * setenv() wants to malloc and tries to aquire the lock for malloc and
2319 * we end up in a deadlock.
2321 * So as a workaround we need to call malloc once before we setup the
2322 * handlers.
2324 * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2326 glibc_malloc_lock_bug = malloc(1);
2327 if (glibc_malloc_lock_bug == NULL) {
2328 exit(-1);
2330 glibc_malloc_lock_bug[0] = '\0';
2333 * If we hold a lock and the application forks, then the child
2334 * is not able to unlock the mutex and we are in a deadlock.
2335 * This should prevent such deadlocks.
2337 pthread_atfork(&uwrap_thread_prepare,
2338 &uwrap_thread_parent,
2339 &uwrap_thread_child);
2341 free(glibc_malloc_lock_bug);
2343 /* Here is safe place to call uwrap_init() and initialize data
2344 * for main process.
2346 uwrap_init();
2349 /****************************
2350 * DESTRUCTOR
2351 ***************************/
2354 * This function is called when the library is unloaded and makes sure that
2355 * resources are freed.
2357 void uwrap_destructor(void)
2359 struct uwrap_thread *u = uwrap.ids;
2361 UWRAP_LOCK_ALL;
2363 while (u != NULL) {
2364 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2366 SAFE_FREE(u->groups);
2367 SAFE_FREE(u);
2369 u = uwrap.ids;
2373 if (uwrap.libc.handle != NULL) {
2374 dlclose(uwrap.libc.handle);
2377 if (uwrap.libpthread.handle != NULL) {
2378 dlclose(uwrap.libpthread.handle);
2381 UWRAP_UNLOCK_ALL;