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>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
46 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
47 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
49 #define DESTRUCTOR_ATTRIBUTE
50 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
53 #define UWRAP_DEBUG(...)
55 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
58 #define UWRAP_DLIST_ADD(list,item) do { \
60 (item)->prev = NULL; \
61 (item)->next = NULL; \
64 (item)->prev = NULL; \
65 (item)->next = (list); \
66 (list)->prev = (item); \
71 #define UWRAP_DLIST_REMOVE(list,item) do { \
72 if ((list) == (item)) { \
73 (list) = (item)->next; \
75 (list)->prev = NULL; \
79 (item)->prev->next = (item)->next; \
82 (item)->next->prev = (item)->prev; \
85 (item)->prev = NULL; \
86 (item)->next = NULL; \
90 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
93 #define LIBC_NAME "libc.so"
95 struct uwrap_libc_fns
{
96 int (*_libc_setuid
)(uid_t uid
);
97 uid_t (*_libc_getuid
)(void);
100 int (*_libc_seteuid
)(uid_t euid
);
103 int (*_libc_setreuid
)(uid_t ruid
, uid_t euid
);
105 #ifdef HAVE_SETRESUID
106 int (*_libc_setresuid
)(uid_t ruid
, uid_t euid
, uid_t suid
);
108 uid_t (*_libc_geteuid
)(void);
110 int (*_libc_setgid
)(gid_t gid
);
111 gid_t (*_libc_getgid
)(void);
113 int (*_libc_setegid
)(uid_t egid
);
116 int (*_libc_setregid
)(uid_t rgid
, uid_t egid
);
118 #ifdef HAVE_SETRESGID
119 int (*_libc_setresgid
)(uid_t rgid
, uid_t egid
, uid_t sgid
);
121 gid_t (*_libc_getegid
)(void);
122 int (*_libc_getgroups
)(int size
, gid_t list
[]);
123 int (*_libc_setgroups
)(size_t size
, const gid_t
*list
);
125 long int (*_libc_syscall
)(long int sysno
, ...);
130 * We keep the virtualised euid/egid/groups information here
132 struct uwrap_thread
{
147 struct uwrap_thread
*next
;
148 struct uwrap_thread
*prev
;
154 struct uwrap_libc_fns fns
;
163 struct uwrap_thread
*ids
;
166 static struct uwrap uwrap
;
168 /* Shortcut to the list item */
169 static UWRAP_THREAD
struct uwrap_thread
*uwrap_tls_id
;
171 /* The mutex or accessing the id */
172 static pthread_mutex_t uwrap_id_mutex
= PTHREAD_MUTEX_INITIALIZER
;
174 /*********************************************************
176 *********************************************************/
178 bool uid_wrapper_enabled(void);
179 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE
;
181 /*********************************************************
182 * UWRAP LIBC LOADER FUNCTIONS
183 *********************************************************/
191 static void *uwrap_load_lib_handle(enum uwrap_lib lib
)
193 int flags
= RTLD_LAZY
;
202 flags
|= RTLD_DEEPBIND
;
208 case UWRAP_LIBSOCKET
:
211 handle
= uwrap
.libc
.handle
;
212 if (handle
== NULL
) {
213 for (handle
= NULL
, i
= 10; handle
== NULL
&& i
>= 0; i
--) {
214 char soname
[256] = {0};
216 snprintf(soname
, sizeof(soname
), "libc.so.%d", i
);
217 handle
= dlopen(soname
, flags
);
220 uwrap
.libc
.handle
= handle
;
225 if (handle
== NULL
) {
227 "Failed to dlopen library: %s\n",
235 static void *_uwrap_load_lib_function(enum uwrap_lib lib
, const char *fn_name
)
240 handle
= uwrap_load_lib_handle(lib
);
242 func
= dlsym(handle
, fn_name
);
245 "Failed to find %s: %s\n",
253 #define uwrap_load_lib_function(lib, fn_name) \
254 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
255 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
256 _uwrap_load_lib_function(lib, #fn_name); \
262 * Functions expeciall from libc need to be loaded individually, you can't load
263 * all at once or gdb will segfault at startup. The same applies to valgrind and
264 * has probably something todo with with the linker.
265 * So we need load each function at the point it is called the first time.
267 static int libc_setuid(uid_t uid
)
269 uwrap_load_lib_function(UWRAP_LIBC
, setuid
);
271 return uwrap
.libc
.fns
._libc_setuid(uid
);
274 static uid_t
libc_getuid(void)
276 uwrap_load_lib_function(UWRAP_LIBC
, getuid
);
278 return uwrap
.libc
.fns
._libc_getuid();
282 static int libc_seteuid(uid_t euid
)
284 uwrap_load_lib_function(UWRAP_LIBC
, seteuid
);
286 return uwrap
.libc
.fns
._libc_seteuid(euid
);
291 static int libc_setreuid(uid_t ruid
, uid_t euid
)
293 uwrap_load_lib_function(UWRAP_LIBC
, setreuid
);
295 return uwrap
.libc
.fns
._libc_setreuid(ruid
, euid
);
299 #ifdef HAVE_SETRESUID
300 static int libc_setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
302 uwrap_load_lib_function(UWRAP_LIBC
, setresuid
);
304 return uwrap
.libc
.fns
._libc_setresuid(ruid
, euid
, suid
);
308 static uid_t
libc_geteuid(void)
310 uwrap_load_lib_function(UWRAP_LIBC
, geteuid
);
312 return uwrap
.libc
.fns
._libc_geteuid();
315 static int libc_setgid(gid_t gid
)
317 uwrap_load_lib_function(UWRAP_LIBC
, setgid
);
319 return uwrap
.libc
.fns
._libc_setgid(gid
);
322 static gid_t
libc_getgid(void)
324 uwrap_load_lib_function(UWRAP_LIBC
, getgid
);
326 return uwrap
.libc
.fns
._libc_getgid();
330 static int libc_setegid(gid_t egid
)
332 uwrap_load_lib_function(UWRAP_LIBC
, setegid
);
334 return uwrap
.libc
.fns
._libc_setegid(egid
);
339 static int libc_setregid(gid_t rgid
, gid_t egid
)
341 uwrap_load_lib_function(UWRAP_LIBC
, setregid
);
343 return uwrap
.libc
.fns
._libc_setregid(rgid
, egid
);
347 #ifdef HAVE_SETRESGID
348 static int libc_setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
350 uwrap_load_lib_function(UWRAP_LIBC
, setresgid
);
352 return uwrap
.libc
.fns
._libc_setresgid(rgid
, egid
, sgid
);
356 static gid_t
libc_getegid(void)
358 uwrap_load_lib_function(UWRAP_LIBC
, getegid
);
360 return uwrap
.libc
.fns
._libc_getegid();
363 static int libc_getgroups(int size
, gid_t list
[])
365 uwrap_load_lib_function(UWRAP_LIBC
, getgroups
);
367 return uwrap
.libc
.fns
._libc_getgroups(size
, list
);
370 static int libc_setgroups(size_t size
, const gid_t
*list
)
372 uwrap_load_lib_function(UWRAP_LIBC
, setgroups
);
374 return uwrap
.libc
.fns
._libc_setgroups(size
, list
);
378 static long int libc_vsyscall(long int sysno
, va_list va
)
384 uwrap_load_lib_function(UWRAP_LIBC
, syscall
);
386 for (i
= 0; i
< 8; i
++) {
387 args
[i
] = va_arg(va
, long int);
390 rc
= uwrap
.libc
.fns
._libc_syscall(sysno
,
404 /*********************************************************
406 *********************************************************/
408 static struct uwrap_thread
*find_uwrap_id(pthread_t tid
)
410 struct uwrap_thread
*id
;
412 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
413 if (pthread_equal(id
->tid
, tid
)) {
421 static int uwrap_new_id(pthread_t tid
, bool do_alloc
)
423 struct uwrap_thread
*id
= uwrap_tls_id
;
426 id
= malloc(sizeof(struct uwrap_thread
));
432 id
->groups
= malloc(sizeof(gid_t
) * 1);
433 if (id
->groups
== NULL
) {
438 UWRAP_DLIST_ADD(uwrap
.ids
, id
);
445 id
->ruid
= id
->euid
= id
->suid
= uwrap
.myuid
;
446 id
->rgid
= id
->egid
= id
->sgid
= uwrap
.mygid
;
449 id
->groups
[0] = uwrap
.mygid
;
454 static void uwrap_thread_prepare(void)
456 pthread_mutex_lock(&uwrap_id_mutex
);
459 * What happens if another atfork prepare functions calls a uwrap
460 * function? So disable it in case another atfork prepare function
461 * calls a (s)uid function.
463 uwrap
.enabled
= false;
466 static void uwrap_thread_parent(void)
468 uwrap
.enabled
= true;
470 pthread_mutex_unlock(&uwrap_id_mutex
);
473 static void uwrap_thread_child(void)
475 uwrap
.enabled
= true;
477 pthread_mutex_unlock(&uwrap_id_mutex
);
480 static void uwrap_init(void)
482 const char *env
= getenv("UID_WRAPPER");
483 pthread_t tid
= pthread_self();
487 if (uwrap
.initialised
) {
488 struct uwrap_thread
*id
= uwrap_tls_id
;
495 pthread_mutex_lock(&uwrap_id_mutex
);
496 id
= find_uwrap_id(tid
);
498 rc
= uwrap_new_id(tid
, true);
503 /* We reuse an old thread id */
506 uwrap_new_id(tid
, false);
508 pthread_mutex_unlock(&uwrap_id_mutex
);
514 * If we hold a lock and the application forks, then the child
515 * is not able to unlock the mutex and we are in a deadlock.
516 * This should prevent such deadlocks.
518 pthread_atfork(&uwrap_thread_prepare
,
519 &uwrap_thread_parent
,
520 &uwrap_thread_child
);
522 pthread_mutex_lock(&uwrap_id_mutex
);
524 uwrap
.initialised
= true;
525 uwrap
.enabled
= false;
527 if (env
!= NULL
&& env
[0] == '1') {
528 const char *root
= getenv("UID_WRAPPER_ROOT");
531 /* put us in one group */
532 if (root
!= NULL
&& root
[0] == '1') {
536 uwrap
.myuid
= libc_geteuid();
537 uwrap
.mygid
= libc_getegid();
540 rc
= uwrap_new_id(tid
, true);
545 uwrap
.enabled
= true;
548 pthread_mutex_unlock(&uwrap_id_mutex
);
551 bool uid_wrapper_enabled(void)
555 return uwrap
.enabled
? true : false;
558 static int uwrap_setresuid_thread(uid_t ruid
, uid_t euid
, uid_t suid
)
560 struct uwrap_thread
*id
= uwrap_tls_id
;
562 if (ruid
== (uid_t
)-1 && euid
== (uid_t
)-1 && suid
== (uid_t
)-1) {
567 pthread_mutex_lock(&uwrap_id_mutex
);
568 if (ruid
!= (uid_t
)-1) {
572 if (euid
!= (uid_t
)-1) {
576 if (suid
!= (uid_t
)-1) {
579 pthread_mutex_unlock(&uwrap_id_mutex
);
584 static int uwrap_setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
586 struct uwrap_thread
*id
;
588 if (ruid
== (uid_t
)-1 && euid
== (uid_t
)-1 && suid
== (uid_t
)-1) {
593 pthread_mutex_lock(&uwrap_id_mutex
);
594 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
599 if (ruid
!= (uid_t
)-1) {
603 if (euid
!= (uid_t
)-1) {
607 if (suid
!= (uid_t
)-1) {
611 pthread_mutex_unlock(&uwrap_id_mutex
);
619 int setuid(uid_t uid
)
621 if (!uid_wrapper_enabled()) {
622 return libc_setuid(uid
);
625 return uwrap_setresuid(uid
, -1, -1);
629 int seteuid(uid_t euid
)
631 if (euid
== (uid_t
)-1) {
636 if (!uid_wrapper_enabled()) {
637 return libc_seteuid(euid
);
640 return uwrap_setresuid(-1, euid
, -1);
645 int setreuid(uid_t ruid
, uid_t euid
)
647 if (ruid
== (uid_t
)-1 && euid
== (uid_t
)-1) {
652 if (!uid_wrapper_enabled()) {
653 return libc_setreuid(ruid
, euid
);
656 return uwrap_setresuid(ruid
, euid
, -1);
660 #ifdef HAVE_SETRESUID
661 int setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
663 if (!uid_wrapper_enabled()) {
664 return libc_setresuid(ruid
, euid
, suid
);
667 return uwrap_setresuid(ruid
, euid
, suid
);
674 static uid_t
uwrap_getuid(void)
676 struct uwrap_thread
*id
= uwrap_tls_id
;
679 pthread_mutex_lock(&uwrap_id_mutex
);
681 pthread_mutex_unlock(&uwrap_id_mutex
);
688 if (!uid_wrapper_enabled()) {
689 return libc_getuid();
692 return uwrap_getuid();
698 static uid_t
uwrap_geteuid(void)
700 const char *env
= getenv("UID_WRAPPER_MYUID");
701 struct uwrap_thread
*id
= uwrap_tls_id
;
704 pthread_mutex_lock(&uwrap_id_mutex
);
706 pthread_mutex_unlock(&uwrap_id_mutex
);
708 /* Disable root and return myuid */
709 if (env
!= NULL
&& env
[0] == '1') {
718 if (!uid_wrapper_enabled()) {
719 return libc_geteuid();
722 return uwrap_geteuid();
725 static int uwrap_setresgid_thread(gid_t rgid
, gid_t egid
, gid_t sgid
)
727 struct uwrap_thread
*id
= uwrap_tls_id
;
729 if (rgid
== (gid_t
)-1 && egid
== (gid_t
)-1 && sgid
== (gid_t
)-1) {
734 pthread_mutex_lock(&uwrap_id_mutex
);
735 if (rgid
!= (gid_t
)-1) {
739 if (egid
!= (gid_t
)-1) {
743 if (sgid
!= (gid_t
)-1) {
746 pthread_mutex_unlock(&uwrap_id_mutex
);
751 static int uwrap_setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
753 struct uwrap_thread
*id
;
755 if (rgid
== (gid_t
)-1 && egid
== (gid_t
)-1 && sgid
== (gid_t
)-1) {
760 pthread_mutex_lock(&uwrap_id_mutex
);
761 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
766 if (rgid
!= (gid_t
)-1) {
770 if (egid
!= (gid_t
)-1) {
774 if (sgid
!= (gid_t
)-1) {
778 pthread_mutex_unlock(&uwrap_id_mutex
);
786 int setgid(gid_t gid
)
788 if (!uid_wrapper_enabled()) {
789 return libc_setgid(gid
);
792 return uwrap_setresgid(gid
, -1, -1);
796 int setegid(gid_t egid
)
798 if (!uid_wrapper_enabled()) {
799 return libc_setegid(egid
);
802 return uwrap_setresgid(-1, egid
, -1);
807 int setregid(gid_t rgid
, gid_t egid
)
809 if (!uid_wrapper_enabled()) {
810 return libc_setregid(rgid
, egid
);
813 return uwrap_setresgid(rgid
, egid
, -1);
817 #ifdef HAVE_SETRESGID
818 int setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
820 if (!uid_wrapper_enabled()) {
821 return libc_setresgid(rgid
, egid
, sgid
);
824 return uwrap_setresgid(rgid
, egid
, sgid
);
831 static gid_t
uwrap_getgid(void)
833 struct uwrap_thread
*id
= uwrap_tls_id
;
836 pthread_mutex_lock(&uwrap_id_mutex
);
838 pthread_mutex_unlock(&uwrap_id_mutex
);
845 if (!uid_wrapper_enabled()) {
846 return libc_getgid();
849 return uwrap_getgid();
855 static uid_t
uwrap_getegid(void)
857 struct uwrap_thread
*id
= uwrap_tls_id
;
860 pthread_mutex_lock(&uwrap_id_mutex
);
862 pthread_mutex_unlock(&uwrap_id_mutex
);
869 if (!uid_wrapper_enabled()) {
870 return libc_getegid();
873 return uwrap_getegid();
876 static int uwrap_setgroups_thread(size_t size
, const gid_t
*list
)
878 struct uwrap_thread
*id
= uwrap_tls_id
;
881 pthread_mutex_lock(&uwrap_id_mutex
);
886 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
894 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
899 pthread_mutex_unlock(&uwrap_id_mutex
);
904 static int uwrap_setgroups(size_t size
, const gid_t
*list
)
906 struct uwrap_thread
*id
;
909 pthread_mutex_lock(&uwrap_id_mutex
);
912 for (id
= uwrap
.ids
; id
; id
= id
->next
) {
915 tmp
= realloc(id
->groups
, sizeof(gid_t
) * size
);
923 memcpy(id
->groups
, list
, size
* sizeof(gid_t
));
929 pthread_mutex_unlock(&uwrap_id_mutex
);
934 #ifdef HAVE_SETGROUPS_INT
935 int setgroups(int size
, const gid_t
*list
)
937 int setgroups(size_t size
, const gid_t
*list
)
940 if (!uid_wrapper_enabled()) {
941 return libc_setgroups(size
, list
);
944 return uwrap_setgroups(size
, list
);
947 static int uwrap_getgroups(int size
, gid_t
*list
)
949 struct uwrap_thread
*id
= uwrap_tls_id
;
952 pthread_mutex_lock(&uwrap_id_mutex
);
953 ngroups
= id
->ngroups
;
955 if (size
> ngroups
) {
961 if (size
< ngroups
) {
965 memcpy(list
, id
->groups
, size
* sizeof(gid_t
));
968 pthread_mutex_unlock(&uwrap_id_mutex
);
973 int getgroups(int size
, gid_t
*list
)
975 if (!uid_wrapper_enabled()) {
976 return libc_getgroups(size
, list
);
979 return uwrap_getgroups(size
, list
);
982 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
983 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
984 static long int uwrap_syscall (long int sysno
, va_list vp
)
991 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1000 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1004 rc
= uwrap_getegid();
1007 #endif /* SYS_getegid */
1009 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1013 gid_t gid
= (gid_t
) va_arg(vp
, int);
1015 rc
= uwrap_setresgid_thread(gid
, -1, -1);
1019 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1020 case SYS_setregid32
:
1023 uid_t rgid
= (uid_t
) va_arg(vp
, int);
1024 uid_t egid
= (uid_t
) va_arg(vp
, int);
1026 rc
= uwrap_setresgid_thread(rgid
, egid
, -1);
1029 #ifdef SYS_setresgid
1031 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1032 case SYS_setresgid32
:
1035 uid_t rgid
= (uid_t
) va_arg(vp
, int);
1036 uid_t egid
= (uid_t
) va_arg(vp
, int);
1037 uid_t sgid
= (uid_t
) va_arg(vp
, int);
1039 rc
= uwrap_setresgid_thread(rgid
, egid
, sgid
);
1042 #endif /* SYS_setresgid */
1046 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1050 rc
= uwrap_getuid();
1055 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1059 rc
= uwrap_geteuid();
1062 #endif /* SYS_geteuid */
1064 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1068 uid_t uid
= (uid_t
) va_arg(vp
, int);
1070 rc
= uwrap_setresuid_thread(uid
, -1, -1);
1074 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1075 case SYS_setreuid32
:
1078 uid_t ruid
= (uid_t
) va_arg(vp
, int);
1079 uid_t euid
= (uid_t
) va_arg(vp
, int);
1081 rc
= uwrap_setresuid_thread(ruid
, euid
, -1);
1084 #ifdef SYS_setresuid
1086 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1087 case SYS_setresuid32
:
1090 uid_t ruid
= (uid_t
) va_arg(vp
, int);
1091 uid_t euid
= (uid_t
) va_arg(vp
, int);
1092 uid_t suid
= (uid_t
) va_arg(vp
, int);
1094 rc
= uwrap_setresuid_thread(ruid
, euid
, suid
);
1097 #endif /* SYS_setresuid */
1101 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1102 case SYS_setgroups32
:
1105 size_t size
= (size_t) va_arg(vp
, size_t);
1106 gid_t
*list
= (gid_t
*) va_arg(vp
, int *);
1108 rc
= uwrap_setgroups_thread(size
, list
);
1112 UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
1115 rc
= libc_vsyscall(sysno
, vp
);
1123 #ifdef HAVE_SYSCALL_INT
1124 int syscall (int sysno
, ...)
1126 long int syscall (long int sysno
, ...)
1129 #ifdef HAVE_SYSCALL_INT
1136 va_start(va
, sysno
);
1138 if (!uid_wrapper_enabled()) {
1139 rc
= libc_vsyscall(sysno
, va
);
1144 rc
= uwrap_syscall(sysno
, va
);
1149 #endif /* HAVE_SYSCALL */
1150 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
1152 /****************************
1154 ***************************/
1157 * This function is called when the library is unloaded and makes sure that
1158 * resources are freed.
1160 void uwrap_destructor(void)
1162 struct uwrap_thread
*u
= uwrap
.ids
;
1165 UWRAP_DLIST_REMOVE(uwrap
.ids
, u
);
1167 SAFE_FREE(u
->groups
);
1173 if (uwrap
.libc
.handle
!= NULL
) {
1174 dlclose(uwrap
.libc
.handle
);