uwrap: Add log message before exit
[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 *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
140 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
141
142 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, 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                 const char *prefix = "UWRAP";
160                 switch (dbglvl) {
161                         case UWRAP_LOG_ERROR:
162                                 prefix = "UWRAP_ERROR";
163                                 break;
164                         case UWRAP_LOG_WARN:
165                                 prefix = "UWRAP_WARN";
166                                 break;
167                         case UWRAP_LOG_DEBUG:
168                                 prefix = "UWRAP_DEBUG";
169                                 break;
170                         case UWRAP_LOG_TRACE:
171                                 prefix = "UWRAP_TRACE";
172                                 break;
173                 }
174
175                 fprintf(stderr,
176                         "%s(%d) - %s: %s\n",
177                         prefix,
178                         (int)getpid(),
179                         function,
180                         buffer);
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                                 /* glibc on Alpha and IA64 is libc.so.6.1 */
412                                 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
413                                 handle = dlopen(soname, flags);
414                                 if (handle != NULL) {
415                                         break;
416                                 }
417                         }
418
419                         uwrap.libc.handle = handle;
420                 }
421                 break;
422         case UWRAP_LIBPTHREAD:
423                 handle = uwrap.libpthread.handle;
424                 if (handle == NULL) {
425                         handle = dlopen("libpthread.so.0", flags);
426                         if (handle != NULL) {
427                                 break;
428                         }
429                 }
430                 break;
431         }
432
433         if (handle == NULL) {
434 #ifdef RTLD_NEXT
435                 handle = uwrap.libc.handle = RTLD_NEXT;
436 #else
437                 fprintf(stderr,
438                         "Failed to dlopen library: %s\n",
439                         dlerror());
440                 exit(-1);
441 #endif
442         }
443
444         return handle;
445 }
446
447 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
448 {
449         void *handle;
450         void *func;
451
452         handle = uwrap_load_lib_handle(lib);
453
454         func = dlsym(handle, fn_name);
455         if (func == NULL) {
456                 fprintf(stderr,
457                         "Failed to find %s: %s\n",
458                         fn_name, dlerror());
459                 exit(-1);
460         }
461
462         return func;
463 }
464
465 #define uwrap_bind_symbol_libc(sym_name) \
466         UWRAP_LOCK(libc_symbol_binding); \
467         if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
468                 uwrap.libc.symbols._libc_##sym_name.obj = \
469                         _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
470         } \
471         UWRAP_UNLOCK(libc_symbol_binding)
472
473 #define uwrap_bind_symbol_libpthread(sym_name) \
474         UWRAP_LOCK(libpthread_symbol_binding); \
475         if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
476                 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
477                         _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
478         } \
479         UWRAP_UNLOCK(libpthread_symbol_binding)
480
481 /*
482  * IMPORTANT
483  *
484  * Functions expeciall from libc need to be loaded individually, you can't load
485  * all at once or gdb will segfault at startup. The same applies to valgrind and
486  * has probably something todo with with the linker.
487  * So we need load each function at the point it is called the first time.
488  */
489 static int libc_setuid(uid_t uid)
490 {
491         uwrap_bind_symbol_libc(setuid);
492
493         return uwrap.libc.symbols._libc_setuid.f(uid);
494 }
495
496 static uid_t libc_getuid(void)
497 {
498         uwrap_bind_symbol_libc(getuid);
499
500         return uwrap.libc.symbols._libc_getuid.f();
501 }
502
503 #ifdef HAVE_SETEUID
504 static int libc_seteuid(uid_t euid)
505 {
506         uwrap_bind_symbol_libc(seteuid);
507
508         return uwrap.libc.symbols._libc_seteuid.f(euid);
509 }
510 #endif
511
512 #ifdef HAVE_SETREUID
513 static int libc_setreuid(uid_t ruid, uid_t euid)
514 {
515         uwrap_bind_symbol_libc(setreuid);
516
517         return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
518 }
519 #endif
520
521 #ifdef HAVE_SETRESUID
522 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
523 {
524         uwrap_bind_symbol_libc(setresuid);
525
526         return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
527 }
528 #endif
529
530 #ifdef HAVE_GETRESUID
531 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
532 {
533         uwrap_bind_symbol_libc(getresuid);
534
535         return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
536 }
537 #endif
538
539 static uid_t libc_geteuid(void)
540 {
541         uwrap_bind_symbol_libc(geteuid);
542
543         return uwrap.libc.symbols._libc_geteuid.f();
544 }
545
546 static int libc_setgid(gid_t gid)
547 {
548         uwrap_bind_symbol_libc(setgid);
549
550         return uwrap.libc.symbols._libc_setgid.f(gid);
551 }
552
553 static gid_t libc_getgid(void)
554 {
555         uwrap_bind_symbol_libc(getgid);
556
557         return uwrap.libc.symbols._libc_getgid.f();
558 }
559
560 #ifdef HAVE_SETEGID
561 static int libc_setegid(gid_t egid)
562 {
563         uwrap_bind_symbol_libc(setegid);
564
565         return uwrap.libc.symbols._libc_setegid.f(egid);
566 }
567 #endif
568
569 #ifdef HAVE_SETREGID
570 static int libc_setregid(gid_t rgid, gid_t egid)
571 {
572         uwrap_bind_symbol_libc(setregid);
573
574         return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
575 }
576 #endif
577
578 #ifdef HAVE_SETRESGID
579 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
580 {
581         uwrap_bind_symbol_libc(setresgid);
582
583         return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
584 }
585 #endif
586
587 #ifdef HAVE_GETRESGID
588 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
589 {
590         uwrap_bind_symbol_libc(setresgid);
591
592         return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
593 }
594 #endif
595
596 static gid_t libc_getegid(void)
597 {
598         uwrap_bind_symbol_libc(getegid);
599
600         return uwrap.libc.symbols._libc_getegid.f();
601 }
602
603 static int libc_getgroups(int size, gid_t list[])
604 {
605         uwrap_bind_symbol_libc(getgroups);
606
607         return uwrap.libc.symbols._libc_getgroups.f(size, list);
608 }
609
610 static int libc_setgroups(size_t size, const gid_t *list)
611 {
612         uwrap_bind_symbol_libc(setgroups);
613
614         return uwrap.libc.symbols._libc_setgroups.f(size, list);
615 }
616
617 #ifdef HAVE_SYSCALL
618 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
619 static long int libc_vsyscall(long int sysno, va_list va)
620 {
621         long int args[8];
622         long int rc;
623         int i;
624
625         uwrap_bind_symbol_libc(syscall);
626
627         for (i = 0; i < 8; i++) {
628                 args[i] = va_arg(va, long int);
629         }
630
631         rc = uwrap.libc.symbols._libc_syscall.f(sysno,
632                                           args[0],
633                                           args[1],
634                                           args[2],
635                                           args[3],
636                                           args[4],
637                                           args[5],
638                                           args[6],
639                                           args[7]);
640
641         return rc;
642 }
643 #endif
644
645 /*
646  * This part is "optimistic".
647  * Thread can ends without pthread_exit call.
648  */
649 static void libpthread_pthread_exit(void *retval)
650 {
651         uwrap_bind_symbol_libpthread(pthread_exit);
652
653         uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
654 }
655
656 static void uwrap_pthread_exit(void *retval)
657 {
658         struct uwrap_thread *id = uwrap_tls_id;
659
660         UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
661
662         UWRAP_LOCK(uwrap_id);
663         if (id == NULL) {
664                 UWRAP_UNLOCK(uwrap_id);
665                 libpthread_pthread_exit(retval);
666                 return;
667         }
668
669         UWRAP_DLIST_REMOVE(uwrap.ids, id);
670         SAFE_FREE(id->groups);
671         SAFE_FREE(id);
672         uwrap_tls_id = NULL;
673
674         UWRAP_UNLOCK(uwrap_id);
675
676         libpthread_pthread_exit(retval);
677 }
678
679 void pthread_exit(void *retval)
680 {
681         if (!uid_wrapper_enabled()) {
682                 libpthread_pthread_exit(retval);
683         };
684
685         uwrap_pthread_exit(retval);
686
687         /* Calm down gcc warning. */
688         exit(666);
689 }
690
691 static int libpthread_pthread_create(pthread_t *thread,
692                                 const pthread_attr_t *attr,
693                                 void *(*start_routine) (void *),
694                                 void *arg)
695 {
696         uwrap_bind_symbol_libpthread(pthread_create);
697         return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
698                                                                      attr,
699                                                                      start_routine,
700                                                                      arg);
701 }
702
703 struct uwrap_pthread_create_args {
704         struct uwrap_thread *id;
705         void *(*start_routine) (void *);
706         void *arg;
707 };
708
709 static void *uwrap_pthread_create_start(void *_a)
710 {
711         struct uwrap_pthread_create_args *a =
712                 (struct uwrap_pthread_create_args *)_a;
713         void *(*start_routine) (void *) = a->start_routine;
714         void *arg = a->arg;
715         struct uwrap_thread *id = a->id;
716
717         SAFE_FREE(a);
718
719         uwrap_tls_id = id;
720
721         return start_routine(arg);
722 }
723
724 static int uwrap_pthread_create(pthread_t *thread,
725                                  const pthread_attr_t *attr,
726                                  void *(*start_routine) (void *),
727                                  void *arg)
728 {
729         struct uwrap_pthread_create_args *args;
730         struct uwrap_thread *src_id = uwrap_tls_id;
731         int ret;
732
733         args = malloc(sizeof(struct uwrap_pthread_create_args));
734         if (args == NULL) {
735                 UWRAP_LOG(UWRAP_LOG_ERROR,
736                           "uwrap_pthread_create: Unable to allocate memory");
737                 errno = ENOMEM;
738                 return -1;
739         }
740         args->start_routine = start_routine;
741         args->arg = arg;
742
743         args->id = calloc(1, sizeof(struct uwrap_thread));
744         if (args->id == NULL) {
745                 SAFE_FREE(args);
746                 UWRAP_LOG(UWRAP_LOG_ERROR,
747                           "uwrap_pthread_create: Unable to allocate memory");
748                 errno = ENOMEM;
749                 return -1;
750         }
751
752         UWRAP_LOCK(uwrap_id);
753
754         args->id->groups = malloc(sizeof(gid_t) * src_id->ngroups);
755         if (args->id->groups == NULL) {
756                 UWRAP_UNLOCK(uwrap_id);
757                 SAFE_FREE(args->id);
758                 SAFE_FREE(args);
759                 UWRAP_LOG(UWRAP_LOG_ERROR,
760                           "uwrap_pthread_create: Unable to allocate memory again");
761                 errno = ENOMEM;
762                 return -1;
763         }
764
765         args->id->ruid = src_id->ruid;
766         args->id->euid = src_id->euid;
767         args->id->suid = src_id->suid;
768
769         args->id->rgid = src_id->rgid;
770         args->id->egid = src_id->egid;
771         args->id->sgid = src_id->sgid;
772
773         args->id->enabled = src_id->enabled;
774
775         args->id->ngroups = src_id->ngroups;
776         if (src_id->groups != NULL) {
777                 memcpy(args->id->groups, src_id->groups,
778                        sizeof(gid_t) * src_id->ngroups);
779         } else {
780                 SAFE_FREE(args->id->groups);
781         }
782
783         UWRAP_DLIST_ADD(uwrap.ids, args->id);
784         UWRAP_UNLOCK(uwrap_id);
785
786         ret = libpthread_pthread_create(thread, attr,
787                                         uwrap_pthread_create_start,
788                                         args);
789         if (ret != 0) {
790                 return ret;
791         }
792
793         return ret;
794 }
795
796 int pthread_create(pthread_t *thread,
797                     const pthread_attr_t *attr,
798                     void *(*start_routine) (void *),
799                     void *arg)
800 {
801         if (!uid_wrapper_enabled()) {
802                 return libpthread_pthread_create(thread,
803                                            attr,
804                                            start_routine,
805                                            arg);
806         };
807
808         return uwrap_pthread_create(thread,
809                                     attr,
810                                     start_routine,
811                                     arg);
812 }
813
814 /*********************************************************
815  * UWRAP ID HANDLING
816  *********************************************************/
817
818 #define GROUP_STRING_SIZE 16384
819 #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
820
821 /**
822  * This function exports all the IDs of the current user so if
823  * we fork and then exec we can setup uid_wrapper in the new process
824  * with those IDs.
825  */
826 static void uwrap_export_ids(struct uwrap_thread *id)
827 {
828         char groups_str[GROUP_STRING_SIZE] = {0};
829         size_t groups_str_size = sizeof(groups_str);
830         char unsigned_str[32] = {0};
831         int i;
832
833         /* UIDS */
834         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
835         setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
836
837         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
838         setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
839
840         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
841         setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
842
843         /* GIDS */
844         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
845         setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
846
847         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
848         setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
849
850         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
851         setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
852
853         if (id->ngroups > GROUP_MAX_COUNT) {
854                 UWRAP_LOG(UWRAP_LOG_ERROR,
855                           "ERROR: Number of groups (%u) exceeds maximum value "
856                           "uid_wrapper will handle (%u).",
857                           id->ngroups,
858                           GROUP_MAX_COUNT);
859                 exit(-1);
860         }
861
862         /* GROUPS */
863         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
864         setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
865
866         for (i = 0; i < id->ngroups; i++) {
867                 size_t groups_str_len = strlen(groups_str);
868                 size_t groups_str_avail = groups_str_size - groups_str_len;
869                 size_t len;
870
871                 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
872                 if (len <= 1) {
873                         continue;
874                 }
875                 if (len < groups_str_avail) {
876                         snprintf(groups_str + groups_str_len,
877                                  groups_str_size - groups_str_len,
878                                  "%s",
879                                  i == 0 ? unsigned_str + 1 : unsigned_str);
880                 }
881         }
882
883         if (id->ngroups > 0) {
884                 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
885         }
886 }
887
888 static void uwrap_thread_prepare(void)
889 {
890         struct uwrap_thread *id = uwrap_tls_id;
891
892         /* uid_wrapper is loaded but not enabled */
893         if (id == NULL) {
894                 return;
895         }
896
897         UWRAP_LOCK_ALL;
898
899         /*
900          * What happens if another atfork prepare functions calls a uwrap
901          * function? So disable it in case another atfork prepare function
902          * calls a (s)uid function. We disable uid_wrapper only for thread
903          * (process) which called fork.
904          */
905         id->enabled = false;
906 }
907
908 static void uwrap_thread_parent(void)
909 {
910         struct uwrap_thread *id = uwrap_tls_id;
911
912         /* uid_wrapper is loaded but not enabled */
913         if (id == NULL) {
914                 return;
915         }
916
917         id->enabled = true;
918
919         UWRAP_UNLOCK_ALL;
920 }
921
922 static void uwrap_thread_child(void)
923 {
924         struct uwrap_thread *id = uwrap_tls_id;
925         struct uwrap_thread *u = uwrap.ids;
926
927         /* uid_wrapper is loaded but not enabled */
928         if (id == NULL) {
929                 return;
930         }
931
932         uwrap_export_ids(id);
933
934         /*
935          * "Garbage collector" - Inspired by DESTRUCTOR.
936          * All threads (except one which called fork()) are dead now.. Dave
937          * That's what posix said...
938          */
939         while (u != NULL) {
940                 if (u == id) {
941                         /* Skip this item. */
942                         u = uwrap.ids->next;
943                         continue;
944                 }
945
946                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
947
948                 SAFE_FREE(u->groups);
949                 SAFE_FREE(u);
950
951                 u = uwrap.ids;
952         }
953
954         id->enabled = true;
955
956         UWRAP_UNLOCK_ALL;
957 }
958
959 /*
960  * This initializes uid_wrapper with the IDs exported to the environment. Those
961  * are normally set after we forked and executed.
962  */
963 static void uwrap_init_env(struct uwrap_thread *id)
964 {
965         const char *env;
966         int ngroups = 0;
967
968         env = getenv("UID_WRAPPER_INITIAL_RUID");
969         if (env != NULL && env[0] != '\0') {
970                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
971                 id->ruid = strtoul(env, (char **)NULL, 10);
972                 unsetenv("UID_WRAPPER_INITIAL_RUID");
973         }
974
975         env = getenv("UID_WRAPPER_INITIAL_EUID");
976         if (env != NULL && env[0] != '\0') {
977                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize euid with %s", env);
978                 id->euid = strtoul(env, (char **)NULL, 10);
979                 unsetenv("UID_WRAPPER_INITIAL_EUID");
980         }
981
982         env = getenv("UID_WRAPPER_INITIAL_SUID");
983         if (env != NULL && env[0] != '\0') {
984                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize suid with %s", env);
985                 id->suid = strtoul(env, (char **)NULL, 10);
986                 unsetenv("UID_WRAPPER_INITIAL_SUID");
987         }
988
989         env = getenv("UID_WRAPPER_INITIAL_RGID");
990         if (env != NULL && env[0] != '\0') {
991                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize ruid with %s", env);
992                 id->rgid = strtoul(env, (char **)NULL, 10);
993                 unsetenv("UID_WRAPPER_INITIAL_RGID");
994         }
995
996         env = getenv("UID_WRAPPER_INITIAL_EGID");
997         if (env != NULL && env[0] != '\0') {
998                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize egid with %s", env);
999                 id->egid = strtoul(env, (char **)NULL, 10);
1000                 unsetenv("UID_WRAPPER_INITIAL_EGID");
1001         }
1002
1003         env = getenv("UID_WRAPPER_INITIAL_SGID");
1004         if (env != NULL && env[0] != '\0') {
1005                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize sgid with %s", env);
1006                 id->sgid = strtoul(env, (char **)NULL, 10);
1007                 unsetenv("UID_WRAPPER_INITIAL_SGID");
1008         }
1009
1010         env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1011         if (env != NULL && env[0] != '\0') {
1012                 ngroups = strtol(env, (char **)NULL, 10);
1013                 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1014         }
1015
1016         if (ngroups > 0 && ngroups < GROUP_MAX_COUNT) {
1017                 int i = 0;
1018
1019                 id->ngroups = 0;
1020
1021                 free(id->groups);
1022                 id->groups = malloc(sizeof(gid_t) * ngroups);
1023                 if (id->groups == NULL) {
1024                         UWRAP_LOG(UWRAP_LOG_ERROR,
1025                                   "Unable to allocate memory");
1026                         exit(-1);
1027                 }
1028
1029                 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1030                 if (env != NULL && env[0] != '\0') {
1031                         char *groups_str = NULL;
1032                         char *saveptr = NULL;
1033                         const char *p = NULL;
1034
1035                         groups_str = strdup(env);
1036                         if (groups_str == NULL) {
1037                                 exit(-1);
1038                         }
1039
1040                         p = strtok_r(groups_str, ",", &saveptr);
1041                         while (p != NULL) {
1042                                 id->groups[i] = strtol(p, (char **)NULL, 10);
1043                                 i++;
1044
1045                                 p = strtok_r(NULL, ",", &saveptr);
1046                         }
1047                         SAFE_FREE(groups_str);
1048                 }
1049
1050                 if (i != ngroups) {
1051                         UWRAP_LOG(UWRAP_LOG_ERROR,
1052                                   "ERROR: The number of groups (%u) passed, "
1053                                   "does not the number of groups (%u) we "
1054                                   "parsed",
1055                                   ngroups,
1056                                   i);
1057                         exit(-1);
1058                 }
1059
1060                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1061                 id->ngroups = ngroups;
1062         }
1063 }
1064
1065 static void uwrap_init(void)
1066 {
1067         const char *env;
1068
1069         UWRAP_LOCK(uwrap_id);
1070
1071         if (uwrap.initialised) {
1072                 struct uwrap_thread *id = uwrap_tls_id;
1073
1074                 if (uwrap.ids == NULL) {
1075                         UWRAP_UNLOCK(uwrap_id);
1076                         return;
1077                 }
1078
1079                 if (id == NULL) {
1080                         UWRAP_LOG(UWRAP_LOG_ERROR,
1081                                   "Invalid id for thread");
1082                         exit(-1);
1083                 }
1084
1085                 UWRAP_UNLOCK(uwrap_id);
1086                 return;
1087         }
1088
1089         UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1090
1091         uwrap.initialised = true;
1092
1093         env = getenv("UID_WRAPPER");
1094         if (env != NULL && env[0] == '1') {
1095                 const char *root = getenv("UID_WRAPPER_ROOT");
1096                 struct uwrap_thread *id;
1097
1098                 id = calloc(1, sizeof(struct uwrap_thread));
1099                 if (id == NULL) {
1100                         UWRAP_LOG(UWRAP_LOG_ERROR,
1101                                   "Unable to allocate memory for main id");
1102                         exit(-1);
1103                 }
1104
1105                 UWRAP_DLIST_ADD(uwrap.ids, id);
1106                 uwrap_tls_id = id;
1107
1108                 uwrap.myuid = libc_geteuid();
1109                 uwrap.mygid = libc_getegid();
1110
1111                 /* put us in one group */
1112                 if (root != NULL && root[0] == '1') {
1113                         id->ruid = id->euid = id->suid = 0;
1114                         id->rgid = id->egid = id->sgid = 0;
1115
1116                         id->groups = malloc(sizeof(gid_t) * 1);
1117                         if (id->groups == NULL) {
1118                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1119                                           "Unable to allocate memory");
1120                                 exit(-1);
1121                         }
1122
1123                         id->ngroups = 1;
1124                         id->groups[0] = 0;
1125
1126                 } else {
1127                         id->ruid = id->euid = id->suid = uwrap.myuid;
1128                         id->rgid = id->egid = id->sgid = uwrap.mygid;
1129
1130                         id->ngroups = libc_getgroups(0, NULL);
1131                         if (id->ngroups == -1) {
1132                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1133                                           "Unable to call libc_getgroups in uwrap_init.");
1134                                 exit(-1);
1135                         }
1136                         id->groups = malloc(sizeof(gid_t) * id->ngroups);
1137                         if (id->groups == NULL) {
1138                                 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1139                                 exit(-1);
1140                         }
1141                         if (libc_getgroups(id->ngroups, id->groups) == -1) {
1142                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1143                                           "Unable to call libc_getgroups again in uwrap_init.");
1144                                 id->groups = 0;
1145                                 /*
1146                                  * Deallocation of uwrap.groups is handled by
1147                                  * library destructor.
1148                                  */
1149                                 exit(-1);
1150                         }
1151                 }
1152
1153                 uwrap_init_env(id);
1154
1155                 id->enabled = true;
1156
1157                 UWRAP_LOG(UWRAP_LOG_DEBUG,
1158                           "Enabled uid_wrapper as %s (real uid=%u)",
1159                           id->ruid == 0 ? "root" : "user",
1160                           (unsigned int)uwrap.myuid);
1161         }
1162
1163         UWRAP_UNLOCK(uwrap_id);
1164
1165         UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
1166 }
1167
1168 bool uid_wrapper_enabled(void)
1169 {
1170         struct uwrap_thread *id = uwrap_tls_id;
1171         bool enabled;
1172
1173         if (id == NULL) {
1174                 return false;
1175         }
1176
1177         UWRAP_LOCK(uwrap_id);
1178         enabled = id->enabled;
1179         UWRAP_UNLOCK(uwrap_id);
1180
1181         return enabled;
1182 }
1183
1184 /*
1185  * UWRAP_SETxUID FUNCTIONS
1186  */
1187
1188 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1189 {
1190         struct uwrap_thread *id = uwrap_tls_id;
1191
1192         UWRAP_LOG(UWRAP_LOG_TRACE,
1193                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1194                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1195
1196         if (id->euid != 0) {
1197                 if (ruid != (uid_t)-1 &&
1198                     ruid != id->ruid &&
1199                     ruid != id->euid &&
1200                     ruid != id->suid) {
1201                         errno = EPERM;
1202                         return -1;
1203                 }
1204                 if (euid != (uid_t)-1 &&
1205                     euid != id->ruid &&
1206                     euid != id->euid &&
1207                     euid != id->suid) {
1208                         errno = EPERM;
1209                         return -1;
1210                 }
1211                 if (suid != (uid_t)-1 &&
1212                     suid != id->ruid &&
1213                     suid != id->euid &&
1214                     suid != id->suid) {
1215                         errno = EPERM;
1216                         return -1;
1217                 }
1218         }
1219
1220         return 0;
1221 }
1222
1223 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1224 {
1225         struct uwrap_thread *id = uwrap_tls_id;
1226         int rc;
1227
1228         UWRAP_LOG(UWRAP_LOG_TRACE,
1229                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1230                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1231
1232         rc = uwrap_setresuid_args(ruid, euid, suid);
1233         if (rc != 0) {
1234                 return rc;
1235         }
1236
1237         UWRAP_LOCK(uwrap_id);
1238
1239         if (ruid != (uid_t)-1) {
1240                 id->ruid = ruid;
1241         }
1242
1243         if (euid != (uid_t)-1) {
1244                 id->euid = euid;
1245         }
1246
1247         if (suid != (uid_t)-1) {
1248                 id->suid = suid;
1249         }
1250
1251         UWRAP_UNLOCK(uwrap_id);
1252
1253         return 0;
1254 }
1255
1256 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1257 {
1258         struct uwrap_thread *id = uwrap_tls_id;
1259         int rc;
1260
1261         UWRAP_LOG(UWRAP_LOG_TRACE,
1262                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1263                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1264
1265         rc = uwrap_setresuid_args(ruid, euid, suid);
1266         if (rc != 0) {
1267                 return rc;
1268         }
1269
1270         UWRAP_LOCK(uwrap_id);
1271
1272         for (id = uwrap.ids; id; id = id->next) {
1273                 if (ruid != (uid_t)-1) {
1274                         id->ruid = ruid;
1275                 }
1276
1277                 if (euid != (uid_t)-1) {
1278                         id->euid = euid;
1279                 }
1280
1281                 if (suid != (uid_t)-1) {
1282                         id->suid = suid;
1283                 }
1284         }
1285
1286         UWRAP_UNLOCK(uwrap_id);
1287
1288         return 0;
1289 }
1290
1291 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1292                                uid_t *_new_ruid,
1293                                uid_t *_new_euid,
1294                                uid_t *_new_suid)
1295 {
1296         struct uwrap_thread *id = uwrap_tls_id;
1297         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1298
1299         UWRAP_LOG(UWRAP_LOG_TRACE,
1300                   "ruid %d -> %d, euid %d -> %d",
1301                   id->ruid, ruid, id->euid, euid);
1302
1303         if (ruid != (uid_t)-1) {
1304                 new_ruid = ruid;
1305                 if (ruid != id->ruid &&
1306                     ruid != id->euid &&
1307                     id->euid != 0) {
1308                         errno = EPERM;
1309                         return -1;
1310                 }
1311         }
1312
1313         if (euid != (uid_t)-1) {
1314                 new_euid = euid;
1315                 if (euid != id->ruid &&
1316                     euid != id->euid &&
1317                     euid != id->suid &&
1318                     id->euid != 0) {
1319                         errno = EPERM;
1320                         return -1;
1321                 }
1322         }
1323
1324         if (ruid != (uid_t) -1 ||
1325             (euid != (uid_t)-1 && id->ruid != euid)) {
1326                 new_suid = new_euid;
1327         }
1328
1329         *_new_ruid = new_ruid;
1330         *_new_euid = new_euid;
1331         *_new_suid = new_suid;
1332
1333         return 0;
1334 }
1335
1336 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1337 {
1338 #ifndef NDEBUG
1339         struct uwrap_thread *id = uwrap_tls_id;
1340 #endif
1341         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1342         int rc;
1343
1344         UWRAP_LOG(UWRAP_LOG_TRACE,
1345                   "ruid %d -> %d, euid %d -> %d",
1346                   id->ruid, ruid, id->euid, euid);
1347
1348         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1349         if (rc != 0) {
1350                 return rc;
1351         }
1352
1353         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1354 }
1355
1356 #ifdef HAVE_SETREUID
1357 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1358 {
1359 #ifndef NDEBUG
1360         struct uwrap_thread *id = uwrap_tls_id;
1361 #endif
1362         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1363         int rc;
1364
1365         UWRAP_LOG(UWRAP_LOG_TRACE,
1366                   "ruid %d -> %d, euid %d -> %d",
1367                   id->ruid, ruid, id->euid, euid);
1368
1369         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1370         if (rc != 0) {
1371                 return rc;
1372         }
1373
1374         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1375 }
1376 #endif
1377
1378 static int uwrap_setuid_args(uid_t uid,
1379                              uid_t *new_ruid,
1380                              uid_t *new_euid,
1381                              uid_t *new_suid)
1382 {
1383         struct uwrap_thread *id = uwrap_tls_id;
1384
1385         UWRAP_LOG(UWRAP_LOG_TRACE,
1386                   "uid %d -> %d",
1387                   id->ruid, uid);
1388
1389         if (uid == (uid_t)-1) {
1390                 errno = EINVAL;
1391                 return -1;
1392         }
1393
1394         if (id->euid == 0) {
1395                 *new_suid = *new_ruid = uid;
1396         } else if (uid != id->ruid &&
1397                    uid != id->suid) {
1398                 errno = EPERM;
1399                 return -1;
1400         }
1401
1402         *new_euid = uid;
1403
1404         return 0;
1405 }
1406
1407 static int uwrap_setuid_thread(uid_t uid)
1408 {
1409         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1410         int rc;
1411
1412         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1413         if (rc != 0) {
1414                 return rc;
1415         }
1416
1417         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1418 }
1419
1420 static int uwrap_setuid(uid_t uid)
1421 {
1422         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1423         int rc;
1424
1425         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1426         if (rc != 0) {
1427                 return rc;
1428         }
1429
1430         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1431 }
1432
1433 /*
1434  * UWRAP_GETxUID FUNCTIONS
1435  */
1436
1437 #ifdef HAVE_GETRESUID
1438 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1439 {
1440         struct uwrap_thread *id = uwrap_tls_id;
1441
1442         UWRAP_LOCK(uwrap_id);
1443
1444         *ruid = id->ruid;
1445         *euid = id->euid;
1446         *suid = id->suid;
1447
1448         UWRAP_UNLOCK(uwrap_id);
1449
1450         return 0;
1451 }
1452 #endif
1453
1454 #ifdef HAVE_GETRESGID
1455 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1456 {
1457         struct uwrap_thread *id = uwrap_tls_id;
1458
1459         UWRAP_LOCK(uwrap_id);
1460
1461         *rgid = id->rgid;
1462         *egid = id->egid;
1463         *sgid = id->sgid;
1464
1465         UWRAP_UNLOCK(uwrap_id);
1466
1467         return 0;
1468 }
1469 #endif
1470
1471 /*
1472  * UWRAP_SETxGID FUNCTIONS
1473  */
1474
1475 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1476 {
1477         struct uwrap_thread *id = uwrap_tls_id;
1478
1479         UWRAP_LOG(UWRAP_LOG_TRACE,
1480                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1481                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1482
1483         if (id->euid != 0) {
1484                 if (rgid != (gid_t)-1 &&
1485                     rgid != id->rgid &&
1486                     rgid != id->egid &&
1487                     rgid != id->sgid) {
1488                         errno = EPERM;
1489                         return -1;
1490                 }
1491                 if (egid != (gid_t)-1 &&
1492                     egid != id->rgid &&
1493                     egid != id->egid &&
1494                     egid != id->sgid) {
1495                         errno = EPERM;
1496                         return -1;
1497                 }
1498                 if (sgid != (gid_t)-1 &&
1499                     sgid != id->rgid &&
1500                     sgid != id->egid &&
1501                     sgid != id->sgid) {
1502                         errno = EPERM;
1503                         return -1;
1504                 }
1505         }
1506
1507         return 0;
1508 }
1509
1510 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1511 {
1512         struct uwrap_thread *id = uwrap_tls_id;
1513         int rc;
1514
1515         UWRAP_LOG(UWRAP_LOG_TRACE,
1516                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1517                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1518
1519         rc = uwrap_setresgid_args(rgid, egid, sgid);
1520         if (rc != 0) {
1521                 return rc;
1522         }
1523
1524         UWRAP_LOCK(uwrap_id);
1525
1526         if (rgid != (gid_t)-1) {
1527                 id->rgid = rgid;
1528         }
1529
1530         if (egid != (gid_t)-1) {
1531                 id->egid = egid;
1532         }
1533
1534         if (sgid != (gid_t)-1) {
1535                 id->sgid = sgid;
1536         }
1537
1538         UWRAP_UNLOCK(uwrap_id);
1539
1540         return 0;
1541 }
1542
1543 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1544 {
1545         struct uwrap_thread *id = uwrap_tls_id;
1546         int rc;
1547
1548         UWRAP_LOG(UWRAP_LOG_TRACE,
1549                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1550                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1551
1552         rc = uwrap_setresgid_args(rgid, egid, sgid);
1553         if (rc != 0) {
1554                 return rc;
1555         }
1556
1557         UWRAP_LOCK(uwrap_id);
1558
1559         for (id = uwrap.ids; id; id = id->next) {
1560                 if (rgid != (gid_t)-1) {
1561                         id->rgid = rgid;
1562                 }
1563
1564                 if (egid != (gid_t)-1) {
1565                         id->egid = egid;
1566                 }
1567
1568                 if (sgid != (gid_t)-1) {
1569                         id->sgid = sgid;
1570                 }
1571         }
1572
1573         UWRAP_UNLOCK(uwrap_id);
1574
1575         return 0;
1576 }
1577
1578 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1579                                gid_t *_new_rgid,
1580                                gid_t *_new_egid,
1581                                gid_t *_new_sgid)
1582 {
1583         struct uwrap_thread *id = uwrap_tls_id;
1584         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1585
1586         UWRAP_LOG(UWRAP_LOG_TRACE,
1587                   "rgid %d -> %d, egid %d -> %d",
1588                   id->rgid, rgid, id->egid, egid);
1589
1590         if (rgid != (gid_t)-1) {
1591                 new_rgid = rgid;
1592                 if (rgid != id->rgid &&
1593                     rgid != id->egid &&
1594                     id->euid != 0) {
1595                         errno = EPERM;
1596                         return -1;
1597                 }
1598         }
1599
1600         if (egid != (gid_t)-1) {
1601                 new_egid = egid;
1602                 if (egid != id->rgid &&
1603                     egid != id->egid &&
1604                     egid != id->sgid &&
1605                     id->euid != 0) {
1606                         errno = EPERM;
1607                         return -1;
1608                 }
1609         }
1610
1611         if (rgid != (gid_t) -1 ||
1612             (egid != (gid_t)-1 && id->rgid != egid)) {
1613                 new_sgid = new_egid;
1614         }
1615
1616         *_new_rgid = new_rgid;
1617         *_new_egid = new_egid;
1618         *_new_sgid = new_sgid;
1619
1620         return 0;
1621 }
1622
1623 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1624 {
1625 #ifndef NDEBUG
1626         struct uwrap_thread *id = uwrap_tls_id;
1627 #endif
1628         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1629         int rc;
1630
1631         UWRAP_LOG(UWRAP_LOG_TRACE,
1632                   "rgid %d -> %d, egid %d -> %d",
1633                   id->rgid, rgid, id->egid, egid);
1634
1635         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1636         if (rc != 0) {
1637                 return rc;
1638         }
1639
1640         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1641 }
1642
1643 #ifdef HAVE_SETREGID
1644 static int uwrap_setregid(gid_t rgid, gid_t egid)
1645 {
1646 #ifndef NDEBUG
1647         struct uwrap_thread *id = uwrap_tls_id;
1648 #endif
1649         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1650         int rc;
1651
1652         UWRAP_LOG(UWRAP_LOG_TRACE,
1653                   "rgid %d -> %d, egid %d -> %d",
1654                   id->rgid, rgid, id->egid, egid);
1655
1656         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1657         if (rc != 0) {
1658                 return rc;
1659         }
1660
1661         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1662 }
1663 #endif
1664
1665 static int uwrap_setgid_args(gid_t gid,
1666                              gid_t *new_rgid,
1667                              gid_t *new_egid,
1668                              gid_t *new_sgid)
1669 {
1670         struct uwrap_thread *id = uwrap_tls_id;
1671
1672         UWRAP_LOG(UWRAP_LOG_TRACE,
1673                   "gid %d -> %d",
1674                   id->rgid, gid);
1675
1676         if (gid == (gid_t)-1) {
1677                 errno = EINVAL;
1678                 return -1;
1679         }
1680
1681         if (id->euid == 0) {
1682                 *new_sgid = *new_rgid = gid;
1683         } else if (gid != id->rgid &&
1684                    gid != id->sgid) {
1685                 errno = EPERM;
1686                 return -1;
1687         }
1688
1689         *new_egid = gid;
1690
1691         return 0;
1692 }
1693
1694 static int uwrap_setgid_thread(gid_t gid)
1695 {
1696         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1697         int rc;
1698
1699         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1700         if (rc != 0) {
1701                 return rc;
1702         }
1703
1704         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1705 }
1706
1707 static int uwrap_setgid(gid_t gid)
1708 {
1709         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1710         int rc;
1711
1712         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1713         if (rc != 0) {
1714                 return rc;
1715         }
1716
1717         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1718 }
1719
1720 /*
1721  * SETUID
1722  */
1723 int setuid(uid_t uid)
1724 {
1725         if (!uid_wrapper_enabled()) {
1726                 return libc_setuid(uid);
1727         }
1728
1729         uwrap_init();
1730         return uwrap_setuid(uid);
1731 }
1732
1733 #ifdef HAVE_SETEUID
1734 int seteuid(uid_t euid)
1735 {
1736         if (!uid_wrapper_enabled()) {
1737                 return libc_seteuid(euid);
1738         }
1739
1740         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1741         if (euid == (uid_t)-1) {
1742                 errno = EINVAL;
1743                 return -1;
1744         }
1745
1746         uwrap_init();
1747         return uwrap_setresuid(-1, euid, -1);
1748 }
1749 #endif
1750
1751 #ifdef HAVE_SETREUID
1752 int setreuid(uid_t ruid, uid_t euid)
1753 {
1754         if (!uid_wrapper_enabled()) {
1755                 return libc_setreuid(ruid, euid);
1756         }
1757
1758         uwrap_init();
1759         return uwrap_setreuid(ruid, euid);
1760 }
1761 #endif
1762
1763 #ifdef HAVE_SETRESUID
1764 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1765 {
1766         if (!uid_wrapper_enabled()) {
1767                 return libc_setresuid(ruid, euid, suid);
1768         }
1769
1770         uwrap_init();
1771         return uwrap_setresuid(ruid, euid, suid);
1772 }
1773 #endif
1774
1775 #ifdef HAVE_GETRESUID
1776 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1777 {
1778         if (!uid_wrapper_enabled()) {
1779                 return libc_getresuid(ruid, euid, suid);
1780         }
1781
1782         uwrap_init();
1783         return uwrap_getresuid(ruid, euid, suid);
1784 }
1785 #endif
1786
1787 /*
1788  * GETUID
1789  */
1790 static uid_t uwrap_getuid(void)
1791 {
1792         struct uwrap_thread *id = uwrap_tls_id;
1793         uid_t uid;
1794
1795         UWRAP_LOCK(uwrap_id);
1796         uid = id->ruid;
1797         UWRAP_UNLOCK(uwrap_id);
1798
1799         return uid;
1800 }
1801
1802 uid_t getuid(void)
1803 {
1804         if (!uid_wrapper_enabled()) {
1805                 return libc_getuid();
1806         }
1807
1808         uwrap_init();
1809         return uwrap_getuid();
1810 }
1811
1812 /*
1813  * GETEUID
1814  */
1815 static uid_t uwrap_geteuid(void)
1816 {
1817         const char *env = getenv("UID_WRAPPER_MYUID");
1818         struct uwrap_thread *id = uwrap_tls_id;
1819         uid_t uid;
1820
1821         UWRAP_LOCK(uwrap_id);
1822         uid = id->euid;
1823         UWRAP_UNLOCK(uwrap_id);
1824
1825         /* Disable root and return myuid */
1826         if (env != NULL && env[0] == '1') {
1827                 uid = uwrap.myuid;
1828         }
1829
1830         return uid;
1831 }
1832
1833 uid_t geteuid(void)
1834 {
1835         if (!uid_wrapper_enabled()) {
1836                 return libc_geteuid();
1837         }
1838
1839         uwrap_init();
1840         return uwrap_geteuid();
1841 }
1842
1843 /*
1844  * SETGID
1845  */
1846 int setgid(gid_t gid)
1847 {
1848         if (!uid_wrapper_enabled()) {
1849                 return libc_setgid(gid);
1850         }
1851
1852         uwrap_init();
1853         return uwrap_setgid(gid);
1854 }
1855
1856 #ifdef HAVE_SETEGID
1857 int setegid(gid_t egid)
1858 {
1859         if (!uid_wrapper_enabled()) {
1860                 return libc_setegid(egid);
1861         }
1862
1863         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1864         if (egid == (gid_t)-1) {
1865                 errno = EINVAL;
1866                 return -1;
1867         }
1868
1869         uwrap_init();
1870         return uwrap_setresgid(-1, egid, -1);
1871 }
1872 #endif
1873
1874 #ifdef HAVE_SETREGID
1875 int setregid(gid_t rgid, gid_t egid)
1876 {
1877         if (!uid_wrapper_enabled()) {
1878                 return libc_setregid(rgid, egid);
1879         }
1880
1881         uwrap_init();
1882         return uwrap_setregid(rgid, egid);
1883 }
1884 #endif
1885
1886 #ifdef HAVE_SETRESGID
1887 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1888 {
1889         if (!uid_wrapper_enabled()) {
1890                 return libc_setresgid(rgid, egid, sgid);
1891         }
1892
1893         uwrap_init();
1894         return uwrap_setresgid(rgid, egid, sgid);
1895 }
1896 #endif
1897
1898 #ifdef HAVE_GETRESGID
1899 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1900 {
1901         if (!uid_wrapper_enabled()) {
1902                 return libc_getresgid(rgid, egid, sgid);
1903         }
1904
1905         uwrap_init();
1906         return uwrap_getresgid(rgid, egid, sgid);
1907 }
1908 #endif
1909
1910 /*
1911  * GETGID
1912  */
1913 static gid_t uwrap_getgid(void)
1914 {
1915         struct uwrap_thread *id = uwrap_tls_id;
1916         gid_t gid;
1917
1918         UWRAP_LOCK(uwrap_id);
1919         gid = id->rgid;
1920         UWRAP_UNLOCK(uwrap_id);
1921
1922         return gid;
1923 }
1924
1925 gid_t getgid(void)
1926 {
1927         if (!uid_wrapper_enabled()) {
1928                 return libc_getgid();
1929         }
1930
1931         uwrap_init();
1932         return uwrap_getgid();
1933 }
1934
1935 /*
1936  * GETEGID
1937  */
1938 static uid_t uwrap_getegid(void)
1939 {
1940         struct uwrap_thread *id = uwrap_tls_id;
1941         gid_t gid;
1942
1943         UWRAP_LOCK(uwrap_id);
1944         gid = id->egid;
1945         UWRAP_UNLOCK(uwrap_id);
1946
1947         return gid;
1948 }
1949
1950 uid_t getegid(void)
1951 {
1952         if (!uid_wrapper_enabled()) {
1953                 return libc_getegid();
1954         }
1955
1956         uwrap_init();
1957         return uwrap_getegid();
1958 }
1959
1960 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1961 {
1962         struct uwrap_thread *id = uwrap_tls_id;
1963         int rc = -1;
1964
1965         UWRAP_LOCK(uwrap_id);
1966
1967         if (size == 0) {
1968                 SAFE_FREE(id->groups);
1969                 id->ngroups = 0;
1970         } else if (size > 0) {
1971                 gid_t *tmp;
1972
1973                 tmp = realloc(id->groups, sizeof(gid_t) * size);
1974                 if (tmp == NULL) {
1975                         errno = ENOMEM;
1976                         goto out;
1977                 }
1978                 id->groups = tmp;
1979                 id->ngroups = size;
1980                 memcpy(id->groups, list, size * sizeof(gid_t));
1981         }
1982
1983         rc = 0;
1984 out:
1985         UWRAP_UNLOCK(uwrap_id);
1986
1987         return rc;
1988 }
1989
1990 static int uwrap_setgroups(size_t size, const gid_t *list)
1991 {
1992         struct uwrap_thread *id;
1993         int rc = -1;
1994
1995         UWRAP_LOCK(uwrap_id);
1996
1997         if (size == 0) {
1998                 for (id = uwrap.ids; id; id = id->next) {
1999                         SAFE_FREE(id->groups);
2000                         id->ngroups = 0;
2001
2002                 }
2003         } else if (size > 0) {
2004                 gid_t *tmp;
2005
2006                 for (id = uwrap.ids; id; id = id->next) {
2007                         tmp = realloc(id->groups, sizeof(gid_t) * size);
2008                         if (tmp == NULL) {
2009                                 errno = ENOMEM;
2010                                 goto out;
2011                         }
2012                         id->groups = tmp;
2013
2014                         id->ngroups = size;
2015                         memcpy(id->groups, list, size * sizeof(gid_t));
2016                 }
2017         }
2018
2019         rc = 0;
2020 out:
2021         UWRAP_UNLOCK(uwrap_id);
2022
2023         return rc;
2024 }
2025
2026 #ifdef HAVE_SETGROUPS_INT
2027 int setgroups(int size, const gid_t *list)
2028 #else
2029 int setgroups(size_t size, const gid_t *list)
2030 #endif
2031 {
2032         if (!uid_wrapper_enabled()) {
2033                 return libc_setgroups(size, list);
2034         }
2035
2036         uwrap_init();
2037         return uwrap_setgroups(size, list);
2038 }
2039
2040 static int uwrap_getgroups(int size, gid_t *list)
2041 {
2042         struct uwrap_thread *id = uwrap_tls_id;
2043         int ngroups;
2044
2045         UWRAP_LOCK(uwrap_id);
2046         ngroups = id->ngroups;
2047
2048         if (size > ngroups) {
2049                 size = ngroups;
2050         }
2051         if (size == 0) {
2052                 goto out;
2053         }
2054         if (size < ngroups) {
2055                 errno = EINVAL;
2056                 ngroups = -1;
2057         }
2058         memcpy(list, id->groups, size * sizeof(gid_t));
2059
2060 out:
2061         UWRAP_UNLOCK(uwrap_id);
2062
2063         return ngroups;
2064 }
2065
2066 int getgroups(int size, gid_t *list)
2067 {
2068         if (!uid_wrapper_enabled()) {
2069                 return libc_getgroups(size, list);
2070         }
2071
2072         uwrap_init();
2073         return uwrap_getgroups(size, list);
2074 }
2075
2076 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2077     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2078 static long int uwrap_syscall (long int sysno, va_list vp)
2079 {
2080         long int rc;
2081
2082         switch (sysno) {
2083                 /* gid */
2084 #ifdef __alpha__
2085                 case SYS_getxgid:
2086 #else
2087                 case SYS_getgid:
2088 #endif
2089 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2090                 case SYS_getgid32:
2091 #endif
2092                         {
2093                                 rc = uwrap_getgid();
2094                         }
2095                         break;
2096 #ifdef SYS_getegid
2097                 case SYS_getegid:
2098 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2099                 case SYS_getegid32:
2100 #endif
2101                         {
2102                                 rc = uwrap_getegid();
2103                         }
2104                         break;
2105 #endif /* SYS_getegid */
2106                 case SYS_setgid:
2107 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2108                 case SYS_setgid32:
2109 #endif
2110                         {
2111                                 gid_t gid = (gid_t) va_arg(vp, gid_t);
2112
2113                                 rc = uwrap_setgid_thread(gid);
2114                         }
2115                         break;
2116                 case SYS_setregid:
2117 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2118                 case SYS_setregid32:
2119 #endif
2120                         {
2121                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2122                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
2123
2124                                 rc = uwrap_setregid_thread(rgid, egid);
2125                         }
2126                         break;
2127 #ifdef SYS_setresgid
2128                 case SYS_setresgid:
2129 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2130                 case SYS_setresgid32:
2131 #endif
2132                         {
2133                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2134                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
2135                                 gid_t sgid = (gid_t) va_arg(vp, gid_t);
2136
2137                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
2138                         }
2139                         break;
2140 #endif /* SYS_setresgid */
2141 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2142                 case SYS_getresgid:
2143 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2144                 case SYS_getresgid32:
2145 #endif
2146                         {
2147                                 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2148                                 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2149                                 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2150
2151                                 rc = uwrap_getresgid(rgid, egid, sgid);
2152                         }
2153                         break;
2154 #endif /* SYS_getresgid && HAVE_GETRESGID */
2155
2156                 /* uid */
2157 #ifdef __alpha__
2158                 case SYS_getxuid:
2159 #else
2160                 case SYS_getuid:
2161 #endif
2162 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2163                 case SYS_getuid32:
2164 #endif
2165                         {
2166                                 rc = uwrap_getuid();
2167                         }
2168                         break;
2169 #ifdef SYS_geteuid
2170                 case SYS_geteuid:
2171 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2172                 case SYS_geteuid32:
2173 #endif
2174                         {
2175                                 rc = uwrap_geteuid();
2176                         }
2177                         break;
2178 #endif /* SYS_geteuid */
2179                 case SYS_setuid:
2180 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2181                 case SYS_setuid32:
2182 #endif
2183                         {
2184                                 uid_t uid = (uid_t) va_arg(vp, uid_t);
2185
2186                                 rc = uwrap_setuid_thread(uid);
2187                         }
2188                         break;
2189                 case SYS_setreuid:
2190 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2191                 case SYS_setreuid32:
2192 #endif
2193                         {
2194                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2195                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
2196
2197                                 rc = uwrap_setreuid_thread(ruid, euid);
2198                         }
2199                         break;
2200 #ifdef SYS_setresuid
2201                 case SYS_setresuid:
2202 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2203                 case SYS_setresuid32:
2204 #endif
2205                         {
2206                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2207                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
2208                                 uid_t suid = (uid_t) va_arg(vp, uid_t);
2209
2210                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
2211                         }
2212                         break;
2213 #endif /* SYS_setresuid */
2214 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2215                 case SYS_getresuid:
2216 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2217                 case SYS_getresuid32:
2218 #endif
2219                         {
2220                                 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2221                                 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2222                                 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2223
2224                                 rc = uwrap_getresuid(ruid, euid, suid);
2225                         }
2226                         break;
2227 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2228                 /* groups */
2229                 case SYS_setgroups:
2230 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2231                 case SYS_setgroups32:
2232 #endif
2233                         {
2234                                 size_t size = (size_t) va_arg(vp, size_t);
2235                                 gid_t *list = (gid_t *) va_arg(vp, int *);
2236
2237                                 rc = uwrap_setgroups_thread(size, list);
2238                         }
2239                         break;
2240                 default:
2241                         UWRAP_LOG(UWRAP_LOG_DEBUG,
2242                                   "UID_WRAPPER calling non-wrapped syscall %lu",
2243                                   sysno);
2244
2245                         rc = libc_vsyscall(sysno, vp);
2246                         break;
2247         }
2248
2249         return rc;
2250 }
2251
2252 #ifdef HAVE_SYSCALL
2253 #ifdef HAVE_SYSCALL_INT
2254 int syscall (int sysno, ...)
2255 #else
2256 long int syscall (long int sysno, ...)
2257 #endif
2258 {
2259 #ifdef HAVE_SYSCALL_INT
2260         int rc;
2261 #else
2262         long int rc;
2263 #endif
2264         va_list va;
2265
2266         va_start(va, sysno);
2267
2268         if (!uid_wrapper_enabled()) {
2269                 rc = libc_vsyscall(sysno, va);
2270                 va_end(va);
2271                 return rc;
2272         }
2273
2274         uwrap_init();
2275         rc = uwrap_syscall(sysno, va);
2276         va_end(va);
2277
2278         return rc;
2279 }
2280 #endif /* HAVE_SYSCALL */
2281 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2282
2283 /****************************
2284  * CONSTRUCTOR
2285  ***************************/
2286 void uwrap_constructor(void)
2287 {
2288         /*
2289         * If we hold a lock and the application forks, then the child
2290         * is not able to unlock the mutex and we are in a deadlock.
2291         * This should prevent such deadlocks.
2292         */
2293         pthread_atfork(&uwrap_thread_prepare,
2294                        &uwrap_thread_parent,
2295                        &uwrap_thread_child);
2296
2297         /* Here is safe place to call uwrap_init() and initialize data
2298          * for main process.
2299          */
2300         uwrap_init();
2301 }
2302
2303 /****************************
2304  * DESTRUCTOR
2305  ***************************/
2306
2307 /*
2308  * This function is called when the library is unloaded and makes sure that
2309  * resources are freed.
2310  */
2311 void uwrap_destructor(void)
2312 {
2313         struct uwrap_thread *u = uwrap.ids;
2314
2315         UWRAP_LOCK_ALL;
2316
2317         while (u != NULL) {
2318                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2319
2320                 SAFE_FREE(u->groups);
2321                 SAFE_FREE(u);
2322
2323                 u = uwrap.ids;
2324         }
2325
2326
2327         if (uwrap.libc.handle != NULL) {
2328                 dlclose(uwrap.libc.handle);
2329         }
2330
2331         if (uwrap.libpthread.handle != NULL) {
2332                 dlclose(uwrap.libpthread.handle);
2333         }
2334
2335         UWRAP_UNLOCK_ALL;
2336 }