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
{
137 # define UWRAP_LOG(...)
139 static void uwrap_log(enum uwrap_dbglvl_e dbglvl
, const char *function
, const char *format
, ...) PRINTF_ATTRIBUTE(3, 4);
140 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
142 static void uwrap_log(enum uwrap_dbglvl_e dbglvl
, const char *function
, const char *format
, ...)
147 unsigned int lvl
= 0;
149 d
= getenv("UID_WRAPPER_DEBUGLEVEL");
154 va_start(va
, format
);
155 vsnprintf(buffer
, sizeof(buffer
), format
, va
);
159 const char *prefix
= "UWRAP";
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";
189 #define LIBC_NAME "libc.so"
191 typedef int (*__libc_setuid
)(uid_t uid
);
193 typedef uid_t (*__libc_getuid
)(void);
196 typedef int (*__libc_seteuid
)(uid_t euid
);
200 typedef int (*__libc_setreuid
)(uid_t ruid
, uid_t euid
);
203 #ifdef HAVE_SETRESUID
204 typedef int (*__libc_setresuid
)(uid_t ruid
, uid_t euid
, uid_t suid
);
207 #ifdef HAVE_GETRESUID
208 typedef int (*__libc_getresuid
)(uid_t
*ruid
, uid_t
*euid
, uid_t
*suid
);
211 typedef uid_t (*__libc_geteuid
)(void);
213 typedef int (*__libc_setgid
)(gid_t gid
);
215 typedef gid_t (*__libc_getgid
)(void);
218 typedef int (*__libc_setegid
)(uid_t egid
);
222 typedef int (*__libc_setregid
)(uid_t rgid
, uid_t egid
);
225 #ifdef HAVE_SETRESGID
226 typedef int (*__libc_setresgid
)(uid_t rgid
, uid_t egid
, uid_t sgid
);
229 #ifdef HAVE_GETRESGID
230 typedef int (*__libc_getresgid
)(gid_t
*rgid
, gid_t
*egid
, gid_t
*sgid
);
233 typedef gid_t (*__libc_getegid
)(void);
235 typedef int (*__libc_getgroups
)(int size
, gid_t list
[]);
237 typedef int (*__libc_setgroups
)(size_t size
, const gid_t
*list
);
240 typedef long int (*__libc_syscall
)(long int sysno
, ...);
243 #define UWRAP_SYMBOL_ENTRY(i) \
249 struct uwrap_libc_symbols
{
250 UWRAP_SYMBOL_ENTRY(setuid
);
251 UWRAP_SYMBOL_ENTRY(getuid
);
253 UWRAP_SYMBOL_ENTRY(seteuid
);
256 UWRAP_SYMBOL_ENTRY(setreuid
);
258 #ifdef HAVE_SETRESUID
259 UWRAP_SYMBOL_ENTRY(setresuid
);
261 #ifdef HAVE_GETRESUID
262 UWRAP_SYMBOL_ENTRY(getresuid
);
264 UWRAP_SYMBOL_ENTRY(geteuid
);
265 UWRAP_SYMBOL_ENTRY(setgid
);
266 UWRAP_SYMBOL_ENTRY(getgid
);
268 UWRAP_SYMBOL_ENTRY(setegid
);
271 UWRAP_SYMBOL_ENTRY(setregid
);
273 #ifdef HAVE_SETRESGID
274 UWRAP_SYMBOL_ENTRY(setresgid
);
276 #ifdef HAVE_GETRESGID
277 UWRAP_SYMBOL_ENTRY(getresgid
);
279 UWRAP_SYMBOL_ENTRY(getegid
);
280 UWRAP_SYMBOL_ENTRY(getgroups
);
281 UWRAP_SYMBOL_ENTRY(setgroups
);
283 UWRAP_SYMBOL_ENTRY(syscall
);
286 #undef UWRAP_SYMBOL_ENTRY
291 /* Yeah... I'm pig. I overloading macro here... So what? */
292 #define UWRAP_SYMBOL_ENTRY(i) \
294 __libpthread_##i f; \
298 typedef int (*__libpthread_pthread_create
)(pthread_t
*thread
,
299 const pthread_attr_t
*attr
,
300 void *(*start_routine
) (void *),
302 typedef void (*__libpthread_pthread_exit
)(void *retval
);
304 struct uwrap_libpthread_symbols
{
305 UWRAP_SYMBOL_ENTRY(pthread_create
);
306 UWRAP_SYMBOL_ENTRY(pthread_exit
);
308 #undef UWRAP_SYMBOL_ENTRY
311 * We keep the virtualised euid/egid/groups information here
313 struct uwrap_thread
{
327 struct uwrap_thread
*next
;
328 struct uwrap_thread
*prev
;
334 struct uwrap_libc_symbols symbols
;
339 struct uwrap_libpthread_symbols symbols
;
344 /* Real uid and gid of user who run uid wrapper */
348 struct uwrap_thread
*ids
;
351 static struct uwrap uwrap
;
353 /* Shortcut to the list item */
354 static UWRAP_THREAD
struct uwrap_thread
*uwrap_tls_id
;
356 /* The mutex or accessing the id */
357 static pthread_mutex_t uwrap_id_mutex
= PTHREAD_MUTEX_INITIALIZER
;
359 /* The mutex for accessing the global libc.symbols */
360 static pthread_mutex_t libc_symbol_binding_mutex
= PTHREAD_MUTEX_INITIALIZER
;
362 /* The mutex for accessing the global libpthread.symbols */
363 static pthread_mutex_t libpthread_symbol_binding_mutex
= PTHREAD_MUTEX_INITIALIZER
;
365 /*********************************************************
367 *********************************************************/
369 bool uid_wrapper_enabled(void);
370 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE
;
371 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE
;
373 /*********************************************************
374 * UWRAP LIBC LOADER FUNCTIONS
375 *********************************************************/
384 static void *uwrap_load_lib_handle(enum uwrap_lib lib
)
386 int flags
= RTLD_LAZY
;
391 flags
|= RTLD_DEEPBIND
;
397 case UWRAP_LIBSOCKET
:
400 handle
= uwrap
.libc
.handle
;
401 if (handle
== NULL
) {
402 for (i
= 10; i
>= 0; i
--) {
403 char soname
[256] = {0};
405 snprintf(soname
, sizeof(soname
), "libc.so.%d", i
);
406 handle
= dlopen(soname
, flags
);
407 if (handle
!= NULL
) {
412 uwrap
.libc
.handle
= handle
;
415 case UWRAP_LIBPTHREAD
:
416 handle
= uwrap
.libpthread
.handle
;
417 if (handle
== NULL
) {
418 handle
= dlopen("libpthread.so.0", flags
);
419 if (handle
!= NULL
) {
426 if (handle
== NULL
) {
428 handle
= uwrap
.libc
.handle
= RTLD_NEXT
;
431 "Failed to dlopen library: %s\n",
440 static void *_uwrap_bind_symbol(enum uwrap_lib lib
, const char *fn_name
)
445 handle
= uwrap_load_lib_handle(lib
);
447 func
= dlsym(handle
, fn_name
);
450 "Failed to find %s: %s\n",
458 #define uwrap_bind_symbol_libc(sym_name) \
459 UWRAP_LOCK(libc_symbol_binding); \
460 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
461 uwrap.libc.symbols._libc_##sym_name.obj = \
462 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
464 UWRAP_UNLOCK(libc_symbol_binding)
466 #define uwrap_bind_symbol_libpthread(sym_name) \
467 UWRAP_LOCK(libpthread_symbol_binding); \
468 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
469 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
470 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
472 UWRAP_UNLOCK(libpthread_symbol_binding)
477 * Functions expeciall from libc need to be loaded individually, you can't load
478 * all at once or gdb will segfault at startup. The same applies to valgrind and
479 * has probably something todo with with the linker.
480 * So we need load each function at the point it is called the first time.
482 static int libc_setuid(uid_t uid
)
484 uwrap_bind_symbol_libc(setuid
);
486 return uwrap
.libc
.symbols
._libc_setuid
.f(uid
);
489 static uid_t
libc_getuid(void)
491 uwrap_bind_symbol_libc(getuid
);
493 return uwrap
.libc
.symbols
._libc_getuid
.f();
497 static int libc_seteuid(uid_t euid
)
499 uwrap_bind_symbol_libc(seteuid
);
501 return uwrap
.libc
.symbols
._libc_seteuid
.f(euid
);
506 static int libc_setreuid(uid_t ruid
, uid_t euid
)
508 uwrap_bind_symbol_libc(setreuid
);
510 return uwrap
.libc
.symbols
._libc_setreuid
.f(ruid
, euid
);
514 #ifdef HAVE_SETRESUID
515 static int libc_setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
517 uwrap_bind_symbol_libc(setresuid
);
519 return uwrap
.libc
.symbols
._libc_setresuid
.f(ruid
, euid
, suid
);
523 #ifdef HAVE_GETRESUID
524 static int libc_getresuid(uid_t
*ruid
, uid_t
*euid
, uid_t
*suid
)
526 uwrap_bind_symbol_libc(getresuid
);
528 return uwrap
.libc
.symbols
._libc_getresuid
.f(ruid
, euid
, suid
);
532 static uid_t
libc_geteuid(void)
534 uwrap_bind_symbol_libc(geteuid
);
536 return uwrap
.libc
.symbols
._libc_geteuid
.f();
539 static int libc_setgid(gid_t gid
)
541 uwrap_bind_symbol_libc(setgid
);
543 return uwrap
.libc
.symbols
._libc_setgid
.f(gid
);
546 static gid_t
libc_getgid(void)
548 uwrap_bind_symbol_libc(getgid
);
550 return uwrap
.libc
.symbols
._libc_getgid
.f();
554 static int libc_setegid(gid_t egid
)
556 uwrap_bind_symbol_libc(setegid
);
558 return uwrap
.libc
.symbols
._libc_setegid
.f(egid
);
563 static int libc_setregid(gid_t rgid
, gid_t egid
)
565 uwrap_bind_symbol_libc(setregid
);
567 return uwrap
.libc
.symbols
._libc_setregid
.f(rgid
, egid
);
571 #ifdef HAVE_SETRESGID
572 static int libc_setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
574 uwrap_bind_symbol_libc(setresgid
);
576 return uwrap
.libc
.symbols
._libc_setresgid
.f(rgid
, egid
, sgid
);
580 #ifdef HAVE_GETRESGID
581 static int libc_getresgid(gid_t
*rgid
, gid_t
*egid
, gid_t
*sgid
)
583 uwrap_bind_symbol_libc(setresgid
);
585 return uwrap
.libc
.symbols
._libc_getresgid
.f(rgid
, egid
, sgid
);
589 static gid_t
libc_getegid(void)
591 uwrap_bind_symbol_libc(getegid
);
593 return uwrap
.libc
.symbols
._libc_getegid
.f();
596 static int libc_getgroups(int size
, gid_t list
[])
598 uwrap_bind_symbol_libc(getgroups
);
600 return uwrap
.libc
.symbols
._libc_getgroups
.f(size
, list
);
603 static int libc_setgroups(size_t size
, const gid_t
*list
)
605 uwrap_bind_symbol_libc(setgroups
);
607 return uwrap
.libc
.symbols
._libc_setgroups
.f(size
, list
);
611 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
612 static long int libc_vsyscall(long int sysno
, va_list va
)
618 uwrap_bind_symbol_libc(syscall
);
620 for (i
= 0; i
< 8; i
++) {
621 args
[i
] = va_arg(va
, long int);
624 rc
= uwrap
.libc
.symbols
._libc_syscall
.f(sysno
,
639 * This part is "optimistic".
640 * Thread can ends without pthread_exit call.
642 static void libpthread_pthread_exit(void *retval
)
644 uwrap_bind_symbol_libpthread(pthread_exit
);
646 uwrap
.libpthread
.symbols
._libpthread_pthread_exit
.f(retval
);
649 static void uwrap_pthread_exit(void *retval
)
651 struct uwrap_thread
*id
= uwrap_tls_id
;
653 UWRAP_LOG(UWRAP_LOG_DEBUG
, "Cleanup thread");
655 UWRAP_LOCK(uwrap_id
);
657 UWRAP_UNLOCK(uwrap_id
);
658 libpthread_pthread_exit(retval
);
662 UWRAP_DLIST_REMOVE(uwrap
.ids
, id
);
663 SAFE_FREE(id
->groups
);
667 UWRAP_UNLOCK(uwrap_id
);
669 libpthread_pthread_exit(retval
);
672 void pthread_exit(void *retval
)
674 if (!uid_wrapper_enabled()) {
675 libpthread_pthread_exit(retval
);
678 uwrap_pthread_exit(retval
);
680 /* Calm down gcc warning. */
684 static int libpthread_pthread_create(pthread_t
*thread
,
685 const pthread_attr_t
*attr
,
686 void *(*start_routine
) (void *),
689 uwrap_bind_symbol_libpthread(pthread_create
);
690 return uwrap
.libpthread
.symbols
._libpthread_pthread_create
.f(thread
,
696 struct uwrap_pthread_create_args
{
697 struct uwrap_thread
*id
;
698 void *(*start_routine
) (void *);
702 static void *uwrap_pthread_create_start(void *_a
)
704 struct uwrap_pthread_create_args
*a
=
705 (struct uwrap_pthread_create_args
*)_a
;
706 void *(*start_routine
) (void *) = a
->start_routine
;
708 struct uwrap_thread
*id
= a
->id
;
714 return start_routine(arg
);
717 static int uwrap_pthread_create(pthread_t
*thread
,
718 const pthread_attr_t
*attr
,
719 void *(*start_routine
) (void *),
722 struct uwrap_pthread_create_args
*args
;
723 struct uwrap_thread
*src_id
= uwrap_tls_id
;
726 args
= malloc(sizeof(struct uwrap_pthread_create_args
));
728 UWRAP_LOG(UWRAP_LOG_ERROR
,
729 "uwrap_pthread_create: Unable to allocate memory");
733 args
->start_routine
= start_routine
;
736 args
->id
= calloc(1, sizeof(struct uwrap_thread
));
737 if (args
->id
== NULL
) {
739 UWRAP_LOG(UWRAP_LOG_ERROR
,
740 "uwrap_pthread_create: Unable to allocate memory");
745 UWRAP_LOCK(uwrap_id
);
747 args
->id
->groups
= malloc(sizeof(gid_t
) * src_id
->ngroups
);
748 if (args
->id
->groups
== NULL
) {
749 UWRAP_UNLOCK(uwrap_id
);
752 UWRAP_LOG(UWRAP_LOG_ERROR
,
753 "uwrap_pthread_create: Unable to allocate memory again");
758 args
->id
->ruid
= src_id
->ruid
;
759 args
->id
->euid
= src_id
->euid
;
760 args
->id
->suid
= src_id
->suid
;
762 args
->id
->rgid
= src_id
->rgid
;
763 args
->id
->egid
= src_id
->egid
;
764 args
->id
->sgid
= src_id
->sgid
;
766 args
->id
->enabled
= src_id
->enabled
;
768 args
->id
->ngroups
= src_id
->ngroups
;
769 if (src_id
->groups
!= NULL
) {
770 memcpy(args
->id
->groups
, src_id
->groups
,
771 sizeof(gid_t
) * src_id
->ngroups
);
773 SAFE_FREE(args
->id
->groups
);
776 UWRAP_DLIST_ADD(uwrap
.ids
, args
->id
);
777 UWRAP_UNLOCK(uwrap_id
);
779 ret
= libpthread_pthread_create(thread
, attr
,
780 uwrap_pthread_create_start
,
789 int pthread_create(pthread_t
*thread
,
790 const pthread_attr_t
*attr
,
791 void *(*start_routine
) (void *),
794 if (!uid_wrapper_enabled()) {
795 return libpthread_pthread_create(thread
,
801 return uwrap_pthread_create(thread
,
807 /*********************************************************
809 *********************************************************/
811 static void uwrap_thread_prepare(void)
813 struct uwrap_thread
*id
= uwrap_tls_id
;
815 /* uid_wrapper is loaded but not enabled */
823 * What happens if another atfork prepare functions calls a uwrap
824 * function? So disable it in case another atfork prepare function
825 * calls a (s)uid function. We disable uid_wrapper only for thread
826 * (process) which called fork.
831 static void uwrap_thread_parent(void)
833 struct uwrap_thread
*id
= uwrap_tls_id
;
835 /* uid_wrapper is loaded but not enabled */
845 static void uwrap_thread_child(void)
847 struct uwrap_thread
*id
= uwrap_tls_id
;
848 struct uwrap_thread
*u
= uwrap
.ids
;
850 /* uid_wrapper is loaded but not enabled */
856 * "Garbage collector" - Inspired by DESTRUCTOR.
857 * All threads (except one which called fork()) are dead now.. Dave
858 * That's what posix said...
862 /* Skip this item. */
867 UWRAP_DLIST_REMOVE(uwrap
.ids
, u
);
869 SAFE_FREE(u
->groups
);
880 static void uwrap_init(void)
884 UWRAP_LOCK(uwrap_id
);
886 if (uwrap
.initialised
) {
887 struct uwrap_thread
*id
= uwrap_tls_id
;
889 if (uwrap
.ids
== NULL
) {
890 UWRAP_UNLOCK(uwrap_id
);
895 UWRAP_LOG(UWRAP_LOG_ERROR
,
896 "Invalid id for thread");
900 UWRAP_UNLOCK(uwrap_id
);
904 UWRAP_LOG(UWRAP_LOG_DEBUG
, "Initialize uid_wrapper");
906 uwrap
.initialised
= true;
908 env
= getenv("UID_WRAPPER");
909 if (env
!= NULL
&& env
[0] == '1') {
910 const char *root
= getenv("UID_WRAPPER_ROOT");
911 struct uwrap_thread
*id
;
913 id
= calloc(1, sizeof(struct uwrap_thread
));
915 UWRAP_LOG(UWRAP_LOG_ERROR
,
916 "Unable to allocate memory for main id");
920 UWRAP_DLIST_ADD(uwrap
.ids
, id
);
923 uwrap
.myuid
= libc_geteuid();
924 uwrap
.mygid
= libc_getegid();
926 /* put us in one group */
927 if (root
!= NULL
&& root
[0] == '1') {
928 id
->ruid
= id
->euid
= id
->suid
= 0;
929 id
->rgid
= id
->egid
= id
->sgid
= 0;
931 id
->groups
= malloc(sizeof(gid_t
) * 1);
932 if (id
->groups
== NULL
) {
933 UWRAP_LOG(UWRAP_LOG_ERROR
,
934 "Unable to allocate memory");
942 id
->ruid
= id
->euid
= id
->suid
= uwrap
.myuid
;
943 id
->rgid
= id
->egid
= id
->sgid
= uwrap
.mygid
;
945 id
->ngroups
= libc_getgroups(0, NULL
);
946 if (id
->ngroups
== -1) {
947 UWRAP_LOG(UWRAP_LOG_ERROR
,
948 "Unable to call libc_getgroups in uwrap_init.");
951 id
->groups
= malloc(sizeof(gid_t
) * id
->ngroups
);
952 if (id
->groups
== NULL
) {
953 UWRAP_LOG(UWRAP_LOG_ERROR
, "Unable to allocate memory");
956 if (libc_getgroups(id
->ngroups
, id
->groups
) == -1) {
957 UWRAP_LOG(UWRAP_LOG_ERROR
,
958 "Unable to call libc_getgroups again in uwrap_init.");
961 * Deallocation of uwrap.groups is handled by
962 * library destructor.
970 UWRAP_LOG(UWRAP_LOG_DEBUG
,
971 "Enabled uid_wrapper as %s (real uid=%u)",
972 id
->ruid
== 0 ? "root" : "user",
973 (unsigned int)uwrap
.myuid
);
976 UWRAP_UNLOCK(uwrap_id
);
978 UWRAP_LOG(UWRAP_LOG_DEBUG
, "Succeccfully initialized uid_wrapper");
981 bool uid_wrapper_enabled(void)
983 struct uwrap_thread
*id
= uwrap_tls_id
;
990 UWRAP_LOCK(uwrap_id
);
991 enabled
= id
->enabled
;
992 UWRAP_UNLOCK(uwrap_id
);
998 * UWRAP_SETxUID FUNCTIONS
1001 static int uwrap_setresuid_args(uid_t ruid
, uid_t euid
, uid_t suid
)
1003 struct uwrap_thread
*id
= uwrap_tls_id
;
1005 UWRAP_LOG(UWRAP_LOG_TRACE
,
1006 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1007 id
->ruid
, ruid
, id
->euid
, euid
, id
->suid
, suid
);
1009 if (id
->euid
!= 0) {
1010 if (ruid
!= (uid_t
)-1 &&
1017 if (euid
!= (uid_t
)-1 &&
1024 if (suid
!= (uid_t
)-1 &&
1036 static int uwrap_setresuid_thread(uid_t ruid
, uid_t euid
, uid_t suid
)
1038 struct uwrap_thread
*id
= uwrap_tls_id
;
1041 UWRAP_LOG(UWRAP_LOG_TRACE
,
1042 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1043 id
->ruid
, ruid
, id
->euid
, euid
, id
->suid
, suid
);
1045 rc
= uwrap_setresuid_args(ruid
, euid
, suid
);
1050 UWRAP_LOCK(uwrap_id
);
1052 if (ruid
!= (uid_t
)-1) {
1056 if (euid
!= (uid_t
)-1) {
1060 if (suid
!= (uid_t
)-1) {
1064 UWRAP_UNLOCK(uwrap_id
);
1069 static int uwrap_setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
1071 struct uwrap_thread
*id
= uwrap_tls_id
;
1074 UWRAP_LOG(UWRAP_LOG_TRACE
,
1075 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1076 id
->ruid
, ruid
, id
->euid
, euid
, id
->suid
, suid
);
1078 rc
= uwrap_setresuid_args(ruid
, euid
, suid
);
1083 UWRAP_LOCK(uwrap_id
);
1085 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1086 if (ruid
!= (uid_t
)-1) {
1090 if (euid
!= (uid_t
)-1) {
1094 if (suid
!= (uid_t
)-1) {
1099 UWRAP_UNLOCK(uwrap_id
);
1104 static int uwrap_setreuid_args(uid_t ruid
, uid_t euid
,
1109 struct uwrap_thread
*id
= uwrap_tls_id
;
1110 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1112 UWRAP_LOG(UWRAP_LOG_TRACE
,
1113 "ruid %d -> %d, euid %d -> %d",
1114 id
->ruid
, ruid
, id
->euid
, euid
);
1116 if (ruid
!= (uid_t
)-1) {
1118 if (ruid
!= id
->ruid
&&
1126 if (euid
!= (uid_t
)-1) {
1128 if (euid
!= id
->ruid
&&
1137 if (ruid
!= (uid_t
) -1 ||
1138 (euid
!= (uid_t
)-1 && id
->ruid
!= euid
)) {
1139 new_suid
= new_euid
;
1142 *_new_ruid
= new_ruid
;
1143 *_new_euid
= new_euid
;
1144 *_new_suid
= new_suid
;
1149 static int uwrap_setreuid_thread(uid_t ruid
, uid_t euid
)
1152 struct uwrap_thread
*id
= uwrap_tls_id
;
1154 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1157 UWRAP_LOG(UWRAP_LOG_TRACE
,
1158 "ruid %d -> %d, euid %d -> %d",
1159 id
->ruid
, ruid
, id
->euid
, euid
);
1161 rc
= uwrap_setreuid_args(ruid
, euid
, &new_ruid
, &new_euid
, &new_suid
);
1166 return uwrap_setresuid_thread(new_ruid
, new_euid
, new_suid
);
1169 #ifdef HAVE_SETREUID
1170 static int uwrap_setreuid(uid_t ruid
, uid_t euid
)
1173 struct uwrap_thread
*id
= uwrap_tls_id
;
1175 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1178 UWRAP_LOG(UWRAP_LOG_TRACE
,
1179 "ruid %d -> %d, euid %d -> %d",
1180 id
->ruid
, ruid
, id
->euid
, euid
);
1182 rc
= uwrap_setreuid_args(ruid
, euid
, &new_ruid
, &new_euid
, &new_suid
);
1187 return uwrap_setresuid(new_ruid
, new_euid
, new_suid
);
1191 static int uwrap_setuid_args(uid_t uid
,
1196 struct uwrap_thread
*id
= uwrap_tls_id
;
1198 UWRAP_LOG(UWRAP_LOG_TRACE
,
1202 if (uid
== (uid_t
)-1) {
1207 if (id
->euid
== 0) {
1208 *new_suid
= *new_ruid
= uid
;
1209 } else if (uid
!= id
->ruid
&&
1220 static int uwrap_setuid_thread(uid_t uid
)
1222 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1225 rc
= uwrap_setuid_args(uid
, &new_ruid
, &new_euid
, &new_suid
);
1230 return uwrap_setresuid_thread(new_ruid
, new_euid
, new_suid
);
1233 static int uwrap_setuid(uid_t uid
)
1235 uid_t new_ruid
= -1, new_euid
= -1, new_suid
= -1;
1238 rc
= uwrap_setuid_args(uid
, &new_ruid
, &new_euid
, &new_suid
);
1243 return uwrap_setresuid(new_ruid
, new_euid
, new_suid
);
1247 * UWRAP_GETxUID FUNCTIONS
1250 #ifdef HAVE_GETRESUID
1251 static int uwrap_getresuid(uid_t
*ruid
, uid_t
*euid
, uid_t
*suid
)
1253 struct uwrap_thread
*id
= uwrap_tls_id
;
1255 UWRAP_LOCK(uwrap_id
);
1261 UWRAP_UNLOCK(uwrap_id
);
1267 #ifdef HAVE_GETRESGID
1268 static int uwrap_getresgid(gid_t
*rgid
, gid_t
*egid
, gid_t
*sgid
)
1270 struct uwrap_thread
*id
= uwrap_tls_id
;
1272 UWRAP_LOCK(uwrap_id
);
1278 UWRAP_UNLOCK(uwrap_id
);
1285 * UWRAP_SETxGID FUNCTIONS
1288 static int uwrap_setresgid_args(gid_t rgid
, gid_t egid
, gid_t sgid
)
1290 struct uwrap_thread
*id
= uwrap_tls_id
;
1292 UWRAP_LOG(UWRAP_LOG_TRACE
,
1293 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1294 id
->rgid
, rgid
, id
->egid
, egid
, id
->sgid
, sgid
);
1296 if (id
->euid
!= 0) {
1297 if (rgid
!= (gid_t
)-1 &&
1304 if (egid
!= (gid_t
)-1 &&
1311 if (sgid
!= (gid_t
)-1 &&
1323 static int uwrap_setresgid_thread(gid_t rgid
, gid_t egid
, gid_t sgid
)
1325 struct uwrap_thread
*id
= uwrap_tls_id
;
1328 UWRAP_LOG(UWRAP_LOG_TRACE
,
1329 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1330 id
->rgid
, rgid
, id
->egid
, egid
, id
->sgid
, sgid
);
1332 rc
= uwrap_setresgid_args(rgid
, egid
, sgid
);
1337 UWRAP_LOCK(uwrap_id
);
1339 if (rgid
!= (gid_t
)-1) {
1343 if (egid
!= (gid_t
)-1) {
1347 if (sgid
!= (gid_t
)-1) {
1351 UWRAP_UNLOCK(uwrap_id
);
1356 static int uwrap_setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
1358 struct uwrap_thread
*id
= uwrap_tls_id
;
1361 UWRAP_LOG(UWRAP_LOG_TRACE
,
1362 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1363 id
->rgid
, rgid
, id
->egid
, egid
, id
->sgid
, sgid
);
1365 rc
= uwrap_setresgid_args(rgid
, egid
, sgid
);
1370 UWRAP_LOCK(uwrap_id
);
1372 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1373 if (rgid
!= (gid_t
)-1) {
1377 if (egid
!= (gid_t
)-1) {
1381 if (sgid
!= (gid_t
)-1) {
1386 UWRAP_UNLOCK(uwrap_id
);
1391 static int uwrap_setregid_args(gid_t rgid
, gid_t egid
,
1396 struct uwrap_thread
*id
= uwrap_tls_id
;
1397 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1399 UWRAP_LOG(UWRAP_LOG_TRACE
,
1400 "rgid %d -> %d, egid %d -> %d",
1401 id
->rgid
, rgid
, id
->egid
, egid
);
1403 if (rgid
!= (gid_t
)-1) {
1405 if (rgid
!= id
->rgid
&&
1413 if (egid
!= (gid_t
)-1) {
1415 if (egid
!= id
->rgid
&&
1424 if (rgid
!= (gid_t
) -1 ||
1425 (egid
!= (gid_t
)-1 && id
->rgid
!= egid
)) {
1426 new_sgid
= new_egid
;
1429 *_new_rgid
= new_rgid
;
1430 *_new_egid
= new_egid
;
1431 *_new_sgid
= new_sgid
;
1436 static int uwrap_setregid_thread(gid_t rgid
, gid_t egid
)
1439 struct uwrap_thread
*id
= uwrap_tls_id
;
1441 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1444 UWRAP_LOG(UWRAP_LOG_TRACE
,
1445 "rgid %d -> %d, egid %d -> %d",
1446 id
->rgid
, rgid
, id
->egid
, egid
);
1448 rc
= uwrap_setregid_args(rgid
, egid
, &new_rgid
, &new_egid
, &new_sgid
);
1453 return uwrap_setresgid_thread(new_rgid
, new_egid
, new_sgid
);
1456 #ifdef HAVE_SETREGID
1457 static int uwrap_setregid(gid_t rgid
, gid_t egid
)
1460 struct uwrap_thread
*id
= uwrap_tls_id
;
1462 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1465 UWRAP_LOG(UWRAP_LOG_TRACE
,
1466 "rgid %d -> %d, egid %d -> %d",
1467 id
->rgid
, rgid
, id
->egid
, egid
);
1469 rc
= uwrap_setregid_args(rgid
, egid
, &new_rgid
, &new_egid
, &new_sgid
);
1474 return uwrap_setresgid(new_rgid
, new_egid
, new_sgid
);
1478 static int uwrap_setgid_args(gid_t gid
,
1483 struct uwrap_thread
*id
= uwrap_tls_id
;
1485 UWRAP_LOG(UWRAP_LOG_TRACE
,
1489 if (gid
== (gid_t
)-1) {
1494 if (id
->euid
== 0) {
1495 *new_sgid
= *new_rgid
= gid
;
1496 } else if (gid
!= id
->rgid
&&
1507 static int uwrap_setgid_thread(gid_t gid
)
1509 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1512 rc
= uwrap_setgid_args(gid
, &new_rgid
, &new_egid
, &new_sgid
);
1517 return uwrap_setresgid_thread(new_rgid
, new_egid
, new_sgid
);
1520 static int uwrap_setgid(gid_t gid
)
1522 gid_t new_rgid
= -1, new_egid
= -1, new_sgid
= -1;
1525 rc
= uwrap_setgid_args(gid
, &new_rgid
, &new_egid
, &new_sgid
);
1530 return uwrap_setresgid(new_rgid
, new_egid
, new_sgid
);
1536 int setuid(uid_t uid
)
1538 if (!uid_wrapper_enabled()) {
1539 return libc_setuid(uid
);
1543 return uwrap_setuid(uid
);
1547 int seteuid(uid_t euid
)
1549 if (!uid_wrapper_enabled()) {
1550 return libc_seteuid(euid
);
1553 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1554 if (euid
== (uid_t
)-1) {
1560 return uwrap_setresuid(-1, euid
, -1);
1564 #ifdef HAVE_SETREUID
1565 int setreuid(uid_t ruid
, uid_t euid
)
1567 if (!uid_wrapper_enabled()) {
1568 return libc_setreuid(ruid
, euid
);
1572 return uwrap_setreuid(ruid
, euid
);
1576 #ifdef HAVE_SETRESUID
1577 int setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
1579 if (!uid_wrapper_enabled()) {
1580 return libc_setresuid(ruid
, euid
, suid
);
1584 return uwrap_setresuid(ruid
, euid
, suid
);
1588 #ifdef HAVE_GETRESUID
1589 int getresuid(uid_t
*ruid
, uid_t
*euid
, uid_t
*suid
)
1591 if (!uid_wrapper_enabled()) {
1592 return libc_getresuid(ruid
, euid
, suid
);
1596 return uwrap_getresuid(ruid
, euid
, suid
);
1603 static uid_t
uwrap_getuid(void)
1605 struct uwrap_thread
*id
= uwrap_tls_id
;
1608 UWRAP_LOCK(uwrap_id
);
1610 UWRAP_UNLOCK(uwrap_id
);
1617 if (!uid_wrapper_enabled()) {
1618 return libc_getuid();
1622 return uwrap_getuid();
1628 static uid_t
uwrap_geteuid(void)
1630 const char *env
= getenv("UID_WRAPPER_MYUID");
1631 struct uwrap_thread
*id
= uwrap_tls_id
;
1634 UWRAP_LOCK(uwrap_id
);
1636 UWRAP_UNLOCK(uwrap_id
);
1638 /* Disable root and return myuid */
1639 if (env
!= NULL
&& env
[0] == '1') {
1648 if (!uid_wrapper_enabled()) {
1649 return libc_geteuid();
1653 return uwrap_geteuid();
1659 int setgid(gid_t gid
)
1661 if (!uid_wrapper_enabled()) {
1662 return libc_setgid(gid
);
1666 return uwrap_setgid(gid
);
1670 int setegid(gid_t egid
)
1672 if (!uid_wrapper_enabled()) {
1673 return libc_setegid(egid
);
1676 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1677 if (egid
== (gid_t
)-1) {
1683 return uwrap_setresgid(-1, egid
, -1);
1687 #ifdef HAVE_SETREGID
1688 int setregid(gid_t rgid
, gid_t egid
)
1690 if (!uid_wrapper_enabled()) {
1691 return libc_setregid(rgid
, egid
);
1695 return uwrap_setregid(rgid
, egid
);
1699 #ifdef HAVE_SETRESGID
1700 int setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
1702 if (!uid_wrapper_enabled()) {
1703 return libc_setresgid(rgid
, egid
, sgid
);
1707 return uwrap_setresgid(rgid
, egid
, sgid
);
1711 #ifdef HAVE_GETRESGID
1712 int getresgid(gid_t
*rgid
, gid_t
*egid
, gid_t
*sgid
)
1714 if (!uid_wrapper_enabled()) {
1715 return libc_getresgid(rgid
, egid
, sgid
);
1719 return uwrap_getresgid(rgid
, egid
, sgid
);
1726 static gid_t
uwrap_getgid(void)
1728 struct uwrap_thread
*id
= uwrap_tls_id
;
1731 UWRAP_LOCK(uwrap_id
);
1733 UWRAP_UNLOCK(uwrap_id
);
1740 if (!uid_wrapper_enabled()) {
1741 return libc_getgid();
1745 return uwrap_getgid();
1751 static uid_t
uwrap_getegid(void)
1753 struct uwrap_thread
*id
= uwrap_tls_id
;
1756 UWRAP_LOCK(uwrap_id
);
1758 UWRAP_UNLOCK(uwrap_id
);
1765 if (!uid_wrapper_enabled()) {
1766 return libc_getegid();
1770 return uwrap_getegid();
1773 static int uwrap_setgroups_thread(size_t size
, const gid_t
*list
)
1775 struct uwrap_thread
*id
= uwrap_tls_id
;
1778 UWRAP_LOCK(uwrap_id
);
1781 SAFE_FREE(id
->groups
);
1783 } else if (size
> 0) {
1786 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
1793 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
1798 UWRAP_UNLOCK(uwrap_id
);
1803 static int uwrap_setgroups(size_t size
, const gid_t
*list
)
1805 struct uwrap_thread
*id
;
1808 UWRAP_LOCK(uwrap_id
);
1811 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1812 SAFE_FREE(id
->groups
);
1816 } else if (size
> 0) {
1819 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
1820 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
1828 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
1834 UWRAP_UNLOCK(uwrap_id
);
1839 #ifdef HAVE_SETGROUPS_INT
1840 int setgroups(int size
, const gid_t
*list
)
1842 int setgroups(size_t size
, const gid_t
*list
)
1845 if (!uid_wrapper_enabled()) {
1846 return libc_setgroups(size
, list
);
1850 return uwrap_setgroups(size
, list
);
1853 static int uwrap_getgroups(int size
, gid_t
*list
)
1855 struct uwrap_thread
*id
= uwrap_tls_id
;
1858 UWRAP_LOCK(uwrap_id
);
1859 ngroups
= id
->ngroups
;
1861 if (size
> ngroups
) {
1867 if (size
< ngroups
) {
1871 memcpy(list
, id
->groups
, size
* sizeof(gid_t
));
1874 UWRAP_UNLOCK(uwrap_id
);
1879 int getgroups(int size
, gid_t
*list
)
1881 if (!uid_wrapper_enabled()) {
1882 return libc_getgroups(size
, list
);
1886 return uwrap_getgroups(size
, list
);
1889 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1890 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1891 static long int uwrap_syscall (long int sysno
, va_list vp
)
1898 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1902 rc
= uwrap_getgid();
1907 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1911 rc
= uwrap_getegid();
1914 #endif /* SYS_getegid */
1916 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1920 gid_t gid
= (gid_t
) va_arg(vp
, gid_t
);
1922 rc
= uwrap_setgid_thread(gid
);
1926 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1927 case SYS_setregid32
:
1930 gid_t rgid
= (gid_t
) va_arg(vp
, gid_t
);
1931 gid_t egid
= (gid_t
) va_arg(vp
, gid_t
);
1933 rc
= uwrap_setregid_thread(rgid
, egid
);
1936 #ifdef SYS_setresgid
1938 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1939 case SYS_setresgid32
:
1942 gid_t rgid
= (gid_t
) va_arg(vp
, gid_t
);
1943 gid_t egid
= (gid_t
) va_arg(vp
, gid_t
);
1944 gid_t sgid
= (gid_t
) va_arg(vp
, gid_t
);
1946 rc
= uwrap_setresgid_thread(rgid
, egid
, sgid
);
1949 #endif /* SYS_setresgid */
1950 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
1952 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1953 case SYS_getresgid32
:
1956 gid_t
*rgid
= (gid_t
*) va_arg(vp
, gid_t
*);
1957 gid_t
*egid
= (gid_t
*) va_arg(vp
, gid_t
*);
1958 gid_t
*sgid
= (gid_t
*) va_arg(vp
, gid_t
*);
1960 rc
= uwrap_getresgid(rgid
, egid
, sgid
);
1963 #endif /* SYS_getresgid && HAVE_GETRESGID */
1967 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1971 rc
= uwrap_getuid();
1976 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1980 rc
= uwrap_geteuid();
1983 #endif /* SYS_geteuid */
1985 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1989 uid_t uid
= (uid_t
) va_arg(vp
, uid_t
);
1991 rc
= uwrap_setuid_thread(uid
);
1995 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1996 case SYS_setreuid32
:
1999 uid_t ruid
= (uid_t
) va_arg(vp
, uid_t
);
2000 uid_t euid
= (uid_t
) va_arg(vp
, uid_t
);
2002 rc
= uwrap_setreuid_thread(ruid
, euid
);
2005 #ifdef SYS_setresuid
2007 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2008 case SYS_setresuid32
:
2011 uid_t ruid
= (uid_t
) va_arg(vp
, uid_t
);
2012 uid_t euid
= (uid_t
) va_arg(vp
, uid_t
);
2013 uid_t suid
= (uid_t
) va_arg(vp
, uid_t
);
2015 rc
= uwrap_setresuid_thread(ruid
, euid
, suid
);
2018 #endif /* SYS_setresuid */
2019 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2021 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2022 case SYS_getresuid32
:
2025 uid_t
*ruid
= (uid_t
*) va_arg(vp
, uid_t
*);
2026 uid_t
*euid
= (uid_t
*) va_arg(vp
, uid_t
*);
2027 uid_t
*suid
= (uid_t
*) va_arg(vp
, uid_t
*);
2029 rc
= uwrap_getresuid(ruid
, euid
, suid
);
2032 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2035 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2036 case SYS_setgroups32
:
2039 size_t size
= (size_t) va_arg(vp
, size_t);
2040 gid_t
*list
= (gid_t
*) va_arg(vp
, int *);
2042 rc
= uwrap_setgroups_thread(size
, list
);
2046 UWRAP_LOG(UWRAP_LOG_DEBUG
,
2047 "UID_WRAPPER calling non-wrapped syscall %lu",
2050 rc
= libc_vsyscall(sysno
, vp
);
2058 #ifdef HAVE_SYSCALL_INT
2059 int syscall (int sysno
, ...)
2061 long int syscall (long int sysno
, ...)
2064 #ifdef HAVE_SYSCALL_INT
2071 va_start(va
, sysno
);
2073 if (!uid_wrapper_enabled()) {
2074 rc
= libc_vsyscall(sysno
, va
);
2080 rc
= uwrap_syscall(sysno
, va
);
2085 #endif /* HAVE_SYSCALL */
2086 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2088 /****************************
2090 ***************************/
2091 void uwrap_constructor(void)
2094 * If we hold a lock and the application forks, then the child
2095 * is not able to unlock the mutex and we are in a deadlock.
2096 * This should prevent such deadlocks.
2098 pthread_atfork(&uwrap_thread_prepare
,
2099 &uwrap_thread_parent
,
2100 &uwrap_thread_child
);
2102 /* Here is safe place to call uwrap_init() and initialize data
2108 /****************************
2110 ***************************/
2113 * This function is called when the library is unloaded and makes sure that
2114 * resources are freed.
2116 void uwrap_destructor(void)
2118 struct uwrap_thread
*u
= uwrap
.ids
;
2123 UWRAP_DLIST_REMOVE(uwrap
.ids
, u
);
2125 SAFE_FREE(u
->groups
);
2132 if (uwrap
.libc
.handle
!= NULL
) {
2133 dlclose(uwrap
.libc
.handle
);
2136 if (uwrap
.libpthread
.handle
!= NULL
) {
2137 dlclose(uwrap
.libpthread
.handle
);