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