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