cmake: Check for HAVE_FUNCTION_ATTRIBUTE_FORMAT.
[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 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
47 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
48 #else
49 #define DESTRUCTOR_ATTRIBUTE
50 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
51
52 /* GCC have printf type attribute check. */
53 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
54 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
55 #else
56 #define PRINTF_ATTRIBUTE(a,b)
57 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
58
59 #ifdef NDEBUG
60 #define UWRAP_DEBUG(...)
61 #else
62 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
63 #endif
64
65 #define UWRAP_DLIST_ADD(list,item) do { \
66         if (!(list)) { \
67                 (item)->prev    = NULL; \
68                 (item)->next    = NULL; \
69                 (list)          = (item); \
70         } else { \
71                 (item)->prev    = NULL; \
72                 (item)->next    = (list); \
73                 (list)->prev    = (item); \
74                 (list)          = (item); \
75         } \
76 } while (0)
77
78 #define UWRAP_DLIST_REMOVE(list,item) do { \
79         if ((list) == (item)) { \
80                 (list)          = (item)->next; \
81                 if (list) { \
82                         (list)->prev    = NULL; \
83                 } \
84         } else { \
85                 if ((item)->prev) { \
86                         (item)->prev->next      = (item)->next; \
87                 } \
88                 if ((item)->next) { \
89                         (item)->next->prev      = (item)->prev; \
90                 } \
91         } \
92         (item)->prev    = NULL; \
93         (item)->next    = NULL; \
94 } while (0)
95
96 #ifndef SAFE_FREE
97 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
98 #endif
99
100 #define LIBC_NAME "libc.so"
101
102 struct uwrap_libc_fns {
103         int (*_libc_setuid)(uid_t uid);
104         uid_t (*_libc_getuid)(void);
105
106 #ifdef HAVE_SETEUID
107         int (*_libc_seteuid)(uid_t euid);
108 #endif
109 #ifdef HAVE_SETREUID
110         int (*_libc_setreuid)(uid_t ruid, uid_t euid);
111 #endif
112 #ifdef HAVE_SETRESUID
113         int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
114 #endif
115         uid_t (*_libc_geteuid)(void);
116
117         int (*_libc_setgid)(gid_t gid);
118         gid_t (*_libc_getgid)(void);
119 #ifdef HAVE_SETEGID
120         int (*_libc_setegid)(uid_t egid);
121 #endif
122 #ifdef HAVE_SETREGID
123         int (*_libc_setregid)(uid_t rgid, uid_t egid);
124 #endif
125 #ifdef HAVE_SETRESGID
126         int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
127 #endif
128         gid_t (*_libc_getegid)(void);
129         int (*_libc_getgroups)(int size, gid_t list[]);
130         int (*_libc_setgroups)(size_t size, const gid_t *list);
131 #ifdef HAVE_SYSCALL
132         long int (*_libc_syscall)(long int sysno, ...);
133 #endif
134 };
135
136 /*
137  * We keep the virtualised euid/egid/groups information here
138  */
139 struct uwrap_thread {
140         pthread_t tid;
141         bool dead;
142
143         uid_t ruid;
144         uid_t euid;
145         uid_t suid;
146
147         gid_t rgid;
148         gid_t egid;
149         gid_t sgid;
150
151         gid_t *groups;
152         int ngroups;
153
154         struct uwrap_thread *next;
155         struct uwrap_thread *prev;
156 };
157
158 struct uwrap {
159         struct {
160                 void *handle;
161                 struct uwrap_libc_fns fns;
162         } libc;
163
164         bool initialised;
165         bool enabled;
166
167         uid_t myuid;
168         uid_t mygid;
169
170         struct uwrap_thread *ids;
171 };
172
173 static struct uwrap uwrap;
174
175 /* Shortcut to the list item */
176 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
177
178 /* The mutex or accessing the id */
179 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
180
181 /*********************************************************
182  * UWRAP PROTOTYPES
183  *********************************************************/
184
185 bool uid_wrapper_enabled(void);
186 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
187
188 /*********************************************************
189  * UWRAP LIBC LOADER FUNCTIONS
190  *********************************************************/
191
192 enum uwrap_lib {
193     UWRAP_LIBC,
194     UWRAP_LIBNSL,
195     UWRAP_LIBSOCKET,
196 };
197
198 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
199 {
200         int flags = RTLD_LAZY;
201         void *handle = NULL;
202         int i;
203
204 #ifdef RTLD_DEEPBIND
205         flags |= RTLD_DEEPBIND;
206 #endif
207
208         switch (lib) {
209         case UWRAP_LIBNSL:
210                 /* FALL TROUGH */
211         case UWRAP_LIBSOCKET:
212                 /* FALL TROUGH */
213         case UWRAP_LIBC:
214                 handle = uwrap.libc.handle;
215                 if (handle == NULL) {
216                         for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
217                                 char soname[256] = {0};
218
219                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
220                                 handle = dlopen(soname, flags);
221                         }
222
223                         uwrap.libc.handle = handle;
224                 }
225                 break;
226         }
227
228         if (handle == NULL) {
229 #ifdef RTLD_NEXT
230                 handle = uwrap.libc.handle = RTLD_NEXT;
231 #else
232                 fprintf(stderr,
233                         "Failed to dlopen library: %s\n",
234                         dlerror());
235                 exit(-1);
236 #endif
237         }
238
239         return handle;
240 }
241
242 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
243 {
244         void *handle;
245         void *func;
246
247         handle = uwrap_load_lib_handle(lib);
248
249         func = dlsym(handle, fn_name);
250         if (func == NULL) {
251                 fprintf(stderr,
252                         "Failed to find %s: %s\n",
253                         fn_name, dlerror());
254                 exit(-1);
255         }
256
257         return func;
258 }
259
260 #define uwrap_load_lib_function(lib, fn_name) \
261         if (uwrap.libc.fns._libc_##fn_name == NULL) { \
262                 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
263                         _uwrap_load_lib_function(lib, #fn_name); \
264         }
265
266 /*
267  * IMPORTANT
268  *
269  * Functions expeciall from libc need to be loaded individually, you can't load
270  * all at once or gdb will segfault at startup. The same applies to valgrind and
271  * has probably something todo with with the linker.
272  * So we need load each function at the point it is called the first time.
273  */
274 static int libc_setuid(uid_t uid)
275 {
276         uwrap_load_lib_function(UWRAP_LIBC, setuid);
277
278         return uwrap.libc.fns._libc_setuid(uid);
279 }
280
281 static uid_t libc_getuid(void)
282 {
283         uwrap_load_lib_function(UWRAP_LIBC, getuid);
284
285         return uwrap.libc.fns._libc_getuid();
286 }
287
288 #ifdef HAVE_SETEUID
289 static int libc_seteuid(uid_t euid)
290 {
291         uwrap_load_lib_function(UWRAP_LIBC, seteuid);
292
293         return uwrap.libc.fns._libc_seteuid(euid);
294 }
295 #endif
296
297 #ifdef HAVE_SETREUID
298 static int libc_setreuid(uid_t ruid, uid_t euid)
299 {
300         uwrap_load_lib_function(UWRAP_LIBC, setreuid);
301
302         return uwrap.libc.fns._libc_setreuid(ruid, euid);
303 }
304 #endif
305
306 #ifdef HAVE_SETRESUID
307 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
308 {
309         uwrap_load_lib_function(UWRAP_LIBC, setresuid);
310
311         return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
312 }
313 #endif
314
315 static uid_t libc_geteuid(void)
316 {
317         uwrap_load_lib_function(UWRAP_LIBC, geteuid);
318
319         return uwrap.libc.fns._libc_geteuid();
320 }
321
322 static int libc_setgid(gid_t gid)
323 {
324         uwrap_load_lib_function(UWRAP_LIBC, setgid);
325
326         return uwrap.libc.fns._libc_setgid(gid);
327 }
328
329 static gid_t libc_getgid(void)
330 {
331         uwrap_load_lib_function(UWRAP_LIBC, getgid);
332
333         return uwrap.libc.fns._libc_getgid();
334 }
335
336 #ifdef HAVE_SETEGID
337 static int libc_setegid(gid_t egid)
338 {
339         uwrap_load_lib_function(UWRAP_LIBC, setegid);
340
341         return uwrap.libc.fns._libc_setegid(egid);
342 }
343 #endif
344
345 #ifdef HAVE_SETREGID
346 static int libc_setregid(gid_t rgid, gid_t egid)
347 {
348         uwrap_load_lib_function(UWRAP_LIBC, setregid);
349
350         return uwrap.libc.fns._libc_setregid(rgid, egid);
351 }
352 #endif
353
354 #ifdef HAVE_SETRESGID
355 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
356 {
357         uwrap_load_lib_function(UWRAP_LIBC, setresgid);
358
359         return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
360 }
361 #endif
362
363 static gid_t libc_getegid(void)
364 {
365         uwrap_load_lib_function(UWRAP_LIBC, getegid);
366
367         return uwrap.libc.fns._libc_getegid();
368 }
369
370 static int libc_getgroups(int size, gid_t list[])
371 {
372         uwrap_load_lib_function(UWRAP_LIBC, getgroups);
373
374         return uwrap.libc.fns._libc_getgroups(size, list);
375 }
376
377 static int libc_setgroups(size_t size, const gid_t *list)
378 {
379         uwrap_load_lib_function(UWRAP_LIBC, setgroups);
380
381         return uwrap.libc.fns._libc_setgroups(size, list);
382 }
383
384 #ifdef HAVE_SYSCALL
385 static long int libc_vsyscall(long int sysno, va_list va)
386 {
387         long int args[8];
388         long int rc;
389         int i;
390
391         uwrap_load_lib_function(UWRAP_LIBC, syscall);
392
393         for (i = 0; i < 8; i++) {
394                 args[i] = va_arg(va, long int);
395         }
396
397         rc = uwrap.libc.fns._libc_syscall(sysno,
398                                           args[0],
399                                           args[1],
400                                           args[2],
401                                           args[3],
402                                           args[4],
403                                           args[5],
404                                           args[6],
405                                           args[7]);
406
407         return rc;
408 }
409 #endif
410
411 /*********************************************************
412  * UWRAP ID HANDLING
413  *********************************************************/
414
415 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
416 {
417         struct uwrap_thread *id;
418
419         for (id = uwrap.ids; id; id = id->next) {
420                 if (pthread_equal(id->tid, tid)) {
421                         return id;
422                 }
423         }
424
425         return NULL;
426 }
427
428 static int uwrap_new_id(pthread_t tid, bool do_alloc)
429 {
430         struct uwrap_thread *id = uwrap_tls_id;
431
432         if (do_alloc) {
433                 id = malloc(sizeof(struct uwrap_thread));
434                 if (id == NULL) {
435                         errno = ENOMEM;
436                         return -1;
437                 }
438
439                 id->groups = malloc(sizeof(gid_t) * 1);
440                 if (id->groups == NULL) {
441                         SAFE_FREE(id);
442                         errno = ENOMEM;
443                         return -1;
444                 }
445
446                 UWRAP_DLIST_ADD(uwrap.ids, id);
447                 uwrap_tls_id = id;
448         }
449
450         id->tid = tid;
451         id->dead = false;
452
453         id->ruid = id->euid = id->suid = uwrap.myuid;
454         id->rgid = id->egid = id->sgid = uwrap.mygid;
455
456         id->ngroups = 1;
457         id->groups[0] = uwrap.mygid;
458
459         return 0;
460 }
461
462 static void uwrap_thread_prepare(void)
463 {
464         pthread_mutex_lock(&uwrap_id_mutex);
465
466         /*
467          * What happens if another atfork prepare functions calls a uwrap
468          * function? So disable it in case another atfork prepare function
469          * calls a (s)uid function.
470          */
471         uwrap.enabled = false;
472 }
473
474 static void uwrap_thread_parent(void)
475 {
476         uwrap.enabled = true;
477
478         pthread_mutex_unlock(&uwrap_id_mutex);
479 }
480
481 static void uwrap_thread_child(void)
482 {
483         uwrap.enabled = true;
484
485         pthread_mutex_unlock(&uwrap_id_mutex);
486 }
487
488 static void uwrap_init(void)
489 {
490         const char *env = getenv("UID_WRAPPER");
491         pthread_t tid = pthread_self();
492
493
494
495         if (uwrap.initialised) {
496                 struct uwrap_thread *id = uwrap_tls_id;
497                 int rc;
498
499                 if (id != NULL) {
500                         return;
501                 }
502
503                 pthread_mutex_lock(&uwrap_id_mutex);
504                 id = find_uwrap_id(tid);
505                 if (id == NULL) {
506                         rc = uwrap_new_id(tid, true);
507                         if (rc < 0) {
508                                 exit(-1);
509                         }
510                 } else {
511                         /* We reuse an old thread id */
512                         uwrap_tls_id = id;
513
514                         uwrap_new_id(tid, false);
515                 }
516                 pthread_mutex_unlock(&uwrap_id_mutex);
517
518                 return;
519         }
520
521         /*
522          * If we hold a lock and the application forks, then the child
523          * is not able to unlock the mutex and we are in a deadlock.
524          * This should prevent such deadlocks.
525          */
526         pthread_atfork(&uwrap_thread_prepare,
527                        &uwrap_thread_parent,
528                        &uwrap_thread_child);
529
530         pthread_mutex_lock(&uwrap_id_mutex);
531
532         uwrap.initialised = true;
533         uwrap.enabled = false;
534
535         if (env != NULL && env[0] == '1') {
536                 const char *root = getenv("UID_WRAPPER_ROOT");
537                 int rc;
538
539                 /* put us in one group */
540                 if (root != NULL && root[0] == '1') {
541                         uwrap.myuid = 0;
542                         uwrap.mygid = 0;
543                 } else {
544                         uwrap.myuid = libc_geteuid();
545                         uwrap.mygid = libc_getegid();
546                 }
547
548                 rc = uwrap_new_id(tid, true);
549                 if (rc < 0) {
550                         exit(-1);
551                 }
552
553                 uwrap.enabled = true;
554         }
555
556         pthread_mutex_unlock(&uwrap_id_mutex);
557 }
558
559 bool uid_wrapper_enabled(void)
560 {
561         uwrap_init();
562
563         return uwrap.enabled ? true : false;
564 }
565
566 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
567 {
568         struct uwrap_thread *id = uwrap_tls_id;
569
570         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
571                 errno = EINVAL;
572                 return -1;
573         }
574
575         pthread_mutex_lock(&uwrap_id_mutex);
576         if (ruid != (uid_t)-1) {
577                 id->ruid = ruid;
578         }
579
580         if (euid != (uid_t)-1) {
581                 id->euid = euid;
582         }
583
584         if (suid != (uid_t)-1) {
585                 id->suid = suid;
586         }
587         pthread_mutex_unlock(&uwrap_id_mutex);
588
589         return 0;
590 }
591
592 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
593 {
594         struct uwrap_thread *id;
595
596         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
597                 errno = EINVAL;
598                 return -1;
599         }
600
601         pthread_mutex_lock(&uwrap_id_mutex);
602         for (id = uwrap.ids; id; id = id->next) {
603                 if (id->dead) {
604                         continue;
605                 }
606
607                 if (ruid != (uid_t)-1) {
608                         id->ruid = ruid;
609                 }
610
611                 if (euid != (uid_t)-1) {
612                         id->euid = euid;
613                 }
614
615                 if (suid != (uid_t)-1) {
616                         id->suid = suid;
617                 }
618         }
619         pthread_mutex_unlock(&uwrap_id_mutex);
620
621         return 0;
622 }
623
624 /*
625  * SETUID
626  */
627 int setuid(uid_t uid)
628 {
629         if (!uid_wrapper_enabled()) {
630                 return libc_setuid(uid);
631         }
632
633         return uwrap_setresuid(uid, -1, -1);
634 }
635
636 #ifdef HAVE_SETEUID
637 int seteuid(uid_t euid)
638 {
639         if (euid == (uid_t)-1) {
640                 errno = EINVAL;
641                 return -1;
642         }
643
644         if (!uid_wrapper_enabled()) {
645                 return libc_seteuid(euid);
646         }
647
648         return uwrap_setresuid(-1, euid, -1);
649 }
650 #endif
651
652 #ifdef HAVE_SETREUID
653 int setreuid(uid_t ruid, uid_t euid)
654 {
655         if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
656                 errno = EINVAL;
657                 return -1;
658         }
659
660         if (!uid_wrapper_enabled()) {
661                 return libc_setreuid(ruid, euid);
662         }
663
664         return uwrap_setresuid(ruid, euid, -1);
665 }
666 #endif
667
668 #ifdef HAVE_SETRESUID
669 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
670 {
671         if (!uid_wrapper_enabled()) {
672                 return libc_setresuid(ruid, euid, suid);
673         }
674
675         return uwrap_setresuid(ruid, euid, suid);
676 }
677 #endif
678
679 /*
680  * GETUID
681  */
682 static uid_t uwrap_getuid(void)
683 {
684         struct uwrap_thread *id = uwrap_tls_id;
685         uid_t uid;
686
687         pthread_mutex_lock(&uwrap_id_mutex);
688         uid = id->ruid;
689         pthread_mutex_unlock(&uwrap_id_mutex);
690
691         return uid;
692 }
693
694 uid_t getuid(void)
695 {
696         if (!uid_wrapper_enabled()) {
697                 return libc_getuid();
698         }
699
700         return uwrap_getuid();
701 }
702
703 /*
704  * GETEUID
705  */
706 static uid_t uwrap_geteuid(void)
707 {
708         const char *env = getenv("UID_WRAPPER_MYUID");
709         struct uwrap_thread *id = uwrap_tls_id;
710         uid_t uid;
711
712         pthread_mutex_lock(&uwrap_id_mutex);
713         uid = id->euid;
714         pthread_mutex_unlock(&uwrap_id_mutex);
715
716         /* Disable root and return myuid */
717         if (env != NULL && env[0] == '1') {
718                 uid = uwrap.myuid;
719         }
720
721         return uid;
722 }
723
724 uid_t geteuid(void)
725 {
726         if (!uid_wrapper_enabled()) {
727                 return libc_geteuid();
728         }
729
730         return uwrap_geteuid();
731 }
732
733 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
734 {
735         struct uwrap_thread *id = uwrap_tls_id;
736
737         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
738                 errno = EINVAL;
739                 return -1;
740         }
741
742         pthread_mutex_lock(&uwrap_id_mutex);
743         if (rgid != (gid_t)-1) {
744                 id->rgid = rgid;
745         }
746
747         if (egid != (gid_t)-1) {
748                 id->egid = egid;
749         }
750
751         if (sgid != (gid_t)-1) {
752                 id->sgid = sgid;
753         }
754         pthread_mutex_unlock(&uwrap_id_mutex);
755
756         return 0;
757 }
758
759 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
760 {
761         struct uwrap_thread *id;
762
763         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
764                 errno = EINVAL;
765                 return -1;
766         }
767
768         pthread_mutex_lock(&uwrap_id_mutex);
769         for (id = uwrap.ids; id; id = id->next) {
770                 if (id->dead) {
771                         continue;
772                 }
773
774                 if (rgid != (gid_t)-1) {
775                         id->rgid = rgid;
776                 }
777
778                 if (egid != (gid_t)-1) {
779                         id->egid = egid;
780                 }
781
782                 if (sgid != (gid_t)-1) {
783                         id->sgid = sgid;
784                 }
785         }
786         pthread_mutex_unlock(&uwrap_id_mutex);
787
788         return 0;
789 }
790
791 /*
792  * SETGID
793  */
794 int setgid(gid_t gid)
795 {
796         if (!uid_wrapper_enabled()) {
797                 return libc_setgid(gid);
798         }
799
800         return uwrap_setresgid(gid, -1, -1);
801 }
802
803 #ifdef HAVE_SETEGID
804 int setegid(gid_t egid)
805 {
806         if (!uid_wrapper_enabled()) {
807                 return libc_setegid(egid);
808         }
809
810         return uwrap_setresgid(-1, egid, -1);
811 }
812 #endif
813
814 #ifdef HAVE_SETREGID
815 int setregid(gid_t rgid, gid_t egid)
816 {
817         if (!uid_wrapper_enabled()) {
818                 return libc_setregid(rgid, egid);
819         }
820
821         return uwrap_setresgid(rgid, egid, -1);
822 }
823 #endif
824
825 #ifdef HAVE_SETRESGID
826 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
827 {
828         if (!uid_wrapper_enabled()) {
829                 return libc_setresgid(rgid, egid, sgid);
830         }
831
832         return uwrap_setresgid(rgid, egid, sgid);
833 }
834 #endif
835
836 /*
837  * GETGID
838  */
839 static gid_t uwrap_getgid(void)
840 {
841         struct uwrap_thread *id = uwrap_tls_id;
842         gid_t gid;
843
844         pthread_mutex_lock(&uwrap_id_mutex);
845         gid = id->rgid;
846         pthread_mutex_unlock(&uwrap_id_mutex);
847
848         return gid;
849 }
850
851 gid_t getgid(void)
852 {
853         if (!uid_wrapper_enabled()) {
854                 return libc_getgid();
855         }
856
857         return uwrap_getgid();
858 }
859
860 /*
861  * GETEGID
862  */
863 static uid_t uwrap_getegid(void)
864 {
865         struct uwrap_thread *id = uwrap_tls_id;
866         gid_t gid;
867
868         pthread_mutex_lock(&uwrap_id_mutex);
869         gid = id->egid;
870         pthread_mutex_unlock(&uwrap_id_mutex);
871
872         return gid;
873 }
874
875 uid_t getegid(void)
876 {
877         if (!uid_wrapper_enabled()) {
878                 return libc_getegid();
879         }
880
881         return uwrap_getegid();
882 }
883
884 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
885 {
886         struct uwrap_thread *id = uwrap_tls_id;
887         int rc = -1;
888
889         pthread_mutex_lock(&uwrap_id_mutex);
890
891         if (size > 0) {
892                 gid_t *tmp;
893
894                 tmp = realloc(id->groups, sizeof(gid_t) * size);
895                 if (tmp == NULL) {
896                         errno = ENOMEM;
897                         goto out;
898                 }
899                 id->groups = tmp;
900
901                 id->ngroups = size;
902                 memcpy(id->groups, list, size * sizeof(gid_t));
903         }
904
905         rc = 0;
906 out:
907         pthread_mutex_unlock(&uwrap_id_mutex);
908
909         return rc;
910 }
911
912 static int uwrap_setgroups(size_t size, const gid_t *list)
913 {
914         struct uwrap_thread *id;
915         int rc = -1;
916
917         pthread_mutex_lock(&uwrap_id_mutex);
918
919         if (size > 0) {
920                 for (id = uwrap.ids; id; id = id->next) {
921                         gid_t *tmp;
922
923                         tmp = realloc(id->groups, sizeof(gid_t) * size);
924                         if (tmp == NULL) {
925                                 errno = ENOMEM;
926                                 goto out;
927                         }
928                         id->groups = tmp;
929
930                         id->ngroups = size;
931                         memcpy(id->groups, list, size * sizeof(gid_t));
932                 }
933         }
934
935         rc = 0;
936 out:
937         pthread_mutex_unlock(&uwrap_id_mutex);
938
939         return rc;
940 }
941
942 #ifdef HAVE_SETGROUPS_INT
943 int setgroups(int size, const gid_t *list)
944 #else
945 int setgroups(size_t size, const gid_t *list)
946 #endif
947 {
948         if (!uid_wrapper_enabled()) {
949                 return libc_setgroups(size, list);
950         }
951
952         return uwrap_setgroups(size, list);
953 }
954
955 static int uwrap_getgroups(int size, gid_t *list)
956 {
957         struct uwrap_thread *id = uwrap_tls_id;
958         int ngroups;
959
960         pthread_mutex_lock(&uwrap_id_mutex);
961         ngroups = id->ngroups;
962
963         if (size > ngroups) {
964                 size = ngroups;
965         }
966         if (size == 0) {
967                 goto out;
968         }
969         if (size < ngroups) {
970                 errno = EINVAL;
971                 ngroups = -1;
972         }
973         memcpy(list, id->groups, size * sizeof(gid_t));
974
975 out:
976         pthread_mutex_unlock(&uwrap_id_mutex);
977
978         return ngroups;
979 }
980
981 int getgroups(int size, gid_t *list)
982 {
983         if (!uid_wrapper_enabled()) {
984                 return libc_getgroups(size, list);
985         }
986
987         return uwrap_getgroups(size, list);
988 }
989
990 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
991     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
992 static long int uwrap_syscall (long int sysno, va_list vp)
993 {
994         long int rc;
995
996         switch (sysno) {
997                 /* gid */
998                 case SYS_getgid:
999 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1000                 case SYS_getgid32:
1001 #endif
1002                         {
1003                                 rc = uwrap_getgid();
1004                         }
1005                         break;
1006 #ifdef SYS_getegid
1007                 case SYS_getegid:
1008 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1009                 case SYS_getegid32:
1010 #endif
1011                         {
1012                                 rc = uwrap_getegid();
1013                         }
1014                         break;
1015 #endif /* SYS_getegid */
1016                 case SYS_setgid:
1017 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1018                 case SYS_setgid32:
1019 #endif
1020                         {
1021                                 gid_t gid = (gid_t) va_arg(vp, int);
1022
1023                                 rc = uwrap_setresgid_thread(gid, -1, -1);
1024                         }
1025                         break;
1026                 case SYS_setregid:
1027 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1028                 case SYS_setregid32:
1029 #endif
1030                         {
1031                                 uid_t rgid = (uid_t) va_arg(vp, int);
1032                                 uid_t egid = (uid_t) va_arg(vp, int);
1033
1034                                 rc = uwrap_setresgid_thread(rgid, egid, -1);
1035                         }
1036                         break;
1037 #ifdef SYS_setresgid
1038                 case SYS_setresgid:
1039 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1040                 case SYS_setresgid32:
1041 #endif
1042                         {
1043                                 uid_t rgid = (uid_t) va_arg(vp, int);
1044                                 uid_t egid = (uid_t) va_arg(vp, int);
1045                                 uid_t sgid = (uid_t) va_arg(vp, int);
1046
1047                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1048                         }
1049                         break;
1050 #endif /* SYS_setresgid */
1051
1052                 /* uid */
1053                 case SYS_getuid:
1054 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1055                 case SYS_getuid32:
1056 #endif
1057                         {
1058                                 rc = uwrap_getuid();
1059                         }
1060                         break;
1061 #ifdef SYS_geteuid
1062                 case SYS_geteuid:
1063 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1064                 case SYS_geteuid32:
1065 #endif
1066                         {
1067                                 rc = uwrap_geteuid();
1068                         }
1069                         break;
1070 #endif /* SYS_geteuid */
1071                 case SYS_setuid:
1072 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1073                 case SYS_setuid32:
1074 #endif
1075                         {
1076                                 uid_t uid = (uid_t) va_arg(vp, int);
1077
1078                                 rc = uwrap_setresuid_thread(uid, -1, -1);
1079                         }
1080                         break;
1081                 case SYS_setreuid:
1082 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1083                 case SYS_setreuid32:
1084 #endif
1085                         {
1086                                 uid_t ruid = (uid_t) va_arg(vp, int);
1087                                 uid_t euid = (uid_t) va_arg(vp, int);
1088
1089                                 rc = uwrap_setresuid_thread(ruid, euid, -1);
1090                         }
1091                         break;
1092 #ifdef SYS_setresuid
1093                 case SYS_setresuid:
1094 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1095                 case SYS_setresuid32:
1096 #endif
1097                         {
1098                                 uid_t ruid = (uid_t) va_arg(vp, int);
1099                                 uid_t euid = (uid_t) va_arg(vp, int);
1100                                 uid_t suid = (uid_t) va_arg(vp, int);
1101
1102                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
1103                         }
1104                         break;
1105 #endif /* SYS_setresuid */
1106
1107                 /* groups */
1108                 case SYS_setgroups:
1109 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1110                 case SYS_setgroups32:
1111 #endif
1112                         {
1113                                 size_t size = (size_t) va_arg(vp, size_t);
1114                                 gid_t *list = (gid_t *) va_arg(vp, int *);
1115
1116                                 rc = uwrap_setgroups_thread(size, list);
1117                         }
1118                         break;
1119                 default:
1120                         UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
1121                                     "%lu\n", sysno);
1122
1123                         rc = libc_vsyscall(sysno, vp);
1124                         break;
1125         }
1126
1127         return rc;
1128 }
1129
1130 #ifdef HAVE_SYSCALL
1131 #ifdef HAVE_SYSCALL_INT
1132 int syscall (int sysno, ...)
1133 #else
1134 long int syscall (long int sysno, ...)
1135 #endif
1136 {
1137 #ifdef HAVE_SYSCALL_INT
1138         int rc;
1139 #else
1140         long int rc;
1141 #endif
1142         va_list va;
1143
1144         va_start(va, sysno);
1145
1146         if (!uid_wrapper_enabled()) {
1147                 rc = libc_vsyscall(sysno, va);
1148                 va_end(va);
1149                 return rc;
1150         }
1151
1152         rc = uwrap_syscall(sysno, va);
1153         va_end(va);
1154
1155         return rc;
1156 }
1157 #endif /* HAVE_SYSCALL */
1158 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1159
1160 /****************************
1161  * DESTRUCTOR
1162  ***************************/
1163
1164 /*
1165  * This function is called when the library is unloaded and makes sure that
1166  * resources are freed.
1167  */
1168 void uwrap_destructor(void)
1169 {
1170         struct uwrap_thread *u = uwrap.ids;
1171
1172         pthread_mutex_lock(&uwrap_id_mutex);
1173         while (u != NULL) {
1174                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1175
1176                 SAFE_FREE(u->groups);
1177                 SAFE_FREE(u);
1178
1179                 u = uwrap.ids;
1180         }
1181         pthread_mutex_unlock(&uwrap_id_mutex);
1182
1183         if (uwrap.libc.handle != NULL) {
1184                 dlclose(uwrap.libc.handle);
1185         }
1186 }