Line data Source code
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 : #include <limits.h>
38 :
39 : #include <pthread.h>
40 :
41 : #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
42 : # define UWRAP_THREAD __thread
43 : #else
44 : # define UWRAP_THREAD
45 : #endif
46 :
47 : # define UWRAP_LOCK(m) do { \
48 : pthread_mutex_lock(&( m ## _mutex)); \
49 : } while(0)
50 :
51 : # define UWRAP_UNLOCK(m) do { \
52 : pthread_mutex_unlock(&( m ## _mutex)); \
53 : } while(0)
54 :
55 : /* Add new global locks here please */
56 : # define UWRAP_LOCK_ALL \
57 : UWRAP_LOCK(uwrap_id); \
58 : UWRAP_LOCK(libc_symbol_binding); \
59 : UWRAP_LOCK(libpthread_symbol_binding)
60 :
61 : # define UWRAP_UNLOCK_ALL \
62 : UWRAP_UNLOCK(libpthread_symbol_binding); \
63 : UWRAP_UNLOCK(libc_symbol_binding); \
64 : UWRAP_UNLOCK(uwrap_id)
65 :
66 : #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
67 : #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
68 : #else
69 : #define CONSTRUCTOR_ATTRIBUTE
70 : #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
71 :
72 : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
73 : #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
74 : #else
75 : #define DESTRUCTOR_ATTRIBUTE
76 : #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
77 :
78 : #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
79 : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
80 : #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
81 : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
82 : #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
83 :
84 : /* GCC have printf type attribute check. */
85 : #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
86 : #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
87 : #else
88 : #define PRINTF_ATTRIBUTE(a,b)
89 : #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
90 :
91 : #ifndef FALL_THROUGH
92 : # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
93 : # define FALL_THROUGH __attribute__ ((fallthrough))
94 : # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
95 : # define FALL_THROUGH
96 : # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
97 : #endif /* FALL_THROUGH */
98 :
99 : #define UWRAP_DLIST_ADD(list,item) do { \
100 : if (!(list)) { \
101 : (item)->prev = NULL; \
102 : (item)->next = NULL; \
103 : (list) = (item); \
104 : } else { \
105 : (item)->prev = NULL; \
106 : (item)->next = (list); \
107 : (list)->prev = (item); \
108 : (list) = (item); \
109 : } \
110 : } while (0)
111 :
112 : #define UWRAP_DLIST_REMOVE(list,item) do { \
113 : if ((list) == (item)) { \
114 : (list) = (item)->next; \
115 : if (list) { \
116 : (list)->prev = NULL; \
117 : } \
118 : } else { \
119 : if ((item)->prev) { \
120 : (item)->prev->next = (item)->next; \
121 : } \
122 : if ((item)->next) { \
123 : (item)->next->prev = (item)->prev; \
124 : } \
125 : } \
126 : (item)->prev = NULL; \
127 : (item)->next = NULL; \
128 : } while (0)
129 :
130 : #ifndef SAFE_FREE
131 : #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
132 : #endif
133 :
134 : /*****************
135 : * LOGGING
136 : *****************/
137 :
138 : enum uwrap_dbglvl_e {
139 : UWRAP_LOG_ERROR = 0,
140 : UWRAP_LOG_WARN,
141 : UWRAP_LOG_DEBUG,
142 : UWRAP_LOG_TRACE
143 : };
144 :
145 : static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
146 : # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
147 :
148 9719395 : static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
149 : {
150 : char buffer[1024];
151 : va_list va;
152 : const char *d;
153 9719395 : unsigned int lvl = 0;
154 9719395 : const char *prefix = "UWRAP";
155 :
156 9719395 : d = getenv("UID_WRAPPER_DEBUGLEVEL");
157 9719395 : if (d != NULL) {
158 0 : lvl = atoi(d);
159 : }
160 :
161 9719395 : if (lvl < dbglvl) {
162 9719395 : return;
163 : }
164 :
165 0 : va_start(va, format);
166 0 : vsnprintf(buffer, sizeof(buffer), format, va);
167 0 : va_end(va);
168 :
169 0 : switch (dbglvl) {
170 0 : case UWRAP_LOG_ERROR:
171 0 : prefix = "UWRAP_ERROR";
172 0 : break;
173 0 : case UWRAP_LOG_WARN:
174 0 : prefix = "UWRAP_WARN";
175 0 : break;
176 0 : case UWRAP_LOG_DEBUG:
177 0 : prefix = "UWRAP_DEBUG";
178 0 : break;
179 0 : case UWRAP_LOG_TRACE:
180 0 : prefix = "UWRAP_TRACE";
181 0 : break;
182 : }
183 :
184 0 : fprintf(stderr,
185 : "%s(%d) - %s: %s\n",
186 : prefix,
187 0 : (int)getpid(),
188 : function,
189 : buffer);
190 : }
191 :
192 : /*****************
193 : * LIBC
194 : *****************/
195 :
196 : #define LIBC_NAME "libc.so"
197 :
198 : typedef int (*__libc_setuid)(uid_t uid);
199 :
200 : typedef uid_t (*__libc_getuid)(void);
201 :
202 : #ifdef HAVE_SETEUID
203 : typedef int (*__libc_seteuid)(uid_t euid);
204 : #endif
205 :
206 : #ifdef HAVE_SETREUID
207 : typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
208 : #endif
209 :
210 : #ifdef HAVE_SETRESUID
211 : typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
212 : #endif
213 :
214 : #ifdef HAVE_GETRESUID
215 : typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
216 : #endif
217 :
218 : typedef uid_t (*__libc_geteuid)(void);
219 :
220 : typedef int (*__libc_setgid)(gid_t gid);
221 :
222 : typedef gid_t (*__libc_getgid)(void);
223 :
224 : #ifdef HAVE_SETEGID
225 : typedef int (*__libc_setegid)(uid_t egid);
226 : #endif
227 :
228 : #ifdef HAVE_SETREGID
229 : typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
230 : #endif
231 :
232 : #ifdef HAVE_SETRESGID
233 : typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
234 : #endif
235 :
236 : #ifdef HAVE_GETRESGID
237 : typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
238 : #endif
239 :
240 : typedef gid_t (*__libc_getegid)(void);
241 :
242 : typedef int (*__libc_getgroups)(int size, gid_t list[]);
243 :
244 : typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
245 :
246 : #ifdef HAVE_SYSCALL
247 : typedef long int (*__libc_syscall)(long int sysno, ...);
248 : #endif
249 :
250 : #define UWRAP_SYMBOL_ENTRY(i) \
251 : union { \
252 : __libc_##i f; \
253 : void *obj; \
254 : } _libc_##i
255 :
256 : struct uwrap_libc_symbols {
257 : UWRAP_SYMBOL_ENTRY(setuid);
258 : UWRAP_SYMBOL_ENTRY(getuid);
259 : #ifdef HAVE_SETEUID
260 : UWRAP_SYMBOL_ENTRY(seteuid);
261 : #endif
262 : #ifdef HAVE_SETREUID
263 : UWRAP_SYMBOL_ENTRY(setreuid);
264 : #endif
265 : #ifdef HAVE_SETRESUID
266 : UWRAP_SYMBOL_ENTRY(setresuid);
267 : #endif
268 : #ifdef HAVE_GETRESUID
269 : UWRAP_SYMBOL_ENTRY(getresuid);
270 : #endif
271 : UWRAP_SYMBOL_ENTRY(geteuid);
272 : UWRAP_SYMBOL_ENTRY(setgid);
273 : UWRAP_SYMBOL_ENTRY(getgid);
274 : #ifdef HAVE_SETEGID
275 : UWRAP_SYMBOL_ENTRY(setegid);
276 : #endif
277 : #ifdef HAVE_SETREGID
278 : UWRAP_SYMBOL_ENTRY(setregid);
279 : #endif
280 : #ifdef HAVE_SETRESGID
281 : UWRAP_SYMBOL_ENTRY(setresgid);
282 : #endif
283 : #ifdef HAVE_GETRESGID
284 : UWRAP_SYMBOL_ENTRY(getresgid);
285 : #endif
286 : UWRAP_SYMBOL_ENTRY(getegid);
287 : UWRAP_SYMBOL_ENTRY(getgroups);
288 : UWRAP_SYMBOL_ENTRY(setgroups);
289 : #ifdef HAVE_SYSCALL
290 : UWRAP_SYMBOL_ENTRY(syscall);
291 : #endif
292 : };
293 : #undef UWRAP_SYMBOL_ENTRY
294 :
295 : /*****************
296 : * LIBPTHREAD
297 : *****************/
298 : /* Yeah... I'm pig. I overloading macro here... So what? */
299 : #define UWRAP_SYMBOL_ENTRY(i) \
300 : union { \
301 : __libpthread_##i f; \
302 : void *obj; \
303 : } _libpthread_##i
304 :
305 : typedef int (*__libpthread_pthread_create)(pthread_t *thread,
306 : const pthread_attr_t *attr,
307 : void *(*start_routine) (void *),
308 : void *arg);
309 : typedef void (*__libpthread_pthread_exit)(void *retval);
310 :
311 : struct uwrap_libpthread_symbols {
312 : UWRAP_SYMBOL_ENTRY(pthread_create);
313 : UWRAP_SYMBOL_ENTRY(pthread_exit);
314 : };
315 : #undef UWRAP_SYMBOL_ENTRY
316 :
317 : /*
318 : * We keep the virtualised euid/egid/groups information here
319 : */
320 : struct uwrap_thread {
321 : bool enabled;
322 :
323 : uid_t ruid;
324 : uid_t euid;
325 : uid_t suid;
326 :
327 : gid_t rgid;
328 : gid_t egid;
329 : gid_t sgid;
330 :
331 : int ngroups;
332 : gid_t *groups;
333 :
334 : struct uwrap_thread *next;
335 : struct uwrap_thread *prev;
336 : };
337 :
338 : struct uwrap {
339 : struct {
340 : void *handle;
341 : struct uwrap_libc_symbols symbols;
342 : } libc;
343 :
344 : struct {
345 : void *handle;
346 : struct uwrap_libpthread_symbols symbols;
347 : } libpthread;
348 :
349 : bool initialised;
350 :
351 : /* Real uid and gid of user who run uid wrapper */
352 : uid_t myuid;
353 : gid_t mygid;
354 :
355 : struct uwrap_thread *ids;
356 : };
357 :
358 : static struct uwrap uwrap;
359 :
360 : /* Shortcut to the list item */
361 : static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
362 :
363 : /* The mutex or accessing the id */
364 : static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
365 :
366 : /* The mutex for accessing the global libc.symbols */
367 : static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
368 :
369 : /* The mutex for accessing the global libpthread.symbols */
370 : static pthread_mutex_t libpthread_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
371 :
372 : /*********************************************************
373 : * UWRAP PROTOTYPES
374 : *********************************************************/
375 :
376 : bool uid_wrapper_enabled(void);
377 : void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
378 : void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
379 :
380 : /*********************************************************
381 : * UWRAP LIBC LOADER FUNCTIONS
382 : *********************************************************/
383 :
384 : enum uwrap_lib {
385 : UWRAP_LIBC,
386 : UWRAP_LIBNSL,
387 : UWRAP_LIBSOCKET,
388 : UWRAP_LIBPTHREAD,
389 : };
390 :
391 170796 : static void *uwrap_load_lib_handle(enum uwrap_lib lib)
392 : {
393 170796 : int flags = RTLD_LAZY;
394 170796 : void *handle = NULL;
395 : int i;
396 :
397 : #ifdef RTLD_DEEPBIND
398 170796 : const char *env_preload = getenv("LD_PRELOAD");
399 170796 : const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
400 170796 : bool enable_deepbind = true;
401 :
402 : /* Don't do a deepbind if we run with libasan */
403 170796 : if (env_preload != NULL && strlen(env_preload) < 1024) {
404 170796 : const char *p = strstr(env_preload, "libasan.so");
405 170796 : if (p != NULL) {
406 0 : enable_deepbind = false;
407 : }
408 : }
409 :
410 170796 : if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
411 0 : enable_deepbind = false;
412 : }
413 :
414 170796 : if (enable_deepbind) {
415 170796 : flags |= RTLD_DEEPBIND;
416 : }
417 : #endif
418 :
419 170796 : switch (lib) {
420 170248 : case UWRAP_LIBNSL:
421 : case UWRAP_LIBSOCKET:
422 : case UWRAP_LIBC:
423 170248 : handle = uwrap.libc.handle;
424 170248 : if (handle == NULL) {
425 495365 : for (i = 10; i >= 0; i--) {
426 289010 : char soname[256] = {0};
427 :
428 289010 : snprintf(soname, sizeof(soname), "libc.so.%d", i);
429 289010 : handle = dlopen(soname, flags);
430 289010 : if (handle != NULL) {
431 99073 : break;
432 : }
433 :
434 : /* glibc on Alpha and IA64 is libc.so.6.1 */
435 231208 : snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
436 231208 : handle = dlopen(soname, flags);
437 231208 : if (handle != NULL) {
438 0 : break;
439 : }
440 : }
441 :
442 57802 : uwrap.libc.handle = handle;
443 : }
444 170248 : break;
445 548 : case UWRAP_LIBPTHREAD:
446 548 : handle = uwrap.libpthread.handle;
447 548 : if (handle == NULL) {
448 548 : handle = dlopen("libpthread.so.0", flags);
449 548 : if (handle != NULL) {
450 548 : break;
451 : }
452 : }
453 0 : break;
454 : }
455 :
456 170796 : if (handle == NULL) {
457 : #ifdef RTLD_NEXT
458 0 : handle = uwrap.libc.handle = RTLD_NEXT;
459 : #else
460 : fprintf(stderr,
461 : "Failed to dlopen library: %s\n",
462 : dlerror());
463 : exit(-1);
464 : #endif
465 : }
466 :
467 170796 : return handle;
468 : }
469 :
470 170796 : static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
471 : {
472 : void *handle;
473 : void *func;
474 :
475 170796 : handle = uwrap_load_lib_handle(lib);
476 :
477 170796 : func = dlsym(handle, fn_name);
478 170796 : if (func == NULL) {
479 0 : fprintf(stderr,
480 : "Failed to find %s: %s\n",
481 : fn_name, dlerror());
482 0 : exit(-1);
483 : }
484 :
485 170796 : return func;
486 : }
487 :
488 : #define uwrap_bind_symbol_libc(sym_name) \
489 : UWRAP_LOCK(libc_symbol_binding); \
490 : if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
491 : uwrap.libc.symbols._libc_##sym_name.obj = \
492 : _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
493 : } \
494 : UWRAP_UNLOCK(libc_symbol_binding)
495 :
496 : #define uwrap_bind_symbol_libpthread(sym_name) \
497 : UWRAP_LOCK(libpthread_symbol_binding); \
498 : if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
499 : uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
500 : _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
501 : } \
502 : UWRAP_UNLOCK(libpthread_symbol_binding)
503 :
504 : /*
505 : * IMPORTANT
506 : *
507 : * Functions expeciall from libc need to be loaded individually, you can't load
508 : * all at once or gdb will segfault at startup. The same applies to valgrind and
509 : * has probably something todo with with the linker.
510 : * So we need load each function at the point it is called the first time.
511 : */
512 0 : static int libc_setuid(uid_t uid)
513 : {
514 0 : uwrap_bind_symbol_libc(setuid);
515 :
516 0 : return uwrap.libc.symbols._libc_setuid.f(uid);
517 : }
518 :
519 0 : static uid_t libc_getuid(void)
520 : {
521 0 : uwrap_bind_symbol_libc(getuid);
522 :
523 0 : return uwrap.libc.symbols._libc_getuid.f();
524 : }
525 :
526 : #ifdef HAVE_SETEUID
527 0 : static int libc_seteuid(uid_t euid)
528 : {
529 0 : uwrap_bind_symbol_libc(seteuid);
530 :
531 0 : return uwrap.libc.symbols._libc_seteuid.f(euid);
532 : }
533 : #endif
534 :
535 : #ifdef HAVE_SETREUID
536 0 : static int libc_setreuid(uid_t ruid, uid_t euid)
537 : {
538 0 : uwrap_bind_symbol_libc(setreuid);
539 :
540 0 : return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
541 : }
542 : #endif
543 :
544 : #ifdef HAVE_SETRESUID
545 0 : static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
546 : {
547 0 : uwrap_bind_symbol_libc(setresuid);
548 :
549 0 : return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
550 : }
551 : #endif
552 :
553 : #ifdef HAVE_GETRESUID
554 0 : static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
555 : {
556 0 : uwrap_bind_symbol_libc(getresuid);
557 :
558 0 : return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
559 : }
560 : #endif
561 :
562 57802 : static uid_t libc_geteuid(void)
563 : {
564 57802 : uwrap_bind_symbol_libc(geteuid);
565 :
566 57802 : return uwrap.libc.symbols._libc_geteuid.f();
567 : }
568 :
569 0 : static int libc_setgid(gid_t gid)
570 : {
571 0 : uwrap_bind_symbol_libc(setgid);
572 :
573 0 : return uwrap.libc.symbols._libc_setgid.f(gid);
574 : }
575 :
576 0 : static gid_t libc_getgid(void)
577 : {
578 0 : uwrap_bind_symbol_libc(getgid);
579 :
580 0 : return uwrap.libc.symbols._libc_getgid.f();
581 : }
582 :
583 : #ifdef HAVE_SETEGID
584 0 : static int libc_setegid(gid_t egid)
585 : {
586 0 : uwrap_bind_symbol_libc(setegid);
587 :
588 0 : return uwrap.libc.symbols._libc_setegid.f(egid);
589 : }
590 : #endif
591 :
592 : #ifdef HAVE_SETREGID
593 0 : static int libc_setregid(gid_t rgid, gid_t egid)
594 : {
595 0 : uwrap_bind_symbol_libc(setregid);
596 :
597 0 : return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
598 : }
599 : #endif
600 :
601 : #ifdef HAVE_SETRESGID
602 0 : static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
603 : {
604 0 : uwrap_bind_symbol_libc(setresgid);
605 :
606 0 : return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
607 : }
608 : #endif
609 :
610 : #ifdef HAVE_GETRESGID
611 0 : static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
612 : {
613 0 : uwrap_bind_symbol_libc(setresgid);
614 :
615 0 : return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
616 : }
617 : #endif
618 :
619 57802 : static gid_t libc_getegid(void)
620 : {
621 57802 : uwrap_bind_symbol_libc(getegid);
622 :
623 57802 : return uwrap.libc.symbols._libc_getegid.f();
624 : }
625 :
626 90506 : static int libc_getgroups(int size, gid_t list[])
627 : {
628 90506 : uwrap_bind_symbol_libc(getgroups);
629 :
630 90506 : return uwrap.libc.symbols._libc_getgroups.f(size, list);
631 : }
632 :
633 0 : static int libc_setgroups(size_t size, const gid_t *list)
634 : {
635 0 : uwrap_bind_symbol_libc(setgroups);
636 :
637 0 : return uwrap.libc.symbols._libc_setgroups.f(size, list);
638 : }
639 :
640 : #ifdef HAVE_SYSCALL
641 : DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
642 265038 : static long int libc_vsyscall(long int sysno, va_list va)
643 : {
644 : long int args[8];
645 : long int rc;
646 : int i;
647 :
648 265038 : uwrap_bind_symbol_libc(syscall);
649 :
650 2385342 : for (i = 0; i < 8; i++) {
651 2120304 : args[i] = va_arg(va, long int);
652 : }
653 :
654 265038 : rc = uwrap.libc.symbols._libc_syscall.f(sysno,
655 : args[0],
656 : args[1],
657 : args[2],
658 : args[3],
659 : args[4],
660 : args[5],
661 : args[6],
662 : args[7]);
663 :
664 265038 : return rc;
665 : }
666 : #endif
667 :
668 : /*
669 : * This part is "optimistic".
670 : * Thread can ends without pthread_exit call.
671 : */
672 36 : static void libpthread_pthread_exit(void *retval)
673 : {
674 36 : uwrap_bind_symbol_libpthread(pthread_exit);
675 :
676 36 : uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
677 0 : }
678 :
679 36 : static void uwrap_pthread_exit(void *retval)
680 : {
681 36 : struct uwrap_thread *id = uwrap_tls_id;
682 :
683 36 : UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
684 :
685 36 : UWRAP_LOCK(uwrap_id);
686 36 : if (id == NULL) {
687 0 : UWRAP_UNLOCK(uwrap_id);
688 0 : libpthread_pthread_exit(retval);
689 0 : return;
690 : }
691 :
692 36 : UWRAP_DLIST_REMOVE(uwrap.ids, id);
693 36 : SAFE_FREE(id->groups);
694 36 : SAFE_FREE(id);
695 36 : uwrap_tls_id = NULL;
696 :
697 36 : UWRAP_UNLOCK(uwrap_id);
698 :
699 36 : libpthread_pthread_exit(retval);
700 : }
701 :
702 : void pthread_exit(void *retval)
703 : {
704 36 : if (!uid_wrapper_enabled()) {
705 0 : libpthread_pthread_exit(retval);
706 : };
707 :
708 36 : uwrap_pthread_exit(retval);
709 :
710 : /* Calm down gcc warning. */
711 0 : exit(666);
712 : }
713 :
714 906 : static int libpthread_pthread_create(pthread_t *thread,
715 : const pthread_attr_t *attr,
716 : void *(*start_routine) (void *),
717 : void *arg)
718 : {
719 906 : uwrap_bind_symbol_libpthread(pthread_create);
720 906 : return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
721 : attr,
722 : start_routine,
723 : arg);
724 : }
725 :
726 : struct uwrap_pthread_create_args {
727 : struct uwrap_thread *id;
728 : void *(*start_routine) (void *);
729 : void *arg;
730 : };
731 :
732 906 : static void *uwrap_pthread_create_start(void *_a)
733 : {
734 906 : struct uwrap_pthread_create_args *a =
735 : (struct uwrap_pthread_create_args *)_a;
736 906 : void *(*start_routine) (void *) = a->start_routine;
737 906 : void *arg = a->arg;
738 906 : struct uwrap_thread *id = a->id;
739 :
740 906 : SAFE_FREE(a);
741 :
742 906 : uwrap_tls_id = id;
743 :
744 906 : return start_routine(arg);
745 : }
746 :
747 906 : static int uwrap_pthread_create(pthread_t *thread,
748 : const pthread_attr_t *attr,
749 : void *(*start_routine) (void *),
750 : void *arg)
751 : {
752 : struct uwrap_pthread_create_args *args;
753 906 : struct uwrap_thread *src_id = uwrap_tls_id;
754 : int ret;
755 :
756 906 : args = malloc(sizeof(struct uwrap_pthread_create_args));
757 906 : if (args == NULL) {
758 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
759 : "uwrap_pthread_create: Unable to allocate memory");
760 0 : errno = ENOMEM;
761 0 : return -1;
762 : }
763 906 : args->start_routine = start_routine;
764 906 : args->arg = arg;
765 :
766 906 : args->id = calloc(1, sizeof(struct uwrap_thread));
767 906 : if (args->id == NULL) {
768 0 : SAFE_FREE(args);
769 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
770 : "uwrap_pthread_create: Unable to allocate memory");
771 0 : errno = ENOMEM;
772 0 : return -1;
773 : }
774 :
775 906 : UWRAP_LOCK(uwrap_id);
776 :
777 906 : args->id->groups = calloc(src_id->ngroups, sizeof(gid_t));
778 906 : if (args->id->groups == NULL) {
779 0 : UWRAP_UNLOCK(uwrap_id);
780 0 : SAFE_FREE(args->id);
781 0 : SAFE_FREE(args);
782 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
783 : "uwrap_pthread_create: Unable to allocate memory again");
784 0 : errno = ENOMEM;
785 0 : return -1;
786 : }
787 :
788 906 : args->id->ruid = src_id->ruid;
789 906 : args->id->euid = src_id->euid;
790 906 : args->id->suid = src_id->suid;
791 :
792 906 : args->id->rgid = src_id->rgid;
793 906 : args->id->egid = src_id->egid;
794 906 : args->id->sgid = src_id->sgid;
795 :
796 906 : args->id->enabled = src_id->enabled;
797 :
798 906 : args->id->ngroups = src_id->ngroups;
799 906 : if (src_id->groups != NULL) {
800 906 : memcpy(args->id->groups, src_id->groups,
801 906 : sizeof(gid_t) * src_id->ngroups);
802 : } else {
803 0 : SAFE_FREE(args->id->groups);
804 : }
805 :
806 906 : UWRAP_DLIST_ADD(uwrap.ids, args->id);
807 906 : UWRAP_UNLOCK(uwrap_id);
808 :
809 906 : ret = libpthread_pthread_create(thread, attr,
810 : uwrap_pthread_create_start,
811 : args);
812 906 : if (ret != 0) {
813 0 : return ret;
814 : }
815 :
816 906 : return ret;
817 : }
818 :
819 : int pthread_create(pthread_t *thread,
820 : const pthread_attr_t *attr,
821 : void *(*start_routine) (void *),
822 : void *arg)
823 : {
824 906 : if (!uid_wrapper_enabled()) {
825 0 : return libpthread_pthread_create(thread,
826 : attr,
827 : start_routine,
828 : arg);
829 : };
830 :
831 906 : return uwrap_pthread_create(thread,
832 : attr,
833 : start_routine,
834 : arg);
835 : }
836 :
837 : /*********************************************************
838 : * UWRAP ID HANDLING
839 : *********************************************************/
840 :
841 : #define GROUP_STRING_SIZE 16384
842 : #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
843 :
844 : /**
845 : * This function exports all the IDs of the current user so if
846 : * we fork and then exec we can setup uid_wrapper in the new process
847 : * with those IDs.
848 : */
849 17675 : static void uwrap_export_ids(struct uwrap_thread *id)
850 : {
851 17675 : char groups_str[GROUP_STRING_SIZE] = {0};
852 17675 : size_t groups_str_size = sizeof(groups_str);
853 17675 : char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
854 : int i;
855 :
856 : /* UIDS */
857 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
858 17675 : setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
859 :
860 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
861 17675 : setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
862 :
863 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
864 17675 : setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
865 :
866 : /* GIDS */
867 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
868 17675 : setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
869 :
870 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
871 17675 : setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
872 :
873 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
874 17675 : setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
875 :
876 17675 : if (id->ngroups > GROUP_MAX_COUNT) {
877 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
878 : "ERROR: Number of groups (%u) exceeds maximum value "
879 : "uid_wrapper can handle (%u).",
880 : id->ngroups,
881 : GROUP_MAX_COUNT);
882 0 : exit(-1);
883 : }
884 :
885 : /* GROUPS */
886 35349 : for (i = 0; i < id->ngroups; i++) {
887 17674 : size_t groups_str_len = strlen(groups_str);
888 17674 : size_t groups_str_avail = groups_str_size - groups_str_len - 1;
889 : int len;
890 :
891 17674 : len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
892 17674 : if (len <= 1) {
893 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
894 : "snprintf failed for groups[%d]=%u",
895 : i,
896 : id->groups[i]);
897 0 : break;
898 : }
899 17674 : if (((size_t)len) >= groups_str_avail) {
900 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
901 : "groups env string is to small for %d groups",
902 : i);
903 0 : break;
904 : }
905 :
906 17674 : len = snprintf(groups_str + groups_str_len,
907 : groups_str_size - groups_str_len,
908 : "%s",
909 : i == 0 ? unsigned_str + 1 : unsigned_str);
910 17674 : if (len < 1) {
911 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
912 : "snprintf failed to create groups string at groups[%d]=%u",
913 : i,
914 : id->groups[i]);
915 0 : break;
916 : }
917 : }
918 :
919 17675 : if (id->ngroups == i) {
920 17675 : setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
921 :
922 17675 : snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
923 17675 : setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
924 : }
925 17675 : }
926 :
927 419750 : static void uwrap_thread_prepare(void)
928 : {
929 419750 : struct uwrap_thread *id = uwrap_tls_id;
930 :
931 419750 : UWRAP_LOCK_ALL;
932 :
933 : /* uid_wrapper is loaded but not enabled */
934 419750 : if (id == NULL) {
935 0 : return;
936 : }
937 :
938 : /*
939 : * What happens if another atfork prepare functions calls a uwrap
940 : * function? So disable it in case another atfork prepare function
941 : * calls a (s)uid function. We disable uid_wrapper only for thread
942 : * (process) which called fork.
943 : */
944 419750 : id->enabled = false;
945 : }
946 :
947 402075 : static void uwrap_thread_parent(void)
948 : {
949 402075 : struct uwrap_thread *id = uwrap_tls_id;
950 :
951 : /* uid_wrapper is loaded but not enabled */
952 402075 : if (id == NULL) {
953 0 : UWRAP_UNLOCK_ALL;
954 0 : return;
955 : }
956 :
957 402075 : id->enabled = true;
958 :
959 402075 : UWRAP_UNLOCK_ALL;
960 : }
961 :
962 17675 : static void uwrap_thread_child(void)
963 : {
964 17675 : struct uwrap_thread *id = uwrap_tls_id;
965 17675 : struct uwrap_thread *u = uwrap.ids;
966 :
967 : /* uid_wrapper is loaded but not enabled */
968 17675 : if (id == NULL) {
969 0 : UWRAP_UNLOCK_ALL;
970 0 : return;
971 : }
972 :
973 : /*
974 : * "Garbage collector" - Inspired by DESTRUCTOR.
975 : * All threads (except one which called fork()) are dead now.. Dave
976 : * That's what posix said...
977 : */
978 49960 : while (u != NULL) {
979 17825 : if (u == id) {
980 : /* Skip this item. */
981 17675 : u = uwrap.ids->next;
982 17675 : continue;
983 : }
984 :
985 150 : UWRAP_DLIST_REMOVE(uwrap.ids, u);
986 :
987 150 : SAFE_FREE(u->groups);
988 150 : SAFE_FREE(u);
989 :
990 150 : u = uwrap.ids;
991 : }
992 :
993 17675 : uwrap_export_ids(id);
994 :
995 17675 : id->enabled = true;
996 :
997 17675 : UWRAP_UNLOCK_ALL;
998 : }
999 :
1000 346812 : static unsigned long uwrap_get_xid_from_env(const char *envname)
1001 : {
1002 : unsigned long xid;
1003 346812 : const char *env = NULL;
1004 346812 : char *endp = NULL;
1005 :
1006 346812 : env = getenv(envname);
1007 346812 : if (env == NULL) {
1008 158480 : return ULONG_MAX;
1009 : }
1010 :
1011 188332 : if (env[0] == '\0') {
1012 0 : unsetenv(envname);
1013 0 : return ULONG_MAX;
1014 : }
1015 :
1016 188332 : xid = strtoul(env, &endp, 10);
1017 188332 : unsetenv(envname);
1018 188332 : if (env == endp) {
1019 0 : return ULONG_MAX;
1020 : }
1021 :
1022 188332 : return xid;
1023 : }
1024 :
1025 : /*
1026 : * This initializes uid_wrapper with the IDs exported to the environment. Those
1027 : * are normally set after we forked and executed.
1028 : */
1029 57802 : static void uwrap_init_env(struct uwrap_thread *id)
1030 : {
1031 : const char *env;
1032 57802 : int ngroups = 0;
1033 : unsigned long xid;
1034 :
1035 : /* UIDs */
1036 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RUID");
1037 57802 : if (xid != ULONG_MAX) {
1038 31392 : id->ruid = (uid_t)xid;
1039 : }
1040 :
1041 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EUID");
1042 57802 : if (xid != ULONG_MAX) {
1043 31392 : id->euid = (uid_t)xid;
1044 : }
1045 :
1046 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SUID");
1047 57802 : if (xid != ULONG_MAX) {
1048 31387 : id->suid = (uid_t)xid;
1049 : }
1050 :
1051 : /* GIDs */
1052 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RGID");
1053 57802 : if (xid != ULONG_MAX) {
1054 31387 : id->rgid = (gid_t)xid;
1055 : }
1056 :
1057 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EGID");
1058 57802 : if (xid != ULONG_MAX) {
1059 31387 : id->egid = (gid_t)xid;
1060 : }
1061 :
1062 57802 : xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SGID");
1063 57802 : if (xid != ULONG_MAX) {
1064 31387 : id->sgid = (gid_t)xid;
1065 : }
1066 :
1067 57802 : env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1068 57802 : if (env != NULL && env[0] != '\0') {
1069 31387 : char *endp = NULL;
1070 : long n;
1071 :
1072 31387 : n = strtol(env, &endp, 10);
1073 31387 : if (env == endp) {
1074 0 : ngroups = 0;
1075 31387 : } else if (n > 0 && n < GROUP_MAX_COUNT) {
1076 31385 : ngroups = (int)n;
1077 : }
1078 31387 : unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1079 : }
1080 :
1081 57802 : if (ngroups > 0) {
1082 31385 : int i = 0;
1083 :
1084 31385 : id->ngroups = 0;
1085 :
1086 31385 : free(id->groups);
1087 31385 : id->groups = calloc(ngroups, sizeof(gid_t));
1088 31385 : if (id->groups == NULL) {
1089 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1090 : "Unable to allocate memory");
1091 0 : exit(-1);
1092 : }
1093 :
1094 31385 : env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1095 31385 : if (env != NULL && env[0] != '\0') {
1096 31385 : char *groups_str = NULL;
1097 31385 : char *saveptr = NULL;
1098 31385 : const char *p = NULL;
1099 :
1100 31385 : groups_str = strdup(env);
1101 31385 : if (groups_str == NULL) {
1102 0 : exit(-1);
1103 : }
1104 :
1105 31385 : p = strtok_r(groups_str, ",", &saveptr);
1106 79848 : while (p != NULL) {
1107 31385 : id->groups[i] = strtol(p, (char **)NULL, 10);
1108 31385 : i++;
1109 :
1110 31385 : p = strtok_r(NULL, ",", &saveptr);
1111 : }
1112 31385 : SAFE_FREE(groups_str);
1113 : }
1114 :
1115 31385 : if (i != ngroups) {
1116 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1117 : "ERROR: The number of groups (%u) passed, "
1118 : "does not match the number of groups (%u) "
1119 : "we parsed.",
1120 : ngroups,
1121 : i);
1122 0 : exit(-1);
1123 : }
1124 :
1125 31385 : UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1126 31385 : id->ngroups = ngroups;
1127 : }
1128 57802 : }
1129 :
1130 10954196 : static void uwrap_init(void)
1131 : {
1132 : const char *env;
1133 :
1134 10954196 : UWRAP_LOCK(uwrap_id);
1135 :
1136 10954196 : if (uwrap.initialised) {
1137 10896394 : struct uwrap_thread *id = uwrap_tls_id;
1138 :
1139 10896394 : if (uwrap.ids == NULL) {
1140 0 : UWRAP_UNLOCK(uwrap_id);
1141 0 : return;
1142 : }
1143 :
1144 10896394 : if (id == NULL) {
1145 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1146 : "Invalid id for thread");
1147 0 : exit(-1);
1148 : }
1149 :
1150 10896394 : UWRAP_UNLOCK(uwrap_id);
1151 10896394 : return;
1152 : }
1153 :
1154 57802 : UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1155 :
1156 57802 : uwrap.initialised = true;
1157 :
1158 57802 : env = getenv("UID_WRAPPER");
1159 57802 : if (env != NULL && env[0] == '1') {
1160 57802 : const char *root = getenv("UID_WRAPPER_ROOT");
1161 : struct uwrap_thread *id;
1162 :
1163 57802 : id = calloc(1, sizeof(struct uwrap_thread));
1164 57802 : if (id == NULL) {
1165 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1166 : "Unable to allocate memory for main id");
1167 0 : exit(-1);
1168 : }
1169 :
1170 57802 : UWRAP_DLIST_ADD(uwrap.ids, id);
1171 57802 : uwrap_tls_id = id;
1172 :
1173 57802 : uwrap.myuid = libc_geteuid();
1174 57802 : uwrap.mygid = libc_getegid();
1175 :
1176 : /* put us in one group */
1177 57802 : if (root != NULL && root[0] == '1') {
1178 12549 : id->ruid = id->euid = id->suid = 0;
1179 12549 : id->rgid = id->egid = id->sgid = 0;
1180 :
1181 12549 : id->groups = malloc(sizeof(gid_t) * 1);
1182 12549 : if (id->groups == NULL) {
1183 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1184 : "Unable to allocate memory");
1185 0 : exit(-1);
1186 : }
1187 :
1188 12549 : id->ngroups = 1;
1189 12549 : id->groups[0] = 0;
1190 :
1191 : } else {
1192 45253 : id->ruid = id->euid = id->suid = uwrap.myuid;
1193 45253 : id->rgid = id->egid = id->sgid = uwrap.mygid;
1194 :
1195 45253 : id->ngroups = libc_getgroups(0, NULL);
1196 45253 : if (id->ngroups == -1) {
1197 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1198 : "Unable to call libc_getgroups in uwrap_init.");
1199 0 : exit(-1);
1200 : }
1201 45253 : id->groups = malloc(sizeof(gid_t) * id->ngroups);
1202 45253 : if (id->groups == NULL) {
1203 0 : UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1204 0 : exit(-1);
1205 : }
1206 45253 : if (libc_getgroups(id->ngroups, id->groups) == -1) {
1207 0 : UWRAP_LOG(UWRAP_LOG_ERROR,
1208 : "Unable to call libc_getgroups again in uwrap_init.");
1209 0 : id->groups = 0;
1210 : /*
1211 : * Deallocation of uwrap.groups is handled by
1212 : * library destructor.
1213 : */
1214 0 : exit(-1);
1215 : }
1216 : }
1217 :
1218 57802 : uwrap_init_env(id);
1219 :
1220 57802 : id->enabled = true;
1221 :
1222 57802 : UWRAP_LOG(UWRAP_LOG_DEBUG,
1223 : "Enabled uid_wrapper as %s (real uid=%u)",
1224 : id->ruid == 0 ? "root" : "user",
1225 : (unsigned int)uwrap.myuid);
1226 : }
1227 :
1228 57802 : UWRAP_UNLOCK(uwrap_id);
1229 :
1230 57802 : UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1231 : }
1232 :
1233 12092552 : bool uid_wrapper_enabled(void)
1234 : {
1235 12092552 : struct uwrap_thread *id = uwrap_tls_id;
1236 : bool enabled;
1237 :
1238 12092552 : if (id == NULL) {
1239 46 : return false;
1240 : }
1241 :
1242 12092506 : UWRAP_LOCK(uwrap_id);
1243 12092506 : enabled = id->enabled;
1244 12092506 : UWRAP_UNLOCK(uwrap_id);
1245 :
1246 12092506 : return enabled;
1247 : }
1248 :
1249 : /*
1250 : * UWRAP_SETxUID FUNCTIONS
1251 : */
1252 :
1253 3008713 : static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1254 : {
1255 3008713 : struct uwrap_thread *id = uwrap_tls_id;
1256 :
1257 3008713 : UWRAP_LOG(UWRAP_LOG_TRACE,
1258 : "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1259 : id->ruid, ruid, id->euid, euid, id->suid, suid);
1260 :
1261 3008713 : if (id->euid != 0) {
1262 753225 : if (ruid != (uid_t)-1 &&
1263 55723 : ruid != id->ruid &&
1264 55057 : ruid != id->euid &&
1265 33233 : ruid != id->suid) {
1266 0 : errno = EPERM;
1267 0 : return -1;
1268 : }
1269 1450027 : if (euid != (uid_t)-1 &&
1270 752656 : euid != id->ruid &&
1271 55057 : euid != id->euid &&
1272 33233 : euid != id->suid) {
1273 0 : errno = EPERM;
1274 0 : return -1;
1275 : }
1276 730835 : if (suid != (uid_t)-1 &&
1277 6 : suid != id->ruid &&
1278 6 : suid != id->euid &&
1279 3 : suid != id->suid) {
1280 0 : errno = EPERM;
1281 0 : return -1;
1282 : }
1283 : }
1284 :
1285 3008713 : return 0;
1286 : }
1287 :
1288 3008713 : static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1289 : {
1290 3008713 : struct uwrap_thread *id = uwrap_tls_id;
1291 : int rc;
1292 :
1293 3008713 : UWRAP_LOG(UWRAP_LOG_TRACE,
1294 : "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1295 : id->ruid, ruid, id->euid, euid, id->suid, suid);
1296 :
1297 3008713 : rc = uwrap_setresuid_args(ruid, euid, suid);
1298 3008713 : if (rc != 0) {
1299 0 : return rc;
1300 : }
1301 :
1302 3008713 : UWRAP_LOCK(uwrap_id);
1303 :
1304 3008713 : if (ruid != (uid_t)-1) {
1305 224160 : id->ruid = ruid;
1306 : }
1307 :
1308 3008713 : if (euid != (uid_t)-1) {
1309 3008713 : id->euid = euid;
1310 : }
1311 :
1312 3008713 : if (suid != (uid_t)-1) {
1313 133 : id->suid = suid;
1314 : }
1315 :
1316 3008713 : UWRAP_UNLOCK(uwrap_id);
1317 :
1318 3008713 : return 0;
1319 : }
1320 :
1321 0 : static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1322 : {
1323 0 : struct uwrap_thread *id = uwrap_tls_id;
1324 : int rc;
1325 :
1326 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1327 : "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1328 : id->ruid, ruid, id->euid, euid, id->suid, suid);
1329 :
1330 0 : rc = uwrap_setresuid_args(ruid, euid, suid);
1331 0 : if (rc != 0) {
1332 0 : return rc;
1333 : }
1334 :
1335 0 : UWRAP_LOCK(uwrap_id);
1336 :
1337 0 : for (id = uwrap.ids; id; id = id->next) {
1338 0 : if (ruid != (uid_t)-1) {
1339 0 : id->ruid = ruid;
1340 : }
1341 :
1342 0 : if (euid != (uid_t)-1) {
1343 0 : id->euid = euid;
1344 : }
1345 :
1346 0 : if (suid != (uid_t)-1) {
1347 0 : id->suid = suid;
1348 : }
1349 : }
1350 :
1351 0 : UWRAP_UNLOCK(uwrap_id);
1352 :
1353 0 : return 0;
1354 : }
1355 :
1356 0 : static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1357 : uid_t *_new_ruid,
1358 : uid_t *_new_euid,
1359 : uid_t *_new_suid)
1360 : {
1361 0 : struct uwrap_thread *id = uwrap_tls_id;
1362 0 : uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1363 :
1364 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1365 : "ruid %d -> %d, euid %d -> %d",
1366 : id->ruid, ruid, id->euid, euid);
1367 :
1368 0 : if (ruid != (uid_t)-1) {
1369 0 : new_ruid = ruid;
1370 0 : if (ruid != id->ruid &&
1371 0 : ruid != id->euid &&
1372 0 : id->euid != 0) {
1373 0 : errno = EPERM;
1374 0 : return -1;
1375 : }
1376 : }
1377 :
1378 0 : if (euid != (uid_t)-1) {
1379 0 : new_euid = euid;
1380 0 : if (euid != id->ruid &&
1381 0 : euid != id->euid &&
1382 0 : euid != id->suid &&
1383 0 : id->euid != 0) {
1384 0 : errno = EPERM;
1385 0 : return -1;
1386 : }
1387 : }
1388 :
1389 0 : if (ruid != (uid_t) -1 ||
1390 0 : (euid != (uid_t)-1 && id->ruid != euid)) {
1391 0 : new_suid = new_euid;
1392 : }
1393 :
1394 0 : *_new_ruid = new_ruid;
1395 0 : *_new_euid = new_euid;
1396 0 : *_new_suid = new_suid;
1397 :
1398 0 : return 0;
1399 : }
1400 :
1401 0 : static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1402 : {
1403 0 : struct uwrap_thread *id = uwrap_tls_id;
1404 0 : uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1405 : int rc;
1406 :
1407 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1408 : "ruid %d -> %d, euid %d -> %d",
1409 : id->ruid, ruid, id->euid, euid);
1410 :
1411 0 : rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1412 0 : if (rc != 0) {
1413 0 : return rc;
1414 : }
1415 :
1416 0 : return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1417 : }
1418 :
1419 : #ifdef HAVE_SETREUID
1420 0 : static int uwrap_setreuid(uid_t ruid, uid_t euid)
1421 : {
1422 0 : struct uwrap_thread *id = uwrap_tls_id;
1423 0 : uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1424 : int rc;
1425 :
1426 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1427 : "ruid %d -> %d, euid %d -> %d",
1428 : id->ruid, ruid, id->euid, euid);
1429 :
1430 0 : rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1431 0 : if (rc != 0) {
1432 0 : return rc;
1433 : }
1434 :
1435 0 : return uwrap_setresuid(new_ruid, new_euid, new_suid);
1436 : }
1437 : #endif
1438 :
1439 68 : static int uwrap_setuid_args(uid_t uid,
1440 : uid_t *new_ruid,
1441 : uid_t *new_euid,
1442 : uid_t *new_suid)
1443 : {
1444 68 : struct uwrap_thread *id = uwrap_tls_id;
1445 :
1446 68 : UWRAP_LOG(UWRAP_LOG_TRACE,
1447 : "uid %d -> %d",
1448 : id->ruid, uid);
1449 :
1450 68 : if (uid == (uid_t)-1) {
1451 0 : errno = EINVAL;
1452 0 : return -1;
1453 : }
1454 :
1455 68 : if (id->euid == 0) {
1456 65 : *new_suid = *new_ruid = uid;
1457 3 : } else if (uid != id->ruid &&
1458 0 : uid != id->suid) {
1459 0 : errno = EPERM;
1460 0 : return -1;
1461 : }
1462 :
1463 68 : *new_euid = uid;
1464 :
1465 68 : return 0;
1466 : }
1467 :
1468 68 : static int uwrap_setuid_thread(uid_t uid)
1469 : {
1470 68 : uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1471 : int rc;
1472 :
1473 68 : rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1474 68 : if (rc != 0) {
1475 0 : return rc;
1476 : }
1477 :
1478 68 : return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1479 : }
1480 :
1481 0 : static int uwrap_setuid(uid_t uid)
1482 : {
1483 0 : uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1484 : int rc;
1485 :
1486 0 : rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1487 0 : if (rc != 0) {
1488 0 : return rc;
1489 : }
1490 :
1491 0 : return uwrap_setresuid(new_ruid, new_euid, new_suid);
1492 : }
1493 :
1494 : /*
1495 : * UWRAP_GETxUID FUNCTIONS
1496 : */
1497 :
1498 : #ifdef HAVE_GETRESUID
1499 0 : static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1500 : {
1501 0 : struct uwrap_thread *id = uwrap_tls_id;
1502 :
1503 0 : UWRAP_LOCK(uwrap_id);
1504 :
1505 0 : *ruid = id->ruid;
1506 0 : *euid = id->euid;
1507 0 : *suid = id->suid;
1508 :
1509 0 : UWRAP_UNLOCK(uwrap_id);
1510 :
1511 0 : return 0;
1512 : }
1513 : #endif
1514 :
1515 : #ifdef HAVE_GETRESGID
1516 0 : static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1517 : {
1518 0 : struct uwrap_thread *id = uwrap_tls_id;
1519 :
1520 0 : UWRAP_LOCK(uwrap_id);
1521 :
1522 0 : *rgid = id->rgid;
1523 0 : *egid = id->egid;
1524 0 : *sgid = id->sgid;
1525 :
1526 0 : UWRAP_UNLOCK(uwrap_id);
1527 :
1528 0 : return 0;
1529 : }
1530 : #endif
1531 :
1532 : /*
1533 : * UWRAP_SETxGID FUNCTIONS
1534 : */
1535 :
1536 1615985 : static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1537 : {
1538 1615985 : struct uwrap_thread *id = uwrap_tls_id;
1539 :
1540 1615985 : UWRAP_LOG(UWRAP_LOG_TRACE,
1541 : "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1542 : id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1543 :
1544 1615985 : if (id->euid != 0) {
1545 33896 : if (rgid != (gid_t)-1 &&
1546 0 : rgid != id->rgid &&
1547 0 : rgid != id->egid &&
1548 0 : rgid != id->sgid) {
1549 0 : errno = EPERM;
1550 0 : return -1;
1551 : }
1552 56286 : if (egid != (gid_t)-1 &&
1553 34465 : egid != id->rgid &&
1554 666 : egid != id->egid &&
1555 0 : egid != id->sgid) {
1556 0 : errno = EPERM;
1557 0 : return -1;
1558 : }
1559 33896 : if (sgid != (gid_t)-1 &&
1560 0 : sgid != id->rgid &&
1561 0 : sgid != id->egid &&
1562 0 : sgid != id->sgid) {
1563 0 : errno = EPERM;
1564 0 : return -1;
1565 : }
1566 : }
1567 :
1568 1615985 : return 0;
1569 : }
1570 :
1571 1615985 : static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1572 : {
1573 1615985 : struct uwrap_thread *id = uwrap_tls_id;
1574 : int rc;
1575 :
1576 1615985 : UWRAP_LOG(UWRAP_LOG_TRACE,
1577 : "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1578 : id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1579 :
1580 1615985 : rc = uwrap_setresgid_args(rgid, egid, sgid);
1581 1615985 : if (rc != 0) {
1582 0 : return rc;
1583 : }
1584 :
1585 1615985 : UWRAP_LOCK(uwrap_id);
1586 :
1587 1615985 : if (rgid != (gid_t)-1) {
1588 224 : id->rgid = rgid;
1589 : }
1590 :
1591 1615985 : if (egid != (gid_t)-1) {
1592 1615985 : id->egid = egid;
1593 : }
1594 :
1595 1615985 : if (sgid != (gid_t)-1) {
1596 180 : id->sgid = sgid;
1597 : }
1598 :
1599 1615985 : UWRAP_UNLOCK(uwrap_id);
1600 :
1601 1615985 : return 0;
1602 : }
1603 :
1604 0 : static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1605 : {
1606 0 : struct uwrap_thread *id = uwrap_tls_id;
1607 : int rc;
1608 :
1609 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1610 : "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1611 : id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1612 :
1613 0 : rc = uwrap_setresgid_args(rgid, egid, sgid);
1614 0 : if (rc != 0) {
1615 0 : return rc;
1616 : }
1617 :
1618 0 : UWRAP_LOCK(uwrap_id);
1619 :
1620 0 : for (id = uwrap.ids; id; id = id->next) {
1621 0 : if (rgid != (gid_t)-1) {
1622 0 : id->rgid = rgid;
1623 : }
1624 :
1625 0 : if (egid != (gid_t)-1) {
1626 0 : id->egid = egid;
1627 : }
1628 :
1629 0 : if (sgid != (gid_t)-1) {
1630 0 : id->sgid = sgid;
1631 : }
1632 : }
1633 :
1634 0 : UWRAP_UNLOCK(uwrap_id);
1635 :
1636 0 : return 0;
1637 : }
1638 :
1639 0 : static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1640 : gid_t *_new_rgid,
1641 : gid_t *_new_egid,
1642 : gid_t *_new_sgid)
1643 : {
1644 0 : struct uwrap_thread *id = uwrap_tls_id;
1645 0 : gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1646 :
1647 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1648 : "rgid %d -> %d, egid %d -> %d",
1649 : id->rgid, rgid, id->egid, egid);
1650 :
1651 0 : if (rgid != (gid_t)-1) {
1652 0 : new_rgid = rgid;
1653 0 : if (rgid != id->rgid &&
1654 0 : rgid != id->egid &&
1655 0 : id->euid != 0) {
1656 0 : errno = EPERM;
1657 0 : return -1;
1658 : }
1659 : }
1660 :
1661 0 : if (egid != (gid_t)-1) {
1662 0 : new_egid = egid;
1663 0 : if (egid != id->rgid &&
1664 0 : egid != id->egid &&
1665 0 : egid != id->sgid &&
1666 0 : id->euid != 0) {
1667 0 : errno = EPERM;
1668 0 : return -1;
1669 : }
1670 : }
1671 :
1672 0 : if (rgid != (gid_t) -1 ||
1673 0 : (egid != (gid_t)-1 && id->rgid != egid)) {
1674 0 : new_sgid = new_egid;
1675 : }
1676 :
1677 0 : *_new_rgid = new_rgid;
1678 0 : *_new_egid = new_egid;
1679 0 : *_new_sgid = new_sgid;
1680 :
1681 0 : return 0;
1682 : }
1683 :
1684 0 : static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1685 : {
1686 0 : struct uwrap_thread *id = uwrap_tls_id;
1687 0 : gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1688 : int rc;
1689 :
1690 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1691 : "rgid %d -> %d, egid %d -> %d",
1692 : id->rgid, rgid, id->egid, egid);
1693 :
1694 0 : rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1695 0 : if (rc != 0) {
1696 0 : return rc;
1697 : }
1698 :
1699 0 : return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1700 : }
1701 :
1702 : #ifdef HAVE_SETREGID
1703 0 : static int uwrap_setregid(gid_t rgid, gid_t egid)
1704 : {
1705 0 : struct uwrap_thread *id = uwrap_tls_id;
1706 0 : gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1707 : int rc;
1708 :
1709 0 : UWRAP_LOG(UWRAP_LOG_TRACE,
1710 : "rgid %d -> %d, egid %d -> %d",
1711 : id->rgid, rgid, id->egid, egid);
1712 :
1713 0 : rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1714 0 : if (rc != 0) {
1715 0 : return rc;
1716 : }
1717 :
1718 0 : return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1719 : }
1720 : #endif
1721 :
1722 112 : static int uwrap_setgid_args(gid_t gid,
1723 : gid_t *new_rgid,
1724 : gid_t *new_egid,
1725 : gid_t *new_sgid)
1726 : {
1727 112 : struct uwrap_thread *id = uwrap_tls_id;
1728 :
1729 112 : UWRAP_LOG(UWRAP_LOG_TRACE,
1730 : "gid %d -> %d",
1731 : id->rgid, gid);
1732 :
1733 112 : if (gid == (gid_t)-1) {
1734 0 : errno = EINVAL;
1735 0 : return -1;
1736 : }
1737 :
1738 112 : if (id->euid == 0) {
1739 112 : *new_sgid = *new_rgid = gid;
1740 0 : } else if (gid != id->rgid &&
1741 0 : gid != id->sgid) {
1742 0 : errno = EPERM;
1743 0 : return -1;
1744 : }
1745 :
1746 112 : *new_egid = gid;
1747 :
1748 112 : return 0;
1749 : }
1750 :
1751 112 : static int uwrap_setgid_thread(gid_t gid)
1752 : {
1753 112 : gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1754 : int rc;
1755 :
1756 112 : rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1757 112 : if (rc != 0) {
1758 0 : return rc;
1759 : }
1760 :
1761 112 : return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1762 : }
1763 :
1764 0 : static int uwrap_setgid(gid_t gid)
1765 : {
1766 0 : gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1767 : int rc;
1768 :
1769 0 : rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1770 0 : if (rc != 0) {
1771 0 : return rc;
1772 : }
1773 :
1774 0 : return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1775 : }
1776 :
1777 : /*
1778 : * SETUID
1779 : */
1780 : int setuid(uid_t uid)
1781 : {
1782 0 : if (!uid_wrapper_enabled()) {
1783 0 : return libc_setuid(uid);
1784 : }
1785 :
1786 0 : uwrap_init();
1787 0 : return uwrap_setuid(uid);
1788 : }
1789 :
1790 : #ifdef HAVE_SETEUID
1791 : int seteuid(uid_t euid)
1792 : {
1793 0 : if (!uid_wrapper_enabled()) {
1794 0 : return libc_seteuid(euid);
1795 : }
1796 :
1797 : /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1798 0 : if (euid == (uid_t)-1) {
1799 0 : errno = EINVAL;
1800 0 : return -1;
1801 : }
1802 :
1803 0 : uwrap_init();
1804 0 : return uwrap_setresuid(-1, euid, -1);
1805 : }
1806 : #endif
1807 :
1808 : #ifdef HAVE_SETREUID
1809 : int setreuid(uid_t ruid, uid_t euid)
1810 : {
1811 0 : if (!uid_wrapper_enabled()) {
1812 0 : return libc_setreuid(ruid, euid);
1813 : }
1814 :
1815 0 : uwrap_init();
1816 0 : return uwrap_setreuid(ruid, euid);
1817 : }
1818 : #endif
1819 :
1820 : #ifdef HAVE_SETRESUID
1821 : int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1822 : {
1823 0 : if (!uid_wrapper_enabled()) {
1824 0 : return libc_setresuid(ruid, euid, suid);
1825 : }
1826 :
1827 0 : uwrap_init();
1828 0 : return uwrap_setresuid(ruid, euid, suid);
1829 : }
1830 : #endif
1831 :
1832 : #ifdef HAVE_GETRESUID
1833 : int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1834 : {
1835 0 : if (!uid_wrapper_enabled()) {
1836 0 : return libc_getresuid(ruid, euid, suid);
1837 : }
1838 :
1839 0 : uwrap_init();
1840 0 : return uwrap_getresuid(ruid, euid, suid);
1841 : }
1842 : #endif
1843 :
1844 : /*
1845 : * GETUID
1846 : */
1847 55996 : static uid_t uwrap_getuid(void)
1848 : {
1849 55996 : struct uwrap_thread *id = uwrap_tls_id;
1850 : uid_t uid;
1851 :
1852 55996 : UWRAP_LOCK(uwrap_id);
1853 55996 : uid = id->ruid;
1854 55996 : UWRAP_UNLOCK(uwrap_id);
1855 :
1856 55996 : return uid;
1857 : }
1858 :
1859 : uid_t getuid(void)
1860 : {
1861 55996 : if (!uid_wrapper_enabled()) {
1862 0 : return libc_getuid();
1863 : }
1864 :
1865 55996 : uwrap_init();
1866 55996 : return uwrap_getuid();
1867 : }
1868 :
1869 : /*
1870 : * GETEUID
1871 : */
1872 1830879 : static uid_t uwrap_geteuid(void)
1873 : {
1874 1830879 : const char *env = getenv("UID_WRAPPER_MYUID");
1875 1830879 : struct uwrap_thread *id = uwrap_tls_id;
1876 : uid_t uid;
1877 :
1878 1830879 : UWRAP_LOCK(uwrap_id);
1879 1830879 : uid = id->euid;
1880 1830879 : UWRAP_UNLOCK(uwrap_id);
1881 :
1882 : /* Disable root and return myuid */
1883 1830879 : if (env != NULL && env[0] == '1') {
1884 370479 : uid = uwrap.myuid;
1885 : }
1886 :
1887 1830879 : return uid;
1888 : }
1889 :
1890 : uid_t geteuid(void)
1891 : {
1892 1830879 : if (!uid_wrapper_enabled()) {
1893 0 : return libc_geteuid();
1894 : }
1895 :
1896 1830879 : uwrap_init();
1897 1830879 : return uwrap_geteuid();
1898 : }
1899 :
1900 : /*
1901 : * SETGID
1902 : */
1903 : int setgid(gid_t gid)
1904 : {
1905 0 : if (!uid_wrapper_enabled()) {
1906 0 : return libc_setgid(gid);
1907 : }
1908 :
1909 0 : uwrap_init();
1910 0 : return uwrap_setgid(gid);
1911 : }
1912 :
1913 : #ifdef HAVE_SETEGID
1914 : int setegid(gid_t egid)
1915 : {
1916 0 : if (!uid_wrapper_enabled()) {
1917 0 : return libc_setegid(egid);
1918 : }
1919 :
1920 : /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1921 0 : if (egid == (gid_t)-1) {
1922 0 : errno = EINVAL;
1923 0 : return -1;
1924 : }
1925 :
1926 0 : uwrap_init();
1927 0 : return uwrap_setresgid(-1, egid, -1);
1928 : }
1929 : #endif
1930 :
1931 : #ifdef HAVE_SETREGID
1932 : int setregid(gid_t rgid, gid_t egid)
1933 : {
1934 0 : if (!uid_wrapper_enabled()) {
1935 0 : return libc_setregid(rgid, egid);
1936 : }
1937 :
1938 0 : uwrap_init();
1939 0 : return uwrap_setregid(rgid, egid);
1940 : }
1941 : #endif
1942 :
1943 : #ifdef HAVE_SETRESGID
1944 : int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1945 : {
1946 0 : if (!uid_wrapper_enabled()) {
1947 0 : return libc_setresgid(rgid, egid, sgid);
1948 : }
1949 :
1950 0 : uwrap_init();
1951 0 : return uwrap_setresgid(rgid, egid, sgid);
1952 : }
1953 : #endif
1954 :
1955 : #ifdef HAVE_GETRESGID
1956 : int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1957 : {
1958 0 : if (!uid_wrapper_enabled()) {
1959 0 : return libc_getresgid(rgid, egid, sgid);
1960 : }
1961 :
1962 0 : uwrap_init();
1963 0 : return uwrap_getresgid(rgid, egid, sgid);
1964 : }
1965 : #endif
1966 :
1967 : /*
1968 : * GETGID
1969 : */
1970 13470 : static gid_t uwrap_getgid(void)
1971 : {
1972 13470 : struct uwrap_thread *id = uwrap_tls_id;
1973 : gid_t gid;
1974 :
1975 13470 : UWRAP_LOCK(uwrap_id);
1976 13470 : gid = id->rgid;
1977 13470 : UWRAP_UNLOCK(uwrap_id);
1978 :
1979 13470 : return gid;
1980 : }
1981 :
1982 : gid_t getgid(void)
1983 : {
1984 13470 : if (!uid_wrapper_enabled()) {
1985 0 : return libc_getgid();
1986 : }
1987 :
1988 13470 : uwrap_init();
1989 13470 : return uwrap_getgid();
1990 : }
1991 :
1992 : /*
1993 : * GETEGID
1994 : */
1995 1011412 : static uid_t uwrap_getegid(void)
1996 : {
1997 1011412 : struct uwrap_thread *id = uwrap_tls_id;
1998 : gid_t gid;
1999 :
2000 1011412 : UWRAP_LOCK(uwrap_id);
2001 1011412 : gid = id->egid;
2002 1011412 : UWRAP_UNLOCK(uwrap_id);
2003 :
2004 1011412 : return gid;
2005 : }
2006 :
2007 : uid_t getegid(void)
2008 : {
2009 1011412 : if (!uid_wrapper_enabled()) {
2010 0 : return libc_getegid();
2011 : }
2012 :
2013 1011412 : uwrap_init();
2014 1011412 : return uwrap_getegid();
2015 : }
2016 :
2017 1615717 : static int uwrap_setgroups_thread(size_t size, const gid_t *list)
2018 : {
2019 1615717 : struct uwrap_thread *id = uwrap_tls_id;
2020 1615717 : int rc = -1;
2021 :
2022 1615717 : UWRAP_LOCK(uwrap_id);
2023 :
2024 1615717 : if (size == 0) {
2025 184450 : SAFE_FREE(id->groups);
2026 184450 : id->ngroups = 0;
2027 1431267 : } else if (size > 0) {
2028 : gid_t *tmp;
2029 :
2030 1431267 : tmp = realloc(id->groups, sizeof(gid_t) * size);
2031 1431267 : if (tmp == NULL) {
2032 0 : errno = ENOMEM;
2033 0 : goto out;
2034 : }
2035 1431267 : id->groups = tmp;
2036 1431267 : id->ngroups = size;
2037 1431267 : memcpy(id->groups, list, size * sizeof(gid_t));
2038 : }
2039 :
2040 1615717 : rc = 0;
2041 1615717 : out:
2042 1615717 : UWRAP_UNLOCK(uwrap_id);
2043 :
2044 1615717 : return rc;
2045 : }
2046 :
2047 0 : static int uwrap_setgroups(size_t size, const gid_t *list)
2048 : {
2049 : struct uwrap_thread *id;
2050 0 : int rc = -1;
2051 :
2052 0 : UWRAP_LOCK(uwrap_id);
2053 :
2054 0 : if (size == 0) {
2055 0 : for (id = uwrap.ids; id; id = id->next) {
2056 0 : SAFE_FREE(id->groups);
2057 0 : id->ngroups = 0;
2058 :
2059 : }
2060 0 : } else if (size > 0) {
2061 : gid_t *tmp;
2062 :
2063 0 : for (id = uwrap.ids; id; id = id->next) {
2064 0 : tmp = realloc(id->groups, sizeof(gid_t) * size);
2065 0 : if (tmp == NULL) {
2066 0 : errno = ENOMEM;
2067 0 : goto out;
2068 : }
2069 0 : id->groups = tmp;
2070 :
2071 0 : id->ngroups = size;
2072 0 : memcpy(id->groups, list, size * sizeof(gid_t));
2073 : }
2074 : }
2075 :
2076 0 : rc = 0;
2077 0 : out:
2078 0 : UWRAP_UNLOCK(uwrap_id);
2079 :
2080 0 : return rc;
2081 : }
2082 :
2083 : #ifdef HAVE_SETGROUPS_INT
2084 : int setgroups(int size, const gid_t *list)
2085 : #else
2086 : int setgroups(size_t size, const gid_t *list)
2087 : #endif
2088 : {
2089 0 : if (!uid_wrapper_enabled()) {
2090 0 : return libc_setgroups(size, list);
2091 : }
2092 :
2093 0 : uwrap_init();
2094 0 : return uwrap_setgroups(size, list);
2095 : }
2096 :
2097 1479230 : static int uwrap_getgroups(int size, gid_t *list)
2098 : {
2099 1479230 : struct uwrap_thread *id = uwrap_tls_id;
2100 : int ngroups;
2101 :
2102 1479230 : UWRAP_LOCK(uwrap_id);
2103 1479230 : ngroups = id->ngroups;
2104 :
2105 1479230 : if (size > ngroups) {
2106 0 : size = ngroups;
2107 : }
2108 1479230 : if (size == 0) {
2109 766012 : goto out;
2110 : }
2111 713218 : if (size < ngroups) {
2112 0 : errno = EINVAL;
2113 0 : ngroups = -1;
2114 : }
2115 713218 : memcpy(list, id->groups, size * sizeof(gid_t));
2116 :
2117 1479230 : out:
2118 1479230 : UWRAP_UNLOCK(uwrap_id);
2119 :
2120 1479230 : return ngroups;
2121 : }
2122 :
2123 : int getgroups(int size, gid_t *list)
2124 : {
2125 1479230 : if (!uid_wrapper_enabled()) {
2126 0 : return libc_getgroups(size, list);
2127 : }
2128 :
2129 1479230 : uwrap_init();
2130 1479230 : return uwrap_getgroups(size, list);
2131 : }
2132 :
2133 : #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2134 : && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2135 6505407 : static long int uwrap_syscall (long int sysno, va_list vp)
2136 : {
2137 : long int rc;
2138 :
2139 6505407 : switch (sysno) {
2140 : /* gid */
2141 : #ifdef __alpha__
2142 : case SYS_getxgid:
2143 : #else
2144 0 : case SYS_getgid:
2145 : #endif
2146 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2147 : case SYS_getgid32:
2148 : #endif
2149 : {
2150 0 : rc = uwrap_getgid();
2151 : }
2152 0 : break;
2153 : #ifdef SYS_getegid
2154 0 : case SYS_getegid:
2155 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2156 : case SYS_getegid32:
2157 : #endif
2158 : {
2159 0 : rc = uwrap_getegid();
2160 : }
2161 0 : break;
2162 : #endif /* SYS_getegid */
2163 112 : case SYS_setgid:
2164 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2165 : case SYS_setgid32:
2166 : #endif
2167 : {
2168 112 : gid_t gid = (gid_t) va_arg(vp, gid_t);
2169 :
2170 112 : rc = uwrap_setgid_thread(gid);
2171 : }
2172 112 : break;
2173 0 : case SYS_setregid:
2174 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2175 : case SYS_setregid32:
2176 : #endif
2177 : {
2178 0 : gid_t rgid = (gid_t) va_arg(vp, gid_t);
2179 0 : gid_t egid = (gid_t) va_arg(vp, gid_t);
2180 :
2181 0 : rc = uwrap_setregid_thread(rgid, egid);
2182 : }
2183 0 : break;
2184 : #ifdef SYS_setresgid
2185 1615873 : case SYS_setresgid:
2186 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2187 : case SYS_setresgid32:
2188 : #endif
2189 : {
2190 1615873 : gid_t rgid = (gid_t) va_arg(vp, gid_t);
2191 1615873 : gid_t egid = (gid_t) va_arg(vp, gid_t);
2192 1615873 : gid_t sgid = (gid_t) va_arg(vp, gid_t);
2193 :
2194 1615873 : rc = uwrap_setresgid_thread(rgid, egid, sgid);
2195 : }
2196 1615873 : break;
2197 : #endif /* SYS_setresgid */
2198 : #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2199 0 : case SYS_getresgid:
2200 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2201 : case SYS_getresgid32:
2202 : #endif
2203 : {
2204 0 : gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2205 0 : gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2206 0 : gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2207 :
2208 0 : rc = uwrap_getresgid(rgid, egid, sgid);
2209 : }
2210 0 : break;
2211 : #endif /* SYS_getresgid && HAVE_GETRESGID */
2212 :
2213 : /* uid */
2214 : #ifdef __alpha__
2215 : case SYS_getxuid:
2216 : #else
2217 0 : case SYS_getuid:
2218 : #endif
2219 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2220 : case SYS_getuid32:
2221 : #endif
2222 : {
2223 0 : rc = uwrap_getuid();
2224 : }
2225 0 : break;
2226 : #ifdef SYS_geteuid
2227 0 : case SYS_geteuid:
2228 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2229 : case SYS_geteuid32:
2230 : #endif
2231 : {
2232 0 : rc = uwrap_geteuid();
2233 : }
2234 0 : break;
2235 : #endif /* SYS_geteuid */
2236 68 : case SYS_setuid:
2237 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2238 : case SYS_setuid32:
2239 : #endif
2240 : {
2241 68 : uid_t uid = (uid_t) va_arg(vp, uid_t);
2242 :
2243 68 : rc = uwrap_setuid_thread(uid);
2244 : }
2245 68 : break;
2246 0 : case SYS_setreuid:
2247 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2248 : case SYS_setreuid32:
2249 : #endif
2250 : {
2251 0 : uid_t ruid = (uid_t) va_arg(vp, uid_t);
2252 0 : uid_t euid = (uid_t) va_arg(vp, uid_t);
2253 :
2254 0 : rc = uwrap_setreuid_thread(ruid, euid);
2255 : }
2256 0 : break;
2257 : #ifdef SYS_setresuid
2258 3008645 : case SYS_setresuid:
2259 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2260 : case SYS_setresuid32:
2261 : #endif
2262 : {
2263 3008645 : uid_t ruid = (uid_t) va_arg(vp, uid_t);
2264 3008645 : uid_t euid = (uid_t) va_arg(vp, uid_t);
2265 3008645 : uid_t suid = (uid_t) va_arg(vp, uid_t);
2266 :
2267 3008645 : rc = uwrap_setresuid_thread(ruid, euid, suid);
2268 : }
2269 3008645 : break;
2270 : #endif /* SYS_setresuid */
2271 : #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2272 0 : case SYS_getresuid:
2273 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2274 : case SYS_getresuid32:
2275 : #endif
2276 : {
2277 0 : uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2278 0 : uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2279 0 : uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2280 :
2281 0 : rc = uwrap_getresuid(ruid, euid, suid);
2282 : }
2283 0 : break;
2284 : #endif /* SYS_getresuid && HAVE_GETRESUID*/
2285 : /* groups */
2286 1615717 : case SYS_setgroups:
2287 : #ifdef HAVE_LINUX_32BIT_SYSCALLS
2288 : case SYS_setgroups32:
2289 : #endif
2290 : {
2291 1615717 : size_t size = (size_t) va_arg(vp, size_t);
2292 1615717 : gid_t *list = (gid_t *) va_arg(vp, int *);
2293 :
2294 1615717 : rc = uwrap_setgroups_thread(size, list);
2295 : }
2296 1615717 : break;
2297 264992 : default:
2298 264992 : UWRAP_LOG(UWRAP_LOG_DEBUG,
2299 : "UID_WRAPPER calling non-wrapped syscall %lu",
2300 : sysno);
2301 :
2302 264992 : rc = libc_vsyscall(sysno, vp);
2303 264992 : break;
2304 : }
2305 :
2306 6505407 : return rc;
2307 : }
2308 :
2309 : #ifdef HAVE_SYSCALL
2310 : #ifdef HAVE_SYSCALL_INT
2311 : int syscall (int sysno, ...)
2312 : #else
2313 : long int syscall (long int sysno, ...)
2314 : #endif
2315 : {
2316 : #ifdef HAVE_SYSCALL_INT
2317 : int rc;
2318 : #else
2319 : long int rc;
2320 : #endif
2321 : va_list va;
2322 :
2323 6505453 : va_start(va, sysno);
2324 :
2325 6505453 : if (!uid_wrapper_enabled()) {
2326 46 : rc = libc_vsyscall(sysno, va);
2327 46 : va_end(va);
2328 46 : return rc;
2329 : }
2330 :
2331 6505407 : uwrap_init();
2332 6505407 : rc = uwrap_syscall(sysno, va);
2333 6505407 : va_end(va);
2334 :
2335 6505407 : return rc;
2336 : }
2337 : #endif /* HAVE_SYSCALL */
2338 : #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2339 :
2340 : /****************************
2341 : * CONSTRUCTOR
2342 : ***************************/
2343 :
2344 57802 : void uwrap_constructor(void)
2345 : {
2346 : char *glibc_malloc_lock_bug;
2347 :
2348 : /*
2349 : * This is a workaround for a bug in glibc < 2.24:
2350 : *
2351 : * The child handler for the malloc() function is called and locks the
2352 : * mutex. Then our child handler is called and we try to call setenv().
2353 : * setenv() wants to malloc and tries to aquire the lock for malloc and
2354 : * we end up in a deadlock.
2355 : *
2356 : * So as a workaround we need to call malloc once before we setup the
2357 : * handlers.
2358 : *
2359 : * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2360 : */
2361 57802 : glibc_malloc_lock_bug = malloc(1);
2362 57802 : if (glibc_malloc_lock_bug == NULL) {
2363 0 : exit(-1);
2364 : }
2365 57802 : glibc_malloc_lock_bug[0] = '\0';
2366 :
2367 : /*
2368 : * If we hold a lock and the application forks, then the child
2369 : * is not able to unlock the mutex and we are in a deadlock.
2370 : * This should prevent such deadlocks.
2371 : */
2372 57802 : pthread_atfork(&uwrap_thread_prepare,
2373 : &uwrap_thread_parent,
2374 : &uwrap_thread_child);
2375 :
2376 57802 : free(glibc_malloc_lock_bug);
2377 :
2378 : /* Here is safe place to call uwrap_init() and initialize data
2379 : * for main process.
2380 : */
2381 57802 : uwrap_init();
2382 57802 : }
2383 :
2384 : /****************************
2385 : * DESTRUCTOR
2386 : ***************************/
2387 :
2388 : /*
2389 : * This function is called when the library is unloaded and makes sure that
2390 : * resources are freed.
2391 : */
2392 76848 : void uwrap_destructor(void)
2393 : {
2394 76848 : struct uwrap_thread *u = uwrap.ids;
2395 :
2396 76848 : UWRAP_LOCK_ALL;
2397 :
2398 208364 : while (u != NULL) {
2399 77718 : UWRAP_DLIST_REMOVE(uwrap.ids, u);
2400 :
2401 77718 : SAFE_FREE(u->groups);
2402 77718 : SAFE_FREE(u);
2403 :
2404 77718 : u = uwrap.ids;
2405 : }
2406 :
2407 :
2408 76848 : if (uwrap.libc.handle != NULL) {
2409 76848 : dlclose(uwrap.libc.handle);
2410 : }
2411 :
2412 76848 : if (uwrap.libpthread.handle != NULL) {
2413 0 : dlclose(uwrap.libpthread.handle);
2414 : }
2415 :
2416 76848 : UWRAP_UNLOCK_ALL;
2417 76848 : }
|