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/>.
28 #include <sys/types.h>
41 #ifdef HAVE_SECURITY_PAM_APPL_H
42 #include <security/pam_appl.h>
44 #ifdef HAVE_SECURITY_PAM_MODULES_H
45 #include <security/pam_modules.h>
47 #ifdef HAVE_SECURITY_PAM_EXT_H
48 #include <security/pam_ext.h>
51 #include "pwrap_compat.h"
53 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
54 # define PWRAP_THREAD __thread
59 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
60 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
62 #define CONSTRUCTOR_ATTRIBUTE
63 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
65 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
66 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
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)))
81 #define PRINTF_ATTRIBUTE(a,b)
82 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
85 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
89 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
92 #ifndef discard_const_p
93 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
100 enum pwrap_dbglvl_e
{
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
,
115 va_list args
) PRINTF_ATTRIBUTE(3, 0);
117 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl
,
118 const char *function
,
124 unsigned int lvl
= 0;
125 const char *prefix
= "PWRAP";
127 d
= getenv("PAM_WRAPPER_DEBUGLEVEL");
136 vsnprintf(buffer
, sizeof(buffer
), format
, args
);
139 case PWRAP_LOG_ERROR
:
140 prefix
= "PWRAP_ERROR";
143 prefix
= "PWRAP_WARN";
145 case PWRAP_LOG_DEBUG
:
146 prefix
= "PWRAP_DEBUG";
148 case PWRAP_LOG_TRACE
:
149 prefix
= "PWRAP_TRACE";
161 static void pwrap_log(enum pwrap_dbglvl_e dbglvl
,
162 const char *function
,
163 const char *format
, ...)
167 va_start(va
, format
);
168 pwrap_vlog(dbglvl
, function
, format
, va
);
176 #define LIBPAM_NAME "libpam.so.0"
178 typedef int (*__libpam_pam_start
)(const char *service_name
,
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
,
207 typedef int (*__libpam_pam_set_item
)(pam_handle_t
*pamh
,
211 typedef int (*__libpam_pam_get_data
)(const pam_handle_t
*pamh
,
212 const char *module_data_name
,
215 typedef int (*__libpam_pam_set_data
)(pam_handle_t
*pamh
,
216 const char *module_data_name
,
218 void (*cleanup
)(pam_handle_t
*pamh
,
222 typedef int (*__libpam_pam_vprompt
)(pam_handle_t
*pamh
,
228 typedef const char * (*__libpam_pam_strerror
)(pam_handle_t
*pamh
,
231 #ifdef HAVE_PAM_VSYSLOG
232 typedef void (*__libpam_pam_vsyslog
)(const pam_handle_t
*pamh
,
238 #define PWRAP_SYMBOL_ENTRY(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
);
270 struct pwrap_libpam_symbols symbols
;
279 static struct pwrap pwrap
;
281 /*********************************************************
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 *********************************************************/
297 static void *pwrap_load_lib_handle(enum pwrap_lib lib
)
299 int flags
= RTLD_LAZY
;
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");
309 flags
|= RTLD_DEEPBIND
;
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
;
329 if (handle
== NULL
) {
330 PWRAP_LOG(PWRAP_LOG_ERROR
,
331 "Failed to dlopen library: %s\n",
339 static void *_pwrap_bind_symbol(enum pwrap_lib lib
, const char *fn_name
)
344 handle
= pwrap_load_lib_handle(lib
);
346 func
= dlsym(handle
, fn_name
);
348 PWRAP_LOG(PWRAP_LOG_ERROR
,
349 "Failed to find %s: %s\n",
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); \
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
,
373 const struct pam_conv
*pam_conversation
,
376 pwrap_bind_symbol_libpam(pam_start
);
378 return pwrap
.libpam
.symbols
._libpam_pam_start
.f(service_name
,
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
,
472 pwrap_bind_symbol_libpam(pam_get_data
);
474 return pwrap
.libpam
.symbols
._libpam_pam_get_data
.f(pamh
,
479 static int libpam_pam_set_data(pam_handle_t
*pamh
,
480 const char *module_data_name
,
482 void (*cleanup
)(pam_handle_t
*pamh
,
486 pwrap_bind_symbol_libpam(pam_set_data
);
488 return pwrap
.libpam
.symbols
._libpam_pam_set_data
.f(pamh
,
494 static int libpam_pam_vprompt(pam_handle_t
*pamh
,
500 pwrap_bind_symbol_libpam(pam_vprompt
);
502 return pwrap
.libpam
.symbols
._libpam_pam_vprompt
.f(pamh
,
509 #ifdef HAVE_PAM_STRERROR_CONST
510 static const char *libpam_pam_strerror(const pam_handle_t
*pamh
, int errnum
)
512 static const char *libpam_pam_strerror(pam_handle_t
*pamh
, int errnum
)
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
,
526 pwrap_bind_symbol_libpam(pam_vsyslog
);
528 pwrap
.libpam
.symbols
._libpam_pam_vsyslog
.f(pamh
,
533 #endif /* HAVE_PAM_VSYSLOG */
535 /*********************************************************
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
)
547 ssize_t bread
, bwritten
;
549 char buf
[BUFFER_SIZE
];
552 cmp
= strcmp(src
, dst
);
557 srcfd
= open(src
, O_RDONLY
, 0);
563 rc
= fstat(srcfd
, &sb
);
571 dstfd
= open(dst
, O_CREAT
|O_WRONLY
|O_TRUNC
, mode
);
578 bread
= read(srcfd
, buf
, BUFFER_SIZE
);
582 } else if (bread
< 0) {
588 bwritten
= write(dstfd
, buf
, bread
);
595 if (bread
!= bwritten
) {
617 /* Do not pass any flag if not defined */
618 #ifndef FTW_ACTIONRETVAL
619 #define FTW_ACTIONRETVAL 0
622 /* Action return values */
628 #define FTW_CONTINUE 0
631 #ifndef FTW_SKIP_SUBTREE
632 #define FTW_SKIP_SUBTREE 0
635 static int copy_ftw(const char *fpath
,
636 const struct stat
*sb
,
641 char buf
[BUFFER_SIZE
];
646 /* We want to copy the directories from this directory */
647 if (ftwbuf
->level
== 0) {
650 return FTW_SKIP_SUBTREE
;
657 rc
= snprintf(buf
, BUFFER_SIZE
, "%s/%s", pwrap
.config_dir
, fpath
+ ftwbuf
->base
);
658 if (rc
>= BUFFER_SIZE
) {
662 PWRAP_LOG(PWRAP_LOG_TRACE
, "Copying %s", fpath
);
663 rc
= p_copy(fpath
, buf
, sb
->st_mode
);
671 static int copy_confdir(const char *src
)
675 PWRAP_LOG(PWRAP_LOG_DEBUG
,
676 "Copy config files from %s to %s",
679 rc
= nftw(src
, copy_ftw
, 1, FTW_ACTIONRETVAL
);
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];
704 /* read the pidfile */
705 fd
= open(pidfile
, O_RDONLY
);
707 if (errno
== ENOENT
) {
708 PWRAP_LOG(PWRAP_LOG_TRACE
,
709 "pidfile %s missing, nothing to do\n",
712 PWRAP_LOG(PWRAP_LOG_ERROR
,
713 "Failed to open pidfile %s - error: %s",
714 pidfile
, strerror(errno
));
719 rc
= read(fd
, buf
, sizeof(buf
));
722 PWRAP_LOG(PWRAP_LOG_ERROR
,
723 "Failed to read pidfile %s - error: %s",
724 pidfile
, strerror(errno
));
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",
738 pid
= (pid_t
)(tmp
& 0xFFFF);
742 PWRAP_LOG(PWRAP_LOG_TRACE
,
743 "Remove stale pam_wrapper dir: %s",
751 static int pso_copy(const char *src
, const char *dst
, const char *pdir
, mode_t mode
)
756 ssize_t bread
, bwritten
;
763 cmp
= strcmp(src
, dst
);
768 srcfd
= open(src
, O_RDONLY
, 0);
774 rc
= fstat(srcfd
, &sb
);
782 dstfd
= open(dst
, O_CREAT
|O_WRONLY
|O_TRUNC
, mode
);
792 bread
= read(srcfd
, buf
, to_read
);
796 } else if (bread
< 0) {
803 if (!found_slash
&& buf
[0] == '/') {
808 if (found_slash
&& bread
== 9) {
809 cmp
= memcmp(buf
, "etc/pam.d", 9);
811 memcpy(buf
, pdir
+ 1, 9);
816 bwritten
= write(dstfd
, buf
, bread
);
823 if (bread
!= bwritten
) {
845 static void pwrap_init(void)
847 char tmp_config_dir
[] = "/tmp/pam.X";
848 size_t len
= strlen(tmp_config_dir
);
853 char pam_library
[128] = { 0 };
854 char libpam_path
[1024] = { 0 };
857 char pidfile_path
[1024] = { 0 };
860 if (!pam_wrapper_enabled()) {
864 if (pwrap
.initialised
) {
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
);
880 PWRAP_LOG(PWRAP_LOG_TRACE
,
881 "Check if pam_wrapper dir %s is a "
884 pwrap_clean_stale_dirs(tmp_config_dir
);
886 if (errno
!= ENOENT
) {
898 PWRAP_LOG(PWRAP_LOG_ERROR
,
899 "Failed to find a possible path to create "
900 "pam_wrapper config dir: %s",
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
,
913 PWRAP_LOG(PWRAP_LOG_TRACE
,
914 "pam_wrapper config dir: %s",
917 rc
= mkdir(pwrap
.config_dir
, 0755);
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
);
928 p_rmdirs(pwrap
.config_dir
);
932 pidfile
= fopen(pidfile_path
, "w");
933 if (pidfile
== NULL
) {
934 p_rmdirs(pwrap
.config_dir
);
938 rc
= fprintf(pidfile
, "%d", getpid());
941 p_rmdirs(pwrap
.config_dir
);
945 /* create lib subdirectory */
946 snprintf(libpam_path
,
951 rc
= mkdir(libpam_path
, 0755);
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
);
960 snprintf(libpam_path
,
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
);
973 /* copy libpam.so.0 */
974 snprintf(libpam_path
, sizeof(libpam_path
), "%s", PAM_LIBRARY
);
975 PWRAP_LOG(PWRAP_LOG_TRACE
,
979 ret
= readlink(libpam_path
, pam_library
, sizeof(pam_library
) - 1);
980 PWRAP_LOG(PWRAP_LOG_TRACE
,
984 PWRAP_LOG(PWRAP_LOG_ERROR
, "Failed to read %s link", LIBPAM_NAME
);
985 p_rmdirs(pwrap
.config_dir
);
989 if (pam_library
[0] == '/') {
990 snprintf(libpam_path
,
995 char libpam_path_cp
[1024] = {0};
998 snprintf(libpam_path_cp
,
999 sizeof(libpam_path_cp
),
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
);
1011 snprintf(libpam_path
,
1012 sizeof(libpam_path
),
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);
1022 PWRAP_LOG(PWRAP_LOG_ERROR
,
1023 "Failed to copy %s - error: %s",
1026 p_rmdirs(pwrap
.config_dir
);
1030 pwrap
.initialised
= true;
1032 env
= getenv("PAM_WRAPPER_SERVICE_DIR");
1034 PWRAP_LOG(PWRAP_LOG_ERROR
, "No config file");
1035 p_rmdirs(pwrap
.config_dir
);
1039 rc
= copy_confdir(env
);
1041 PWRAP_LOG(PWRAP_LOG_ERROR
, "Failed to copy config files");
1042 p_rmdirs(pwrap
.config_dir
);
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)
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 /****************************
1076 ***************************/
1077 void pwrap_constructor(void)
1080 * Here is safe place to call pwrap_init() and initialize data
1088 static int pwrap_openpam_start(const char *service_name
,
1090 const struct pam_conv
*pam_conversation
,
1091 pam_handle_t
**pamh
)
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");
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");
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");
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");
1130 return libpam_pam_start(fullpath
,
1137 static int pwrap_pam_start(const char *service_name
,
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",
1148 return pwrap_openpam_start(service_name
,
1153 return libpam_pam_start(service_name
,
1161 int pam_start(const char *service_name
,
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
)
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] == '/') {
1291 PWRAP_LOG(PWRAP_LOG_TRACE
,
1292 "PAM_SERVICE=%s", service_name
);
1293 return service_name
;
1295 return libpam_service
;
1299 static int pwrap_pam_get_item(const pam_handle_t
*pamh
,
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
) {
1313 PWRAP_LOG(PWRAP_LOG_TRACE
,
1314 "pwrap_get_item PAM_USER=%s",
1315 (const char *)*item
);
1318 svc
= pwrap_get_service((const char *) *item
);
1320 PWRAP_LOG(PWRAP_LOG_TRACE
,
1321 "pwrap_get_item PAM_SERVICE=%s",
1325 case PAM_USER_PROMPT
:
1326 PWRAP_LOG(PWRAP_LOG_TRACE
,
1327 "pwrap_get_item PAM_USER_PROMPT=%s",
1328 (const char *)*item
);
1331 PWRAP_LOG(PWRAP_LOG_TRACE
,
1332 "pwrap_get_item PAM_TTY=%s",
1333 (const char *)*item
);
1336 PWRAP_LOG(PWRAP_LOG_TRACE
,
1337 "pwrap_get_item PAM_RUSER=%s",
1338 (const char *)*item
);
1341 PWRAP_LOG(PWRAP_LOG_TRACE
,
1342 "pwrap_get_item PAM_RHOST=%s",
1343 (const char *)*item
);
1346 PWRAP_LOG(PWRAP_LOG_TRACE
,
1347 "pwrap_get_item PAM_AUTHTOK=%s",
1348 (const char *)*item
);
1350 case PAM_OLDAUTHTOK
:
1351 PWRAP_LOG(PWRAP_LOG_TRACE
,
1352 "pwrap_get_item PAM_OLDAUTHTOK=%s",
1353 (const char *)*item
);
1356 PWRAP_LOG(PWRAP_LOG_TRACE
,
1357 "pwrap_get_item PAM_CONV=%p",
1358 (const void *)*item
);
1361 PWRAP_LOG(PWRAP_LOG_TRACE
,
1362 "pwrap_get_item item_type=%d item=%p",
1363 item_type
, (const void *)*item
);
1367 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_get_item failed rc=%d", 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
,
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
) {
1390 PWRAP_LOG(PWRAP_LOG_TRACE
,
1391 "pwrap_set_item PAM_USER=%s",
1392 (const char *)item
);
1395 PWRAP_LOG(PWRAP_LOG_TRACE
,
1396 "pwrap_set_item PAM_SERVICE=%s",
1397 (const char *)item
);
1399 case PAM_USER_PROMPT
:
1400 PWRAP_LOG(PWRAP_LOG_TRACE
,
1401 "pwrap_set_item PAM_USER_PROMPT=%s",
1402 (const char *)item
);
1405 PWRAP_LOG(PWRAP_LOG_TRACE
,
1406 "pwrap_set_item PAM_TTY=%s",
1407 (const char *)item
);
1410 PWRAP_LOG(PWRAP_LOG_TRACE
,
1411 "pwrap_set_item PAM_RUSER=%s",
1412 (const char *)item
);
1415 PWRAP_LOG(PWRAP_LOG_TRACE
,
1416 "pwrap_set_item PAM_RHOST=%s",
1417 (const char *)item
);
1420 PWRAP_LOG(PWRAP_LOG_TRACE
,
1421 "pwrap_set_item PAM_AUTHTOK=%s",
1422 (const char *)item
);
1424 case PAM_OLDAUTHTOK
:
1425 PWRAP_LOG(PWRAP_LOG_TRACE
,
1426 "pwrap_set_item PAM_OLDAUTHTOK=%s",
1427 (const char *)item
);
1430 PWRAP_LOG(PWRAP_LOG_TRACE
,
1431 "pwrap_set_item PAM_CONV=%p",
1435 PWRAP_LOG(PWRAP_LOG_TRACE
,
1436 "pwrap_set_item item_type=%d item=%p",
1441 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_set_item failed rc=%d", 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
,
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
,
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
,
1471 void (*cleanup
)(pam_handle_t
*pamh
,
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
,
1484 void (*cleanup
)(pam_handle_t
*pamh
,
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
,
1494 static int pwrap_pam_vprompt(pam_handle_t
*pamh
,
1501 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_pam_vprompt style=%d", style
);
1502 return libpam_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1509 #ifdef HAVE_PAM_VPROMPT_CONST
1510 int pam_vprompt(const pam_handle_t
*pamh
,
1516 int pam_vprompt(pam_handle_t
*pamh
,
1523 return pwrap_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1530 #ifdef HAVE_PAM_PROMPT_CONST
1531 int pam_prompt(const pam_handle_t
*pamh
,
1534 const char *fmt
, ...)
1536 int pam_prompt(pam_handle_t
*pamh
,
1539 const char *fmt
, ...)
1545 va_start(args
, fmt
);
1546 rv
= pwrap_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1556 #ifdef HAVE_PAM_STRERROR_CONST
1557 static const char *pwrap_pam_strerror(const pam_handle_t
*pamh
, int errnum
)
1559 static const char *pwrap_pam_strerror(pam_handle_t
*pamh
, int errnum
)
1566 PWRAP_LOG(PWRAP_LOG_TRACE
, "pam_strerror errnum=%d", errnum
);
1568 str
= libpam_pam_strerror(discard_const_p(pam_handle_t
, pamh
),
1571 PWRAP_LOG(PWRAP_LOG_TRACE
, "pam_strerror error=%s", str
);
1576 #ifdef HAVE_PAM_STRERROR_CONST
1577 const char *pam_strerror(const pam_handle_t
*pamh
, int errnum
)
1579 const char *pam_strerror(pam_handle_t
*pamh
, int errnum
)
1582 return pwrap_pam_strerror(discard_const_p(pam_handle_t
, pamh
),
1586 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1587 static void pwrap_pam_vsyslog(const pam_handle_t
*pamh
,
1590 va_list args
) PRINTF_ATTRIBUTE(3, 0);
1592 static void pwrap_pam_vsyslog(const pam_handle_t
*pamh
,
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
);
1609 #endif /* HAVE_PAM_VSYSLOG */
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
;
1618 case 4: /* LOG_WARN */
1619 dbglvl
= PWRAP_LOG_WARN
;
1621 case 5: /* LOG_NOTICE */
1622 case 6: /* LOG_INFO */
1623 case 7: /* LOG_DEBUG */
1624 dbglvl
= PWRAP_LOG_DEBUG
;
1627 dbglvl
= PWRAP_LOG_TRACE
;
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
,
1643 pwrap_pam_vsyslog(pamh
, priority
, fmt
, args
);
1647 #ifdef HAVE_PAM_SYSLOG
1648 void pam_syslog(const pam_handle_t
*pamh
,
1650 const char *fmt
, ...)
1654 va_start(args
, fmt
);
1655 pwrap_pam_vsyslog(pamh
, priority
, fmt
, args
);
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
;
1672 /* Disable BSD auditing */
1673 int cannot_audit(int x
);
1674 int cannot_audit(int x
)
1681 /****************************
1683 ***************************/
1685 static int p_rmdirs_at(const char *path
, int parent_fd
)
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) {
1703 d
= fdopendir(path_fd
);
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'))) {
1717 rc
= fstatat(path_fd
, dp
->d_name
,
1718 &sb
, AT_SYMLINK_NOFOLLOW
);
1723 if (S_ISDIR(sb
.st_mode
)) {
1724 rc
= p_rmdirs_at(dp
->d_name
, path_fd
);
1726 rc
= unlinkat(path_fd
, dp
->d_name
, 0);
1734 rc
= unlinkat(parent_fd
, path
, AT_REMOVEDIR
);
1737 PWRAP_LOG(PWRAP_LOG_TRACE
,
1738 "cannot unlink %s error %d\n", path
, rc
);
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)
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
) {
1777 PWRAP_LOG(PWRAP_LOG_TRACE
,
1778 "destructor called for pam_wrapper dir %s",
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
;