s3:lib: fix const warnings in popt_common.c
[Samba.git] / lib / uid_wrapper / uid_wrapper.c
blob2181767246ebe38b6582a36986108f25b6ac1c7c
1 /*
2 * Copyright (c) 2009 Andrew Tridgell
3 * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
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.
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.
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/>.
19 #include "config.h"
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>
38 #include <pthread.h>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
42 #else
43 # define UWRAP_THREAD
44 #endif
46 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
47 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
48 #else
49 #define DESTRUCTOR_ATTRIBUTE
50 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
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 */
59 #define UWRAP_DLIST_ADD(list,item) do { \
60 if (!(list)) { \
61 (item)->prev = NULL; \
62 (item)->next = NULL; \
63 (list) = (item); \
64 } else { \
65 (item)->prev = NULL; \
66 (item)->next = (list); \
67 (list)->prev = (item); \
68 (list) = (item); \
69 } \
70 } while (0)
72 #define UWRAP_DLIST_REMOVE(list,item) do { \
73 if ((list) == (item)) { \
74 (list) = (item)->next; \
75 if (list) { \
76 (list)->prev = NULL; \
77 } \
78 } else { \
79 if ((item)->prev) { \
80 (item)->prev->next = (item)->next; \
81 } \
82 if ((item)->next) { \
83 (item)->next->prev = (item)->prev; \
84 } \
85 } \
86 (item)->prev = NULL; \
87 (item)->next = NULL; \
88 } while (0)
90 #ifndef SAFE_FREE
91 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
92 #endif
94 /*****************
95 * LOGGING
96 *****************/
98 enum uwrap_dbglvl_e {
99 UWRAP_LOG_ERROR = 0,
100 UWRAP_LOG_WARN,
101 UWRAP_LOG_DEBUG,
102 UWRAP_LOG_TRACE
105 #ifdef NDEBUG
106 # define UWRAP_LOG(...)
107 #else /* NDEBUG */
108 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
109 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __VA_ARGS__)
111 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *format, ...)
113 char buffer[1024];
114 va_list va;
115 const char *d;
116 unsigned int lvl = 0;
118 d = getenv("UID_WRAPPER_DEBUGLEVEL");
119 if (d != NULL) {
120 lvl = atoi(d);
123 va_start(va, format);
124 vsnprintf(buffer, sizeof(buffer), format, va);
125 va_end(va);
127 if (lvl >= dbglvl) {
128 switch (dbglvl) {
129 case UWRAP_LOG_ERROR:
130 fprintf(stderr,
131 "UWRAP_ERROR(%d): %s\n",
132 (int)getpid(), buffer);
133 break;
134 case UWRAP_LOG_WARN:
135 fprintf(stderr,
136 "UWRAP_WARN(%d): %s\n",
137 (int)getpid(), buffer);
138 break;
139 case UWRAP_LOG_DEBUG:
140 fprintf(stderr,
141 "UWRAP_DEBUG(%d): %s\n",
142 (int)getpid(), buffer);
143 break;
144 case UWRAP_LOG_TRACE:
145 fprintf(stderr,
146 "UWRAP_TRACE(%d): %s\n",
147 (int)getpid(), buffer);
148 break;
152 #endif /* NDEBUG */
154 /*****************
155 * LIBC
156 *****************/
158 #define LIBC_NAME "libc.so"
160 struct uwrap_libc_fns {
161 int (*_libc_setuid)(uid_t uid);
162 uid_t (*_libc_getuid)(void);
164 #ifdef HAVE_SETEUID
165 int (*_libc_seteuid)(uid_t euid);
166 #endif
167 #ifdef HAVE_SETREUID
168 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
169 #endif
170 #ifdef HAVE_SETRESUID
171 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
172 #endif
173 uid_t (*_libc_geteuid)(void);
175 int (*_libc_setgid)(gid_t gid);
176 gid_t (*_libc_getgid)(void);
177 #ifdef HAVE_SETEGID
178 int (*_libc_setegid)(uid_t egid);
179 #endif
180 #ifdef HAVE_SETREGID
181 int (*_libc_setregid)(uid_t rgid, uid_t egid);
182 #endif
183 #ifdef HAVE_SETRESGID
184 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
185 #endif
186 gid_t (*_libc_getegid)(void);
187 int (*_libc_getgroups)(int size, gid_t list[]);
188 int (*_libc_setgroups)(size_t size, const gid_t *list);
189 #ifdef HAVE_SYSCALL
190 long int (*_libc_syscall)(long int sysno, ...);
191 #endif
195 * We keep the virtualised euid/egid/groups information here
197 struct uwrap_thread {
198 pthread_t tid;
199 bool dead;
201 uid_t ruid;
202 uid_t euid;
203 uid_t suid;
205 gid_t rgid;
206 gid_t egid;
207 gid_t sgid;
209 gid_t *groups;
210 int ngroups;
212 struct uwrap_thread *next;
213 struct uwrap_thread *prev;
216 struct uwrap {
217 struct {
218 void *handle;
219 struct uwrap_libc_fns fns;
220 } libc;
222 bool initialised;
223 bool enabled;
225 uid_t myuid;
226 uid_t mygid;
228 struct uwrap_thread *ids;
231 static struct uwrap uwrap;
233 /* Shortcut to the list item */
234 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
236 /* The mutex or accessing the id */
237 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
239 /*********************************************************
240 * UWRAP PROTOTYPES
241 *********************************************************/
243 bool uid_wrapper_enabled(void);
244 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
246 /*********************************************************
247 * UWRAP LIBC LOADER FUNCTIONS
248 *********************************************************/
250 enum uwrap_lib {
251 UWRAP_LIBC,
252 UWRAP_LIBNSL,
253 UWRAP_LIBSOCKET,
256 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
258 int flags = RTLD_LAZY;
259 void *handle = NULL;
260 int i;
262 #ifdef RTLD_DEEPBIND
263 flags |= RTLD_DEEPBIND;
264 #endif
266 switch (lib) {
267 case UWRAP_LIBNSL:
268 /* FALL TROUGH */
269 case UWRAP_LIBSOCKET:
270 /* FALL TROUGH */
271 case UWRAP_LIBC:
272 handle = uwrap.libc.handle;
273 if (handle == NULL) {
274 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
275 char soname[256] = {0};
277 snprintf(soname, sizeof(soname), "libc.so.%d", i);
278 handle = dlopen(soname, flags);
281 uwrap.libc.handle = handle;
283 break;
286 if (handle == NULL) {
287 #ifdef RTLD_NEXT
288 handle = uwrap.libc.handle = RTLD_NEXT;
289 #else
290 fprintf(stderr,
291 "Failed to dlopen library: %s\n",
292 dlerror());
293 exit(-1);
294 #endif
297 return handle;
300 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
302 void *handle;
303 void *func;
305 handle = uwrap_load_lib_handle(lib);
307 func = dlsym(handle, fn_name);
308 if (func == NULL) {
309 fprintf(stderr,
310 "Failed to find %s: %s\n",
311 fn_name, dlerror());
312 exit(-1);
315 return func;
318 #define uwrap_load_lib_function(lib, fn_name) \
319 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
320 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
321 _uwrap_load_lib_function(lib, #fn_name); \
325 * IMPORTANT
327 * Functions expeciall from libc need to be loaded individually, you can't load
328 * all at once or gdb will segfault at startup. The same applies to valgrind and
329 * has probably something todo with with the linker.
330 * So we need load each function at the point it is called the first time.
332 static int libc_setuid(uid_t uid)
334 uwrap_load_lib_function(UWRAP_LIBC, setuid);
336 return uwrap.libc.fns._libc_setuid(uid);
339 static uid_t libc_getuid(void)
341 uwrap_load_lib_function(UWRAP_LIBC, getuid);
343 return uwrap.libc.fns._libc_getuid();
346 #ifdef HAVE_SETEUID
347 static int libc_seteuid(uid_t euid)
349 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
351 return uwrap.libc.fns._libc_seteuid(euid);
353 #endif
355 #ifdef HAVE_SETREUID
356 static int libc_setreuid(uid_t ruid, uid_t euid)
358 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
360 return uwrap.libc.fns._libc_setreuid(ruid, euid);
362 #endif
364 #ifdef HAVE_SETRESUID
365 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
367 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
369 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
371 #endif
373 static uid_t libc_geteuid(void)
375 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
377 return uwrap.libc.fns._libc_geteuid();
380 static int libc_setgid(gid_t gid)
382 uwrap_load_lib_function(UWRAP_LIBC, setgid);
384 return uwrap.libc.fns._libc_setgid(gid);
387 static gid_t libc_getgid(void)
389 uwrap_load_lib_function(UWRAP_LIBC, getgid);
391 return uwrap.libc.fns._libc_getgid();
394 #ifdef HAVE_SETEGID
395 static int libc_setegid(gid_t egid)
397 uwrap_load_lib_function(UWRAP_LIBC, setegid);
399 return uwrap.libc.fns._libc_setegid(egid);
401 #endif
403 #ifdef HAVE_SETREGID
404 static int libc_setregid(gid_t rgid, gid_t egid)
406 uwrap_load_lib_function(UWRAP_LIBC, setregid);
408 return uwrap.libc.fns._libc_setregid(rgid, egid);
410 #endif
412 #ifdef HAVE_SETRESGID
413 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
415 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
417 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
419 #endif
421 static gid_t libc_getegid(void)
423 uwrap_load_lib_function(UWRAP_LIBC, getegid);
425 return uwrap.libc.fns._libc_getegid();
428 static int libc_getgroups(int size, gid_t list[])
430 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
432 return uwrap.libc.fns._libc_getgroups(size, list);
435 static int libc_setgroups(size_t size, const gid_t *list)
437 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
439 return uwrap.libc.fns._libc_setgroups(size, list);
442 #ifdef HAVE_SYSCALL
443 static long int libc_vsyscall(long int sysno, va_list va)
445 long int args[8];
446 long int rc;
447 int i;
449 uwrap_load_lib_function(UWRAP_LIBC, syscall);
451 for (i = 0; i < 8; i++) {
452 args[i] = va_arg(va, long int);
455 rc = uwrap.libc.fns._libc_syscall(sysno,
456 args[0],
457 args[1],
458 args[2],
459 args[3],
460 args[4],
461 args[5],
462 args[6],
463 args[7]);
465 return rc;
467 #endif
469 /*********************************************************
470 * UWRAP ID HANDLING
471 *********************************************************/
473 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
475 struct uwrap_thread *id;
477 for (id = uwrap.ids; id; id = id->next) {
478 if (pthread_equal(id->tid, tid)) {
479 return id;
483 return NULL;
486 static int uwrap_new_id(pthread_t tid, bool do_alloc)
488 struct uwrap_thread *id = uwrap_tls_id;
490 if (do_alloc) {
491 id = malloc(sizeof(struct uwrap_thread));
492 if (id == NULL) {
493 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
494 errno = ENOMEM;
495 return -1;
498 id->groups = malloc(sizeof(gid_t) * 1);
499 if (id->groups == NULL) {
500 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
501 SAFE_FREE(id);
502 errno = ENOMEM;
503 return -1;
506 UWRAP_DLIST_ADD(uwrap.ids, id);
507 uwrap_tls_id = id;
510 id->tid = tid;
511 id->dead = false;
513 id->ruid = id->euid = id->suid = uwrap.myuid;
514 id->rgid = id->egid = id->sgid = uwrap.mygid;
516 id->ngroups = 1;
517 id->groups[0] = uwrap.mygid;
519 return 0;
522 static void uwrap_thread_prepare(void)
524 pthread_mutex_lock(&uwrap_id_mutex);
527 * What happens if another atfork prepare functions calls a uwrap
528 * function? So disable it in case another atfork prepare function
529 * calls a (s)uid function.
531 uwrap.enabled = false;
534 static void uwrap_thread_parent(void)
536 uwrap.enabled = true;
538 pthread_mutex_unlock(&uwrap_id_mutex);
541 static void uwrap_thread_child(void)
543 uwrap.enabled = true;
545 pthread_mutex_unlock(&uwrap_id_mutex);
548 static void uwrap_init(void)
550 const char *env = getenv("UID_WRAPPER");
551 pthread_t tid = pthread_self();
555 if (uwrap.initialised) {
556 struct uwrap_thread *id = uwrap_tls_id;
557 int rc;
559 if (id != NULL) {
560 return;
563 pthread_mutex_lock(&uwrap_id_mutex);
564 id = find_uwrap_id(tid);
565 if (id == NULL) {
566 rc = uwrap_new_id(tid, true);
567 if (rc < 0) {
568 exit(-1);
570 } else {
571 /* We reuse an old thread id */
572 uwrap_tls_id = id;
574 uwrap_new_id(tid, false);
576 pthread_mutex_unlock(&uwrap_id_mutex);
578 return;
581 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
584 * If we hold a lock and the application forks, then the child
585 * is not able to unlock the mutex and we are in a deadlock.
586 * This should prevent such deadlocks.
588 pthread_atfork(&uwrap_thread_prepare,
589 &uwrap_thread_parent,
590 &uwrap_thread_child);
592 pthread_mutex_lock(&uwrap_id_mutex);
594 uwrap.initialised = true;
595 uwrap.enabled = false;
597 if (env != NULL && env[0] == '1') {
598 const char *root = getenv("UID_WRAPPER_ROOT");
599 int rc;
601 /* put us in one group */
602 if (root != NULL && root[0] == '1') {
603 uwrap.myuid = 0;
604 uwrap.mygid = 0;
605 } else {
606 uwrap.myuid = libc_geteuid();
607 uwrap.mygid = libc_getegid();
610 rc = uwrap_new_id(tid, true);
611 if (rc < 0) {
612 exit(-1);
615 uwrap.enabled = true;
617 UWRAP_LOG(UWRAP_LOG_DEBUG,
618 "Enabled uid_wrapper as %s",
619 uwrap.myuid == 0 ? "root" : "user");
622 pthread_mutex_unlock(&uwrap_id_mutex);
624 UWRAP_LOG(UWRAP_LOG_DEBUG, "Succeccfully initialized uid_wrapper");
627 bool uid_wrapper_enabled(void)
629 uwrap_init();
631 return uwrap.enabled ? true : false;
634 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
636 struct uwrap_thread *id = uwrap_tls_id;
638 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
639 errno = EINVAL;
640 return -1;
643 pthread_mutex_lock(&uwrap_id_mutex);
644 if (ruid != (uid_t)-1) {
645 id->ruid = ruid;
648 if (euid != (uid_t)-1) {
649 id->euid = euid;
652 if (suid != (uid_t)-1) {
653 id->suid = suid;
655 pthread_mutex_unlock(&uwrap_id_mutex);
657 return 0;
660 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
662 struct uwrap_thread *id;
664 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
665 errno = EINVAL;
666 return -1;
669 pthread_mutex_lock(&uwrap_id_mutex);
670 for (id = uwrap.ids; id; id = id->next) {
671 if (id->dead) {
672 continue;
675 if (ruid != (uid_t)-1) {
676 id->ruid = ruid;
679 if (euid != (uid_t)-1) {
680 id->euid = euid;
683 if (suid != (uid_t)-1) {
684 id->suid = suid;
687 pthread_mutex_unlock(&uwrap_id_mutex);
689 return 0;
693 * SETUID
695 int setuid(uid_t uid)
697 if (!uid_wrapper_enabled()) {
698 return libc_setuid(uid);
701 return uwrap_setresuid(uid, -1, -1);
704 #ifdef HAVE_SETEUID
705 int seteuid(uid_t euid)
707 if (euid == (uid_t)-1) {
708 errno = EINVAL;
709 return -1;
712 if (!uid_wrapper_enabled()) {
713 return libc_seteuid(euid);
716 return uwrap_setresuid(-1, euid, -1);
718 #endif
720 #ifdef HAVE_SETREUID
721 int setreuid(uid_t ruid, uid_t euid)
723 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
724 errno = EINVAL;
725 return -1;
728 if (!uid_wrapper_enabled()) {
729 return libc_setreuid(ruid, euid);
732 return uwrap_setresuid(ruid, euid, -1);
734 #endif
736 #ifdef HAVE_SETRESUID
737 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
739 if (!uid_wrapper_enabled()) {
740 return libc_setresuid(ruid, euid, suid);
743 return uwrap_setresuid(ruid, euid, suid);
745 #endif
748 * GETUID
750 static uid_t uwrap_getuid(void)
752 struct uwrap_thread *id = uwrap_tls_id;
753 uid_t uid;
755 pthread_mutex_lock(&uwrap_id_mutex);
756 uid = id->ruid;
757 pthread_mutex_unlock(&uwrap_id_mutex);
759 return uid;
762 uid_t getuid(void)
764 if (!uid_wrapper_enabled()) {
765 return libc_getuid();
768 return uwrap_getuid();
772 * GETEUID
774 static uid_t uwrap_geteuid(void)
776 const char *env = getenv("UID_WRAPPER_MYUID");
777 struct uwrap_thread *id = uwrap_tls_id;
778 uid_t uid;
780 pthread_mutex_lock(&uwrap_id_mutex);
781 uid = id->euid;
782 pthread_mutex_unlock(&uwrap_id_mutex);
784 /* Disable root and return myuid */
785 if (env != NULL && env[0] == '1') {
786 uid = uwrap.myuid;
789 return uid;
792 uid_t geteuid(void)
794 if (!uid_wrapper_enabled()) {
795 return libc_geteuid();
798 return uwrap_geteuid();
801 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
803 struct uwrap_thread *id = uwrap_tls_id;
805 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
806 errno = EINVAL;
807 return -1;
810 pthread_mutex_lock(&uwrap_id_mutex);
811 if (rgid != (gid_t)-1) {
812 id->rgid = rgid;
815 if (egid != (gid_t)-1) {
816 id->egid = egid;
819 if (sgid != (gid_t)-1) {
820 id->sgid = sgid;
822 pthread_mutex_unlock(&uwrap_id_mutex);
824 return 0;
827 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
829 struct uwrap_thread *id;
831 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
832 errno = EINVAL;
833 return -1;
836 pthread_mutex_lock(&uwrap_id_mutex);
837 for (id = uwrap.ids; id; id = id->next) {
838 if (id->dead) {
839 continue;
842 if (rgid != (gid_t)-1) {
843 id->rgid = rgid;
846 if (egid != (gid_t)-1) {
847 id->egid = egid;
850 if (sgid != (gid_t)-1) {
851 id->sgid = sgid;
854 pthread_mutex_unlock(&uwrap_id_mutex);
856 return 0;
860 * SETGID
862 int setgid(gid_t gid)
864 if (!uid_wrapper_enabled()) {
865 return libc_setgid(gid);
868 return uwrap_setresgid(gid, -1, -1);
871 #ifdef HAVE_SETEGID
872 int setegid(gid_t egid)
874 if (!uid_wrapper_enabled()) {
875 return libc_setegid(egid);
878 return uwrap_setresgid(-1, egid, -1);
880 #endif
882 #ifdef HAVE_SETREGID
883 int setregid(gid_t rgid, gid_t egid)
885 if (!uid_wrapper_enabled()) {
886 return libc_setregid(rgid, egid);
889 return uwrap_setresgid(rgid, egid, -1);
891 #endif
893 #ifdef HAVE_SETRESGID
894 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
896 if (!uid_wrapper_enabled()) {
897 return libc_setresgid(rgid, egid, sgid);
900 return uwrap_setresgid(rgid, egid, sgid);
902 #endif
905 * GETGID
907 static gid_t uwrap_getgid(void)
909 struct uwrap_thread *id = uwrap_tls_id;
910 gid_t gid;
912 pthread_mutex_lock(&uwrap_id_mutex);
913 gid = id->rgid;
914 pthread_mutex_unlock(&uwrap_id_mutex);
916 return gid;
919 gid_t getgid(void)
921 if (!uid_wrapper_enabled()) {
922 return libc_getgid();
925 return uwrap_getgid();
929 * GETEGID
931 static uid_t uwrap_getegid(void)
933 struct uwrap_thread *id = uwrap_tls_id;
934 gid_t gid;
936 pthread_mutex_lock(&uwrap_id_mutex);
937 gid = id->egid;
938 pthread_mutex_unlock(&uwrap_id_mutex);
940 return gid;
943 uid_t getegid(void)
945 if (!uid_wrapper_enabled()) {
946 return libc_getegid();
949 return uwrap_getegid();
952 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
954 struct uwrap_thread *id = uwrap_tls_id;
955 int rc = -1;
957 pthread_mutex_lock(&uwrap_id_mutex);
959 if (size == 0) {
960 free(id->groups);
961 id->groups = NULL;
962 id->ngroups = 0;
963 } else if (size > 0) {
964 gid_t *tmp;
966 tmp = realloc(id->groups, sizeof(gid_t) * size);
967 if (tmp == NULL) {
968 errno = ENOMEM;
969 goto out;
971 id->groups = tmp;
973 id->ngroups = size;
974 memcpy(id->groups, list, size * sizeof(gid_t));
977 rc = 0;
978 out:
979 pthread_mutex_unlock(&uwrap_id_mutex);
981 return rc;
984 static int uwrap_setgroups(size_t size, const gid_t *list)
986 struct uwrap_thread *id;
987 int rc = -1;
989 pthread_mutex_lock(&uwrap_id_mutex);
991 if (size == 0) {
992 for (id = uwrap.ids; id; id = id->next) {
993 free(id->groups);
994 id->groups = NULL;
995 id->ngroups = 0;
997 } else if (size > 0) {
998 for (id = uwrap.ids; id; id = id->next) {
999 gid_t *tmp;
1001 tmp = realloc(id->groups, sizeof(gid_t) * size);
1002 if (tmp == NULL) {
1003 errno = ENOMEM;
1004 goto out;
1006 id->groups = tmp;
1008 id->ngroups = size;
1009 memcpy(id->groups, list, size * sizeof(gid_t));
1013 rc = 0;
1014 out:
1015 pthread_mutex_unlock(&uwrap_id_mutex);
1017 return rc;
1020 #ifdef HAVE_SETGROUPS_INT
1021 int setgroups(int size, const gid_t *list)
1022 #else
1023 int setgroups(size_t size, const gid_t *list)
1024 #endif
1026 if (!uid_wrapper_enabled()) {
1027 return libc_setgroups(size, list);
1030 return uwrap_setgroups(size, list);
1033 static int uwrap_getgroups(int size, gid_t *list)
1035 struct uwrap_thread *id = uwrap_tls_id;
1036 int ngroups;
1038 pthread_mutex_lock(&uwrap_id_mutex);
1039 ngroups = id->ngroups;
1041 if (size > ngroups) {
1042 size = ngroups;
1044 if (size == 0) {
1045 goto out;
1047 if (size < ngroups) {
1048 errno = EINVAL;
1049 ngroups = -1;
1051 memcpy(list, id->groups, size * sizeof(gid_t));
1053 out:
1054 pthread_mutex_unlock(&uwrap_id_mutex);
1056 return ngroups;
1059 int getgroups(int size, gid_t *list)
1061 if (!uid_wrapper_enabled()) {
1062 return libc_getgroups(size, list);
1065 return uwrap_getgroups(size, list);
1068 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1069 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1070 static long int uwrap_syscall (long int sysno, va_list vp)
1072 long int rc;
1074 switch (sysno) {
1075 /* gid */
1076 case SYS_getgid:
1077 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1078 case SYS_getgid32:
1079 #endif
1081 rc = uwrap_getgid();
1083 break;
1084 #ifdef SYS_getegid
1085 case SYS_getegid:
1086 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1087 case SYS_getegid32:
1088 #endif
1090 rc = uwrap_getegid();
1092 break;
1093 #endif /* SYS_getegid */
1094 case SYS_setgid:
1095 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1096 case SYS_setgid32:
1097 #endif
1099 gid_t gid = (gid_t) va_arg(vp, int);
1101 rc = uwrap_setresgid_thread(gid, -1, -1);
1103 break;
1104 case SYS_setregid:
1105 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1106 case SYS_setregid32:
1107 #endif
1109 uid_t rgid = (uid_t) va_arg(vp, int);
1110 uid_t egid = (uid_t) va_arg(vp, int);
1112 rc = uwrap_setresgid_thread(rgid, egid, -1);
1114 break;
1115 #ifdef SYS_setresgid
1116 case SYS_setresgid:
1117 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1118 case SYS_setresgid32:
1119 #endif
1121 uid_t rgid = (uid_t) va_arg(vp, int);
1122 uid_t egid = (uid_t) va_arg(vp, int);
1123 uid_t sgid = (uid_t) va_arg(vp, int);
1125 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1127 break;
1128 #endif /* SYS_setresgid */
1130 /* uid */
1131 case SYS_getuid:
1132 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1133 case SYS_getuid32:
1134 #endif
1136 rc = uwrap_getuid();
1138 break;
1139 #ifdef SYS_geteuid
1140 case SYS_geteuid:
1141 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1142 case SYS_geteuid32:
1143 #endif
1145 rc = uwrap_geteuid();
1147 break;
1148 #endif /* SYS_geteuid */
1149 case SYS_setuid:
1150 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1151 case SYS_setuid32:
1152 #endif
1154 uid_t uid = (uid_t) va_arg(vp, int);
1156 rc = uwrap_setresuid_thread(uid, -1, -1);
1158 break;
1159 case SYS_setreuid:
1160 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1161 case SYS_setreuid32:
1162 #endif
1164 uid_t ruid = (uid_t) va_arg(vp, int);
1165 uid_t euid = (uid_t) va_arg(vp, int);
1167 rc = uwrap_setresuid_thread(ruid, euid, -1);
1169 break;
1170 #ifdef SYS_setresuid
1171 case SYS_setresuid:
1172 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1173 case SYS_setresuid32:
1174 #endif
1176 uid_t ruid = (uid_t) va_arg(vp, int);
1177 uid_t euid = (uid_t) va_arg(vp, int);
1178 uid_t suid = (uid_t) va_arg(vp, int);
1180 rc = uwrap_setresuid_thread(ruid, euid, suid);
1182 break;
1183 #endif /* SYS_setresuid */
1185 /* groups */
1186 case SYS_setgroups:
1187 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1188 case SYS_setgroups32:
1189 #endif
1191 size_t size = (size_t) va_arg(vp, size_t);
1192 gid_t *list = (gid_t *) va_arg(vp, int *);
1194 rc = uwrap_setgroups_thread(size, list);
1196 break;
1197 default:
1198 UWRAP_LOG(UWRAP_LOG_DEBUG,
1199 "UID_WRAPPER calling non-wrapped syscall %lu\n",
1200 sysno);
1202 rc = libc_vsyscall(sysno, vp);
1203 break;
1206 return rc;
1209 #ifdef HAVE_SYSCALL
1210 #ifdef HAVE_SYSCALL_INT
1211 int syscall (int sysno, ...)
1212 #else
1213 long int syscall (long int sysno, ...)
1214 #endif
1216 #ifdef HAVE_SYSCALL_INT
1217 int rc;
1218 #else
1219 long int rc;
1220 #endif
1221 va_list va;
1223 va_start(va, sysno);
1225 if (!uid_wrapper_enabled()) {
1226 rc = libc_vsyscall(sysno, va);
1227 va_end(va);
1228 return rc;
1231 rc = uwrap_syscall(sysno, va);
1232 va_end(va);
1234 return rc;
1236 #endif /* HAVE_SYSCALL */
1237 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1239 /****************************
1240 * DESTRUCTOR
1241 ***************************/
1244 * This function is called when the library is unloaded and makes sure that
1245 * resources are freed.
1247 void uwrap_destructor(void)
1249 struct uwrap_thread *u = uwrap.ids;
1251 pthread_mutex_lock(&uwrap_id_mutex);
1252 while (u != NULL) {
1253 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1255 SAFE_FREE(u->groups);
1256 SAFE_FREE(u);
1258 u = uwrap.ids;
1260 pthread_mutex_unlock(&uwrap_id_mutex);
1262 if (uwrap.libc.handle != NULL) {
1263 dlclose(uwrap.libc.handle);