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 flags |= RTLD_DEEPBIND;
308 handle = pwrap.libpam.handle;
309 if (handle == NULL) {
310 handle = dlopen(pwrap.libpam_so, flags);
311 if (handle != NULL) {
312 PWRAP_LOG(PWRAP_LOG_DEBUG,
313 "Opened %s\n", pwrap.libpam_so);
314 pwrap.libpam.handle = handle;
321 if (handle == NULL) {
322 PWRAP_LOG(PWRAP_LOG_ERROR,
323 "Failed to dlopen library: %s\n",
331 static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
336 handle = pwrap_load_lib_handle(lib);
338 func = dlsym(handle, fn_name);
340 PWRAP_LOG(PWRAP_LOG_ERROR,
341 "Failed to find %s: %s\n",
349 #define pwrap_bind_symbol_libpam(sym_name) \
350 if (pwrap.libpam.symbols._libpam_##sym_name.obj == NULL) { \
351 pwrap.libpam.symbols._libpam_##sym_name.obj = \
352 _pwrap_bind_symbol(PWRAP_LIBPAM, #sym_name); \
358 * Functions especially from libpam need to be loaded individually, you can't
359 * load all at once or gdb will segfault at startup. The same applies to
360 * valgrind and has probably something todo with with the linker.
361 * So we need load each function at the point it is called the first time.
363 static int libpam_pam_start(const char *service_name,
365 const struct pam_conv *pam_conversation,
368 pwrap_bind_symbol_libpam(pam_start);
370 return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
376 static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
378 pwrap_bind_symbol_libpam(pam_end);
380 return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
383 static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
385 pwrap_bind_symbol_libpam(pam_authenticate);
387 return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
390 static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
392 pwrap_bind_symbol_libpam(pam_chauthtok);
394 return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
397 static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
399 pwrap_bind_symbol_libpam(pam_acct_mgmt);
401 return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
404 static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
406 pwrap_bind_symbol_libpam(pam_putenv);
408 return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
411 static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
413 pwrap_bind_symbol_libpam(pam_getenv);
415 return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
418 static char **libpam_pam_getenvlist(pam_handle_t *pamh)
420 pwrap_bind_symbol_libpam(pam_getenvlist);
422 return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
425 static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
427 pwrap_bind_symbol_libpam(pam_open_session);
429 return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
432 static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
434 pwrap_bind_symbol_libpam(pam_close_session);
436 return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
439 static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
441 pwrap_bind_symbol_libpam(pam_setcred);
443 return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
446 static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
448 pwrap_bind_symbol_libpam(pam_get_item);
450 return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
453 static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
455 pwrap_bind_symbol_libpam(pam_set_item);
457 return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
460 static int libpam_pam_get_data(const pam_handle_t *pamh,
461 const char *module_data_name,
464 pwrap_bind_symbol_libpam(pam_get_data);
466 return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
471 static int libpam_pam_set_data(pam_handle_t *pamh,
472 const char *module_data_name,
474 void (*cleanup)(pam_handle_t *pamh,
478 pwrap_bind_symbol_libpam(pam_set_data);
480 return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
486 static int libpam_pam_vprompt(pam_handle_t *pamh,
492 pwrap_bind_symbol_libpam(pam_vprompt);
494 return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
501 #ifdef HAVE_PAM_STRERROR_CONST
502 static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
504 static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
507 pwrap_bind_symbol_libpam(pam_strerror);
509 return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
512 #ifdef HAVE_PAM_VSYSLOG
513 static void libpam_pam_vsyslog(const pam_handle_t *pamh,
518 pwrap_bind_symbol_libpam(pam_vsyslog);
520 pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
525 #endif /* HAVE_PAM_VSYSLOG */
527 /*********************************************************
529 *********************************************************/
531 #define BUFFER_SIZE 32768
533 /* copy file from src to dst, overwrites dst */
534 static int p_copy(const char *src, const char *dst, mode_t mode)
539 ssize_t bread, bwritten;
541 char buf[BUFFER_SIZE];
544 cmp = strcmp(src, dst);
549 srcfd = open(src, O_RDONLY, 0);
555 rc = fstat(srcfd, &sb);
563 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
570 bread = read(srcfd, buf, BUFFER_SIZE);
574 } else if (bread < 0) {
580 bwritten = write(dstfd, buf, bread);
587 if (bread != bwritten) {
609 /* Do not pass any flag if not defined */
610 #ifndef FTW_ACTIONRETVAL
611 #define FTW_ACTIONRETVAL 0
614 /* Action return values */
620 #define FTW_CONTINUE 0
623 #ifndef FTW_SKIP_SUBTREE
624 #define FTW_SKIP_SUBTREE 0
627 static int copy_ftw(const char *fpath,
628 const struct stat *sb,
633 char buf[BUFFER_SIZE];
638 /* We want to copy the directories from this directory */
639 if (ftwbuf->level == 0) {
642 return FTW_SKIP_SUBTREE;
649 rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
650 if (rc >= BUFFER_SIZE) {
654 PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
655 rc = p_copy(fpath, buf, sb->st_mode);
663 static int copy_confdir(const char *src)
667 PWRAP_LOG(PWRAP_LOG_DEBUG,
668 "Copy config files from %s to %s",
671 rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
679 static int p_rmdirs(const char *path);
681 static void pwrap_clean_stale_dirs(const char *dir)
683 size_t len = strlen(dir);
684 char pidfile[len + 5];
696 /* read the pidfile */
697 fd = open(pidfile, O_RDONLY);
699 if (errno == ENOENT) {
700 PWRAP_LOG(PWRAP_LOG_TRACE,
701 "pidfile %s missing, nothing to do\n",
704 PWRAP_LOG(PWRAP_LOG_ERROR,
705 "Failed to open pidfile %s - error: %s",
706 pidfile, strerror(errno));
711 rc = read(fd, buf, sizeof(buf));
714 PWRAP_LOG(PWRAP_LOG_ERROR,
715 "Failed to read pidfile %s - error: %s",
716 pidfile, strerror(errno));
720 buf[sizeof(buf) - 1] = '\0';
722 tmp = strtol(buf, NULL, 10);
723 if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
724 PWRAP_LOG(PWRAP_LOG_ERROR,
725 "Failed to parse pid, buf=%s",
730 pid = (pid_t)(tmp & 0xFFFF);
734 PWRAP_LOG(PWRAP_LOG_TRACE,
735 "Remove stale pam_wrapper dir: %s",
743 static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
748 ssize_t bread, bwritten;
755 cmp = strcmp(src, dst);
760 srcfd = open(src, O_RDONLY, 0);
766 rc = fstat(srcfd, &sb);
774 dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
784 bread = read(srcfd, buf, to_read);
788 } else if (bread < 0) {
795 if (!found_slash && buf[0] == '/') {
800 if (found_slash && bread == 9) {
801 cmp = memcmp(buf, "etc/pam.d", 9);
803 memcpy(buf, pdir + 1, 9);
808 bwritten = write(dstfd, buf, bread);
815 if (bread != bwritten) {
837 static void pwrap_init(void)
839 char tmp_config_dir[] = "/tmp/pam.X";
840 size_t len = strlen(tmp_config_dir);
845 char pam_library[128] = { 0 };
846 char libpam_path[1024] = { 0 };
849 char pidfile_path[1024] = { 0 };
852 if (!pam_wrapper_enabled()) {
856 if (pwrap.initialised) {
861 * The name is selected to match/replace /etc/pam.d
862 * We start from a random alphanum trying letters until
863 * an available directory is found.
865 letter = 48 + (getpid() % 70);
866 for (i = 0; i < 127; i++) {
867 if (isalpha(letter) || isdigit(letter)) {
868 tmp_config_dir[len - 1] = letter;
870 rc = lstat(tmp_config_dir, &sb);
872 PWRAP_LOG(PWRAP_LOG_TRACE,
873 "Check if pam_wrapper dir %s is a "
876 pwrap_clean_stale_dirs(tmp_config_dir);
878 if (errno != ENOENT) {
890 PWRAP_LOG(PWRAP_LOG_ERROR,
891 "Failed to find a possible path to create "
892 "pam_wrapper config dir: %s",
897 PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
899 pwrap_clean_stale_dirs(tmp_config_dir);
901 pwrap.config_dir = strdup(tmp_config_dir);
902 if (pwrap.config_dir == NULL) {
903 PWRAP_LOG(PWRAP_LOG_ERROR,
907 PWRAP_LOG(PWRAP_LOG_TRACE,
908 "pam_wrapper config dir: %s",
911 rc = mkdir(pwrap.config_dir, 0755);
913 PWRAP_LOG(PWRAP_LOG_ERROR,
914 "Failed to create pam_wrapper config dir: %s - %s",
915 tmp_config_dir, strerror(errno));
918 /* Create file with the PID of the the process */
919 ret = snprintf(pidfile_path, sizeof(pidfile_path),
920 "%s/pid", pwrap.config_dir);
922 p_rmdirs(pwrap.config_dir);
926 pidfile = fopen(pidfile_path, "w");
927 if (pidfile == NULL) {
928 p_rmdirs(pwrap.config_dir);
932 rc = fprintf(pidfile, "%d", getpid());
935 p_rmdirs(pwrap.config_dir);
939 /* create lib subdirectory */
940 snprintf(libpam_path,
945 rc = mkdir(libpam_path, 0755);
947 PWRAP_LOG(PWRAP_LOG_ERROR,
948 "Failed to create pam_wrapper config dir: %s - %s",
949 tmp_config_dir, strerror(errno));
950 p_rmdirs(pwrap.config_dir);
954 snprintf(libpam_path,
960 pwrap.libpam_so = strdup(libpam_path);
961 if (pwrap.libpam_so == NULL) {
962 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
963 p_rmdirs(pwrap.config_dir);
967 /* copy libpam.so.0 */
968 snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
969 PWRAP_LOG(PWRAP_LOG_TRACE,
973 ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
974 PWRAP_LOG(PWRAP_LOG_TRACE,
978 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
979 p_rmdirs(pwrap.config_dir);
983 if (pam_library[0] == '/') {
984 snprintf(libpam_path,
989 char libpam_path_cp[1024] = {0};
992 snprintf(libpam_path_cp,
993 sizeof(libpam_path_cp),
997 dname = dirname(libpam_path_cp);
999 PWRAP_LOG(PWRAP_LOG_ERROR,
1000 "No directory component in %s", libpam_path);
1001 p_rmdirs(pwrap.config_dir);
1005 snprintf(libpam_path,
1006 sizeof(libpam_path),
1011 PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
1013 PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
1014 rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
1016 PWRAP_LOG(PWRAP_LOG_ERROR,
1017 "Failed to copy %s - error: %s",
1020 p_rmdirs(pwrap.config_dir);
1024 pwrap.initialised = true;
1026 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1028 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
1029 p_rmdirs(pwrap.config_dir);
1033 rc = copy_confdir(env);
1035 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
1036 p_rmdirs(pwrap.config_dir);
1040 setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
1042 PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
1045 bool pam_wrapper_enabled(void)
1049 pwrap.enabled = false;
1051 env = getenv("PAM_WRAPPER");
1052 if (env != NULL && env[0] == '1') {
1053 pwrap.enabled = true;
1056 if (pwrap.enabled) {
1057 pwrap.enabled = false;
1059 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1060 if (env != NULL && env[0] != '\0') {
1061 pwrap.enabled = true;
1065 return pwrap.enabled;
1068 /****************************
1070 ***************************/
1071 void pwrap_constructor(void)
1074 * Here is safe place to call pwrap_init() and initialize data
1082 static int pwrap_openpam_start(const char *service_name,
1084 const struct pam_conv *pam_conversation,
1085 pam_handle_t **pamh)
1088 char fullpath[1024];
1090 rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1091 if (rv != PAM_SUCCESS) {
1092 PWRAP_LOG(PWRAP_LOG_ERROR,
1093 "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1097 rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1098 if (rv != PAM_SUCCESS) {
1099 PWRAP_LOG(PWRAP_LOG_ERROR,
1100 "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1104 rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1105 if (rv != PAM_SUCCESS) {
1106 PWRAP_LOG(PWRAP_LOG_ERROR,
1107 "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1111 rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1112 if (rv != PAM_SUCCESS) {
1113 PWRAP_LOG(PWRAP_LOG_ERROR,
1114 "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1124 return libpam_pam_start(fullpath,
1131 static int pwrap_pam_start(const char *service_name,
1133 const struct pam_conv *pam_conversation,
1134 pam_handle_t **pamh)
1136 PWRAP_LOG(PWRAP_LOG_TRACE,
1137 "pam_start service=%s, user=%s",
1142 return pwrap_openpam_start(service_name,
1147 return libpam_pam_start(service_name,
1155 int pam_start(const char *service_name,
1157 const struct pam_conv *pam_conversation,
1158 pam_handle_t **pamh)
1160 return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1163 static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1165 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1166 return libpam_pam_end(pamh, pam_status);
1170 int pam_end(pam_handle_t *pamh, int pam_status)
1172 return pwrap_pam_end(pamh, pam_status);
1175 static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1177 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1178 return libpam_pam_authenticate(pamh, flags);
1181 int pam_authenticate(pam_handle_t *pamh, int flags)
1183 return pwrap_pam_authenticate(pamh, flags);
1186 static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1188 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1189 return libpam_pam_chauthtok(pamh, flags);
1192 int pam_chauthtok(pam_handle_t *pamh, int flags)
1194 return pwrap_pam_chauthtok(pamh, flags);
1197 static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1199 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1200 return libpam_pam_acct_mgmt(pamh, flags);
1203 int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1205 return pwrap_pam_acct_mgmt(pamh, flags);
1208 static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1210 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1211 return libpam_pam_putenv(pamh, name_value);
1214 int pam_putenv(pam_handle_t *pamh, const char *name_value)
1216 return pwrap_pam_putenv(pamh, name_value);
1219 static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1221 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1222 return libpam_pam_getenv(pamh, name);
1225 const char *pam_getenv(pam_handle_t *pamh, const char *name)
1227 return pwrap_pam_getenv(pamh, name);
1230 static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1232 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1233 return libpam_pam_getenvlist(pamh);
1236 char **pam_getenvlist(pam_handle_t *pamh)
1238 return pwrap_pam_getenvlist(pamh);
1241 static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1243 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1244 return libpam_pam_open_session(pamh, flags);
1247 int pam_open_session(pam_handle_t *pamh, int flags)
1249 return pwrap_pam_open_session(pamh, flags);
1252 static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1254 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1255 return libpam_pam_close_session(pamh, flags);
1258 int pam_close_session(pam_handle_t *pamh, int flags)
1260 return pwrap_pam_close_session(pamh, flags);
1263 static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1265 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1266 return libpam_pam_setcred(pamh, flags);
1269 int pam_setcred(pam_handle_t *pamh, int flags)
1271 return pwrap_pam_setcred(pamh, flags);
1274 static const char *pwrap_get_service(const char *libpam_service)
1277 const char *service_name;
1279 PWRAP_LOG(PWRAP_LOG_TRACE,
1280 "internal PAM_SERVICE=%s", libpam_service);
1281 service_name = strrchr(libpam_service, '/');
1282 if (service_name != NULL && service_name[0] == '/') {
1285 PWRAP_LOG(PWRAP_LOG_TRACE,
1286 "PAM_SERVICE=%s", service_name);
1287 return service_name;
1289 return libpam_service;
1293 static int pwrap_pam_get_item(const pam_handle_t *pamh,
1300 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1302 rc = libpam_pam_get_item(pamh, item_type, item);
1304 if (rc == PAM_SUCCESS) {
1307 PWRAP_LOG(PWRAP_LOG_TRACE,
1308 "pwrap_get_item PAM_USER=%s",
1309 (const char *)*item);
1312 svc = pwrap_get_service((const char *) *item);
1314 PWRAP_LOG(PWRAP_LOG_TRACE,
1315 "pwrap_get_item PAM_SERVICE=%s",
1319 case PAM_USER_PROMPT:
1320 PWRAP_LOG(PWRAP_LOG_TRACE,
1321 "pwrap_get_item PAM_USER_PROMPT=%s",
1322 (const char *)*item);
1325 PWRAP_LOG(PWRAP_LOG_TRACE,
1326 "pwrap_get_item PAM_TTY=%s",
1327 (const char *)*item);
1330 PWRAP_LOG(PWRAP_LOG_TRACE,
1331 "pwrap_get_item PAM_RUSER=%s",
1332 (const char *)*item);
1335 PWRAP_LOG(PWRAP_LOG_TRACE,
1336 "pwrap_get_item PAM_RHOST=%s",
1337 (const char *)*item);
1340 PWRAP_LOG(PWRAP_LOG_TRACE,
1341 "pwrap_get_item PAM_AUTHTOK=%s",
1342 (const char *)*item);
1344 case PAM_OLDAUTHTOK:
1345 PWRAP_LOG(PWRAP_LOG_TRACE,
1346 "pwrap_get_item PAM_OLDAUTHTOK=%s",
1347 (const char *)*item);
1350 PWRAP_LOG(PWRAP_LOG_TRACE,
1351 "pwrap_get_item PAM_CONV=%p",
1352 (const void *)*item);
1355 PWRAP_LOG(PWRAP_LOG_TRACE,
1356 "pwrap_get_item item_type=%d item=%p",
1357 item_type, (const void *)*item);
1361 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1367 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1369 return pwrap_pam_get_item(pamh, item_type, item);
1372 static int pwrap_pam_set_item(pam_handle_t *pamh,
1378 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1380 rc = libpam_pam_set_item(pamh, item_type, item);
1381 if (rc == PAM_SUCCESS) {
1384 PWRAP_LOG(PWRAP_LOG_TRACE,
1385 "pwrap_set_item PAM_USER=%s",
1386 (const char *)item);
1389 PWRAP_LOG(PWRAP_LOG_TRACE,
1390 "pwrap_set_item PAM_SERVICE=%s",
1391 (const char *)item);
1393 case PAM_USER_PROMPT:
1394 PWRAP_LOG(PWRAP_LOG_TRACE,
1395 "pwrap_set_item PAM_USER_PROMPT=%s",
1396 (const char *)item);
1399 PWRAP_LOG(PWRAP_LOG_TRACE,
1400 "pwrap_set_item PAM_TTY=%s",
1401 (const char *)item);
1404 PWRAP_LOG(PWRAP_LOG_TRACE,
1405 "pwrap_set_item PAM_RUSER=%s",
1406 (const char *)item);
1409 PWRAP_LOG(PWRAP_LOG_TRACE,
1410 "pwrap_set_item PAM_RHOST=%s",
1411 (const char *)item);
1414 PWRAP_LOG(PWRAP_LOG_TRACE,
1415 "pwrap_set_item PAM_AUTHTOK=%s",
1416 (const char *)item);
1418 case PAM_OLDAUTHTOK:
1419 PWRAP_LOG(PWRAP_LOG_TRACE,
1420 "pwrap_set_item PAM_OLDAUTHTOK=%s",
1421 (const char *)item);
1424 PWRAP_LOG(PWRAP_LOG_TRACE,
1425 "pwrap_set_item PAM_CONV=%p",
1429 PWRAP_LOG(PWRAP_LOG_TRACE,
1430 "pwrap_set_item item_type=%d item=%p",
1435 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1441 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1443 return pwrap_pam_set_item(pamh, item_type, item);
1446 static int pwrap_pam_get_data(const pam_handle_t *pamh,
1447 const char *module_data_name,
1450 PWRAP_LOG(PWRAP_LOG_TRACE,
1451 "pwrap_get_data module_data_name=%s", module_data_name);
1452 return libpam_pam_get_data(pamh, module_data_name, data);
1455 int pam_get_data(const pam_handle_t *pamh,
1456 const char *module_data_name,
1459 return pwrap_pam_get_data(pamh, module_data_name, data);
1462 static int pwrap_pam_set_data(pam_handle_t *pamh,
1463 const char *module_data_name,
1465 void (*cleanup)(pam_handle_t *pamh,
1469 PWRAP_LOG(PWRAP_LOG_TRACE,
1470 "pwrap_set_data module_data_name=%s data=%p",
1471 module_data_name, data);
1472 return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1475 int pam_set_data(pam_handle_t *pamh,
1476 const char *module_data_name,
1478 void (*cleanup)(pam_handle_t *pamh,
1482 return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1485 #ifdef HAVE_PAM_VPROMPT_CONST
1486 static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1488 static int pwrap_pam_vprompt(pam_handle_t *pamh,
1495 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1496 return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1503 #ifdef HAVE_PAM_VPROMPT_CONST
1504 int pam_vprompt(const pam_handle_t *pamh,
1510 int pam_vprompt(pam_handle_t *pamh,
1517 return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1524 #ifdef HAVE_PAM_PROMPT_CONST
1525 int pam_prompt(const pam_handle_t *pamh,
1528 const char *fmt, ...)
1530 int pam_prompt(pam_handle_t *pamh,
1533 const char *fmt, ...)
1539 va_start(args, fmt);
1540 rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1550 #ifdef HAVE_PAM_STRERROR_CONST
1551 static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1553 static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1560 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1562 str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1565 PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1570 #ifdef HAVE_PAM_STRERROR_CONST
1571 const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1573 const char *pam_strerror(pam_handle_t *pamh, int errnum)
1576 return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1580 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1581 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1584 va_list args) PRINTF_ATTRIBUTE(3, 0);
1586 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1592 char syslog_str[32] = {0};
1593 enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1595 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1597 #ifdef HAVE_PAM_VSYSLOG
1598 d = getenv("PAM_WRAPPER_USE_SYSLOG");
1599 if (d != NULL && d[0] == '1') {
1600 libpam_pam_vsyslog(pamh, priority, fmt, args);
1603 #endif /* HAVE_PAM_VSYSLOG */
1606 case 0: /* LOG_EMERG */
1607 case 1: /* LOG_ALERT */
1608 case 2: /* LOG_CRIT */
1609 case 3: /* LOG_ERR */
1610 dbglvl = PWRAP_LOG_ERROR;
1612 case 4: /* LOG_WARN */
1613 dbglvl = PWRAP_LOG_WARN;
1615 case 5: /* LOG_NOTICE */
1616 case 6: /* LOG_INFO */
1617 case 7: /* LOG_DEBUG */
1618 dbglvl = PWRAP_LOG_DEBUG;
1621 dbglvl = PWRAP_LOG_TRACE;
1625 snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1627 pwrap_vlog(dbglvl, syslog_str, fmt, args);
1629 #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1631 #ifdef HAVE_PAM_VSYSLOG
1632 void pam_vsyslog(const pam_handle_t *pamh,
1637 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1641 #ifdef HAVE_PAM_SYSLOG
1642 void pam_syslog(const pam_handle_t *pamh,
1644 const char *fmt, ...)
1648 va_start(args, fmt);
1649 pwrap_pam_vsyslog(pamh, priority, fmt, args);
1654 /* This might be called by pam_end() running with sshd */
1655 int audit_open(void);
1656 int audit_open(void)
1659 * Tell the application that the kernel doesn't
1660 * have audit compiled in.
1662 errno = EPROTONOSUPPORT;
1666 /* Disable BSD auditing */
1667 int cannot_audit(int x);
1668 int cannot_audit(int x)
1675 /****************************
1677 ***************************/
1679 static int p_rmdirs_at(const char *path, int parent_fd)
1687 /* If path is absolute, parent_fd is ignored. */
1688 PWRAP_LOG(PWRAP_LOG_TRACE,
1689 "p_rmdirs_at removing %s at %d\n", path, parent_fd);
1691 path_fd = openat(parent_fd,
1692 path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1693 if (path_fd == -1) {
1697 d = fdopendir(path_fd);
1703 while ((dp = readdir(d)) != NULL) {
1704 /* skip '.' and '..' */
1705 if (dp->d_name[0] == '.' &&
1706 (dp->d_name[1] == '\0' ||
1707 (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
1711 rc = fstatat(path_fd, dp->d_name,
1712 &sb, AT_SYMLINK_NOFOLLOW);
1717 if (S_ISDIR(sb.st_mode)) {
1718 rc = p_rmdirs_at(dp->d_name, path_fd);
1720 rc = unlinkat(path_fd, dp->d_name, 0);
1728 rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
1731 PWRAP_LOG(PWRAP_LOG_TRACE,
1732 "cannot unlink %s error %d\n", path, rc);
1739 static int p_rmdirs(const char *path)
1742 * If path is absolute, p_rmdirs_at ignores parent_fd.
1743 * If it's relative, start from cwd.
1745 return p_rmdirs_at(path, AT_FDCWD);
1749 * This function is called when the library is unloaded and makes sure that
1750 * resources are freed.
1752 void pwrap_destructor(void)
1756 PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
1758 if (pwrap.libpam.handle != NULL) {
1759 dlclose(pwrap.libpam.handle);
1762 if (pwrap.libpam_so != NULL) {
1763 free(pwrap.libpam_so);
1764 pwrap.libpam_so = NULL;
1767 if (!pwrap.initialised) {
1771 PWRAP_LOG(PWRAP_LOG_TRACE,
1772 "destructor called for pam_wrapper dir %s",
1774 env = getenv("PAM_WRAPPER_KEEP_DIR");
1775 if (env == NULL || env[0] != '1') {
1776 p_rmdirs(pwrap.config_dir);
1779 if (pwrap.config_dir != NULL) {
1780 free(pwrap.config_dir);
1781 pwrap.config_dir = NULL;