samba-tool group delete: use binary encoded group name
[Samba.git] / third_party / pam_wrapper / pam_wrapper.c
blob48d2c2ae566a6a20a74e2caec5ff448c706aa44b
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 <ftw.h>
41 #ifdef HAVE_SECURITY_PAM_APPL_H
42 #include <security/pam_appl.h>
43 #endif
44 #ifdef HAVE_SECURITY_PAM_MODULES_H
45 #include <security/pam_modules.h>
46 #endif
47 #ifdef HAVE_SECURITY_PAM_EXT_H
48 #include <security/pam_ext.h>
49 #endif
51 #include "pwrap_compat.h"
53 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
54 # define PWRAP_THREAD __thread
55 #else
56 # define PWRAP_THREAD
57 #endif
59 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
60 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
61 #else
62 #define CONSTRUCTOR_ATTRIBUTE
63 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
65 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
66 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
67 #else
68 #define DESTRUCTOR_ATTRIBUTE
69 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
71 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
72 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
73 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
74 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
75 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
77 /* GCC have printf type attribute check. */
78 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
79 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
80 #else
81 #define PRINTF_ATTRIBUTE(a,b)
82 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
84 #ifndef SAFE_FREE
85 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
86 #endif
88 #ifndef discard_const
89 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
90 #endif
92 #ifndef discard_const_p
93 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
94 #endif
96 /*****************
97 * LOGGING
98 *****************/
100 enum pwrap_dbglvl_e {
101 PWRAP_LOG_ERROR = 0,
102 PWRAP_LOG_WARN,
103 PWRAP_LOG_DEBUG,
104 PWRAP_LOG_TRACE
107 static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
108 const char *function,
109 const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
110 # define PWRAP_LOG(dbglvl, ...) pwrap_log((dbglvl), __func__, __VA_ARGS__)
112 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
113 const char *function,
114 const char *format,
115 va_list args) PRINTF_ATTRIBUTE(3, 0);
117 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
118 const char *function,
119 const char *format,
120 va_list args)
122 char buffer[1024];
123 const char *d;
124 unsigned int lvl = 0;
125 const char *prefix = "PWRAP";
127 d = getenv("PAM_WRAPPER_DEBUGLEVEL");
128 if (d != NULL) {
129 lvl = atoi(d);
132 if (lvl < dbglvl) {
133 return;
136 vsnprintf(buffer, sizeof(buffer), format, args);
138 switch (dbglvl) {
139 case PWRAP_LOG_ERROR:
140 prefix = "PWRAP_ERROR";
141 break;
142 case PWRAP_LOG_WARN:
143 prefix = "PWRAP_WARN";
144 break;
145 case PWRAP_LOG_DEBUG:
146 prefix = "PWRAP_DEBUG";
147 break;
148 case PWRAP_LOG_TRACE:
149 prefix = "PWRAP_TRACE";
150 break;
153 fprintf(stderr,
154 "%s(%d) - %s: %s\n",
155 prefix,
156 (int)getpid(),
157 function,
158 buffer);
161 static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
162 const char *function,
163 const char *format, ...)
165 va_list va;
167 va_start(va, format);
168 pwrap_vlog(dbglvl, function, format, va);
169 va_end(va);
172 /*****************
173 * LIBC
174 *****************/
176 #define LIBPAM_NAME "libpam.so.0"
178 typedef int (*__libpam_pam_start)(const char *service_name,
179 const char *user,
180 const struct pam_conv *pam_conversation,
181 pam_handle_t **pamh);
183 typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
185 typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
187 typedef int (*__libpam_pam_chauthtok)(pam_handle_t *pamh, int flags);
189 typedef int (*__libpam_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
191 typedef int (*__libpam_pam_putenv)(pam_handle_t *pamh, const char *name_value);
193 typedef const char * (*__libpam_pam_getenv)(pam_handle_t *pamh, const char *name);
195 typedef char ** (*__libpam_pam_getenvlist)(pam_handle_t *pamh);
197 typedef int (*__libpam_pam_open_session)(pam_handle_t *pamh, int flags);
199 typedef int (*__libpam_pam_close_session)(pam_handle_t *pamh, int flags);
201 typedef int (*__libpam_pam_setcred)(pam_handle_t *pamh, int flags);
203 typedef int (*__libpam_pam_get_item)(const pam_handle_t *pamh,
204 int item_type,
205 const void **item);
207 typedef int (*__libpam_pam_set_item)(pam_handle_t *pamh,
208 int item_type,
209 const void *item);
211 typedef int (*__libpam_pam_get_data)(const pam_handle_t *pamh,
212 const char *module_data_name,
213 const void **data);
215 typedef int (*__libpam_pam_set_data)(pam_handle_t *pamh,
216 const char *module_data_name,
217 void *data,
218 void (*cleanup)(pam_handle_t *pamh,
219 void *data,
220 int error_status));
222 typedef int (*__libpam_pam_vprompt)(pam_handle_t *pamh,
223 int style,
224 char **response,
225 const char *fmt,
226 va_list args);
228 typedef const char * (*__libpam_pam_strerror)(pam_handle_t *pamh,
229 int errnum);
231 #ifdef HAVE_PAM_VSYSLOG
232 typedef void (*__libpam_pam_vsyslog)(const pam_handle_t *pamh,
233 int priority,
234 const char *fmt,
235 va_list args);
236 #endif
238 #define PWRAP_SYMBOL_ENTRY(i) \
239 union { \
240 __libpam_##i f; \
241 void *obj; \
242 } _libpam_##i
244 struct pwrap_libpam_symbols {
245 PWRAP_SYMBOL_ENTRY(pam_start);
246 PWRAP_SYMBOL_ENTRY(pam_end);
247 PWRAP_SYMBOL_ENTRY(pam_authenticate);
248 PWRAP_SYMBOL_ENTRY(pam_chauthtok);
249 PWRAP_SYMBOL_ENTRY(pam_acct_mgmt);
250 PWRAP_SYMBOL_ENTRY(pam_putenv);
251 PWRAP_SYMBOL_ENTRY(pam_getenv);
252 PWRAP_SYMBOL_ENTRY(pam_getenvlist);
253 PWRAP_SYMBOL_ENTRY(pam_open_session);
254 PWRAP_SYMBOL_ENTRY(pam_close_session);
255 PWRAP_SYMBOL_ENTRY(pam_setcred);
256 PWRAP_SYMBOL_ENTRY(pam_get_item);
257 PWRAP_SYMBOL_ENTRY(pam_set_item);
258 PWRAP_SYMBOL_ENTRY(pam_get_data);
259 PWRAP_SYMBOL_ENTRY(pam_set_data);
260 PWRAP_SYMBOL_ENTRY(pam_vprompt);
261 PWRAP_SYMBOL_ENTRY(pam_strerror);
262 #ifdef HAVE_PAM_VSYSLOG
263 PWRAP_SYMBOL_ENTRY(pam_vsyslog);
264 #endif
267 struct pwrap {
268 struct {
269 void *handle;
270 struct pwrap_libpam_symbols symbols;
271 } libpam;
273 bool enabled;
274 bool initialised;
275 char *config_dir;
276 char *libpam_so;
279 static struct pwrap pwrap;
281 /*********************************************************
282 * PWRAP PROTOTYPES
283 *********************************************************/
285 bool pam_wrapper_enabled(void);
286 void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
287 void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
289 /*********************************************************
290 * PWRAP LIBC LOADER FUNCTIONS
291 *********************************************************/
293 enum pwrap_lib {
294 PWRAP_LIBPAM,
297 static void *pwrap_load_lib_handle(enum pwrap_lib lib)
299 int flags = RTLD_LAZY;
300 void *handle = NULL;
302 #ifdef RTLD_DEEPBIND
303 const char *env = getenv("LD_PRELOAD");
305 /* Don't do a deepbind if we run with libasan */
306 if (env != NULL && strlen(env) < PATH_MAX) {
307 const char *p = strstr(env, "libasan.so");
308 if (p == NULL) {
309 flags |= RTLD_DEEPBIND;
312 #endif
314 switch (lib) {
315 case PWRAP_LIBPAM:
316 handle = pwrap.libpam.handle;
317 if (handle == NULL) {
318 handle = dlopen(pwrap.libpam_so, flags);
319 if (handle != NULL) {
320 PWRAP_LOG(PWRAP_LOG_DEBUG,
321 "Opened %s\n", pwrap.libpam_so);
322 pwrap.libpam.handle = handle;
323 break;
326 break;
329 if (handle == NULL) {
330 PWRAP_LOG(PWRAP_LOG_ERROR,
331 "Failed to dlopen library: %s\n",
332 dlerror());
333 exit(-1);
336 return handle;
339 static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
341 void *handle;
342 void *func;
344 handle = pwrap_load_lib_handle(lib);
346 func = dlsym(handle, fn_name);
347 if (func == NULL) {
348 PWRAP_LOG(PWRAP_LOG_ERROR,
349 "Failed to find %s: %s\n",
350 fn_name, dlerror());
351 exit(-1);
354 return func;
357 #define pwrap_bind_symbol_libpam(sym_name) \
358 if (pwrap.libpam.symbols._libpam_##sym_name.obj == NULL) { \
359 pwrap.libpam.symbols._libpam_##sym_name.obj = \
360 _pwrap_bind_symbol(PWRAP_LIBPAM, #sym_name); \
364 * IMPORTANT
366 * Functions especially from libpam need to be loaded individually, you can't
367 * load all at once or gdb will segfault at startup. The same applies to
368 * valgrind and has probably something todo with with the linker.
369 * So we need load each function at the point it is called the first time.
371 static int libpam_pam_start(const char *service_name,
372 const char *user,
373 const struct pam_conv *pam_conversation,
374 pam_handle_t **pamh)
376 pwrap_bind_symbol_libpam(pam_start);
378 return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
379 user,
380 pam_conversation,
381 pamh);
384 static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
386 pwrap_bind_symbol_libpam(pam_end);
388 return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
391 static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
393 pwrap_bind_symbol_libpam(pam_authenticate);
395 return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
398 static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
400 pwrap_bind_symbol_libpam(pam_chauthtok);
402 return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
405 static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
407 pwrap_bind_symbol_libpam(pam_acct_mgmt);
409 return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
412 static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
414 pwrap_bind_symbol_libpam(pam_putenv);
416 return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
419 static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
421 pwrap_bind_symbol_libpam(pam_getenv);
423 return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
426 static char **libpam_pam_getenvlist(pam_handle_t *pamh)
428 pwrap_bind_symbol_libpam(pam_getenvlist);
430 return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
433 static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
435 pwrap_bind_symbol_libpam(pam_open_session);
437 return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
440 static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
442 pwrap_bind_symbol_libpam(pam_close_session);
444 return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
447 static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
449 pwrap_bind_symbol_libpam(pam_setcred);
451 return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
454 static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
456 pwrap_bind_symbol_libpam(pam_get_item);
458 return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
461 static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
463 pwrap_bind_symbol_libpam(pam_set_item);
465 return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
468 static int libpam_pam_get_data(const pam_handle_t *pamh,
469 const char *module_data_name,
470 const void **data)
472 pwrap_bind_symbol_libpam(pam_get_data);
474 return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
475 module_data_name,
476 data);
479 static int libpam_pam_set_data(pam_handle_t *pamh,
480 const char *module_data_name,
481 void *data,
482 void (*cleanup)(pam_handle_t *pamh,
483 void *data,
484 int error_status))
486 pwrap_bind_symbol_libpam(pam_set_data);
488 return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
489 module_data_name,
490 data,
491 cleanup);
494 static int libpam_pam_vprompt(pam_handle_t *pamh,
495 int style,
496 char **response,
497 const char *fmt,
498 va_list args)
500 pwrap_bind_symbol_libpam(pam_vprompt);
502 return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
503 style,
504 response,
505 fmt,
506 args);
509 #ifdef HAVE_PAM_STRERROR_CONST
510 static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
511 #else
512 static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
513 #endif
515 pwrap_bind_symbol_libpam(pam_strerror);
517 return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
520 #ifdef HAVE_PAM_VSYSLOG
521 static void libpam_pam_vsyslog(const pam_handle_t *pamh,
522 int priority,
523 const char *fmt,
524 va_list args)
526 pwrap_bind_symbol_libpam(pam_vsyslog);
528 pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
529 priority,
530 fmt,
531 args);
533 #endif /* HAVE_PAM_VSYSLOG */
535 /*********************************************************
536 * PWRAP INIT
537 *********************************************************/
539 #define BUFFER_SIZE 32768
541 /* copy file from src to dst, overwrites dst */
542 static int p_copy(const char *src, const char *dst, mode_t mode)
544 int srcfd = -1;
545 int dstfd = -1;
546 int rc = -1;
547 ssize_t bread, bwritten;
548 struct stat sb;
549 char buf[BUFFER_SIZE];
550 int cmp;
552 cmp = strcmp(src, dst);
553 if (cmp == 0) {
554 return -1;
557 srcfd = open(src, O_RDONLY, 0);
558 if (srcfd < 0) {
559 return -1;
562 if (mode == 0) {
563 rc = fstat(srcfd, &sb);
564 if (rc != 0) {
565 rc = -1;
566 goto out;
568 mode = sb.st_mode;
571 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
572 if (dstfd < 0) {
573 rc = -1;
574 goto out;
577 for (;;) {
578 bread = read(srcfd, buf, BUFFER_SIZE);
579 if (bread == 0) {
580 /* done */
581 break;
582 } else if (bread < 0) {
583 errno = EIO;
584 rc = -1;
585 goto out;
588 bwritten = write(dstfd, buf, bread);
589 if (bwritten < 0) {
590 errno = EIO;
591 rc = -1;
592 goto out;
595 if (bread != bwritten) {
596 errno = EFAULT;
597 rc = -1;
598 goto out;
602 rc = 0;
603 out:
604 if (srcfd != -1) {
605 close(srcfd);
607 if (dstfd != -1) {
608 close(dstfd);
610 if (rc < 0) {
611 unlink(dst);
614 return rc;
617 /* Do not pass any flag if not defined */
618 #ifndef FTW_ACTIONRETVAL
619 #define FTW_ACTIONRETVAL 0
620 #endif
622 /* Action return values */
623 #ifndef FTW_STOP
624 #define FTW_STOP -1
625 #endif
627 #ifndef FTW_CONTINUE
628 #define FTW_CONTINUE 0
629 #endif
631 #ifndef FTW_SKIP_SUBTREE
632 #define FTW_SKIP_SUBTREE 0
633 #endif
635 static int copy_ftw(const char *fpath,
636 const struct stat *sb,
637 int typeflag,
638 struct FTW *ftwbuf)
640 int rc;
641 char buf[BUFFER_SIZE];
643 switch (typeflag) {
644 case FTW_D:
645 case FTW_DNR:
646 /* We want to copy the directories from this directory */
647 if (ftwbuf->level == 0) {
648 return FTW_CONTINUE;
650 return FTW_SKIP_SUBTREE;
651 case FTW_F:
652 break;
653 default:
654 return FTW_CONTINUE;
657 rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
658 if (rc >= BUFFER_SIZE) {
659 return FTW_STOP;
662 PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
663 rc = p_copy(fpath, buf, sb->st_mode);
664 if (rc != 0) {
665 return FTW_STOP;
668 return FTW_CONTINUE;
671 static int copy_confdir(const char *src)
673 int rc;
675 PWRAP_LOG(PWRAP_LOG_DEBUG,
676 "Copy config files from %s to %s",
677 src,
678 pwrap.config_dir);
679 rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
680 if (rc != 0) {
681 return -1;
684 return 0;
687 static int p_rmdirs(const char *path);
689 static void pwrap_clean_stale_dirs(const char *dir)
691 size_t len = strlen(dir);
692 char pidfile[len + 5];
693 ssize_t rc;
694 char buf[8] = {0};
695 long int tmp;
696 pid_t pid;
697 int fd;
699 snprintf(pidfile,
700 sizeof(pidfile),
701 "%s/pid",
702 dir);
704 /* read the pidfile */
705 fd = open(pidfile, O_RDONLY);
706 if (fd < 0) {
707 if (errno == ENOENT) {
708 PWRAP_LOG(PWRAP_LOG_TRACE,
709 "pidfile %s missing, nothing to do\n",
710 pidfile);
711 } else {
712 PWRAP_LOG(PWRAP_LOG_ERROR,
713 "Failed to open pidfile %s - error: %s",
714 pidfile, strerror(errno));
716 return;
719 rc = read(fd, buf, sizeof(buf));
720 close(fd);
721 if (rc < 0) {
722 PWRAP_LOG(PWRAP_LOG_ERROR,
723 "Failed to read pidfile %s - error: %s",
724 pidfile, strerror(errno));
725 return;
728 buf[sizeof(buf) - 1] = '\0';
730 tmp = strtol(buf, NULL, 10);
731 if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
732 PWRAP_LOG(PWRAP_LOG_ERROR,
733 "Failed to parse pid, buf=%s",
734 buf);
735 return;
738 pid = (pid_t)(tmp & 0xFFFF);
740 rc = kill(pid, 0);
741 if (rc == -1) {
742 PWRAP_LOG(PWRAP_LOG_TRACE,
743 "Remove stale pam_wrapper dir: %s",
744 dir);
745 p_rmdirs(dir);
748 return;
751 static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
753 int srcfd = -1;
754 int dstfd = -1;
755 int rc = -1;
756 ssize_t bread, bwritten;
757 struct stat sb;
758 char buf[10];
759 int cmp;
760 size_t to_read;
761 bool found_slash;
763 cmp = strcmp(src, dst);
764 if (cmp == 0) {
765 return -1;
768 srcfd = open(src, O_RDONLY, 0);
769 if (srcfd < 0) {
770 return -1;
773 if (mode == 0) {
774 rc = fstat(srcfd, &sb);
775 if (rc != 0) {
776 rc = -1;
777 goto out;
779 mode = sb.st_mode;
782 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
783 if (dstfd < 0) {
784 rc = -1;
785 goto out;
788 found_slash = false;
789 to_read = 1;
791 for (;;) {
792 bread = read(srcfd, buf, to_read);
793 if (bread == 0) {
794 /* done */
795 break;
796 } else if (bread < 0) {
797 errno = EIO;
798 rc = -1;
799 goto out;
802 to_read = 1;
803 if (!found_slash && buf[0] == '/') {
804 found_slash = true;
805 to_read = 9;
808 if (found_slash && bread == 9) {
809 cmp = memcmp(buf, "etc/pam.d", 9);
810 if (cmp == 0) {
811 memcpy(buf, pdir + 1, 9);
813 found_slash = false;
816 bwritten = write(dstfd, buf, bread);
817 if (bwritten < 0) {
818 errno = EIO;
819 rc = -1;
820 goto out;
823 if (bread != bwritten) {
824 errno = EFAULT;
825 rc = -1;
826 goto out;
830 rc = 0;
831 out:
832 if (srcfd != -1) {
833 close(srcfd);
835 if (dstfd != -1) {
836 close(dstfd);
838 if (rc < 0) {
839 unlink(dst);
842 return rc;
845 static void pwrap_init(void)
847 char tmp_config_dir[] = "/tmp/pam.X";
848 size_t len = strlen(tmp_config_dir);
849 const char *env;
850 struct stat sb;
851 int rc;
852 unsigned i;
853 char pam_library[128] = { 0 };
854 char libpam_path[1024] = { 0 };
855 ssize_t ret;
856 FILE *pidfile;
857 char pidfile_path[1024] = { 0 };
858 char letter;
860 if (!pam_wrapper_enabled()) {
861 return;
864 if (pwrap.initialised) {
865 return;
869 * The name is selected to match/replace /etc/pam.d
870 * We start from a random alphanum trying letters until
871 * an available directory is found.
873 letter = 48 + (getpid() % 70);
874 for (i = 0; i < 127; i++) {
875 if (isalpha(letter) || isdigit(letter)) {
876 tmp_config_dir[len - 1] = letter;
878 rc = lstat(tmp_config_dir, &sb);
879 if (rc == 0) {
880 PWRAP_LOG(PWRAP_LOG_TRACE,
881 "Check if pam_wrapper dir %s is a "
882 "stale directory",
883 tmp_config_dir);
884 pwrap_clean_stale_dirs(tmp_config_dir);
885 } else if (rc < 0) {
886 if (errno != ENOENT) {
887 continue;
889 break; /* found */
893 letter++;
894 letter %= 127;
897 if (i == 127) {
898 PWRAP_LOG(PWRAP_LOG_ERROR,
899 "Failed to find a possible path to create "
900 "pam_wrapper config dir: %s",
901 tmp_config_dir);
902 exit(1);
905 PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
907 pwrap.config_dir = strdup(tmp_config_dir);
908 if (pwrap.config_dir == NULL) {
909 PWRAP_LOG(PWRAP_LOG_ERROR,
910 "No memory");
911 exit(1);
913 PWRAP_LOG(PWRAP_LOG_TRACE,
914 "pam_wrapper config dir: %s",
915 tmp_config_dir);
917 rc = mkdir(pwrap.config_dir, 0755);
918 if (rc != 0) {
919 PWRAP_LOG(PWRAP_LOG_ERROR,
920 "Failed to create pam_wrapper config dir: %s - %s",
921 tmp_config_dir, strerror(errno));
924 /* Create file with the PID of the the process */
925 ret = snprintf(pidfile_path, sizeof(pidfile_path),
926 "%s/pid", pwrap.config_dir);
927 if (ret < 0) {
928 p_rmdirs(pwrap.config_dir);
929 exit(1);
932 pidfile = fopen(pidfile_path, "w");
933 if (pidfile == NULL) {
934 p_rmdirs(pwrap.config_dir);
935 exit(1);
938 rc = fprintf(pidfile, "%d", getpid());
939 fclose(pidfile);
940 if (rc <= 0) {
941 p_rmdirs(pwrap.config_dir);
942 exit(1);
945 /* create lib subdirectory */
946 snprintf(libpam_path,
947 sizeof(libpam_path),
948 "%s/lib",
949 pwrap.config_dir);
951 rc = mkdir(libpam_path, 0755);
952 if (rc != 0) {
953 PWRAP_LOG(PWRAP_LOG_ERROR,
954 "Failed to create path for libpam: %s - %s",
955 tmp_config_dir, strerror(errno));
956 p_rmdirs(pwrap.config_dir);
957 exit(1);
960 snprintf(libpam_path,
961 sizeof(libpam_path),
962 "%s/lib/%s",
963 pwrap.config_dir,
964 LIBPAM_NAME);
966 pwrap.libpam_so = strdup(libpam_path);
967 if (pwrap.libpam_so == NULL) {
968 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
969 p_rmdirs(pwrap.config_dir);
970 exit(1);
973 /* copy libpam.so.0 */
974 snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
975 PWRAP_LOG(PWRAP_LOG_TRACE,
976 "PAM path: %s",
977 libpam_path);
979 ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
980 PWRAP_LOG(PWRAP_LOG_TRACE,
981 "PAM library: %s",
982 pam_library);
983 if (ret <= 0) {
984 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
985 p_rmdirs(pwrap.config_dir);
986 exit(1);
989 if (pam_library[0] == '/') {
990 snprintf(libpam_path,
991 sizeof(libpam_path),
992 "%s",
993 pam_library);
994 } else {
995 char libpam_path_cp[1024] = {0};
996 char *dname = NULL;
998 snprintf(libpam_path_cp,
999 sizeof(libpam_path_cp),
1000 "%s",
1001 libpam_path);
1003 dname = dirname(libpam_path_cp);
1004 if (dname == NULL) {
1005 PWRAP_LOG(PWRAP_LOG_ERROR,
1006 "No directory component in %s", libpam_path);
1007 p_rmdirs(pwrap.config_dir);
1008 exit(1);
1011 snprintf(libpam_path,
1012 sizeof(libpam_path),
1013 "%s/%s",
1014 dname,
1015 pam_library);
1017 PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
1019 PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
1020 rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
1021 if (rc != 0) {
1022 PWRAP_LOG(PWRAP_LOG_ERROR,
1023 "Failed to copy %s - error: %s",
1024 LIBPAM_NAME,
1025 strerror(errno));
1026 p_rmdirs(pwrap.config_dir);
1027 exit(1);
1030 pwrap.initialised = true;
1032 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1033 if (env == NULL) {
1034 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
1035 p_rmdirs(pwrap.config_dir);
1036 exit(1);
1039 rc = copy_confdir(env);
1040 if (rc != 0) {
1041 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
1042 p_rmdirs(pwrap.config_dir);
1043 exit(1);
1046 setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
1048 PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
1051 bool pam_wrapper_enabled(void)
1053 const char *env;
1055 pwrap.enabled = false;
1057 env = getenv("PAM_WRAPPER");
1058 if (env != NULL && env[0] == '1') {
1059 pwrap.enabled = true;
1062 if (pwrap.enabled) {
1063 pwrap.enabled = false;
1065 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1066 if (env != NULL && env[0] != '\0') {
1067 pwrap.enabled = true;
1071 return pwrap.enabled;
1074 /****************************
1075 * CONSTRUCTOR
1076 ***************************/
1077 void pwrap_constructor(void)
1080 * Here is safe place to call pwrap_init() and initialize data
1081 * for main process.
1083 pwrap_init();
1087 #ifdef HAVE_OPENPAM
1088 static int pwrap_openpam_start(const char *service_name,
1089 const char *user,
1090 const struct pam_conv *pam_conversation,
1091 pam_handle_t **pamh)
1093 int rv;
1094 char fullpath[1024];
1096 rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1097 if (rv != PAM_SUCCESS) {
1098 PWRAP_LOG(PWRAP_LOG_ERROR,
1099 "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1100 return rv;
1103 rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1104 if (rv != PAM_SUCCESS) {
1105 PWRAP_LOG(PWRAP_LOG_ERROR,
1106 "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1107 return rv;
1110 rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1111 if (rv != PAM_SUCCESS) {
1112 PWRAP_LOG(PWRAP_LOG_ERROR,
1113 "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1114 return rv;
1117 rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1118 if (rv != PAM_SUCCESS) {
1119 PWRAP_LOG(PWRAP_LOG_ERROR,
1120 "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1121 return rv;
1124 snprintf(fullpath,
1125 sizeof(fullpath),
1126 "%s/%s",
1127 pwrap.config_dir,
1128 service_name);
1130 return libpam_pam_start(fullpath,
1131 user,
1132 pam_conversation,
1133 pamh);
1135 #endif
1137 static int pwrap_pam_start(const char *service_name,
1138 const char *user,
1139 const struct pam_conv *pam_conversation,
1140 pam_handle_t **pamh)
1142 PWRAP_LOG(PWRAP_LOG_TRACE,
1143 "pam_start service=%s, user=%s",
1144 service_name,
1145 user);
1147 #ifdef HAVE_OPENPAM
1148 return pwrap_openpam_start(service_name,
1149 user,
1150 pam_conversation,
1151 pamh);
1152 #else
1153 return libpam_pam_start(service_name,
1154 user,
1155 pam_conversation,
1156 pamh);
1157 #endif
1161 int pam_start(const char *service_name,
1162 const char *user,
1163 const struct pam_conv *pam_conversation,
1164 pam_handle_t **pamh)
1166 return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1169 static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1171 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1172 return libpam_pam_end(pamh, pam_status);
1176 int pam_end(pam_handle_t *pamh, int pam_status)
1178 return pwrap_pam_end(pamh, pam_status);
1181 static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1183 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1184 return libpam_pam_authenticate(pamh, flags);
1187 int pam_authenticate(pam_handle_t *pamh, int flags)
1189 return pwrap_pam_authenticate(pamh, flags);
1192 static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1194 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1195 return libpam_pam_chauthtok(pamh, flags);
1198 int pam_chauthtok(pam_handle_t *pamh, int flags)
1200 return pwrap_pam_chauthtok(pamh, flags);
1203 static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1205 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1206 return libpam_pam_acct_mgmt(pamh, flags);
1209 int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1211 return pwrap_pam_acct_mgmt(pamh, flags);
1214 static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1216 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1217 return libpam_pam_putenv(pamh, name_value);
1220 int pam_putenv(pam_handle_t *pamh, const char *name_value)
1222 return pwrap_pam_putenv(pamh, name_value);
1225 static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1227 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1228 return libpam_pam_getenv(pamh, name);
1231 const char *pam_getenv(pam_handle_t *pamh, const char *name)
1233 return pwrap_pam_getenv(pamh, name);
1236 static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1238 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1239 return libpam_pam_getenvlist(pamh);
1242 char **pam_getenvlist(pam_handle_t *pamh)
1244 return pwrap_pam_getenvlist(pamh);
1247 static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1249 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1250 return libpam_pam_open_session(pamh, flags);
1253 int pam_open_session(pam_handle_t *pamh, int flags)
1255 return pwrap_pam_open_session(pamh, flags);
1258 static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1260 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1261 return libpam_pam_close_session(pamh, flags);
1264 int pam_close_session(pam_handle_t *pamh, int flags)
1266 return pwrap_pam_close_session(pamh, flags);
1269 static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1271 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1272 return libpam_pam_setcred(pamh, flags);
1275 int pam_setcred(pam_handle_t *pamh, int flags)
1277 return pwrap_pam_setcred(pamh, flags);
1280 static const char *pwrap_get_service(const char *libpam_service)
1282 #ifdef HAVE_OPENPAM
1283 const char *service_name;
1285 PWRAP_LOG(PWRAP_LOG_TRACE,
1286 "internal PAM_SERVICE=%s", libpam_service);
1287 service_name = strrchr(libpam_service, '/');
1288 if (service_name != NULL && service_name[0] == '/') {
1289 service_name++;
1291 PWRAP_LOG(PWRAP_LOG_TRACE,
1292 "PAM_SERVICE=%s", service_name);
1293 return service_name;
1294 #else
1295 return libpam_service;
1296 #endif
1299 static int pwrap_pam_get_item(const pam_handle_t *pamh,
1300 int item_type,
1301 const void **item)
1303 int rc;
1304 const char *svc;
1306 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1308 rc = libpam_pam_get_item(pamh, item_type, item);
1310 if (rc == PAM_SUCCESS) {
1311 switch(item_type) {
1312 case PAM_USER:
1313 PWRAP_LOG(PWRAP_LOG_TRACE,
1314 "pwrap_get_item PAM_USER=%s",
1315 (const char *)*item);
1316 break;
1317 case PAM_SERVICE:
1318 svc = pwrap_get_service((const char *) *item);
1320 PWRAP_LOG(PWRAP_LOG_TRACE,
1321 "pwrap_get_item PAM_SERVICE=%s",
1322 svc);
1323 *item = svc;
1324 break;
1325 case PAM_USER_PROMPT:
1326 PWRAP_LOG(PWRAP_LOG_TRACE,
1327 "pwrap_get_item PAM_USER_PROMPT=%s",
1328 (const char *)*item);
1329 break;
1330 case PAM_TTY:
1331 PWRAP_LOG(PWRAP_LOG_TRACE,
1332 "pwrap_get_item PAM_TTY=%s",
1333 (const char *)*item);
1334 break;
1335 case PAM_RUSER:
1336 PWRAP_LOG(PWRAP_LOG_TRACE,
1337 "pwrap_get_item PAM_RUSER=%s",
1338 (const char *)*item);
1339 break;
1340 case PAM_RHOST:
1341 PWRAP_LOG(PWRAP_LOG_TRACE,
1342 "pwrap_get_item PAM_RHOST=%s",
1343 (const char *)*item);
1344 break;
1345 case PAM_AUTHTOK:
1346 PWRAP_LOG(PWRAP_LOG_TRACE,
1347 "pwrap_get_item PAM_AUTHTOK=%s",
1348 (const char *)*item);
1349 break;
1350 case PAM_OLDAUTHTOK:
1351 PWRAP_LOG(PWRAP_LOG_TRACE,
1352 "pwrap_get_item PAM_OLDAUTHTOK=%s",
1353 (const char *)*item);
1354 break;
1355 case PAM_CONV:
1356 PWRAP_LOG(PWRAP_LOG_TRACE,
1357 "pwrap_get_item PAM_CONV=%p",
1358 (const void *)*item);
1359 break;
1360 default:
1361 PWRAP_LOG(PWRAP_LOG_TRACE,
1362 "pwrap_get_item item_type=%d item=%p",
1363 item_type, (const void *)*item);
1364 break;
1366 } else {
1367 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1370 return rc;
1373 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1375 return pwrap_pam_get_item(pamh, item_type, item);
1378 static int pwrap_pam_set_item(pam_handle_t *pamh,
1379 int item_type,
1380 const void *item)
1382 int rc;
1384 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1386 rc = libpam_pam_set_item(pamh, item_type, item);
1387 if (rc == PAM_SUCCESS) {
1388 switch(item_type) {
1389 case PAM_USER:
1390 PWRAP_LOG(PWRAP_LOG_TRACE,
1391 "pwrap_set_item PAM_USER=%s",
1392 (const char *)item);
1393 break;
1394 case PAM_SERVICE:
1395 PWRAP_LOG(PWRAP_LOG_TRACE,
1396 "pwrap_set_item PAM_SERVICE=%s",
1397 (const char *)item);
1398 break;
1399 case PAM_USER_PROMPT:
1400 PWRAP_LOG(PWRAP_LOG_TRACE,
1401 "pwrap_set_item PAM_USER_PROMPT=%s",
1402 (const char *)item);
1403 break;
1404 case PAM_TTY:
1405 PWRAP_LOG(PWRAP_LOG_TRACE,
1406 "pwrap_set_item PAM_TTY=%s",
1407 (const char *)item);
1408 break;
1409 case PAM_RUSER:
1410 PWRAP_LOG(PWRAP_LOG_TRACE,
1411 "pwrap_set_item PAM_RUSER=%s",
1412 (const char *)item);
1413 break;
1414 case PAM_RHOST:
1415 PWRAP_LOG(PWRAP_LOG_TRACE,
1416 "pwrap_set_item PAM_RHOST=%s",
1417 (const char *)item);
1418 break;
1419 case PAM_AUTHTOK:
1420 PWRAP_LOG(PWRAP_LOG_TRACE,
1421 "pwrap_set_item PAM_AUTHTOK=%s",
1422 (const char *)item);
1423 break;
1424 case PAM_OLDAUTHTOK:
1425 PWRAP_LOG(PWRAP_LOG_TRACE,
1426 "pwrap_set_item PAM_OLDAUTHTOK=%s",
1427 (const char *)item);
1428 break;
1429 case PAM_CONV:
1430 PWRAP_LOG(PWRAP_LOG_TRACE,
1431 "pwrap_set_item PAM_CONV=%p",
1432 item);
1433 break;
1434 default:
1435 PWRAP_LOG(PWRAP_LOG_TRACE,
1436 "pwrap_set_item item_type=%d item=%p",
1437 item_type, item);
1438 break;
1440 } else {
1441 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1444 return rc;
1447 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1449 return pwrap_pam_set_item(pamh, item_type, item);
1452 static int pwrap_pam_get_data(const pam_handle_t *pamh,
1453 const char *module_data_name,
1454 const void **data)
1456 PWRAP_LOG(PWRAP_LOG_TRACE,
1457 "pwrap_get_data module_data_name=%s", module_data_name);
1458 return libpam_pam_get_data(pamh, module_data_name, data);
1461 int pam_get_data(const pam_handle_t *pamh,
1462 const char *module_data_name,
1463 const void **data)
1465 return pwrap_pam_get_data(pamh, module_data_name, data);
1468 static int pwrap_pam_set_data(pam_handle_t *pamh,
1469 const char *module_data_name,
1470 void *data,
1471 void (*cleanup)(pam_handle_t *pamh,
1472 void *data,
1473 int error_status))
1475 PWRAP_LOG(PWRAP_LOG_TRACE,
1476 "pwrap_set_data module_data_name=%s data=%p",
1477 module_data_name, data);
1478 return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1481 int pam_set_data(pam_handle_t *pamh,
1482 const char *module_data_name,
1483 void *data,
1484 void (*cleanup)(pam_handle_t *pamh,
1485 void *data,
1486 int error_status))
1488 return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1491 #ifdef HAVE_PAM_VPROMPT_CONST
1492 static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1493 #else
1494 static int pwrap_pam_vprompt(pam_handle_t *pamh,
1495 #endif
1496 int style,
1497 char **response,
1498 const char *fmt,
1499 va_list args)
1501 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1502 return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1503 style,
1504 response,
1505 fmt,
1506 args);
1509 #ifdef HAVE_PAM_VPROMPT_CONST
1510 int pam_vprompt(const pam_handle_t *pamh,
1511 int style,
1512 char **response,
1513 const char *fmt,
1514 va_list args)
1515 #else
1516 int pam_vprompt(pam_handle_t *pamh,
1517 int style,
1518 char **response,
1519 const char *fmt,
1520 va_list args)
1521 #endif
1523 return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1524 style,
1525 response,
1526 fmt,
1527 args);
1530 #ifdef HAVE_PAM_PROMPT_CONST
1531 int pam_prompt(const pam_handle_t *pamh,
1532 int style,
1533 char **response,
1534 const char *fmt, ...)
1535 #else
1536 int pam_prompt(pam_handle_t *pamh,
1537 int style,
1538 char **response,
1539 const char *fmt, ...)
1540 #endif
1542 va_list args;
1543 int rv;
1545 va_start(args, fmt);
1546 rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1547 style,
1548 response,
1549 fmt,
1550 args);
1551 va_end(args);
1553 return rv;
1556 #ifdef HAVE_PAM_STRERROR_CONST
1557 static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1558 #else
1559 static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1560 #endif
1562 const char *str;
1564 pwrap_init();
1566 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1568 str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1569 errnum);
1571 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1573 return str;
1576 #ifdef HAVE_PAM_STRERROR_CONST
1577 const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1578 #else
1579 const char *pam_strerror(pam_handle_t *pamh, int errnum)
1580 #endif
1582 return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1583 errnum);
1586 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1587 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1588 int priority,
1589 const char *fmt,
1590 va_list args) PRINTF_ATTRIBUTE(3, 0);
1592 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1593 int priority,
1594 const char *fmt,
1595 va_list args)
1597 const char *d;
1598 char syslog_str[32] = {0};
1599 enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1601 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1603 #ifdef HAVE_PAM_VSYSLOG
1604 d = getenv("PAM_WRAPPER_USE_SYSLOG");
1605 if (d != NULL && d[0] == '1') {
1606 libpam_pam_vsyslog(pamh, priority, fmt, args);
1607 return;
1609 #endif /* HAVE_PAM_VSYSLOG */
1611 switch(priority) {
1612 case 0: /* LOG_EMERG */
1613 case 1: /* LOG_ALERT */
1614 case 2: /* LOG_CRIT */
1615 case 3: /* LOG_ERR */
1616 dbglvl = PWRAP_LOG_ERROR;
1617 break;
1618 case 4: /* LOG_WARN */
1619 dbglvl = PWRAP_LOG_WARN;
1620 break;
1621 case 5: /* LOG_NOTICE */
1622 case 6: /* LOG_INFO */
1623 case 7: /* LOG_DEBUG */
1624 dbglvl = PWRAP_LOG_DEBUG;
1625 break;
1626 default:
1627 dbglvl = PWRAP_LOG_TRACE;
1628 break;
1631 snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1633 pwrap_vlog(dbglvl, syslog_str, fmt, args);
1635 #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1637 #ifdef HAVE_PAM_VSYSLOG
1638 void pam_vsyslog(const pam_handle_t *pamh,
1639 int priority,
1640 const char *fmt,
1641 va_list args)
1643 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1645 #endif
1647 #ifdef HAVE_PAM_SYSLOG
1648 void pam_syslog(const pam_handle_t *pamh,
1649 int priority,
1650 const char *fmt, ...)
1652 va_list args;
1654 va_start(args, fmt);
1655 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1656 va_end(args);
1658 #endif
1660 /* This might be called by pam_end() running with sshd */
1661 int audit_open(void);
1662 int audit_open(void)
1665 * Tell the application that the kernel doesn't
1666 * have audit compiled in.
1668 errno = EPROTONOSUPPORT;
1669 return -1;
1672 /* Disable BSD auditing */
1673 int cannot_audit(int x);
1674 int cannot_audit(int x)
1676 (void) x;
1678 return 1;
1681 /****************************
1682 * DESTRUCTOR
1683 ***************************/
1685 static int p_rmdirs_at(const char *path, int parent_fd)
1687 DIR *d;
1688 struct dirent *dp;
1689 struct stat sb;
1690 int path_fd;
1691 int rc;
1693 /* If path is absolute, parent_fd is ignored. */
1694 PWRAP_LOG(PWRAP_LOG_TRACE,
1695 "p_rmdirs_at removing %s at %d\n", path, parent_fd);
1697 path_fd = openat(parent_fd,
1698 path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1699 if (path_fd == -1) {
1700 return -1;
1703 d = fdopendir(path_fd);
1704 if (d == NULL) {
1705 close(path_fd);
1706 return -1;
1709 while ((dp = readdir(d)) != NULL) {
1710 /* skip '.' and '..' */
1711 if (dp->d_name[0] == '.' &&
1712 (dp->d_name[1] == '\0' ||
1713 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
1714 continue;
1717 rc = fstatat(path_fd, dp->d_name,
1718 &sb, AT_SYMLINK_NOFOLLOW);
1719 if (rc != 0) {
1720 continue;
1723 if (S_ISDIR(sb.st_mode)) {
1724 rc = p_rmdirs_at(dp->d_name, path_fd);
1725 } else {
1726 rc = unlinkat(path_fd, dp->d_name, 0);
1728 if (rc != 0) {
1729 continue;
1732 closedir(d);
1734 rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
1735 if (rc != 0) {
1736 rc = errno;
1737 PWRAP_LOG(PWRAP_LOG_TRACE,
1738 "cannot unlink %s error %d\n", path, rc);
1739 return -1;
1742 return 0;
1745 static int p_rmdirs(const char *path)
1748 * If path is absolute, p_rmdirs_at ignores parent_fd.
1749 * If it's relative, start from cwd.
1751 return p_rmdirs_at(path, AT_FDCWD);
1755 * This function is called when the library is unloaded and makes sure that
1756 * resources are freed.
1758 void pwrap_destructor(void)
1760 const char *env;
1762 PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
1764 if (pwrap.libpam.handle != NULL) {
1765 dlclose(pwrap.libpam.handle);
1768 if (pwrap.libpam_so != NULL) {
1769 free(pwrap.libpam_so);
1770 pwrap.libpam_so = NULL;
1773 if (!pwrap.initialised) {
1774 return;
1777 PWRAP_LOG(PWRAP_LOG_TRACE,
1778 "destructor called for pam_wrapper dir %s",
1779 pwrap.config_dir);
1780 env = getenv("PAM_WRAPPER_KEEP_DIR");
1781 if (env == NULL || env[0] != '1') {
1782 p_rmdirs(pwrap.config_dir);
1785 if (pwrap.config_dir != NULL) {
1786 free(pwrap.config_dir);
1787 pwrap.config_dir = NULL;