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