VERSION: Bump version up to 4.12.2...
[Samba.git] / third_party / uid_wrapper / uid_wrapper.c
blob6e4a6da2f0d7a2335dd93eafc78e8397f758ef14
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>
37 #include <limits.h>
39 #include <pthread.h>
41 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
42 # define UWRAP_THREAD __thread
43 #else
44 # define UWRAP_THREAD
45 #endif
47 # define UWRAP_LOCK(m) do { \
48 pthread_mutex_lock(&( m ## _mutex)); \
49 } while(0)
51 # define UWRAP_UNLOCK(m) do { \
52 pthread_mutex_unlock(&( m ## _mutex)); \
53 } while(0)
55 /* Add new global locks here please */
56 # define UWRAP_LOCK_ALL \
57 UWRAP_LOCK(uwrap_id); \
58 UWRAP_LOCK(libc_symbol_binding); \
59 UWRAP_LOCK(libpthread_symbol_binding)
61 # define UWRAP_UNLOCK_ALL \
62 UWRAP_UNLOCK(libpthread_symbol_binding); \
63 UWRAP_UNLOCK(libc_symbol_binding); \
64 UWRAP_UNLOCK(uwrap_id)
66 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
67 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
68 #else
69 #define CONSTRUCTOR_ATTRIBUTE
70 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
72 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
73 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
74 #else
75 #define DESTRUCTOR_ATTRIBUTE
76 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
78 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
79 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
80 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
81 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
82 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
84 /* GCC have printf type attribute check. */
85 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
86 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
87 #else
88 #define PRINTF_ATTRIBUTE(a,b)
89 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
91 #ifndef FALL_THROUGH
92 # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
93 # define FALL_THROUGH __attribute__ ((fallthrough))
94 # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
95 # define FALL_THROUGH
96 # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
97 #endif /* FALL_THROUGH */
99 #define UWRAP_DLIST_ADD(list,item) do { \
100 if (!(list)) { \
101 (item)->prev = NULL; \
102 (item)->next = NULL; \
103 (list) = (item); \
104 } else { \
105 (item)->prev = NULL; \
106 (item)->next = (list); \
107 (list)->prev = (item); \
108 (list) = (item); \
110 } while (0)
112 #define UWRAP_DLIST_REMOVE(list,item) do { \
113 if ((list) == (item)) { \
114 (list) = (item)->next; \
115 if (list) { \
116 (list)->prev = NULL; \
118 } else { \
119 if ((item)->prev) { \
120 (item)->prev->next = (item)->next; \
122 if ((item)->next) { \
123 (item)->next->prev = (item)->prev; \
126 (item)->prev = NULL; \
127 (item)->next = NULL; \
128 } while (0)
130 #ifndef SAFE_FREE
131 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
132 #endif
134 /*****************
135 * LOGGING
136 *****************/
138 enum uwrap_dbglvl_e {
139 UWRAP_LOG_ERROR = 0,
140 UWRAP_LOG_WARN,
141 UWRAP_LOG_DEBUG,
142 UWRAP_LOG_TRACE
145 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
146 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
148 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
150 char buffer[1024];
151 va_list va;
152 const char *d;
153 unsigned int lvl = 0;
154 const char *prefix = "UWRAP";
156 d = getenv("UID_WRAPPER_DEBUGLEVEL");
157 if (d != NULL) {
158 lvl = atoi(d);
161 if (lvl < dbglvl) {
162 return;
165 va_start(va, format);
166 vsnprintf(buffer, sizeof(buffer), format, va);
167 va_end(va);
169 switch (dbglvl) {
170 case UWRAP_LOG_ERROR:
171 prefix = "UWRAP_ERROR";
172 break;
173 case UWRAP_LOG_WARN:
174 prefix = "UWRAP_WARN";
175 break;
176 case UWRAP_LOG_DEBUG:
177 prefix = "UWRAP_DEBUG";
178 break;
179 case UWRAP_LOG_TRACE:
180 prefix = "UWRAP_TRACE";
181 break;
184 fprintf(stderr,
185 "%s(%d) - %s: %s\n",
186 prefix,
187 (int)getpid(),
188 function,
189 buffer);
192 /*****************
193 * LIBC
194 *****************/
196 #define LIBC_NAME "libc.so"
198 typedef int (*__libc_setuid)(uid_t uid);
200 typedef uid_t (*__libc_getuid)(void);
202 #ifdef HAVE_SETEUID
203 typedef int (*__libc_seteuid)(uid_t euid);
204 #endif
206 #ifdef HAVE_SETREUID
207 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
208 #endif
210 #ifdef HAVE_SETRESUID
211 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
212 #endif
214 #ifdef HAVE_GETRESUID
215 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
216 #endif
218 typedef uid_t (*__libc_geteuid)(void);
220 typedef int (*__libc_setgid)(gid_t gid);
222 typedef gid_t (*__libc_getgid)(void);
224 #ifdef HAVE_SETEGID
225 typedef int (*__libc_setegid)(uid_t egid);
226 #endif
228 #ifdef HAVE_SETREGID
229 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
230 #endif
232 #ifdef HAVE_SETRESGID
233 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
234 #endif
236 #ifdef HAVE_GETRESGID
237 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
238 #endif
240 typedef gid_t (*__libc_getegid)(void);
242 typedef int (*__libc_getgroups)(int size, gid_t list[]);
244 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
246 #ifdef HAVE_SYSCALL
247 typedef long int (*__libc_syscall)(long int sysno, ...);
248 #endif
250 #define UWRAP_SYMBOL_ENTRY(i) \
251 union { \
252 __libc_##i f; \
253 void *obj; \
254 } _libc_##i
256 struct uwrap_libc_symbols {
257 UWRAP_SYMBOL_ENTRY(setuid);
258 UWRAP_SYMBOL_ENTRY(getuid);
259 #ifdef HAVE_SETEUID
260 UWRAP_SYMBOL_ENTRY(seteuid);
261 #endif
262 #ifdef HAVE_SETREUID
263 UWRAP_SYMBOL_ENTRY(setreuid);
264 #endif
265 #ifdef HAVE_SETRESUID
266 UWRAP_SYMBOL_ENTRY(setresuid);
267 #endif
268 #ifdef HAVE_GETRESUID
269 UWRAP_SYMBOL_ENTRY(getresuid);
270 #endif
271 UWRAP_SYMBOL_ENTRY(geteuid);
272 UWRAP_SYMBOL_ENTRY(setgid);
273 UWRAP_SYMBOL_ENTRY(getgid);
274 #ifdef HAVE_SETEGID
275 UWRAP_SYMBOL_ENTRY(setegid);
276 #endif
277 #ifdef HAVE_SETREGID
278 UWRAP_SYMBOL_ENTRY(setregid);
279 #endif
280 #ifdef HAVE_SETRESGID
281 UWRAP_SYMBOL_ENTRY(setresgid);
282 #endif
283 #ifdef HAVE_GETRESGID
284 UWRAP_SYMBOL_ENTRY(getresgid);
285 #endif
286 UWRAP_SYMBOL_ENTRY(getegid);
287 UWRAP_SYMBOL_ENTRY(getgroups);
288 UWRAP_SYMBOL_ENTRY(setgroups);
289 #ifdef HAVE_SYSCALL
290 UWRAP_SYMBOL_ENTRY(syscall);
291 #endif
293 #undef UWRAP_SYMBOL_ENTRY
295 /*****************
296 * LIBPTHREAD
297 *****************/
298 /* Yeah... I'm pig. I overloading macro here... So what? */
299 #define UWRAP_SYMBOL_ENTRY(i) \
300 union { \
301 __libpthread_##i f; \
302 void *obj; \
303 } _libpthread_##i
305 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
306 const pthread_attr_t *attr,
307 void *(*start_routine) (void *),
308 void *arg);
309 typedef void (*__libpthread_pthread_exit)(void *retval);
311 struct uwrap_libpthread_symbols {
312 UWRAP_SYMBOL_ENTRY(pthread_create);
313 UWRAP_SYMBOL_ENTRY(pthread_exit);
315 #undef UWRAP_SYMBOL_ENTRY
318 * We keep the virtualised euid/egid/groups information here
320 struct uwrap_thread {
321 bool enabled;
323 uid_t ruid;
324 uid_t euid;
325 uid_t suid;
327 gid_t rgid;
328 gid_t egid;
329 gid_t sgid;
331 int ngroups;
332 gid_t *groups;
334 struct uwrap_thread *next;
335 struct uwrap_thread *prev;
338 struct uwrap {
339 struct {
340 void *handle;
341 struct uwrap_libc_symbols symbols;
342 } libc;
344 struct {
345 void *handle;
346 struct uwrap_libpthread_symbols symbols;
347 } libpthread;
349 bool initialised;
351 /* Real uid and gid of user who run uid wrapper */
352 uid_t myuid;
353 gid_t mygid;
355 struct uwrap_thread *ids;
358 static struct uwrap uwrap;
360 /* Shortcut to the list item */
361 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
363 /* The mutex or accessing the id */
364 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
366 /* The mutex for accessing the global libc.symbols */
367 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
369 /* The mutex for accessing the global libpthread.symbols */
370 static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
372 /*********************************************************
373 * UWRAP PROTOTYPES
374 *********************************************************/
376 bool uid_wrapper_enabled(void);
377 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
378 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
380 /*********************************************************
381 * UWRAP LIBC LOADER FUNCTIONS
382 *********************************************************/
384 enum uwrap_lib {
385 UWRAP_LIBC,
386 UWRAP_LIBNSL,
387 UWRAP_LIBSOCKET,
388 UWRAP_LIBPTHREAD,
391 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
393 int flags = RTLD_LAZY;
394 void *handle = NULL;
395 int i;
397 #ifdef RTLD_DEEPBIND
398 const char *env_preload = getenv("LD_PRELOAD");
399 const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
400 bool enable_deepbind = true;
402 /* Don't do a deepbind if we run with libasan */
403 if (env_preload != NULL && strlen(env_preload) < 1024) {
404 const char *p = strstr(env_preload, "libasan.so");
405 if (p != NULL) {
406 enable_deepbind = false;
410 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
411 enable_deepbind = false;
414 if (enable_deepbind) {
415 flags |= RTLD_DEEPBIND;
417 #endif
419 switch (lib) {
420 case UWRAP_LIBNSL:
421 case UWRAP_LIBSOCKET:
422 case UWRAP_LIBC:
423 handle = uwrap.libc.handle;
424 if (handle == NULL) {
425 for (i = 10; i >= 0; i--) {
426 char soname[256] = {0};
428 snprintf(soname, sizeof(soname), "libc.so.%d", i);
429 handle = dlopen(soname, flags);
430 if (handle != NULL) {
431 break;
434 /* glibc on Alpha and IA64 is libc.so.6.1 */
435 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
436 handle = dlopen(soname, flags);
437 if (handle != NULL) {
438 break;
442 uwrap.libc.handle = handle;
444 break;
445 case UWRAP_LIBPTHREAD:
446 handle = uwrap.libpthread.handle;
447 if (handle == NULL) {
448 handle = dlopen("libpthread.so.0", flags);
449 if (handle != NULL) {
450 break;
453 break;
456 if (handle == NULL) {
457 #ifdef RTLD_NEXT
458 handle = uwrap.libc.handle = RTLD_NEXT;
459 #else
460 fprintf(stderr,
461 "Failed to dlopen library: %s\n",
462 dlerror());
463 exit(-1);
464 #endif
467 return handle;
470 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
472 void *handle;
473 void *func;
475 handle = uwrap_load_lib_handle(lib);
477 func = dlsym(handle, fn_name);
478 if (func == NULL) {
479 fprintf(stderr,
480 "Failed to find %s: %s\n",
481 fn_name, dlerror());
482 exit(-1);
485 return func;
488 #define uwrap_bind_symbol_libc(sym_name) \
489 UWRAP_LOCK(libc_symbol_binding); \
490 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
491 uwrap.libc.symbols._libc_##sym_name.obj = \
492 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
494 UWRAP_UNLOCK(libc_symbol_binding)
496 #define uwrap_bind_symbol_libpthread(sym_name) \
497 UWRAP_LOCK(libpthread_symbol_binding); \
498 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
499 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
500 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
502 UWRAP_UNLOCK(libpthread_symbol_binding)
505 * IMPORTANT
507 * Functions expeciall from libc need to be loaded individually, you can't load
508 * all at once or gdb will segfault at startup. The same applies to valgrind and
509 * has probably something todo with with the linker.
510 * So we need load each function at the point it is called the first time.
512 static int libc_setuid(uid_t uid)
514 uwrap_bind_symbol_libc(setuid);
516 return uwrap.libc.symbols._libc_setuid.f(uid);
519 static uid_t libc_getuid(void)
521 uwrap_bind_symbol_libc(getuid);
523 return uwrap.libc.symbols._libc_getuid.f();
526 #ifdef HAVE_SETEUID
527 static int libc_seteuid(uid_t euid)
529 uwrap_bind_symbol_libc(seteuid);
531 return uwrap.libc.symbols._libc_seteuid.f(euid);
533 #endif
535 #ifdef HAVE_SETREUID
536 static int libc_setreuid(uid_t ruid, uid_t euid)
538 uwrap_bind_symbol_libc(setreuid);
540 return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
542 #endif
544 #ifdef HAVE_SETRESUID
545 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
547 uwrap_bind_symbol_libc(setresuid);
549 return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
551 #endif
553 #ifdef HAVE_GETRESUID
554 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
556 uwrap_bind_symbol_libc(getresuid);
558 return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
560 #endif
562 static uid_t libc_geteuid(void)
564 uwrap_bind_symbol_libc(geteuid);
566 return uwrap.libc.symbols._libc_geteuid.f();
569 static int libc_setgid(gid_t gid)
571 uwrap_bind_symbol_libc(setgid);
573 return uwrap.libc.symbols._libc_setgid.f(gid);
576 static gid_t libc_getgid(void)
578 uwrap_bind_symbol_libc(getgid);
580 return uwrap.libc.symbols._libc_getgid.f();
583 #ifdef HAVE_SETEGID
584 static int libc_setegid(gid_t egid)
586 uwrap_bind_symbol_libc(setegid);
588 return uwrap.libc.symbols._libc_setegid.f(egid);
590 #endif
592 #ifdef HAVE_SETREGID
593 static int libc_setregid(gid_t rgid, gid_t egid)
595 uwrap_bind_symbol_libc(setregid);
597 return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
599 #endif
601 #ifdef HAVE_SETRESGID
602 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
604 uwrap_bind_symbol_libc(setresgid);
606 return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
608 #endif
610 #ifdef HAVE_GETRESGID
611 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
613 uwrap_bind_symbol_libc(setresgid);
615 return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
617 #endif
619 static gid_t libc_getegid(void)
621 uwrap_bind_symbol_libc(getegid);
623 return uwrap.libc.symbols._libc_getegid.f();
626 static int libc_getgroups(int size, gid_t list[])
628 uwrap_bind_symbol_libc(getgroups);
630 return uwrap.libc.symbols._libc_getgroups.f(size, list);
633 static int libc_setgroups(size_t size, const gid_t *list)
635 uwrap_bind_symbol_libc(setgroups);
637 return uwrap.libc.symbols._libc_setgroups.f(size, list);
640 #ifdef HAVE_SYSCALL
641 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
642 static long int libc_vsyscall(long int sysno, va_list va)
644 long int args[8];
645 long int rc;
646 int i;
648 uwrap_bind_symbol_libc(syscall);
650 for (i = 0; i < 8; i++) {
651 args[i] = va_arg(va, long int);
654 rc = uwrap.libc.symbols._libc_syscall.f(sysno,
655 args[0],
656 args[1],
657 args[2],
658 args[3],
659 args[4],
660 args[5],
661 args[6],
662 args[7]);
664 return rc;
666 #endif
669 * This part is "optimistic".
670 * Thread can ends without pthread_exit call.
672 static void libpthread_pthread_exit(void *retval)
674 uwrap_bind_symbol_libpthread(pthread_exit);
676 uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
679 static void uwrap_pthread_exit(void *retval)
681 struct uwrap_thread *id = uwrap_tls_id;
683 UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
685 UWRAP_LOCK(uwrap_id);
686 if (id == NULL) {
687 UWRAP_UNLOCK(uwrap_id);
688 libpthread_pthread_exit(retval);
689 return;
692 UWRAP_DLIST_REMOVE(uwrap.ids, id);
693 SAFE_FREE(id->groups);
694 SAFE_FREE(id);
695 uwrap_tls_id = NULL;
697 UWRAP_UNLOCK(uwrap_id);
699 libpthread_pthread_exit(retval);
702 void pthread_exit(void *retval)
704 if (!uid_wrapper_enabled()) {
705 libpthread_pthread_exit(retval);
708 uwrap_pthread_exit(retval);
710 /* Calm down gcc warning. */
711 exit(666);
714 static int libpthread_pthread_create(pthread_t *thread,
715 const pthread_attr_t *attr,
716 void *(*start_routine) (void *),
717 void *arg)
719 uwrap_bind_symbol_libpthread(pthread_create);
720 return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
721 attr,
722 start_routine,
723 arg);
726 struct uwrap_pthread_create_args {
727 struct uwrap_thread *id;
728 void *(*start_routine) (void *);
729 void *arg;
732 static void *uwrap_pthread_create_start(void *_a)
734 struct uwrap_pthread_create_args *a =
735 (struct uwrap_pthread_create_args *)_a;
736 void *(*start_routine) (void *) = a->start_routine;
737 void *arg = a->arg;
738 struct uwrap_thread *id = a->id;
740 SAFE_FREE(a);
742 uwrap_tls_id = id;
744 return start_routine(arg);
747 static int uwrap_pthread_create(pthread_t *thread,
748 const pthread_attr_t *attr,
749 void *(*start_routine) (void *),
750 void *arg)
752 struct uwrap_pthread_create_args *args;
753 struct uwrap_thread *src_id = uwrap_tls_id;
754 int ret;
756 args = malloc(sizeof(struct uwrap_pthread_create_args));
757 if (args == NULL) {
758 UWRAP_LOG(UWRAP_LOG_ERROR,
759 "uwrap_pthread_create: Unable to allocate memory");
760 errno = ENOMEM;
761 return -1;
763 args->start_routine = start_routine;
764 args->arg = arg;
766 args->id = calloc(1, sizeof(struct uwrap_thread));
767 if (args->id == NULL) {
768 SAFE_FREE(args);
769 UWRAP_LOG(UWRAP_LOG_ERROR,
770 "uwrap_pthread_create: Unable to allocate memory");
771 errno = ENOMEM;
772 return -1;
775 UWRAP_LOCK(uwrap_id);
777 args->id->groups = calloc(src_id->ngroups, sizeof(gid_t));
778 if (args->id->groups == NULL) {
779 UWRAP_UNLOCK(uwrap_id);
780 SAFE_FREE(args->id);
781 SAFE_FREE(args);
782 UWRAP_LOG(UWRAP_LOG_ERROR,
783 "uwrap_pthread_create: Unable to allocate memory again");
784 errno = ENOMEM;
785 return -1;
788 args->id->ruid = src_id->ruid;
789 args->id->euid = src_id->euid;
790 args->id->suid = src_id->suid;
792 args->id->rgid = src_id->rgid;
793 args->id->egid = src_id->egid;
794 args->id->sgid = src_id->sgid;
796 args->id->enabled = src_id->enabled;
798 args->id->ngroups = src_id->ngroups;
799 if (src_id->groups != NULL) {
800 memcpy(args->id->groups, src_id->groups,
801 sizeof(gid_t) * src_id->ngroups);
802 } else {
803 SAFE_FREE(args->id->groups);
806 UWRAP_DLIST_ADD(uwrap.ids, args->id);
807 UWRAP_UNLOCK(uwrap_id);
809 ret = libpthread_pthread_create(thread, attr,
810 uwrap_pthread_create_start,
811 args);
812 if (ret != 0) {
813 return ret;
816 return ret;
819 int pthread_create(pthread_t *thread,
820 const pthread_attr_t *attr,
821 void *(*start_routine) (void *),
822 void *arg)
824 if (!uid_wrapper_enabled()) {
825 return libpthread_pthread_create(thread,
826 attr,
827 start_routine,
828 arg);
831 return uwrap_pthread_create(thread,
832 attr,
833 start_routine,
834 arg);
837 /*********************************************************
838 * UWRAP ID HANDLING
839 *********************************************************/
841 #define GROUP_STRING_SIZE 16384
842 #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
845 * This function exports all the IDs of the current user so if
846 * we fork and then exec we can setup uid_wrapper in the new process
847 * with those IDs.
849 static void uwrap_export_ids(struct uwrap_thread *id)
851 char groups_str[GROUP_STRING_SIZE] = {0};
852 size_t groups_str_size = sizeof(groups_str);
853 char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
854 int i;
856 /* UIDS */
857 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
858 setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
860 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
861 setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
863 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
864 setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
866 /* GIDS */
867 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
868 setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
870 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
871 setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
873 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
874 setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
876 if (id->ngroups > GROUP_MAX_COUNT) {
877 UWRAP_LOG(UWRAP_LOG_ERROR,
878 "ERROR: Number of groups (%u) exceeds maximum value "
879 "uid_wrapper can handle (%u).",
880 id->ngroups,
881 GROUP_MAX_COUNT);
882 exit(-1);
885 /* GROUPS */
886 for (i = 0; i < id->ngroups; i++) {
887 size_t groups_str_len = strlen(groups_str);
888 size_t groups_str_avail = groups_str_size - groups_str_len - 1;
889 int len;
891 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
892 if (len <= 1) {
893 UWRAP_LOG(UWRAP_LOG_ERROR,
894 "snprintf failed for groups[%d]=%u",
896 id->groups[i]);
897 break;
899 if (((size_t)len) >= groups_str_avail) {
900 UWRAP_LOG(UWRAP_LOG_ERROR,
901 "groups env string is to small for %d groups",
903 break;
906 len = snprintf(groups_str + groups_str_len,
907 groups_str_size - groups_str_len,
908 "%s",
909 i == 0 ? unsigned_str + 1 : unsigned_str);
910 if (len < 1) {
911 UWRAP_LOG(UWRAP_LOG_ERROR,
912 "snprintf failed to create groups string at groups[%d]=%u",
914 id->groups[i]);
915 break;
919 if (id->ngroups == i) {
920 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
922 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
923 setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
927 static void uwrap_thread_prepare(void)
929 struct uwrap_thread *id = uwrap_tls_id;
931 UWRAP_LOCK_ALL;
933 /* uid_wrapper is loaded but not enabled */
934 if (id == NULL) {
935 return;
939 * What happens if another atfork prepare functions calls a uwrap
940 * function? So disable it in case another atfork prepare function
941 * calls a (s)uid function. We disable uid_wrapper only for thread
942 * (process) which called fork.
944 id->enabled = false;
947 static void uwrap_thread_parent(void)
949 struct uwrap_thread *id = uwrap_tls_id;
951 /* uid_wrapper is loaded but not enabled */
952 if (id == NULL) {
953 UWRAP_UNLOCK_ALL;
954 return;
957 id->enabled = true;
959 UWRAP_UNLOCK_ALL;
962 static void uwrap_thread_child(void)
964 struct uwrap_thread *id = uwrap_tls_id;
965 struct uwrap_thread *u = uwrap.ids;
967 /* uid_wrapper is loaded but not enabled */
968 if (id == NULL) {
969 UWRAP_UNLOCK_ALL;
970 return;
974 * "Garbage collector" - Inspired by DESTRUCTOR.
975 * All threads (except one which called fork()) are dead now.. Dave
976 * That's what posix said...
978 while (u != NULL) {
979 if (u == id) {
980 /* Skip this item. */
981 u = uwrap.ids->next;
982 continue;
985 UWRAP_DLIST_REMOVE(uwrap.ids, u);
987 SAFE_FREE(u->groups);
988 SAFE_FREE(u);
990 u = uwrap.ids;
993 uwrap_export_ids(id);
995 id->enabled = true;
997 UWRAP_UNLOCK_ALL;
1000 static unsigned long uwrap_get_xid_from_env(const char *envname)
1002 unsigned long xid;
1003 const char *env = NULL;
1004 char *endp = NULL;
1006 env = getenv(envname);
1007 if (env == NULL) {
1008 return ULONG_MAX;
1011 if (env[0] == '\0') {
1012 unsetenv(envname);
1013 return ULONG_MAX;
1016 xid = strtoul(env, &endp, 10);
1017 unsetenv(envname);
1018 if (env == endp) {
1019 return ULONG_MAX;
1022 return xid;
1026 * This initializes uid_wrapper with the IDs exported to the environment. Those
1027 * are normally set after we forked and executed.
1029 static void uwrap_init_env(struct uwrap_thread *id)
1031 const char *env;
1032 int ngroups = 0;
1033 unsigned long xid;
1035 /* UIDs */
1036 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RUID");
1037 if (xid != ULONG_MAX) {
1038 id->ruid = (uid_t)xid;
1041 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EUID");
1042 if (xid != ULONG_MAX) {
1043 id->euid = (uid_t)xid;
1046 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SUID");
1047 if (xid != ULONG_MAX) {
1048 id->suid = (uid_t)xid;
1051 /* GIDs */
1052 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RGID");
1053 if (xid != ULONG_MAX) {
1054 id->rgid = (gid_t)xid;
1057 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EGID");
1058 if (xid != ULONG_MAX) {
1059 id->egid = (gid_t)xid;
1062 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SGID");
1063 if (xid != ULONG_MAX) {
1064 id->sgid = (gid_t)xid;
1067 env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1068 if (env != NULL && env[0] != '\0') {
1069 char *endp = NULL;
1070 long n;
1072 n = strtol(env, &endp, 10);
1073 if (env == endp) {
1074 ngroups = 0;
1075 } else if (n > 0 && n < GROUP_MAX_COUNT) {
1076 ngroups = (int)n;
1078 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1081 if (ngroups > 0) {
1082 int i = 0;
1084 id->ngroups = 0;
1086 free(id->groups);
1087 id->groups = calloc(ngroups, sizeof(gid_t));
1088 if (id->groups == NULL) {
1089 UWRAP_LOG(UWRAP_LOG_ERROR,
1090 "Unable to allocate memory");
1091 exit(-1);
1094 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1095 if (env != NULL && env[0] != '\0') {
1096 char *groups_str = NULL;
1097 char *saveptr = NULL;
1098 const char *p = NULL;
1100 groups_str = strdup(env);
1101 if (groups_str == NULL) {
1102 exit(-1);
1105 p = strtok_r(groups_str, ",", &saveptr);
1106 while (p != NULL) {
1107 id->groups[i] = strtol(p, (char **)NULL, 10);
1108 i++;
1110 p = strtok_r(NULL, ",", &saveptr);
1112 SAFE_FREE(groups_str);
1115 if (i != ngroups) {
1116 UWRAP_LOG(UWRAP_LOG_ERROR,
1117 "ERROR: The number of groups (%u) passed, "
1118 "does not match the number of groups (%u) "
1119 "we parsed.",
1120 ngroups,
1122 exit(-1);
1125 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1126 id->ngroups = ngroups;
1130 static void uwrap_init(void)
1132 const char *env;
1134 UWRAP_LOCK(uwrap_id);
1136 if (uwrap.initialised) {
1137 struct uwrap_thread *id = uwrap_tls_id;
1139 if (uwrap.ids == NULL) {
1140 UWRAP_UNLOCK(uwrap_id);
1141 return;
1144 if (id == NULL) {
1145 UWRAP_LOG(UWRAP_LOG_ERROR,
1146 "Invalid id for thread");
1147 exit(-1);
1150 UWRAP_UNLOCK(uwrap_id);
1151 return;
1154 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1156 uwrap.initialised = true;
1158 env = getenv("UID_WRAPPER");
1159 if (env != NULL && env[0] == '1') {
1160 const char *root = getenv("UID_WRAPPER_ROOT");
1161 struct uwrap_thread *id;
1163 id = calloc(1, sizeof(struct uwrap_thread));
1164 if (id == NULL) {
1165 UWRAP_LOG(UWRAP_LOG_ERROR,
1166 "Unable to allocate memory for main id");
1167 exit(-1);
1170 UWRAP_DLIST_ADD(uwrap.ids, id);
1171 uwrap_tls_id = id;
1173 uwrap.myuid = libc_geteuid();
1174 uwrap.mygid = libc_getegid();
1176 /* put us in one group */
1177 if (root != NULL && root[0] == '1') {
1178 id->ruid = id->euid = id->suid = 0;
1179 id->rgid = id->egid = id->sgid = 0;
1181 id->groups = malloc(sizeof(gid_t) * 1);
1182 if (id->groups == NULL) {
1183 UWRAP_LOG(UWRAP_LOG_ERROR,
1184 "Unable to allocate memory");
1185 exit(-1);
1188 id->ngroups = 1;
1189 id->groups[0] = 0;
1191 } else {
1192 id->ruid = id->euid = id->suid = uwrap.myuid;
1193 id->rgid = id->egid = id->sgid = uwrap.mygid;
1195 id->ngroups = libc_getgroups(0, NULL);
1196 if (id->ngroups == -1) {
1197 UWRAP_LOG(UWRAP_LOG_ERROR,
1198 "Unable to call libc_getgroups in uwrap_init.");
1199 exit(-1);
1201 id->groups = malloc(sizeof(gid_t) * id->ngroups);
1202 if (id->groups == NULL) {
1203 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1204 exit(-1);
1206 if (libc_getgroups(id->ngroups, id->groups) == -1) {
1207 UWRAP_LOG(UWRAP_LOG_ERROR,
1208 "Unable to call libc_getgroups again in uwrap_init.");
1209 id->groups = 0;
1211 * Deallocation of uwrap.groups is handled by
1212 * library destructor.
1214 exit(-1);
1218 uwrap_init_env(id);
1220 id->enabled = true;
1222 UWRAP_LOG(UWRAP_LOG_DEBUG,
1223 "Enabled uid_wrapper as %s (real uid=%u)",
1224 id->ruid == 0 ? "root" : "user",
1225 (unsigned int)uwrap.myuid);
1228 UWRAP_UNLOCK(uwrap_id);
1230 UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1233 bool uid_wrapper_enabled(void)
1235 struct uwrap_thread *id = uwrap_tls_id;
1236 bool enabled;
1238 if (id == NULL) {
1239 return false;
1242 UWRAP_LOCK(uwrap_id);
1243 enabled = id->enabled;
1244 UWRAP_UNLOCK(uwrap_id);
1246 return enabled;
1250 * UWRAP_SETxUID FUNCTIONS
1253 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1255 struct uwrap_thread *id = uwrap_tls_id;
1257 UWRAP_LOG(UWRAP_LOG_TRACE,
1258 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1259 id->ruid, ruid, id->euid, euid, id->suid, suid);
1261 if (id->euid != 0) {
1262 if (ruid != (uid_t)-1 &&
1263 ruid != id->ruid &&
1264 ruid != id->euid &&
1265 ruid != id->suid) {
1266 errno = EPERM;
1267 return -1;
1269 if (euid != (uid_t)-1 &&
1270 euid != id->ruid &&
1271 euid != id->euid &&
1272 euid != id->suid) {
1273 errno = EPERM;
1274 return -1;
1276 if (suid != (uid_t)-1 &&
1277 suid != id->ruid &&
1278 suid != id->euid &&
1279 suid != id->suid) {
1280 errno = EPERM;
1281 return -1;
1285 return 0;
1288 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1290 struct uwrap_thread *id = uwrap_tls_id;
1291 int rc;
1293 UWRAP_LOG(UWRAP_LOG_TRACE,
1294 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1295 id->ruid, ruid, id->euid, euid, id->suid, suid);
1297 rc = uwrap_setresuid_args(ruid, euid, suid);
1298 if (rc != 0) {
1299 return rc;
1302 UWRAP_LOCK(uwrap_id);
1304 if (ruid != (uid_t)-1) {
1305 id->ruid = ruid;
1308 if (euid != (uid_t)-1) {
1309 id->euid = euid;
1312 if (suid != (uid_t)-1) {
1313 id->suid = suid;
1316 UWRAP_UNLOCK(uwrap_id);
1318 return 0;
1321 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1323 struct uwrap_thread *id = uwrap_tls_id;
1324 int rc;
1326 UWRAP_LOG(UWRAP_LOG_TRACE,
1327 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1328 id->ruid, ruid, id->euid, euid, id->suid, suid);
1330 rc = uwrap_setresuid_args(ruid, euid, suid);
1331 if (rc != 0) {
1332 return rc;
1335 UWRAP_LOCK(uwrap_id);
1337 for (id = uwrap.ids; id; id = id->next) {
1338 if (ruid != (uid_t)-1) {
1339 id->ruid = ruid;
1342 if (euid != (uid_t)-1) {
1343 id->euid = euid;
1346 if (suid != (uid_t)-1) {
1347 id->suid = suid;
1351 UWRAP_UNLOCK(uwrap_id);
1353 return 0;
1356 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1357 uid_t *_new_ruid,
1358 uid_t *_new_euid,
1359 uid_t *_new_suid)
1361 struct uwrap_thread *id = uwrap_tls_id;
1362 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1364 UWRAP_LOG(UWRAP_LOG_TRACE,
1365 "ruid %d -> %d, euid %d -> %d",
1366 id->ruid, ruid, id->euid, euid);
1368 if (ruid != (uid_t)-1) {
1369 new_ruid = ruid;
1370 if (ruid != id->ruid &&
1371 ruid != id->euid &&
1372 id->euid != 0) {
1373 errno = EPERM;
1374 return -1;
1378 if (euid != (uid_t)-1) {
1379 new_euid = euid;
1380 if (euid != id->ruid &&
1381 euid != id->euid &&
1382 euid != id->suid &&
1383 id->euid != 0) {
1384 errno = EPERM;
1385 return -1;
1389 if (ruid != (uid_t) -1 ||
1390 (euid != (uid_t)-1 && id->ruid != euid)) {
1391 new_suid = new_euid;
1394 *_new_ruid = new_ruid;
1395 *_new_euid = new_euid;
1396 *_new_suid = new_suid;
1398 return 0;
1401 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1403 struct uwrap_thread *id = uwrap_tls_id;
1404 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1405 int rc;
1407 UWRAP_LOG(UWRAP_LOG_TRACE,
1408 "ruid %d -> %d, euid %d -> %d",
1409 id->ruid, ruid, id->euid, euid);
1411 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1412 if (rc != 0) {
1413 return rc;
1416 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1419 #ifdef HAVE_SETREUID
1420 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1422 struct uwrap_thread *id = uwrap_tls_id;
1423 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1424 int rc;
1426 UWRAP_LOG(UWRAP_LOG_TRACE,
1427 "ruid %d -> %d, euid %d -> %d",
1428 id->ruid, ruid, id->euid, euid);
1430 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1431 if (rc != 0) {
1432 return rc;
1435 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1437 #endif
1439 static int uwrap_setuid_args(uid_t uid,
1440 uid_t *new_ruid,
1441 uid_t *new_euid,
1442 uid_t *new_suid)
1444 struct uwrap_thread *id = uwrap_tls_id;
1446 UWRAP_LOG(UWRAP_LOG_TRACE,
1447 "uid %d -> %d",
1448 id->ruid, uid);
1450 if (uid == (uid_t)-1) {
1451 errno = EINVAL;
1452 return -1;
1455 if (id->euid == 0) {
1456 *new_suid = *new_ruid = uid;
1457 } else if (uid != id->ruid &&
1458 uid != id->suid) {
1459 errno = EPERM;
1460 return -1;
1463 *new_euid = uid;
1465 return 0;
1468 static int uwrap_setuid_thread(uid_t uid)
1470 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1471 int rc;
1473 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1474 if (rc != 0) {
1475 return rc;
1478 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1481 static int uwrap_setuid(uid_t uid)
1483 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1484 int rc;
1486 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1487 if (rc != 0) {
1488 return rc;
1491 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1495 * UWRAP_GETxUID FUNCTIONS
1498 #ifdef HAVE_GETRESUID
1499 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1501 struct uwrap_thread *id = uwrap_tls_id;
1503 UWRAP_LOCK(uwrap_id);
1505 *ruid = id->ruid;
1506 *euid = id->euid;
1507 *suid = id->suid;
1509 UWRAP_UNLOCK(uwrap_id);
1511 return 0;
1513 #endif
1515 #ifdef HAVE_GETRESGID
1516 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1518 struct uwrap_thread *id = uwrap_tls_id;
1520 UWRAP_LOCK(uwrap_id);
1522 *rgid = id->rgid;
1523 *egid = id->egid;
1524 *sgid = id->sgid;
1526 UWRAP_UNLOCK(uwrap_id);
1528 return 0;
1530 #endif
1533 * UWRAP_SETxGID FUNCTIONS
1536 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1538 struct uwrap_thread *id = uwrap_tls_id;
1540 UWRAP_LOG(UWRAP_LOG_TRACE,
1541 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1542 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1544 if (id->euid != 0) {
1545 if (rgid != (gid_t)-1 &&
1546 rgid != id->rgid &&
1547 rgid != id->egid &&
1548 rgid != id->sgid) {
1549 errno = EPERM;
1550 return -1;
1552 if (egid != (gid_t)-1 &&
1553 egid != id->rgid &&
1554 egid != id->egid &&
1555 egid != id->sgid) {
1556 errno = EPERM;
1557 return -1;
1559 if (sgid != (gid_t)-1 &&
1560 sgid != id->rgid &&
1561 sgid != id->egid &&
1562 sgid != id->sgid) {
1563 errno = EPERM;
1564 return -1;
1568 return 0;
1571 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1573 struct uwrap_thread *id = uwrap_tls_id;
1574 int rc;
1576 UWRAP_LOG(UWRAP_LOG_TRACE,
1577 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1578 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1580 rc = uwrap_setresgid_args(rgid, egid, sgid);
1581 if (rc != 0) {
1582 return rc;
1585 UWRAP_LOCK(uwrap_id);
1587 if (rgid != (gid_t)-1) {
1588 id->rgid = rgid;
1591 if (egid != (gid_t)-1) {
1592 id->egid = egid;
1595 if (sgid != (gid_t)-1) {
1596 id->sgid = sgid;
1599 UWRAP_UNLOCK(uwrap_id);
1601 return 0;
1604 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1606 struct uwrap_thread *id = uwrap_tls_id;
1607 int rc;
1609 UWRAP_LOG(UWRAP_LOG_TRACE,
1610 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1611 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1613 rc = uwrap_setresgid_args(rgid, egid, sgid);
1614 if (rc != 0) {
1615 return rc;
1618 UWRAP_LOCK(uwrap_id);
1620 for (id = uwrap.ids; id; id = id->next) {
1621 if (rgid != (gid_t)-1) {
1622 id->rgid = rgid;
1625 if (egid != (gid_t)-1) {
1626 id->egid = egid;
1629 if (sgid != (gid_t)-1) {
1630 id->sgid = sgid;
1634 UWRAP_UNLOCK(uwrap_id);
1636 return 0;
1639 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1640 gid_t *_new_rgid,
1641 gid_t *_new_egid,
1642 gid_t *_new_sgid)
1644 struct uwrap_thread *id = uwrap_tls_id;
1645 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1647 UWRAP_LOG(UWRAP_LOG_TRACE,
1648 "rgid %d -> %d, egid %d -> %d",
1649 id->rgid, rgid, id->egid, egid);
1651 if (rgid != (gid_t)-1) {
1652 new_rgid = rgid;
1653 if (rgid != id->rgid &&
1654 rgid != id->egid &&
1655 id->euid != 0) {
1656 errno = EPERM;
1657 return -1;
1661 if (egid != (gid_t)-1) {
1662 new_egid = egid;
1663 if (egid != id->rgid &&
1664 egid != id->egid &&
1665 egid != id->sgid &&
1666 id->euid != 0) {
1667 errno = EPERM;
1668 return -1;
1672 if (rgid != (gid_t) -1 ||
1673 (egid != (gid_t)-1 && id->rgid != egid)) {
1674 new_sgid = new_egid;
1677 *_new_rgid = new_rgid;
1678 *_new_egid = new_egid;
1679 *_new_sgid = new_sgid;
1681 return 0;
1684 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1686 struct uwrap_thread *id = uwrap_tls_id;
1687 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1688 int rc;
1690 UWRAP_LOG(UWRAP_LOG_TRACE,
1691 "rgid %d -> %d, egid %d -> %d",
1692 id->rgid, rgid, id->egid, egid);
1694 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1695 if (rc != 0) {
1696 return rc;
1699 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1702 #ifdef HAVE_SETREGID
1703 static int uwrap_setregid(gid_t rgid, gid_t egid)
1705 struct uwrap_thread *id = uwrap_tls_id;
1706 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1707 int rc;
1709 UWRAP_LOG(UWRAP_LOG_TRACE,
1710 "rgid %d -> %d, egid %d -> %d",
1711 id->rgid, rgid, id->egid, egid);
1713 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1714 if (rc != 0) {
1715 return rc;
1718 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1720 #endif
1722 static int uwrap_setgid_args(gid_t gid,
1723 gid_t *new_rgid,
1724 gid_t *new_egid,
1725 gid_t *new_sgid)
1727 struct uwrap_thread *id = uwrap_tls_id;
1729 UWRAP_LOG(UWRAP_LOG_TRACE,
1730 "gid %d -> %d",
1731 id->rgid, gid);
1733 if (gid == (gid_t)-1) {
1734 errno = EINVAL;
1735 return -1;
1738 if (id->euid == 0) {
1739 *new_sgid = *new_rgid = gid;
1740 } else if (gid != id->rgid &&
1741 gid != id->sgid) {
1742 errno = EPERM;
1743 return -1;
1746 *new_egid = gid;
1748 return 0;
1751 static int uwrap_setgid_thread(gid_t gid)
1753 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1754 int rc;
1756 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1757 if (rc != 0) {
1758 return rc;
1761 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1764 static int uwrap_setgid(gid_t gid)
1766 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1767 int rc;
1769 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1770 if (rc != 0) {
1771 return rc;
1774 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1778 * SETUID
1780 int setuid(uid_t uid)
1782 if (!uid_wrapper_enabled()) {
1783 return libc_setuid(uid);
1786 uwrap_init();
1787 return uwrap_setuid(uid);
1790 #ifdef HAVE_SETEUID
1791 int seteuid(uid_t euid)
1793 if (!uid_wrapper_enabled()) {
1794 return libc_seteuid(euid);
1797 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1798 if (euid == (uid_t)-1) {
1799 errno = EINVAL;
1800 return -1;
1803 uwrap_init();
1804 return uwrap_setresuid(-1, euid, -1);
1806 #endif
1808 #ifdef HAVE_SETREUID
1809 int setreuid(uid_t ruid, uid_t euid)
1811 if (!uid_wrapper_enabled()) {
1812 return libc_setreuid(ruid, euid);
1815 uwrap_init();
1816 return uwrap_setreuid(ruid, euid);
1818 #endif
1820 #ifdef HAVE_SETRESUID
1821 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1823 if (!uid_wrapper_enabled()) {
1824 return libc_setresuid(ruid, euid, suid);
1827 uwrap_init();
1828 return uwrap_setresuid(ruid, euid, suid);
1830 #endif
1832 #ifdef HAVE_GETRESUID
1833 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1835 if (!uid_wrapper_enabled()) {
1836 return libc_getresuid(ruid, euid, suid);
1839 uwrap_init();
1840 return uwrap_getresuid(ruid, euid, suid);
1842 #endif
1845 * GETUID
1847 static uid_t uwrap_getuid(void)
1849 struct uwrap_thread *id = uwrap_tls_id;
1850 uid_t uid;
1852 UWRAP_LOCK(uwrap_id);
1853 uid = id->ruid;
1854 UWRAP_UNLOCK(uwrap_id);
1856 return uid;
1859 uid_t getuid(void)
1861 if (!uid_wrapper_enabled()) {
1862 return libc_getuid();
1865 uwrap_init();
1866 return uwrap_getuid();
1870 * GETEUID
1872 static uid_t uwrap_geteuid(void)
1874 const char *env = getenv("UID_WRAPPER_MYUID");
1875 struct uwrap_thread *id = uwrap_tls_id;
1876 uid_t uid;
1878 UWRAP_LOCK(uwrap_id);
1879 uid = id->euid;
1880 UWRAP_UNLOCK(uwrap_id);
1882 /* Disable root and return myuid */
1883 if (env != NULL && env[0] == '1') {
1884 uid = uwrap.myuid;
1887 return uid;
1890 uid_t geteuid(void)
1892 if (!uid_wrapper_enabled()) {
1893 return libc_geteuid();
1896 uwrap_init();
1897 return uwrap_geteuid();
1901 * SETGID
1903 int setgid(gid_t gid)
1905 if (!uid_wrapper_enabled()) {
1906 return libc_setgid(gid);
1909 uwrap_init();
1910 return uwrap_setgid(gid);
1913 #ifdef HAVE_SETEGID
1914 int setegid(gid_t egid)
1916 if (!uid_wrapper_enabled()) {
1917 return libc_setegid(egid);
1920 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1921 if (egid == (gid_t)-1) {
1922 errno = EINVAL;
1923 return -1;
1926 uwrap_init();
1927 return uwrap_setresgid(-1, egid, -1);
1929 #endif
1931 #ifdef HAVE_SETREGID
1932 int setregid(gid_t rgid, gid_t egid)
1934 if (!uid_wrapper_enabled()) {
1935 return libc_setregid(rgid, egid);
1938 uwrap_init();
1939 return uwrap_setregid(rgid, egid);
1941 #endif
1943 #ifdef HAVE_SETRESGID
1944 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1946 if (!uid_wrapper_enabled()) {
1947 return libc_setresgid(rgid, egid, sgid);
1950 uwrap_init();
1951 return uwrap_setresgid(rgid, egid, sgid);
1953 #endif
1955 #ifdef HAVE_GETRESGID
1956 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1958 if (!uid_wrapper_enabled()) {
1959 return libc_getresgid(rgid, egid, sgid);
1962 uwrap_init();
1963 return uwrap_getresgid(rgid, egid, sgid);
1965 #endif
1968 * GETGID
1970 static gid_t uwrap_getgid(void)
1972 struct uwrap_thread *id = uwrap_tls_id;
1973 gid_t gid;
1975 UWRAP_LOCK(uwrap_id);
1976 gid = id->rgid;
1977 UWRAP_UNLOCK(uwrap_id);
1979 return gid;
1982 gid_t getgid(void)
1984 if (!uid_wrapper_enabled()) {
1985 return libc_getgid();
1988 uwrap_init();
1989 return uwrap_getgid();
1993 * GETEGID
1995 static uid_t uwrap_getegid(void)
1997 struct uwrap_thread *id = uwrap_tls_id;
1998 gid_t gid;
2000 UWRAP_LOCK(uwrap_id);
2001 gid = id->egid;
2002 UWRAP_UNLOCK(uwrap_id);
2004 return gid;
2007 uid_t getegid(void)
2009 if (!uid_wrapper_enabled()) {
2010 return libc_getegid();
2013 uwrap_init();
2014 return uwrap_getegid();
2017 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
2019 struct uwrap_thread *id = uwrap_tls_id;
2020 int rc = -1;
2022 UWRAP_LOCK(uwrap_id);
2024 if (size == 0) {
2025 SAFE_FREE(id->groups);
2026 id->ngroups = 0;
2027 } else if (size > 0) {
2028 gid_t *tmp;
2030 tmp = realloc(id->groups, sizeof(gid_t) * size);
2031 if (tmp == NULL) {
2032 errno = ENOMEM;
2033 goto out;
2035 id->groups = tmp;
2036 id->ngroups = size;
2037 memcpy(id->groups, list, size * sizeof(gid_t));
2040 rc = 0;
2041 out:
2042 UWRAP_UNLOCK(uwrap_id);
2044 return rc;
2047 static int uwrap_setgroups(size_t size, const gid_t *list)
2049 struct uwrap_thread *id;
2050 int rc = -1;
2052 UWRAP_LOCK(uwrap_id);
2054 if (size == 0) {
2055 for (id = uwrap.ids; id; id = id->next) {
2056 SAFE_FREE(id->groups);
2057 id->ngroups = 0;
2060 } else if (size > 0) {
2061 gid_t *tmp;
2063 for (id = uwrap.ids; id; id = id->next) {
2064 tmp = realloc(id->groups, sizeof(gid_t) * size);
2065 if (tmp == NULL) {
2066 errno = ENOMEM;
2067 goto out;
2069 id->groups = tmp;
2071 id->ngroups = size;
2072 memcpy(id->groups, list, size * sizeof(gid_t));
2076 rc = 0;
2077 out:
2078 UWRAP_UNLOCK(uwrap_id);
2080 return rc;
2083 #ifdef HAVE_SETGROUPS_INT
2084 int setgroups(int size, const gid_t *list)
2085 #else
2086 int setgroups(size_t size, const gid_t *list)
2087 #endif
2089 if (!uid_wrapper_enabled()) {
2090 return libc_setgroups(size, list);
2093 uwrap_init();
2094 return uwrap_setgroups(size, list);
2097 static int uwrap_getgroups(int size, gid_t *list)
2099 struct uwrap_thread *id = uwrap_tls_id;
2100 int ngroups;
2102 UWRAP_LOCK(uwrap_id);
2103 ngroups = id->ngroups;
2105 if (size > ngroups) {
2106 size = ngroups;
2108 if (size == 0) {
2109 goto out;
2111 if (size < ngroups) {
2112 errno = EINVAL;
2113 ngroups = -1;
2115 memcpy(list, id->groups, size * sizeof(gid_t));
2117 out:
2118 UWRAP_UNLOCK(uwrap_id);
2120 return ngroups;
2123 int getgroups(int size, gid_t *list)
2125 if (!uid_wrapper_enabled()) {
2126 return libc_getgroups(size, list);
2129 uwrap_init();
2130 return uwrap_getgroups(size, list);
2133 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2134 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2135 static long int uwrap_syscall (long int sysno, va_list vp)
2137 long int rc;
2139 switch (sysno) {
2140 /* gid */
2141 #ifdef __alpha__
2142 case SYS_getxgid:
2143 #else
2144 case SYS_getgid:
2145 #endif
2146 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2147 case SYS_getgid32:
2148 #endif
2150 rc = uwrap_getgid();
2152 break;
2153 #ifdef SYS_getegid
2154 case SYS_getegid:
2155 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2156 case SYS_getegid32:
2157 #endif
2159 rc = uwrap_getegid();
2161 break;
2162 #endif /* SYS_getegid */
2163 case SYS_setgid:
2164 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2165 case SYS_setgid32:
2166 #endif
2168 gid_t gid = (gid_t) va_arg(vp, gid_t);
2170 rc = uwrap_setgid_thread(gid);
2172 break;
2173 case SYS_setregid:
2174 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2175 case SYS_setregid32:
2176 #endif
2178 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2179 gid_t egid = (gid_t) va_arg(vp, gid_t);
2181 rc = uwrap_setregid_thread(rgid, egid);
2183 break;
2184 #ifdef SYS_setresgid
2185 case SYS_setresgid:
2186 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2187 case SYS_setresgid32:
2188 #endif
2190 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2191 gid_t egid = (gid_t) va_arg(vp, gid_t);
2192 gid_t sgid = (gid_t) va_arg(vp, gid_t);
2194 rc = uwrap_setresgid_thread(rgid, egid, sgid);
2196 break;
2197 #endif /* SYS_setresgid */
2198 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2199 case SYS_getresgid:
2200 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2201 case SYS_getresgid32:
2202 #endif
2204 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2205 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2206 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2208 rc = uwrap_getresgid(rgid, egid, sgid);
2210 break;
2211 #endif /* SYS_getresgid && HAVE_GETRESGID */
2213 /* uid */
2214 #ifdef __alpha__
2215 case SYS_getxuid:
2216 #else
2217 case SYS_getuid:
2218 #endif
2219 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2220 case SYS_getuid32:
2221 #endif
2223 rc = uwrap_getuid();
2225 break;
2226 #ifdef SYS_geteuid
2227 case SYS_geteuid:
2228 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2229 case SYS_geteuid32:
2230 #endif
2232 rc = uwrap_geteuid();
2234 break;
2235 #endif /* SYS_geteuid */
2236 case SYS_setuid:
2237 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2238 case SYS_setuid32:
2239 #endif
2241 uid_t uid = (uid_t) va_arg(vp, uid_t);
2243 rc = uwrap_setuid_thread(uid);
2245 break;
2246 case SYS_setreuid:
2247 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2248 case SYS_setreuid32:
2249 #endif
2251 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2252 uid_t euid = (uid_t) va_arg(vp, uid_t);
2254 rc = uwrap_setreuid_thread(ruid, euid);
2256 break;
2257 #ifdef SYS_setresuid
2258 case SYS_setresuid:
2259 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2260 case SYS_setresuid32:
2261 #endif
2263 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2264 uid_t euid = (uid_t) va_arg(vp, uid_t);
2265 uid_t suid = (uid_t) va_arg(vp, uid_t);
2267 rc = uwrap_setresuid_thread(ruid, euid, suid);
2269 break;
2270 #endif /* SYS_setresuid */
2271 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2272 case SYS_getresuid:
2273 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2274 case SYS_getresuid32:
2275 #endif
2277 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2278 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2279 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2281 rc = uwrap_getresuid(ruid, euid, suid);
2283 break;
2284 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2285 /* groups */
2286 case SYS_setgroups:
2287 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2288 case SYS_setgroups32:
2289 #endif
2291 size_t size = (size_t) va_arg(vp, size_t);
2292 gid_t *list = (gid_t *) va_arg(vp, int *);
2294 rc = uwrap_setgroups_thread(size, list);
2296 break;
2297 default:
2298 UWRAP_LOG(UWRAP_LOG_DEBUG,
2299 "UID_WRAPPER calling non-wrapped syscall %lu",
2300 sysno);
2302 rc = libc_vsyscall(sysno, vp);
2303 break;
2306 return rc;
2309 #ifdef HAVE_SYSCALL
2310 #ifdef HAVE_SYSCALL_INT
2311 int syscall (int sysno, ...)
2312 #else
2313 long int syscall (long int sysno, ...)
2314 #endif
2316 #ifdef HAVE_SYSCALL_INT
2317 int rc;
2318 #else
2319 long int rc;
2320 #endif
2321 va_list va;
2323 va_start(va, sysno);
2325 if (!uid_wrapper_enabled()) {
2326 rc = libc_vsyscall(sysno, va);
2327 va_end(va);
2328 return rc;
2331 uwrap_init();
2332 rc = uwrap_syscall(sysno, va);
2333 va_end(va);
2335 return rc;
2337 #endif /* HAVE_SYSCALL */
2338 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2340 /****************************
2341 * CONSTRUCTOR
2342 ***************************/
2344 void uwrap_constructor(void)
2346 char *glibc_malloc_lock_bug;
2349 * This is a workaround for a bug in glibc < 2.24:
2351 * The child handler for the malloc() function is called and locks the
2352 * mutex. Then our child handler is called and we try to call setenv().
2353 * setenv() wants to malloc and tries to aquire the lock for malloc and
2354 * we end up in a deadlock.
2356 * So as a workaround we need to call malloc once before we setup the
2357 * handlers.
2359 * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2361 glibc_malloc_lock_bug = malloc(1);
2362 if (glibc_malloc_lock_bug == NULL) {
2363 exit(-1);
2365 glibc_malloc_lock_bug[0] = '\0';
2368 * If we hold a lock and the application forks, then the child
2369 * is not able to unlock the mutex and we are in a deadlock.
2370 * This should prevent such deadlocks.
2372 pthread_atfork(&uwrap_thread_prepare,
2373 &uwrap_thread_parent,
2374 &uwrap_thread_child);
2376 free(glibc_malloc_lock_bug);
2378 /* Here is safe place to call uwrap_init() and initialize data
2379 * for main process.
2381 uwrap_init();
2384 /****************************
2385 * DESTRUCTOR
2386 ***************************/
2389 * This function is called when the library is unloaded and makes sure that
2390 * resources are freed.
2392 void uwrap_destructor(void)
2394 struct uwrap_thread *u = uwrap.ids;
2396 UWRAP_LOCK_ALL;
2398 while (u != NULL) {
2399 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2401 SAFE_FREE(u->groups);
2402 SAFE_FREE(u);
2404 u = uwrap.ids;
2408 if (uwrap.libc.handle != NULL) {
2409 dlclose(uwrap.libc.handle);
2412 if (uwrap.libpthread.handle != NULL) {
2413 dlclose(uwrap.libpthread.handle);
2416 UWRAP_UNLOCK_ALL;