2 * Copyright (c) 2009 Andrew Tridgell
3 * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
46 # define UWRAP_LOCK(m) do { \
47 pthread_mutex_lock(&( m ## _mutex)); \
50 # define UWRAP_UNLOCK(m) do { \
51 pthread_mutex_unlock(&( m ## _mutex)); \
54 /* 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))
68 #define CONSTRUCTOR_ATTRIBUTE
69 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
71 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
72 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
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)))
87 #define PRINTF_ATTRIBUTE(a,b)
88 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
90 #define UWRAP_DLIST_ADD(list,item) do { \
92 (item)->prev = NULL; \
93 (item)->next = NULL; \
96 (item)->prev = NULL; \
97 (item)->next = (list); \
98 (list)->prev = (item); \
103 #define UWRAP_DLIST_REMOVE(list,item) do { \
104 if ((list) == (item)) { \
105 (list) = (item)->next; \
107 (list)->prev = NULL; \
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; \
122 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
129 enum uwrap_dbglvl_e
{
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
, ...)
144 unsigned int lvl
= 0;
145 const char *prefix
= "UWRAP";
147 d
= getenv("UID_WRAPPER_DEBUGLEVEL");
156 va_start(va
, format
);
157 vsnprintf(buffer
, sizeof(buffer
), format
, va
);
161 case UWRAP_LOG_ERROR
:
162 prefix
= "UWRAP_ERROR";
165 prefix
= "UWRAP_WARN";
167 case UWRAP_LOG_DEBUG
:
168 prefix
= "UWRAP_DEBUG";
170 case UWRAP_LOG_TRACE
:
171 prefix
= "UWRAP_TRACE";
187 #define LIBC_NAME "libc.so"
189 typedef int (*__libc_setuid
)(uid_t uid
);
191 typedef uid_t (*__libc_getuid
)(void);
194 typedef int (*__libc_seteuid
)(uid_t euid
);
198 typedef int (*__libc_setreuid
)(uid_t ruid
, uid_t euid
);
201 #ifdef HAVE_SETRESUID
202 typedef int (*__libc_setresuid
)(uid_t ruid
, uid_t euid
, uid_t suid
);
205 #ifdef HAVE_GETRESUID
206 typedef int (*__libc_getresuid
)(uid_t
*ruid
, uid_t
*euid
, uid_t
*suid
);
209 typedef uid_t (*__libc_geteuid
)(void);
211 typedef int (*__libc_setgid
)(gid_t gid
);
213 typedef gid_t (*__libc_getgid
)(void);
216 typedef int (*__libc_setegid
)(uid_t egid
);
220 typedef int (*__libc_setregid
)(uid_t rgid
, uid_t egid
);
223 #ifdef HAVE_SETRESGID
224 typedef int (*__libc_setresgid
)(uid_t rgid
, uid_t egid
, uid_t sgid
);
227 #ifdef HAVE_GETRESGID
228 typedef int (*__libc_getresgid
)(gid_t
*rgid
, gid_t
*egid
, gid_t
*sgid
);
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
);
238 typedef long int (*__libc_syscall
)(long int sysno
, ...);
241 #define UWRAP_SYMBOL_ENTRY(i) \
247 struct uwrap_libc_symbols
{
248 UWRAP_SYMBOL_ENTRY(setuid
);
249 UWRAP_SYMBOL_ENTRY(getuid
);
251 UWRAP_SYMBOL_ENTRY(seteuid
);
254 UWRAP_SYMBOL_ENTRY(setreuid
);
256 #ifdef HAVE_SETRESUID
257 UWRAP_SYMBOL_ENTRY(setresuid
);
259 #ifdef HAVE_GETRESUID
260 UWRAP_SYMBOL_ENTRY(getresuid
);
262 UWRAP_SYMBOL_ENTRY(geteuid
);
263 UWRAP_SYMBOL_ENTRY(setgid
);
264 UWRAP_SYMBOL_ENTRY(getgid
);
266 UWRAP_SYMBOL_ENTRY(setegid
);
269 UWRAP_SYMBOL_ENTRY(setregid
);
271 #ifdef HAVE_SETRESGID
272 UWRAP_SYMBOL_ENTRY(setresgid
);
274 #ifdef HAVE_GETRESGID
275 UWRAP_SYMBOL_ENTRY(getresgid
);
277 UWRAP_SYMBOL_ENTRY(getegid
);
278 UWRAP_SYMBOL_ENTRY(getgroups
);
279 UWRAP_SYMBOL_ENTRY(setgroups
);
281 UWRAP_SYMBOL_ENTRY(syscall
);
284 #undef UWRAP_SYMBOL_ENTRY
289 /* Yeah... I'm pig. I overloading macro here... So what? */
290 #define UWRAP_SYMBOL_ENTRY(i) \
292 __libpthread_##i f; \
296 typedef int (*__libpthread_pthread_create
)(pthread_t
*thread
,
297 const pthread_attr_t
*attr
,
298 void *(*start_routine
) (void *),
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
{
325 struct uwrap_thread
*next
;
326 struct uwrap_thread
*prev
;
332 struct uwrap_libc_symbols symbols
;
337 struct uwrap_libpthread_symbols symbols
;
342 /* Real uid and gid of user who run uid wrapper */
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 /*********************************************************
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 *********************************************************/
382 static void *uwrap_load_lib_handle(enum uwrap_lib lib
)
384 int flags
= RTLD_LAZY
;
389 flags
|= RTLD_DEEPBIND
;
395 case UWRAP_LIBSOCKET
:
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
) {
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
) {
417 uwrap
.libc
.handle
= handle
;
420 case UWRAP_LIBPTHREAD
:
421 handle
= uwrap
.libpthread
.handle
;
422 if (handle
== NULL
) {
423 handle
= dlopen("libpthread.so.0", flags
);
424 if (handle
!= NULL
) {
431 if (handle
== NULL
) {
433 handle
= uwrap
.libc
.handle
= RTLD_NEXT
;
436 "Failed to dlopen library: %s\n",
445 static void *_uwrap_bind_symbol(enum uwrap_lib lib
, const char *fn_name
)
450 handle
= uwrap_load_lib_handle(lib
);
452 func
= dlsym(handle
, fn_name
);
455 "Failed to find %s: %s\n",
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)
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();
502 static int libc_seteuid(uid_t euid
)
504 uwrap_bind_symbol_libc(seteuid
);
506 return uwrap
.libc
.symbols
._libc_seteuid
.f(euid
);
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
);
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
);
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
);
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();
559 static int libc_setegid(gid_t egid
)
561 uwrap_bind_symbol_libc(setegid
);
563 return uwrap
.libc
.symbols
._libc_setegid
.f(egid
);
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
);
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
);
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
);
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
);
616 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
617 static long int libc_vsyscall(long int sysno
, va_list va
)
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
,
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
);
662 UWRAP_UNLOCK(uwrap_id
);
663 libpthread_pthread_exit(retval
);
667 UWRAP_DLIST_REMOVE(uwrap
.ids
, id
);
668 SAFE_FREE(id
->groups
);
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. */
689 static int libpthread_pthread_create(pthread_t
*thread
,
690 const pthread_attr_t
*attr
,
691 void *(*start_routine
) (void *),
694 uwrap_bind_symbol_libpthread(pthread_create
);
695 return uwrap
.libpthread
.symbols
._libpthread_pthread_create
.f(thread
,
701 struct uwrap_pthread_create_args
{
702 struct uwrap_thread
*id
;
703 void *(*start_routine
) (void *);
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
;
713 struct uwrap_thread
*id
= a
->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 *),
727 struct uwrap_pthread_create_args
*args
;
728 struct uwrap_thread
*src_id
= uwrap_tls_id
;
731 args
= malloc(sizeof(struct uwrap_pthread_create_args
));
733 UWRAP_LOG(UWRAP_LOG_ERROR
,
734 "uwrap_pthread_create: Unable to allocate memory");
738 args
->start_routine
= start_routine
;
741 args
->id
= calloc(1, sizeof(struct uwrap_thread
));
742 if (args
->id
== NULL
) {
744 UWRAP_LOG(UWRAP_LOG_ERROR
,
745 "uwrap_pthread_create: Unable to allocate memory");
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
);
757 UWRAP_LOG(UWRAP_LOG_ERROR
,
758 "uwrap_pthread_create: Unable to allocate memory again");
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
);
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
,
794 int pthread_create(pthread_t
*thread
,
795 const pthread_attr_t
*attr
,
796 void *(*start_routine
) (void *),
799 if (!uid_wrapper_enabled()) {
800 return libpthread_pthread_create(thread
,
806 return uwrap_pthread_create(thread
,
812 /*********************************************************
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
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) */
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);
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).",
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;
866 len
= snprintf(unsigned_str
, sizeof(unsigned_str
), ",%u", id
->groups
[i
]);
868 UWRAP_LOG(UWRAP_LOG_ERROR
,
869 "snprintf failed for groups[%d]=%u",
874 if (((size_t)len
) >= groups_str_avail
) {
875 UWRAP_LOG(UWRAP_LOG_ERROR
,
876 "groups env string is to small for %d groups",
881 len
= snprintf(groups_str
+ groups_str_len
,
882 groups_str_size
- groups_str_len
,
884 i
== 0 ? unsigned_str
+ 1 : unsigned_str
);
886 UWRAP_LOG(UWRAP_LOG_ERROR
,
887 "snprintf failed to create groups string at groups[%d]=%u",
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
;
908 /* uid_wrapper is loaded but not enabled */
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.
922 static void uwrap_thread_parent(void)
924 struct uwrap_thread
*id
= uwrap_tls_id
;
926 /* uid_wrapper is loaded but not enabled */
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 */
949 * "Garbage collector" - Inspired by DESTRUCTOR.
950 * All threads (except one which called fork()) are dead now.. Dave
951 * That's what posix said...
955 /* Skip this item. */
960 UWRAP_DLIST_REMOVE(uwrap
.ids
, u
);
962 SAFE_FREE(u
->groups
);
968 uwrap_export_ids(id
);
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
)
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') {
1037 n
= strtol(env
, &endp
, 10);
1040 } else if (n
> 0 && n
< GROUP_MAX_COUNT
) {
1043 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1052 id
->groups
= calloc(ngroups
, sizeof(gid_t
));
1053 if (id
->groups
== NULL
) {
1054 UWRAP_LOG(UWRAP_LOG_ERROR
,
1055 "Unable to allocate memory");
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
) {
1070 p
= strtok_r(groups_str
, ",", &saveptr
);
1072 id
->groups
[i
] = strtol(p
, (char **)NULL
, 10);
1075 p
= strtok_r(NULL
, ",", &saveptr
);
1077 SAFE_FREE(groups_str
);
1081 UWRAP_LOG(UWRAP_LOG_ERROR
,
1082 "ERROR: The number of groups (%u) passed, "
1083 "does not match the number of groups (%u) "
1090 UWRAP_LOG(UWRAP_LOG_DEBUG
, "Initalize groups with %s", env
);
1091 id
->ngroups
= ngroups
;
1095 static void uwrap_init(void)
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
);
1110 UWRAP_LOG(UWRAP_LOG_ERROR
,
1111 "Invalid id for thread");
1115 UWRAP_UNLOCK(uwrap_id
);
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
));
1130 UWRAP_LOG(UWRAP_LOG_ERROR
,
1131 "Unable to allocate memory for main id");
1135 UWRAP_DLIST_ADD(uwrap
.ids
, 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");
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.");
1166 id
->groups
= malloc(sizeof(gid_t
) * id
->ngroups
);
1167 if (id
->groups
== NULL
) {
1168 UWRAP_LOG(UWRAP_LOG_ERROR
, "Unable to allocate memory");
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.");
1176 * Deallocation of uwrap.groups is handled by
1177 * library destructor.
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
;
1207 UWRAP_LOCK(uwrap_id
);
1208 enabled
= id
->enabled
;
1209 UWRAP_UNLOCK(uwrap_id
);
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 &&
1234 if (euid
!= (uid_t
)-1 &&
1241 if (suid
!= (uid_t
)-1 &&
1253 static int uwrap_setresuid_thread(uid_t ruid
, uid_t euid
, uid_t suid
)
1255 struct uwrap_thread
*id
= uwrap_tls_id
;
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
);
1267 UWRAP_LOCK(uwrap_id
);
1269 if (ruid
!= (uid_t
)-1) {
1273 if (euid
!= (uid_t
)-1) {
1277 if (suid
!= (uid_t
)-1) {
1281 UWRAP_UNLOCK(uwrap_id
);
1286 static int uwrap_setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
1288 struct uwrap_thread
*id
= uwrap_tls_id
;
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
);
1300 UWRAP_LOCK(uwrap_id
);
1302 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1303 if (ruid
!= (uid_t
)-1) {
1307 if (euid
!= (uid_t
)-1) {
1311 if (suid
!= (uid_t
)-1) {
1316 UWRAP_UNLOCK(uwrap_id
);
1321 static int uwrap_setreuid_args(uid_t ruid
, uid_t euid
,
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) {
1335 if (ruid
!= id
->ruid
&&
1343 if (euid
!= (uid_t
)-1) {
1345 if (euid
!= id
->ruid
&&
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
;
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;
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
);
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;
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
);
1400 return uwrap_setresuid(new_ruid
, new_euid
, new_suid
);
1404 static int uwrap_setuid_args(uid_t uid
,
1409 struct uwrap_thread
*id
= uwrap_tls_id
;
1411 UWRAP_LOG(UWRAP_LOG_TRACE
,
1415 if (uid
== (uid_t
)-1) {
1420 if (id
->euid
== 0) {
1421 *new_suid
= *new_ruid
= uid
;
1422 } else if (uid
!= id
->ruid
&&
1433 static int uwrap_setuid_thread(uid_t uid
)
1435 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1438 rc
= uwrap_setuid_args(uid
, &new_ruid
, &new_euid
, &new_suid
);
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;
1451 rc
= uwrap_setuid_args(uid
, &new_ruid
, &new_euid
, &new_suid
);
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
);
1474 UWRAP_UNLOCK(uwrap_id
);
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
);
1491 UWRAP_UNLOCK(uwrap_id
);
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 &&
1517 if (egid
!= (gid_t
)-1 &&
1524 if (sgid
!= (gid_t
)-1 &&
1536 static int uwrap_setresgid_thread(gid_t rgid
, gid_t egid
, gid_t sgid
)
1538 struct uwrap_thread
*id
= uwrap_tls_id
;
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
);
1550 UWRAP_LOCK(uwrap_id
);
1552 if (rgid
!= (gid_t
)-1) {
1556 if (egid
!= (gid_t
)-1) {
1560 if (sgid
!= (gid_t
)-1) {
1564 UWRAP_UNLOCK(uwrap_id
);
1569 static int uwrap_setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
1571 struct uwrap_thread
*id
= uwrap_tls_id
;
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
);
1583 UWRAP_LOCK(uwrap_id
);
1585 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1586 if (rgid
!= (gid_t
)-1) {
1590 if (egid
!= (gid_t
)-1) {
1594 if (sgid
!= (gid_t
)-1) {
1599 UWRAP_UNLOCK(uwrap_id
);
1604 static int uwrap_setregid_args(gid_t rgid
, gid_t egid
,
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) {
1618 if (rgid
!= id
->rgid
&&
1626 if (egid
!= (gid_t
)-1) {
1628 if (egid
!= id
->rgid
&&
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
;
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;
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
);
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;
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
);
1683 return uwrap_setresgid(new_rgid
, new_egid
, new_sgid
);
1687 static int uwrap_setgid_args(gid_t gid
,
1692 struct uwrap_thread
*id
= uwrap_tls_id
;
1694 UWRAP_LOG(UWRAP_LOG_TRACE
,
1698 if (gid
== (gid_t
)-1) {
1703 if (id
->euid
== 0) {
1704 *new_sgid
= *new_rgid
= gid
;
1705 } else if (gid
!= id
->rgid
&&
1716 static int uwrap_setgid_thread(gid_t gid
)
1718 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1721 rc
= uwrap_setgid_args(gid
, &new_rgid
, &new_egid
, &new_sgid
);
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;
1734 rc
= uwrap_setgid_args(gid
, &new_rgid
, &new_egid
, &new_sgid
);
1739 return uwrap_setresgid(new_rgid
, new_egid
, new_sgid
);
1745 int setuid(uid_t uid
)
1747 if (!uid_wrapper_enabled()) {
1748 return libc_setuid(uid
);
1752 return uwrap_setuid(uid
);
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) {
1769 return uwrap_setresuid(-1, euid
, -1);
1773 #ifdef HAVE_SETREUID
1774 int setreuid(uid_t ruid
, uid_t euid
)
1776 if (!uid_wrapper_enabled()) {
1777 return libc_setreuid(ruid
, euid
);
1781 return uwrap_setreuid(ruid
, euid
);
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
);
1793 return uwrap_setresuid(ruid
, euid
, suid
);
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
);
1805 return uwrap_getresuid(ruid
, euid
, suid
);
1812 static uid_t
uwrap_getuid(void)
1814 struct uwrap_thread
*id
= uwrap_tls_id
;
1817 UWRAP_LOCK(uwrap_id
);
1819 UWRAP_UNLOCK(uwrap_id
);
1826 if (!uid_wrapper_enabled()) {
1827 return libc_getuid();
1831 return uwrap_getuid();
1837 static uid_t
uwrap_geteuid(void)
1839 const char *env
= getenv("UID_WRAPPER_MYUID");
1840 struct uwrap_thread
*id
= uwrap_tls_id
;
1843 UWRAP_LOCK(uwrap_id
);
1845 UWRAP_UNLOCK(uwrap_id
);
1847 /* Disable root and return myuid */
1848 if (env
!= NULL
&& env
[0] == '1') {
1857 if (!uid_wrapper_enabled()) {
1858 return libc_geteuid();
1862 return uwrap_geteuid();
1868 int setgid(gid_t gid
)
1870 if (!uid_wrapper_enabled()) {
1871 return libc_setgid(gid
);
1875 return uwrap_setgid(gid
);
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) {
1892 return uwrap_setresgid(-1, egid
, -1);
1896 #ifdef HAVE_SETREGID
1897 int setregid(gid_t rgid
, gid_t egid
)
1899 if (!uid_wrapper_enabled()) {
1900 return libc_setregid(rgid
, egid
);
1904 return uwrap_setregid(rgid
, egid
);
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
);
1916 return uwrap_setresgid(rgid
, egid
, sgid
);
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
);
1928 return uwrap_getresgid(rgid
, egid
, sgid
);
1935 static gid_t
uwrap_getgid(void)
1937 struct uwrap_thread
*id
= uwrap_tls_id
;
1940 UWRAP_LOCK(uwrap_id
);
1942 UWRAP_UNLOCK(uwrap_id
);
1949 if (!uid_wrapper_enabled()) {
1950 return libc_getgid();
1954 return uwrap_getgid();
1960 static uid_t
uwrap_getegid(void)
1962 struct uwrap_thread
*id
= uwrap_tls_id
;
1965 UWRAP_LOCK(uwrap_id
);
1967 UWRAP_UNLOCK(uwrap_id
);
1974 if (!uid_wrapper_enabled()) {
1975 return libc_getegid();
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
;
1987 UWRAP_LOCK(uwrap_id
);
1990 SAFE_FREE(id
->groups
);
1992 } else if (size
> 0) {
1995 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
2002 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
2007 UWRAP_UNLOCK(uwrap_id
);
2012 static int uwrap_setgroups(size_t size
, const gid_t
*list
)
2014 struct uwrap_thread
*id
;
2017 UWRAP_LOCK(uwrap_id
);
2020 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
2021 SAFE_FREE(id
->groups
);
2025 } else if (size
> 0) {
2028 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
2029 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
2037 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
2043 UWRAP_UNLOCK(uwrap_id
);
2048 #ifdef HAVE_SETGROUPS_INT
2049 int setgroups(int size
, const gid_t
*list
)
2051 int setgroups(size_t size
, const gid_t
*list
)
2054 if (!uid_wrapper_enabled()) {
2055 return libc_setgroups(size
, list
);
2059 return uwrap_setgroups(size
, list
);
2062 static int uwrap_getgroups(int size
, gid_t
*list
)
2064 struct uwrap_thread
*id
= uwrap_tls_id
;
2067 UWRAP_LOCK(uwrap_id
);
2068 ngroups
= id
->ngroups
;
2070 if (size
> ngroups
) {
2076 if (size
< ngroups
) {
2080 memcpy(list
, id
->groups
, size
* sizeof(gid_t
));
2083 UWRAP_UNLOCK(uwrap_id
);
2088 int getgroups(int size
, gid_t
*list
)
2090 if (!uid_wrapper_enabled()) {
2091 return libc_getgroups(size
, list
);
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
)
2111 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2115 rc
= uwrap_getgid();
2120 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2124 rc
= uwrap_getegid();
2127 #endif /* SYS_getegid */
2129 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2133 gid_t gid
= (gid_t
) va_arg(vp
, gid_t
);
2135 rc
= uwrap_setgid_thread(gid
);
2139 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2140 case SYS_setregid32
:
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
);
2149 #ifdef SYS_setresgid
2151 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2152 case SYS_setresgid32
:
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
);
2162 #endif /* SYS_setresgid */
2163 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2165 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2166 case SYS_getresgid32
:
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
);
2176 #endif /* SYS_getresgid && HAVE_GETRESGID */
2184 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2188 rc
= uwrap_getuid();
2193 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2197 rc
= uwrap_geteuid();
2200 #endif /* SYS_geteuid */
2202 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2206 uid_t uid
= (uid_t
) va_arg(vp
, uid_t
);
2208 rc
= uwrap_setuid_thread(uid
);
2212 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2213 case SYS_setreuid32
:
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
);
2222 #ifdef SYS_setresuid
2224 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2225 case SYS_setresuid32
:
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
);
2235 #endif /* SYS_setresuid */
2236 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2238 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2239 case SYS_getresuid32
:
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
);
2249 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2252 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2253 case SYS_setgroups32
:
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
);
2263 UWRAP_LOG(UWRAP_LOG_DEBUG
,
2264 "UID_WRAPPER calling non-wrapped syscall %lu",
2267 rc
= libc_vsyscall(sysno
, vp
);
2275 #ifdef HAVE_SYSCALL_INT
2276 int syscall (int sysno
, ...)
2278 long int syscall (long int sysno
, ...)
2281 #ifdef HAVE_SYSCALL_INT
2288 va_start(va
, sysno
);
2290 if (!uid_wrapper_enabled()) {
2291 rc
= libc_vsyscall(sysno
, va
);
2297 rc
= uwrap_syscall(sysno
, va
);
2302 #endif /* HAVE_SYSCALL */
2303 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2305 /****************************
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
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
) {
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
2349 /****************************
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
;
2364 UWRAP_DLIST_REMOVE(uwrap
.ids
, u
);
2366 SAFE_FREE(u
->groups
);
2373 if (uwrap
.libc
.handle
!= NULL
) {
2374 dlclose(uwrap
.libc
.handle
);
2377 if (uwrap
.libpthread
.handle
!= NULL
) {
2378 dlclose(uwrap
.libpthread
.handle
);