s3: smbd: Move check_fsp_open() and check_fsp() to smb1_reply.c
[Samba.git] / third_party / pam_wrapper / pam_wrapper.c
blobda2c73816563d8f0e3fac1c94a05b0bfa4386e72
1 /*
2 * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
3 * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <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>
39 #include <pthread.h>
41 #include <ftw.h>
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
53 #include "pwrap_compat.h"
55 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
56 # define PWRAP_THREAD __thread
57 #else
58 # define PWRAP_THREAD
59 #endif
61 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
62 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
63 #else
64 #define CONSTRUCTOR_ATTRIBUTE
65 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
67 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
68 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
69 #else
70 #define DESTRUCTOR_ATTRIBUTE
71 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
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 */
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 */
86 #ifndef SAFE_FREE
87 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
88 #endif
90 #ifndef discard_const
91 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
92 #endif
94 #ifndef discard_const_p
95 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
96 #endif
98 /*****************
99 * LOGGING
100 *****************/
102 #ifndef HAVE_GETPROGNAME
103 static const char *getprogname(void)
105 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
106 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 */
113 #endif /* HAVE_GETPROGNAME */
115 enum pwrap_dbglvl_e {
116 PWRAP_LOG_ERROR = 0,
117 PWRAP_LOG_WARN,
118 PWRAP_LOG_DEBUG,
119 PWRAP_LOG_TRACE
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__)
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);
132 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
133 const char *function,
134 const char *format,
135 va_list args)
137 char buffer[1024];
138 const char *d;
139 unsigned int lvl = 0;
140 const char *prefix = "PWRAP";
141 const char *progname = getprogname();
143 d = getenv("PAM_WRAPPER_DEBUGLEVEL");
144 if (d != NULL) {
145 lvl = atoi(d);
148 if (lvl < dbglvl) {
149 return;
152 vsnprintf(buffer, sizeof(buffer), format, args);
154 switch (dbglvl) {
155 case PWRAP_LOG_ERROR:
156 prefix = "PWRAP_ERROR";
157 break;
158 case PWRAP_LOG_WARN:
159 prefix = "PWRAP_WARN";
160 break;
161 case PWRAP_LOG_DEBUG:
162 prefix = "PWRAP_DEBUG";
163 break;
164 case PWRAP_LOG_TRACE:
165 prefix = "PWRAP_TRACE";
166 break;
169 if (progname == NULL) {
170 progname = "<unknown>";
173 fprintf(stderr,
174 "%s[%s (%u)] - %s: %s\n",
175 prefix,
176 progname,
177 (unsigned int)getpid(),
178 function,
179 buffer);
182 static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
183 const char *function,
184 const char *format, ...)
186 va_list va;
188 va_start(va, format);
189 pwrap_vlog(dbglvl, function, format, va);
190 va_end(va);
193 /*****************
194 * LIBC
195 *****************/
197 #define LIBPAM_NAME "libpam.so.0"
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);
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);
210 typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
212 typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
214 typedef int (*__libpam_pam_chauthtok)(pam_handle_t *pamh, int flags);
216 typedef int (*__libpam_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
218 typedef int (*__libpam_pam_putenv)(pam_handle_t *pamh, const char *name_value);
220 typedef const char * (*__libpam_pam_getenv)(pam_handle_t *pamh, const char *name);
222 typedef char ** (*__libpam_pam_getenvlist)(pam_handle_t *pamh);
224 typedef int (*__libpam_pam_open_session)(pam_handle_t *pamh, int flags);
226 typedef int (*__libpam_pam_close_session)(pam_handle_t *pamh, int flags);
228 typedef int (*__libpam_pam_setcred)(pam_handle_t *pamh, int flags);
230 typedef int (*__libpam_pam_get_item)(const pam_handle_t *pamh,
231 int item_type,
232 const void **item);
234 typedef int (*__libpam_pam_set_item)(pam_handle_t *pamh,
235 int item_type,
236 const void *item);
238 typedef int (*__libpam_pam_get_data)(const pam_handle_t *pamh,
239 const char *module_data_name,
240 const void **data);
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));
249 typedef int (*__libpam_pam_vprompt)(pam_handle_t *pamh,
250 int style,
251 char **response,
252 const char *fmt,
253 va_list args);
255 typedef const char * (*__libpam_pam_strerror)(pam_handle_t *pamh,
256 int errnum);
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
265 #define PWRAP_SYMBOL_ENTRY(i) \
266 union { \
267 __libpam_##i f; \
268 void *obj; \
269 } _libpam_##i
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
295 struct pwrap {
296 struct {
297 void *handle;
298 struct pwrap_libpam_symbols symbols;
299 } libpam;
301 bool enabled;
302 bool initialised;
303 char *config_dir;
304 char *libpam_so;
307 static struct pwrap pwrap;
309 /*********************************************************
310 * PWRAP PROTOTYPES
311 *********************************************************/
313 bool pam_wrapper_enabled(void);
314 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
315 /* xlC and other oldschool compilers support (only) this */
316 #pragma init (pwrap_constructor)
317 #endif
318 void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
319 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
320 #pragma fini (pwrap_destructor)
321 #endif
322 void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
324 /*********************************************************
325 * PWRAP LIBC LOADER FUNCTIONS
326 *********************************************************/
328 enum pwrap_lib {
329 PWRAP_LIBPAM,
332 static void *pwrap_load_lib_handle(enum pwrap_lib lib)
334 int flags = RTLD_LAZY;
335 void *handle = NULL;
337 #ifdef RTLD_DEEPBIND
338 const char *env_preload = getenv("LD_PRELOAD");
339 const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
340 bool enable_deepbind = true;
342 /* Don't do a deepbind if we run with libasan */
343 if (env_preload != NULL && strlen(env_preload) < 1024) {
344 const char *p = strstr(env_preload, "libasan.so");
345 if (p != NULL) {
346 enable_deepbind = false;
350 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
351 enable_deepbind = false;
354 if (enable_deepbind) {
355 flags |= RTLD_DEEPBIND;
357 #endif
359 switch (lib) {
360 case PWRAP_LIBPAM:
361 handle = pwrap.libpam.handle;
362 if (handle == NULL) {
363 handle = dlopen(pwrap.libpam_so, flags);
364 if (handle != NULL) {
365 PWRAP_LOG(PWRAP_LOG_DEBUG,
366 "Opened %s\n", pwrap.libpam_so);
367 pwrap.libpam.handle = handle;
368 break;
371 break;
374 if (handle == NULL) {
375 PWRAP_LOG(PWRAP_LOG_ERROR,
376 "Failed to dlopen library: %s\n",
377 dlerror());
378 exit(-1);
381 return handle;
384 static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
386 void *handle;
387 void *func;
389 handle = pwrap_load_lib_handle(lib);
391 func = dlsym(handle, fn_name);
392 if (func == NULL) {
393 PWRAP_LOG(PWRAP_LOG_ERROR,
394 "Failed to find %s: %s\n",
395 fn_name, dlerror());
396 exit(-1);
399 return func;
402 #define pwrap_bind_symbol_libpam(sym_name) \
403 if (pwrap.libpam.symbols._libpam_##sym_name.obj == NULL) { \
404 pwrap.libpam.symbols._libpam_##sym_name.obj = \
405 _pwrap_bind_symbol(PWRAP_LIBPAM, #sym_name); \
409 * IMPORTANT
411 * Functions especially from libpam need to be loaded individually, you can't
412 * load all at once or gdb will segfault at startup. The same applies to
413 * valgrind and has probably something todo with with the linker.
414 * So we need load each function at the point it is called the first time.
416 #ifdef HAVE_PAM_START_CONFDIR
417 static int libpam_pam_start_confdir(const char *service_name,
418 const char *user,
419 const struct pam_conv *pam_conversation,
420 const char *confdir,
421 pam_handle_t **pamh)
423 pwrap_bind_symbol_libpam(pam_start_confdir);
425 return pwrap.libpam.symbols._libpam_pam_start_confdir.f(service_name,
426 user,
427 pam_conversation,
428 confdir,
429 pamh);
431 #else
432 static int libpam_pam_start(const char *service_name,
433 const char *user,
434 const struct pam_conv *pam_conversation,
435 pam_handle_t **pamh)
437 pwrap_bind_symbol_libpam(pam_start);
439 return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
440 user,
441 pam_conversation,
442 pamh);
445 #endif
447 static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
449 pwrap_bind_symbol_libpam(pam_end);
451 return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
454 static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
456 pwrap_bind_symbol_libpam(pam_authenticate);
458 return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
461 static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
463 pwrap_bind_symbol_libpam(pam_chauthtok);
465 return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
468 static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
470 pwrap_bind_symbol_libpam(pam_acct_mgmt);
472 return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
475 static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
477 pwrap_bind_symbol_libpam(pam_putenv);
479 return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
482 static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
484 pwrap_bind_symbol_libpam(pam_getenv);
486 return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
489 static char **libpam_pam_getenvlist(pam_handle_t *pamh)
491 pwrap_bind_symbol_libpam(pam_getenvlist);
493 return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
496 static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
498 pwrap_bind_symbol_libpam(pam_open_session);
500 return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
503 static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
505 pwrap_bind_symbol_libpam(pam_close_session);
507 return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
510 static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
512 pwrap_bind_symbol_libpam(pam_setcred);
514 return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
517 static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
519 pwrap_bind_symbol_libpam(pam_get_item);
521 return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
524 static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
526 pwrap_bind_symbol_libpam(pam_set_item);
528 return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
531 static int libpam_pam_get_data(const pam_handle_t *pamh,
532 const char *module_data_name,
533 const void **data)
535 pwrap_bind_symbol_libpam(pam_get_data);
537 return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
538 module_data_name,
539 data);
542 static int libpam_pam_set_data(pam_handle_t *pamh,
543 const char *module_data_name,
544 void *data,
545 void (*cleanup)(pam_handle_t *pamh,
546 void *data,
547 int error_status))
549 pwrap_bind_symbol_libpam(pam_set_data);
551 return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
552 module_data_name,
553 data,
554 cleanup);
557 static int libpam_pam_vprompt(pam_handle_t *pamh,
558 int style,
559 char **response,
560 const char *fmt,
561 va_list args)
563 pwrap_bind_symbol_libpam(pam_vprompt);
565 return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
566 style,
567 response,
568 fmt,
569 args);
572 #ifdef HAVE_PAM_STRERROR_CONST
573 static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
574 #else
575 static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
576 #endif
578 pwrap_bind_symbol_libpam(pam_strerror);
580 return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
583 #ifdef HAVE_PAM_VSYSLOG
584 static void libpam_pam_vsyslog(const pam_handle_t *pamh,
585 int priority,
586 const char *fmt,
587 va_list args)
589 pwrap_bind_symbol_libpam(pam_vsyslog);
591 pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
592 priority,
593 fmt,
594 args);
596 #endif /* HAVE_PAM_VSYSLOG */
598 /*********************************************************
599 * PWRAP INIT
600 *********************************************************/
602 #define BUFFER_SIZE 32768
604 /* copy file from src to dst, overwrites dst */
605 static int p_copy(const char *src, const char *dst, mode_t mode)
607 int srcfd = -1;
608 int dstfd = -1;
609 int rc = -1;
610 ssize_t bread, bwritten;
611 struct stat sb;
612 char buf[BUFFER_SIZE];
613 int cmp;
615 cmp = strcmp(src, dst);
616 if (cmp == 0) {
617 return -1;
620 srcfd = open(src, O_RDONLY, 0);
621 if (srcfd < 0) {
622 return -1;
625 if (mode == 0) {
626 rc = fstat(srcfd, &sb);
627 if (rc != 0) {
628 rc = -1;
629 goto out;
631 mode = sb.st_mode;
634 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
635 if (dstfd < 0) {
636 rc = -1;
637 goto out;
640 for (;;) {
641 bread = read(srcfd, buf, BUFFER_SIZE);
642 if (bread == 0) {
643 /* done */
644 break;
645 } else if (bread < 0) {
646 errno = EIO;
647 rc = -1;
648 goto out;
651 bwritten = write(dstfd, buf, bread);
652 if (bwritten < 0) {
653 errno = EIO;
654 rc = -1;
655 goto out;
658 if (bread != bwritten) {
659 errno = EFAULT;
660 rc = -1;
661 goto out;
665 rc = 0;
666 out:
667 if (srcfd != -1) {
668 close(srcfd);
670 if (dstfd != -1) {
671 close(dstfd);
673 if (rc < 0) {
674 unlink(dst);
677 return rc;
680 /* Do not pass any flag if not defined */
681 #ifndef FTW_ACTIONRETVAL
682 #define FTW_ACTIONRETVAL 0
683 #endif
685 /* Action return values */
686 #ifndef FTW_STOP
687 #define FTW_STOP -1
688 #endif
690 #ifndef FTW_CONTINUE
691 #define FTW_CONTINUE 0
692 #endif
694 #ifndef FTW_SKIP_SUBTREE
695 #define FTW_SKIP_SUBTREE 0
696 #endif
698 static int copy_ftw(const char *fpath,
699 const struct stat *sb,
700 int typeflag,
701 struct FTW *ftwbuf)
703 int rc;
704 char buf[BUFFER_SIZE];
706 switch (typeflag) {
707 case FTW_D:
708 case FTW_DNR:
709 /* We want to copy the directories from this directory */
710 if (ftwbuf->level == 0) {
711 return FTW_CONTINUE;
713 return FTW_SKIP_SUBTREE;
714 case FTW_F:
715 break;
716 default:
717 return FTW_CONTINUE;
720 rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
721 if (rc >= BUFFER_SIZE) {
722 return FTW_STOP;
725 PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
726 rc = p_copy(fpath, buf, sb->st_mode);
727 if (rc != 0) {
728 return FTW_STOP;
731 return FTW_CONTINUE;
734 static int copy_confdir(const char *src)
736 int rc;
738 PWRAP_LOG(PWRAP_LOG_DEBUG,
739 "Copy config files from %s to %s",
740 src,
741 pwrap.config_dir);
742 rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
743 if (rc != 0) {
744 return -1;
747 return 0;
750 static int p_rmdirs(const char *path);
752 static void pwrap_clean_stale_dirs(const char *dir)
754 size_t len = strlen(dir);
755 char pidfile[len + 5];
756 ssize_t rc;
757 char buf[8] = {0};
758 long int tmp;
759 pid_t pid;
760 int fd;
762 snprintf(pidfile,
763 sizeof(pidfile),
764 "%s/pid",
765 dir);
767 /* read the pidfile */
768 fd = open(pidfile, O_RDONLY);
769 if (fd < 0) {
770 if (errno == ENOENT) {
771 PWRAP_LOG(PWRAP_LOG_TRACE,
772 "pidfile %s missing, nothing to do\n",
773 pidfile);
774 } else {
775 PWRAP_LOG(PWRAP_LOG_ERROR,
776 "Failed to open pidfile %s - error: %s",
777 pidfile, strerror(errno));
779 return;
782 rc = read(fd, buf, sizeof(buf));
783 close(fd);
784 if (rc < 0) {
785 PWRAP_LOG(PWRAP_LOG_ERROR,
786 "Failed to read pidfile %s - error: %s",
787 pidfile, strerror(errno));
788 return;
791 buf[sizeof(buf) - 1] = '\0';
793 tmp = strtol(buf, NULL, 10);
794 if (tmp == 0 || errno == ERANGE) {
795 PWRAP_LOG(PWRAP_LOG_ERROR,
796 "Failed to parse pid, buf=%s",
797 buf);
798 return;
801 pid = (pid_t)tmp;
802 /* Check if we are out of pid_t range on this system */
803 if ((long)pid != tmp) {
804 PWRAP_LOG(PWRAP_LOG_ERROR,
805 "pid out of range: %ld", tmp);
806 return;
809 rc = kill(pid, 0);
810 if (rc == -1) {
811 PWRAP_LOG(PWRAP_LOG_TRACE,
812 "Remove stale pam_wrapper dir: %s",
813 dir);
814 p_rmdirs(dir);
817 return;
820 #ifdef HAVE_PAM_START_CONFDIR
821 static void pwrap_init(void)
823 char tmp_config_dir[] = "/tmp/pam.X";
824 size_t len = strlen(tmp_config_dir);
825 const char *env;
826 struct stat sb;
827 int rc;
828 unsigned i;
829 ssize_t ret;
830 FILE *pidfile;
831 char pidfile_path[1024] = { 0 };
832 char letter;
834 if (!pam_wrapper_enabled()) {
835 return;
838 if (pwrap.initialised) {
839 return;
843 * The name is selected to match/replace /etc/pam.d
844 * We start from a random alphanum trying letters until
845 * an available directory is found.
847 letter = 48 + (getpid() % 70);
848 for (i = 0; i < 127; i++) {
849 if (isalpha(letter) || isdigit(letter)) {
850 tmp_config_dir[len - 1] = letter;
852 rc = lstat(tmp_config_dir, &sb);
853 if (rc == 0) {
854 PWRAP_LOG(PWRAP_LOG_TRACE,
855 "Check if pam_wrapper dir %s is a "
856 "stale directory",
857 tmp_config_dir);
858 pwrap_clean_stale_dirs(tmp_config_dir);
859 } else if (rc < 0) {
860 if (errno != ENOENT) {
861 continue;
863 break; /* found */
867 letter++;
868 letter %= 127;
871 if (i == 127) {
872 PWRAP_LOG(PWRAP_LOG_ERROR,
873 "Failed to find a possible path to create "
874 "pam_wrapper config dir: %s",
875 tmp_config_dir);
876 exit(1);
879 PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
881 pwrap.config_dir = strdup(tmp_config_dir);
882 if (pwrap.config_dir == NULL) {
883 PWRAP_LOG(PWRAP_LOG_ERROR,
884 "No memory");
885 exit(1);
887 PWRAP_LOG(PWRAP_LOG_TRACE,
888 "pam_wrapper config dir: %s",
889 tmp_config_dir);
891 rc = mkdir(pwrap.config_dir, 0755);
892 if (rc != 0) {
893 PWRAP_LOG(PWRAP_LOG_ERROR,
894 "Failed to create pam_wrapper config dir: %s - %s",
895 tmp_config_dir, strerror(errno));
898 /* Create file with the PID of the the process */
899 ret = snprintf(pidfile_path, sizeof(pidfile_path),
900 "%s/pid", pwrap.config_dir);
901 if (ret < 0) {
902 p_rmdirs(pwrap.config_dir);
903 exit(1);
906 pidfile = fopen(pidfile_path, "w");
907 if (pidfile == NULL) {
908 p_rmdirs(pwrap.config_dir);
909 exit(1);
912 rc = fprintf(pidfile, "%d", getpid());
913 fclose(pidfile);
914 if (rc <= 0) {
915 p_rmdirs(pwrap.config_dir);
916 exit(1);
919 pwrap.libpam_so = strdup(PAM_LIBRARY);
920 if (pwrap.libpam_so == NULL) {
921 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
922 p_rmdirs(pwrap.config_dir);
923 exit(1);
926 PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
928 pwrap.initialised = true;
930 env = getenv("PAM_WRAPPER_SERVICE_DIR");
931 if (env == NULL) {
932 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
933 p_rmdirs(pwrap.config_dir);
934 exit(1);
937 rc = copy_confdir(env);
938 if (rc != 0) {
939 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
940 p_rmdirs(pwrap.config_dir);
941 exit(1);
944 setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
946 PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
949 #else /* HAVE_PAM_START_CONFDIR */
951 static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
953 #define PSO_COPY_READ_SIZE 9
954 int srcfd = -1;
955 int dstfd = -1;
956 int rc = -1;
957 ssize_t bread, bwritten;
958 struct stat sb;
959 char buf[PSO_COPY_READ_SIZE + 1];
960 int cmp;
961 size_t to_read;
962 bool found_slash;
964 cmp = strcmp(src, dst);
965 if (cmp == 0) {
966 return -1;
969 srcfd = open(src, O_RDONLY, 0);
970 if (srcfd < 0) {
971 return -1;
974 if (mode == 0) {
975 rc = fstat(srcfd, &sb);
976 if (rc != 0) {
977 rc = -1;
978 goto out;
980 mode = sb.st_mode;
983 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
984 if (dstfd < 0) {
985 rc = -1;
986 goto out;
989 found_slash = false;
990 to_read = 1;
992 for (;;) {
993 bread = read(srcfd, buf, to_read);
994 if (bread == 0) {
995 /* done */
996 break;
997 } else if (bread < 0) {
998 errno = EIO;
999 rc = -1;
1000 goto out;
1003 to_read = 1;
1004 if (!found_slash && buf[0] == '/') {
1005 found_slash = true;
1006 to_read = PSO_COPY_READ_SIZE;
1009 if (found_slash && bread == PSO_COPY_READ_SIZE) {
1010 cmp = memcmp(buf, "etc/pam.d", PSO_COPY_READ_SIZE);
1011 if (cmp == 0) {
1012 memcpy(buf, pdir + 1, PSO_COPY_READ_SIZE);
1014 found_slash = false;
1017 bwritten = write(dstfd, buf, bread);
1018 if (bwritten < 0) {
1019 errno = EIO;
1020 rc = -1;
1021 goto out;
1024 if (bread != bwritten) {
1025 errno = EFAULT;
1026 rc = -1;
1027 goto out;
1031 rc = 0;
1032 out:
1033 if (srcfd != -1) {
1034 close(srcfd);
1036 if (dstfd != -1) {
1037 close(dstfd);
1039 if (rc < 0) {
1040 unlink(dst);
1043 return rc;
1044 #undef PSO_COPY_READ_SIZE
1047 static void pwrap_init(void)
1049 char tmp_config_dir[] = "/tmp/pam.X";
1050 size_t len = strlen(tmp_config_dir);
1051 const char *env;
1052 struct stat sb;
1053 int rc;
1054 unsigned i;
1055 char pam_library[128] = { 0 };
1056 char libpam_path[1024] = { 0 };
1057 ssize_t ret;
1058 FILE *pidfile;
1059 char pidfile_path[1024] = { 0 };
1060 char letter;
1062 if (!pam_wrapper_enabled()) {
1063 return;
1066 if (pwrap.initialised) {
1067 return;
1071 * The name is selected to match/replace /etc/pam.d
1072 * We start from a random alphanum trying letters until
1073 * an available directory is found.
1075 letter = 48 + (getpid() % 70);
1076 for (i = 0; i < 127; i++) {
1077 if (isalpha(letter) || isdigit(letter)) {
1078 tmp_config_dir[len - 1] = letter;
1080 rc = lstat(tmp_config_dir, &sb);
1081 if (rc == 0) {
1082 PWRAP_LOG(PWRAP_LOG_TRACE,
1083 "Check if pam_wrapper dir %s is a "
1084 "stale directory",
1085 tmp_config_dir);
1086 pwrap_clean_stale_dirs(tmp_config_dir);
1087 } else if (rc < 0) {
1088 if (errno != ENOENT) {
1089 continue;
1091 break; /* found */
1095 letter++;
1096 letter %= 127;
1099 if (i == 127) {
1100 PWRAP_LOG(PWRAP_LOG_ERROR,
1101 "Failed to find a possible path to create "
1102 "pam_wrapper config dir: %s",
1103 tmp_config_dir);
1104 exit(1);
1107 PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
1109 pwrap.config_dir = strdup(tmp_config_dir);
1110 if (pwrap.config_dir == NULL) {
1111 PWRAP_LOG(PWRAP_LOG_ERROR,
1112 "No memory");
1113 exit(1);
1115 PWRAP_LOG(PWRAP_LOG_TRACE,
1116 "pam_wrapper config dir: %s",
1117 tmp_config_dir);
1119 rc = mkdir(pwrap.config_dir, 0755);
1120 if (rc != 0) {
1121 PWRAP_LOG(PWRAP_LOG_ERROR,
1122 "Failed to create pam_wrapper config dir: %s - %s",
1123 tmp_config_dir, strerror(errno));
1126 /* Create file with the PID of the the process */
1127 ret = snprintf(pidfile_path, sizeof(pidfile_path),
1128 "%s/pid", pwrap.config_dir);
1129 if (ret < 0) {
1130 p_rmdirs(pwrap.config_dir);
1131 exit(1);
1134 pidfile = fopen(pidfile_path, "w");
1135 if (pidfile == NULL) {
1136 p_rmdirs(pwrap.config_dir);
1137 exit(1);
1140 rc = fprintf(pidfile, "%d", getpid());
1141 fclose(pidfile);
1142 if (rc <= 0) {
1143 p_rmdirs(pwrap.config_dir);
1144 exit(1);
1147 /* create lib subdirectory */
1148 snprintf(libpam_path,
1149 sizeof(libpam_path),
1150 "%s/lib",
1151 pwrap.config_dir);
1153 rc = mkdir(libpam_path, 0755);
1154 if (rc != 0) {
1155 PWRAP_LOG(PWRAP_LOG_ERROR,
1156 "Failed to create path for libpam: %s - %s",
1157 tmp_config_dir, strerror(errno));
1158 p_rmdirs(pwrap.config_dir);
1159 exit(1);
1162 snprintf(libpam_path,
1163 sizeof(libpam_path),
1164 "%s/lib/%s",
1165 pwrap.config_dir,
1166 LIBPAM_NAME);
1168 pwrap.libpam_so = strdup(libpam_path);
1169 if (pwrap.libpam_so == NULL) {
1170 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
1171 p_rmdirs(pwrap.config_dir);
1172 exit(1);
1175 /* copy libpam.so.0 */
1176 snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
1177 PWRAP_LOG(PWRAP_LOG_TRACE,
1178 "PAM path: %s",
1179 libpam_path);
1181 ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
1182 PWRAP_LOG(PWRAP_LOG_TRACE,
1183 "PAM library: %s",
1184 pam_library);
1185 if (ret <= 0) {
1186 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
1187 p_rmdirs(pwrap.config_dir);
1188 exit(1);
1191 if (pam_library[0] == '/') {
1192 snprintf(libpam_path,
1193 sizeof(libpam_path),
1194 "%s",
1195 pam_library);
1196 } else {
1197 char libpam_path_cp[1024] = {0};
1198 char *dname = NULL;
1200 snprintf(libpam_path_cp,
1201 sizeof(libpam_path_cp),
1202 "%s",
1203 libpam_path);
1205 dname = dirname(libpam_path_cp);
1206 if (dname == NULL) {
1207 PWRAP_LOG(PWRAP_LOG_ERROR,
1208 "No directory component in %s", libpam_path);
1209 p_rmdirs(pwrap.config_dir);
1210 exit(1);
1213 snprintf(libpam_path,
1214 sizeof(libpam_path),
1215 "%s/%s",
1216 dname,
1217 pam_library);
1219 PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
1221 PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
1222 rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
1223 if (rc != 0) {
1224 PWRAP_LOG(PWRAP_LOG_ERROR,
1225 "Failed to copy %s - error: %s",
1226 LIBPAM_NAME,
1227 strerror(errno));
1228 p_rmdirs(pwrap.config_dir);
1229 exit(1);
1232 PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
1234 pwrap.initialised = true;
1236 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1237 if (env == NULL) {
1238 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
1239 p_rmdirs(pwrap.config_dir);
1240 exit(1);
1243 rc = copy_confdir(env);
1244 if (rc != 0) {
1245 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
1246 p_rmdirs(pwrap.config_dir);
1247 exit(1);
1250 setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
1252 PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
1254 #endif /* HAVE_PAM_START_CONFDIR */
1256 bool pam_wrapper_enabled(void)
1258 const char *env;
1260 pwrap.enabled = false;
1262 env = getenv("PAM_WRAPPER");
1263 if (env != NULL && env[0] == '1') {
1264 pwrap.enabled = true;
1267 if (pwrap.enabled) {
1268 pwrap.enabled = false;
1270 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1271 if (env != NULL && env[0] != '\0') {
1272 pwrap.enabled = true;
1276 return pwrap.enabled;
1279 #ifdef HAVE_OPENPAM
1280 static int pwrap_openpam_start(const char *service_name,
1281 const char *user,
1282 const struct pam_conv *pam_conversation,
1283 pam_handle_t **pamh)
1285 int rv;
1286 char fullpath[1024];
1288 rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1289 if (rv != PAM_SUCCESS) {
1290 PWRAP_LOG(PWRAP_LOG_ERROR,
1291 "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1292 return rv;
1295 rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1296 if (rv != PAM_SUCCESS) {
1297 PWRAP_LOG(PWRAP_LOG_ERROR,
1298 "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1299 return rv;
1302 rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1303 if (rv != PAM_SUCCESS) {
1304 PWRAP_LOG(PWRAP_LOG_ERROR,
1305 "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1306 return rv;
1309 rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1310 if (rv != PAM_SUCCESS) {
1311 PWRAP_LOG(PWRAP_LOG_ERROR,
1312 "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1313 return rv;
1316 snprintf(fullpath,
1317 sizeof(fullpath),
1318 "%s/%s",
1319 pwrap.config_dir,
1320 service_name);
1322 return libpam_pam_start(fullpath,
1323 user,
1324 pam_conversation,
1325 pamh);
1327 #endif
1329 static int pwrap_pam_start(const char *service_name,
1330 const char *user,
1331 const struct pam_conv *pam_conversation,
1332 pam_handle_t **pamh)
1334 int rc;
1336 pwrap_init();
1338 PWRAP_LOG(PWRAP_LOG_TRACE,
1339 "pam_start service=%s, user=%s",
1340 service_name,
1341 user);
1343 #if defined(HAVE_OPENPAM)
1344 rc = pwrap_openpam_start(service_name,
1345 user,
1346 pam_conversation,
1347 pamh);
1348 #elif defined (HAVE_PAM_START_CONFDIR)
1349 rc = libpam_pam_start_confdir(service_name,
1350 user,
1351 pam_conversation,
1352 pwrap.config_dir,
1353 pamh);
1354 #else
1355 rc = libpam_pam_start(service_name,
1356 user,
1357 pam_conversation,
1358 pamh);
1359 #endif
1360 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_start rc=%d", rc);
1362 return rc;
1366 int pam_start(const char *service_name,
1367 const char *user,
1368 const struct pam_conv *pam_conversation,
1369 pam_handle_t **pamh)
1371 return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1374 static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1376 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1377 return libpam_pam_end(pamh, pam_status);
1381 int pam_end(pam_handle_t *pamh, int pam_status)
1383 return pwrap_pam_end(pamh, pam_status);
1386 static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1388 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1389 return libpam_pam_authenticate(pamh, flags);
1392 int pam_authenticate(pam_handle_t *pamh, int flags)
1394 return pwrap_pam_authenticate(pamh, flags);
1397 static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1399 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1400 return libpam_pam_chauthtok(pamh, flags);
1403 int pam_chauthtok(pam_handle_t *pamh, int flags)
1405 return pwrap_pam_chauthtok(pamh, flags);
1408 static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1410 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1411 return libpam_pam_acct_mgmt(pamh, flags);
1414 int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1416 return pwrap_pam_acct_mgmt(pamh, flags);
1419 static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1421 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1422 return libpam_pam_putenv(pamh, name_value);
1425 int pam_putenv(pam_handle_t *pamh, const char *name_value)
1427 return pwrap_pam_putenv(pamh, name_value);
1430 static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1432 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1433 return libpam_pam_getenv(pamh, name);
1436 const char *pam_getenv(pam_handle_t *pamh, const char *name)
1438 return pwrap_pam_getenv(pamh, name);
1441 static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1443 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1444 return libpam_pam_getenvlist(pamh);
1447 char **pam_getenvlist(pam_handle_t *pamh)
1449 return pwrap_pam_getenvlist(pamh);
1452 static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1454 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1455 return libpam_pam_open_session(pamh, flags);
1458 int pam_open_session(pam_handle_t *pamh, int flags)
1460 return pwrap_pam_open_session(pamh, flags);
1463 static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1465 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1466 return libpam_pam_close_session(pamh, flags);
1469 int pam_close_session(pam_handle_t *pamh, int flags)
1471 return pwrap_pam_close_session(pamh, flags);
1474 static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1476 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1477 return libpam_pam_setcred(pamh, flags);
1480 int pam_setcred(pam_handle_t *pamh, int flags)
1482 return pwrap_pam_setcred(pamh, flags);
1485 static const char *pwrap_get_service(const char *libpam_service)
1487 #ifdef HAVE_OPENPAM
1488 const char *service_name;
1490 PWRAP_LOG(PWRAP_LOG_TRACE,
1491 "internal PAM_SERVICE=%s", libpam_service);
1492 service_name = strrchr(libpam_service, '/');
1493 if (service_name != NULL && service_name[0] == '/') {
1494 service_name++;
1496 PWRAP_LOG(PWRAP_LOG_TRACE,
1497 "PAM_SERVICE=%s", service_name);
1498 return service_name;
1499 #else
1500 return libpam_service;
1501 #endif
1504 static int pwrap_pam_get_item(const pam_handle_t *pamh,
1505 int item_type,
1506 const void **item)
1508 int rc;
1509 const char *svc;
1511 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1513 rc = libpam_pam_get_item(pamh, item_type, item);
1515 if (rc == PAM_SUCCESS) {
1516 switch(item_type) {
1517 case PAM_USER:
1518 PWRAP_LOG(PWRAP_LOG_TRACE,
1519 "pwrap_get_item PAM_USER=%s",
1520 (const char *)*item);
1521 break;
1522 case PAM_SERVICE:
1523 svc = pwrap_get_service((const char *) *item);
1525 PWRAP_LOG(PWRAP_LOG_TRACE,
1526 "pwrap_get_item PAM_SERVICE=%s",
1527 svc);
1528 *item = svc;
1529 break;
1530 case PAM_USER_PROMPT:
1531 PWRAP_LOG(PWRAP_LOG_TRACE,
1532 "pwrap_get_item PAM_USER_PROMPT=%s",
1533 (const char *)*item);
1534 break;
1535 case PAM_TTY:
1536 PWRAP_LOG(PWRAP_LOG_TRACE,
1537 "pwrap_get_item PAM_TTY=%s",
1538 (const char *)*item);
1539 break;
1540 case PAM_RUSER:
1541 PWRAP_LOG(PWRAP_LOG_TRACE,
1542 "pwrap_get_item PAM_RUSER=%s",
1543 (const char *)*item);
1544 break;
1545 case PAM_RHOST:
1546 PWRAP_LOG(PWRAP_LOG_TRACE,
1547 "pwrap_get_item PAM_RHOST=%s",
1548 (const char *)*item);
1549 break;
1550 case PAM_AUTHTOK:
1551 PWRAP_LOG(PWRAP_LOG_TRACE,
1552 "pwrap_get_item PAM_AUTHTOK=%s",
1553 (const char *)*item);
1554 break;
1555 case PAM_OLDAUTHTOK:
1556 PWRAP_LOG(PWRAP_LOG_TRACE,
1557 "pwrap_get_item PAM_OLDAUTHTOK=%s",
1558 (const char *)*item);
1559 break;
1560 case PAM_CONV:
1561 PWRAP_LOG(PWRAP_LOG_TRACE,
1562 "pwrap_get_item PAM_CONV=%p",
1563 (const void *)*item);
1564 break;
1565 default:
1566 PWRAP_LOG(PWRAP_LOG_TRACE,
1567 "pwrap_get_item item_type=%d item=%p",
1568 item_type, (const void *)*item);
1569 break;
1571 } else {
1572 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1575 return rc;
1578 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1580 return pwrap_pam_get_item(pamh, item_type, item);
1583 static int pwrap_pam_set_item(pam_handle_t *pamh,
1584 int item_type,
1585 const void *item)
1587 int rc;
1589 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1591 rc = libpam_pam_set_item(pamh, item_type, item);
1592 if (rc == PAM_SUCCESS) {
1593 switch(item_type) {
1594 case PAM_USER:
1595 PWRAP_LOG(PWRAP_LOG_TRACE,
1596 "pwrap_set_item PAM_USER=%s",
1597 (const char *)item);
1598 break;
1599 case PAM_SERVICE:
1600 PWRAP_LOG(PWRAP_LOG_TRACE,
1601 "pwrap_set_item PAM_SERVICE=%s",
1602 (const char *)item);
1603 break;
1604 case PAM_USER_PROMPT:
1605 PWRAP_LOG(PWRAP_LOG_TRACE,
1606 "pwrap_set_item PAM_USER_PROMPT=%s",
1607 (const char *)item);
1608 break;
1609 case PAM_TTY:
1610 PWRAP_LOG(PWRAP_LOG_TRACE,
1611 "pwrap_set_item PAM_TTY=%s",
1612 (const char *)item);
1613 break;
1614 case PAM_RUSER:
1615 PWRAP_LOG(PWRAP_LOG_TRACE,
1616 "pwrap_set_item PAM_RUSER=%s",
1617 (const char *)item);
1618 break;
1619 case PAM_RHOST:
1620 PWRAP_LOG(PWRAP_LOG_TRACE,
1621 "pwrap_set_item PAM_RHOST=%s",
1622 (const char *)item);
1623 break;
1624 case PAM_AUTHTOK:
1625 PWRAP_LOG(PWRAP_LOG_TRACE,
1626 "pwrap_set_item PAM_AUTHTOK=%s",
1627 (const char *)item);
1628 break;
1629 case PAM_OLDAUTHTOK:
1630 PWRAP_LOG(PWRAP_LOG_TRACE,
1631 "pwrap_set_item PAM_OLDAUTHTOK=%s",
1632 (const char *)item);
1633 break;
1634 case PAM_CONV:
1635 PWRAP_LOG(PWRAP_LOG_TRACE,
1636 "pwrap_set_item PAM_CONV=%p",
1637 item);
1638 break;
1639 default:
1640 PWRAP_LOG(PWRAP_LOG_TRACE,
1641 "pwrap_set_item item_type=%d item=%p",
1642 item_type, item);
1643 break;
1645 } else {
1646 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1649 return rc;
1652 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1654 return pwrap_pam_set_item(pamh, item_type, item);
1657 static int pwrap_pam_get_data(const pam_handle_t *pamh,
1658 const char *module_data_name,
1659 const void **data)
1661 PWRAP_LOG(PWRAP_LOG_TRACE,
1662 "pwrap_get_data module_data_name=%s", module_data_name);
1663 return libpam_pam_get_data(pamh, module_data_name, data);
1666 int pam_get_data(const pam_handle_t *pamh,
1667 const char *module_data_name,
1668 const void **data)
1670 return pwrap_pam_get_data(pamh, module_data_name, data);
1673 static int pwrap_pam_set_data(pam_handle_t *pamh,
1674 const char *module_data_name,
1675 void *data,
1676 void (*cleanup)(pam_handle_t *pamh,
1677 void *data,
1678 int error_status))
1680 PWRAP_LOG(PWRAP_LOG_TRACE,
1681 "pwrap_set_data module_data_name=%s data=%p",
1682 module_data_name, data);
1683 return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1686 int pam_set_data(pam_handle_t *pamh,
1687 const char *module_data_name,
1688 void *data,
1689 void (*cleanup)(pam_handle_t *pamh,
1690 void *data,
1691 int error_status))
1693 return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1696 #ifdef HAVE_PAM_VPROMPT_CONST
1697 static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1698 #else
1699 static int pwrap_pam_vprompt(pam_handle_t *pamh,
1700 #endif
1701 int style,
1702 char **response,
1703 const char *fmt,
1704 va_list args)
1706 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1707 return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1708 style,
1709 response,
1710 fmt,
1711 args);
1714 #ifdef HAVE_PAM_VPROMPT_CONST
1715 int pam_vprompt(const pam_handle_t *pamh,
1716 int style,
1717 char **response,
1718 const char *fmt,
1719 va_list args)
1720 #else
1721 int pam_vprompt(pam_handle_t *pamh,
1722 int style,
1723 char **response,
1724 const char *fmt,
1725 va_list args)
1726 #endif
1728 return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1729 style,
1730 response,
1731 fmt,
1732 args);
1735 #ifdef HAVE_PAM_PROMPT_CONST
1736 int pam_prompt(const pam_handle_t *pamh,
1737 int style,
1738 char **response,
1739 const char *fmt, ...)
1740 #else
1741 int pam_prompt(pam_handle_t *pamh,
1742 int style,
1743 char **response,
1744 const char *fmt, ...)
1745 #endif
1747 va_list args;
1748 int rv;
1750 va_start(args, fmt);
1751 rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1752 style,
1753 response,
1754 fmt,
1755 args);
1756 va_end(args);
1758 return rv;
1761 #ifdef HAVE_PAM_STRERROR_CONST
1762 static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1763 #else
1764 static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1765 #endif
1767 const char *str;
1769 pwrap_init();
1771 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1773 str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1774 errnum);
1776 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1778 return str;
1781 #ifdef HAVE_PAM_STRERROR_CONST
1782 const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1783 #else
1784 const char *pam_strerror(pam_handle_t *pamh, int errnum)
1785 #endif
1787 return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1788 errnum);
1791 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1792 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1793 int priority,
1794 const char *fmt,
1795 va_list args) PRINTF_ATTRIBUTE(3, 0);
1797 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1798 int priority,
1799 const char *fmt,
1800 va_list args)
1802 const char *d;
1803 char syslog_str[32] = {0};
1804 enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1806 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1808 #ifdef HAVE_PAM_VSYSLOG
1809 d = getenv("PAM_WRAPPER_USE_SYSLOG");
1810 if (d != NULL && d[0] == '1') {
1811 libpam_pam_vsyslog(pamh, priority, fmt, args);
1812 return;
1814 #endif /* HAVE_PAM_VSYSLOG */
1816 switch(priority) {
1817 case 0: /* LOG_EMERG */
1818 case 1: /* LOG_ALERT */
1819 case 2: /* LOG_CRIT */
1820 case 3: /* LOG_ERR */
1821 dbglvl = PWRAP_LOG_ERROR;
1822 break;
1823 case 4: /* LOG_WARN */
1824 dbglvl = PWRAP_LOG_WARN;
1825 break;
1826 case 5: /* LOG_NOTICE */
1827 case 6: /* LOG_INFO */
1828 case 7: /* LOG_DEBUG */
1829 dbglvl = PWRAP_LOG_DEBUG;
1830 break;
1831 default:
1832 dbglvl = PWRAP_LOG_TRACE;
1833 break;
1836 snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1838 pwrap_vlog(dbglvl, syslog_str, fmt, args);
1840 #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1842 #ifdef HAVE_PAM_VSYSLOG
1843 void pam_vsyslog(const pam_handle_t *pamh,
1844 int priority,
1845 const char *fmt,
1846 va_list args)
1848 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1850 #endif
1852 #ifdef HAVE_PAM_SYSLOG
1853 void pam_syslog(const pam_handle_t *pamh,
1854 int priority,
1855 const char *fmt, ...)
1857 va_list args;
1859 va_start(args, fmt);
1860 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1861 va_end(args);
1863 #endif
1865 /* This might be called by pam_end() running with sshd */
1866 int audit_open(void);
1867 int audit_open(void)
1870 * Tell the application that the kernel doesn't
1871 * have audit compiled in.
1873 errno = EPROTONOSUPPORT;
1874 return -1;
1877 /* Disable BSD auditing */
1878 int cannot_audit(int x);
1879 int cannot_audit(int x)
1881 (void) x;
1883 return 1;
1886 /****************************
1887 * CONSTRUCTOR
1888 ***************************/
1891 * Handler executed before fork(2) processing starts.
1893 static void pwrap_thread_prepare(void)
1898 * Handler that is executed in the parent process after fork(2) processing
1899 * completes.
1901 static void pwrap_thread_parent(void)
1906 * Handler that is executed in the child process after fork(2) processing
1907 * completes.
1909 static void pwrap_thread_child(void)
1911 pwrap.initialised = false;
1914 void pwrap_constructor(void)
1917 * If we hold a lock and the application forks, then the child
1918 * is not able to unlock the mutex and we are in a deadlock.
1919 * This should prevent such deadlocks.
1921 pthread_atfork(&pwrap_thread_prepare,
1922 &pwrap_thread_parent,
1923 &pwrap_thread_child);
1926 * Here is safe place to call pwrap_init() and initialize data
1927 * for main process.
1929 pwrap_init();
1932 /****************************
1933 * DESTRUCTOR
1934 ***************************/
1936 static int p_rmdirs_at(const char *path, int parent_fd)
1938 DIR *d = NULL;
1939 struct dirent *dp = NULL;
1940 struct stat sb;
1941 char fd_str[64] = { 0 };
1942 int path_fd;
1943 int rc;
1945 switch(parent_fd) {
1946 case AT_FDCWD:
1947 snprintf(fd_str, sizeof(fd_str), "CWD");
1948 break;
1949 default:
1950 snprintf(fd_str, sizeof(fd_str), "fd=%d", parent_fd);
1951 break;
1954 /* If path is absolute, parent_fd is ignored. */
1955 PWRAP_LOG(PWRAP_LOG_TRACE,
1956 "p_rmdirs_at removing %s at %s\n", path, fd_str);
1958 path_fd = openat(parent_fd,
1959 path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1960 if (path_fd == -1) {
1961 return -1;
1964 d = fdopendir(path_fd);
1965 if (d == NULL) {
1966 close(path_fd);
1967 return -1;
1970 while ((dp = readdir(d)) != NULL) {
1971 /* skip '.' and '..' */
1972 if (dp->d_name[0] == '.' &&
1973 (dp->d_name[1] == '\0' ||
1974 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
1975 continue;
1978 rc = fstatat(path_fd, dp->d_name,
1979 &sb, AT_SYMLINK_NOFOLLOW);
1980 if (rc != 0) {
1981 continue;
1984 if (S_ISDIR(sb.st_mode)) {
1985 rc = p_rmdirs_at(dp->d_name, path_fd);
1986 } else {
1987 rc = unlinkat(path_fd, dp->d_name, 0);
1989 if (rc != 0) {
1990 continue;
1993 closedir(d);
1995 rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
1996 if (rc != 0) {
1997 rc = errno;
1998 PWRAP_LOG(PWRAP_LOG_TRACE,
1999 "cannot unlink %s error %d\n", path, rc);
2000 return -1;
2003 return 0;
2006 static int p_rmdirs(const char *path)
2009 * If path is absolute, p_rmdirs_at ignores parent_fd.
2010 * If it's relative, start from cwd.
2012 return p_rmdirs_at(path, AT_FDCWD);
2016 * This function is called when the library is unloaded and makes sure that
2017 * resources are freed.
2019 void pwrap_destructor(void)
2021 const char *env;
2023 PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
2025 if (pwrap.libpam.handle != NULL) {
2026 dlclose(pwrap.libpam.handle);
2029 if (pwrap.libpam_so != NULL) {
2030 free(pwrap.libpam_so);
2031 pwrap.libpam_so = NULL;
2034 if (!pwrap.initialised) {
2035 return;
2037 pwrap.initialised = false;
2039 PWRAP_LOG(PWRAP_LOG_TRACE,
2040 "destructor called for pam_wrapper dir %s",
2041 pwrap.config_dir);
2042 env = getenv("PAM_WRAPPER_KEEP_DIR");
2043 if (env == NULL || env[0] != '1') {
2044 p_rmdirs(pwrap.config_dir);
2047 if (pwrap.config_dir != NULL) {
2048 free(pwrap.config_dir);
2049 pwrap.config_dir = NULL;