Line data Source code
1 : /*
2 : * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
3 : * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
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 <stdint.h>
28 : #include <sys/types.h>
29 : #include <sys/stat.h>
30 : #include <dirent.h>
31 : #include <fcntl.h>
32 : #include <unistd.h>
33 : #include <dlfcn.h>
34 : #include <libgen.h>
35 : #include <signal.h>
36 : #include <limits.h>
37 : #include <ctype.h>
38 :
39 : #include <pthread.h>
40 :
41 : #include <ftw.h>
42 :
43 : #ifdef HAVE_SECURITY_PAM_APPL_H
44 : #include <security/pam_appl.h>
45 : #endif
46 : #ifdef HAVE_SECURITY_PAM_MODULES_H
47 : #include <security/pam_modules.h>
48 : #endif
49 : #ifdef HAVE_SECURITY_PAM_EXT_H
50 : #include <security/pam_ext.h>
51 : #endif
52 :
53 : #include "pwrap_compat.h"
54 :
55 : #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
56 : # define PWRAP_THREAD __thread
57 : #else
58 : # define PWRAP_THREAD
59 : #endif
60 :
61 : #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
62 : #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
63 : #else
64 : #define CONSTRUCTOR_ATTRIBUTE
65 : #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
66 :
67 : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
68 : #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
69 : #else
70 : #define DESTRUCTOR_ATTRIBUTE
71 : #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
72 :
73 : #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
74 : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
75 : #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
76 : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
77 : #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
78 :
79 : /* GCC have printf type attribute check. */
80 : #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
81 : #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
82 : #else
83 : #define PRINTF_ATTRIBUTE(a,b)
84 : #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
85 :
86 : #ifndef SAFE_FREE
87 : #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
88 : #endif
89 :
90 : #ifndef discard_const
91 : #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
92 : #endif
93 :
94 : #ifndef discard_const_p
95 : #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
96 : #endif
97 :
98 : /*****************
99 : * LOGGING
100 : *****************/
101 :
102 : #ifndef HAVE_GETPROGNAME
103 31410 : static const char *getprogname(void)
104 : {
105 : #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
106 31410 : return program_invocation_short_name;
107 : #elif defined(HAVE_GETEXECNAME)
108 : return getexecname();
109 : #else
110 : return NULL;
111 : #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
112 : }
113 : #endif /* HAVE_GETPROGNAME */
114 :
115 : enum pwrap_dbglvl_e {
116 : PWRAP_LOG_ERROR = 0,
117 : PWRAP_LOG_WARN,
118 : PWRAP_LOG_DEBUG,
119 : PWRAP_LOG_TRACE
120 : };
121 :
122 : static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
123 : const char *function,
124 : const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
125 : # define PWRAP_LOG(dbglvl, ...) pwrap_log((dbglvl), __func__, __VA_ARGS__)
126 :
127 : static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
128 : const char *function,
129 : const char *format,
130 : va_list args) PRINTF_ATTRIBUTE(3, 0);
131 :
132 31410 : static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
133 : const char *function,
134 : const char *format,
135 : va_list args)
136 : {
137 : char buffer[1024];
138 : const char *d;
139 31410 : unsigned int lvl = 0;
140 31410 : const char *prefix = "PWRAP";
141 31410 : const char *progname = getprogname();
142 :
143 31410 : d = getenv("PAM_WRAPPER_DEBUGLEVEL");
144 31410 : if (d != NULL) {
145 31410 : lvl = atoi(d);
146 : }
147 :
148 31410 : if (lvl < dbglvl) {
149 25982 : return;
150 : }
151 :
152 5428 : vsnprintf(buffer, sizeof(buffer), format, args);
153 :
154 5428 : switch (dbglvl) {
155 204 : case PWRAP_LOG_ERROR:
156 204 : prefix = "PWRAP_ERROR";
157 204 : break;
158 76 : case PWRAP_LOG_WARN:
159 76 : prefix = "PWRAP_WARN";
160 76 : break;
161 5148 : case PWRAP_LOG_DEBUG:
162 5148 : prefix = "PWRAP_DEBUG";
163 5148 : break;
164 0 : case PWRAP_LOG_TRACE:
165 0 : prefix = "PWRAP_TRACE";
166 0 : break;
167 : }
168 :
169 5428 : if (progname == NULL) {
170 0 : progname = "<unknown>";
171 : }
172 :
173 5428 : fprintf(stderr,
174 : "%s[%s (%u)] - %s: %s\n",
175 : prefix,
176 : progname,
177 5428 : (unsigned int)getpid(),
178 : function,
179 : buffer);
180 : }
181 :
182 27006 : static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
183 : const char *function,
184 : const char *format, ...)
185 : {
186 : va_list va;
187 :
188 27006 : va_start(va, format);
189 27006 : pwrap_vlog(dbglvl, function, format, va);
190 27006 : va_end(va);
191 27006 : }
192 :
193 : /*****************
194 : * LIBC
195 : *****************/
196 :
197 : #define LIBPAM_NAME "libpam.so.0"
198 :
199 : typedef int (*__libpam_pam_start)(const char *service_name,
200 : const char *user,
201 : const struct pam_conv *pam_conversation,
202 : pam_handle_t **pamh);
203 :
204 : typedef int (*__libpam_pam_start_confdir)(const char *service_name,
205 : const char *user,
206 : const struct pam_conv *pam_conversation,
207 : const char *confdir,
208 : pam_handle_t **pamh);
209 :
210 : typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
211 :
212 : typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
213 :
214 : typedef int (*__libpam_pam_chauthtok)(pam_handle_t *pamh, int flags);
215 :
216 : typedef int (*__libpam_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
217 :
218 : typedef int (*__libpam_pam_putenv)(pam_handle_t *pamh, const char *name_value);
219 :
220 : typedef const char * (*__libpam_pam_getenv)(pam_handle_t *pamh, const char *name);
221 :
222 : typedef char ** (*__libpam_pam_getenvlist)(pam_handle_t *pamh);
223 :
224 : typedef int (*__libpam_pam_open_session)(pam_handle_t *pamh, int flags);
225 :
226 : typedef int (*__libpam_pam_close_session)(pam_handle_t *pamh, int flags);
227 :
228 : typedef int (*__libpam_pam_setcred)(pam_handle_t *pamh, int flags);
229 :
230 : typedef int (*__libpam_pam_get_item)(const pam_handle_t *pamh,
231 : int item_type,
232 : const void **item);
233 :
234 : typedef int (*__libpam_pam_set_item)(pam_handle_t *pamh,
235 : int item_type,
236 : const void *item);
237 :
238 : typedef int (*__libpam_pam_get_data)(const pam_handle_t *pamh,
239 : const char *module_data_name,
240 : const void **data);
241 :
242 : typedef int (*__libpam_pam_set_data)(pam_handle_t *pamh,
243 : const char *module_data_name,
244 : void *data,
245 : void (*cleanup)(pam_handle_t *pamh,
246 : void *data,
247 : int error_status));
248 :
249 : typedef int (*__libpam_pam_vprompt)(pam_handle_t *pamh,
250 : int style,
251 : char **response,
252 : const char *fmt,
253 : va_list args);
254 :
255 : typedef const char * (*__libpam_pam_strerror)(pam_handle_t *pamh,
256 : int errnum);
257 :
258 : #ifdef HAVE_PAM_VSYSLOG
259 : typedef void (*__libpam_pam_vsyslog)(const pam_handle_t *pamh,
260 : int priority,
261 : const char *fmt,
262 : va_list args);
263 : #endif
264 :
265 : #define PWRAP_SYMBOL_ENTRY(i) \
266 : union { \
267 : __libpam_##i f; \
268 : void *obj; \
269 : } _libpam_##i
270 :
271 : struct pwrap_libpam_symbols {
272 : PWRAP_SYMBOL_ENTRY(pam_start);
273 : PWRAP_SYMBOL_ENTRY(pam_start_confdir);
274 : PWRAP_SYMBOL_ENTRY(pam_end);
275 : PWRAP_SYMBOL_ENTRY(pam_authenticate);
276 : PWRAP_SYMBOL_ENTRY(pam_chauthtok);
277 : PWRAP_SYMBOL_ENTRY(pam_acct_mgmt);
278 : PWRAP_SYMBOL_ENTRY(pam_putenv);
279 : PWRAP_SYMBOL_ENTRY(pam_getenv);
280 : PWRAP_SYMBOL_ENTRY(pam_getenvlist);
281 : PWRAP_SYMBOL_ENTRY(pam_open_session);
282 : PWRAP_SYMBOL_ENTRY(pam_close_session);
283 : PWRAP_SYMBOL_ENTRY(pam_setcred);
284 : PWRAP_SYMBOL_ENTRY(pam_get_item);
285 : PWRAP_SYMBOL_ENTRY(pam_set_item);
286 : PWRAP_SYMBOL_ENTRY(pam_get_data);
287 : PWRAP_SYMBOL_ENTRY(pam_set_data);
288 : PWRAP_SYMBOL_ENTRY(pam_vprompt);
289 : PWRAP_SYMBOL_ENTRY(pam_strerror);
290 : #ifdef HAVE_PAM_VSYSLOG
291 : PWRAP_SYMBOL_ENTRY(pam_vsyslog);
292 : #endif
293 : };
294 :
295 : struct pwrap {
296 : struct {
297 : void *handle;
298 : struct pwrap_libpam_symbols symbols;
299 : } libpam;
300 :
301 : bool enabled;
302 : bool initialised;
303 : char *config_dir;
304 : char *libpam_so;
305 : };
306 :
307 : static struct pwrap pwrap;
308 :
309 : /*********************************************************
310 : * PWRAP PROTOTYPES
311 : *********************************************************/
312 :
313 : bool pam_wrapper_enabled(void);
314 : void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
315 : void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
316 :
317 : /*********************************************************
318 : * PWRAP LIBC LOADER FUNCTIONS
319 : *********************************************************/
320 :
321 : enum pwrap_lib {
322 : PWRAP_LIBPAM,
323 : };
324 :
325 700 : static void *pwrap_load_lib_handle(enum pwrap_lib lib)
326 : {
327 700 : int flags = RTLD_LAZY;
328 700 : void *handle = NULL;
329 :
330 : #ifdef RTLD_DEEPBIND
331 700 : const char *env_preload = getenv("LD_PRELOAD");
332 700 : const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
333 700 : bool enable_deepbind = true;
334 :
335 : /* Don't do a deepbind if we run with libasan */
336 700 : if (env_preload != NULL && strlen(env_preload) < 1024) {
337 700 : const char *p = strstr(env_preload, "libasan.so");
338 700 : if (p != NULL) {
339 0 : enable_deepbind = false;
340 : }
341 : }
342 :
343 700 : if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
344 0 : enable_deepbind = false;
345 : }
346 :
347 700 : if (enable_deepbind) {
348 700 : flags |= RTLD_DEEPBIND;
349 : }
350 : #endif
351 :
352 700 : switch (lib) {
353 700 : case PWRAP_LIBPAM:
354 700 : handle = pwrap.libpam.handle;
355 700 : if (handle == NULL) {
356 96 : handle = dlopen(pwrap.libpam_so, flags);
357 96 : if (handle != NULL) {
358 96 : PWRAP_LOG(PWRAP_LOG_DEBUG,
359 : "Opened %s\n", pwrap.libpam_so);
360 96 : pwrap.libpam.handle = handle;
361 96 : break;
362 : }
363 : }
364 604 : break;
365 : }
366 :
367 700 : if (handle == NULL) {
368 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
369 : "Failed to dlopen library: %s\n",
370 : dlerror());
371 0 : exit(-1);
372 : }
373 :
374 700 : return handle;
375 : }
376 :
377 700 : static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
378 : {
379 : void *handle;
380 : void *func;
381 :
382 700 : handle = pwrap_load_lib_handle(lib);
383 :
384 700 : func = dlsym(handle, fn_name);
385 700 : if (func == NULL) {
386 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
387 : "Failed to find %s: %s\n",
388 : fn_name, dlerror());
389 0 : exit(-1);
390 : }
391 :
392 700 : return func;
393 : }
394 :
395 : #define pwrap_bind_symbol_libpam(sym_name) \
396 : if (pwrap.libpam.symbols._libpam_##sym_name.obj == NULL) { \
397 : pwrap.libpam.symbols._libpam_##sym_name.obj = \
398 : _pwrap_bind_symbol(PWRAP_LIBPAM, #sym_name); \
399 : } \
400 :
401 : /*
402 : * IMPORTANT
403 : *
404 : * Functions especially from libpam need to be loaded individually, you can't
405 : * load all at once or gdb will segfault at startup. The same applies to
406 : * valgrind and has probably something todo with with the linker.
407 : * So we need load each function at the point it is called the first time.
408 : */
409 : #ifdef HAVE_PAM_START_CONFDIR
410 124 : static int libpam_pam_start_confdir(const char *service_name,
411 : const char *user,
412 : const struct pam_conv *pam_conversation,
413 : const char *confdir,
414 : pam_handle_t **pamh)
415 : {
416 124 : pwrap_bind_symbol_libpam(pam_start_confdir);
417 :
418 124 : return pwrap.libpam.symbols._libpam_pam_start_confdir.f(service_name,
419 : user,
420 : pam_conversation,
421 : confdir,
422 : pamh);
423 : }
424 : #else
425 124 : static int libpam_pam_start(const char *service_name,
426 : const char *user,
427 : const struct pam_conv *pam_conversation,
428 : pam_handle_t **pamh)
429 : {
430 124 : pwrap_bind_symbol_libpam(pam_start);
431 :
432 124 : return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
433 : user,
434 : pam_conversation,
435 : pamh);
436 : }
437 :
438 : #endif
439 :
440 248 : static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
441 : {
442 248 : pwrap_bind_symbol_libpam(pam_end);
443 :
444 248 : return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
445 : }
446 :
447 236 : static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
448 : {
449 236 : pwrap_bind_symbol_libpam(pam_authenticate);
450 :
451 236 : return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
452 : }
453 :
454 12 : static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
455 : {
456 12 : pwrap_bind_symbol_libpam(pam_chauthtok);
457 :
458 12 : return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
459 : }
460 :
461 0 : static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
462 : {
463 0 : pwrap_bind_symbol_libpam(pam_acct_mgmt);
464 :
465 0 : return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
466 : }
467 :
468 52 : static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
469 : {
470 52 : pwrap_bind_symbol_libpam(pam_putenv);
471 :
472 52 : return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
473 : }
474 :
475 0 : static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
476 : {
477 0 : pwrap_bind_symbol_libpam(pam_getenv);
478 :
479 0 : return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
480 : }
481 :
482 0 : static char **libpam_pam_getenvlist(pam_handle_t *pamh)
483 : {
484 0 : pwrap_bind_symbol_libpam(pam_getenvlist);
485 :
486 0 : return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
487 : }
488 :
489 0 : static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
490 : {
491 0 : pwrap_bind_symbol_libpam(pam_open_session);
492 :
493 0 : return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
494 : }
495 :
496 0 : static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
497 : {
498 0 : pwrap_bind_symbol_libpam(pam_close_session);
499 :
500 0 : return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
501 : }
502 :
503 0 : static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
504 : {
505 0 : pwrap_bind_symbol_libpam(pam_setcred);
506 :
507 0 : return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
508 : }
509 :
510 6044 : static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
511 : {
512 6044 : pwrap_bind_symbol_libpam(pam_get_item);
513 :
514 6044 : return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
515 : }
516 :
517 936 : static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
518 : {
519 936 : pwrap_bind_symbol_libpam(pam_set_item);
520 :
521 936 : return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
522 : }
523 :
524 3664 : static int libpam_pam_get_data(const pam_handle_t *pamh,
525 : const char *module_data_name,
526 : const void **data)
527 : {
528 3664 : pwrap_bind_symbol_libpam(pam_get_data);
529 :
530 3664 : return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
531 : module_data_name,
532 : data);
533 : }
534 :
535 752 : static int libpam_pam_set_data(pam_handle_t *pamh,
536 : const char *module_data_name,
537 : void *data,
538 : void (*cleanup)(pam_handle_t *pamh,
539 : void *data,
540 : int error_status))
541 : {
542 752 : pwrap_bind_symbol_libpam(pam_set_data);
543 :
544 752 : return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
545 : module_data_name,
546 : data,
547 : cleanup);
548 : }
549 :
550 0 : static int libpam_pam_vprompt(pam_handle_t *pamh,
551 : int style,
552 : char **response,
553 : const char *fmt,
554 : va_list args)
555 : {
556 0 : pwrap_bind_symbol_libpam(pam_vprompt);
557 :
558 0 : return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
559 : style,
560 : response,
561 : fmt,
562 : args);
563 : }
564 :
565 : #ifdef HAVE_PAM_STRERROR_CONST
566 : static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
567 : #else
568 0 : static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
569 : #endif
570 : {
571 0 : pwrap_bind_symbol_libpam(pam_strerror);
572 :
573 0 : return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
574 : }
575 :
576 : #ifdef HAVE_PAM_VSYSLOG
577 0 : static void libpam_pam_vsyslog(const pam_handle_t *pamh,
578 : int priority,
579 : const char *fmt,
580 : va_list args)
581 : {
582 0 : pwrap_bind_symbol_libpam(pam_vsyslog);
583 :
584 0 : pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
585 : priority,
586 : fmt,
587 : args);
588 0 : }
589 : #endif /* HAVE_PAM_VSYSLOG */
590 :
591 : /*********************************************************
592 : * PWRAP INIT
593 : *********************************************************/
594 :
595 : #define BUFFER_SIZE 32768
596 :
597 : /* copy file from src to dst, overwrites dst */
598 266 : static int p_copy(const char *src, const char *dst, mode_t mode)
599 : {
600 266 : int srcfd = -1;
601 266 : int dstfd = -1;
602 266 : int rc = -1;
603 : ssize_t bread, bwritten;
604 : struct stat sb;
605 : char buf[BUFFER_SIZE];
606 : int cmp;
607 :
608 266 : cmp = strcmp(src, dst);
609 266 : if (cmp == 0) {
610 0 : return -1;
611 : }
612 :
613 266 : srcfd = open(src, O_RDONLY, 0);
614 266 : if (srcfd < 0) {
615 0 : return -1;
616 : }
617 :
618 266 : if (mode == 0) {
619 0 : rc = fstat(srcfd, &sb);
620 0 : if (rc != 0) {
621 0 : rc = -1;
622 0 : goto out;
623 : }
624 0 : mode = sb.st_mode;
625 : }
626 :
627 266 : dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
628 266 : if (dstfd < 0) {
629 0 : rc = -1;
630 0 : goto out;
631 : }
632 :
633 : for (;;) {
634 662 : bread = read(srcfd, buf, BUFFER_SIZE);
635 532 : if (bread == 0) {
636 : /* done */
637 266 : break;
638 266 : } else if (bread < 0) {
639 0 : errno = EIO;
640 0 : rc = -1;
641 0 : goto out;
642 : }
643 :
644 266 : bwritten = write(dstfd, buf, bread);
645 266 : if (bwritten < 0) {
646 0 : errno = EIO;
647 0 : rc = -1;
648 0 : goto out;
649 : }
650 :
651 266 : if (bread != bwritten) {
652 0 : errno = EFAULT;
653 0 : rc = -1;
654 0 : goto out;
655 : }
656 : }
657 :
658 266 : rc = 0;
659 266 : out:
660 266 : if (srcfd != -1) {
661 266 : close(srcfd);
662 : }
663 266 : if (dstfd != -1) {
664 266 : close(dstfd);
665 : }
666 266 : if (rc < 0) {
667 0 : unlink(dst);
668 : }
669 :
670 266 : return rc;
671 : }
672 :
673 : /* Do not pass any flag if not defined */
674 : #ifndef FTW_ACTIONRETVAL
675 : #define FTW_ACTIONRETVAL 0
676 : #endif
677 :
678 : /* Action return values */
679 : #ifndef FTW_STOP
680 : #define FTW_STOP -1
681 : #endif
682 :
683 : #ifndef FTW_CONTINUE
684 : #define FTW_CONTINUE 0
685 : #endif
686 :
687 : #ifndef FTW_SKIP_SUBTREE
688 : #define FTW_SKIP_SUBTREE 0
689 : #endif
690 :
691 532 : static int copy_ftw(const char *fpath,
692 : const struct stat *sb,
693 : int typeflag,
694 : struct FTW *ftwbuf)
695 : {
696 : int rc;
697 : char buf[BUFFER_SIZE];
698 :
699 532 : switch (typeflag) {
700 266 : case FTW_D:
701 : case FTW_DNR:
702 : /* We want to copy the directories from this directory */
703 266 : if (ftwbuf->level == 0) {
704 266 : return FTW_CONTINUE;
705 : }
706 0 : return FTW_SKIP_SUBTREE;
707 266 : case FTW_F:
708 266 : break;
709 0 : default:
710 0 : return FTW_CONTINUE;
711 : }
712 :
713 266 : rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
714 266 : if (rc >= BUFFER_SIZE) {
715 0 : return FTW_STOP;
716 : }
717 :
718 266 : PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
719 266 : rc = p_copy(fpath, buf, sb->st_mode);
720 266 : if (rc != 0) {
721 0 : return FTW_STOP;
722 : }
723 :
724 266 : return FTW_CONTINUE;
725 : }
726 :
727 266 : static int copy_confdir(const char *src)
728 : {
729 : int rc;
730 :
731 266 : PWRAP_LOG(PWRAP_LOG_DEBUG,
732 : "Copy config files from %s to %s",
733 : src,
734 : pwrap.config_dir);
735 266 : rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
736 266 : if (rc != 0) {
737 0 : return -1;
738 : }
739 :
740 266 : return 0;
741 : }
742 :
743 : static int p_rmdirs(const char *path);
744 :
745 0 : static void pwrap_clean_stale_dirs(const char *dir)
746 0 : {
747 0 : size_t len = strlen(dir);
748 0 : char pidfile[len + 5];
749 : ssize_t rc;
750 0 : char buf[8] = {0};
751 : long int tmp;
752 : pid_t pid;
753 : int fd;
754 :
755 0 : snprintf(pidfile,
756 : sizeof(pidfile),
757 : "%s/pid",
758 : dir);
759 :
760 : /* read the pidfile */
761 0 : fd = open(pidfile, O_RDONLY);
762 0 : if (fd < 0) {
763 0 : if (errno == ENOENT) {
764 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
765 : "pidfile %s missing, nothing to do\n",
766 : pidfile);
767 : } else {
768 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
769 : "Failed to open pidfile %s - error: %s",
770 : pidfile, strerror(errno));
771 : }
772 0 : return;
773 : }
774 :
775 0 : rc = read(fd, buf, sizeof(buf));
776 0 : close(fd);
777 0 : if (rc < 0) {
778 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
779 : "Failed to read pidfile %s - error: %s",
780 : pidfile, strerror(errno));
781 0 : return;
782 : }
783 :
784 0 : buf[sizeof(buf) - 1] = '\0';
785 :
786 0 : tmp = strtol(buf, NULL, 10);
787 0 : if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
788 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
789 : "Failed to parse pid, buf=%s",
790 : buf);
791 0 : return;
792 : }
793 :
794 0 : pid = (pid_t)(tmp & 0xFFFF);
795 :
796 0 : rc = kill(pid, 0);
797 0 : if (rc == -1) {
798 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
799 : "Remove stale pam_wrapper dir: %s",
800 : dir);
801 0 : p_rmdirs(dir);
802 : }
803 :
804 0 : return;
805 : }
806 :
807 : #ifdef HAVE_PAM_START_CONFDIR
808 278 : static void pwrap_init(void)
809 : {
810 278 : char tmp_config_dir[] = "/tmp/pam.X";
811 278 : size_t len = strlen(tmp_config_dir);
812 : const char *env;
813 : struct stat sb;
814 : int rc;
815 : unsigned i;
816 : ssize_t ret;
817 : FILE *pidfile;
818 278 : char pidfile_path[1024] = { 0 };
819 : char letter;
820 :
821 278 : if (!pam_wrapper_enabled()) {
822 142 : return;
823 : }
824 :
825 260 : if (pwrap.initialised) {
826 124 : return;
827 : }
828 :
829 : /*
830 : * The name is selected to match/replace /etc/pam.d
831 : * We start from a random alphanum trying letters until
832 : * an available directory is found.
833 : */
834 136 : letter = 48 + (getpid() % 70);
835 231 : for (i = 0; i < 127; i++) {
836 231 : if (isalpha(letter) || isdigit(letter)) {
837 136 : tmp_config_dir[len - 1] = letter;
838 :
839 136 : rc = lstat(tmp_config_dir, &sb);
840 136 : if (rc == 0) {
841 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
842 : "Check if pam_wrapper dir %s is a "
843 : "stale directory",
844 : tmp_config_dir);
845 0 : pwrap_clean_stale_dirs(tmp_config_dir);
846 136 : } else if (rc < 0) {
847 136 : if (errno != ENOENT) {
848 0 : continue;
849 : }
850 136 : break; /* found */
851 : }
852 : }
853 :
854 95 : letter++;
855 95 : letter %= 127;
856 : }
857 :
858 136 : if (i == 127) {
859 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
860 : "Failed to find a possible path to create "
861 : "pam_wrapper config dir: %s",
862 : tmp_config_dir);
863 0 : exit(1);
864 : }
865 :
866 136 : PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
867 :
868 136 : pwrap.config_dir = strdup(tmp_config_dir);
869 136 : if (pwrap.config_dir == NULL) {
870 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
871 : "No memory");
872 0 : exit(1);
873 : }
874 136 : PWRAP_LOG(PWRAP_LOG_TRACE,
875 : "pam_wrapper config dir: %s",
876 : tmp_config_dir);
877 :
878 136 : rc = mkdir(pwrap.config_dir, 0755);
879 136 : if (rc != 0) {
880 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
881 : "Failed to create pam_wrapper config dir: %s - %s",
882 : tmp_config_dir, strerror(errno));
883 : }
884 :
885 : /* Create file with the PID of the the process */
886 136 : ret = snprintf(pidfile_path, sizeof(pidfile_path),
887 : "%s/pid", pwrap.config_dir);
888 136 : if (ret < 0) {
889 0 : p_rmdirs(pwrap.config_dir);
890 0 : exit(1);
891 : }
892 :
893 136 : pidfile = fopen(pidfile_path, "w");
894 136 : if (pidfile == NULL) {
895 0 : p_rmdirs(pwrap.config_dir);
896 0 : exit(1);
897 : }
898 :
899 136 : rc = fprintf(pidfile, "%d", getpid());
900 136 : fclose(pidfile);
901 136 : if (rc <= 0) {
902 0 : p_rmdirs(pwrap.config_dir);
903 0 : exit(1);
904 : }
905 :
906 136 : pwrap.libpam_so = strdup(PAM_LIBRARY);
907 136 : if (pwrap.libpam_so == NULL) {
908 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
909 0 : p_rmdirs(pwrap.config_dir);
910 0 : exit(1);
911 : }
912 :
913 136 : PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
914 :
915 136 : pwrap.initialised = true;
916 :
917 136 : env = getenv("PAM_WRAPPER_SERVICE_DIR");
918 136 : if (env == NULL) {
919 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
920 0 : p_rmdirs(pwrap.config_dir);
921 0 : exit(1);
922 : }
923 :
924 136 : rc = copy_confdir(env);
925 136 : if (rc != 0) {
926 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
927 0 : p_rmdirs(pwrap.config_dir);
928 0 : exit(1);
929 : }
930 :
931 136 : setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
932 :
933 136 : PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
934 : }
935 :
936 : #else /* HAVE_PAM_START_CONFDIR */
937 :
938 : #ifdef HAVE_PAM_MODUTIL_SEARCH_KEY
939 : /*
940 : * This is needed to workaround Tumbleweed which packages a libpam git version.
941 : */
942 : static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
943 : {
944 : #define PSO_COPY_READ_SIZE 16
945 : int srcfd = -1;
946 : int dstfd = -1;
947 : int rc = -1;
948 : ssize_t bread, bwritten;
949 : struct stat sb;
950 : char buf[PSO_COPY_READ_SIZE + 1];
951 : size_t pso_copy_read_size = PSO_COPY_READ_SIZE;
952 : int cmp;
953 : size_t to_read;
954 : bool found_slash;
955 :
956 : cmp = strcmp(src, dst);
957 : if (cmp == 0) {
958 : return -1;
959 : }
960 :
961 : srcfd = open(src, O_RDONLY, 0);
962 : if (srcfd < 0) {
963 : return -1;
964 : }
965 :
966 : if (mode == 0) {
967 : rc = fstat(srcfd, &sb);
968 : if (rc != 0) {
969 : rc = -1;
970 : goto out;
971 : }
972 : mode = sb.st_mode;
973 : }
974 :
975 : dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
976 : if (dstfd < 0) {
977 : rc = -1;
978 : goto out;
979 : }
980 :
981 : found_slash = false;
982 : to_read = 1;
983 :
984 : for (;;) {
985 : bread = read(srcfd, buf, to_read);
986 : if (bread == 0) {
987 : /* done */
988 : break;
989 : } else if (bread < 0) {
990 : errno = EIO;
991 : rc = -1;
992 : goto out;
993 : }
994 :
995 : to_read = 1;
996 : if (!found_slash && buf[0] == '/') {
997 : found_slash = true;
998 : to_read = pso_copy_read_size;
999 : }
1000 :
1001 : if (found_slash && bread == PSO_COPY_READ_SIZE) {
1002 : cmp = memcmp(buf, "usr/etc/pam.d/%s", 16);
1003 : if (cmp == 0) {
1004 : char tmp[16] = {0};
1005 :
1006 : snprintf(tmp, sizeof(tmp), "%s/%%s", pdir + 1);
1007 :
1008 : memcpy(buf, tmp, 12);
1009 : memset(&buf[12], '\0', 4);
1010 :
1011 : /*
1012 : * If we found this string, we need to reduce
1013 : * the read size to not miss, the next one.
1014 : */
1015 : pso_copy_read_size = 13;
1016 : } else {
1017 : cmp = memcmp(buf, "usr/etc/pam.d", 13);
1018 : if (cmp == 0) {
1019 : memcpy(buf, pdir + 1, 9);
1020 : memset(&buf[9], '\0', 4);
1021 : } else {
1022 : cmp = memcmp(buf, "etc/pam.d", 9);
1023 : if (cmp == 0) {
1024 : memcpy(buf, pdir + 1, 9);
1025 : }
1026 : }
1027 : }
1028 : found_slash = false;
1029 : }
1030 :
1031 : bwritten = write(dstfd, buf, bread);
1032 : if (bwritten < 0) {
1033 : errno = EIO;
1034 : rc = -1;
1035 : goto out;
1036 : }
1037 :
1038 : if (bread != bwritten) {
1039 : errno = EFAULT;
1040 : rc = -1;
1041 : goto out;
1042 : }
1043 : }
1044 :
1045 : rc = 0;
1046 : out:
1047 : if (srcfd != -1) {
1048 : close(srcfd);
1049 : }
1050 : if (dstfd != -1) {
1051 : close(dstfd);
1052 : }
1053 : if (rc < 0) {
1054 : unlink(dst);
1055 : }
1056 :
1057 : return rc;
1058 : #undef PSO_COPY_READ_SIZE
1059 : }
1060 : #else /* HAVE_PAM_MODUTIL_SEARCH_KEY */
1061 :
1062 130 : static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
1063 : {
1064 : #define PSO_COPY_READ_SIZE 9
1065 130 : int srcfd = -1;
1066 130 : int dstfd = -1;
1067 130 : int rc = -1;
1068 : ssize_t bread, bwritten;
1069 : struct stat sb;
1070 : char buf[PSO_COPY_READ_SIZE + 1];
1071 : int cmp;
1072 : size_t to_read;
1073 : bool found_slash;
1074 :
1075 130 : cmp = strcmp(src, dst);
1076 130 : if (cmp == 0) {
1077 0 : return -1;
1078 : }
1079 :
1080 130 : srcfd = open(src, O_RDONLY, 0);
1081 130 : if (srcfd < 0) {
1082 0 : return -1;
1083 : }
1084 :
1085 130 : if (mode == 0) {
1086 0 : rc = fstat(srcfd, &sb);
1087 0 : if (rc != 0) {
1088 0 : rc = -1;
1089 0 : goto out;
1090 : }
1091 0 : mode = sb.st_mode;
1092 : }
1093 :
1094 130 : dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
1095 130 : if (dstfd < 0) {
1096 0 : rc = -1;
1097 0 : goto out;
1098 : }
1099 :
1100 130 : found_slash = false;
1101 130 : to_read = 1;
1102 :
1103 : for (;;) {
1104 14416610 : bread = read(srcfd, buf, to_read);
1105 7208370 : if (bread == 0) {
1106 : /* done */
1107 130 : break;
1108 7208240 : } else if (bread < 0) {
1109 0 : errno = EIO;
1110 0 : rc = -1;
1111 0 : goto out;
1112 : }
1113 :
1114 7208240 : to_read = 1;
1115 7208240 : if (!found_slash && buf[0] == '/') {
1116 6500 : found_slash = true;
1117 6500 : to_read = PSO_COPY_READ_SIZE;
1118 : }
1119 :
1120 7208240 : if (found_slash && bread == PSO_COPY_READ_SIZE) {
1121 6500 : cmp = memcmp(buf, "etc/pam.d", PSO_COPY_READ_SIZE);
1122 6500 : if (cmp == 0) {
1123 390 : memcpy(buf, pdir + 1, PSO_COPY_READ_SIZE);
1124 : }
1125 6500 : found_slash = false;
1126 : }
1127 :
1128 7208240 : bwritten = write(dstfd, buf, bread);
1129 7208240 : if (bwritten < 0) {
1130 0 : errno = EIO;
1131 0 : rc = -1;
1132 0 : goto out;
1133 : }
1134 :
1135 7208240 : if (bread != bwritten) {
1136 0 : errno = EFAULT;
1137 0 : rc = -1;
1138 0 : goto out;
1139 : }
1140 : }
1141 :
1142 130 : rc = 0;
1143 130 : out:
1144 130 : if (srcfd != -1) {
1145 130 : close(srcfd);
1146 : }
1147 130 : if (dstfd != -1) {
1148 130 : close(dstfd);
1149 : }
1150 130 : if (rc < 0) {
1151 0 : unlink(dst);
1152 : }
1153 :
1154 130 : return rc;
1155 : #undef PSO_COPY_READ_SIZE
1156 : }
1157 : #endif /* HAVE_PAM_MODUTIL_SEARCH_KEY */
1158 :
1159 278 : static void pwrap_init(void)
1160 : {
1161 278 : char tmp_config_dir[] = "/tmp/pam.X";
1162 278 : size_t len = strlen(tmp_config_dir);
1163 : const char *env;
1164 : struct stat sb;
1165 : int rc;
1166 : unsigned i;
1167 278 : char pam_library[128] = { 0 };
1168 278 : char libpam_path[1024] = { 0 };
1169 : ssize_t ret;
1170 : FILE *pidfile;
1171 278 : char pidfile_path[1024] = { 0 };
1172 : char letter;
1173 :
1174 278 : if (!pam_wrapper_enabled()) {
1175 172 : return;
1176 : }
1177 :
1178 254 : if (pwrap.initialised) {
1179 124 : return;
1180 : }
1181 :
1182 : /*
1183 : * The name is selected to match/replace /etc/pam.d
1184 : * We start from a random alphanum trying letters until
1185 : * an available directory is found.
1186 : */
1187 130 : letter = 48 + (getpid() % 70);
1188 237 : for (i = 0; i < 127; i++) {
1189 237 : if (isalpha(letter) || isdigit(letter)) {
1190 130 : tmp_config_dir[len - 1] = letter;
1191 :
1192 130 : rc = lstat(tmp_config_dir, &sb);
1193 130 : if (rc == 0) {
1194 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1195 : "Check if pam_wrapper dir %s is a "
1196 : "stale directory",
1197 : tmp_config_dir);
1198 0 : pwrap_clean_stale_dirs(tmp_config_dir);
1199 130 : } else if (rc < 0) {
1200 130 : if (errno != ENOENT) {
1201 0 : continue;
1202 : }
1203 130 : break; /* found */
1204 : }
1205 : }
1206 :
1207 107 : letter++;
1208 107 : letter %= 127;
1209 : }
1210 :
1211 130 : if (i == 127) {
1212 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1213 : "Failed to find a possible path to create "
1214 : "pam_wrapper config dir: %s",
1215 : tmp_config_dir);
1216 0 : exit(1);
1217 : }
1218 :
1219 130 : PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
1220 :
1221 130 : pwrap.config_dir = strdup(tmp_config_dir);
1222 130 : if (pwrap.config_dir == NULL) {
1223 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1224 : "No memory");
1225 0 : exit(1);
1226 : }
1227 130 : PWRAP_LOG(PWRAP_LOG_TRACE,
1228 : "pam_wrapper config dir: %s",
1229 : tmp_config_dir);
1230 :
1231 130 : rc = mkdir(pwrap.config_dir, 0755);
1232 130 : if (rc != 0) {
1233 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1234 : "Failed to create pam_wrapper config dir: %s - %s",
1235 : tmp_config_dir, strerror(errno));
1236 : }
1237 :
1238 : /* Create file with the PID of the the process */
1239 130 : ret = snprintf(pidfile_path, sizeof(pidfile_path),
1240 : "%s/pid", pwrap.config_dir);
1241 130 : if (ret < 0) {
1242 0 : p_rmdirs(pwrap.config_dir);
1243 0 : exit(1);
1244 : }
1245 :
1246 130 : pidfile = fopen(pidfile_path, "w");
1247 130 : if (pidfile == NULL) {
1248 0 : p_rmdirs(pwrap.config_dir);
1249 0 : exit(1);
1250 : }
1251 :
1252 130 : rc = fprintf(pidfile, "%d", getpid());
1253 130 : fclose(pidfile);
1254 130 : if (rc <= 0) {
1255 0 : p_rmdirs(pwrap.config_dir);
1256 0 : exit(1);
1257 : }
1258 :
1259 : /* create lib subdirectory */
1260 130 : snprintf(libpam_path,
1261 : sizeof(libpam_path),
1262 : "%s/lib",
1263 : pwrap.config_dir);
1264 :
1265 130 : rc = mkdir(libpam_path, 0755);
1266 130 : if (rc != 0) {
1267 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1268 : "Failed to create path for libpam: %s - %s",
1269 : tmp_config_dir, strerror(errno));
1270 0 : p_rmdirs(pwrap.config_dir);
1271 0 : exit(1);
1272 : }
1273 :
1274 130 : snprintf(libpam_path,
1275 : sizeof(libpam_path),
1276 : "%s/lib/%s",
1277 : pwrap.config_dir,
1278 : LIBPAM_NAME);
1279 :
1280 130 : pwrap.libpam_so = strdup(libpam_path);
1281 130 : if (pwrap.libpam_so == NULL) {
1282 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
1283 0 : p_rmdirs(pwrap.config_dir);
1284 0 : exit(1);
1285 : }
1286 :
1287 : /* copy libpam.so.0 */
1288 130 : snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
1289 130 : PWRAP_LOG(PWRAP_LOG_TRACE,
1290 : "PAM path: %s",
1291 : libpam_path);
1292 :
1293 130 : ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
1294 130 : PWRAP_LOG(PWRAP_LOG_TRACE,
1295 : "PAM library: %s",
1296 : pam_library);
1297 130 : if (ret <= 0) {
1298 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
1299 0 : p_rmdirs(pwrap.config_dir);
1300 0 : exit(1);
1301 : }
1302 :
1303 130 : if (pam_library[0] == '/') {
1304 130 : snprintf(libpam_path,
1305 : sizeof(libpam_path),
1306 : "%s",
1307 : pam_library);
1308 : } else {
1309 0 : char libpam_path_cp[1024] = {0};
1310 0 : char *dname = NULL;
1311 :
1312 0 : snprintf(libpam_path_cp,
1313 : sizeof(libpam_path_cp),
1314 : "%s",
1315 : libpam_path);
1316 :
1317 0 : dname = dirname(libpam_path_cp);
1318 0 : if (dname == NULL) {
1319 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1320 : "No directory component in %s", libpam_path);
1321 0 : p_rmdirs(pwrap.config_dir);
1322 0 : exit(1);
1323 : }
1324 :
1325 0 : snprintf(libpam_path,
1326 : sizeof(libpam_path),
1327 : "%s/%s",
1328 : dname,
1329 : pam_library);
1330 : }
1331 130 : PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
1332 :
1333 130 : PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
1334 130 : rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
1335 130 : if (rc != 0) {
1336 0 : PWRAP_LOG(PWRAP_LOG_ERROR,
1337 : "Failed to copy %s - error: %s",
1338 : LIBPAM_NAME,
1339 : strerror(errno));
1340 0 : p_rmdirs(pwrap.config_dir);
1341 0 : exit(1);
1342 : }
1343 :
1344 130 : PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
1345 :
1346 130 : pwrap.initialised = true;
1347 :
1348 130 : env = getenv("PAM_WRAPPER_SERVICE_DIR");
1349 130 : if (env == NULL) {
1350 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
1351 0 : p_rmdirs(pwrap.config_dir);
1352 0 : exit(1);
1353 : }
1354 :
1355 130 : rc = copy_confdir(env);
1356 130 : if (rc != 0) {
1357 0 : PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
1358 0 : p_rmdirs(pwrap.config_dir);
1359 0 : exit(1);
1360 : }
1361 :
1362 130 : setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
1363 :
1364 130 : PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
1365 : }
1366 : #endif /* HAVE_PAM_START_CONFDIR */
1367 :
1368 556 : bool pam_wrapper_enabled(void)
1369 : {
1370 : const char *env;
1371 :
1372 556 : pwrap.enabled = false;
1373 :
1374 556 : env = getenv("PAM_WRAPPER");
1375 556 : if (env != NULL && env[0] == '1') {
1376 514 : pwrap.enabled = true;
1377 : }
1378 :
1379 556 : if (pwrap.enabled) {
1380 514 : pwrap.enabled = false;
1381 :
1382 514 : env = getenv("PAM_WRAPPER_SERVICE_DIR");
1383 514 : if (env != NULL && env[0] != '\0') {
1384 514 : pwrap.enabled = true;
1385 : }
1386 : }
1387 :
1388 556 : return pwrap.enabled;
1389 : }
1390 :
1391 : #ifdef HAVE_OPENPAM
1392 : static int pwrap_openpam_start(const char *service_name,
1393 : const char *user,
1394 : const struct pam_conv *pam_conversation,
1395 : pam_handle_t **pamh)
1396 : {
1397 : int rv;
1398 : char fullpath[1024];
1399 :
1400 : rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1401 : if (rv != PAM_SUCCESS) {
1402 : PWRAP_LOG(PWRAP_LOG_ERROR,
1403 : "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1404 : return rv;
1405 : }
1406 :
1407 : rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1408 : if (rv != PAM_SUCCESS) {
1409 : PWRAP_LOG(PWRAP_LOG_ERROR,
1410 : "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1411 : return rv;
1412 : }
1413 :
1414 : rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1415 : if (rv != PAM_SUCCESS) {
1416 : PWRAP_LOG(PWRAP_LOG_ERROR,
1417 : "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1418 : return rv;
1419 : }
1420 :
1421 : rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1422 : if (rv != PAM_SUCCESS) {
1423 : PWRAP_LOG(PWRAP_LOG_ERROR,
1424 : "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1425 : return rv;
1426 : }
1427 :
1428 : snprintf(fullpath,
1429 : sizeof(fullpath),
1430 : "%s/%s",
1431 : pwrap.config_dir,
1432 : service_name);
1433 :
1434 : return libpam_pam_start(fullpath,
1435 : user,
1436 : pam_conversation,
1437 : pamh);
1438 : }
1439 : #endif
1440 :
1441 248 : static int pwrap_pam_start(const char *service_name,
1442 : const char *user,
1443 : const struct pam_conv *pam_conversation,
1444 : pam_handle_t **pamh)
1445 : {
1446 : int rc;
1447 :
1448 248 : pwrap_init();
1449 :
1450 248 : PWRAP_LOG(PWRAP_LOG_TRACE,
1451 : "pam_start service=%s, user=%s",
1452 : service_name,
1453 : user);
1454 :
1455 : #if defined(HAVE_OPENPAM)
1456 : rc = pwrap_openpam_start(service_name,
1457 : user,
1458 : pam_conversation,
1459 : pamh);
1460 : #elif defined (HAVE_PAM_START_CONFDIR)
1461 124 : rc = libpam_pam_start_confdir(service_name,
1462 : user,
1463 : pam_conversation,
1464 124 : pwrap.config_dir,
1465 : pamh);
1466 : #else
1467 124 : rc = libpam_pam_start(service_name,
1468 : user,
1469 : pam_conversation,
1470 : pamh);
1471 : #endif
1472 248 : PWRAP_LOG(PWRAP_LOG_TRACE, "pam_start rc=%d", rc);
1473 :
1474 248 : return rc;
1475 : }
1476 :
1477 :
1478 : int pam_start(const char *service_name,
1479 : const char *user,
1480 : const struct pam_conv *pam_conversation,
1481 : pam_handle_t **pamh)
1482 : {
1483 248 : return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1484 : }
1485 :
1486 248 : static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1487 : {
1488 248 : PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1489 248 : return libpam_pam_end(pamh, pam_status);
1490 : }
1491 :
1492 :
1493 : int pam_end(pam_handle_t *pamh, int pam_status)
1494 : {
1495 248 : return pwrap_pam_end(pamh, pam_status);
1496 : }
1497 :
1498 236 : static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1499 : {
1500 236 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1501 236 : return libpam_pam_authenticate(pamh, flags);
1502 : }
1503 :
1504 : int pam_authenticate(pam_handle_t *pamh, int flags)
1505 : {
1506 236 : return pwrap_pam_authenticate(pamh, flags);
1507 : }
1508 :
1509 12 : static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1510 : {
1511 12 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1512 12 : return libpam_pam_chauthtok(pamh, flags);
1513 : }
1514 :
1515 : int pam_chauthtok(pam_handle_t *pamh, int flags)
1516 : {
1517 12 : return pwrap_pam_chauthtok(pamh, flags);
1518 : }
1519 :
1520 0 : static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1521 : {
1522 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1523 0 : return libpam_pam_acct_mgmt(pamh, flags);
1524 : }
1525 :
1526 : int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1527 : {
1528 0 : return pwrap_pam_acct_mgmt(pamh, flags);
1529 : }
1530 :
1531 52 : static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1532 : {
1533 52 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1534 52 : return libpam_pam_putenv(pamh, name_value);
1535 : }
1536 :
1537 : int pam_putenv(pam_handle_t *pamh, const char *name_value)
1538 : {
1539 52 : return pwrap_pam_putenv(pamh, name_value);
1540 : }
1541 :
1542 0 : static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1543 : {
1544 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1545 0 : return libpam_pam_getenv(pamh, name);
1546 : }
1547 :
1548 : const char *pam_getenv(pam_handle_t *pamh, const char *name)
1549 : {
1550 0 : return pwrap_pam_getenv(pamh, name);
1551 : }
1552 :
1553 0 : static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1554 : {
1555 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1556 0 : return libpam_pam_getenvlist(pamh);
1557 : }
1558 :
1559 : char **pam_getenvlist(pam_handle_t *pamh)
1560 : {
1561 0 : return pwrap_pam_getenvlist(pamh);
1562 : }
1563 :
1564 0 : static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1565 : {
1566 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1567 0 : return libpam_pam_open_session(pamh, flags);
1568 : }
1569 :
1570 : int pam_open_session(pam_handle_t *pamh, int flags)
1571 : {
1572 0 : return pwrap_pam_open_session(pamh, flags);
1573 : }
1574 :
1575 0 : static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1576 : {
1577 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1578 0 : return libpam_pam_close_session(pamh, flags);
1579 : }
1580 :
1581 : int pam_close_session(pam_handle_t *pamh, int flags)
1582 : {
1583 0 : return pwrap_pam_close_session(pamh, flags);
1584 : }
1585 :
1586 0 : static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1587 : {
1588 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1589 0 : return libpam_pam_setcred(pamh, flags);
1590 : }
1591 :
1592 : int pam_setcred(pam_handle_t *pamh, int flags)
1593 : {
1594 0 : return pwrap_pam_setcred(pamh, flags);
1595 : }
1596 :
1597 780 : static const char *pwrap_get_service(const char *libpam_service)
1598 : {
1599 : #ifdef HAVE_OPENPAM
1600 : const char *service_name;
1601 :
1602 : PWRAP_LOG(PWRAP_LOG_TRACE,
1603 : "internal PAM_SERVICE=%s", libpam_service);
1604 : service_name = strrchr(libpam_service, '/');
1605 : if (service_name != NULL && service_name[0] == '/') {
1606 : service_name++;
1607 : }
1608 : PWRAP_LOG(PWRAP_LOG_TRACE,
1609 : "PAM_SERVICE=%s", service_name);
1610 : return service_name;
1611 : #else
1612 780 : return libpam_service;
1613 : #endif
1614 : }
1615 :
1616 6044 : static int pwrap_pam_get_item(const pam_handle_t *pamh,
1617 : int item_type,
1618 : const void **item)
1619 : {
1620 : int rc;
1621 : const char *svc;
1622 :
1623 6044 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1624 :
1625 6044 : rc = libpam_pam_get_item(pamh, item_type, item);
1626 :
1627 6044 : if (rc == PAM_SUCCESS) {
1628 6044 : switch(item_type) {
1629 520 : case PAM_USER:
1630 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1631 : "pwrap_get_item PAM_USER=%s",
1632 : (const char *)*item);
1633 520 : break;
1634 780 : case PAM_SERVICE:
1635 780 : svc = pwrap_get_service((const char *) *item);
1636 :
1637 780 : PWRAP_LOG(PWRAP_LOG_TRACE,
1638 : "pwrap_get_item PAM_SERVICE=%s",
1639 : svc);
1640 780 : *item = svc;
1641 780 : break;
1642 520 : case PAM_USER_PROMPT:
1643 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1644 : "pwrap_get_item PAM_USER_PROMPT=%s",
1645 : (const char *)*item);
1646 520 : break;
1647 520 : case PAM_TTY:
1648 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1649 : "pwrap_get_item PAM_TTY=%s",
1650 : (const char *)*item);
1651 520 : break;
1652 520 : case PAM_RUSER:
1653 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1654 : "pwrap_get_item PAM_RUSER=%s",
1655 : (const char *)*item);
1656 520 : break;
1657 520 : case PAM_RHOST:
1658 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1659 : "pwrap_get_item PAM_RHOST=%s",
1660 : (const char *)*item);
1661 520 : break;
1662 768 : case PAM_AUTHTOK:
1663 768 : PWRAP_LOG(PWRAP_LOG_TRACE,
1664 : "pwrap_get_item PAM_AUTHTOK=%s",
1665 : (const char *)*item);
1666 768 : break;
1667 544 : case PAM_OLDAUTHTOK:
1668 544 : PWRAP_LOG(PWRAP_LOG_TRACE,
1669 : "pwrap_get_item PAM_OLDAUTHTOK=%s",
1670 : (const char *)*item);
1671 544 : break;
1672 832 : case PAM_CONV:
1673 832 : PWRAP_LOG(PWRAP_LOG_TRACE,
1674 : "pwrap_get_item PAM_CONV=%p",
1675 : (const void *)*item);
1676 832 : break;
1677 520 : default:
1678 520 : PWRAP_LOG(PWRAP_LOG_TRACE,
1679 : "pwrap_get_item item_type=%d item=%p",
1680 : item_type, (const void *)*item);
1681 520 : break;
1682 : }
1683 : } else {
1684 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1685 : }
1686 :
1687 6044 : return rc;
1688 : }
1689 :
1690 : int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1691 : {
1692 6044 : return pwrap_pam_get_item(pamh, item_type, item);
1693 : }
1694 :
1695 936 : static int pwrap_pam_set_item(pam_handle_t *pamh,
1696 : int item_type,
1697 : const void *item)
1698 : {
1699 : int rc;
1700 :
1701 936 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1702 :
1703 936 : rc = libpam_pam_set_item(pamh, item_type, item);
1704 936 : if (rc == PAM_SUCCESS) {
1705 936 : switch(item_type) {
1706 160 : case PAM_USER:
1707 160 : PWRAP_LOG(PWRAP_LOG_TRACE,
1708 : "pwrap_set_item PAM_USER=%s",
1709 : (const char *)item);
1710 160 : break;
1711 0 : case PAM_SERVICE:
1712 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1713 : "pwrap_set_item PAM_SERVICE=%s",
1714 : (const char *)item);
1715 0 : break;
1716 0 : case PAM_USER_PROMPT:
1717 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1718 : "pwrap_set_item PAM_USER_PROMPT=%s",
1719 : (const char *)item);
1720 0 : break;
1721 0 : case PAM_TTY:
1722 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1723 : "pwrap_set_item PAM_TTY=%s",
1724 : (const char *)item);
1725 0 : break;
1726 0 : case PAM_RUSER:
1727 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1728 : "pwrap_set_item PAM_RUSER=%s",
1729 : (const char *)item);
1730 0 : break;
1731 0 : case PAM_RHOST:
1732 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1733 : "pwrap_set_item PAM_RHOST=%s",
1734 : (const char *)item);
1735 0 : break;
1736 504 : case PAM_AUTHTOK:
1737 504 : PWRAP_LOG(PWRAP_LOG_TRACE,
1738 : "pwrap_set_item PAM_AUTHTOK=%s",
1739 : (const char *)item);
1740 504 : break;
1741 272 : case PAM_OLDAUTHTOK:
1742 272 : PWRAP_LOG(PWRAP_LOG_TRACE,
1743 : "pwrap_set_item PAM_OLDAUTHTOK=%s",
1744 : (const char *)item);
1745 272 : break;
1746 0 : case PAM_CONV:
1747 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1748 : "pwrap_set_item PAM_CONV=%p",
1749 : item);
1750 0 : break;
1751 0 : default:
1752 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
1753 : "pwrap_set_item item_type=%d item=%p",
1754 : item_type, item);
1755 0 : break;
1756 : }
1757 : } else {
1758 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1759 : }
1760 :
1761 936 : return rc;
1762 : }
1763 :
1764 : int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1765 : {
1766 936 : return pwrap_pam_set_item(pamh, item_type, item);
1767 : }
1768 :
1769 3664 : static int pwrap_pam_get_data(const pam_handle_t *pamh,
1770 : const char *module_data_name,
1771 : const void **data)
1772 : {
1773 3664 : PWRAP_LOG(PWRAP_LOG_TRACE,
1774 : "pwrap_get_data module_data_name=%s", module_data_name);
1775 3664 : return libpam_pam_get_data(pamh, module_data_name, data);
1776 : }
1777 :
1778 : int pam_get_data(const pam_handle_t *pamh,
1779 : const char *module_data_name,
1780 : const void **data)
1781 : {
1782 3664 : return pwrap_pam_get_data(pamh, module_data_name, data);
1783 : }
1784 :
1785 752 : static int pwrap_pam_set_data(pam_handle_t *pamh,
1786 : const char *module_data_name,
1787 : void *data,
1788 : void (*cleanup)(pam_handle_t *pamh,
1789 : void *data,
1790 : int error_status))
1791 : {
1792 752 : PWRAP_LOG(PWRAP_LOG_TRACE,
1793 : "pwrap_set_data module_data_name=%s data=%p",
1794 : module_data_name, data);
1795 752 : return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1796 : }
1797 :
1798 : int pam_set_data(pam_handle_t *pamh,
1799 : const char *module_data_name,
1800 : void *data,
1801 : void (*cleanup)(pam_handle_t *pamh,
1802 : void *data,
1803 : int error_status))
1804 : {
1805 752 : return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1806 : }
1807 :
1808 : #ifdef HAVE_PAM_VPROMPT_CONST
1809 : static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1810 : #else
1811 0 : static int pwrap_pam_vprompt(pam_handle_t *pamh,
1812 : #endif
1813 : int style,
1814 : char **response,
1815 : const char *fmt,
1816 : va_list args)
1817 : {
1818 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1819 0 : return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1820 : style,
1821 : response,
1822 : fmt,
1823 : args);
1824 : }
1825 :
1826 : #ifdef HAVE_PAM_VPROMPT_CONST
1827 : int pam_vprompt(const pam_handle_t *pamh,
1828 : int style,
1829 : char **response,
1830 : const char *fmt,
1831 : va_list args)
1832 : #else
1833 : int pam_vprompt(pam_handle_t *pamh,
1834 : int style,
1835 : char **response,
1836 : const char *fmt,
1837 : va_list args)
1838 : #endif
1839 : {
1840 0 : return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1841 : style,
1842 : response,
1843 : fmt,
1844 : args);
1845 : }
1846 :
1847 : #ifdef HAVE_PAM_PROMPT_CONST
1848 : int pam_prompt(const pam_handle_t *pamh,
1849 : int style,
1850 : char **response,
1851 : const char *fmt, ...)
1852 : #else
1853 : int pam_prompt(pam_handle_t *pamh,
1854 : int style,
1855 : char **response,
1856 : const char *fmt, ...)
1857 : #endif
1858 : {
1859 : va_list args;
1860 : int rv;
1861 :
1862 0 : va_start(args, fmt);
1863 0 : rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1864 : style,
1865 : response,
1866 : fmt,
1867 : args);
1868 0 : va_end(args);
1869 :
1870 0 : return rv;
1871 : }
1872 :
1873 : #ifdef HAVE_PAM_STRERROR_CONST
1874 : static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1875 : #else
1876 0 : static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1877 : #endif
1878 : {
1879 : const char *str;
1880 :
1881 0 : pwrap_init();
1882 :
1883 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1884 :
1885 0 : str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1886 : errnum);
1887 :
1888 0 : PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1889 :
1890 0 : return str;
1891 : }
1892 :
1893 : #ifdef HAVE_PAM_STRERROR_CONST
1894 : const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1895 : #else
1896 : const char *pam_strerror(pam_handle_t *pamh, int errnum)
1897 : #endif
1898 : {
1899 0 : return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1900 : errnum);
1901 : }
1902 :
1903 : #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1904 : static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1905 : int priority,
1906 : const char *fmt,
1907 : va_list args) PRINTF_ATTRIBUTE(3, 0);
1908 :
1909 4404 : static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1910 : int priority,
1911 : const char *fmt,
1912 : va_list args)
1913 : {
1914 : const char *d;
1915 4404 : char syslog_str[32] = {0};
1916 4404 : enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1917 :
1918 4404 : PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1919 :
1920 : #ifdef HAVE_PAM_VSYSLOG
1921 4404 : d = getenv("PAM_WRAPPER_USE_SYSLOG");
1922 4404 : if (d != NULL && d[0] == '1') {
1923 0 : libpam_pam_vsyslog(pamh, priority, fmt, args);
1924 0 : return;
1925 : }
1926 : #endif /* HAVE_PAM_VSYSLOG */
1927 :
1928 4404 : switch(priority) {
1929 204 : case 0: /* LOG_EMERG */
1930 : case 1: /* LOG_ALERT */
1931 : case 2: /* LOG_CRIT */
1932 : case 3: /* LOG_ERR */
1933 204 : dbglvl = PWRAP_LOG_ERROR;
1934 204 : break;
1935 76 : case 4: /* LOG_WARN */
1936 76 : dbglvl = PWRAP_LOG_WARN;
1937 76 : break;
1938 4124 : case 5: /* LOG_NOTICE */
1939 : case 6: /* LOG_INFO */
1940 : case 7: /* LOG_DEBUG */
1941 4124 : dbglvl = PWRAP_LOG_DEBUG;
1942 4124 : break;
1943 0 : default:
1944 0 : dbglvl = PWRAP_LOG_TRACE;
1945 0 : break;
1946 : }
1947 :
1948 4404 : snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1949 :
1950 4404 : pwrap_vlog(dbglvl, syslog_str, fmt, args);
1951 : }
1952 : #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1953 :
1954 : #ifdef HAVE_PAM_VSYSLOG
1955 : void pam_vsyslog(const pam_handle_t *pamh,
1956 : int priority,
1957 : const char *fmt,
1958 : va_list args)
1959 : {
1960 4280 : pwrap_pam_vsyslog(pamh, priority, fmt, args);
1961 4280 : }
1962 : #endif
1963 :
1964 : #ifdef HAVE_PAM_SYSLOG
1965 : void pam_syslog(const pam_handle_t *pamh,
1966 : int priority,
1967 : const char *fmt, ...)
1968 : {
1969 : va_list args;
1970 :
1971 124 : va_start(args, fmt);
1972 124 : pwrap_pam_vsyslog(pamh, priority, fmt, args);
1973 124 : va_end(args);
1974 124 : }
1975 : #endif
1976 :
1977 : /* This might be called by pam_end() running with sshd */
1978 : int audit_open(void);
1979 248 : int audit_open(void)
1980 : {
1981 : /*
1982 : * Tell the application that the kernel doesn't
1983 : * have audit compiled in.
1984 : */
1985 248 : errno = EPROTONOSUPPORT;
1986 248 : return -1;
1987 : }
1988 :
1989 : /* Disable BSD auditing */
1990 : int cannot_audit(int x);
1991 0 : int cannot_audit(int x)
1992 : {
1993 : (void) x;
1994 :
1995 0 : return 1;
1996 : }
1997 :
1998 : /****************************
1999 : * CONSTRUCTOR
2000 : ***************************/
2001 :
2002 : /*
2003 : * Handler executed before fork(2) processing starts.
2004 : */
2005 30 : static void pwrap_thread_prepare(void)
2006 : {
2007 30 : }
2008 :
2009 : /*
2010 : * Handler that is executed in the parent process after fork(2) processing
2011 : * completes.
2012 : */
2013 30 : static void pwrap_thread_parent(void)
2014 : {
2015 30 : }
2016 :
2017 : /*
2018 : * Handler that is executed in the child process after fork(2) processing
2019 : * completes.
2020 : */
2021 0 : static void pwrap_thread_child(void)
2022 : {
2023 0 : pwrap.initialised = false;
2024 0 : }
2025 :
2026 308 : void pwrap_constructor(void)
2027 : {
2028 : /*
2029 : * If we hold a lock and the application forks, then the child
2030 : * is not able to unlock the mutex and we are in a deadlock.
2031 : * This should prevent such deadlocks.
2032 : */
2033 308 : pthread_atfork(&pwrap_thread_prepare,
2034 : &pwrap_thread_parent,
2035 : &pwrap_thread_child);
2036 :
2037 : /*
2038 : * Here is safe place to call pwrap_init() and initialize data
2039 : * for main process.
2040 : */
2041 308 : pwrap_init();
2042 308 : }
2043 :
2044 : /****************************
2045 : * DESTRUCTOR
2046 : ***************************/
2047 :
2048 396 : static int p_rmdirs_at(const char *path, int parent_fd)
2049 : {
2050 396 : DIR *d = NULL;
2051 396 : struct dirent *dp = NULL;
2052 : struct stat sb;
2053 396 : char fd_str[64] = { 0 };
2054 : int path_fd;
2055 : int rc;
2056 :
2057 396 : switch(parent_fd) {
2058 266 : case AT_FDCWD:
2059 266 : snprintf(fd_str, sizeof(fd_str), "CWD");
2060 266 : break;
2061 130 : default:
2062 130 : snprintf(fd_str, sizeof(fd_str), "fd=%d", parent_fd);
2063 130 : break;
2064 : }
2065 :
2066 : /* If path is absolute, parent_fd is ignored. */
2067 396 : PWRAP_LOG(PWRAP_LOG_TRACE,
2068 : "p_rmdirs_at removing %s at %s\n", path, fd_str);
2069 :
2070 396 : path_fd = openat(parent_fd,
2071 : path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
2072 396 : if (path_fd == -1) {
2073 0 : return -1;
2074 : }
2075 :
2076 396 : d = fdopendir(path_fd);
2077 396 : if (d == NULL) {
2078 0 : close(path_fd);
2079 0 : return -1;
2080 : }
2081 :
2082 2240 : while ((dp = readdir(d)) != NULL) {
2083 : /* skip '.' and '..' */
2084 2104 : if (dp->d_name[0] == '.' &&
2085 1052 : (dp->d_name[1] == '\0' ||
2086 656 : (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
2087 792 : continue;
2088 : }
2089 :
2090 792 : rc = fstatat(path_fd, dp->d_name,
2091 : &sb, AT_SYMLINK_NOFOLLOW);
2092 792 : if (rc != 0) {
2093 0 : continue;
2094 : }
2095 :
2096 792 : if (S_ISDIR(sb.st_mode)) {
2097 130 : rc = p_rmdirs_at(dp->d_name, path_fd);
2098 : } else {
2099 662 : rc = unlinkat(path_fd, dp->d_name, 0);
2100 : }
2101 792 : if (rc != 0) {
2102 0 : continue;
2103 : }
2104 : }
2105 396 : closedir(d);
2106 :
2107 396 : rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
2108 396 : if (rc != 0) {
2109 0 : rc = errno;
2110 0 : PWRAP_LOG(PWRAP_LOG_TRACE,
2111 : "cannot unlink %s error %d\n", path, rc);
2112 0 : return -1;
2113 : }
2114 :
2115 396 : return 0;
2116 : }
2117 :
2118 266 : static int p_rmdirs(const char *path)
2119 : {
2120 : /*
2121 : * If path is absolute, p_rmdirs_at ignores parent_fd.
2122 : * If it's relative, start from cwd.
2123 : */
2124 266 : return p_rmdirs_at(path, AT_FDCWD);
2125 : }
2126 :
2127 : /*
2128 : * This function is called when the library is unloaded and makes sure that
2129 : * resources are freed.
2130 : */
2131 308 : void pwrap_destructor(void)
2132 : {
2133 : const char *env;
2134 :
2135 308 : PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
2136 :
2137 308 : if (pwrap.libpam.handle != NULL) {
2138 96 : dlclose(pwrap.libpam.handle);
2139 : }
2140 :
2141 308 : if (pwrap.libpam_so != NULL) {
2142 266 : free(pwrap.libpam_so);
2143 266 : pwrap.libpam_so = NULL;
2144 : }
2145 :
2146 308 : if (!pwrap.initialised) {
2147 42 : return;
2148 : }
2149 266 : pwrap.initialised = false;
2150 :
2151 266 : PWRAP_LOG(PWRAP_LOG_TRACE,
2152 : "destructor called for pam_wrapper dir %s",
2153 : pwrap.config_dir);
2154 266 : env = getenv("PAM_WRAPPER_KEEP_DIR");
2155 266 : if (env == NULL || env[0] != '1') {
2156 266 : p_rmdirs(pwrap.config_dir);
2157 : }
2158 :
2159 266 : if (pwrap.config_dir != NULL) {
2160 266 : free(pwrap.config_dir);
2161 266 : pwrap.config_dir = NULL;
2162 : }
2163 : }
|