uwrap: Allow setresgid calls only for privileged users
[uid_wrapper.git] / src / uid_wrapper.c
1 /*
2  * Copyright (c) 2009      Andrew Tridgell
3  * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "config.h"
20
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <grp.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
32 #endif
33 #ifdef HAVE_SYSCALL_H
34 #include <syscall.h>
35 #endif
36 #include <dlfcn.h>
37
38 #include <pthread.h>
39
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
42 #else
43 # define UWRAP_THREAD
44 #endif
45
46 # define UWRAP_LOCK(m) do { \
47         pthread_mutex_lock(&( m ## _mutex)); \
48 } while(0)
49
50 # define UWRAP_UNLOCK(m) do { \
51         pthread_mutex_unlock(&( m ## _mutex)); \
52 } while(0)
53
54 /* Add new global locks here please */
55 # define UWRAP_LOCK_ALL \
56         UWRAP_LOCK(uwrap_id); \
57         UWRAP_LOCK(libc_symbol_binding); \
58         UWRAP_LOCK(libpthread_symbol_binding)
59
60 # define UWRAP_UNLOCK_ALL \
61         UWRAP_UNLOCK(libpthread_symbol_binding); \
62         UWRAP_UNLOCK(libc_symbol_binding); \
63         UWRAP_UNLOCK(uwrap_id)
64
65 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
66 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
67 #else
68 #define CONSTRUCTOR_ATTRIBUTE
69 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
70
71 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
72 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
73 #else
74 #define DESTRUCTOR_ATTRIBUTE
75 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
76
77 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
78 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
79 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
80 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
81 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
82
83 /* GCC have printf type attribute check. */
84 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
85 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
86 #else
87 #define PRINTF_ATTRIBUTE(a,b)
88 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
89
90 #define UWRAP_DLIST_ADD(list,item) do { \
91         if (!(list)) { \
92                 (item)->prev    = NULL; \
93                 (item)->next    = NULL; \
94                 (list)          = (item); \
95         } else { \
96                 (item)->prev    = NULL; \
97                 (item)->next    = (list); \
98                 (list)->prev    = (item); \
99                 (list)          = (item); \
100         } \
101 } while (0)
102
103 #define UWRAP_DLIST_REMOVE(list,item) do { \
104         if ((list) == (item)) { \
105                 (list)          = (item)->next; \
106                 if (list) { \
107                         (list)->prev    = NULL; \
108                 } \
109         } else { \
110                 if ((item)->prev) { \
111                         (item)->prev->next      = (item)->next; \
112                 } \
113                 if ((item)->next) { \
114                         (item)->next->prev      = (item)->prev; \
115                 } \
116         } \
117         (item)->prev    = NULL; \
118         (item)->next    = NULL; \
119 } while (0)
120
121 #ifndef SAFE_FREE
122 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
123 #endif
124
125 /*****************
126  * LOGGING
127  *****************/
128
129 enum uwrap_dbglvl_e {
130         UWRAP_LOG_ERROR = 0,
131         UWRAP_LOG_WARN,
132         UWRAP_LOG_DEBUG,
133         UWRAP_LOG_TRACE
134 };
135
136 #ifdef NDEBUG
137 # define UWRAP_LOG(...)
138 #else /* NDEBUG */
139 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
140 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
141
142 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
143 {
144         char buffer[1024];
145         va_list va;
146         const char *d;
147         unsigned int lvl = 0;
148
149         d = getenv("UID_WRAPPER_DEBUGLEVEL");
150         if (d != NULL) {
151                 lvl = atoi(d);
152         }
153
154         va_start(va, format);
155         vsnprintf(buffer, sizeof(buffer), format, va);
156         va_end(va);
157
158         if (lvl >= dbglvl) {
159                 const char *prefix;
160                 switch (dbglvl) {
161                         case UWRAP_LOG_ERROR:
162                                 prefix = "UWRAP_ERROR";
163                                 break;
164                         case UWRAP_LOG_WARN:
165                                 prefix = "UWRAP_WARN";
166                                 break;
167                         case UWRAP_LOG_DEBUG:
168                                 prefix = "UWRAP_DEBUG";
169                                 break;
170                         case UWRAP_LOG_TRACE:
171                                 prefix = "UWRAP_TRACE";
172                                 break;
173                 }
174
175                 fprintf(stderr,
176                         "%s(%d) - %s: %s\n",
177                         prefix,
178                         (int)getpid(),
179                         function,
180                         buffer);
181         }
182 }
183 #endif /* NDEBUG */
184
185 /*****************
186  * LIBC
187  *****************/
188
189 #define LIBC_NAME "libc.so"
190
191 typedef int (*__libc_setuid)(uid_t uid);
192
193 typedef uid_t (*__libc_getuid)(void);
194
195 #ifdef HAVE_SETEUID
196 typedef int (*__libc_seteuid)(uid_t euid);
197 #endif
198
199 #ifdef HAVE_SETREUID
200 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
201 #endif
202
203 #ifdef HAVE_SETRESUID
204 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
205 #endif
206
207 #ifdef HAVE_GETRESUID
208 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
209 #endif
210
211 typedef uid_t (*__libc_geteuid)(void);
212
213 typedef int (*__libc_setgid)(gid_t gid);
214
215 typedef gid_t (*__libc_getgid)(void);
216
217 #ifdef HAVE_SETEGID
218 typedef int (*__libc_setegid)(uid_t egid);
219 #endif
220
221 #ifdef HAVE_SETREGID
222 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
223 #endif
224
225 #ifdef HAVE_SETRESGID
226 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
227 #endif
228
229 #ifdef HAVE_GETRESGID
230 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
231 #endif
232
233 typedef gid_t (*__libc_getegid)(void);
234
235 typedef int (*__libc_getgroups)(int size, gid_t list[]);
236
237 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
238
239 #ifdef HAVE_SYSCALL
240 typedef long int (*__libc_syscall)(long int sysno, ...);
241 #endif
242
243 #define UWRAP_SYMBOL_ENTRY(i) \
244         union { \
245                 __libc_##i f; \
246                 void *obj; \
247         } _libc_##i
248
249 struct uwrap_libc_symbols {
250         UWRAP_SYMBOL_ENTRY(setuid);
251         UWRAP_SYMBOL_ENTRY(getuid);
252 #ifdef HAVE_SETEUID
253         UWRAP_SYMBOL_ENTRY(seteuid);
254 #endif
255 #ifdef HAVE_SETREUID
256         UWRAP_SYMBOL_ENTRY(setreuid);
257 #endif
258 #ifdef HAVE_SETRESUID
259         UWRAP_SYMBOL_ENTRY(setresuid);
260 #endif
261 #ifdef HAVE_GETRESUID
262         UWRAP_SYMBOL_ENTRY(getresuid);
263 #endif
264         UWRAP_SYMBOL_ENTRY(geteuid);
265         UWRAP_SYMBOL_ENTRY(setgid);
266         UWRAP_SYMBOL_ENTRY(getgid);
267 #ifdef HAVE_SETEGID
268         UWRAP_SYMBOL_ENTRY(setegid);
269 #endif
270 #ifdef HAVE_SETREGID
271         UWRAP_SYMBOL_ENTRY(setregid);
272 #endif
273 #ifdef HAVE_SETRESGID
274         UWRAP_SYMBOL_ENTRY(setresgid);
275 #endif
276 #ifdef HAVE_GETRESGID
277         UWRAP_SYMBOL_ENTRY(getresgid);
278 #endif
279         UWRAP_SYMBOL_ENTRY(getegid);
280         UWRAP_SYMBOL_ENTRY(getgroups);
281         UWRAP_SYMBOL_ENTRY(setgroups);
282 #ifdef HAVE_SYSCALL
283         UWRAP_SYMBOL_ENTRY(syscall);
284 #endif
285 };
286 #undef UWRAP_SYMBOL_ENTRY
287
288 /*****************
289  * LIBPTHREAD
290  *****************/
291 /* Yeah... I'm pig. I overloading macro here... So what? */
292 #define UWRAP_SYMBOL_ENTRY(i) \
293         union { \
294                 __libpthread_##i f; \
295                 void *obj; \
296         } _libpthread_##i
297
298 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
299                                     const pthread_attr_t *attr,
300                                     void *(*start_routine) (void *),
301                                     void *arg);
302 typedef void (*__libpthread_pthread_exit)(void *retval);
303
304 struct uwrap_libpthread_symbols {
305         UWRAP_SYMBOL_ENTRY(pthread_create);
306         UWRAP_SYMBOL_ENTRY(pthread_exit);
307 };
308 #undef UWRAP_SYMBOL_ENTRY
309
310 /*
311  * We keep the virtualised euid/egid/groups information here
312  */
313 struct uwrap_thread {
314         bool enabled;
315
316         uid_t ruid;
317         uid_t euid;
318         uid_t suid;
319
320         gid_t rgid;
321         gid_t egid;
322         gid_t sgid;
323
324         int ngroups;
325         gid_t *groups;
326
327         struct uwrap_thread *next;
328         struct uwrap_thread *prev;
329 };
330
331 struct uwrap {
332         struct {
333                 void *handle;
334                 struct uwrap_libc_symbols symbols;
335         } libc;
336
337         struct {
338                 void *handle;
339                 struct uwrap_libpthread_symbols symbols;
340         } libpthread;
341
342         bool initialised;
343
344         /* Real uid and gid of user who run uid wrapper */
345         uid_t myuid;
346         gid_t mygid;
347
348         struct uwrap_thread *ids;
349 };
350
351 static struct uwrap uwrap;
352
353 /* Shortcut to the list item */
354 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
355
356 /* The mutex or accessing the id */
357 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
358
359 /* The mutex for accessing the global libc.symbols */
360 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
361
362 /* The mutex for accessing the global libpthread.symbols */
363 static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
364
365 /*********************************************************
366  * UWRAP PROTOTYPES
367  *********************************************************/
368
369 bool uid_wrapper_enabled(void);
370 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
371 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
372
373 /*********************************************************
374  * UWRAP LIBC LOADER FUNCTIONS
375  *********************************************************/
376
377 enum uwrap_lib {
378     UWRAP_LIBC,
379     UWRAP_LIBNSL,
380     UWRAP_LIBSOCKET,
381     UWRAP_LIBPTHREAD,
382 };
383
384 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
385 {
386         int flags = RTLD_LAZY;
387         void *handle = NULL;
388         int i;
389
390 #ifdef RTLD_DEEPBIND
391         flags |= RTLD_DEEPBIND;
392 #endif
393
394         switch (lib) {
395         case UWRAP_LIBNSL:
396                 /* FALL TROUGH */
397         case UWRAP_LIBSOCKET:
398                 /* FALL TROUGH */
399         case UWRAP_LIBC:
400                 handle = uwrap.libc.handle;
401                 if (handle == NULL) {
402                         for (i = 10; i >= 0; i--) {
403                                 char soname[256] = {0};
404
405                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
406                                 handle = dlopen(soname, flags);
407                                 if (handle != NULL) {
408                                         break;
409                                 }
410                         }
411
412                         uwrap.libc.handle = handle;
413                 }
414                 break;
415         case UWRAP_LIBPTHREAD:
416                 handle = uwrap.libpthread.handle;
417                 if (handle == NULL) {
418                         handle = dlopen("libpthread.so.0", flags);
419                         if (handle != NULL) {
420                                 break;
421                         }
422                 }
423                 break;
424         }
425
426         if (handle == NULL) {
427 #ifdef RTLD_NEXT
428                 handle = uwrap.libc.handle = RTLD_NEXT;
429 #else
430                 fprintf(stderr,
431                         "Failed to dlopen library: %s\n",
432                         dlerror());
433                 exit(-1);
434 #endif
435         }
436
437         return handle;
438 }
439
440 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
441 {
442         void *handle;
443         void *func;
444
445         handle = uwrap_load_lib_handle(lib);
446
447         func = dlsym(handle, fn_name);
448         if (func == NULL) {
449                 fprintf(stderr,
450                         "Failed to find %s: %s\n",
451                         fn_name, dlerror());
452                 exit(-1);
453         }
454
455         return func;
456 }
457
458 #define uwrap_bind_symbol_libc(sym_name) \
459         UWRAP_LOCK(libc_symbol_binding); \
460         if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
461                 uwrap.libc.symbols._libc_##sym_name.obj = \
462                         _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
463         } \
464         UWRAP_UNLOCK(libc_symbol_binding)
465
466 #define uwrap_bind_symbol_libpthread(sym_name) \
467         UWRAP_LOCK(libpthread_symbol_binding); \
468         if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
469                 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
470                         _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
471         } \
472         UWRAP_UNLOCK(libpthread_symbol_binding)
473
474 /*
475  * IMPORTANT
476  *
477  * Functions expeciall from libc need to be loaded individually, you can't load
478  * all at once or gdb will segfault at startup. The same applies to valgrind and
479  * has probably something todo with with the linker.
480  * So we need load each function at the point it is called the first time.
481  */
482 static int libc_setuid(uid_t uid)
483 {
484         uwrap_bind_symbol_libc(setuid);
485
486         return uwrap.libc.symbols._libc_setuid.f(uid);
487 }
488
489 static uid_t libc_getuid(void)
490 {
491         uwrap_bind_symbol_libc(getuid);
492
493         return uwrap.libc.symbols._libc_getuid.f();
494 }
495
496 #ifdef HAVE_SETEUID
497 static int libc_seteuid(uid_t euid)
498 {
499         uwrap_bind_symbol_libc(seteuid);
500
501         return uwrap.libc.symbols._libc_seteuid.f(euid);
502 }
503 #endif
504
505 #ifdef HAVE_SETREUID
506 static int libc_setreuid(uid_t ruid, uid_t euid)
507 {
508         uwrap_bind_symbol_libc(setreuid);
509
510         return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
511 }
512 #endif
513
514 #ifdef HAVE_SETRESUID
515 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
516 {
517         uwrap_bind_symbol_libc(setresuid);
518
519         return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
520 }
521 #endif
522
523 #ifdef HAVE_GETRESUID
524 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
525 {
526         uwrap_bind_symbol_libc(getresuid);
527
528         return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
529 }
530 #endif
531
532 static uid_t libc_geteuid(void)
533 {
534         uwrap_bind_symbol_libc(geteuid);
535
536         return uwrap.libc.symbols._libc_geteuid.f();
537 }
538
539 static int libc_setgid(gid_t gid)
540 {
541         uwrap_bind_symbol_libc(setgid);
542
543         return uwrap.libc.symbols._libc_setgid.f(gid);
544 }
545
546 static gid_t libc_getgid(void)
547 {
548         uwrap_bind_symbol_libc(getgid);
549
550         return uwrap.libc.symbols._libc_getgid.f();
551 }
552
553 #ifdef HAVE_SETEGID
554 static int libc_setegid(gid_t egid)
555 {
556         uwrap_bind_symbol_libc(setegid);
557
558         return uwrap.libc.symbols._libc_setegid.f(egid);
559 }
560 #endif
561
562 #ifdef HAVE_SETREGID
563 static int libc_setregid(gid_t rgid, gid_t egid)
564 {
565         uwrap_bind_symbol_libc(setregid);
566
567         return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
568 }
569 #endif
570
571 #ifdef HAVE_SETRESGID
572 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
573 {
574         uwrap_bind_symbol_libc(setresgid);
575
576         return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
577 }
578 #endif
579
580 #ifdef HAVE_GETRESGID
581 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
582 {
583         uwrap_bind_symbol_libc(setresgid);
584
585         return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
586 }
587 #endif
588
589 static gid_t libc_getegid(void)
590 {
591         uwrap_bind_symbol_libc(getegid);
592
593         return uwrap.libc.symbols._libc_getegid.f();
594 }
595
596 static int libc_getgroups(int size, gid_t list[])
597 {
598         uwrap_bind_symbol_libc(getgroups);
599
600         return uwrap.libc.symbols._libc_getgroups.f(size, list);
601 }
602
603 static int libc_setgroups(size_t size, const gid_t *list)
604 {
605         uwrap_bind_symbol_libc(setgroups);
606
607         return uwrap.libc.symbols._libc_setgroups.f(size, list);
608 }
609
610 #ifdef HAVE_SYSCALL
611 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
612 static long int libc_vsyscall(long int sysno, va_list va)
613 {
614         long int args[8];
615         long int rc;
616         int i;
617
618         uwrap_bind_symbol_libc(syscall);
619
620         for (i = 0; i < 8; i++) {
621                 args[i] = va_arg(va, long int);
622         }
623
624         rc = uwrap.libc.symbols._libc_syscall.f(sysno,
625                                           args[0],
626                                           args[1],
627                                           args[2],
628                                           args[3],
629                                           args[4],
630                                           args[5],
631                                           args[6],
632                                           args[7]);
633
634         return rc;
635 }
636 #endif
637
638 /*
639  * This part is "optimistic".
640  * Thread can ends without pthread_exit call.
641  */
642 static void libpthread_pthread_exit(void *retval)
643 {
644         uwrap_bind_symbol_libpthread(pthread_exit);
645
646         uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
647 }
648
649 static void uwrap_pthread_exit(void *retval)
650 {
651         struct uwrap_thread *id = uwrap_tls_id;
652
653         UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
654
655         UWRAP_LOCK(uwrap_id);
656         if (id == NULL) {
657                 UWRAP_UNLOCK(uwrap_id);
658                 libpthread_pthread_exit(retval);
659                 return;
660         }
661
662         UWRAP_DLIST_REMOVE(uwrap.ids, id);
663         SAFE_FREE(id->groups);
664         SAFE_FREE(id);
665         uwrap_tls_id = NULL;
666
667         UWRAP_UNLOCK(uwrap_id);
668
669         libpthread_pthread_exit(retval);
670 }
671
672 void pthread_exit(void *retval)
673 {
674         if (!uid_wrapper_enabled()) {
675                 libpthread_pthread_exit(retval);
676         };
677
678         uwrap_pthread_exit(retval);
679
680         /* Calm down gcc warning. */
681         exit(666);
682 }
683
684 static int libpthread_pthread_create(pthread_t *thread,
685                                 const pthread_attr_t *attr,
686                                 void *(*start_routine) (void *),
687                                 void *arg)
688 {
689         uwrap_bind_symbol_libpthread(pthread_create);
690         return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
691                                                                      attr,
692                                                                      start_routine,
693                                                                      arg);
694 }
695
696 struct uwrap_pthread_create_args {
697         struct uwrap_thread *id;
698         void *(*start_routine) (void *);
699         void *arg;
700 };
701
702 static void *uwrap_pthread_create_start(void *_a)
703 {
704         struct uwrap_pthread_create_args *a =
705                 (struct uwrap_pthread_create_args *)_a;
706         void *(*start_routine) (void *) = a->start_routine;
707         void *arg = a->arg;
708         struct uwrap_thread *id = a->id;
709
710         SAFE_FREE(a);
711
712         uwrap_tls_id = id;
713
714         return start_routine(arg);
715 }
716
717 static int uwrap_pthread_create(pthread_t *thread,
718                                  const pthread_attr_t *attr,
719                                  void *(*start_routine) (void *),
720                                  void *arg)
721 {
722         struct uwrap_pthread_create_args *args;
723         struct uwrap_thread *src_id = uwrap_tls_id;
724         int ret;
725
726         args = malloc(sizeof(struct uwrap_pthread_create_args));
727         if (args == NULL) {
728                 UWRAP_LOG(UWRAP_LOG_ERROR,
729                           "uwrap_pthread_create: Unable to allocate memory");
730                 errno = ENOMEM;
731                 return -1;
732         }
733         args->start_routine = start_routine;
734         args->arg = arg;
735
736         args->id = calloc(1, sizeof(struct uwrap_thread));
737         if (args->id == NULL) {
738                 SAFE_FREE(args);
739                 UWRAP_LOG(UWRAP_LOG_ERROR,
740                           "uwrap_pthread_create: Unable to allocate memory");
741                 errno = ENOMEM;
742                 return -1;
743         }
744
745         UWRAP_LOCK(uwrap_id);
746
747         args->id->groups = malloc(sizeof(gid_t) * src_id->ngroups);
748         if (args->id->groups == NULL) {
749                 UWRAP_UNLOCK(uwrap_id);
750                 SAFE_FREE(args->id);
751                 SAFE_FREE(args);
752                 UWRAP_LOG(UWRAP_LOG_ERROR,
753                           "uwrap_pthread_create: Unable to allocate memory again");
754                 errno = ENOMEM;
755                 return -1;
756         }
757
758         args->id->ruid = src_id->ruid;
759         args->id->euid = src_id->euid;
760         args->id->suid = src_id->suid;
761
762         args->id->rgid = src_id->rgid;
763         args->id->egid = src_id->egid;
764         args->id->sgid = src_id->sgid;
765
766         args->id->enabled = src_id->enabled;
767
768         args->id->ngroups = src_id->ngroups;
769         if (src_id->groups != NULL) {
770                 memcpy(args->id->groups, src_id->groups,
771                        sizeof(gid_t) * src_id->ngroups);
772         } else {
773                 SAFE_FREE(args->id->groups);
774         }
775
776         UWRAP_DLIST_ADD(uwrap.ids, args->id);
777         UWRAP_UNLOCK(uwrap_id);
778
779         ret = libpthread_pthread_create(thread, attr,
780                                         uwrap_pthread_create_start,
781                                         args);
782         if (ret != 0) {
783                 return ret;
784         }
785
786         return ret;
787 }
788
789 int pthread_create(pthread_t *thread,
790                     const pthread_attr_t *attr,
791                     void *(*start_routine) (void *),
792                     void *arg)
793 {
794         if (!uid_wrapper_enabled()) {
795                 return libpthread_pthread_create(thread,
796                                            attr,
797                                            start_routine,
798                                            arg);
799         };
800
801         return uwrap_pthread_create(thread,
802                                     attr,
803                                     start_routine,
804                                     arg);
805 }
806
807 /*********************************************************
808  * UWRAP ID HANDLING
809  *********************************************************/
810
811 static void uwrap_thread_prepare(void)
812 {
813         struct uwrap_thread *id = uwrap_tls_id;
814
815         /* uid_wrapper is loaded but not enabled */
816         if (id == NULL) {
817                 return;
818         }
819
820         UWRAP_LOCK_ALL;
821
822         /*
823          * What happens if another atfork prepare functions calls a uwrap
824          * function? So disable it in case another atfork prepare function
825          * calls a (s)uid function. We disable uid_wrapper only for thread
826          * (process) which called fork.
827          */
828         id->enabled = false;
829 }
830
831 static void uwrap_thread_parent(void)
832 {
833         struct uwrap_thread *id = uwrap_tls_id;
834
835         /* uid_wrapper is loaded but not enabled */
836         if (id == NULL) {
837                 return;
838         }
839
840         id->enabled = true;
841
842         UWRAP_UNLOCK_ALL;
843 }
844
845 static void uwrap_thread_child(void)
846 {
847         struct uwrap_thread *id = uwrap_tls_id;
848         struct uwrap_thread *u = uwrap.ids;
849
850         /* uid_wrapper is loaded but not enabled */
851         if (id == NULL) {
852                 return;
853         }
854
855         /*
856          * "Garbage collector" - Inspired by DESTRUCTOR.
857          * All threads (except one which called fork()) are dead now.. Dave
858          * That's what posix said...
859          */
860         while (u != NULL) {
861                 if (u == id) {
862                         /* Skip this item. */
863                         u = uwrap.ids->next;
864                         continue;
865                 }
866
867                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
868
869                 SAFE_FREE(u->groups);
870                 SAFE_FREE(u);
871
872                 u = uwrap.ids;
873         }
874
875         id->enabled = true;
876
877         UWRAP_UNLOCK_ALL;
878 }
879
880 static void uwrap_init(void)
881 {
882         const char *env;
883
884         UWRAP_LOCK(uwrap_id);
885
886         if (uwrap.initialised) {
887                 struct uwrap_thread *id = uwrap_tls_id;
888
889                 if (uwrap.ids == NULL) {
890                         UWRAP_UNLOCK(uwrap_id);
891                         return;
892                 }
893
894                 if (id == NULL) {
895                         UWRAP_LOG(UWRAP_LOG_ERROR,
896                                   "Invalid id for thread");
897                         exit(-1);
898                 }
899
900                 UWRAP_UNLOCK(uwrap_id);
901                 return;
902         }
903
904         UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
905
906         uwrap.initialised = true;
907
908         env = getenv("UID_WRAPPER");
909         if (env != NULL && env[0] == '1') {
910                 const char *root = getenv("UID_WRAPPER_ROOT");
911                 struct uwrap_thread *id;
912
913                 id = calloc(1, sizeof(struct uwrap_thread));
914                 if (id == NULL) {
915                         UWRAP_LOG(UWRAP_LOG_ERROR,
916                                   "Unable to allocate memory for main id");
917                         exit(-1);
918                 }
919
920                 UWRAP_DLIST_ADD(uwrap.ids, id);
921                 uwrap_tls_id = id;
922
923                 uwrap.myuid = libc_geteuid();
924                 uwrap.mygid = libc_getegid();
925
926                 /* put us in one group */
927                 if (root != NULL && root[0] == '1') {
928                         id->ruid = id->euid = id->suid = 0;
929                         id->rgid = id->egid = id->sgid = 0;
930
931                         id->groups = malloc(sizeof(gid_t) * 1);
932                         if (id->groups == NULL) {
933                                 UWRAP_LOG(UWRAP_LOG_ERROR,
934                                           "Unable to allocate memory");
935                                 exit(-1);
936                         }
937
938                         id->ngroups = 1;
939                         id->groups[0] = 0;
940
941                 } else {
942                         id->ruid = id->euid = id->suid = uwrap.myuid;
943                         id->rgid = id->egid = id->sgid = uwrap.mygid;
944
945                         id->ngroups = libc_getgroups(0, NULL);
946                         if (id->ngroups == -1) {
947                                 UWRAP_LOG(UWRAP_LOG_ERROR,
948                                           "Unable to call libc_getgroups in uwrap_init.");
949                                 exit(-1);
950                         }
951                         id->groups = malloc(sizeof(gid_t) * id->ngroups);
952                         if (id->groups == NULL) {
953                                 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
954                                 exit(-1);
955                         }
956                         if (libc_getgroups(id->ngroups, id->groups) == -1) {
957                                 UWRAP_LOG(UWRAP_LOG_ERROR,
958                                           "Unable to call libc_getgroups again in uwrap_init.");
959                                 id->groups = 0;
960                                 /*
961                                  * Deallocation of uwrap.groups is handled by
962                                  * library destructor.
963                                  */
964                                 exit(-1);
965                         }
966                 }
967
968                 id->enabled = true;
969
970                 UWRAP_LOG(UWRAP_LOG_DEBUG,
971                           "Enabled uid_wrapper as %s (real uid=%u)",
972                           id->ruid == 0 ? "root" : "user",
973                           (unsigned int)uwrap.myuid);
974         }
975
976         UWRAP_UNLOCK(uwrap_id);
977
978         UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
979 }
980
981 bool uid_wrapper_enabled(void)
982 {
983         struct uwrap_thread *id = uwrap_tls_id;
984         bool enabled;
985
986         if (id == NULL) {
987                 return false;
988         }
989
990         UWRAP_LOCK(uwrap_id);
991         enabled = id->enabled;
992         UWRAP_UNLOCK(uwrap_id);
993
994         return enabled;
995 }
996
997 /*
998  * UWRAP_SETxUID FUNCTIONS
999  */
1000
1001 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1002 {
1003         struct uwrap_thread *id = uwrap_tls_id;
1004
1005         UWRAP_LOG(UWRAP_LOG_TRACE,
1006                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1007                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1008
1009         if (id->euid != 0) {
1010                 if (ruid != (uid_t)-1 &&
1011                     ruid != id->ruid &&
1012                     ruid != id->euid &&
1013                     ruid != id->suid) {
1014                         errno = EPERM;
1015                         return -1;
1016                 }
1017                 if (euid != (uid_t)-1 &&
1018                     euid != id->ruid &&
1019                     euid != id->euid &&
1020                     euid != id->suid) {
1021                         errno = EPERM;
1022                         return -1;
1023                 }
1024                 if (suid != (uid_t)-1 &&
1025                     suid != id->ruid &&
1026                     suid != id->euid &&
1027                     suid != id->suid) {
1028                         errno = EPERM;
1029                         return -1;
1030                 }
1031         }
1032
1033         return 0;
1034 }
1035
1036 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1037 {
1038         struct uwrap_thread *id = uwrap_tls_id;
1039         int rc;
1040
1041         UWRAP_LOG(UWRAP_LOG_TRACE,
1042                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1043                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1044
1045         rc = uwrap_setresuid_args(ruid, euid, suid);
1046         if (rc != 0) {
1047                 return rc;
1048         }
1049
1050         UWRAP_LOCK(uwrap_id);
1051
1052         if (ruid != (uid_t)-1) {
1053                 id->ruid = ruid;
1054         }
1055
1056         if (euid != (uid_t)-1) {
1057                 id->euid = euid;
1058         }
1059
1060         if (suid != (uid_t)-1) {
1061                 id->suid = suid;
1062         }
1063
1064         UWRAP_UNLOCK(uwrap_id);
1065
1066         return 0;
1067 }
1068
1069 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1070 {
1071         struct uwrap_thread *id = uwrap_tls_id;
1072         int rc;
1073
1074         UWRAP_LOG(UWRAP_LOG_TRACE,
1075                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1076                   id->ruid, ruid, id->euid, euid, id->suid, suid);
1077
1078         rc = uwrap_setresuid_args(ruid, euid, suid);
1079         if (rc != 0) {
1080                 return rc;
1081         }
1082
1083         UWRAP_LOCK(uwrap_id);
1084
1085         for (id = uwrap.ids; id; id = id->next) {
1086                 if (ruid != (uid_t)-1) {
1087                         id->ruid = ruid;
1088                 }
1089
1090                 if (euid != (uid_t)-1) {
1091                         id->euid = euid;
1092                 }
1093
1094                 if (suid != (uid_t)-1) {
1095                         id->suid = suid;
1096                 }
1097         }
1098
1099         UWRAP_UNLOCK(uwrap_id);
1100
1101         return 0;
1102 }
1103
1104 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1105                                uid_t *_new_ruid,
1106                                uid_t *_new_euid,
1107                                uid_t *_new_suid)
1108 {
1109         struct uwrap_thread *id = uwrap_tls_id;
1110         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1111
1112         UWRAP_LOG(UWRAP_LOG_TRACE,
1113                   "ruid %d -> %d, euid %d -> %d",
1114                   id->ruid, ruid, id->euid, euid);
1115
1116         if (ruid != (uid_t)-1) {
1117                 new_ruid = ruid;
1118                 if (ruid != id->ruid &&
1119                     ruid != id->euid &&
1120                     id->euid != 0) {
1121                         errno = EPERM;
1122                         return -1;
1123                 }
1124         }
1125
1126         if (euid != (uid_t)-1) {
1127                 new_euid = euid;
1128                 if (euid != id->ruid &&
1129                     euid != id->euid &&
1130                     euid != id->suid &&
1131                     id->euid != 0) {
1132                         errno = EPERM;
1133                         return -1;
1134                 }
1135         }
1136
1137         if (ruid != (uid_t) -1 ||
1138             (euid != (uid_t)-1 && id->ruid != euid)) {
1139                 new_suid = new_euid;
1140         }
1141
1142         *_new_ruid = new_ruid;
1143         *_new_euid = new_euid;
1144         *_new_suid = new_suid;
1145
1146         return 0;
1147 }
1148
1149 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1150 {
1151         struct uwrap_thread *id = uwrap_tls_id;
1152         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1153         int rc;
1154
1155         UWRAP_LOG(UWRAP_LOG_TRACE,
1156                   "ruid %d -> %d, euid %d -> %d",
1157                   id->ruid, ruid, id->euid, euid);
1158
1159         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1160         if (rc != 0) {
1161                 return rc;
1162         }
1163
1164         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1165 }
1166
1167 #ifdef HAVE_SETREUID
1168 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1169 {
1170         struct uwrap_thread *id = uwrap_tls_id;
1171         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1172         int rc;
1173
1174         UWRAP_LOG(UWRAP_LOG_TRACE,
1175                   "ruid %d -> %d, euid %d -> %d",
1176                   id->ruid, ruid, id->euid, euid);
1177
1178         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1179         if (rc != 0) {
1180                 return rc;
1181         }
1182
1183         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1184 }
1185 #endif
1186
1187 static int uwrap_setuid_args(uid_t uid,
1188                              uid_t *new_ruid,
1189                              uid_t *new_euid,
1190                              uid_t *new_suid)
1191 {
1192         struct uwrap_thread *id = uwrap_tls_id;
1193
1194         UWRAP_LOG(UWRAP_LOG_TRACE,
1195                   "uid %d -> %d",
1196                   id->ruid, uid);
1197
1198         if (uid == (uid_t)-1) {
1199                 errno = EINVAL;
1200                 return -1;
1201         }
1202
1203         if (id->euid == 0) {
1204                 *new_suid = *new_ruid = uid;
1205         } else if (uid != id->ruid &&
1206                    uid != id->suid) {
1207                 errno = EPERM;
1208                 return -1;
1209         }
1210
1211         *new_euid = uid;
1212
1213         return 0;
1214 }
1215
1216 static int uwrap_setuid_thread(uid_t uid)
1217 {
1218         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1219         int rc;
1220
1221         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1222         if (rc != 0) {
1223                 return rc;
1224         }
1225
1226         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1227 }
1228
1229 static int uwrap_setuid(uid_t uid)
1230 {
1231         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1232         int rc;
1233
1234         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1235         if (rc != 0) {
1236                 return rc;
1237         }
1238
1239         return uwrap_setresuid(new_ruid, new_euid, new_suid);
1240 }
1241
1242 /*
1243  * UWRAP_GETxUID FUNCTIONS
1244  */
1245
1246 #ifdef HAVE_GETRESUID
1247 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1248 {
1249         struct uwrap_thread *id = uwrap_tls_id;
1250
1251         UWRAP_LOCK(uwrap_id);
1252
1253         *ruid = id->ruid;
1254         *euid = id->euid;
1255         *suid = id->suid;
1256
1257         UWRAP_UNLOCK(uwrap_id);
1258
1259         return 0;
1260 }
1261 #endif
1262
1263 #ifdef HAVE_GETRESGID
1264 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1265 {
1266         struct uwrap_thread *id = uwrap_tls_id;
1267
1268         UWRAP_LOCK(uwrap_id);
1269
1270         *rgid = id->rgid;
1271         *egid = id->egid;
1272         *sgid = id->sgid;
1273
1274         UWRAP_UNLOCK(uwrap_id);
1275
1276         return 0;
1277 }
1278 #endif
1279
1280 /*
1281  * UWRAP_SETxGID FUNCTIONS
1282  */
1283
1284 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1285 {
1286         struct uwrap_thread *id = uwrap_tls_id;
1287
1288         UWRAP_LOG(UWRAP_LOG_TRACE,
1289                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1290                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1291
1292         if (id->euid != 0) {
1293                 if (rgid != (gid_t)-1 &&
1294                     rgid != id->rgid &&
1295                     rgid != id->egid &&
1296                     rgid != id->sgid) {
1297                         errno = EPERM;
1298                         return -1;
1299                 }
1300                 if (egid != (gid_t)-1 &&
1301                     egid != id->rgid &&
1302                     egid != id->egid &&
1303                     egid != id->sgid) {
1304                         errno = EPERM;
1305                         return -1;
1306                 }
1307                 if (sgid != (gid_t)-1 &&
1308                     sgid != id->rgid &&
1309                     sgid != id->egid &&
1310                     sgid != id->sgid) {
1311                         errno = EPERM;
1312                         return -1;
1313                 }
1314         }
1315
1316         return 0;
1317 }
1318
1319 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1320 {
1321         struct uwrap_thread *id = uwrap_tls_id;
1322         int rc;
1323
1324         UWRAP_LOG(UWRAP_LOG_TRACE,
1325                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1326                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1327
1328         rc = uwrap_setresgid_args(rgid, egid, sgid);
1329         if (rc != 0) {
1330                 return rc;
1331         }
1332
1333         UWRAP_LOCK(uwrap_id);
1334
1335         if (rgid != (gid_t)-1) {
1336                 id->rgid = rgid;
1337         }
1338
1339         if (egid != (gid_t)-1) {
1340                 id->egid = egid;
1341         }
1342
1343         if (sgid != (gid_t)-1) {
1344                 id->sgid = sgid;
1345         }
1346
1347         UWRAP_UNLOCK(uwrap_id);
1348
1349         return 0;
1350 }
1351
1352 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1353 {
1354         struct uwrap_thread *id = uwrap_tls_id;
1355         int rc;
1356
1357         UWRAP_LOG(UWRAP_LOG_TRACE,
1358                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1359                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1360
1361         rc = uwrap_setresgid_args(rgid, egid, sgid);
1362         if (rc != 0) {
1363                 return rc;
1364         }
1365
1366         UWRAP_LOCK(uwrap_id);
1367
1368         for (id = uwrap.ids; id; id = id->next) {
1369                 if (rgid != (gid_t)-1) {
1370                         id->rgid = rgid;
1371                 }
1372
1373                 if (egid != (gid_t)-1) {
1374                         id->egid = egid;
1375                 }
1376
1377                 if (sgid != (gid_t)-1) {
1378                         id->sgid = sgid;
1379                 }
1380         }
1381
1382         UWRAP_UNLOCK(uwrap_id);
1383
1384         return 0;
1385 }
1386
1387 /*
1388  * SETUID
1389  */
1390 int setuid(uid_t uid)
1391 {
1392         if (!uid_wrapper_enabled()) {
1393                 return libc_setuid(uid);
1394         }
1395
1396         uwrap_init();
1397         return uwrap_setuid(uid);
1398 }
1399
1400 #ifdef HAVE_SETEUID
1401 int seteuid(uid_t euid)
1402 {
1403         if (!uid_wrapper_enabled()) {
1404                 return libc_seteuid(euid);
1405         }
1406
1407         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1408         if (euid == (uid_t)-1) {
1409                 errno = EINVAL;
1410                 return -1;
1411         }
1412
1413         uwrap_init();
1414         return uwrap_setresuid(-1, euid, -1);
1415 }
1416 #endif
1417
1418 #ifdef HAVE_SETREUID
1419 int setreuid(uid_t ruid, uid_t euid)
1420 {
1421         if (!uid_wrapper_enabled()) {
1422                 return libc_setreuid(ruid, euid);
1423         }
1424
1425         uwrap_init();
1426         return uwrap_setreuid(ruid, euid);
1427 }
1428 #endif
1429
1430 #ifdef HAVE_SETRESUID
1431 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1432 {
1433         if (!uid_wrapper_enabled()) {
1434                 return libc_setresuid(ruid, euid, suid);
1435         }
1436
1437         uwrap_init();
1438         return uwrap_setresuid(ruid, euid, suid);
1439 }
1440 #endif
1441
1442 #ifdef HAVE_GETRESUID
1443 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1444 {
1445         if (!uid_wrapper_enabled()) {
1446                 return libc_getresuid(ruid, euid, suid);
1447         }
1448
1449         uwrap_init();
1450         return uwrap_getresuid(ruid, euid, suid);
1451 }
1452 #endif
1453
1454 /*
1455  * GETUID
1456  */
1457 static uid_t uwrap_getuid(void)
1458 {
1459         struct uwrap_thread *id = uwrap_tls_id;
1460         uid_t uid;
1461
1462         UWRAP_LOCK(uwrap_id);
1463         uid = id->ruid;
1464         UWRAP_UNLOCK(uwrap_id);
1465
1466         return uid;
1467 }
1468
1469 uid_t getuid(void)
1470 {
1471         if (!uid_wrapper_enabled()) {
1472                 return libc_getuid();
1473         }
1474
1475         uwrap_init();
1476         return uwrap_getuid();
1477 }
1478
1479 /*
1480  * GETEUID
1481  */
1482 static uid_t uwrap_geteuid(void)
1483 {
1484         const char *env = getenv("UID_WRAPPER_MYUID");
1485         struct uwrap_thread *id = uwrap_tls_id;
1486         uid_t uid;
1487
1488         UWRAP_LOCK(uwrap_id);
1489         uid = id->euid;
1490         UWRAP_UNLOCK(uwrap_id);
1491
1492         /* Disable root and return myuid */
1493         if (env != NULL && env[0] == '1') {
1494                 uid = uwrap.myuid;
1495         }
1496
1497         return uid;
1498 }
1499
1500 uid_t geteuid(void)
1501 {
1502         if (!uid_wrapper_enabled()) {
1503                 return libc_geteuid();
1504         }
1505
1506         uwrap_init();
1507         return uwrap_geteuid();
1508 }
1509
1510 /*
1511  * SETGID
1512  */
1513 int setgid(gid_t gid)
1514 {
1515         if (!uid_wrapper_enabled()) {
1516                 return libc_setgid(gid);
1517         }
1518
1519         uwrap_init();
1520         return uwrap_setresgid(gid, -1, -1);
1521 }
1522
1523 #ifdef HAVE_SETEGID
1524 int setegid(gid_t egid)
1525 {
1526         if (!uid_wrapper_enabled()) {
1527                 return libc_setegid(egid);
1528         }
1529
1530         uwrap_init();
1531         return uwrap_setresgid(-1, egid, -1);
1532 }
1533 #endif
1534
1535 #ifdef HAVE_SETREGID
1536 int setregid(gid_t rgid, gid_t egid)
1537 {
1538         if (!uid_wrapper_enabled()) {
1539                 return libc_setregid(rgid, egid);
1540         }
1541
1542         uwrap_init();
1543         return uwrap_setresgid(rgid, egid, -1);
1544 }
1545 #endif
1546
1547 #ifdef HAVE_SETRESGID
1548 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1549 {
1550         if (!uid_wrapper_enabled()) {
1551                 return libc_setresgid(rgid, egid, sgid);
1552         }
1553
1554         uwrap_init();
1555         return uwrap_setresgid(rgid, egid, sgid);
1556 }
1557 #endif
1558
1559 #ifdef HAVE_GETRESGID
1560 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1561 {
1562         if (!uid_wrapper_enabled()) {
1563                 return libc_getresgid(rgid, egid, sgid);
1564         }
1565
1566         uwrap_init();
1567         return uwrap_getresgid(rgid, egid, sgid);
1568 }
1569 #endif
1570
1571 /*
1572  * GETGID
1573  */
1574 static gid_t uwrap_getgid(void)
1575 {
1576         struct uwrap_thread *id = uwrap_tls_id;
1577         gid_t gid;
1578
1579         UWRAP_LOCK(uwrap_id);
1580         gid = id->rgid;
1581         UWRAP_UNLOCK(uwrap_id);
1582
1583         return gid;
1584 }
1585
1586 gid_t getgid(void)
1587 {
1588         if (!uid_wrapper_enabled()) {
1589                 return libc_getgid();
1590         }
1591
1592         uwrap_init();
1593         return uwrap_getgid();
1594 }
1595
1596 /*
1597  * GETEGID
1598  */
1599 static uid_t uwrap_getegid(void)
1600 {
1601         struct uwrap_thread *id = uwrap_tls_id;
1602         gid_t gid;
1603
1604         UWRAP_LOCK(uwrap_id);
1605         gid = id->egid;
1606         UWRAP_UNLOCK(uwrap_id);
1607
1608         return gid;
1609 }
1610
1611 uid_t getegid(void)
1612 {
1613         if (!uid_wrapper_enabled()) {
1614                 return libc_getegid();
1615         }
1616
1617         uwrap_init();
1618         return uwrap_getegid();
1619 }
1620
1621 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
1622 {
1623         struct uwrap_thread *id = uwrap_tls_id;
1624         int rc = -1;
1625
1626         UWRAP_LOCK(uwrap_id);
1627
1628         if (size == 0) {
1629                 SAFE_FREE(id->groups);
1630                 id->ngroups = 0;
1631         } else if (size > 0) {
1632                 gid_t *tmp;
1633
1634                 tmp = realloc(id->groups, sizeof(gid_t) * size);
1635                 if (tmp == NULL) {
1636                         errno = ENOMEM;
1637                         goto out;
1638                 }
1639                 id->groups = tmp;
1640                 id->ngroups = size;
1641                 memcpy(id->groups, list, size * sizeof(gid_t));
1642         }
1643
1644         rc = 0;
1645 out:
1646         UWRAP_UNLOCK(uwrap_id);
1647
1648         return rc;
1649 }
1650
1651 static int uwrap_setgroups(size_t size, const gid_t *list)
1652 {
1653         struct uwrap_thread *id;
1654         int rc = -1;
1655
1656         UWRAP_LOCK(uwrap_id);
1657
1658         if (size == 0) {
1659                 for (id = uwrap.ids; id; id = id->next) {
1660                         SAFE_FREE(id->groups);
1661                         id->ngroups = 0;
1662
1663                 }
1664         } else if (size > 0) {
1665                 gid_t *tmp;
1666
1667                 for (id = uwrap.ids; id; id = id->next) {
1668                         tmp = realloc(id->groups, sizeof(gid_t) * size);
1669                         if (tmp == NULL) {
1670                                 errno = ENOMEM;
1671                                 goto out;
1672                         }
1673                         id->groups = tmp;
1674
1675                         id->ngroups = size;
1676                         memcpy(id->groups, list, size * sizeof(gid_t));
1677                 }
1678         }
1679
1680         rc = 0;
1681 out:
1682         UWRAP_UNLOCK(uwrap_id);
1683
1684         return rc;
1685 }
1686
1687 #ifdef HAVE_SETGROUPS_INT
1688 int setgroups(int size, const gid_t *list)
1689 #else
1690 int setgroups(size_t size, const gid_t *list)
1691 #endif
1692 {
1693         if (!uid_wrapper_enabled()) {
1694                 return libc_setgroups(size, list);
1695         }
1696
1697         uwrap_init();
1698         return uwrap_setgroups(size, list);
1699 }
1700
1701 static int uwrap_getgroups(int size, gid_t *list)
1702 {
1703         struct uwrap_thread *id = uwrap_tls_id;
1704         int ngroups;
1705
1706         UWRAP_LOCK(uwrap_id);
1707         ngroups = id->ngroups;
1708
1709         if (size > ngroups) {
1710                 size = ngroups;
1711         }
1712         if (size == 0) {
1713                 goto out;
1714         }
1715         if (size < ngroups) {
1716                 errno = EINVAL;
1717                 ngroups = -1;
1718         }
1719         memcpy(list, id->groups, size * sizeof(gid_t));
1720
1721 out:
1722         UWRAP_UNLOCK(uwrap_id);
1723
1724         return ngroups;
1725 }
1726
1727 int getgroups(int size, gid_t *list)
1728 {
1729         if (!uid_wrapper_enabled()) {
1730                 return libc_getgroups(size, list);
1731         }
1732
1733         uwrap_init();
1734         return uwrap_getgroups(size, list);
1735 }
1736
1737 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1738     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1739 static long int uwrap_syscall (long int sysno, va_list vp)
1740 {
1741         long int rc;
1742
1743         switch (sysno) {
1744                 /* gid */
1745                 case SYS_getgid:
1746 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1747                 case SYS_getgid32:
1748 #endif
1749                         {
1750                                 rc = uwrap_getgid();
1751                         }
1752                         break;
1753 #ifdef SYS_getegid
1754                 case SYS_getegid:
1755 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1756                 case SYS_getegid32:
1757 #endif
1758                         {
1759                                 rc = uwrap_getegid();
1760                         }
1761                         break;
1762 #endif /* SYS_getegid */
1763                 case SYS_setgid:
1764 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1765                 case SYS_setgid32:
1766 #endif
1767                         {
1768                                 gid_t gid = (gid_t) va_arg(vp, gid_t);
1769
1770                                 rc = uwrap_setresgid_thread(gid, -1, -1);
1771                         }
1772                         break;
1773                 case SYS_setregid:
1774 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1775                 case SYS_setregid32:
1776 #endif
1777                         {
1778                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1779                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
1780
1781                                 rc = uwrap_setresgid_thread(rgid, egid, -1);
1782                         }
1783                         break;
1784 #ifdef SYS_setresgid
1785                 case SYS_setresgid:
1786 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1787                 case SYS_setresgid32:
1788 #endif
1789                         {
1790                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
1791                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
1792                                 gid_t sgid = (gid_t) va_arg(vp, gid_t);
1793
1794                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1795                         }
1796                         break;
1797 #endif /* SYS_setresgid */
1798 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
1799                 case SYS_getresgid:
1800 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1801                 case SYS_getresgid32:
1802 #endif
1803                         {
1804                                 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
1805                                 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
1806                                 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
1807
1808                                 rc = uwrap_getresgid(rgid, egid, sgid);
1809                         }
1810                         break;
1811 #endif /* SYS_getresgid && HAVE_GETRESGID */
1812
1813                 /* uid */
1814                 case SYS_getuid:
1815 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1816                 case SYS_getuid32:
1817 #endif
1818                         {
1819                                 rc = uwrap_getuid();
1820                         }
1821                         break;
1822 #ifdef SYS_geteuid
1823                 case SYS_geteuid:
1824 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1825                 case SYS_geteuid32:
1826 #endif
1827                         {
1828                                 rc = uwrap_geteuid();
1829                         }
1830                         break;
1831 #endif /* SYS_geteuid */
1832                 case SYS_setuid:
1833 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1834                 case SYS_setuid32:
1835 #endif
1836                         {
1837                                 uid_t uid = (uid_t) va_arg(vp, uid_t);
1838
1839                                 rc = uwrap_setuid_thread(uid);
1840                         }
1841                         break;
1842                 case SYS_setreuid:
1843 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1844                 case SYS_setreuid32:
1845 #endif
1846                         {
1847                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1848                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
1849
1850                                 rc = uwrap_setreuid_thread(ruid, euid);
1851                         }
1852                         break;
1853 #ifdef SYS_setresuid
1854                 case SYS_setresuid:
1855 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1856                 case SYS_setresuid32:
1857 #endif
1858                         {
1859                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
1860                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
1861                                 uid_t suid = (uid_t) va_arg(vp, uid_t);
1862
1863                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
1864                         }
1865                         break;
1866 #endif /* SYS_setresuid */
1867 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
1868                 case SYS_getresuid:
1869 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1870                 case SYS_getresuid32:
1871 #endif
1872                         {
1873                                 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
1874                                 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
1875                                 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
1876
1877                                 rc = uwrap_getresuid(ruid, euid, suid);
1878                         }
1879                         break;
1880 #endif /* SYS_getresuid && HAVE_GETRESUID*/
1881                 /* groups */
1882                 case SYS_setgroups:
1883 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1884                 case SYS_setgroups32:
1885 #endif
1886                         {
1887                                 size_t size = (size_t) va_arg(vp, size_t);
1888                                 gid_t *list = (gid_t *) va_arg(vp, int *);
1889
1890                                 rc = uwrap_setgroups_thread(size, list);
1891                         }
1892                         break;
1893                 default:
1894                         UWRAP_LOG(UWRAP_LOG_DEBUG,
1895                                   "UID_WRAPPER calling non-wrapped syscall %lu",
1896                                   sysno);
1897
1898                         rc = libc_vsyscall(sysno, vp);
1899                         break;
1900         }
1901
1902         return rc;
1903 }
1904
1905 #ifdef HAVE_SYSCALL
1906 #ifdef HAVE_SYSCALL_INT
1907 int syscall (int sysno, ...)
1908 #else
1909 long int syscall (long int sysno, ...)
1910 #endif
1911 {
1912 #ifdef HAVE_SYSCALL_INT
1913         int rc;
1914 #else
1915         long int rc;
1916 #endif
1917         va_list va;
1918
1919         va_start(va, sysno);
1920
1921         if (!uid_wrapper_enabled()) {
1922                 rc = libc_vsyscall(sysno, va);
1923                 va_end(va);
1924                 return rc;
1925         }
1926
1927         uwrap_init();
1928         rc = uwrap_syscall(sysno, va);
1929         va_end(va);
1930
1931         return rc;
1932 }
1933 #endif /* HAVE_SYSCALL */
1934 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1935
1936 /****************************
1937  * CONSTRUCTOR
1938  ***************************/
1939 void uwrap_constructor(void)
1940 {
1941         /*
1942         * If we hold a lock and the application forks, then the child
1943         * is not able to unlock the mutex and we are in a deadlock.
1944         * This should prevent such deadlocks.
1945         */
1946         pthread_atfork(&uwrap_thread_prepare,
1947                        &uwrap_thread_parent,
1948                        &uwrap_thread_child);
1949
1950         /* Here is safe place to call uwrap_init() and initialize data
1951          * for main process.
1952          */
1953         uwrap_init();
1954 }
1955
1956 /****************************
1957  * DESTRUCTOR
1958  ***************************/
1959
1960 /*
1961  * This function is called when the library is unloaded and makes sure that
1962  * resources are freed.
1963  */
1964 void uwrap_destructor(void)
1965 {
1966         struct uwrap_thread *u = uwrap.ids;
1967
1968         UWRAP_LOCK_ALL;
1969
1970         while (u != NULL) {
1971                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1972
1973                 SAFE_FREE(u->groups);
1974                 SAFE_FREE(u);
1975
1976                 u = uwrap.ids;
1977         }
1978
1979
1980         if (uwrap.libc.handle != NULL) {
1981                 dlclose(uwrap.libc.handle);
1982         }
1983
1984         if (uwrap.libpthread.handle != NULL) {
1985                 dlclose(uwrap.libpthread.handle);
1986         }
1987
1988         UWRAP_UNLOCK_ALL;
1989 }