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