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/>.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
38 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
39 # define UWRAP_THREAD __thread
45 #define UWRAP_DEBUG(...)
47 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
50 #define LIBC_NAME "libc.so"
52 struct uwrap_libc_fns {
53 int (*_libc_setuid)(uid_t uid);
54 uid_t (*_libc_getuid)(void);
57 int (*_libc_seteuid)(uid_t euid);
60 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
63 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
65 uid_t (*_libc_geteuid)(void);
67 int (*_libc_setgid)(gid_t gid);
68 gid_t (*_libc_getgid)(void);
70 int (*_libc_setegid)(uid_t egid);
73 int (*_libc_setregid)(uid_t rgid, uid_t egid);
76 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
78 gid_t (*_libc_getegid)(void);
79 int (*_libc_getgroups)(int size, gid_t list[]);
80 int (*_libc_setgroups)(size_t size, const gid_t *list);
82 long int (*_libc_syscall)(long int sysno, ...);
87 * We keep the virtualised euid/egid/groups information here
92 struct uwrap_libc_fns fns;
108 static struct uwrap uwrap;
110 static void *uwrap_libc_fn(struct uwrap *u, const char *fn_name)
114 if (u->libc.handle == NULL) {
118 func = dlsym(u->libc.handle, fn_name);
120 printf("Failed to find %s in %s: %s\n",
121 fn_name, LIBC_NAME, dlerror());
128 static void uwrap_libc_init(struct uwrap *u)
131 int flags = RTLD_LAZY;
134 flags |= RTLD_DEEPBIND;
137 for (u->libc.handle = NULL, i = 10; u->libc.handle == NULL; i--) {
138 char soname[256] = {0};
140 snprintf(soname, sizeof(soname), "%s.%u", LIBC_NAME, i);
141 u->libc.handle = dlopen(soname, flags);
144 if (u->libc.handle == NULL) {
145 printf("Failed to dlopen %s.%u: %s\n", LIBC_NAME, i, dlerror());
149 *(void **) (&u->libc.fns._libc_setuid) = uwrap_libc_fn(u, "setuid");
150 *(void **) (&u->libc.fns._libc_getuid) = uwrap_libc_fn(u, "getuid");
153 *(void **) (&u->libc.fns._libc_seteuid) = uwrap_libc_fn(u, "seteuid");
156 *(void **) (&u->libc.fns._libc_setreuid) = uwrap_libc_fn(u, "setreuid");
158 #ifdef HAVE_SETRESUID
159 *(void **) (&u->libc.fns._libc_setresuid) = uwrap_libc_fn(u, "setresuid");
161 *(void **) (&u->libc.fns._libc_geteuid) = uwrap_libc_fn(u, "geteuid");
163 *(void **) (&u->libc.fns._libc_setgid) = uwrap_libc_fn(u, "setgid");
164 *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
166 *(void **) (&u->libc.fns._libc_setegid) = uwrap_libc_fn(u, "setegid");
169 *(void **) (&u->libc.fns._libc_setregid) = uwrap_libc_fn(u, "setregid");
171 #ifdef HAVE_SETRESGID
172 *(void **) (&u->libc.fns._libc_setresgid) = uwrap_libc_fn(u, "setresgid");
174 *(void **) (&u->libc.fns._libc_getegid) = uwrap_libc_fn(u, "getegid");
175 *(void **) (&u->libc.fns._libc_getgroups) = uwrap_libc_fn(u, "getgroups");
176 *(void **) (&u->libc.fns._libc_setgroups) = uwrap_libc_fn(u, "setgroups");
177 *(void **) (&u->libc.fns._libc_getuid) = uwrap_libc_fn(u, "getuid");
178 *(void **) (&u->libc.fns._libc_getgid) = uwrap_libc_fn(u, "getgid");
180 *(void **) (&u->libc.fns._libc_syscall) = uwrap_libc_fn(u, "syscall");
184 static void uwrap_init(void)
186 const char *env = getenv("UID_WRAPPER");
188 if (uwrap.initialised) {
192 uwrap_libc_init(&uwrap);
194 uwrap.initialised = true;
195 uwrap.enabled = false;
197 if (env != NULL && env[0] == '1') {
198 const char *root = getenv("UID_WRAPPER_ROOT");
199 uwrap.enabled = true;
200 /* put us in one group */
201 if (root != NULL && root[0] == '1') {
205 uwrap.myuid = uwrap.libc.fns._libc_geteuid();
206 uwrap.mygid = uwrap.libc.fns._libc_getegid();
209 uwrap.ruid = uwrap.euid = uwrap.suid = uwrap.myuid;
210 uwrap.rgid = uwrap.egid = uwrap.sgid = uwrap.mygid;
213 uwrap.groups = malloc(sizeof(gid_t) * uwrap.ngroups);
214 uwrap.groups[0] = uwrap.mygid;
218 static int uwrap_enabled(void)
222 return uwrap.enabled ? 1 : 0;
225 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
227 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
232 if (ruid != (uid_t)-1) {
236 if (euid != (uid_t)-1) {
240 if (suid != (uid_t)-1) {
250 int setuid(uid_t uid)
252 if (!uwrap_enabled()) {
253 return uwrap.libc.fns._libc_setuid(uid);
256 return uwrap_setresuid(uid, -1, -1);
262 static uid_t uwrap_getuid(void)
269 if (!uwrap_enabled()) {
270 return uwrap.libc.fns._libc_getuid();
273 return uwrap_getuid();
277 int seteuid(uid_t euid)
279 if (euid == (uid_t)-1) {
284 if (!uwrap_enabled()) {
285 return uwrap.libc.fns._libc_seteuid(euid);
288 return uwrap_setresuid(-1, euid, -1);
293 int setreuid(uid_t ruid, uid_t euid)
295 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
300 if (!uwrap_enabled()) {
301 return uwrap.libc.fns._libc_setreuid(ruid, euid);
304 return uwrap_setresuid(ruid, euid, -1);
308 #ifdef HAVE_SETRESUID
309 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
311 if (!uwrap_enabled()) {
312 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
315 return uwrap_setresuid(ruid, euid, suid);
319 static uid_t uwrap_geteuid(void)
326 if (!uwrap_enabled()) {
327 return uwrap.libc.fns._libc_geteuid();
330 return uwrap_geteuid();
336 static int uwrap_setgid(gid_t gid)
338 if (gid == (gid_t)-1) {
348 int setgid(gid_t gid)
350 if (!uwrap_enabled()) {
351 return uwrap.libc.fns._libc_setgid(gid);
354 return uwrap_setgid(gid);
360 static gid_t uwrap_getgid(void)
367 if (!uwrap_enabled()) {
368 return uwrap.libc.fns._libc_getgid();
371 return uwrap_getgid();
374 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
376 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
381 if (rgid != (gid_t)-1) {
385 if (egid != (gid_t)-1) {
389 if (sgid != (gid_t)-1) {
397 int setegid(gid_t egid)
399 if (!uwrap_enabled()) {
400 return uwrap.libc.fns._libc_setegid(egid);
403 return uwrap_setresgid(-1, egid, -1);
408 int setregid(gid_t rgid, gid_t egid)
410 if (!uwrap_enabled()) {
411 return uwrap.libc.fns._libc_setregid(rgid, egid);
414 return uwrap_setresgid(rgid, egid, -1);
418 #ifdef HAVE_SETRESGID
419 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
421 if (!uwrap_enabled()) {
422 return uwrap.libc.fns._libc_setregid(rgid, egid, sgid);
425 return uwrap_setresgid(rgid, egid, sgid);
429 static uid_t uwrap_getegid(void)
436 if (!uwrap_enabled()) {
437 return uwrap.libc.fns._libc_getegid();
440 return uwrap_getegid();
443 static int uwrap_setgroups(size_t size, const gid_t *list)
450 uwrap.groups = malloc(sizeof(gid_t) * size);
451 if (uwrap.groups == NULL) {
455 uwrap.ngroups = size;
456 memcpy(uwrap.groups, list, size*sizeof(gid_t));
462 int setgroups(size_t size, const gid_t *list)
464 if (!uwrap_enabled()) {
465 return uwrap.libc.fns._libc_setgroups(size, list);
468 return uwrap_setgroups(size, list);
471 static int uwrap_getgroups(int size, gid_t *list)
475 ngroups = uwrap.ngroups;
477 if (size > ngroups) {
483 if (size < ngroups) {
487 memcpy(list, uwrap.groups, size*sizeof(gid_t));
492 int getgroups(int size, gid_t *list)
494 if (!uwrap_enabled()) {
495 return uwrap.libc.fns._libc_getgroups(size, list);
498 return uwrap_getgroups(size, list);
501 static long int libc_vsyscall(long int sysno, va_list va)
507 for (i = 0; i < 8; i++) {
508 args[i] = va_arg(va, long int);
511 rc = uwrap.libc.fns._libc_syscall(sysno,
524 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
525 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
526 static long int uwrap_syscall (long int sysno, va_list vp)
533 #ifdef HAVE_LINUX_32BIT_SYSCALLS
537 gid_t gid = (gid_t) va_arg(vp, int);
539 rc = uwrap_setresgid(gid, -1, -1);
543 #ifdef HAVE_LINUX_32BIT_SYSCALLS
547 uid_t rgid = (uid_t) va_arg(vp, int);
548 uid_t egid = (uid_t) va_arg(vp, int);
550 rc = uwrap_setresgid(rgid, egid, -1);
554 #ifdef HAVE_LINUX_32BIT_SYSCALLS
555 case SYS_setresgid32:
558 uid_t rgid = (uid_t) va_arg(vp, int);
559 uid_t egid = (uid_t) va_arg(vp, int);
560 uid_t sgid = (uid_t) va_arg(vp, int);
562 rc = uwrap_setresgid(rgid, egid, sgid);
568 #ifdef HAVE_LINUX_32BIT_SYSCALLS
572 uid_t uid = (uid_t) va_arg(vp, int);
574 rc = uwrap_setresuid(uid, -1, -1);
578 #ifdef HAVE_LINUX_32BIT_SYSCALLS
582 uid_t ruid = (uid_t) va_arg(vp, int);
583 uid_t euid = (uid_t) va_arg(vp, int);
585 rc = uwrap_setresuid(ruid, euid, -1);
589 #ifdef HAVE_LINUX_32BIT_SYSCALLS
590 case SYS_setresuid32:
593 uid_t ruid = (uid_t) va_arg(vp, int);
594 uid_t euid = (uid_t) va_arg(vp, int);
595 uid_t suid = (uid_t) va_arg(vp, int);
597 rc = uwrap_setresuid(ruid, euid, suid);
603 #ifdef HAVE_LINUX_32BIT_SYSCALLS
604 case SYS_setgroups32:
607 size_t size = (size_t) va_arg(vp, size_t);
608 gid_t *list = (gid_t *) va_arg(vp, int *);
610 rc = uwrap_setgroups(size, list);
614 UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
617 rc = libc_vsyscall(sysno, vp);
625 long int syscall (long int sysno, ...)
632 if (!uwrap_enabled()) {
633 rc = libc_vsyscall(sysno, va);
638 rc = uwrap_syscall(sysno, va);
643 #endif /* HAVE_SYSCALL */
644 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */