third_party:build: Test for the flags, recognized by Clang.
[samba.git] / third_party / uid_wrapper / uid_wrapper.c
1 /*
2  * Copyright (c) 2009      Andrew Tridgell
3  * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "config.h"
20
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <grp.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
32 #endif
33 #ifdef HAVE_SYSCALL_H
34 #include <syscall.h>
35 #endif
36 #include <dlfcn.h>
37
38 #include <pthread.h>
39
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
42 #else
43 # define UWRAP_THREAD
44 #endif
45
46 # define UWRAP_LOCK(m) do { \
47         pthread_mutex_lock(&( m ## _mutex)); \
48 } while(0)
49
50 # define UWRAP_UNLOCK(m) do { \
51         pthread_mutex_unlock(&( m ## _mutex)); \
52 } while(0)
53
54 /* 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         /*
949          * "Garbage collector" - Inspired by DESTRUCTOR.
950          * All threads (except one which called fork()) are dead now.. Dave
951          * That's what posix said...
952          */
953         while (u != NULL) {
954                 if (u == id) {
955                         /* Skip this item. */
956                         u = uwrap.ids->next;
957                         continue;
958                 }
959
960                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
961
962                 SAFE_FREE(u->groups);
963                 SAFE_FREE(u);
964
965                 u = uwrap.ids;
966         }
967
968         uwrap_export_ids(id);
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         env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1033         if (env != NULL && env[0] != '\0') {
1034                 char *endp = NULL;
1035                 long n;
1036
1037                 n = strtol(env, &endp, 10);
1038                 if (env == endp) {
1039                         ngroups = 0;
1040                 } else if (n > 0 && n < GROUP_MAX_COUNT) {
1041                         ngroups = (int)n;
1042                 }
1043                 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1044         }
1045
1046         if (ngroups > 0) {
1047                 int i = 0;
1048
1049                 id->ngroups = 0;
1050
1051                 free(id->groups);
1052                 id->groups = calloc(ngroups, sizeof(gid_t));
1053                 if (id->groups == NULL) {
1054                         UWRAP_LOG(UWRAP_LOG_ERROR,
1055                                   "Unable to allocate memory");
1056                         exit(-1);
1057                 }
1058
1059                 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1060                 if (env != NULL && env[0] != '\0') {
1061                         char *groups_str = NULL;
1062                         char *saveptr = NULL;
1063                         const char *p = NULL;
1064
1065                         groups_str = strdup(env);
1066                         if (groups_str == NULL) {
1067                                 exit(-1);
1068                         }
1069
1070                         p = strtok_r(groups_str, ",", &saveptr);
1071                         while (p != NULL) {
1072                                 id->groups[i] = strtol(p, (char **)NULL, 10);
1073                                 i++;
1074
1075                                 p = strtok_r(NULL, ",", &saveptr);
1076                         }
1077                         SAFE_FREE(groups_str);
1078                 }
1079
1080                 if (i != ngroups) {
1081                         UWRAP_LOG(UWRAP_LOG_ERROR,
1082                                   "ERROR: The number of groups (%u) passed, "
1083                                   "does not match the number of groups (%u) "
1084                                   "we parsed.",
1085                                   ngroups,
1086                                   i);
1087                         exit(-1);
1088                 }
1089
1090                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1091                 id->ngroups = ngroups;
1092         }
1093 }
1094
1095 static void uwrap_init(void)
1096 {
1097         const char *env;
1098
1099         UWRAP_LOCK(uwrap_id);
1100
1101         if (uwrap.initialised) {
1102                 struct uwrap_thread *id = uwrap_tls_id;
1103
1104                 if (uwrap.ids == NULL) {
1105                         UWRAP_UNLOCK(uwrap_id);
1106                         return;
1107                 }
1108
1109                 if (id == NULL) {
1110                         UWRAP_LOG(UWRAP_LOG_ERROR,
1111                                   "Invalid id for thread");
1112                         exit(-1);
1113                 }
1114
1115                 UWRAP_UNLOCK(uwrap_id);
1116                 return;
1117         }
1118
1119         UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1120
1121         uwrap.initialised = true;
1122
1123         env = getenv("UID_WRAPPER");
1124         if (env != NULL && env[0] == '1') {
1125                 const char *root = getenv("UID_WRAPPER_ROOT");
1126                 struct uwrap_thread *id;
1127
1128                 id = calloc(1, sizeof(struct uwrap_thread));
1129                 if (id == NULL) {
1130                         UWRAP_LOG(UWRAP_LOG_ERROR,
1131                                   "Unable to allocate memory for main id");
1132                         exit(-1);
1133                 }
1134
1135                 UWRAP_DLIST_ADD(uwrap.ids, id);
1136                 uwrap_tls_id = id;
1137
1138                 uwrap.myuid = libc_geteuid();
1139                 uwrap.mygid = libc_getegid();
1140
1141                 /* put us in one group */
1142                 if (root != NULL && root[0] == '1') {
1143                         id->ruid = id->euid = id->suid = 0;
1144                         id->rgid = id->egid = id->sgid = 0;
1145
1146                         id->groups = malloc(sizeof(gid_t) * 1);
1147                         if (id->groups == NULL) {
1148                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1149                                           "Unable to allocate memory");
1150                                 exit(-1);
1151                         }
1152
1153                         id->ngroups = 1;
1154                         id->groups[0] = 0;
1155
1156                 } else {
1157                         id->ruid = id->euid = id->suid = uwrap.myuid;
1158                         id->rgid = id->egid = id->sgid = uwrap.mygid;
1159
1160                         id->ngroups = libc_getgroups(0, NULL);
1161                         if (id->ngroups == -1) {
1162                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1163                                           "Unable to call libc_getgroups in uwrap_init.");
1164                                 exit(-1);
1165                         }
1166                         id->groups = malloc(sizeof(gid_t) * id->ngroups);
1167                         if (id->groups == NULL) {
1168                                 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1169                                 exit(-1);
1170                         }
1171                         if (libc_getgroups(id->ngroups, id->groups) == -1) {
1172                                 UWRAP_LOG(UWRAP_LOG_ERROR,
1173                                           "Unable to call libc_getgroups again in uwrap_init.");
1174                                 id->groups = 0;
1175                                 /*
1176                                  * Deallocation of uwrap.groups is handled by
1177                                  * library destructor.
1178                                  */
1179                                 exit(-1);
1180                         }
1181                 }
1182
1183                 uwrap_init_env(id);
1184
1185                 id->enabled = true;
1186
1187                 UWRAP_LOG(UWRAP_LOG_DEBUG,
1188                           "Enabled uid_wrapper as %s (real uid=%u)",
1189                           id->ruid == 0 ? "root" : "user",
1190                           (unsigned int)uwrap.myuid);
1191         }
1192
1193         UWRAP_UNLOCK(uwrap_id);
1194
1195         UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1196 }
1197
1198 bool uid_wrapper_enabled(void)
1199 {
1200         struct uwrap_thread *id = uwrap_tls_id;
1201         bool enabled;
1202
1203         if (id == NULL) {
1204                 return false;
1205         }
1206
1207         UWRAP_LOCK(uwrap_id);
1208         enabled = id->enabled;
1209         UWRAP_UNLOCK(uwrap_id);
1210
1211         return enabled;
1212 }
1213
1214 /*
1215  * UWRAP_SETxUID FUNCTIONS
1216  */
1217
1218 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1219 {
1220         struct uwrap_thread *id = uwrap_tls_id;
1221
1222         UWRAP_LOG(UWRAP_LOG_TRACE,
1223                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1224                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1225
1226         if (id->euid != 0) {
1227                 if (ruid != (uid_t)-1 &&
1228                     ruid != id->ruid &&
1229                     ruid != id->euid &&
1230                     ruid != id->suid) {
1231                         errno = EPERM;
1232                         return -1;
1233                 }
1234                 if (euid != (uid_t)-1 &&
1235                     euid != id->ruid &&
1236                     euid != id->euid &&
1237                     euid != id->suid) {
1238                         errno = EPERM;
1239                         return -1;
1240                 }
1241                 if (suid != (uid_t)-1 &&
1242                     suid != id->ruid &&
1243                     suid != id->euid &&
1244                     suid != id->suid) {
1245                         errno = EPERM;
1246                         return -1;
1247                 }
1248         }
1249
1250         return 0;
1251 }
1252
1253 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1254 {
1255         struct uwrap_thread *id = uwrap_tls_id;
1256         int rc;
1257
1258         UWRAP_LOG(UWRAP_LOG_TRACE,
1259                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1260                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1261
1262         rc = uwrap_setresuid_args(ruid, euid, suid);
1263         if (rc != 0) {
1264                 return rc;
1265         }
1266
1267         UWRAP_LOCK(uwrap_id);
1268
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         UWRAP_UNLOCK(uwrap_id);
1282
1283         return 0;
1284 }
1285
1286 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1287 {
1288         struct uwrap_thread *id = uwrap_tls_id;
1289         int rc;
1290
1291         UWRAP_LOG(UWRAP_LOG_TRACE,
1292                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1293                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1294
1295         rc = uwrap_setresuid_args(ruid, euid, suid);
1296         if (rc != 0) {
1297                 return rc;
1298         }
1299
1300         UWRAP_LOCK(uwrap_id);
1301
1302         for (id = uwrap.ids; id; id = id->next) {
1303                 if (ruid != (uid_t)-1) {
1304                         id->ruid = ruid;
1305                 }
1306
1307                 if (euid != (uid_t)-1) {
1308                         id->euid = euid;
1309                 }
1310
1311                 if (suid != (uid_t)-1) {
1312                         id->suid = suid;
1313                 }
1314         }
1315
1316         UWRAP_UNLOCK(uwrap_id);
1317
1318         return 0;
1319 }
1320
1321 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1322                                uid_t *_new_ruid,
1323                                uid_t *_new_euid,
1324                                uid_t *_new_suid)
1325 {
1326         struct uwrap_thread *id = uwrap_tls_id;
1327         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1328
1329         UWRAP_LOG(UWRAP_LOG_TRACE,
1330                   "ruid %d -> %d, euid %d -> %d",
1331                   id->ruid, ruid, id->euid, euid);
1332
1333         if (ruid != (uid_t)-1) {
1334                 new_ruid = ruid;
1335                 if (ruid != id->ruid &&
1336                     ruid != id->euid &&
1337                     id->euid != 0) {
1338                         errno = EPERM;
1339                         return -1;
1340                 }
1341         }
1342
1343         if (euid != (uid_t)-1) {
1344                 new_euid = euid;
1345                 if (euid != id->ruid &&
1346                     euid != id->euid &&
1347                     euid != id->suid &&
1348                     id->euid != 0) {
1349                         errno = EPERM;
1350                         return -1;
1351                 }
1352         }
1353
1354         if (ruid != (uid_t) -1 ||
1355             (euid != (uid_t)-1 && id->ruid != euid)) {
1356                 new_suid = new_euid;
1357         }
1358
1359         *_new_ruid = new_ruid;
1360         *_new_euid = new_euid;
1361         *_new_suid = new_suid;
1362
1363         return 0;
1364 }
1365
1366 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1367 {
1368         struct uwrap_thread *id = uwrap_tls_id;
1369         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1370         int rc;
1371
1372         UWRAP_LOG(UWRAP_LOG_TRACE,
1373                   "ruid %d -> %d, euid %d -> %d",
1374                   id->ruid, ruid, id->euid, euid);
1375
1376         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1377         if (rc != 0) {
1378                 return rc;
1379         }
1380
1381         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1382 }
1383
1384 #ifdef HAVE_SETREUID
1385 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1386 {
1387         struct uwrap_thread *id = uwrap_tls_id;
1388         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1389         int rc;
1390
1391         UWRAP_LOG(UWRAP_LOG_TRACE,
1392                   "ruid %d -> %d, euid %d -> %d",
1393                   id->ruid, ruid, id->euid, euid);
1394
1395         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1396         if (rc != 0) {
1397                 return rc;
1398         }
1399
1400         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1401 }
1402 #endif
1403
1404 static int uwrap_setuid_args(uid_t uid,
1405                              uid_t *new_ruid,
1406                              uid_t *new_euid,
1407                              uid_t *new_suid)
1408 {
1409         struct uwrap_thread *id = uwrap_tls_id;
1410
1411         UWRAP_LOG(UWRAP_LOG_TRACE,
1412                   "uid %d -> %d",
1413                   id->ruid, uid);
1414
1415         if (uid == (uid_t)-1) {
1416                 errno = EINVAL;
1417                 return -1;
1418         }
1419
1420         if (id->euid == 0) {
1421                 *new_suid = *new_ruid = uid;
1422         } else if (uid != id->ruid &&
1423                    uid != id->suid) {
1424                 errno = EPERM;
1425                 return -1;
1426         }
1427
1428         *new_euid = uid;
1429
1430         return 0;
1431 }
1432
1433 static int uwrap_setuid_thread(uid_t uid)
1434 {
1435         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1436         int rc;
1437
1438         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1439         if (rc != 0) {
1440                 return rc;
1441         }
1442
1443         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1444 }
1445
1446 static int uwrap_setuid(uid_t uid)
1447 {
1448         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1449         int rc;
1450
1451         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1452         if (rc != 0) {
1453                 return rc;
1454         }
1455
1456         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1457 }
1458
1459 /*
1460  * UWRAP_GETxUID FUNCTIONS
1461  */
1462
1463 #ifdef HAVE_GETRESUID
1464 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1465 {
1466         struct uwrap_thread *id = uwrap_tls_id;
1467
1468         UWRAP_LOCK(uwrap_id);
1469
1470         *ruid = id->ruid;
1471         *euid = id->euid;
1472         *suid = id->suid;
1473
1474         UWRAP_UNLOCK(uwrap_id);
1475
1476         return 0;
1477 }
1478 #endif
1479
1480 #ifdef HAVE_GETRESGID
1481 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1482 {
1483         struct uwrap_thread *id = uwrap_tls_id;
1484
1485         UWRAP_LOCK(uwrap_id);
1486
1487         *rgid = id->rgid;
1488         *egid = id->egid;
1489         *sgid = id->sgid;
1490
1491         UWRAP_UNLOCK(uwrap_id);
1492
1493         return 0;
1494 }
1495 #endif
1496
1497 /*
1498  * UWRAP_SETxGID FUNCTIONS
1499  */
1500
1501 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1502 {
1503         struct uwrap_thread *id = uwrap_tls_id;
1504
1505         UWRAP_LOG(UWRAP_LOG_TRACE,
1506                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1507                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1508
1509         if (id->euid != 0) {
1510                 if (rgid != (gid_t)-1 &&
1511                     rgid != id->rgid &&
1512                     rgid != id->egid &&
1513                     rgid != id->sgid) {
1514                         errno = EPERM;
1515                         return -1;
1516                 }
1517                 if (egid != (gid_t)-1 &&
1518                     egid != id->rgid &&
1519                     egid != id->egid &&
1520                     egid != id->sgid) {
1521                         errno = EPERM;
1522                         return -1;
1523                 }
1524                 if (sgid != (gid_t)-1 &&
1525                     sgid != id->rgid &&
1526                     sgid != id->egid &&
1527                     sgid != id->sgid) {
1528                         errno = EPERM;
1529                         return -1;
1530                 }
1531         }
1532
1533         return 0;
1534 }
1535
1536 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1537 {
1538         struct uwrap_thread *id = uwrap_tls_id;
1539         int rc;
1540
1541         UWRAP_LOG(UWRAP_LOG_TRACE,
1542                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1543                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1544
1545         rc = uwrap_setresgid_args(rgid, egid, sgid);
1546         if (rc != 0) {
1547                 return rc;
1548         }
1549
1550         UWRAP_LOCK(uwrap_id);
1551
1552         if (rgid != (gid_t)-1) {
1553                 id->rgid = rgid;
1554         }
1555
1556         if (egid != (gid_t)-1) {
1557                 id->egid = egid;
1558         }
1559
1560         if (sgid != (gid_t)-1) {
1561                 id->sgid = sgid;
1562         }
1563
1564         UWRAP_UNLOCK(uwrap_id);
1565
1566         return 0;
1567 }
1568
1569 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1570 {
1571         struct uwrap_thread *id = uwrap_tls_id;
1572         int rc;
1573
1574         UWRAP_LOG(UWRAP_LOG_TRACE,
1575                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1576                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1577
1578         rc = uwrap_setresgid_args(rgid, egid, sgid);
1579         if (rc != 0) {
1580                 return rc;
1581         }
1582
1583         UWRAP_LOCK(uwrap_id);
1584
1585         for (id = uwrap.ids; id; id = id->next) {
1586                 if (rgid != (gid_t)-1) {
1587                         id->rgid = rgid;
1588                 }
1589
1590                 if (egid != (gid_t)-1) {
1591                         id->egid = egid;
1592                 }
1593
1594                 if (sgid != (gid_t)-1) {
1595                         id->sgid = sgid;
1596                 }
1597         }
1598
1599         UWRAP_UNLOCK(uwrap_id);
1600
1601         return 0;
1602 }
1603
1604 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1605                                gid_t *_new_rgid,
1606                                gid_t *_new_egid,
1607                                gid_t *_new_sgid)
1608 {
1609         struct uwrap_thread *id = uwrap_tls_id;
1610         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1611
1612         UWRAP_LOG(UWRAP_LOG_TRACE,
1613                   "rgid %d -> %d, egid %d -> %d",
1614                   id->rgid, rgid, id->egid, egid);
1615
1616         if (rgid != (gid_t)-1) {
1617                 new_rgid = rgid;
1618                 if (rgid != id->rgid &&
1619                     rgid != id->egid &&
1620                     id->euid != 0) {
1621                         errno = EPERM;
1622                         return -1;
1623                 }
1624         }
1625
1626         if (egid != (gid_t)-1) {
1627                 new_egid = egid;
1628                 if (egid != id->rgid &&
1629                     egid != id->egid &&
1630                     egid != id->sgid &&
1631                     id->euid != 0) {
1632                         errno = EPERM;
1633                         return -1;
1634                 }
1635         }
1636
1637         if (rgid != (gid_t) -1 ||
1638             (egid != (gid_t)-1 && id->rgid != egid)) {
1639                 new_sgid = new_egid;
1640         }
1641
1642         *_new_rgid = new_rgid;
1643         *_new_egid = new_egid;
1644         *_new_sgid = new_sgid;
1645
1646         return 0;
1647 }
1648
1649 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1650 {
1651         struct uwrap_thread *id = uwrap_tls_id;
1652         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1653         int rc;
1654
1655         UWRAP_LOG(UWRAP_LOG_TRACE,
1656                   "rgid %d -> %d, egid %d -> %d",
1657                   id->rgid, rgid, id->egid, egid);
1658
1659         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1660         if (rc != 0) {
1661                 return rc;
1662         }
1663
1664         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1665 }
1666
1667 #ifdef HAVE_SETREGID
1668 static int uwrap_setregid(gid_t rgid, gid_t egid)
1669 {
1670         struct uwrap_thread *id = uwrap_tls_id;
1671         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1672         int rc;
1673
1674         UWRAP_LOG(UWRAP_LOG_TRACE,
1675                   "rgid %d -> %d, egid %d -> %d",
1676                   id->rgid, rgid, id->egid, egid);
1677
1678         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1679         if (rc != 0) {
1680                 return rc;
1681         }
1682
1683         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1684 }
1685 #endif
1686
1687 static int uwrap_setgid_args(gid_t gid,
1688                              gid_t *new_rgid,
1689                              gid_t *new_egid,
1690                              gid_t *new_sgid)
1691 {
1692         struct uwrap_thread *id = uwrap_tls_id;
1693
1694         UWRAP_LOG(UWRAP_LOG_TRACE,
1695                   "gid %d -> %d",
1696                   id->rgid, gid);
1697
1698         if (gid == (gid_t)-1) {
1699                 errno = EINVAL;
1700                 return -1;
1701         }
1702
1703         if (id->euid == 0) {
1704                 *new_sgid = *new_rgid = gid;
1705         } else if (gid != id->rgid &&
1706                    gid != id->sgid) {
1707                 errno = EPERM;
1708                 return -1;
1709         }
1710
1711         *new_egid = gid;
1712
1713         return 0;
1714 }
1715
1716 static int uwrap_setgid_thread(gid_t gid)
1717 {
1718         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1719         int rc;
1720
1721         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1722         if (rc != 0) {
1723                 return rc;
1724         }
1725
1726         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1727 }
1728
1729 static int uwrap_setgid(gid_t gid)
1730 {
1731         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1732         int rc;
1733
1734         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1735         if (rc != 0) {
1736                 return rc;
1737         }
1738
1739         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1740 }
1741
1742 /*
1743  * SETUID
1744  */
1745 int setuid(uid_t uid)
1746 {
1747         if (!uid_wrapper_enabled()) {
1748                 return libc_setuid(uid);
1749         }
1750
1751         uwrap_init();
1752         return uwrap_setuid(uid);
1753 }
1754
1755 #ifdef HAVE_SETEUID
1756 int seteuid(uid_t euid)
1757 {
1758         if (!uid_wrapper_enabled()) {
1759                 return libc_seteuid(euid);
1760         }
1761
1762         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1763         if (euid == (uid_t)-1) {
1764                 errno = EINVAL;
1765                 return -1;
1766         }
1767
1768         uwrap_init();
1769         return uwrap_setresuid(-1, euid, -1);
1770 }
1771 #endif
1772
1773 #ifdef HAVE_SETREUID
1774 int setreuid(uid_t ruid, uid_t euid)
1775 {
1776         if (!uid_wrapper_enabled()) {
1777                 return libc_setreuid(ruid, euid);
1778         }
1779
1780         uwrap_init();
1781         return uwrap_setreuid(ruid, euid);
1782 }
1783 #endif
1784
1785 #ifdef HAVE_SETRESUID
1786 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1787 {
1788         if (!uid_wrapper_enabled()) {
1789                 return libc_setresuid(ruid, euid, suid);
1790         }
1791
1792         uwrap_init();
1793         return uwrap_setresuid(ruid, euid, suid);
1794 }
1795 #endif
1796
1797 #ifdef HAVE_GETRESUID
1798 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1799 {
1800         if (!uid_wrapper_enabled()) {
1801                 return libc_getresuid(ruid, euid, suid);
1802         }
1803
1804         uwrap_init();
1805         return uwrap_getresuid(ruid, euid, suid);
1806 }
1807 #endif
1808
1809 /*
1810  * GETUID
1811  */
1812 static uid_t uwrap_getuid(void)
1813 {
1814         struct uwrap_thread *id = uwrap_tls_id;
1815         uid_t uid;
1816
1817         UWRAP_LOCK(uwrap_id);
1818         uid = id->ruid;
1819         UWRAP_UNLOCK(uwrap_id);
1820
1821         return uid;
1822 }
1823
1824 uid_t getuid(void)
1825 {
1826         if (!uid_wrapper_enabled()) {
1827                 return libc_getuid();
1828         }
1829
1830         uwrap_init();
1831         return uwrap_getuid();
1832 }
1833
1834 /*
1835  * GETEUID
1836  */
1837 static uid_t uwrap_geteuid(void)
1838 {
1839         const char *env = getenv("UID_WRAPPER_MYUID");
1840         struct uwrap_thread *id = uwrap_tls_id;
1841         uid_t uid;
1842
1843         UWRAP_LOCK(uwrap_id);
1844         uid = id->euid;
1845         UWRAP_UNLOCK(uwrap_id);
1846
1847         /* Disable root and return myuid */
1848         if (env != NULL && env[0] == '1') {
1849                 uid = uwrap.myuid;
1850         }
1851
1852         return uid;
1853 }
1854
1855 uid_t geteuid(void)
1856 {
1857         if (!uid_wrapper_enabled()) {
1858                 return libc_geteuid();
1859         }
1860
1861         uwrap_init();
1862         return uwrap_geteuid();
1863 }
1864
1865 /*
1866  * SETGID
1867  */
1868 int setgid(gid_t gid)
1869 {
1870         if (!uid_wrapper_enabled()) {
1871                 return libc_setgid(gid);
1872         }
1873
1874         uwrap_init();
1875         return uwrap_setgid(gid);
1876 }
1877
1878 #ifdef HAVE_SETEGID
1879 int setegid(gid_t egid)
1880 {
1881         if (!uid_wrapper_enabled()) {
1882                 return libc_setegid(egid);
1883         }
1884
1885         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1886         if (egid == (gid_t)-1) {
1887                 errno = EINVAL;
1888                 return -1;
1889         }
1890
1891         uwrap_init();
1892         return uwrap_setresgid(-1, egid, -1);
1893 }
1894 #endif
1895
1896 #ifdef HAVE_SETREGID
1897 int setregid(gid_t rgid, gid_t egid)
1898 {
1899         if (!uid_wrapper_enabled()) {
1900                 return libc_setregid(rgid, egid);
1901         }
1902
1903         uwrap_init();
1904         return uwrap_setregid(rgid, egid);
1905 }
1906 #endif
1907
1908 #ifdef HAVE_SETRESGID
1909 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1910 {
1911         if (!uid_wrapper_enabled()) {
1912                 return libc_setresgid(rgid, egid, sgid);
1913         }
1914
1915         uwrap_init();
1916         return uwrap_setresgid(rgid, egid, sgid);
1917 }
1918 #endif
1919
1920 #ifdef HAVE_GETRESGID
1921 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1922 {
1923         if (!uid_wrapper_enabled()) {
1924                 return libc_getresgid(rgid, egid, sgid);
1925         }
1926
1927         uwrap_init();
1928         return uwrap_getresgid(rgid, egid, sgid);
1929 }
1930 #endif
1931
1932 /*
1933  * GETGID
1934  */
1935 static gid_t uwrap_getgid(void)
1936 {
1937         struct uwrap_thread *id = uwrap_tls_id;
1938         gid_t gid;
1939
1940         UWRAP_LOCK(uwrap_id);
1941         gid = id->rgid;
1942         UWRAP_UNLOCK(uwrap_id);
1943
1944         return gid;
1945 }
1946
1947 gid_t getgid(void)
1948 {
1949         if (!uid_wrapper_enabled()) {
1950                 return libc_getgid();
1951         }
1952
1953         uwrap_init();
1954         return uwrap_getgid();
1955 }
1956
1957 /*
1958  * GETEGID
1959  */
1960 static uid_t uwrap_getegid(void)
1961 {
1962         struct uwrap_thread *id = uwrap_tls_id;
1963         gid_t gid;
1964
1965         UWRAP_LOCK(uwrap_id);
1966         gid = id->egid;
1967         UWRAP_UNLOCK(uwrap_id);
1968
1969         return gid;
1970 }
1971
1972 uid_t getegid(void)
1973 {
1974         if (!uid_wrapper_enabled()) {
1975                 return libc_getegid();
1976         }
1977
1978         uwrap_init();
1979         return uwrap_getegid();
1980 }
1981
1982 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1983 {
1984         struct uwrap_thread *id = uwrap_tls_id;
1985         int rc = -1;
1986
1987         UWRAP_LOCK(uwrap_id);
1988
1989         if (size == 0) {
1990                 SAFE_FREE(id->groups);
1991                 id->ngroups = 0;
1992         } else if (size > 0) {
1993                 gid_t *tmp;
1994
1995                 tmp = realloc(id->groups, sizeof(gid_t) * size);
1996                 if (tmp == NULL) {
1997                         errno = ENOMEM;
1998                         goto out;
1999                 }
2000                 id->groups = tmp;
2001                 id->ngroups = size;
2002                 memcpy(id->groups, list, size * sizeof(gid_t));
2003         }
2004
2005         rc = 0;
2006 out:
2007         UWRAP_UNLOCK(uwrap_id);
2008
2009         return rc;
2010 }
2011
2012 static int uwrap_setgroups(size_t size, const gid_t *list)
2013 {
2014         struct uwrap_thread *id;
2015         int rc = -1;
2016
2017         UWRAP_LOCK(uwrap_id);
2018
2019         if (size == 0) {
2020                 for (id = uwrap.ids; id; id = id->next) {
2021                         SAFE_FREE(id->groups);
2022                         id->ngroups = 0;
2023
2024                 }
2025         } else if (size > 0) {
2026                 gid_t *tmp;
2027
2028                 for (id = uwrap.ids; id; id = id->next) {
2029                         tmp = realloc(id->groups, sizeof(gid_t) * size);
2030                         if (tmp == NULL) {
2031                                 errno = ENOMEM;
2032                                 goto out;
2033                         }
2034                         id->groups = tmp;
2035
2036                         id->ngroups = size;
2037                         memcpy(id->groups, list, size * sizeof(gid_t));
2038                 }
2039         }
2040
2041         rc = 0;
2042 out:
2043         UWRAP_UNLOCK(uwrap_id);
2044
2045         return rc;
2046 }
2047
2048 #ifdef HAVE_SETGROUPS_INT
2049 int setgroups(int size, const gid_t *list)
2050 #else
2051 int setgroups(size_t size, const gid_t *list)
2052 #endif
2053 {
2054         if (!uid_wrapper_enabled()) {
2055                 return libc_setgroups(size, list);
2056         }
2057
2058         uwrap_init();
2059         return uwrap_setgroups(size, list);
2060 }
2061
2062 static int uwrap_getgroups(int size, gid_t *list)
2063 {
2064         struct uwrap_thread *id = uwrap_tls_id;
2065         int ngroups;
2066
2067         UWRAP_LOCK(uwrap_id);
2068         ngroups = id->ngroups;
2069
2070         if (size > ngroups) {
2071                 size = ngroups;
2072         }
2073         if (size == 0) {
2074                 goto out;
2075         }
2076         if (size < ngroups) {
2077                 errno = EINVAL;
2078                 ngroups = -1;
2079         }
2080         memcpy(list, id->groups, size * sizeof(gid_t));
2081
2082 out:
2083         UWRAP_UNLOCK(uwrap_id);
2084
2085         return ngroups;
2086 }
2087
2088 int getgroups(int size, gid_t *list)
2089 {
2090         if (!uid_wrapper_enabled()) {
2091                 return libc_getgroups(size, list);
2092         }
2093
2094         uwrap_init();
2095         return uwrap_getgroups(size, list);
2096 }
2097
2098 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2099     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2100 static long int uwrap_syscall (long int sysno, va_list vp)
2101 {
2102         long int rc;
2103
2104         switch (sysno) {
2105                 /* gid */
2106 #ifdef __alpha__
2107                 case SYS_getxgid:
2108 #else
2109                 case SYS_getgid:
2110 #endif
2111 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2112                 case SYS_getgid32:
2113 #endif
2114                         {
2115                                 rc = uwrap_getgid();
2116                         }
2117                         break;
2118 #ifdef SYS_getegid
2119                 case SYS_getegid:
2120 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2121                 case SYS_getegid32:
2122 #endif
2123                         {
2124                                 rc = uwrap_getegid();
2125                         }
2126                         break;
2127 #endif /* SYS_getegid */
2128                 case SYS_setgid:
2129 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2130                 case SYS_setgid32:
2131 #endif
2132                         {
2133                                 gid_t gid = (gid_t) va_arg(vp, gid_t);
2134
2135                                 rc = uwrap_setgid_thread(gid);
2136                         }
2137                         break;
2138                 case SYS_setregid:
2139 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2140                 case SYS_setregid32:
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
2146                                 rc = uwrap_setregid_thread(rgid, egid);
2147                         }
2148                         break;
2149 #ifdef SYS_setresgid
2150                 case SYS_setresgid:
2151 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2152                 case SYS_setresgid32:
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_setresgid_thread(rgid, egid, sgid);
2160                         }
2161                         break;
2162 #endif /* SYS_setresgid */
2163 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2164                 case SYS_getresgid:
2165 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2166                 case SYS_getresgid32:
2167 #endif
2168                         {
2169                                 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2170                                 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2171                                 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2172
2173                                 rc = uwrap_getresgid(rgid, egid, sgid);
2174                         }
2175                         break;
2176 #endif /* SYS_getresgid && HAVE_GETRESGID */
2177
2178                 /* uid */
2179 #ifdef __alpha__
2180                 case SYS_getxuid:
2181 #else
2182                 case SYS_getuid:
2183 #endif
2184 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2185                 case SYS_getuid32:
2186 #endif
2187                         {
2188                                 rc = uwrap_getuid();
2189                         }
2190                         break;
2191 #ifdef SYS_geteuid
2192                 case SYS_geteuid:
2193 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2194                 case SYS_geteuid32:
2195 #endif
2196                         {
2197                                 rc = uwrap_geteuid();
2198                         }
2199                         break;
2200 #endif /* SYS_geteuid */
2201                 case SYS_setuid:
2202 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2203                 case SYS_setuid32:
2204 #endif
2205                         {
2206                                 uid_t uid = (uid_t) va_arg(vp, uid_t);
2207
2208                                 rc = uwrap_setuid_thread(uid);
2209                         }
2210                         break;
2211                 case SYS_setreuid:
2212 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2213                 case SYS_setreuid32:
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
2219                                 rc = uwrap_setreuid_thread(ruid, euid);
2220                         }
2221                         break;
2222 #ifdef SYS_setresuid
2223                 case SYS_setresuid:
2224 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2225                 case SYS_setresuid32:
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_setresuid_thread(ruid, euid, suid);
2233                         }
2234                         break;
2235 #endif /* SYS_setresuid */
2236 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2237                 case SYS_getresuid:
2238 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2239                 case SYS_getresuid32:
2240 #endif
2241                         {
2242                                 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2243                                 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2244                                 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2245
2246                                 rc = uwrap_getresuid(ruid, euid, suid);
2247                         }
2248                         break;
2249 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2250                 /* groups */
2251                 case SYS_setgroups:
2252 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2253                 case SYS_setgroups32:
2254 #endif
2255                         {
2256                                 size_t size = (size_t) va_arg(vp, size_t);
2257                                 gid_t *list = (gid_t *) va_arg(vp, int *);
2258
2259                                 rc = uwrap_setgroups_thread(size, list);
2260                         }
2261                         break;
2262                 default:
2263                         UWRAP_LOG(UWRAP_LOG_DEBUG,
2264                                   "UID_WRAPPER calling non-wrapped syscall %lu",
2265                                   sysno);
2266
2267                         rc = libc_vsyscall(sysno, vp);
2268                         break;
2269         }
2270
2271         return rc;
2272 }
2273
2274 #ifdef HAVE_SYSCALL
2275 #ifdef HAVE_SYSCALL_INT
2276 int syscall (int sysno, ...)
2277 #else
2278 long int syscall (long int sysno, ...)
2279 #endif
2280 {
2281 #ifdef HAVE_SYSCALL_INT
2282         int rc;
2283 #else
2284         long int rc;
2285 #endif
2286         va_list va;
2287
2288         va_start(va, sysno);
2289
2290         if (!uid_wrapper_enabled()) {
2291                 rc = libc_vsyscall(sysno, va);
2292                 va_end(va);
2293                 return rc;
2294         }
2295
2296         uwrap_init();
2297         rc = uwrap_syscall(sysno, va);
2298         va_end(va);
2299
2300         return rc;
2301 }
2302 #endif /* HAVE_SYSCALL */
2303 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2304
2305 /****************************
2306  * CONSTRUCTOR
2307  ***************************/
2308
2309 void uwrap_constructor(void)
2310 {
2311         char *glibc_malloc_lock_bug;
2312
2313         /*
2314          * This is a workaround for a bug in glibc < 2.24:
2315          *
2316          * The child handler for the malloc() function is called and locks the
2317          * mutex. Then our child handler is called and we try to call setenv().
2318          * setenv() wants to malloc and tries to aquire the lock for malloc and
2319          * we end up in a deadlock.
2320          *
2321          * So as a workaround we need to call malloc once before we setup the
2322          * handlers.
2323          *
2324          * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2325          */
2326         glibc_malloc_lock_bug = malloc(1);
2327         if (glibc_malloc_lock_bug == NULL) {
2328                 exit(-1);
2329         }
2330         glibc_malloc_lock_bug[0] = '\0';
2331
2332         /*
2333         * If we hold a lock and the application forks, then the child
2334         * is not able to unlock the mutex and we are in a deadlock.
2335         * This should prevent such deadlocks.
2336         */
2337         pthread_atfork(&uwrap_thread_prepare,
2338                        &uwrap_thread_parent,
2339                        &uwrap_thread_child);
2340
2341         free(glibc_malloc_lock_bug);
2342
2343         /* Here is safe place to call uwrap_init() and initialize data
2344          * for main process.
2345          */
2346         uwrap_init();
2347 }
2348
2349 /****************************
2350  * DESTRUCTOR
2351  ***************************/
2352
2353 /*
2354  * This function is called when the library is unloaded and makes sure that
2355  * resources are freed.
2356  */
2357 void uwrap_destructor(void)
2358 {
2359         struct uwrap_thread *u = uwrap.ids;
2360
2361         UWRAP_LOCK_ALL;
2362
2363         while (u != NULL) {
2364                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2365
2366                 SAFE_FREE(u->groups);
2367                 SAFE_FREE(u);
2368
2369                 u = uwrap.ids;
2370         }
2371
2372
2373         if (uwrap.libc.handle != NULL) {
2374                 dlclose(uwrap.libc.handle);
2375         }
2376
2377         if (uwrap.libpthread.handle != NULL) {
2378                 dlclose(uwrap.libpthread.handle);
2379         }
2380
2381         UWRAP_UNLOCK_ALL;
2382 }