uwrap: Fix wrong data types in syscalls switch.
[bbaumbach/samba-autobuild/.git] / lib / uid_wrapper / uid_wrapper.c
1 /*
2  * Copyright (c) 2009      Andrew Tridgell
3  * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
4  *
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.
9  *
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.
14  *
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/>.
17  */
18
19 #include "config.h"
20
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
38 #include <pthread.h>
39
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
42 #else
43 # define UWRAP_THREAD
44 #endif
45
46 # define UWRAP_LOCK(m) do { \
47         pthread_mutex_lock(&( m ## _mutex)); \
48 } while(0)
49
50 # define UWRAP_UNLOCK(m) do { \
51         pthread_mutex_unlock(&( m ## _mutex)); \
52 } while(0)
53
54 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
55 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
56 #else
57 #define CONSTRUCTOR_ATTRIBUTE
58 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
59
60 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
61 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
62 #else
63 #define DESTRUCTOR_ATTRIBUTE
64 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
65
66 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
67 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
68 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
69 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
70 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
71
72 /* GCC have printf type attribute check. */
73 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
74 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
75 #else
76 #define PRINTF_ATTRIBUTE(a,b)
77 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
78
79 #define UWRAP_DLIST_ADD(list,item) do { \
80         if (!(list)) { \
81                 (item)->prev    = NULL; \
82                 (item)->next    = NULL; \
83                 (list)          = (item); \
84         } else { \
85                 (item)->prev    = NULL; \
86                 (item)->next    = (list); \
87                 (list)->prev    = (item); \
88                 (list)          = (item); \
89         } \
90 } while (0)
91
92 #define UWRAP_DLIST_REMOVE(list,item) do { \
93         if ((list) == (item)) { \
94                 (list)          = (item)->next; \
95                 if (list) { \
96                         (list)->prev    = NULL; \
97                 } \
98         } else { \
99                 if ((item)->prev) { \
100                         (item)->prev->next      = (item)->next; \
101                 } \
102                 if ((item)->next) { \
103                         (item)->next->prev      = (item)->prev; \
104                 } \
105         } \
106         (item)->prev    = NULL; \
107         (item)->next    = NULL; \
108 } while (0)
109
110 #ifndef SAFE_FREE
111 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
112 #endif
113
114 /*****************
115  * LOGGING
116  *****************/
117
118 enum uwrap_dbglvl_e {
119         UWRAP_LOG_ERROR = 0,
120         UWRAP_LOG_WARN,
121         UWRAP_LOG_DEBUG,
122         UWRAP_LOG_TRACE
123 };
124
125 #ifdef NDEBUG
126 # define UWRAP_LOG(...)
127 #else /* NDEBUG */
128 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
129 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __VA_ARGS__)
130
131 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
132 {
133         char buffer[1024];
134         va_list va;
135         const char *d;
136         unsigned int lvl = 0;
137
138         d = getenv("UID_WRAPPER_DEBUGLEVEL");
139         if (d != NULL) {
140                 lvl = atoi(d);
141         }
142
143         va_start(va, format);
144         vsnprintf(buffer, sizeof(buffer), format, va);
145         va_end(va);
146
147         if (lvl >= dbglvl) {
148                 switch (dbglvl) {
149                         case UWRAP_LOG_ERROR:
150                                 fprintf(stderr,
151                                         "UWRAP_ERROR(%d): %s\n",
152                                         (int)getpid(), buffer);
153                                 break;
154                         case UWRAP_LOG_WARN:
155                                 fprintf(stderr,
156                                         "UWRAP_WARN(%d): %s\n",
157                                         (int)getpid(), buffer);
158                                 break;
159                         case UWRAP_LOG_DEBUG:
160                                 fprintf(stderr,
161                                         "UWRAP_DEBUG(%d): %s\n",
162                                         (int)getpid(), buffer);
163                                 break;
164                         case UWRAP_LOG_TRACE:
165                                 fprintf(stderr,
166                                         "UWRAP_TRACE(%d): %s\n",
167                                         (int)getpid(), buffer);
168                                 break;
169                 }
170         }
171 }
172 #endif /* NDEBUG */
173
174 /*****************
175  * LIBC
176  *****************/
177
178 #define LIBC_NAME "libc.so"
179
180 struct uwrap_libc_fns {
181         int (*_libc_setuid)(uid_t uid);
182         uid_t (*_libc_getuid)(void);
183
184 #ifdef HAVE_SETEUID
185         int (*_libc_seteuid)(uid_t euid);
186 #endif
187 #ifdef HAVE_SETREUID
188         int (*_libc_setreuid)(uid_t ruid, uid_t euid);
189 #endif
190 #ifdef HAVE_SETRESUID
191         int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
192 #endif
193 #ifdef HAVE_GETRESUID
194         int (*_libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
195 #endif
196         uid_t (*_libc_geteuid)(void);
197
198         int (*_libc_setgid)(gid_t gid);
199         gid_t (*_libc_getgid)(void);
200 #ifdef HAVE_SETEGID
201         int (*_libc_setegid)(uid_t egid);
202 #endif
203 #ifdef HAVE_SETREGID
204         int (*_libc_setregid)(uid_t rgid, uid_t egid);
205 #endif
206 #ifdef HAVE_SETRESGID
207         int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
208 #endif
209 #ifdef HAVE_GETRESGID
210         int (*_libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
211 #endif
212         gid_t (*_libc_getegid)(void);
213         int (*_libc_getgroups)(int size, gid_t list[]);
214         int (*_libc_setgroups)(size_t size, const gid_t *list);
215 #ifdef HAVE_SYSCALL
216         long int (*_libc_syscall)(long int sysno, ...);
217 #endif
218 };
219
220 /*
221  * We keep the virtualised euid/egid/groups information here
222  */
223 struct uwrap_thread {
224         pthread_t tid;
225         bool dead;
226
227         uid_t ruid;
228         uid_t euid;
229         uid_t suid;
230
231         gid_t rgid;
232         gid_t egid;
233         gid_t sgid;
234
235         int ngroups;
236         gid_t *groups;
237
238         struct uwrap_thread *next;
239         struct uwrap_thread *prev;
240 };
241
242 struct uwrap {
243         pthread_t tid;
244
245         struct {
246                 void *handle;
247                 struct uwrap_libc_fns fns;
248         } libc;
249
250         bool initialised;
251         bool enabled;
252
253         uid_t ruid;
254         uid_t euid;
255         uid_t suid;
256
257         gid_t rgid;
258         gid_t egid;
259         gid_t sgid;
260
261         int ngroups;
262         gid_t *groups;
263
264         /* Real uid and gid of user who run uid wrapper */
265         uid_t myuid;
266         gid_t mygid;
267
268         struct uwrap_thread *ids;
269 };
270
271 static struct uwrap uwrap;
272
273 /* Shortcut to the list item */
274 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
275
276 /* The mutex or accessing the id */
277 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
278
279 /* The mutex for accessing the global libc.fns */
280 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
281
282 /*********************************************************
283  * UWRAP PROTOTYPES
284  *********************************************************/
285
286 bool uid_wrapper_enabled(void);
287 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
288 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
289
290 /*********************************************************
291  * UWRAP LIBC LOADER FUNCTIONS
292  *********************************************************/
293
294 enum uwrap_lib {
295     UWRAP_LIBC,
296     UWRAP_LIBNSL,
297     UWRAP_LIBSOCKET,
298 };
299
300 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
301 {
302         int flags = RTLD_LAZY;
303         void *handle = NULL;
304         int i;
305
306 #ifdef RTLD_DEEPBIND
307         flags |= RTLD_DEEPBIND;
308 #endif
309
310         switch (lib) {
311         case UWRAP_LIBNSL:
312                 /* FALL TROUGH */
313         case UWRAP_LIBSOCKET:
314                 /* FALL TROUGH */
315         case UWRAP_LIBC:
316                 handle = uwrap.libc.handle;
317                 if (handle == NULL) {
318                         for (i = 10; i >= 0; i--) {
319                                 char soname[256] = {0};
320
321                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
322                                 handle = dlopen(soname, flags);
323                                 if (handle != NULL) {
324                                         break;
325                                 }
326                         }
327
328                         uwrap.libc.handle = handle;
329                 }
330                 break;
331         }
332
333         if (handle == NULL) {
334 #ifdef RTLD_NEXT
335                 handle = uwrap.libc.handle = RTLD_NEXT;
336 #else
337                 fprintf(stderr,
338                         "Failed to dlopen library: %s\n",
339                         dlerror());
340                 exit(-1);
341 #endif
342         }
343
344         return handle;
345 }
346
347 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
348 {
349         void *handle;
350         void *func;
351
352         handle = uwrap_load_lib_handle(lib);
353
354         func = dlsym(handle, fn_name);
355         if (func == NULL) {
356                 fprintf(stderr,
357                         "Failed to find %s: %s\n",
358                         fn_name, dlerror());
359                 exit(-1);
360         }
361
362         return func;
363 }
364
365 #define uwrap_load_lib_function(lib, fn_name) \
366         UWRAP_LOCK(libc_symbol_binding); \
367         if (uwrap.libc.fns._libc_##fn_name == NULL) { \
368                 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
369                         _uwrap_load_lib_function(lib, #fn_name); \
370         } \
371         UWRAP_UNLOCK(libc_symbol_binding)
372
373 /*
374  * IMPORTANT
375  *
376  * Functions expeciall from libc need to be loaded individually, you can't load
377  * all at once or gdb will segfault at startup. The same applies to valgrind and
378  * has probably something todo with with the linker.
379  * So we need load each function at the point it is called the first time.
380  */
381 static int libc_setuid(uid_t uid)
382 {
383         uwrap_load_lib_function(UWRAP_LIBC, setuid);
384
385         return uwrap.libc.fns._libc_setuid(uid);
386 }
387
388 static uid_t libc_getuid(void)
389 {
390         uwrap_load_lib_function(UWRAP_LIBC, getuid);
391
392         return uwrap.libc.fns._libc_getuid();
393 }
394
395 #ifdef HAVE_SETEUID
396 static int libc_seteuid(uid_t euid)
397 {
398         uwrap_load_lib_function(UWRAP_LIBC, seteuid);
399
400         return uwrap.libc.fns._libc_seteuid(euid);
401 }
402 #endif
403
404 #ifdef HAVE_SETREUID
405 static int libc_setreuid(uid_t ruid, uid_t euid)
406 {
407         uwrap_load_lib_function(UWRAP_LIBC, setreuid);
408
409         return uwrap.libc.fns._libc_setreuid(ruid, euid);
410 }
411 #endif
412
413 #ifdef HAVE_SETRESUID
414 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
415 {
416         uwrap_load_lib_function(UWRAP_LIBC, setresuid);
417
418         return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
419 }
420 #endif
421
422 #ifdef HAVE_GETRESUID
423 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
424 {
425         uwrap_load_lib_function(UWRAP_LIBC, getresuid);
426
427         return uwrap.libc.fns._libc_getresuid(ruid, euid, suid);
428 }
429 #endif
430
431 static uid_t libc_geteuid(void)
432 {
433         uwrap_load_lib_function(UWRAP_LIBC, geteuid);
434
435         return uwrap.libc.fns._libc_geteuid();
436 }
437
438 static int libc_setgid(gid_t gid)
439 {
440         uwrap_load_lib_function(UWRAP_LIBC, setgid);
441
442         return uwrap.libc.fns._libc_setgid(gid);
443 }
444
445 static gid_t libc_getgid(void)
446 {
447         uwrap_load_lib_function(UWRAP_LIBC, getgid);
448
449         return uwrap.libc.fns._libc_getgid();
450 }
451
452 #ifdef HAVE_SETEGID
453 static int libc_setegid(gid_t egid)
454 {
455         uwrap_load_lib_function(UWRAP_LIBC, setegid);
456
457         return uwrap.libc.fns._libc_setegid(egid);
458 }
459 #endif
460
461 #ifdef HAVE_SETREGID
462 static int libc_setregid(gid_t rgid, gid_t egid)
463 {
464         uwrap_load_lib_function(UWRAP_LIBC, setregid);
465
466         return uwrap.libc.fns._libc_setregid(rgid, egid);
467 }
468 #endif
469
470 #ifdef HAVE_SETRESGID
471 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
472 {
473         uwrap_load_lib_function(UWRAP_LIBC, setresgid);
474
475         return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
476 }
477 #endif
478
479 #ifdef HAVE_GETRESGID
480 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
481 {
482         uwrap_load_lib_function(UWRAP_LIBC, setresgid);
483
484         return uwrap.libc.fns._libc_getresgid(rgid, egid, sgid);
485 }
486 #endif
487
488 static gid_t libc_getegid(void)
489 {
490         uwrap_load_lib_function(UWRAP_LIBC, getegid);
491
492         return uwrap.libc.fns._libc_getegid();
493 }
494
495 static int libc_getgroups(int size, gid_t list[])
496 {
497         uwrap_load_lib_function(UWRAP_LIBC, getgroups);
498
499         return uwrap.libc.fns._libc_getgroups(size, list);
500 }
501
502 static int libc_setgroups(size_t size, const gid_t *list)
503 {
504         uwrap_load_lib_function(UWRAP_LIBC, setgroups);
505
506         return uwrap.libc.fns._libc_setgroups(size, list);
507 }
508
509 #ifdef HAVE_SYSCALL
510 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
511 static long int libc_vsyscall(long int sysno, va_list va)
512 {
513         long int args[8];
514         long int rc;
515         int i;
516
517         uwrap_load_lib_function(UWRAP_LIBC, syscall);
518
519         for (i = 0; i < 8; i++) {
520                 args[i] = va_arg(va, long int);
521         }
522
523         rc = uwrap.libc.fns._libc_syscall(sysno,
524                                           args[0],
525                                           args[1],
526                                           args[2],
527                                           args[3],
528                                           args[4],
529                                           args[5],
530                                           args[6],
531                                           args[7]);
532
533         return rc;
534 }
535 #endif
536
537 /*********************************************************
538  * UWRAP ID HANDLING
539  *********************************************************/
540
541 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
542 {
543         struct uwrap_thread *id;
544
545         for (id = uwrap.ids; id; id = id->next) {
546                 if (pthread_equal(id->tid, tid)) {
547                         return id;
548                 }
549         }
550
551         return NULL;
552 }
553
554 static int uwrap_new_id(pthread_t tid, bool do_alloc)
555 {
556         struct uwrap_thread *id = uwrap_tls_id;
557
558         if (do_alloc) {
559                 id = malloc(sizeof(struct uwrap_thread));
560                 if (id == NULL) {
561                         UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
562                         errno = ENOMEM;
563                         return -1;
564                 }
565
566                 id->groups = malloc(sizeof(gid_t) * uwrap.ngroups);
567                 if (id->groups == NULL) {
568                         UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
569                         SAFE_FREE(id);
570                         errno = ENOMEM;
571                         return -1;
572                 }
573
574                 UWRAP_DLIST_ADD(uwrap.ids, id);
575                 uwrap_tls_id = id;
576         }
577
578         id->tid = tid;
579         id->dead = false;
580
581         id->ruid = uwrap.ruid;
582         id->euid = uwrap.euid;
583         id->suid = uwrap.suid;
584
585         id->rgid = uwrap.rgid;
586         id->egid = uwrap.egid;
587         id->sgid = uwrap.sgid;
588
589         id->ngroups = uwrap.ngroups;
590         if (uwrap.groups != NULL) {
591                 memcpy(id->groups, uwrap.groups, sizeof(gid_t) * uwrap.ngroups);
592         } else {
593                 id->groups = NULL;
594         }
595
596         return 0;
597 }
598
599 static void uwrap_thread_prepare(void)
600 {
601         UWRAP_LOCK(uwrap_id);
602         UWRAP_LOCK(libc_symbol_binding);
603         /*
604          * What happens if another atfork prepare functions calls a uwrap
605          * function? So disable it in case another atfork prepare function
606          * calls a (s)uid function.
607          */
608         uwrap.enabled = false;
609 }
610
611 static void uwrap_thread_parent(void)
612 {
613         uwrap.enabled = true;
614
615         UWRAP_UNLOCK(libc_symbol_binding);
616         UWRAP_UNLOCK(uwrap_id);
617 }
618
619 static void uwrap_thread_child(void)
620 {
621         uwrap.enabled = true;
622
623         /* We need to update to the new tid if we fork */
624         uwrap.tid = pthread_self();
625
626         UWRAP_UNLOCK(libc_symbol_binding);
627         UWRAP_UNLOCK(uwrap_id);
628 }
629
630 static void uwrap_init(void)
631 {
632         const char *env;
633         pthread_t tid = pthread_self();
634
635         UWRAP_LOCK(uwrap_id);
636         if (uwrap.initialised) {
637                 struct uwrap_thread *id = uwrap_tls_id;
638                 int rc;
639
640                 if (id != NULL) {
641                         UWRAP_UNLOCK(uwrap_id);
642                         return;
643                 }
644
645                 id = find_uwrap_id(tid);
646                 if (id == NULL) {
647                         rc = uwrap_new_id(tid, true);
648                         if (rc < 0) {
649                                 exit(-1);
650                         }
651                 } else {
652                         /* We reuse an old thread id */
653                         uwrap_tls_id = id;
654
655                         uwrap_new_id(tid, false);
656                 }
657                 UWRAP_UNLOCK(uwrap_id);
658
659                 return;
660         }
661
662         UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
663
664         uwrap.initialised = true;
665         uwrap.enabled = false;
666
667         env = getenv("UID_WRAPPER");
668         if (env != NULL && env[0] == '1') {
669                 const char *root = getenv("UID_WRAPPER_ROOT");
670                 int rc;
671
672                 uwrap.myuid = libc_geteuid();
673                 uwrap.mygid = libc_getegid();
674                 /* put us in one group */
675                 if (root != NULL && root[0] == '1') {
676                         uwrap.ruid = uwrap.euid = uwrap.suid = 0;
677                         uwrap.rgid = uwrap.egid = uwrap.sgid = 0;
678
679                         uwrap.groups = malloc(sizeof(gid_t) * 1);
680                         if (uwrap.groups == NULL) {
681                                 UWRAP_LOG(UWRAP_LOG_ERROR,
682                                           "Unable to allocate memory");
683                                 exit(-1);
684                         }
685
686                         uwrap.ngroups = 1;
687                         uwrap.groups[0] = 0;
688
689                 } else {
690                         uwrap.ruid = uwrap.euid = uwrap.suid = uwrap.myuid;
691                         uwrap.rgid = uwrap.egid = uwrap.sgid = uwrap.mygid;
692
693                         uwrap.ngroups = libc_getgroups(0, NULL);
694                         if (uwrap.ngroups == -1) {
695                                 UWRAP_LOG(UWRAP_LOG_ERROR,
696                                           "Unable to call libc_getgroups in uwrap_init.");
697                                 exit(-1);
698                         }
699                         uwrap.groups = malloc(sizeof(gid_t) * uwrap.ngroups);
700                         if (uwrap.groups == NULL) {
701                                 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
702                                 exit(-1);
703                         }
704                         if (libc_getgroups(uwrap.ngroups, uwrap.groups) == -1) {
705                                 UWRAP_LOG(UWRAP_LOG_ERROR,
706                                           "Unable to call libc_getgroups again in uwrap_init.");
707                                 uwrap.ngroups = 0;
708                                 /*
709                                  * Deallocation of uwrap.groups is handled by
710                                  * library destructor.
711                                  */
712                                 exit(-1);
713                         }
714                 }
715
716                 rc = uwrap_new_id(tid, true);
717                 if (rc < 0) {
718                         exit(-1);
719                 }
720
721                 uwrap.tid = tid;
722                 uwrap.enabled = true;
723
724                 UWRAP_LOG(UWRAP_LOG_DEBUG,
725                           "Enabled uid_wrapper as %s",
726                           uwrap.myuid == 0 ? "root" : "user");
727         }
728
729         UWRAP_UNLOCK(uwrap_id);
730
731         UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
732 }
733
734 bool uid_wrapper_enabled(void)
735 {
736         bool enabled = false;
737         #ifdef HAVE_GCC_ATOMIC_BUILTINS
738                 __atomic_load(&uwrap.enabled, &enabled, __ATOMIC_RELAXED);
739         #else
740                 UWRAP_LOCK(uwrap_id);
741                 enabled = uwrap.enabled;
742                 UWRAP_UNLOCK(uwrap_id);
743         #endif
744         return enabled;
745 }
746
747 #ifdef HAVE_GETRESUID
748 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
749 {
750         struct uwrap_thread *id = uwrap_tls_id;
751
752         UWRAP_LOCK(uwrap_id);
753
754         *ruid = id->ruid;
755         *euid = id->euid;
756         *suid = id->suid;
757
758         UWRAP_UNLOCK(uwrap_id);
759
760         return 0;
761 }
762 #endif
763
764 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
765 {
766         struct uwrap_thread *id = uwrap_tls_id;
767
768         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
769                 errno = EINVAL;
770                 return -1;
771         }
772
773         UWRAP_LOCK(uwrap_id);
774         if (ruid != (uid_t)-1) {
775                 id->ruid = ruid;
776         }
777
778         if (euid != (uid_t)-1) {
779                 id->euid = euid;
780         }
781
782         if (suid != (uid_t)-1) {
783                 id->suid = suid;
784         }
785
786         /* Check If syscall is called from main thread. */
787         if (pthread_equal(id->tid, uwrap.tid)) {
788                 if (ruid != (uid_t)-1) {
789                     uwrap.ruid = ruid;
790                 }
791
792                 if (euid != (uid_t)-1) {
793                     uwrap.euid = euid;
794                 }
795
796                 if (suid != (uid_t)-1) {
797                     uwrap.suid = suid;
798                 }
799         }
800
801         UWRAP_UNLOCK(uwrap_id);
802
803         return 0;
804 }
805
806 #ifdef HAVE_GETRESGID
807 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
808 {
809         struct uwrap_thread *id = uwrap_tls_id;
810
811         UWRAP_LOCK(uwrap_id);
812
813         *rgid = id->rgid;
814         *egid = id->egid;
815         *sgid = id->sgid;
816
817         UWRAP_UNLOCK(uwrap_id);
818
819         return 0;
820 }
821 #endif
822
823 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
824 {
825         struct uwrap_thread *id;
826
827         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
828                 errno = EINVAL;
829                 return -1;
830         }
831
832         UWRAP_LOCK(uwrap_id);
833         for (id = uwrap.ids; id; id = id->next) {
834                 if (id->dead) {
835                         continue;
836                 }
837
838                 if (ruid != (uid_t)-1) {
839                         id->ruid = ruid;
840                 }
841
842                 if (euid != (uid_t)-1) {
843                         id->euid = euid;
844                 }
845
846                 if (suid != (uid_t)-1) {
847                         id->suid = suid;
848                 }
849         }
850
851         /* Reflect changes in thread to main process. */
852         if (ruid != (uid_t)-1) {
853                 uwrap.ruid = ruid;
854         }
855
856         if (euid != (uid_t)-1) {
857                 uwrap.euid = euid;
858         }
859
860         if (suid != (uid_t)-1) {
861                 uwrap.suid = suid;
862         }
863
864         UWRAP_UNLOCK(uwrap_id);
865
866         return 0;
867 }
868
869 /*
870  * SETUID
871  */
872 int setuid(uid_t uid)
873 {
874         if (!uid_wrapper_enabled()) {
875                 return libc_setuid(uid);
876         }
877
878         uwrap_init();
879         return uwrap_setresuid(uid, -1, -1);
880 }
881
882 #ifdef HAVE_SETEUID
883 int seteuid(uid_t euid)
884 {
885         if (euid == (uid_t)-1) {
886                 errno = EINVAL;
887                 return -1;
888         }
889
890         if (!uid_wrapper_enabled()) {
891                 return libc_seteuid(euid);
892         }
893
894         uwrap_init();
895         return uwrap_setresuid(-1, euid, -1);
896 }
897 #endif
898
899 #ifdef HAVE_SETREUID
900 int setreuid(uid_t ruid, uid_t euid)
901 {
902         if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
903                 errno = EINVAL;
904                 return -1;
905         }
906
907         if (!uid_wrapper_enabled()) {
908                 return libc_setreuid(ruid, euid);
909         }
910
911         uwrap_init();
912         return uwrap_setresuid(ruid, euid, -1);
913 }
914 #endif
915
916 #ifdef HAVE_SETRESUID
917 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
918 {
919         if (!uid_wrapper_enabled()) {
920                 return libc_setresuid(ruid, euid, suid);
921         }
922
923         uwrap_init();
924         return uwrap_setresuid(ruid, euid, suid);
925 }
926 #endif
927
928 #ifdef HAVE_GETRESUID
929 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
930 {
931         if (!uid_wrapper_enabled()) {
932                 return libc_getresuid(ruid, euid, suid);
933         }
934
935         uwrap_init();
936         return uwrap_getresuid(ruid, euid, suid);
937 }
938 #endif
939
940 /*
941  * GETUID
942  */
943 static uid_t uwrap_getuid(void)
944 {
945         struct uwrap_thread *id = uwrap_tls_id;
946         uid_t uid;
947
948         UWRAP_LOCK(uwrap_id);
949         uid = id->ruid;
950         UWRAP_UNLOCK(uwrap_id);
951
952         return uid;
953 }
954
955 uid_t getuid(void)
956 {
957         if (!uid_wrapper_enabled()) {
958                 return libc_getuid();
959         }
960
961         uwrap_init();
962         return uwrap_getuid();
963 }
964
965 /*
966  * GETEUID
967  */
968 static uid_t uwrap_geteuid(void)
969 {
970         const char *env = getenv("UID_WRAPPER_MYUID");
971         struct uwrap_thread *id = uwrap_tls_id;
972         uid_t uid;
973
974         UWRAP_LOCK(uwrap_id);
975         uid = id->euid;
976         UWRAP_UNLOCK(uwrap_id);
977
978         /* Disable root and return myuid */
979         if (env != NULL && env[0] == '1') {
980                 uid = uwrap.myuid;
981         }
982
983         return uid;
984 }
985
986 uid_t geteuid(void)
987 {
988         if (!uid_wrapper_enabled()) {
989                 return libc_geteuid();
990         }
991
992         uwrap_init();
993         return uwrap_geteuid();
994 }
995
996 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
997 {
998         struct uwrap_thread *id = uwrap_tls_id;
999
1000         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
1001                 errno = EINVAL;
1002                 return -1;
1003         }
1004
1005         UWRAP_LOCK(uwrap_id);
1006         if (rgid != (gid_t)-1) {
1007                 id->rgid = rgid;
1008         }
1009
1010         if (egid != (gid_t)-1) {
1011                 id->egid = egid;
1012         }
1013
1014         if (sgid != (gid_t)-1) {
1015                 id->sgid = sgid;
1016         }
1017
1018         if (pthread_equal(id->tid, uwrap.tid)) {
1019                 if (rgid != (gid_t)-1) {
1020                         uwrap.rgid = rgid;
1021                 }
1022
1023                 if (egid != (gid_t)-1) {
1024                         uwrap.egid = egid;
1025                 }
1026
1027                 if (sgid != (gid_t)-1) {
1028                         uwrap.sgid = sgid;
1029                 }
1030         }
1031         UWRAP_UNLOCK(uwrap_id);
1032
1033         return 0;
1034 }
1035
1036 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1037 {
1038         struct uwrap_thread *id;
1039
1040         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
1041                 errno = EINVAL;
1042                 return -1;
1043         }
1044
1045         UWRAP_LOCK(uwrap_id);
1046         for (id = uwrap.ids; id; id = id->next) {
1047                 if (id->dead) {
1048                         continue;
1049                 }
1050
1051                 if (rgid != (gid_t)-1) {
1052                         id->rgid = rgid;
1053                 }
1054
1055                 if (egid != (gid_t)-1) {
1056                         id->egid = egid;
1057                 }
1058
1059                 if (sgid != (gid_t)-1) {
1060                         id->sgid = sgid;
1061                 }
1062         }
1063
1064         /* Reflect changes in thread to main process. */
1065         if (rgid != (gid_t)-1) {
1066                 uwrap.rgid = rgid;
1067         }
1068
1069         if (egid != (gid_t)-1) {
1070                 uwrap.egid = egid;
1071         }
1072
1073         if (sgid != (gid_t)-1) {
1074                 uwrap.sgid = sgid;
1075         }
1076         UWRAP_UNLOCK(uwrap_id);
1077
1078         return 0;
1079 }
1080
1081 /*
1082  * SETGID
1083  */
1084 int setgid(gid_t gid)
1085 {
1086         if (!uid_wrapper_enabled()) {
1087                 return libc_setgid(gid);
1088         }
1089
1090         uwrap_init();
1091         return uwrap_setresgid(gid, -1, -1);
1092 }
1093
1094 #ifdef HAVE_SETEGID
1095 int setegid(gid_t egid)
1096 {
1097         if (!uid_wrapper_enabled()) {
1098                 return libc_setegid(egid);
1099         }
1100
1101         uwrap_init();
1102         return uwrap_setresgid(-1, egid, -1);
1103 }
1104 #endif
1105
1106 #ifdef HAVE_SETREGID
1107 int setregid(gid_t rgid, gid_t egid)
1108 {
1109         if (!uid_wrapper_enabled()) {
1110                 return libc_setregid(rgid, egid);
1111         }
1112
1113         uwrap_init();
1114         return uwrap_setresgid(rgid, egid, -1);
1115 }
1116 #endif
1117
1118 #ifdef HAVE_SETRESGID
1119 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1120 {
1121         if (!uid_wrapper_enabled()) {
1122                 return libc_setresgid(rgid, egid, sgid);
1123         }
1124
1125         uwrap_init();
1126         return uwrap_setresgid(rgid, egid, sgid);
1127 }
1128 #endif
1129
1130 #ifdef HAVE_GETRESGID
1131 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1132 {
1133         if (!uid_wrapper_enabled()) {
1134                 return libc_getresgid(rgid, egid, sgid);
1135         }
1136
1137         uwrap_init();
1138         return uwrap_getresgid(rgid, egid, sgid);
1139 }
1140 #endif
1141
1142 /*
1143  * GETGID
1144  */
1145 static gid_t uwrap_getgid(void)
1146 {
1147         struct uwrap_thread *id = uwrap_tls_id;
1148         gid_t gid;
1149
1150         UWRAP_LOCK(uwrap_id);
1151         gid = id->rgid;
1152         UWRAP_UNLOCK(uwrap_id);
1153
1154         return gid;
1155 }
1156
1157 gid_t getgid(void)
1158 {
1159         if (!uid_wrapper_enabled()) {
1160                 return libc_getgid();
1161         }
1162
1163         uwrap_init();
1164         return uwrap_getgid();
1165 }
1166
1167 /*
1168  * GETEGID
1169  */
1170 static uid_t uwrap_getegid(void)
1171 {
1172         struct uwrap_thread *id = uwrap_tls_id;
1173         gid_t gid;
1174
1175         UWRAP_LOCK(uwrap_id);
1176         gid = id->egid;
1177         UWRAP_UNLOCK(uwrap_id);
1178
1179         return gid;
1180 }
1181
1182 uid_t getegid(void)
1183 {
1184         if (!uid_wrapper_enabled()) {
1185                 return libc_getegid();
1186         }
1187
1188         uwrap_init();
1189         return uwrap_getegid();
1190 }
1191
1192 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1193 {
1194         struct uwrap_thread *id = uwrap_tls_id;
1195         int rc = -1;
1196
1197         UWRAP_LOCK(uwrap_id);
1198
1199         if (size == 0) {
1200                 SAFE_FREE(id->groups);
1201                 id->ngroups = 0;
1202                 if (pthread_equal(id->tid, uwrap.tid)) {
1203                         SAFE_FREE(uwrap.groups);
1204                         uwrap.ngroups = 0;
1205                 }
1206         } else if (size > 0) {
1207                 gid_t *tmp;
1208
1209                 tmp = realloc(id->groups, sizeof(gid_t) * size);
1210                 if (tmp == NULL) {
1211                         errno = ENOMEM;
1212                         goto out;
1213                 }
1214                 id->groups = tmp;
1215                 id->ngroups = size;
1216                 memcpy(id->groups, list, size * sizeof(gid_t));
1217
1218                 if (pthread_equal(id->tid, uwrap.tid)) {
1219                         tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1220                         if (tmp == NULL) {
1221                                 /* How to return back id->groups? */
1222                                 errno = ENOMEM;
1223                                 goto out;
1224                         }
1225
1226                         uwrap.groups = tmp;
1227                         uwrap.ngroups = size;
1228                         memcpy(uwrap.groups, list, size * sizeof(gid_t));
1229                 }
1230         }
1231
1232         rc = 0;
1233 out:
1234         UWRAP_UNLOCK(uwrap_id);
1235
1236         return rc;
1237 }
1238
1239 static int uwrap_setgroups(size_t size, const gid_t *list)
1240 {
1241         struct uwrap_thread *id;
1242         int rc = -1;
1243
1244         UWRAP_LOCK(uwrap_id);
1245
1246         if (size == 0) {
1247                 for (id = uwrap.ids; id; id = id->next) {
1248                         SAFE_FREE(id->groups);
1249                         id->ngroups = 0;
1250
1251                 }
1252                 SAFE_FREE(uwrap.groups);
1253                 uwrap.ngroups = 0;
1254         } else if (size > 0) {
1255                 gid_t *tmp;
1256
1257                 for (id = uwrap.ids; id; id = id->next) {
1258                         tmp = realloc(id->groups, sizeof(gid_t) * size);
1259                         if (tmp == NULL) {
1260                                 errno = ENOMEM;
1261                                 goto out;
1262                         }
1263                         id->groups = tmp;
1264
1265                         id->ngroups = size;
1266                         memcpy(id->groups, list, size * sizeof(gid_t));
1267                 }
1268
1269                 tmp = realloc(uwrap.groups, sizeof(gid_t) * size);
1270                 if (tmp == NULL) {
1271                         /* How to return back id->groups? */
1272                         errno = ENOMEM;
1273                         goto out;
1274                 }
1275
1276                 uwrap.groups = tmp;
1277                 uwrap.ngroups = size;
1278                 memcpy(uwrap.groups, list, size * sizeof(gid_t));
1279
1280         }
1281
1282         rc = 0;
1283 out:
1284         UWRAP_UNLOCK(uwrap_id);
1285
1286         return rc;
1287 }
1288
1289 #ifdef HAVE_SETGROUPS_INT
1290 int setgroups(int size, const gid_t *list)
1291 #else
1292 int setgroups(size_t size, const gid_t *list)
1293 #endif
1294 {
1295         if (!uid_wrapper_enabled()) {
1296                 return libc_setgroups(size, list);
1297         }
1298
1299         uwrap_init();
1300         return uwrap_setgroups(size, list);
1301 }
1302
1303 static int uwrap_getgroups(int size, gid_t *list)
1304 {
1305         struct uwrap_thread *id = uwrap_tls_id;
1306         int ngroups;
1307
1308         UWRAP_LOCK(uwrap_id);
1309         ngroups = id->ngroups;
1310
1311         if (size > ngroups) {
1312                 size = ngroups;
1313         }
1314         if (size == 0) {
1315                 goto out;
1316         }
1317         if (size < ngroups) {
1318                 errno = EINVAL;
1319                 ngroups = -1;
1320         }
1321         memcpy(list, id->groups, size * sizeof(gid_t));
1322
1323 out:
1324         UWRAP_UNLOCK(uwrap_id);
1325
1326         return ngroups;
1327 }
1328
1329 int getgroups(int size, gid_t *list)
1330 {
1331         if (!uid_wrapper_enabled()) {
1332                 return libc_getgroups(size, list);
1333         }
1334
1335         uwrap_init();
1336         return uwrap_getgroups(size, list);
1337 }
1338
1339 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1340     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1341 static long int uwrap_syscall (long int sysno, va_list vp)
1342 {
1343         long int rc;
1344
1345         switch (sysno) {
1346                 /* gid */
1347                 case SYS_getgid:
1348 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1349                 case SYS_getgid32:
1350 #endif
1351                         {
1352                                 rc = uwrap_getgid();
1353                         }
1354                         break;
1355 #ifdef SYS_getegid
1356                 case SYS_getegid:
1357 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1358                 case SYS_getegid32:
1359 #endif
1360                         {
1361                                 rc = uwrap_getegid();
1362                         }
1363                         break;
1364 #endif /* SYS_getegid */
1365                 case SYS_setgid:
1366 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1367                 case SYS_setgid32:
1368 #endif
1369                         {
1370                                 gid_t gid = (gid_t) va_arg(vp, gid_t);
1371
1372                                 rc = uwrap_setresgid_thread(gid, -1, -1);
1373                         }
1374                         break;
1375                 case SYS_setregid:
1376 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1377                 case SYS_setregid32:
1378 #endif
1379                         {
1380                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1381                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
1382
1383                                 rc = uwrap_setresgid_thread(rgid, egid, -1);
1384                         }
1385                         break;
1386 #ifdef SYS_setresgid
1387                 case SYS_setresgid:
1388 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1389                 case SYS_setresgid32:
1390 #endif
1391                         {
1392                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1393                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
1394                                 gid_t sgid = (gid_t) va_arg(vp, gid_t);
1395
1396                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1397                         }
1398                         break;
1399 #endif /* SYS_setresgid */
1400 #ifdef SYS_getresgid
1401                 case SYS_getresgid:
1402 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1403                 case SYS_getresgid32:
1404 #endif
1405                         {
1406                                 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
1407                                 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
1408                                 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
1409
1410                                 rc = uwrap_getresgid(rgid, egid, sgid);
1411                         }
1412                         break;
1413 #endif /* SYS_getresgid */
1414
1415                 /* uid */
1416                 case SYS_getuid:
1417 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1418                 case SYS_getuid32:
1419 #endif
1420                         {
1421                                 rc = uwrap_getuid();
1422                         }
1423                         break;
1424 #ifdef SYS_geteuid
1425                 case SYS_geteuid:
1426 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1427                 case SYS_geteuid32:
1428 #endif
1429                         {
1430                                 rc = uwrap_geteuid();
1431                         }
1432                         break;
1433 #endif /* SYS_geteuid */
1434                 case SYS_setuid:
1435 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1436                 case SYS_setuid32:
1437 #endif
1438                         {
1439                                 uid_t uid = (uid_t) va_arg(vp, uid_t);
1440
1441                                 rc = uwrap_setresuid_thread(uid, -1, -1);
1442                         }
1443                         break;
1444                 case SYS_setreuid:
1445 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1446                 case SYS_setreuid32:
1447 #endif
1448                         {
1449                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1450                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
1451
1452                                 rc = uwrap_setresuid_thread(ruid, euid, -1);
1453                         }
1454                         break;
1455 #ifdef SYS_setresuid
1456                 case SYS_setresuid:
1457 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1458                 case SYS_setresuid32:
1459 #endif
1460                         {
1461                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1462                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
1463                                 uid_t suid = (uid_t) va_arg(vp, uid_t);
1464
1465                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
1466                         }
1467                         break;
1468 #endif /* SYS_setresuid */
1469 #ifdef SYS_getresuid
1470                 case SYS_getresuid:
1471 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1472                 case SYS_getresuid32:
1473 #endif
1474                         {
1475                                 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
1476                                 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
1477                                 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
1478
1479                                 rc = uwrap_getresuid(ruid, euid, suid);
1480                         }
1481                         break;
1482 #endif /* SYS_getresuid */
1483                 /* groups */
1484                 case SYS_setgroups:
1485 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1486                 case SYS_setgroups32:
1487 #endif
1488                         {
1489                                 size_t size = (size_t) va_arg(vp, size_t);
1490                                 gid_t *list = (gid_t *) va_arg(vp, int *);
1491
1492                                 rc = uwrap_setgroups_thread(size, list);
1493                         }
1494                         break;
1495                 default:
1496                         UWRAP_LOG(UWRAP_LOG_DEBUG,
1497                                   "UID_WRAPPER calling non-wrapped syscall %lu\n",
1498                                   sysno);
1499
1500                         rc = libc_vsyscall(sysno, vp);
1501                         break;
1502         }
1503
1504         return rc;
1505 }
1506
1507 #ifdef HAVE_SYSCALL
1508 #ifdef HAVE_SYSCALL_INT
1509 int syscall (int sysno, ...)
1510 #else
1511 long int syscall (long int sysno, ...)
1512 #endif
1513 {
1514 #ifdef HAVE_SYSCALL_INT
1515         int rc;
1516 #else
1517         long int rc;
1518 #endif
1519         va_list va;
1520
1521         va_start(va, sysno);
1522
1523         if (!uid_wrapper_enabled()) {
1524                 rc = libc_vsyscall(sysno, va);
1525                 va_end(va);
1526                 return rc;
1527         }
1528
1529         uwrap_init();
1530         rc = uwrap_syscall(sysno, va);
1531         va_end(va);
1532
1533         return rc;
1534 }
1535 #endif /* HAVE_SYSCALL */
1536 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1537
1538 /****************************
1539  * CONSTRUCTOR
1540  ***************************/
1541 void uwrap_constructor(void)
1542 {
1543         /*
1544         * If we hold a lock and the application forks, then the child
1545         * is not able to unlock the mutex and we are in a deadlock.
1546         * This should prevent such deadlocks.
1547         */
1548         pthread_atfork(&uwrap_thread_prepare,
1549                        &uwrap_thread_parent,
1550                        &uwrap_thread_child);
1551
1552         /* Here is safe place to call uwrap_init() and initialize data
1553          * for main process.
1554          */
1555         uwrap_init();
1556 }
1557
1558 /****************************
1559  * DESTRUCTOR
1560  ***************************/
1561
1562 /*
1563  * This function is called when the library is unloaded and makes sure that
1564  * resources are freed.
1565  */
1566 void uwrap_destructor(void)
1567 {
1568         struct uwrap_thread *u = uwrap.ids;
1569
1570         UWRAP_LOCK(uwrap_id);
1571         UWRAP_LOCK(libc_symbol_binding);
1572
1573         while (u != NULL) {
1574                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1575
1576                 SAFE_FREE(u->groups);
1577                 SAFE_FREE(u);
1578
1579                 u = uwrap.ids;
1580         }
1581
1582         SAFE_FREE(uwrap.groups);
1583
1584         if (uwrap.libc.handle != NULL) {
1585                 dlclose(uwrap.libc.handle);
1586         }
1587
1588         UWRAP_UNLOCK(libc_symbol_binding);
1589         UWRAP_UNLOCK(uwrap_id);
1590 }