uwrap: Prevent deadlocks if the application forks.
[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 NDEBUG
47 #define UWRAP_DEBUG(...)
48 #else
49 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
50 #endif
51
52 #define UWRAP_DLIST_ADD(list,item) do { \
53         if (!(list)) { \
54                 (item)->prev    = NULL; \
55                 (item)->next    = NULL; \
56                 (list)          = (item); \
57         } else { \
58                 (item)->prev    = NULL; \
59                 (item)->next    = (list); \
60                 (list)->prev    = (item); \
61                 (list)          = (item); \
62         } \
63 } while (0)
64
65 #define UWRAP_DLIST_REMOVE(list,item) do { \
66         if ((list) == (item)) { \
67                 (list)          = (item)->next; \
68                 if (list) { \
69                         (list)->prev    = NULL; \
70                 } \
71         } else { \
72                 if ((item)->prev) { \
73                         (item)->prev->next      = (item)->next; \
74                 } \
75                 if ((item)->next) { \
76                         (item)->next->prev      = (item)->prev; \
77                 } \
78         } \
79         (item)->prev    = NULL; \
80         (item)->next    = NULL; \
81 } while (0)
82
83 #define LIBC_NAME "libc.so"
84
85 struct uwrap_libc_fns {
86         int (*_libc_setuid)(uid_t uid);
87         uid_t (*_libc_getuid)(void);
88
89 #ifdef HAVE_SETEUID
90         int (*_libc_seteuid)(uid_t euid);
91 #endif
92 #ifdef HAVE_SETREUID
93         int (*_libc_setreuid)(uid_t ruid, uid_t euid);
94 #endif
95 #ifdef HAVE_SETREUID
96         int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
97 #endif
98         uid_t (*_libc_geteuid)(void);
99
100         int (*_libc_setgid)(gid_t gid);
101         gid_t (*_libc_getgid)(void);
102 #ifdef HAVE_SETEGID
103         int (*_libc_setegid)(uid_t egid);
104 #endif
105 #ifdef HAVE_SETREGID
106         int (*_libc_setregid)(uid_t rgid, uid_t egid);
107 #endif
108 #ifdef HAVE_SETREGID
109         int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
110 #endif
111         gid_t (*_libc_getegid)(void);
112         int (*_libc_getgroups)(int size, gid_t list[]);
113         int (*_libc_setgroups)(size_t size, const gid_t *list);
114 #ifdef HAVE_SYSCALL
115         long int (*_libc_syscall)(long int sysno, ...);
116 #endif
117 };
118
119 /*
120  * We keep the virtualised euid/egid/groups information here
121  */
122 struct uwrap_thread {
123         pthread_t tid;
124         bool dead;
125
126         uid_t ruid;
127         uid_t euid;
128         uid_t suid;
129
130         gid_t rgid;
131         gid_t egid;
132         gid_t sgid;
133
134         gid_t *groups;
135         int ngroups;
136
137         struct uwrap_thread *next;
138         struct uwrap_thread *prev;
139 };
140
141 struct uwrap {
142         struct {
143                 void *handle;
144                 struct uwrap_libc_fns fns;
145         } libc;
146
147         bool initialised;
148         bool enabled;
149
150         uid_t myuid;
151         uid_t mygid;
152
153         struct uwrap_thread *ids;
154 };
155
156 static struct uwrap uwrap;
157
158 /* Shortcut to the list item */
159 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
160
161 /* The mutex or accessing the id */
162 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
163
164 static void *uwrap_libc_fn(struct uwrap *u, const char *fn_name)
165 {
166         void *func;
167
168         if (u->libc.handle == NULL) {
169                 return NULL;
170         }
171
172         func = dlsym(u->libc.handle, fn_name);
173         if (func == NULL) {
174                 printf("Failed to find %s in %s: %s\n",
175                                 fn_name, LIBC_NAME, dlerror());
176                 exit(-1);
177         }
178
179         return func;
180 }
181
182 static void uwrap_libc_init(struct uwrap *u)
183 {
184         unsigned int i;
185         int flags = RTLD_LAZY;
186
187 #ifdef RTLD_DEEPBIND
188         flags |= RTLD_DEEPBIND;
189 #endif
190
191         for (u->libc.handle = NULL, i = 10; u->libc.handle == NULL; i--) {
192                 char soname[256] = {0};
193
194                 snprintf(soname, sizeof(soname), "%s.%u", LIBC_NAME, i);
195                 u->libc.handle = dlopen(soname, flags);
196         }
197
198         if (u->libc.handle == NULL) {
199                 printf("Failed to dlopen %s.%u: %s\n", LIBC_NAME, i, dlerror());
200                 exit(-1);
201         }
202
203         *(void **) (&u->libc.fns._libc_setuid) = uwrap_libc_fn(u, "setuid");
204         *(void **) (&u->libc.fns._libc_getuid) = uwrap_libc_fn(u, "getuid");
205
206 #ifdef HAVE_SETEUID
207         *(void **) (&u->libc.fns._libc_seteuid) = uwrap_libc_fn(u, "seteuid");
208 #endif
209 #ifdef HAVE_SETREUID
210         *(void **) (&u->libc.fns._libc_setreuid) = uwrap_libc_fn(u, "setreuid");
211 #endif
212 #ifdef HAVE_SETRESUID
213         *(void **) (&u->libc.fns._libc_setresuid) = uwrap_libc_fn(u, "setresuid");
214 #endif
215         *(void **) (&u->libc.fns._libc_geteuid) = uwrap_libc_fn(u, "geteuid");
216
217         *(void **) (&u->libc.fns._libc_setgid) = uwrap_libc_fn(u, "setgid");
218         *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
219 #ifdef HAVE_SETEGID
220         *(void **) (&u->libc.fns._libc_setegid) = uwrap_libc_fn(u, "setegid");
221 #endif
222 #ifdef HAVE_SETREGID
223         *(void **) (&u->libc.fns._libc_setregid) = uwrap_libc_fn(u, "setregid");
224 #endif
225 #ifdef HAVE_SETRESGID
226         *(void **) (&u->libc.fns._libc_setresgid) = uwrap_libc_fn(u, "setresgid");
227 #endif
228         *(void **) (&u->libc.fns._libc_getegid) = uwrap_libc_fn(u, "getegid");
229         *(void **) (&u->libc.fns._libc_getgroups) = uwrap_libc_fn(u, "getgroups");
230         *(void **) (&u->libc.fns._libc_setgroups) = uwrap_libc_fn(u, "setgroups");
231         *(void **) (&u->libc.fns._libc_getuid) = uwrap_libc_fn(u, "getuid");
232         *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
233 #ifdef HAVE_SYSCALL
234         *(void **) (&u->libc.fns._libc_syscall) = uwrap_libc_fn(u, "syscall");
235 #endif
236 }
237
238 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
239 {
240         struct uwrap_thread *id;
241
242         for (id = uwrap.ids; id; id = id->next) {
243                 if (pthread_equal(id->tid, tid)) {
244                         return id;
245                 }
246         }
247
248         return NULL;
249 }
250
251 static int uwrap_new_id(pthread_t tid, bool do_alloc)
252 {
253         struct uwrap_thread *id = uwrap_tls_id;
254
255         if (do_alloc) {
256                 id = malloc(sizeof(struct uwrap_thread));
257                 if (id == NULL) {
258                         errno = ENOMEM;
259                         return -1;
260                 }
261         }
262
263         id->tid = tid;
264         id->dead = false;
265
266         id->ruid = id->euid = id->suid = uwrap.myuid;
267         id->rgid = id->egid = id->sgid = uwrap.mygid;
268
269         id->ngroups = 1;
270         id->groups = malloc(sizeof(gid_t) * id->ngroups);
271         id->groups[0] = uwrap.mygid;
272
273         if (do_alloc) {
274                 UWRAP_DLIST_ADD(uwrap.ids, id);
275                 uwrap_tls_id = id;
276         }
277
278         return 0;
279 }
280
281 static void uwrap_thread_prepare(void)
282 {
283         pthread_mutex_lock(&uwrap_id_mutex);
284
285         /*
286          * What happens if another atfork prepare functions calls a uwrap
287          * function? So disable it in case another atfork prepare function
288          * calls a (s)uid function.
289          */
290         uwrap.enabled = false;
291 }
292
293 static void uwrap_thread_parent(void)
294 {
295         uwrap.enabled = true;
296
297         pthread_mutex_unlock(&uwrap_id_mutex);
298 }
299
300 static void uwrap_thread_child(void)
301 {
302         uwrap.enabled = true;
303
304         pthread_mutex_unlock(&uwrap_id_mutex);
305 }
306
307 static void uwrap_init(void)
308 {
309         const char *env = getenv("UID_WRAPPER");
310         pthread_t tid = pthread_self();
311
312
313
314         if (uwrap.initialised) {
315                 struct uwrap_thread *id = uwrap_tls_id;
316                 int rc;
317
318                 /*
319                  * If we hold a lock and the application forks, then the child
320                  * is not able to unlock the mutex and we are in a deadlock.
321                  * This should prevent such deadlocks.
322                  */
323                 pthread_atfork(&uwrap_thread_prepare,
324                                &uwrap_thread_parent,
325                                &uwrap_thread_child);
326
327                 if (id != NULL) {
328                         return;
329                 }
330
331                 pthread_mutex_lock(&uwrap_id_mutex);
332                 id = find_uwrap_id(tid);
333                 if (id == NULL) {
334                         rc = uwrap_new_id(tid, 1);
335                         if (rc < 0) {
336                                 exit(-1);
337                         }
338                 } else {
339                         /* We reuse an old thread id */
340                         uwrap_tls_id = id;
341
342                         uwrap_new_id(tid, 0);
343                 }
344                 pthread_mutex_unlock(&uwrap_id_mutex);
345
346                 return;
347         }
348
349         pthread_mutex_lock(&uwrap_id_mutex);
350
351         uwrap_libc_init(&uwrap);
352
353         uwrap.initialised = true;
354         uwrap.enabled = false;
355
356         if (env != NULL && env[0] == '1') {
357                 const char *root = getenv("UID_WRAPPER_ROOT");
358                 int rc;
359
360                 /* put us in one group */
361                 if (root != NULL && root[0] == '1') {
362                         uwrap.myuid = 0;
363                         uwrap.mygid = 0;
364                 } else {
365                         uwrap.myuid = uwrap.libc.fns._libc_geteuid();
366                         uwrap.mygid = uwrap.libc.fns._libc_getegid();
367                 }
368
369                 rc = uwrap_new_id(tid, 1);
370                 if (rc < 0) {
371                         exit(-1);
372                 }
373
374                 uwrap.enabled = true;
375         }
376
377         pthread_mutex_unlock(&uwrap_id_mutex);
378 }
379
380 static int uwrap_enabled(void)
381 {
382         uwrap_init();
383
384         return uwrap.enabled ? 1 : 0;
385 }
386
387 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
388 {
389         struct uwrap_thread *id = uwrap_tls_id;
390
391         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
392                 errno = EINVAL;
393                 return -1;
394         }
395
396         pthread_mutex_lock(&uwrap_id_mutex);
397         if (ruid != (uid_t)-1) {
398                 id->ruid = ruid;
399         }
400
401         if (euid != (uid_t)-1) {
402                 id->euid = euid;
403         }
404
405         if (suid != (uid_t)-1) {
406                 id->suid = suid;
407         }
408         pthread_mutex_unlock(&uwrap_id_mutex);
409
410         return 0;
411 }
412
413 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
414 {
415         struct uwrap_thread *id;
416
417         if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
418                 errno = EINVAL;
419                 return -1;
420         }
421
422         pthread_mutex_lock(&uwrap_id_mutex);
423         for (id = uwrap.ids; id; id = id->next) {
424                 if (id->dead) {
425                         continue;
426                 }
427
428                 if (ruid != (uid_t)-1) {
429                         id->ruid = ruid;
430                 }
431
432                 if (euid != (uid_t)-1) {
433                         id->euid = euid;
434                 }
435
436                 if (suid != (uid_t)-1) {
437                         id->suid = suid;
438                 }
439         }
440         pthread_mutex_unlock(&uwrap_id_mutex);
441
442         return 0;
443 }
444
445 /*
446  * SETUID
447  */
448 int setuid(uid_t uid)
449 {
450         if (!uwrap_enabled()) {
451                 return uwrap.libc.fns._libc_setuid(uid);
452         }
453
454         return uwrap_setresuid(uid, -1, -1);
455 }
456
457 #ifdef HAVE_SETEUID
458 int seteuid(uid_t euid)
459 {
460         if (euid == (uid_t)-1) {
461                 errno = EINVAL;
462                 return -1;
463         }
464
465         if (!uwrap_enabled()) {
466                 return uwrap.libc.fns._libc_seteuid(euid);
467         }
468
469         return uwrap_setresuid(-1, euid, -1);
470 }
471 #endif
472
473 #ifdef HAVE_SETREUID
474 int setreuid(uid_t ruid, uid_t euid)
475 {
476         if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
477                 errno = EINVAL;
478                 return -1;
479         }
480
481         if (!uwrap_enabled()) {
482                 return uwrap.libc.fns._libc_setreuid(ruid, euid);
483         }
484
485         return uwrap_setresuid(ruid, euid, -1);
486 }
487 #endif
488
489 #ifdef HAVE_SETRESUID
490 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
491 {
492         if (!uwrap_enabled()) {
493                 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
494         }
495
496         return uwrap_setresuid(ruid, euid, suid);
497 }
498 #endif
499
500 /*
501  * GETUID
502  */
503 static uid_t uwrap_getuid(void)
504 {
505         struct uwrap_thread *id = uwrap_tls_id;
506         uid_t uid;
507
508         pthread_mutex_lock(&uwrap_id_mutex);
509         uid = id->ruid;
510         pthread_mutex_unlock(&uwrap_id_mutex);
511
512         return uid;
513 }
514
515 uid_t getuid(void)
516 {
517         if (!uwrap_enabled()) {
518                 return uwrap.libc.fns._libc_getuid();
519         }
520
521         return uwrap_getuid();
522 }
523
524 /*
525  * GETEUID
526  */
527 static uid_t uwrap_geteuid(void)
528 {
529         const char *env = getenv("UID_WRAPPER_ROOT");
530         struct uwrap_thread *id = uwrap_tls_id;
531         uid_t uid;
532
533         pthread_mutex_lock(&uwrap_id_mutex);
534         uid = id->euid;
535         pthread_mutex_unlock(&uwrap_id_mutex);
536
537         /* Disable root and return myuid */
538         if (env != NULL && env[0] == '2') {
539                 uid = uwrap.myuid;
540         }
541
542         return uid;
543 }
544
545 uid_t geteuid(void)
546 {
547         if (!uwrap_enabled()) {
548                 return uwrap.libc.fns._libc_geteuid();
549         }
550
551         return uwrap_geteuid();
552 }
553
554 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
555 {
556         struct uwrap_thread *id = uwrap_tls_id;
557
558         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
559                 errno = EINVAL;
560                 return -1;
561         }
562
563         pthread_mutex_lock(&uwrap_id_mutex);
564         if (rgid != (gid_t)-1) {
565                 id->rgid = rgid;
566         }
567
568         if (egid != (gid_t)-1) {
569                 id->egid = egid;
570         }
571
572         if (sgid != (gid_t)-1) {
573                 id->sgid = sgid;
574         }
575         pthread_mutex_unlock(&uwrap_id_mutex);
576
577         return 0;
578 }
579
580 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
581 {
582         struct uwrap_thread *id;
583
584         if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
585                 errno = EINVAL;
586                 return -1;
587         }
588
589         pthread_mutex_lock(&uwrap_id_mutex);
590         for (id = uwrap.ids; id; id = id->next) {
591                 if (id->dead) {
592                         continue;
593                 }
594
595                 if (rgid != (gid_t)-1) {
596                         id->rgid = rgid;
597                 }
598
599                 if (egid != (gid_t)-1) {
600                         id->egid = egid;
601                 }
602
603                 if (sgid != (gid_t)-1) {
604                         id->sgid = sgid;
605                 }
606         }
607         pthread_mutex_unlock(&uwrap_id_mutex);
608
609         return 0;
610 }
611
612 /*
613  * SETGID
614  */
615 int setgid(gid_t gid)
616 {
617         if (!uwrap_enabled()) {
618                 return uwrap.libc.fns._libc_setgid(gid);
619         }
620
621         return uwrap_setresgid(gid, -1, -1);
622 }
623
624 #ifdef HAVE_SETEGID
625 int setegid(gid_t egid)
626 {
627         if (!uwrap_enabled()) {
628                 return uwrap.libc.fns._libc_setegid(egid);
629         }
630
631         return uwrap_setresgid(-1, egid, -1);
632 }
633 #endif
634
635 #ifdef HAVE_SETREGID
636 int setregid(gid_t rgid, gid_t egid)
637 {
638         if (!uwrap_enabled()) {
639                 return uwrap.libc.fns._libc_setregid(rgid, egid);
640         }
641
642         return uwrap_setresgid(rgid, egid, -1);
643 }
644 #endif
645
646 #ifdef HAVE_SETRESGID
647 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
648 {
649         if (!uwrap_enabled()) {
650                 return uwrap.libc.fns._libc_setregid(rgid, egid, sgid);
651         }
652
653         return uwrap_setresgid(rgid, egid, sgid);
654 }
655 #endif
656
657 /*
658  * GETGID
659  */
660 static gid_t uwrap_getgid(void)
661 {
662         struct uwrap_thread *id = uwrap_tls_id;
663         gid_t gid;
664
665         pthread_mutex_lock(&uwrap_id_mutex);
666         gid = id->rgid;
667         pthread_mutex_unlock(&uwrap_id_mutex);
668
669         return gid;
670 }
671
672 gid_t getgid(void)
673 {
674         if (!uwrap_enabled()) {
675                 return uwrap.libc.fns._libc_getgid();
676         }
677
678         return uwrap_getgid();
679 }
680
681 /*
682  * GETEGID
683  */
684 static uid_t uwrap_getegid(void)
685 {
686         struct uwrap_thread *id = uwrap_tls_id;
687         gid_t gid;
688
689         pthread_mutex_lock(&uwrap_id_mutex);
690         gid = id->egid;
691         pthread_mutex_unlock(&uwrap_id_mutex);
692
693         return gid;
694 }
695
696 uid_t getegid(void)
697 {
698         if (!uwrap_enabled()) {
699                 return uwrap.libc.fns._libc_getegid();
700         }
701
702         return uwrap_getegid();
703 }
704
705 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
706 {
707         struct uwrap_thread *id = uwrap_tls_id;
708         int rc = -1;
709
710         pthread_mutex_lock(&uwrap_id_mutex);
711         free(id->groups);
712         id->groups = NULL;
713         id->ngroups = 0;
714
715         if (size != 0) {
716                 id->groups = malloc(sizeof(gid_t) * size);
717                 if (id->groups == NULL) {
718                         errno = ENOMEM;
719                         goto out;
720                 }
721                 id->ngroups = size;
722                 memcpy(id->groups, list, size * sizeof(gid_t));
723         }
724
725         rc = 0;
726 out:
727         pthread_mutex_unlock(&uwrap_id_mutex);
728
729         return rc;
730 }
731
732 static int uwrap_setgroups(size_t size, const gid_t *list)
733 {
734         struct uwrap_thread *id;
735         int rc = -1;
736
737         pthread_mutex_lock(&uwrap_id_mutex);
738         for (id = uwrap.ids; id; id = id->next) {
739                 free(id->groups);
740                 id->groups = NULL;
741                 id->ngroups = 0;
742
743                 if (size != 0) {
744                         id->groups = malloc(sizeof(gid_t) * size);
745                         if (id->groups == NULL) {
746                                 errno = ENOMEM;
747                                 goto out;
748                         }
749                         id->ngroups = size;
750                         memcpy(id->groups, list, size * sizeof(gid_t));
751                 }
752         }
753
754         rc = 0;
755 out:
756         pthread_mutex_unlock(&uwrap_id_mutex);
757
758         return rc;
759 }
760
761 int setgroups(size_t size, const gid_t *list)
762 {
763         if (!uwrap_enabled()) {
764                 return uwrap.libc.fns._libc_setgroups(size, list);
765         }
766
767         return uwrap_setgroups(size, list);
768 }
769
770 static int uwrap_getgroups(int size, gid_t *list)
771 {
772         struct uwrap_thread *id = uwrap_tls_id;
773         int ngroups;
774
775         pthread_mutex_lock(&uwrap_id_mutex);
776         ngroups = id->ngroups;
777
778         if (size > ngroups) {
779                 size = ngroups;
780         }
781         if (size == 0) {
782                 goto out;
783         }
784         if (size < ngroups) {
785                 errno = EINVAL;
786                 ngroups = -1;
787         }
788         memcpy(list, id->groups, size * sizeof(gid_t));
789
790 out:
791         pthread_mutex_unlock(&uwrap_id_mutex);
792
793         return ngroups;
794 }
795
796 int getgroups(int size, gid_t *list)
797 {
798         if (!uwrap_enabled()) {
799                 return uwrap.libc.fns._libc_getgroups(size, list);
800         }
801
802         return uwrap_getgroups(size, list);
803 }
804
805 static long int libc_vsyscall(long int sysno, va_list va)
806 {
807         long int args[8];
808         long int rc;
809         int i;
810
811         for (i = 0; i < 8; i++) {
812                 args[i] = va_arg(va, long int);
813         }
814
815         rc = uwrap.libc.fns._libc_syscall(sysno,
816                                           args[0],
817                                           args[1],
818                                           args[2],
819                                           args[3],
820                                           args[4],
821                                           args[5],
822                                           args[6],
823                                           args[7]);
824
825         return rc;
826 }
827
828 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
829     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
830 static long int uwrap_syscall (long int sysno, va_list vp)
831 {
832         long int rc;
833
834         switch (sysno) {
835                 /* gid */
836                 case SYS_getgid:
837 #ifdef HAVE_LINUX_32BIT_SYSCALLS
838                 case SYS_getgid32:
839 #endif
840                         {
841                                 rc = uwrap_getgid();
842                         }
843                         break;
844                 case SYS_getegid:
845 #ifdef HAVE_LINUX_32BIT_SYSCALLS
846                 case SYS_getegid32:
847 #endif
848                         {
849                                 rc = uwrap_getegid();
850                         }
851                         break;
852                 case SYS_setgid:
853 #ifdef HAVE_LINUX_32BIT_SYSCALLS
854                 case SYS_setgid32:
855 #endif
856                         {
857                                 gid_t gid = (gid_t) va_arg(vp, int);
858
859                                 rc = uwrap_setresgid_thread(gid, -1, -1);
860                         }
861                         break;
862                 case SYS_setregid:
863 #ifdef HAVE_LINUX_32BIT_SYSCALLS
864                 case SYS_setregid32:
865 #endif
866                         {
867                                 uid_t rgid = (uid_t) va_arg(vp, int);
868                                 uid_t egid = (uid_t) va_arg(vp, int);
869
870                                 rc = uwrap_setresgid_thread(rgid, egid, -1);
871                         }
872                         break;
873                 case SYS_setresgid:
874 #ifdef HAVE_LINUX_32BIT_SYSCALLS
875                 case SYS_setresgid32:
876 #endif
877                         {
878                                 uid_t rgid = (uid_t) va_arg(vp, int);
879                                 uid_t egid = (uid_t) va_arg(vp, int);
880                                 uid_t sgid = (uid_t) va_arg(vp, int);
881
882                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
883                         }
884                         break;
885
886                 /* uid */
887                 case SYS_getuid:
888 #ifdef HAVE_LINUX_32BIT_SYSCALLS
889                 case SYS_getuid32:
890 #endif
891                         {
892                                 rc = uwrap_getuid();
893                         }
894                         break;
895                 case SYS_geteuid:
896 #ifdef HAVE_LINUX_32BIT_SYSCALLS
897                 case SYS_geteuid32:
898 #endif
899                         {
900                                 rc = uwrap_geteuid();
901                         }
902                         break;
903                 case SYS_setuid:
904 #ifdef HAVE_LINUX_32BIT_SYSCALLS
905                 case SYS_setuid32:
906 #endif
907                         {
908                                 uid_t uid = (uid_t) va_arg(vp, int);
909
910                                 rc = uwrap_setresuid_thread(uid, -1, -1);
911                         }
912                         break;
913                 case SYS_setreuid:
914 #ifdef HAVE_LINUX_32BIT_SYSCALLS
915                 case SYS_setreuid32:
916 #endif
917                         {
918                                 uid_t ruid = (uid_t) va_arg(vp, int);
919                                 uid_t euid = (uid_t) va_arg(vp, int);
920
921                                 rc = uwrap_setresuid_thread(ruid, euid, -1);
922                         }
923                         break;
924                 case SYS_setresuid:
925 #ifdef HAVE_LINUX_32BIT_SYSCALLS
926                 case SYS_setresuid32:
927 #endif
928                         {
929                                 uid_t ruid = (uid_t) va_arg(vp, int);
930                                 uid_t euid = (uid_t) va_arg(vp, int);
931                                 uid_t suid = (uid_t) va_arg(vp, int);
932
933                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
934                         }
935                         break;
936
937                 /* groups */
938                 case SYS_setgroups:
939 #ifdef HAVE_LINUX_32BIT_SYSCALLS
940                 case SYS_setgroups32:
941 #endif
942                         {
943                                 size_t size = (size_t) va_arg(vp, size_t);
944                                 gid_t *list = (gid_t *) va_arg(vp, int *);
945
946                                 rc = uwrap_setgroups_thread(size, list);
947                         }
948                         break;
949                 default:
950                         UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
951                                     "%lu\n", sysno);
952
953                         rc = libc_vsyscall(sysno, vp);
954                         break;
955         }
956
957         return rc;
958 }
959
960 #ifdef HAVE_SYSCALL
961 long int syscall (long int sysno, ...)
962 {
963         long int rc;
964         va_list va;
965
966         va_start(va, sysno);
967
968         if (!uwrap_enabled()) {
969                 rc = libc_vsyscall(sysno, va);
970                 va_end(va);
971                 return rc;
972         }
973
974         rc = uwrap_syscall(sysno, va);
975         va_end(va);
976
977         return rc;
978 }
979 #endif /* HAVE_SYSCALL */
980 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */