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>
43 #ifdef HAVE_SECURITY_PAM_APPL_H
44 #include <security/pam_appl.h>
46 #ifdef HAVE_SECURITY_PAM_MODULES_H
47 #include <security/pam_modules.h>
49 #ifdef HAVE_SECURITY_PAM_EXT_H
50 #include <security/pam_ext.h>
53 #include "pwrap_compat.h"
55 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
56 # define PWRAP_THREAD __thread
61 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
62 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
64 #define CONSTRUCTOR_ATTRIBUTE
65 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
67 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
68 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
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)))
83 #define PRINTF_ATTRIBUTE(a,b)
84 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
87 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
91 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
94 #ifndef discard_const_p
95 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
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();
111 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
113 #endif /* HAVE_GETPROGNAME */
115 enum pwrap_dbglvl_e
{
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
,
130 va_list args
) PRINTF_ATTRIBUTE(3, 0);
132 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl
,
133 const char *function
,
139 unsigned int lvl
= 0;
140 const char *prefix
= "PWRAP";
141 const char *progname
= getprogname();
143 d
= getenv("PAM_WRAPPER_DEBUGLEVEL");
152 vsnprintf(buffer
, sizeof(buffer
), format
, args
);
155 case PWRAP_LOG_ERROR
:
156 prefix
= "PWRAP_ERROR";
159 prefix
= "PWRAP_WARN";
161 case PWRAP_LOG_DEBUG
:
162 prefix
= "PWRAP_DEBUG";
164 case PWRAP_LOG_TRACE
:
165 prefix
= "PWRAP_TRACE";
169 if (progname
== NULL
) {
170 progname
= "<unknown>";
174 "%s[%s (%u)] - %s: %s\n",
177 (unsigned int)getpid(),
182 static void pwrap_log(enum pwrap_dbglvl_e dbglvl
,
183 const char *function
,
184 const char *format
, ...)
188 va_start(va
, format
);
189 pwrap_vlog(dbglvl
, function
, format
, va
);
197 #define LIBPAM_NAME "libpam.so.0"
199 typedef int (*__libpam_pam_start
)(const char *service_name
,
201 const struct pam_conv
*pam_conversation
,
202 pam_handle_t
**pamh
);
204 typedef int (*__libpam_pam_start_confdir
)(const char *service_name
,
206 const struct pam_conv
*pam_conversation
,
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
,
234 typedef int (*__libpam_pam_set_item
)(pam_handle_t
*pamh
,
238 typedef int (*__libpam_pam_get_data
)(const pam_handle_t
*pamh
,
239 const char *module_data_name
,
242 typedef int (*__libpam_pam_set_data
)(pam_handle_t
*pamh
,
243 const char *module_data_name
,
245 void (*cleanup
)(pam_handle_t
*pamh
,
249 typedef int (*__libpam_pam_vprompt
)(pam_handle_t
*pamh
,
255 typedef const char * (*__libpam_pam_strerror
)(pam_handle_t
*pamh
,
258 #ifdef HAVE_PAM_VSYSLOG
259 typedef void (*__libpam_pam_vsyslog
)(const pam_handle_t
*pamh
,
265 #define PWRAP_SYMBOL_ENTRY(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
);
298 struct pwrap_libpam_symbols symbols
;
307 static struct pwrap pwrap
;
309 /*********************************************************
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)
318 void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE
;
319 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
320 #pragma fini (pwrap_destructor)
322 void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE
;
324 /*********************************************************
325 * PWRAP LIBC LOADER FUNCTIONS
326 *********************************************************/
332 static void *pwrap_load_lib_handle(enum pwrap_lib lib
)
334 int flags
= RTLD_LAZY
;
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");
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
;
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
;
374 if (handle
== NULL
) {
375 PWRAP_LOG(PWRAP_LOG_ERROR
,
376 "Failed to dlopen library: %s\n",
384 static void *_pwrap_bind_symbol(enum pwrap_lib lib
, const char *fn_name
)
389 handle
= pwrap_load_lib_handle(lib
);
391 func
= dlsym(handle
, fn_name
);
393 PWRAP_LOG(PWRAP_LOG_ERROR
,
394 "Failed to find %s: %s\n",
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); \
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
,
419 const struct pam_conv
*pam_conversation
,
423 pwrap_bind_symbol_libpam(pam_start_confdir
);
425 return pwrap
.libpam
.symbols
._libpam_pam_start_confdir
.f(service_name
,
432 static int libpam_pam_start(const char *service_name
,
434 const struct pam_conv
*pam_conversation
,
437 pwrap_bind_symbol_libpam(pam_start
);
439 return pwrap
.libpam
.symbols
._libpam_pam_start
.f(service_name
,
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
,
535 pwrap_bind_symbol_libpam(pam_get_data
);
537 return pwrap
.libpam
.symbols
._libpam_pam_get_data
.f(pamh
,
542 static int libpam_pam_set_data(pam_handle_t
*pamh
,
543 const char *module_data_name
,
545 void (*cleanup
)(pam_handle_t
*pamh
,
549 pwrap_bind_symbol_libpam(pam_set_data
);
551 return pwrap
.libpam
.symbols
._libpam_pam_set_data
.f(pamh
,
557 static int libpam_pam_vprompt(pam_handle_t
*pamh
,
563 pwrap_bind_symbol_libpam(pam_vprompt
);
565 return pwrap
.libpam
.symbols
._libpam_pam_vprompt
.f(pamh
,
572 #ifdef HAVE_PAM_STRERROR_CONST
573 static const char *libpam_pam_strerror(const pam_handle_t
*pamh
, int errnum
)
575 static const char *libpam_pam_strerror(pam_handle_t
*pamh
, int errnum
)
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
,
589 pwrap_bind_symbol_libpam(pam_vsyslog
);
591 pwrap
.libpam
.symbols
._libpam_pam_vsyslog
.f(pamh
,
596 #endif /* HAVE_PAM_VSYSLOG */
598 /*********************************************************
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
)
610 ssize_t bread
, bwritten
;
612 char buf
[BUFFER_SIZE
];
615 cmp
= strcmp(src
, dst
);
620 srcfd
= open(src
, O_RDONLY
, 0);
626 rc
= fstat(srcfd
, &sb
);
634 dstfd
= open(dst
, O_CREAT
|O_WRONLY
|O_TRUNC
, mode
);
641 bread
= read(srcfd
, buf
, BUFFER_SIZE
);
645 } else if (bread
< 0) {
651 bwritten
= write(dstfd
, buf
, bread
);
658 if (bread
!= bwritten
) {
680 /* Do not pass any flag if not defined */
681 #ifndef FTW_ACTIONRETVAL
682 #define FTW_ACTIONRETVAL 0
685 /* Action return values */
691 #define FTW_CONTINUE 0
694 #ifndef FTW_SKIP_SUBTREE
695 #define FTW_SKIP_SUBTREE 0
698 static int copy_ftw(const char *fpath
,
699 const struct stat
*sb
,
704 char buf
[BUFFER_SIZE
];
709 /* We want to copy the directories from this directory */
710 if (ftwbuf
->level
== 0) {
713 return FTW_SKIP_SUBTREE
;
720 rc
= snprintf(buf
, BUFFER_SIZE
, "%s/%s", pwrap
.config_dir
, fpath
+ ftwbuf
->base
);
721 if (rc
>= BUFFER_SIZE
) {
725 PWRAP_LOG(PWRAP_LOG_TRACE
, "Copying %s", fpath
);
726 rc
= p_copy(fpath
, buf
, sb
->st_mode
);
734 static int copy_confdir(const char *src
)
738 PWRAP_LOG(PWRAP_LOG_DEBUG
,
739 "Copy config files from %s to %s",
742 rc
= nftw(src
, copy_ftw
, 1, FTW_ACTIONRETVAL
);
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];
767 /* read the pidfile */
768 fd
= open(pidfile
, O_RDONLY
);
770 if (errno
== ENOENT
) {
771 PWRAP_LOG(PWRAP_LOG_TRACE
,
772 "pidfile %s missing, nothing to do\n",
775 PWRAP_LOG(PWRAP_LOG_ERROR
,
776 "Failed to open pidfile %s - error: %s",
777 pidfile
, strerror(errno
));
782 rc
= read(fd
, buf
, sizeof(buf
));
785 PWRAP_LOG(PWRAP_LOG_ERROR
,
786 "Failed to read pidfile %s - error: %s",
787 pidfile
, strerror(errno
));
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",
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
);
811 PWRAP_LOG(PWRAP_LOG_TRACE
,
812 "Remove stale pam_wrapper dir: %s",
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
);
831 char pidfile_path
[1024] = { 0 };
834 if (!pam_wrapper_enabled()) {
838 if (pwrap
.initialised
) {
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
);
854 PWRAP_LOG(PWRAP_LOG_TRACE
,
855 "Check if pam_wrapper dir %s is a "
858 pwrap_clean_stale_dirs(tmp_config_dir
);
860 if (errno
!= ENOENT
) {
872 PWRAP_LOG(PWRAP_LOG_ERROR
,
873 "Failed to find a possible path to create "
874 "pam_wrapper config dir: %s",
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
,
887 PWRAP_LOG(PWRAP_LOG_TRACE
,
888 "pam_wrapper config dir: %s",
891 rc
= mkdir(pwrap
.config_dir
, 0755);
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
);
902 p_rmdirs(pwrap
.config_dir
);
906 pidfile
= fopen(pidfile_path
, "w");
907 if (pidfile
== NULL
) {
908 p_rmdirs(pwrap
.config_dir
);
912 rc
= fprintf(pidfile
, "%d", getpid());
915 p_rmdirs(pwrap
.config_dir
);
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
);
926 PWRAP_LOG(PWRAP_LOG_TRACE
, "Using libpam path: %s", pwrap
.libpam_so
);
928 pwrap
.initialised
= true;
930 env
= getenv("PAM_WRAPPER_SERVICE_DIR");
932 PWRAP_LOG(PWRAP_LOG_ERROR
, "No config file");
933 p_rmdirs(pwrap
.config_dir
);
937 rc
= copy_confdir(env
);
939 PWRAP_LOG(PWRAP_LOG_ERROR
, "Failed to copy config files");
940 p_rmdirs(pwrap
.config_dir
);
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
957 ssize_t bread
, bwritten
;
959 char buf
[PSO_COPY_READ_SIZE
+ 1];
964 cmp
= strcmp(src
, dst
);
969 srcfd
= open(src
, O_RDONLY
, 0);
975 rc
= fstat(srcfd
, &sb
);
983 dstfd
= open(dst
, O_CREAT
|O_WRONLY
|O_TRUNC
, mode
);
993 bread
= read(srcfd
, buf
, to_read
);
997 } else if (bread
< 0) {
1004 if (!found_slash
&& buf
[0] == '/') {
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
);
1012 memcpy(buf
, pdir
+ 1, PSO_COPY_READ_SIZE
);
1014 found_slash
= false;
1017 bwritten
= write(dstfd
, buf
, bread
);
1024 if (bread
!= bwritten
) {
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
);
1055 char pam_library
[128] = { 0 };
1056 char libpam_path
[1024] = { 0 };
1059 char pidfile_path
[1024] = { 0 };
1062 if (!pam_wrapper_enabled()) {
1066 if (pwrap
.initialised
) {
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
);
1082 PWRAP_LOG(PWRAP_LOG_TRACE
,
1083 "Check if pam_wrapper dir %s is a "
1086 pwrap_clean_stale_dirs(tmp_config_dir
);
1087 } else if (rc
< 0) {
1088 if (errno
!= ENOENT
) {
1100 PWRAP_LOG(PWRAP_LOG_ERROR
,
1101 "Failed to find a possible path to create "
1102 "pam_wrapper config dir: %s",
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
,
1115 PWRAP_LOG(PWRAP_LOG_TRACE
,
1116 "pam_wrapper config dir: %s",
1119 rc
= mkdir(pwrap
.config_dir
, 0755);
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
);
1130 p_rmdirs(pwrap
.config_dir
);
1134 pidfile
= fopen(pidfile_path
, "w");
1135 if (pidfile
== NULL
) {
1136 p_rmdirs(pwrap
.config_dir
);
1140 rc
= fprintf(pidfile
, "%d", getpid());
1143 p_rmdirs(pwrap
.config_dir
);
1147 /* create lib subdirectory */
1148 snprintf(libpam_path
,
1149 sizeof(libpam_path
),
1153 rc
= mkdir(libpam_path
, 0755);
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
);
1162 snprintf(libpam_path
,
1163 sizeof(libpam_path
),
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
);
1175 /* copy libpam.so.0 */
1176 snprintf(libpam_path
, sizeof(libpam_path
), "%s", PAM_LIBRARY
);
1177 PWRAP_LOG(PWRAP_LOG_TRACE
,
1181 ret
= readlink(libpam_path
, pam_library
, sizeof(pam_library
) - 1);
1182 PWRAP_LOG(PWRAP_LOG_TRACE
,
1186 PWRAP_LOG(PWRAP_LOG_ERROR
, "Failed to read %s link", LIBPAM_NAME
);
1187 p_rmdirs(pwrap
.config_dir
);
1191 if (pam_library
[0] == '/') {
1192 snprintf(libpam_path
,
1193 sizeof(libpam_path
),
1197 char libpam_path_cp
[1024] = {0};
1200 snprintf(libpam_path_cp
,
1201 sizeof(libpam_path_cp
),
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
);
1213 snprintf(libpam_path
,
1214 sizeof(libpam_path
),
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);
1224 PWRAP_LOG(PWRAP_LOG_ERROR
,
1225 "Failed to copy %s - error: %s",
1228 p_rmdirs(pwrap
.config_dir
);
1232 PWRAP_LOG(PWRAP_LOG_TRACE
, "Using libpam path: %s", pwrap
.libpam_so
);
1234 pwrap
.initialised
= true;
1236 env
= getenv("PAM_WRAPPER_SERVICE_DIR");
1238 PWRAP_LOG(PWRAP_LOG_ERROR
, "No config file");
1239 p_rmdirs(pwrap
.config_dir
);
1243 rc
= copy_confdir(env
);
1245 PWRAP_LOG(PWRAP_LOG_ERROR
, "Failed to copy config files");
1246 p_rmdirs(pwrap
.config_dir
);
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)
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
;
1280 static int pwrap_openpam_start(const char *service_name
,
1282 const struct pam_conv
*pam_conversation
,
1283 pam_handle_t
**pamh
)
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");
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");
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");
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");
1322 return libpam_pam_start(fullpath
,
1329 static int pwrap_pam_start(const char *service_name
,
1331 const struct pam_conv
*pam_conversation
,
1332 pam_handle_t
**pamh
)
1338 PWRAP_LOG(PWRAP_LOG_TRACE
,
1339 "pam_start service=%s, user=%s",
1343 #if defined(HAVE_OPENPAM)
1344 rc
= pwrap_openpam_start(service_name
,
1348 #elif defined (HAVE_PAM_START_CONFDIR)
1349 rc
= libpam_pam_start_confdir(service_name
,
1355 rc
= libpam_pam_start(service_name
,
1360 PWRAP_LOG(PWRAP_LOG_TRACE
, "pam_start rc=%d", rc
);
1366 int pam_start(const char *service_name
,
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
)
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] == '/') {
1496 PWRAP_LOG(PWRAP_LOG_TRACE
,
1497 "PAM_SERVICE=%s", service_name
);
1498 return service_name
;
1500 return libpam_service
;
1504 static int pwrap_pam_get_item(const pam_handle_t
*pamh
,
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
) {
1518 PWRAP_LOG(PWRAP_LOG_TRACE
,
1519 "pwrap_get_item PAM_USER=%s",
1520 (const char *)*item
);
1523 svc
= pwrap_get_service((const char *) *item
);
1525 PWRAP_LOG(PWRAP_LOG_TRACE
,
1526 "pwrap_get_item PAM_SERVICE=%s",
1530 case PAM_USER_PROMPT
:
1531 PWRAP_LOG(PWRAP_LOG_TRACE
,
1532 "pwrap_get_item PAM_USER_PROMPT=%s",
1533 (const char *)*item
);
1536 PWRAP_LOG(PWRAP_LOG_TRACE
,
1537 "pwrap_get_item PAM_TTY=%s",
1538 (const char *)*item
);
1541 PWRAP_LOG(PWRAP_LOG_TRACE
,
1542 "pwrap_get_item PAM_RUSER=%s",
1543 (const char *)*item
);
1546 PWRAP_LOG(PWRAP_LOG_TRACE
,
1547 "pwrap_get_item PAM_RHOST=%s",
1548 (const char *)*item
);
1551 PWRAP_LOG(PWRAP_LOG_TRACE
,
1552 "pwrap_get_item PAM_AUTHTOK=%s",
1553 (const char *)*item
);
1555 case PAM_OLDAUTHTOK
:
1556 PWRAP_LOG(PWRAP_LOG_TRACE
,
1557 "pwrap_get_item PAM_OLDAUTHTOK=%s",
1558 (const char *)*item
);
1561 PWRAP_LOG(PWRAP_LOG_TRACE
,
1562 "pwrap_get_item PAM_CONV=%p",
1563 (const void *)*item
);
1566 PWRAP_LOG(PWRAP_LOG_TRACE
,
1567 "pwrap_get_item item_type=%d item=%p",
1568 item_type
, (const void *)*item
);
1572 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_get_item failed rc=%d", 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
,
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
) {
1595 PWRAP_LOG(PWRAP_LOG_TRACE
,
1596 "pwrap_set_item PAM_USER=%s",
1597 (const char *)item
);
1600 PWRAP_LOG(PWRAP_LOG_TRACE
,
1601 "pwrap_set_item PAM_SERVICE=%s",
1602 (const char *)item
);
1604 case PAM_USER_PROMPT
:
1605 PWRAP_LOG(PWRAP_LOG_TRACE
,
1606 "pwrap_set_item PAM_USER_PROMPT=%s",
1607 (const char *)item
);
1610 PWRAP_LOG(PWRAP_LOG_TRACE
,
1611 "pwrap_set_item PAM_TTY=%s",
1612 (const char *)item
);
1615 PWRAP_LOG(PWRAP_LOG_TRACE
,
1616 "pwrap_set_item PAM_RUSER=%s",
1617 (const char *)item
);
1620 PWRAP_LOG(PWRAP_LOG_TRACE
,
1621 "pwrap_set_item PAM_RHOST=%s",
1622 (const char *)item
);
1625 PWRAP_LOG(PWRAP_LOG_TRACE
,
1626 "pwrap_set_item PAM_AUTHTOK=%s",
1627 (const char *)item
);
1629 case PAM_OLDAUTHTOK
:
1630 PWRAP_LOG(PWRAP_LOG_TRACE
,
1631 "pwrap_set_item PAM_OLDAUTHTOK=%s",
1632 (const char *)item
);
1635 PWRAP_LOG(PWRAP_LOG_TRACE
,
1636 "pwrap_set_item PAM_CONV=%p",
1640 PWRAP_LOG(PWRAP_LOG_TRACE
,
1641 "pwrap_set_item item_type=%d item=%p",
1646 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_set_item failed rc=%d", 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
,
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
,
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
,
1676 void (*cleanup
)(pam_handle_t
*pamh
,
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
,
1689 void (*cleanup
)(pam_handle_t
*pamh
,
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
,
1699 static int pwrap_pam_vprompt(pam_handle_t
*pamh
,
1706 PWRAP_LOG(PWRAP_LOG_TRACE
, "pwrap_pam_vprompt style=%d", style
);
1707 return libpam_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1714 #ifdef HAVE_PAM_VPROMPT_CONST
1715 int pam_vprompt(const pam_handle_t
*pamh
,
1721 int pam_vprompt(pam_handle_t
*pamh
,
1728 return pwrap_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1735 #ifdef HAVE_PAM_PROMPT_CONST
1736 int pam_prompt(const pam_handle_t
*pamh
,
1739 const char *fmt
, ...)
1741 int pam_prompt(pam_handle_t
*pamh
,
1744 const char *fmt
, ...)
1750 va_start(args
, fmt
);
1751 rv
= pwrap_pam_vprompt(discard_const_p(pam_handle_t
, pamh
),
1761 #ifdef HAVE_PAM_STRERROR_CONST
1762 static const char *pwrap_pam_strerror(const pam_handle_t
*pamh
, int errnum
)
1764 static const char *pwrap_pam_strerror(pam_handle_t
*pamh
, int errnum
)
1771 PWRAP_LOG(PWRAP_LOG_TRACE
, "pam_strerror errnum=%d", errnum
);
1773 str
= libpam_pam_strerror(discard_const_p(pam_handle_t
, pamh
),
1776 PWRAP_LOG(PWRAP_LOG_TRACE
, "pam_strerror error=%s", str
);
1781 #ifdef HAVE_PAM_STRERROR_CONST
1782 const char *pam_strerror(const pam_handle_t
*pamh
, int errnum
)
1784 const char *pam_strerror(pam_handle_t
*pamh
, int errnum
)
1787 return pwrap_pam_strerror(discard_const_p(pam_handle_t
, pamh
),
1791 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1792 static void pwrap_pam_vsyslog(const pam_handle_t
*pamh
,
1795 va_list args
) PRINTF_ATTRIBUTE(3, 0);
1797 static void pwrap_pam_vsyslog(const pam_handle_t
*pamh
,
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
);
1814 #endif /* HAVE_PAM_VSYSLOG */
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
;
1823 case 4: /* LOG_WARN */
1824 dbglvl
= PWRAP_LOG_WARN
;
1826 case 5: /* LOG_NOTICE */
1827 case 6: /* LOG_INFO */
1828 case 7: /* LOG_DEBUG */
1829 dbglvl
= PWRAP_LOG_DEBUG
;
1832 dbglvl
= PWRAP_LOG_TRACE
;
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
,
1848 pwrap_pam_vsyslog(pamh
, priority
, fmt
, args
);
1852 #ifdef HAVE_PAM_SYSLOG
1853 void pam_syslog(const pam_handle_t
*pamh
,
1855 const char *fmt
, ...)
1859 va_start(args
, fmt
);
1860 pwrap_pam_vsyslog(pamh
, priority
, fmt
, args
);
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
;
1877 /* Disable BSD auditing */
1878 int cannot_audit(int x
);
1879 int cannot_audit(int x
)
1886 /****************************
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
1901 static void pwrap_thread_parent(void)
1906 * Handler that is executed in the child process after fork(2) processing
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
1932 /****************************
1934 ***************************/
1936 static int p_rmdirs_at(const char *path
, int parent_fd
)
1939 struct dirent
*dp
= NULL
;
1941 char fd_str
[64] = { 0 };
1947 snprintf(fd_str
, sizeof(fd_str
), "CWD");
1950 snprintf(fd_str
, sizeof(fd_str
), "fd=%d", parent_fd
);
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) {
1964 d
= fdopendir(path_fd
);
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'))) {
1978 rc
= fstatat(path_fd
, dp
->d_name
,
1979 &sb
, AT_SYMLINK_NOFOLLOW
);
1984 if (S_ISDIR(sb
.st_mode
)) {
1985 rc
= p_rmdirs_at(dp
->d_name
, path_fd
);
1987 rc
= unlinkat(path_fd
, dp
->d_name
, 0);
1995 rc
= unlinkat(parent_fd
, path
, AT_REMOVEDIR
);
1998 PWRAP_LOG(PWRAP_LOG_TRACE
,
1999 "cannot unlink %s error %d\n", path
, rc
);
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)
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
) {
2037 pwrap
.initialised
= false;
2039 PWRAP_LOG(PWRAP_LOG_TRACE
,
2040 "destructor called for pam_wrapper dir %s",
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
;