LCOV - code coverage report
Current view: top level - third_party/pam_wrapper - pam_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 378 555 68.1 %
Date: 2024-04-21 15:09:00 Functions: 43 57 75.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
       3             :  * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
       4             :  *
       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.
       9             :  *
      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.
      14             :  *
      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/>.
      17             :  */
      18             : 
      19             : #include "config.h"
      20             : 
      21             : #include <errno.h>
      22             : #include <stdarg.h>
      23             : #include <stdbool.h>
      24             : #include <stdlib.h>
      25             : #include <stdio.h>
      26             : #include <string.h>
      27             : #include <stdint.h>
      28             : #include <sys/types.h>
      29             : #include <sys/stat.h>
      30             : #include <dirent.h>
      31             : #include <fcntl.h>
      32             : #include <unistd.h>
      33             : #include <dlfcn.h>
      34             : #include <libgen.h>
      35             : #include <signal.h>
      36             : #include <limits.h>
      37             : #include <ctype.h>
      38             : 
      39             : #include <pthread.h>
      40             : 
      41             : #include <ftw.h>
      42             : 
      43             : #ifdef HAVE_SECURITY_PAM_APPL_H
      44             : #include <security/pam_appl.h>
      45             : #endif
      46             : #ifdef HAVE_SECURITY_PAM_MODULES_H
      47             : #include <security/pam_modules.h>
      48             : #endif
      49             : #ifdef HAVE_SECURITY_PAM_EXT_H
      50             : #include <security/pam_ext.h>
      51             : #endif
      52             : 
      53             : #include "pwrap_compat.h"
      54             : 
      55             : #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
      56             : # define PWRAP_THREAD __thread
      57             : #else
      58             : # define PWRAP_THREAD
      59             : #endif
      60             : 
      61             : #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
      62             : #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
      63             : #else
      64             : #define CONSTRUCTOR_ATTRIBUTE
      65             : #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
      66             : 
      67             : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
      68             : #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
      69             : #else
      70             : #define DESTRUCTOR_ATTRIBUTE
      71             : #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
      72             : 
      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 */
      78             : 
      79             : /* GCC have printf type attribute check. */
      80             : #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
      81             : #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
      82             : #else
      83             : #define PRINTF_ATTRIBUTE(a,b)
      84             : #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
      85             : 
      86             : #ifndef SAFE_FREE
      87             : #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
      88             : #endif
      89             : 
      90             : #ifndef discard_const
      91             : #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
      92             : #endif
      93             : 
      94             : #ifndef discard_const_p
      95             : #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
      96             : #endif
      97             : 
      98             : /*****************
      99             :  * LOGGING
     100             :  *****************/
     101             : 
     102             : #ifndef HAVE_GETPROGNAME
     103       31324 : static const char *getprogname(void)
     104             : {
     105             : #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
     106       31324 :         return program_invocation_short_name;
     107             : #elif defined(HAVE_GETEXECNAME)
     108             :         return getexecname();
     109             : #else
     110             :         return NULL;
     111             : #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
     112             : }
     113             : #endif /* HAVE_GETPROGNAME */
     114             : 
     115             : enum pwrap_dbglvl_e {
     116             :         PWRAP_LOG_ERROR = 0,
     117             :         PWRAP_LOG_WARN,
     118             :         PWRAP_LOG_DEBUG,
     119             :         PWRAP_LOG_TRACE
     120             : };
     121             : 
     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__)
     126             : 
     127             : static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
     128             :                        const char *function,
     129             :                        const char *format,
     130             :                        va_list args) PRINTF_ATTRIBUTE(3, 0);
     131             : 
     132       31324 : static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
     133             :                        const char *function,
     134             :                        const char *format,
     135             :                        va_list args)
     136             : {
     137             :         char buffer[1024];
     138             :         const char *d;
     139       31324 :         unsigned int lvl = 0;
     140       31324 :         const char *prefix = "PWRAP";
     141       31324 :         const char *progname = getprogname();
     142             : 
     143       31324 :         d = getenv("PAM_WRAPPER_DEBUGLEVEL");
     144       31324 :         if (d != NULL) {
     145       31324 :                 lvl = atoi(d);
     146             :         }
     147             : 
     148       31324 :         if (lvl < dbglvl) {
     149       25428 :                 return;
     150             :         }
     151             : 
     152        5896 :         vsnprintf(buffer, sizeof(buffer), format, args);
     153             : 
     154        5896 :         switch (dbglvl) {
     155         201 :                 case PWRAP_LOG_ERROR:
     156         201 :                         prefix = "PWRAP_ERROR";
     157         201 :                         break;
     158          76 :                 case PWRAP_LOG_WARN:
     159          76 :                         prefix = "PWRAP_WARN";
     160          76 :                         break;
     161        5114 :                 case PWRAP_LOG_DEBUG:
     162        5114 :                         prefix = "PWRAP_DEBUG";
     163        5114 :                         break;
     164         505 :                 case PWRAP_LOG_TRACE:
     165         505 :                         prefix = "PWRAP_TRACE";
     166         505 :                         break;
     167             :         }
     168             : 
     169        5896 :         if (progname == NULL) {
     170           0 :                 progname = "<unknown>";
     171             :         }
     172             : 
     173        5896 :         fprintf(stderr,
     174             :                 "%s[%s (%u)] - %s: %s\n",
     175             :                 prefix,
     176             :                 progname,
     177        5896 :                 (unsigned int)getpid(),
     178             :                 function,
     179             :                 buffer);
     180             : }
     181             : 
     182       26865 : static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
     183             :                       const char *function,
     184             :                       const char *format, ...)
     185             : {
     186             :         va_list va;
     187             : 
     188       26865 :         va_start(va, format);
     189       26865 :         pwrap_vlog(dbglvl, function, format, va);
     190       26865 :         va_end(va);
     191       26865 : }
     192             : 
     193             : /*****************
     194             :  * LIBC
     195             :  *****************/
     196             : 
     197             : #define LIBPAM_NAME "libpam.so.0"
     198             : 
     199             : typedef int (*__libpam_pam_start)(const char *service_name,
     200             :                                   const char *user,
     201             :                                   const struct pam_conv *pam_conversation,
     202             :                                   pam_handle_t **pamh);
     203             : 
     204             : typedef int (*__libpam_pam_start_confdir)(const char *service_name,
     205             :                                           const char *user,
     206             :                                           const struct pam_conv *pam_conversation,
     207             :                                           const char *confdir,
     208             :                                           pam_handle_t **pamh);
     209             : 
     210             : typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
     211             : 
     212             : typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
     213             : 
     214             : typedef int (*__libpam_pam_chauthtok)(pam_handle_t *pamh, int flags);
     215             : 
     216             : typedef int (*__libpam_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
     217             : 
     218             : typedef int (*__libpam_pam_putenv)(pam_handle_t *pamh, const char *name_value);
     219             : 
     220             : typedef const char * (*__libpam_pam_getenv)(pam_handle_t *pamh, const char *name);
     221             : 
     222             : typedef char ** (*__libpam_pam_getenvlist)(pam_handle_t *pamh);
     223             : 
     224             : typedef int (*__libpam_pam_open_session)(pam_handle_t *pamh, int flags);
     225             : 
     226             : typedef int (*__libpam_pam_close_session)(pam_handle_t *pamh, int flags);
     227             : 
     228             : typedef int (*__libpam_pam_setcred)(pam_handle_t *pamh, int flags);
     229             : 
     230             : typedef int (*__libpam_pam_get_item)(const pam_handle_t *pamh,
     231             :                                      int item_type,
     232             :                                      const void **item);
     233             : 
     234             : typedef int (*__libpam_pam_set_item)(pam_handle_t *pamh,
     235             :                                      int item_type,
     236             :                                      const void *item);
     237             : 
     238             : typedef int (*__libpam_pam_get_data)(const pam_handle_t *pamh,
     239             :                                      const char *module_data_name,
     240             :                                      const void **data);
     241             : 
     242             : typedef int (*__libpam_pam_set_data)(pam_handle_t *pamh,
     243             :                                      const char *module_data_name,
     244             :                                      void *data,
     245             :                                      void (*cleanup)(pam_handle_t *pamh,
     246             :                                                      void *data,
     247             :                                                      int error_status));
     248             : 
     249             : typedef int (*__libpam_pam_vprompt)(pam_handle_t *pamh,
     250             :                                     int style,
     251             :                                     char **response,
     252             :                                     const char *fmt,
     253             :                                     va_list args);
     254             : 
     255             : typedef const char * (*__libpam_pam_strerror)(pam_handle_t *pamh,
     256             :                                               int errnum);
     257             : 
     258             : #ifdef HAVE_PAM_VSYSLOG
     259             : typedef void (*__libpam_pam_vsyslog)(const pam_handle_t *pamh,
     260             :                                      int priority,
     261             :                                      const char *fmt,
     262             :                                      va_list args);
     263             : #endif
     264             : 
     265             : #define PWRAP_SYMBOL_ENTRY(i) \
     266             :         union { \
     267             :                 __libpam_##i f; \
     268             :                 void *obj; \
     269             :         } _libpam_##i
     270             : 
     271             : struct pwrap_libpam_symbols {
     272             :         PWRAP_SYMBOL_ENTRY(pam_start);
     273             :         PWRAP_SYMBOL_ENTRY(pam_start_confdir);
     274             :         PWRAP_SYMBOL_ENTRY(pam_end);
     275             :         PWRAP_SYMBOL_ENTRY(pam_authenticate);
     276             :         PWRAP_SYMBOL_ENTRY(pam_chauthtok);
     277             :         PWRAP_SYMBOL_ENTRY(pam_acct_mgmt);
     278             :         PWRAP_SYMBOL_ENTRY(pam_putenv);
     279             :         PWRAP_SYMBOL_ENTRY(pam_getenv);
     280             :         PWRAP_SYMBOL_ENTRY(pam_getenvlist);
     281             :         PWRAP_SYMBOL_ENTRY(pam_open_session);
     282             :         PWRAP_SYMBOL_ENTRY(pam_close_session);
     283             :         PWRAP_SYMBOL_ENTRY(pam_setcred);
     284             :         PWRAP_SYMBOL_ENTRY(pam_get_item);
     285             :         PWRAP_SYMBOL_ENTRY(pam_set_item);
     286             :         PWRAP_SYMBOL_ENTRY(pam_get_data);
     287             :         PWRAP_SYMBOL_ENTRY(pam_set_data);
     288             :         PWRAP_SYMBOL_ENTRY(pam_vprompt);
     289             :         PWRAP_SYMBOL_ENTRY(pam_strerror);
     290             : #ifdef HAVE_PAM_VSYSLOG
     291             :         PWRAP_SYMBOL_ENTRY(pam_vsyslog);
     292             : #endif
     293             : };
     294             : 
     295             : struct pwrap {
     296             :         struct {
     297             :                 void *handle;
     298             :                 struct pwrap_libpam_symbols symbols;
     299             :         } libpam;
     300             : 
     301             :         bool enabled;
     302             :         bool initialised;
     303             :         char *config_dir;
     304             :         char *libpam_so;
     305             : };
     306             : 
     307             : static struct pwrap pwrap;
     308             : 
     309             : /*********************************************************
     310             :  * PWRAP PROTOTYPES
     311             :  *********************************************************/
     312             : 
     313             : bool pam_wrapper_enabled(void);
     314             : #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
     315             : /* xlC and other oldschool compilers support (only) this */
     316             : #pragma init (pwrap_constructor)
     317             : #endif
     318             : void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
     319             : #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
     320             : #pragma fini (pwrap_destructor)
     321             : #endif
     322             : void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
     323             : 
     324             : /*********************************************************
     325             :  * PWRAP LIBC LOADER FUNCTIONS
     326             :  *********************************************************/
     327             : 
     328             : enum pwrap_lib {
     329             :     PWRAP_LIBPAM,
     330             : };
     331             : 
     332         708 : static void *pwrap_load_lib_handle(enum pwrap_lib lib)
     333             : {
     334         708 :         int flags = RTLD_LAZY;
     335         708 :         void *handle = NULL;
     336             : 
     337             : #ifdef RTLD_DEEPBIND
     338         708 :         const char *env_preload = getenv("LD_PRELOAD");
     339         708 :         const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
     340         708 :         bool enable_deepbind = true;
     341             : 
     342             :         /* Don't do a deepbind if we run with libasan */
     343         708 :         if (env_preload != NULL && strlen(env_preload) < 1024) {
     344         708 :                 const char *p = strstr(env_preload, "libasan.so");
     345         708 :                 if (p != NULL) {
     346           0 :                         enable_deepbind = false;
     347             :                 }
     348             :         }
     349             : 
     350         708 :         if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
     351           0 :                 enable_deepbind = false;
     352             :         }
     353             : 
     354         708 :         if (enable_deepbind) {
     355         708 :                 flags |= RTLD_DEEPBIND;
     356             :         }
     357             : #endif
     358             : 
     359         708 :         switch (lib) {
     360         708 :         case PWRAP_LIBPAM:
     361         708 :                 handle = pwrap.libpam.handle;
     362         708 :                 if (handle == NULL) {
     363          98 :                         handle = dlopen(pwrap.libpam_so, flags);
     364          98 :                         if (handle != NULL) {
     365          98 :                                 PWRAP_LOG(PWRAP_LOG_DEBUG,
     366             :                                           "Opened %s\n", pwrap.libpam_so);
     367          98 :                                 pwrap.libpam.handle = handle;
     368          98 :                                 break;
     369             :                         }
     370             :                 }
     371         610 :                 break;
     372             :         }
     373             : 
     374         708 :         if (handle == NULL) {
     375           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     376             :                           "Failed to dlopen library: %s\n",
     377             :                           dlerror());
     378           0 :                 exit(-1);
     379             :         }
     380             : 
     381         708 :         return handle;
     382             : }
     383             : 
     384         708 : static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
     385             : {
     386             :         void *handle;
     387             :         void *func;
     388             : 
     389         708 :         handle = pwrap_load_lib_handle(lib);
     390             : 
     391         708 :         func = dlsym(handle, fn_name);
     392         708 :         if (func == NULL) {
     393           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     394             :                           "Failed to find %s: %s\n",
     395             :                           fn_name, dlerror());
     396           0 :                 exit(-1);
     397             :         }
     398             : 
     399         708 :         return func;
     400             : }
     401             : 
     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); \
     406             :         } \
     407             : 
     408             : /*
     409             :  * IMPORTANT
     410             :  *
     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.
     415             :  */
     416             : #ifdef HAVE_PAM_START_CONFDIR
     417         250 : static int libpam_pam_start_confdir(const char *service_name,
     418             :                                     const char *user,
     419             :                                     const struct pam_conv *pam_conversation,
     420             :                                     const char *confdir,
     421             :                                     pam_handle_t **pamh)
     422             : {
     423         250 :         pwrap_bind_symbol_libpam(pam_start_confdir);
     424             : 
     425         250 :         return pwrap.libpam.symbols._libpam_pam_start_confdir.f(service_name,
     426             :                                                                 user,
     427             :                                                                 pam_conversation,
     428             :                                                                 confdir,
     429             :                                                                 pamh);
     430             : }
     431             : #else
     432             : static int libpam_pam_start(const char *service_name,
     433             :                             const char *user,
     434             :                             const struct pam_conv *pam_conversation,
     435             :                             pam_handle_t **pamh)
     436             : {
     437             :         pwrap_bind_symbol_libpam(pam_start);
     438             : 
     439             :         return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
     440             :                                                         user,
     441             :                                                         pam_conversation,
     442             :                                                         pamh);
     443             : }
     444             : 
     445             : #endif
     446             : 
     447         250 : static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
     448             : {
     449         250 :         pwrap_bind_symbol_libpam(pam_end);
     450             : 
     451         250 :         return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
     452             : }
     453             : 
     454         238 : static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
     455             : {
     456         238 :         pwrap_bind_symbol_libpam(pam_authenticate);
     457             : 
     458         238 :         return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
     459             : }
     460             : 
     461          12 : static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
     462             : {
     463          12 :         pwrap_bind_symbol_libpam(pam_chauthtok);
     464             : 
     465          12 :         return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
     466             : }
     467             : 
     468           0 : static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
     469             : {
     470           0 :         pwrap_bind_symbol_libpam(pam_acct_mgmt);
     471             : 
     472           0 :         return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
     473             : }
     474             : 
     475          30 : static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
     476             : {
     477          30 :         pwrap_bind_symbol_libpam(pam_putenv);
     478             : 
     479          30 :         return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
     480             : }
     481             : 
     482           4 : static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
     483             : {
     484           4 :         pwrap_bind_symbol_libpam(pam_getenv);
     485             : 
     486           4 :         return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
     487             : }
     488             : 
     489           2 : static char **libpam_pam_getenvlist(pam_handle_t *pamh)
     490             : {
     491           2 :         pwrap_bind_symbol_libpam(pam_getenvlist);
     492             : 
     493           2 :         return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
     494             : }
     495             : 
     496           0 : static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
     497             : {
     498           0 :         pwrap_bind_symbol_libpam(pam_open_session);
     499             : 
     500           0 :         return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
     501             : }
     502             : 
     503           0 : static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
     504             : {
     505           0 :         pwrap_bind_symbol_libpam(pam_close_session);
     506             : 
     507           0 :         return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
     508             : }
     509             : 
     510           2 : static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
     511             : {
     512           2 :         pwrap_bind_symbol_libpam(pam_setcred);
     513             : 
     514           2 :         return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
     515             : }
     516             : 
     517        6170 : static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
     518             : {
     519        6170 :         pwrap_bind_symbol_libpam(pam_get_item);
     520             : 
     521        6170 :         return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
     522             : }
     523             : 
     524         944 : static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
     525             : {
     526         944 :         pwrap_bind_symbol_libpam(pam_set_item);
     527             : 
     528         944 :         return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
     529             : }
     530             : 
     531        3748 : static int libpam_pam_get_data(const pam_handle_t *pamh,
     532             :                                const char *module_data_name,
     533             :                                const void **data)
     534             : {
     535        3748 :         pwrap_bind_symbol_libpam(pam_get_data);
     536             : 
     537        3748 :         return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
     538             :                                                            module_data_name,
     539             :                                                            data);
     540             : }
     541             : 
     542         756 : static int libpam_pam_set_data(pam_handle_t *pamh,
     543             :                                const char *module_data_name,
     544             :                                void *data,
     545             :                                void (*cleanup)(pam_handle_t *pamh,
     546             :                                                void *data,
     547             :                                                int error_status))
     548             : {
     549         756 :         pwrap_bind_symbol_libpam(pam_set_data);
     550             : 
     551         756 :         return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
     552             :                                                            module_data_name,
     553             :                                                            data,
     554             :                                                            cleanup);
     555             : }
     556             : 
     557           0 : static int libpam_pam_vprompt(pam_handle_t *pamh,
     558             :                               int style,
     559             :                               char **response,
     560             :                               const char *fmt,
     561             :                               va_list args)
     562             : {
     563           0 :         pwrap_bind_symbol_libpam(pam_vprompt);
     564             : 
     565           0 :         return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
     566             :                                                           style,
     567             :                                                           response,
     568             :                                                           fmt,
     569             :                                                           args);
     570             : }
     571             : 
     572             : #ifdef HAVE_PAM_STRERROR_CONST
     573             : static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
     574             : #else
     575           0 : static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
     576             : #endif
     577             : {
     578           0 :         pwrap_bind_symbol_libpam(pam_strerror);
     579             : 
     580           0 :         return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
     581             : }
     582             : 
     583             : #ifdef HAVE_PAM_VSYSLOG
     584           0 : static void libpam_pam_vsyslog(const pam_handle_t *pamh,
     585             :                                int priority,
     586             :                                const char *fmt,
     587             :                                va_list args)
     588             : {
     589           0 :         pwrap_bind_symbol_libpam(pam_vsyslog);
     590             : 
     591           0 :         pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
     592             :                                                    priority,
     593             :                                                    fmt,
     594             :                                                    args);
     595           0 : }
     596             : #endif /* HAVE_PAM_VSYSLOG */
     597             : 
     598             : /*********************************************************
     599             :  * PWRAP INIT
     600             :  *********************************************************/
     601             : 
     602             : #define BUFFER_SIZE 32768
     603             : 
     604             : /* copy file from src to dst, overwrites dst */
     605         278 : static int p_copy(const char *src, const char *dst, mode_t mode)
     606             : {
     607         278 :         int srcfd = -1;
     608         278 :         int dstfd = -1;
     609         278 :         int rc = -1;
     610             :         ssize_t bread, bwritten;
     611             :         struct stat sb;
     612             :         char buf[BUFFER_SIZE];
     613             :         int cmp;
     614             : 
     615         278 :         cmp = strcmp(src, dst);
     616         278 :         if (cmp == 0) {
     617           0 :                 return -1;
     618             :         }
     619             : 
     620         278 :         srcfd = open(src, O_RDONLY, 0);
     621         278 :         if (srcfd < 0) {
     622           0 :                 return -1;
     623             :         }
     624             : 
     625         278 :         if (mode == 0) {
     626           0 :                 rc = fstat(srcfd, &sb);
     627           0 :                 if (rc != 0) {
     628           0 :                         rc = -1;
     629           0 :                         goto out;
     630             :                 }
     631           0 :                 mode = sb.st_mode;
     632             :         }
     633             : 
     634         278 :         dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
     635         278 :         if (dstfd < 0) {
     636           0 :                 rc = -1;
     637           0 :                 goto out;
     638             :         }
     639             : 
     640             :         for (;;) {
     641         556 :                 bread = read(srcfd, buf, BUFFER_SIZE);
     642         556 :                 if (bread == 0) {
     643             :                         /* done */
     644         278 :                         break;
     645         278 :                 } else if (bread < 0) {
     646           0 :                         errno = EIO;
     647           0 :                         rc = -1;
     648           0 :                         goto out;
     649             :                 }
     650             : 
     651         278 :                 bwritten = write(dstfd, buf, bread);
     652         278 :                 if (bwritten < 0) {
     653           0 :                         errno = EIO;
     654           0 :                         rc = -1;
     655           0 :                         goto out;
     656             :                 }
     657             : 
     658         278 :                 if (bread != bwritten) {
     659           0 :                         errno = EFAULT;
     660           0 :                         rc = -1;
     661           0 :                         goto out;
     662             :                 }
     663             :         }
     664             : 
     665         278 :         rc = 0;
     666         278 : out:
     667         278 :         if (srcfd != -1) {
     668         278 :                 close(srcfd);
     669             :         }
     670         278 :         if (dstfd != -1) {
     671         278 :                 close(dstfd);
     672             :         }
     673         278 :         if (rc < 0) {
     674           0 :                 unlink(dst);
     675             :         }
     676             : 
     677         278 :         return rc;
     678             : }
     679             : 
     680             : /* Do not pass any flag if not defined */
     681             : #ifndef FTW_ACTIONRETVAL
     682             : #define FTW_ACTIONRETVAL 0
     683             : #endif
     684             : 
     685             : /* Action return values */
     686             : #ifndef FTW_STOP
     687             : #define FTW_STOP -1
     688             : #endif
     689             : 
     690             : #ifndef FTW_CONTINUE
     691             : #define FTW_CONTINUE 0
     692             : #endif
     693             : 
     694             : #ifndef FTW_SKIP_SUBTREE
     695             : #define FTW_SKIP_SUBTREE 0
     696             : #endif
     697             : 
     698         556 : static int copy_ftw(const char *fpath,
     699             :                     const struct stat *sb,
     700             :                     int typeflag,
     701             :                     struct FTW *ftwbuf)
     702             : {
     703             :         int rc;
     704             :         char buf[BUFFER_SIZE];
     705             : 
     706         556 :         switch (typeflag) {
     707         278 :         case FTW_D:
     708             :         case FTW_DNR:
     709             :                 /* We want to copy the directories from this directory */
     710         278 :                 if (ftwbuf->level == 0) {
     711         278 :                         return FTW_CONTINUE;
     712             :                 }
     713           0 :                 return FTW_SKIP_SUBTREE;
     714         278 :         case FTW_F:
     715         278 :                 break;
     716           0 :         default:
     717           0 :                 return FTW_CONTINUE;
     718             :         }
     719             : 
     720         278 :         rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
     721         278 :         if (rc >= BUFFER_SIZE) {
     722           0 :                 return FTW_STOP;
     723             :         }
     724             : 
     725         278 :         PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
     726         278 :         rc = p_copy(fpath, buf, sb->st_mode);
     727         278 :         if (rc != 0) {
     728           0 :                 return FTW_STOP;
     729             :         }
     730             : 
     731         278 :         return FTW_CONTINUE;
     732             : }
     733             : 
     734         278 : static int copy_confdir(const char *src)
     735             : {
     736             :         int rc;
     737             : 
     738         278 :         PWRAP_LOG(PWRAP_LOG_DEBUG,
     739             :                   "Copy config files from %s to %s",
     740             :                   src,
     741             :                   pwrap.config_dir);
     742         278 :         rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
     743         278 :         if (rc != 0) {
     744           0 :                 return -1;
     745             :         }
     746             : 
     747         278 :         return 0;
     748             : }
     749             : 
     750             : static int p_rmdirs(const char *path);
     751             : 
     752           0 : static void pwrap_clean_stale_dirs(const char *dir)
     753           0 : {
     754           0 :         size_t len = strlen(dir);
     755           0 :         char pidfile[len + 5];
     756             :         ssize_t rc;
     757           0 :         char buf[8] = {0};
     758             :         long int tmp;
     759             :         pid_t pid;
     760             :         int fd;
     761             : 
     762           0 :         snprintf(pidfile,
     763             :                  sizeof(pidfile),
     764             :                  "%s/pid",
     765             :                  dir);
     766             : 
     767             :         /* read the pidfile */
     768           0 :         fd = open(pidfile, O_RDONLY);
     769           0 :         if (fd < 0) {
     770           0 :                 if (errno == ENOENT) {
     771           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
     772             :                                   "pidfile %s missing, nothing to do\n",
     773             :                                   pidfile);
     774             :                 } else {
     775           0 :                         PWRAP_LOG(PWRAP_LOG_ERROR,
     776             :                                   "Failed to open pidfile %s - error: %s",
     777             :                                   pidfile, strerror(errno));
     778             :                 }
     779           0 :                 return;
     780             :         }
     781             : 
     782           0 :         rc = read(fd, buf, sizeof(buf));
     783           0 :         close(fd);
     784           0 :         if (rc < 0) {
     785           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     786             :                           "Failed to read pidfile %s - error: %s",
     787             :                           pidfile, strerror(errno));
     788           0 :                 return;
     789             :         }
     790             : 
     791           0 :         buf[sizeof(buf) - 1] = '\0';
     792             : 
     793           0 :         tmp = strtol(buf, NULL, 10);
     794           0 :         if (tmp == 0 || errno == ERANGE) {
     795           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     796             :                           "Failed to parse pid, buf=%s",
     797             :                           buf);
     798           0 :                 return;
     799             :         }
     800             : 
     801           0 :         pid = (pid_t)tmp;
     802             :         /* Check if we are out of pid_t range on this system */
     803           0 :         if ((long)pid != tmp) {
     804           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     805             :                           "pid out of range: %ld", tmp);
     806           0 :                 return;
     807             :         }
     808             : 
     809           0 :         rc = kill(pid, 0);
     810           0 :         if (rc == -1) {
     811           0 :                 PWRAP_LOG(PWRAP_LOG_TRACE,
     812             :                           "Remove stale pam_wrapper dir: %s",
     813             :                           dir);
     814           0 :                 p_rmdirs(dir);
     815             :         }
     816             : 
     817           0 :         return;
     818             : }
     819             : 
     820             : #ifdef HAVE_PAM_START_CONFDIR
     821         564 : static void pwrap_init(void)
     822             : {
     823         564 :         char tmp_config_dir[] = "/tmp/pam.X";
     824         564 :         size_t len = strlen(tmp_config_dir);
     825             :         const char *env;
     826             :         struct stat sb;
     827             :         int rc;
     828             :         unsigned i;
     829             :         ssize_t ret;
     830             :         FILE *pidfile;
     831         564 :         char pidfile_path[1024] = { 0 };
     832             :         char letter;
     833             : 
     834         564 :         if (!pam_wrapper_enabled()) {
     835         286 :                 return;
     836             :         }
     837             : 
     838         528 :         if (pwrap.initialised) {
     839         250 :                 return;
     840             :         }
     841             : 
     842             :         /*
     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.
     846             :          */
     847         278 :         letter = 48 + (getpid() % 70);
     848         487 :         for (i = 0; i < 127; i++) {
     849         487 :                 if (isalpha(letter) || isdigit(letter)) {
     850         278 :                         tmp_config_dir[len - 1] = letter;
     851             : 
     852         278 :                         rc = lstat(tmp_config_dir, &sb);
     853         278 :                         if (rc == 0) {
     854           0 :                                 PWRAP_LOG(PWRAP_LOG_TRACE,
     855             :                                           "Check if pam_wrapper dir %s is a "
     856             :                                           "stale directory",
     857             :                                           tmp_config_dir);
     858           0 :                                 pwrap_clean_stale_dirs(tmp_config_dir);
     859         278 :                         } else if (rc < 0) {
     860         278 :                                 if (errno != ENOENT) {
     861           0 :                                         continue;
     862             :                                 }
     863         278 :                                 break; /* found */
     864             :                         }
     865             :                 }
     866             : 
     867         209 :                 letter++;
     868         209 :                 letter %= 127;
     869             :         }
     870             : 
     871         278 :         if (i == 127) {
     872           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     873             :                           "Failed to find a possible path to create "
     874             :                           "pam_wrapper config dir: %s",
     875             :                           tmp_config_dir);
     876           0 :                 exit(1);
     877             :         }
     878             : 
     879         278 :         PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
     880             : 
     881         278 :         pwrap.config_dir = strdup(tmp_config_dir);
     882         278 :         if (pwrap.config_dir == NULL) {
     883           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     884             :                           "No memory");
     885           0 :                 exit(1);
     886             :         }
     887         278 :         PWRAP_LOG(PWRAP_LOG_TRACE,
     888             :                   "pam_wrapper config dir: %s",
     889             :                   tmp_config_dir);
     890             : 
     891         278 :         rc = mkdir(pwrap.config_dir, 0755);
     892         278 :         if (rc != 0) {
     893           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR,
     894             :                           "Failed to create pam_wrapper config dir: %s - %s",
     895             :                           tmp_config_dir, strerror(errno));
     896             :         }
     897             : 
     898             :         /* Create file with the PID of the the process */
     899         278 :         ret = snprintf(pidfile_path, sizeof(pidfile_path),
     900             :                        "%s/pid", pwrap.config_dir);
     901         278 :         if (ret < 0) {
     902           0 :                 p_rmdirs(pwrap.config_dir);
     903           0 :                 exit(1);
     904             :         }
     905             : 
     906         278 :         pidfile = fopen(pidfile_path, "w");
     907         278 :         if (pidfile == NULL) {
     908           0 :                 p_rmdirs(pwrap.config_dir);
     909           0 :                 exit(1);
     910             :         }
     911             : 
     912         278 :         rc = fprintf(pidfile, "%d", getpid());
     913         278 :         fclose(pidfile);
     914         278 :         if (rc <= 0) {
     915           0 :                 p_rmdirs(pwrap.config_dir);
     916           0 :                 exit(1);
     917             :         }
     918             : 
     919         278 :         pwrap.libpam_so = strdup(PAM_LIBRARY);
     920         278 :         if (pwrap.libpam_so == NULL) {
     921           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
     922           0 :                 p_rmdirs(pwrap.config_dir);
     923           0 :                 exit(1);
     924             :         }
     925             : 
     926         278 :         PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
     927             : 
     928         278 :         pwrap.initialised = true;
     929             : 
     930         278 :         env = getenv("PAM_WRAPPER_SERVICE_DIR");
     931         278 :         if (env == NULL) {
     932           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
     933           0 :                 p_rmdirs(pwrap.config_dir);
     934           0 :                 exit(1);
     935             :         }
     936             : 
     937         278 :         rc = copy_confdir(env);
     938         278 :         if (rc != 0) {
     939           0 :                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
     940           0 :                 p_rmdirs(pwrap.config_dir);
     941           0 :                 exit(1);
     942             :         }
     943             : 
     944         278 :         setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
     945             : 
     946         278 :         PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
     947             : }
     948             : 
     949             : #else /* HAVE_PAM_START_CONFDIR */
     950             : 
     951             : static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
     952             : {
     953             : #define PSO_COPY_READ_SIZE 9
     954             :         int srcfd = -1;
     955             :         int dstfd = -1;
     956             :         int rc = -1;
     957             :         ssize_t bread, bwritten;
     958             :         struct stat sb;
     959             :         char buf[PSO_COPY_READ_SIZE + 1];
     960             :         int cmp;
     961             :         size_t to_read;
     962             :         bool found_slash;
     963             : 
     964             :         cmp = strcmp(src, dst);
     965             :         if (cmp == 0) {
     966             :                 return -1;
     967             :         }
     968             : 
     969             :         srcfd = open(src, O_RDONLY, 0);
     970             :         if (srcfd < 0) {
     971             :                 return -1;
     972             :         }
     973             : 
     974             :         if (mode == 0) {
     975             :                 rc = fstat(srcfd, &sb);
     976             :                 if (rc != 0) {
     977             :                         rc = -1;
     978             :                         goto out;
     979             :                 }
     980             :                 mode = sb.st_mode;
     981             :         }
     982             : 
     983             :         dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
     984             :         if (dstfd < 0) {
     985             :                 rc = -1;
     986             :                 goto out;
     987             :         }
     988             : 
     989             :         found_slash = false;
     990             :         to_read = 1;
     991             : 
     992             :         for (;;) {
     993             :                 bread = read(srcfd, buf, to_read);
     994             :                 if (bread == 0) {
     995             :                         /* done */
     996             :                         break;
     997             :                 } else if (bread < 0) {
     998             :                         errno = EIO;
     999             :                         rc = -1;
    1000             :                         goto out;
    1001             :                 }
    1002             : 
    1003             :                 to_read = 1;
    1004             :                 if (!found_slash && buf[0] == '/') {
    1005             :                         found_slash = true;
    1006             :                         to_read = PSO_COPY_READ_SIZE;
    1007             :                 }
    1008             : 
    1009             :                 if (found_slash && bread == PSO_COPY_READ_SIZE) {
    1010             :                         cmp = memcmp(buf, "etc/pam.d", PSO_COPY_READ_SIZE);
    1011             :                         if (cmp == 0) {
    1012             :                                 memcpy(buf, pdir + 1, PSO_COPY_READ_SIZE);
    1013             :                         }
    1014             :                         found_slash = false;
    1015             :                 }
    1016             : 
    1017             :                 bwritten = write(dstfd, buf, bread);
    1018             :                 if (bwritten < 0) {
    1019             :                         errno = EIO;
    1020             :                         rc = -1;
    1021             :                         goto out;
    1022             :                 }
    1023             : 
    1024             :                 if (bread != bwritten) {
    1025             :                         errno = EFAULT;
    1026             :                         rc = -1;
    1027             :                         goto out;
    1028             :                 }
    1029             :         }
    1030             : 
    1031             :         rc = 0;
    1032             : out:
    1033             :         if (srcfd != -1) {
    1034             :                 close(srcfd);
    1035             :         }
    1036             :         if (dstfd != -1) {
    1037             :                 close(dstfd);
    1038             :         }
    1039             :         if (rc < 0) {
    1040             :                 unlink(dst);
    1041             :         }
    1042             : 
    1043             :         return rc;
    1044             : #undef PSO_COPY_READ_SIZE
    1045             : }
    1046             : 
    1047             : static void pwrap_init(void)
    1048             : {
    1049             :         char tmp_config_dir[] = "/tmp/pam.X";
    1050             :         size_t len = strlen(tmp_config_dir);
    1051             :         const char *env;
    1052             :         struct stat sb;
    1053             :         int rc;
    1054             :         unsigned i;
    1055             :         char pam_library[128] = { 0 };
    1056             :         char libpam_path[1024] = { 0 };
    1057             :         ssize_t ret;
    1058             :         FILE *pidfile;
    1059             :         char pidfile_path[1024] = { 0 };
    1060             :         char letter;
    1061             : 
    1062             :         if (!pam_wrapper_enabled()) {
    1063             :                 return;
    1064             :         }
    1065             : 
    1066             :         if (pwrap.initialised) {
    1067             :                 return;
    1068             :         }
    1069             : 
    1070             :         /*
    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.
    1074             :          */
    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;
    1079             : 
    1080             :                         rc = lstat(tmp_config_dir, &sb);
    1081             :                         if (rc == 0) {
    1082             :                                 PWRAP_LOG(PWRAP_LOG_TRACE,
    1083             :                                           "Check if pam_wrapper dir %s is a "
    1084             :                                           "stale directory",
    1085             :                                           tmp_config_dir);
    1086             :                                 pwrap_clean_stale_dirs(tmp_config_dir);
    1087             :                         } else if (rc < 0) {
    1088             :                                 if (errno != ENOENT) {
    1089             :                                         continue;
    1090             :                                 }
    1091             :                                 break; /* found */
    1092             :                         }
    1093             :                 }
    1094             : 
    1095             :                 letter++;
    1096             :                 letter %= 127;
    1097             :         }
    1098             : 
    1099             :         if (i == 127) {
    1100             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1101             :                           "Failed to find a possible path to create "
    1102             :                           "pam_wrapper config dir: %s",
    1103             :                           tmp_config_dir);
    1104             :                 exit(1);
    1105             :         }
    1106             : 
    1107             :         PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
    1108             : 
    1109             :         pwrap.config_dir = strdup(tmp_config_dir);
    1110             :         if (pwrap.config_dir == NULL) {
    1111             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1112             :                           "No memory");
    1113             :                 exit(1);
    1114             :         }
    1115             :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1116             :                   "pam_wrapper config dir: %s",
    1117             :                   tmp_config_dir);
    1118             : 
    1119             :         rc = mkdir(pwrap.config_dir, 0755);
    1120             :         if (rc != 0) {
    1121             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1122             :                           "Failed to create pam_wrapper config dir: %s - %s",
    1123             :                           tmp_config_dir, strerror(errno));
    1124             :         }
    1125             : 
    1126             :         /* Create file with the PID of the the process */
    1127             :         ret = snprintf(pidfile_path, sizeof(pidfile_path),
    1128             :                        "%s/pid", pwrap.config_dir);
    1129             :         if (ret < 0) {
    1130             :                 p_rmdirs(pwrap.config_dir);
    1131             :                 exit(1);
    1132             :         }
    1133             : 
    1134             :         pidfile = fopen(pidfile_path, "w");
    1135             :         if (pidfile == NULL) {
    1136             :                 p_rmdirs(pwrap.config_dir);
    1137             :                 exit(1);
    1138             :         }
    1139             : 
    1140             :         rc = fprintf(pidfile, "%d", getpid());
    1141             :         fclose(pidfile);
    1142             :         if (rc <= 0) {
    1143             :                 p_rmdirs(pwrap.config_dir);
    1144             :                 exit(1);
    1145             :         }
    1146             : 
    1147             :         /* create lib subdirectory */
    1148             :         snprintf(libpam_path,
    1149             :                  sizeof(libpam_path),
    1150             :                  "%s/lib",
    1151             :                  pwrap.config_dir);
    1152             : 
    1153             :         rc = mkdir(libpam_path, 0755);
    1154             :         if (rc != 0) {
    1155             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1156             :                           "Failed to create path for libpam: %s - %s",
    1157             :                           tmp_config_dir, strerror(errno));
    1158             :                 p_rmdirs(pwrap.config_dir);
    1159             :                 exit(1);
    1160             :         }
    1161             : 
    1162             :         snprintf(libpam_path,
    1163             :                  sizeof(libpam_path),
    1164             :                  "%s/lib/%s",
    1165             :                  pwrap.config_dir,
    1166             :                  LIBPAM_NAME);
    1167             : 
    1168             :         pwrap.libpam_so = strdup(libpam_path);
    1169             :         if (pwrap.libpam_so == NULL) {
    1170             :                 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
    1171             :                 p_rmdirs(pwrap.config_dir);
    1172             :                 exit(1);
    1173             :         }
    1174             : 
    1175             :         /* copy libpam.so.0 */
    1176             :         snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
    1177             :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1178             :                   "PAM path: %s",
    1179             :                   libpam_path);
    1180             : 
    1181             :         ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
    1182             :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1183             :                   "PAM library: %s",
    1184             :                   pam_library);
    1185             :         if (ret <= 0) {
    1186             :                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
    1187             :                 p_rmdirs(pwrap.config_dir);
    1188             :                 exit(1);
    1189             :         }
    1190             : 
    1191             :         if (pam_library[0] == '/') {
    1192             :                 snprintf(libpam_path,
    1193             :                          sizeof(libpam_path),
    1194             :                          "%s",
    1195             :                          pam_library);
    1196             :         } else {
    1197             :                 char libpam_path_cp[1024] = {0};
    1198             :                 char *dname = NULL;
    1199             : 
    1200             :                 snprintf(libpam_path_cp,
    1201             :                          sizeof(libpam_path_cp),
    1202             :                          "%s",
    1203             :                          libpam_path);
    1204             : 
    1205             :                 dname = dirname(libpam_path_cp);
    1206             :                 if (dname == NULL) {
    1207             :                         PWRAP_LOG(PWRAP_LOG_ERROR,
    1208             :                                   "No directory component in %s", libpam_path);
    1209             :                         p_rmdirs(pwrap.config_dir);
    1210             :                         exit(1);
    1211             :                 }
    1212             : 
    1213             :                 snprintf(libpam_path,
    1214             :                          sizeof(libpam_path),
    1215             :                          "%s/%s",
    1216             :                          dname,
    1217             :                          pam_library);
    1218             :         }
    1219             :         PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
    1220             : 
    1221             :         PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
    1222             :         rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
    1223             :         if (rc != 0) {
    1224             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1225             :                           "Failed to copy %s - error: %s",
    1226             :                           LIBPAM_NAME,
    1227             :                           strerror(errno));
    1228             :                 p_rmdirs(pwrap.config_dir);
    1229             :                 exit(1);
    1230             :         }
    1231             : 
    1232             :         PWRAP_LOG(PWRAP_LOG_TRACE, "Using libpam path: %s", pwrap.libpam_so);
    1233             : 
    1234             :         pwrap.initialised = true;
    1235             : 
    1236             :         env = getenv("PAM_WRAPPER_SERVICE_DIR");
    1237             :         if (env == NULL) {
    1238             :                 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
    1239             :                 p_rmdirs(pwrap.config_dir);
    1240             :                 exit(1);
    1241             :         }
    1242             : 
    1243             :         rc = copy_confdir(env);
    1244             :         if (rc != 0) {
    1245             :                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
    1246             :                 p_rmdirs(pwrap.config_dir);
    1247             :                 exit(1);
    1248             :         }
    1249             : 
    1250             :         setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
    1251             : 
    1252             :         PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
    1253             : }
    1254             : #endif /* HAVE_PAM_START_CONFDIR */
    1255             : 
    1256         564 : bool pam_wrapper_enabled(void)
    1257             : {
    1258             :         const char *env;
    1259             : 
    1260         564 :         pwrap.enabled = false;
    1261             : 
    1262         564 :         env = getenv("PAM_WRAPPER");
    1263         564 :         if (env != NULL && env[0] == '1') {
    1264         528 :                 pwrap.enabled = true;
    1265             :         }
    1266             : 
    1267         564 :         if (pwrap.enabled) {
    1268         528 :                 pwrap.enabled = false;
    1269             : 
    1270         528 :                 env = getenv("PAM_WRAPPER_SERVICE_DIR");
    1271         528 :                 if (env != NULL && env[0] != '\0') {
    1272         528 :                         pwrap.enabled = true;
    1273             :                 }
    1274             :         }
    1275             : 
    1276         564 :         return pwrap.enabled;
    1277             : }
    1278             : 
    1279             : #ifdef HAVE_OPENPAM
    1280             : static int pwrap_openpam_start(const char *service_name,
    1281             :                                const char *user,
    1282             :                                const struct pam_conv *pam_conversation,
    1283             :                                pam_handle_t **pamh)
    1284             : {
    1285             :         int rv;
    1286             :         char fullpath[1024];
    1287             : 
    1288             :         rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
    1289             :         if (rv != PAM_SUCCESS) {
    1290             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1291             :                           "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
    1292             :                 return rv;
    1293             :         }
    1294             : 
    1295             :         rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
    1296             :         if (rv != PAM_SUCCESS) {
    1297             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1298             :                           "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
    1299             :                 return rv;
    1300             :         }
    1301             : 
    1302             :         rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
    1303             :         if (rv != PAM_SUCCESS) {
    1304             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1305             :                           "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
    1306             :                 return rv;
    1307             :         }
    1308             : 
    1309             :         rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
    1310             :         if (rv != PAM_SUCCESS) {
    1311             :                 PWRAP_LOG(PWRAP_LOG_ERROR,
    1312             :                           "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
    1313             :                 return rv;
    1314             :         }
    1315             : 
    1316             :         snprintf(fullpath,
    1317             :                  sizeof(fullpath),
    1318             :                  "%s/%s",
    1319             :                  pwrap.config_dir,
    1320             :                  service_name);
    1321             : 
    1322             :         return libpam_pam_start(fullpath,
    1323             :                                 user,
    1324             :                                 pam_conversation,
    1325             :                                 pamh);
    1326             : }
    1327             : #endif
    1328             : 
    1329         250 : static int pwrap_pam_start(const char *service_name,
    1330             :                            const char *user,
    1331             :                            const struct pam_conv *pam_conversation,
    1332             :                            pam_handle_t **pamh)
    1333             : {
    1334             :         int rc;
    1335             : 
    1336         250 :         pwrap_init();
    1337             : 
    1338         250 :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1339             :                   "pam_start service=%s, user=%s",
    1340             :                   service_name,
    1341             :                   user);
    1342             : 
    1343             : #if defined(HAVE_OPENPAM)
    1344             :         rc = pwrap_openpam_start(service_name,
    1345             :                                  user,
    1346             :                                  pam_conversation,
    1347             :                                  pamh);
    1348             : #elif defined (HAVE_PAM_START_CONFDIR)
    1349         250 :         rc = libpam_pam_start_confdir(service_name,
    1350             :                                       user,
    1351             :                                       pam_conversation,
    1352         250 :                                       pwrap.config_dir,
    1353             :                                       pamh);
    1354             : #else
    1355             :         rc = libpam_pam_start(service_name,
    1356             :                               user,
    1357             :                               pam_conversation,
    1358             :                               pamh);
    1359             : #endif
    1360         250 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_start rc=%d", rc);
    1361             : 
    1362         250 :         return rc;
    1363             : }
    1364             : 
    1365             : 
    1366             : int pam_start(const char *service_name,
    1367             :               const char *user,
    1368             :               const struct pam_conv *pam_conversation,
    1369             :               pam_handle_t **pamh)
    1370             : {
    1371         250 :         return pwrap_pam_start(service_name, user, pam_conversation, pamh);
    1372             : }
    1373             : 
    1374         250 : static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
    1375             : {
    1376         250 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
    1377         250 :         return libpam_pam_end(pamh, pam_status);
    1378             : }
    1379             : 
    1380             : 
    1381             : int pam_end(pam_handle_t *pamh, int pam_status)
    1382             : {
    1383         250 :         return pwrap_pam_end(pamh, pam_status);
    1384             : }
    1385             : 
    1386         238 : static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
    1387             : {
    1388         238 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
    1389         238 :         return libpam_pam_authenticate(pamh, flags);
    1390             : }
    1391             : 
    1392             : int pam_authenticate(pam_handle_t *pamh, int flags)
    1393             : {
    1394         238 :         return pwrap_pam_authenticate(pamh, flags);
    1395             : }
    1396             : 
    1397          12 : static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
    1398             : {
    1399          12 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
    1400          12 :         return libpam_pam_chauthtok(pamh, flags);
    1401             : }
    1402             : 
    1403             : int pam_chauthtok(pam_handle_t *pamh, int flags)
    1404             : {
    1405          12 :         return pwrap_pam_chauthtok(pamh, flags);
    1406             : }
    1407             : 
    1408           0 : static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
    1409             : {
    1410           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
    1411           0 :         return libpam_pam_acct_mgmt(pamh, flags);
    1412             : }
    1413             : 
    1414             : int pam_acct_mgmt(pam_handle_t *pamh, int flags)
    1415             : {
    1416           0 :         return pwrap_pam_acct_mgmt(pamh, flags);
    1417             : }
    1418             : 
    1419          30 : static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
    1420             : {
    1421          30 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
    1422          30 :         return libpam_pam_putenv(pamh, name_value);
    1423             : }
    1424             : 
    1425             : int pam_putenv(pam_handle_t *pamh, const char *name_value)
    1426             : {
    1427          30 :         return pwrap_pam_putenv(pamh, name_value);
    1428             : }
    1429             : 
    1430           4 : static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
    1431             : {
    1432           4 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
    1433           4 :         return libpam_pam_getenv(pamh, name);
    1434             : }
    1435             : 
    1436             : const char *pam_getenv(pam_handle_t *pamh, const char *name)
    1437             : {
    1438           4 :         return pwrap_pam_getenv(pamh, name);
    1439             : }
    1440             : 
    1441           2 : static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
    1442             : {
    1443           2 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
    1444           2 :         return libpam_pam_getenvlist(pamh);
    1445             : }
    1446             : 
    1447             : char **pam_getenvlist(pam_handle_t *pamh)
    1448             : {
    1449           2 :         return pwrap_pam_getenvlist(pamh);
    1450             : }
    1451             : 
    1452           0 : static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
    1453             : {
    1454           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
    1455           0 :         return libpam_pam_open_session(pamh, flags);
    1456             : }
    1457             : 
    1458             : int pam_open_session(pam_handle_t *pamh, int flags)
    1459             : {
    1460           0 :         return pwrap_pam_open_session(pamh, flags);
    1461             : }
    1462             : 
    1463           0 : static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
    1464             : {
    1465           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
    1466           0 :         return libpam_pam_close_session(pamh, flags);
    1467             : }
    1468             : 
    1469             : int pam_close_session(pam_handle_t *pamh, int flags)
    1470             : {
    1471           0 :         return pwrap_pam_close_session(pamh, flags);
    1472             : }
    1473             : 
    1474           2 : static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
    1475             : {
    1476           2 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
    1477           2 :         return libpam_pam_setcred(pamh, flags);
    1478             : }
    1479             : 
    1480             : int pam_setcred(pam_handle_t *pamh, int flags)
    1481             : {
    1482           2 :         return pwrap_pam_setcred(pamh, flags);
    1483             : }
    1484             : 
    1485         798 : static const char *pwrap_get_service(const char *libpam_service)
    1486             : {
    1487             : #ifdef HAVE_OPENPAM
    1488             :         const char *service_name;
    1489             : 
    1490             :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1491             :                   "internal PAM_SERVICE=%s", libpam_service);
    1492             :         service_name = strrchr(libpam_service, '/');
    1493             :         if (service_name != NULL && service_name[0] == '/') {
    1494             :                 service_name++;
    1495             :         }
    1496             :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1497             :                   "PAM_SERVICE=%s", service_name);
    1498             :         return service_name;
    1499             : #else
    1500         798 :         return libpam_service;
    1501             : #endif
    1502             : }
    1503             : 
    1504        6170 : static int pwrap_pam_get_item(const pam_handle_t *pamh,
    1505             :                               int item_type,
    1506             :                               const void **item)
    1507             : {
    1508             :         int rc;
    1509             :         const char *svc;
    1510             : 
    1511        6170 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
    1512             : 
    1513        6170 :         rc = libpam_pam_get_item(pamh, item_type, item);
    1514             : 
    1515        6170 :         if (rc == PAM_SUCCESS) {
    1516        6170 :                 switch(item_type) {
    1517         532 :                 case PAM_USER:
    1518         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1519             :                                   "pwrap_get_item PAM_USER=%s",
    1520             :                                   (const char *)*item);
    1521         532 :                         break;
    1522         798 :                 case PAM_SERVICE:
    1523         798 :                         svc = pwrap_get_service((const char *) *item);
    1524             : 
    1525         798 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1526             :                                   "pwrap_get_item PAM_SERVICE=%s",
    1527             :                                   svc);
    1528         798 :                         *item = svc;
    1529         798 :                         break;
    1530         532 :                 case PAM_USER_PROMPT:
    1531         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1532             :                                   "pwrap_get_item PAM_USER_PROMPT=%s",
    1533             :                                   (const char *)*item);
    1534         532 :                         break;
    1535         532 :                 case PAM_TTY:
    1536         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1537             :                                   "pwrap_get_item PAM_TTY=%s",
    1538             :                                   (const char *)*item);
    1539         532 :                         break;
    1540         532 :                 case PAM_RUSER:
    1541         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1542             :                                   "pwrap_get_item PAM_RUSER=%s",
    1543             :                                   (const char *)*item);
    1544         532 :                         break;
    1545         532 :                 case PAM_RHOST:
    1546         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1547             :                                   "pwrap_get_item PAM_RHOST=%s",
    1548             :                                   (const char *)*item);
    1549         532 :                         break;
    1550         782 :                 case PAM_AUTHTOK:
    1551         782 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1552             :                                   "pwrap_get_item PAM_AUTHTOK=%s",
    1553             :                                   (const char *)*item);
    1554         782 :                         break;
    1555         556 :                 case PAM_OLDAUTHTOK:
    1556         556 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1557             :                                   "pwrap_get_item PAM_OLDAUTHTOK=%s",
    1558             :                                   (const char *)*item);
    1559         556 :                         break;
    1560         842 :                 case PAM_CONV:
    1561         842 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1562             :                                   "pwrap_get_item PAM_CONV=%p",
    1563             :                                   (const void *)*item);
    1564         842 :                         break;
    1565         532 :                 default:
    1566         532 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1567             :                                   "pwrap_get_item item_type=%d item=%p",
    1568             :                                   item_type, (const void *)*item);
    1569         532 :                         break;
    1570             :                 }
    1571             :         } else {
    1572           0 :                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
    1573             :         }
    1574             : 
    1575        6170 :         return rc;
    1576             : }
    1577             : 
    1578             : int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
    1579             : {
    1580        6170 :         return pwrap_pam_get_item(pamh, item_type, item);
    1581             : }
    1582             : 
    1583         944 : static int pwrap_pam_set_item(pam_handle_t *pamh,
    1584             :                               int item_type,
    1585             :                               const void *item)
    1586             : {
    1587             :         int rc;
    1588             : 
    1589         944 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
    1590             : 
    1591         944 :         rc = libpam_pam_set_item(pamh, item_type, item);
    1592         944 :         if (rc == PAM_SUCCESS) {
    1593         944 :                 switch(item_type) {
    1594         162 :                 case PAM_USER:
    1595         162 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1596             :                                   "pwrap_set_item PAM_USER=%s",
    1597             :                                   (const char *)item);
    1598         162 :                         break;
    1599           0 :                 case PAM_SERVICE:
    1600           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1601             :                                   "pwrap_set_item PAM_SERVICE=%s",
    1602             :                                   (const char *)item);
    1603           0 :                         break;
    1604           0 :                 case PAM_USER_PROMPT:
    1605           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1606             :                                   "pwrap_set_item PAM_USER_PROMPT=%s",
    1607             :                                   (const char *)item);
    1608           0 :                         break;
    1609           0 :                 case PAM_TTY:
    1610           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1611             :                                   "pwrap_set_item PAM_TTY=%s",
    1612             :                                   (const char *)item);
    1613           0 :                         break;
    1614           0 :                 case PAM_RUSER:
    1615           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1616             :                                   "pwrap_set_item PAM_RUSER=%s",
    1617             :                                   (const char *)item);
    1618           0 :                         break;
    1619           0 :                 case PAM_RHOST:
    1620           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1621             :                                   "pwrap_set_item PAM_RHOST=%s",
    1622             :                                   (const char *)item);
    1623           0 :                         break;
    1624         508 :                 case PAM_AUTHTOK:
    1625         508 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1626             :                                   "pwrap_set_item PAM_AUTHTOK=%s",
    1627             :                                   (const char *)item);
    1628         508 :                         break;
    1629         274 :                 case PAM_OLDAUTHTOK:
    1630         274 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1631             :                                   "pwrap_set_item PAM_OLDAUTHTOK=%s",
    1632             :                                   (const char *)item);
    1633         274 :                         break;
    1634           0 :                 case PAM_CONV:
    1635           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1636             :                                   "pwrap_set_item PAM_CONV=%p",
    1637             :                                   item);
    1638           0 :                         break;
    1639           0 :                 default:
    1640           0 :                         PWRAP_LOG(PWRAP_LOG_TRACE,
    1641             :                                   "pwrap_set_item item_type=%d item=%p",
    1642             :                                   item_type, item);
    1643           0 :                         break;
    1644             :                 }
    1645             :         } else {
    1646           0 :                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
    1647             :         }
    1648             : 
    1649         944 :         return rc;
    1650             : }
    1651             : 
    1652             : int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
    1653             : {
    1654         944 :         return pwrap_pam_set_item(pamh, item_type, item);
    1655             : }
    1656             : 
    1657        3748 : static int pwrap_pam_get_data(const pam_handle_t *pamh,
    1658             :                               const char *module_data_name,
    1659             :                               const void **data)
    1660             : {
    1661        3748 :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1662             :                   "pwrap_get_data module_data_name=%s", module_data_name);
    1663        3748 :         return libpam_pam_get_data(pamh, module_data_name, data);
    1664             : }
    1665             : 
    1666             : int pam_get_data(const pam_handle_t *pamh,
    1667             :                  const char *module_data_name,
    1668             :                  const void **data)
    1669             : {
    1670        3748 :         return pwrap_pam_get_data(pamh, module_data_name, data);
    1671             : }
    1672             : 
    1673         756 : static int pwrap_pam_set_data(pam_handle_t *pamh,
    1674             :                               const char *module_data_name,
    1675             :                               void *data,
    1676             :                               void (*cleanup)(pam_handle_t *pamh,
    1677             :                                               void *data,
    1678             :                                               int error_status))
    1679             : {
    1680         756 :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1681             :                   "pwrap_set_data module_data_name=%s data=%p",
    1682             :                   module_data_name, data);
    1683         756 :         return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
    1684             : }
    1685             : 
    1686             : int pam_set_data(pam_handle_t *pamh,
    1687             :                  const char *module_data_name,
    1688             :                  void *data,
    1689             :                  void (*cleanup)(pam_handle_t *pamh,
    1690             :                                  void *data,
    1691             :                                  int error_status))
    1692             : {
    1693         756 :         return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
    1694             : }
    1695             : 
    1696             : #ifdef HAVE_PAM_VPROMPT_CONST
    1697             : static int pwrap_pam_vprompt(const pam_handle_t *pamh,
    1698             : #else
    1699           0 : static int pwrap_pam_vprompt(pam_handle_t *pamh,
    1700             : #endif
    1701             :                              int style,
    1702             :                              char **response,
    1703             :                              const char *fmt,
    1704             :                              va_list args)
    1705             : {
    1706           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
    1707           0 :         return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
    1708             :                                   style,
    1709             :                                   response,
    1710             :                                   fmt,
    1711             :                                   args);
    1712             : }
    1713             : 
    1714             : #ifdef HAVE_PAM_VPROMPT_CONST
    1715             : int pam_vprompt(const pam_handle_t *pamh,
    1716             :                 int style,
    1717             :                 char **response,
    1718             :                 const char *fmt,
    1719             :                 va_list args)
    1720             : #else
    1721             : int pam_vprompt(pam_handle_t *pamh,
    1722             :                 int style,
    1723             :                 char **response,
    1724             :                 const char *fmt,
    1725             :                 va_list args)
    1726             : #endif
    1727             : {
    1728           0 :         return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
    1729             :                                  style,
    1730             :                                  response,
    1731             :                                  fmt,
    1732             :                                  args);
    1733             : }
    1734             : 
    1735             : #ifdef HAVE_PAM_PROMPT_CONST
    1736             : int pam_prompt(const pam_handle_t *pamh,
    1737             :                int style,
    1738             :                char **response,
    1739             :                const char *fmt, ...)
    1740             : #else
    1741             : int pam_prompt(pam_handle_t *pamh,
    1742             :                int style,
    1743             :                char **response,
    1744             :                const char *fmt, ...)
    1745             : #endif
    1746             : {
    1747             :         va_list args;
    1748             :         int rv;
    1749             : 
    1750           0 :         va_start(args, fmt);
    1751           0 :         rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
    1752             :                                style,
    1753             :                                response,
    1754             :                                fmt,
    1755             :                                args);
    1756           0 :         va_end(args);
    1757             : 
    1758           0 :         return rv;
    1759             : }
    1760             : 
    1761             : #ifdef HAVE_PAM_STRERROR_CONST
    1762             : static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
    1763             : #else
    1764           0 : static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
    1765             : #endif
    1766             : {
    1767             :         const char *str;
    1768             : 
    1769           0 :         pwrap_init();
    1770             : 
    1771           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
    1772             : 
    1773           0 :         str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
    1774             :                                   errnum);
    1775             : 
    1776           0 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
    1777             : 
    1778           0 :         return str;
    1779             : }
    1780             : 
    1781             : #ifdef HAVE_PAM_STRERROR_CONST
    1782             : const char *pam_strerror(const pam_handle_t *pamh, int errnum)
    1783             : #else
    1784             : const char *pam_strerror(pam_handle_t *pamh, int errnum)
    1785             : #endif
    1786             : {
    1787           0 :         return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
    1788             :                                   errnum);
    1789             : }
    1790             : 
    1791             : #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
    1792             : static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
    1793             :                               int priority,
    1794             :                               const char *fmt,
    1795             :                               va_list args) PRINTF_ATTRIBUTE(3, 0);
    1796             : 
    1797        4459 : static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
    1798             :                               int priority,
    1799             :                               const char *fmt,
    1800             :                               va_list args)
    1801             : {
    1802             :         const char *d;
    1803        4459 :         char syslog_str[32] = {0};
    1804        4459 :         enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
    1805             : 
    1806        4459 :         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
    1807             : 
    1808             : #ifdef HAVE_PAM_VSYSLOG
    1809        4459 :         d = getenv("PAM_WRAPPER_USE_SYSLOG");
    1810        4459 :         if (d != NULL && d[0] == '1') {
    1811           0 :                 libpam_pam_vsyslog(pamh, priority, fmt, args);
    1812           0 :                 return;
    1813             :         }
    1814             : #endif /* HAVE_PAM_VSYSLOG */
    1815             : 
    1816        4459 :         switch(priority) {
    1817         201 :         case 0: /* LOG_EMERG */
    1818             :         case 1: /* LOG_ALERT */
    1819             :         case 2: /* LOG_CRIT */
    1820             :         case 3: /* LOG_ERR */
    1821         201 :                 dbglvl = PWRAP_LOG_ERROR;
    1822         201 :                 break;
    1823          76 :         case 4: /* LOG_WARN */
    1824          76 :                 dbglvl = PWRAP_LOG_WARN;
    1825          76 :                 break;
    1826        4182 :         case 5: /* LOG_NOTICE */
    1827             :         case 6: /* LOG_INFO */
    1828             :         case 7: /* LOG_DEBUG */
    1829        4182 :                 dbglvl = PWRAP_LOG_DEBUG;
    1830        4182 :                 break;
    1831           0 :         default:
    1832           0 :                 dbglvl = PWRAP_LOG_TRACE;
    1833           0 :                 break;
    1834             :         }
    1835             : 
    1836        4459 :         snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
    1837             : 
    1838        4459 :         pwrap_vlog(dbglvl, syslog_str, fmt, args);
    1839             : }
    1840             : #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
    1841             : 
    1842             : #ifdef HAVE_PAM_VSYSLOG
    1843             : void pam_vsyslog(const pam_handle_t *pamh,
    1844             :                  int priority,
    1845             :                  const char *fmt,
    1846             :                  va_list args)
    1847             : {
    1848        4334 :         pwrap_pam_vsyslog(pamh, priority, fmt, args);
    1849        4334 : }
    1850             : #endif
    1851             : 
    1852             : #ifdef HAVE_PAM_SYSLOG
    1853             : void pam_syslog(const pam_handle_t *pamh,
    1854             :                 int priority,
    1855             :                 const char *fmt, ...)
    1856             : {
    1857             :         va_list args;
    1858             : 
    1859         125 :         va_start(args, fmt);
    1860         125 :         pwrap_pam_vsyslog(pamh, priority, fmt, args);
    1861         125 :         va_end(args);
    1862         125 : }
    1863             : #endif
    1864             : 
    1865             : /* This might be called by pam_end() running with sshd */
    1866             : int audit_open(void);
    1867         502 : int audit_open(void)
    1868             : {
    1869             :         /*
    1870             :          * Tell the application that the kernel doesn't
    1871             :          * have audit compiled in.
    1872             :          */
    1873         502 :         errno = EPROTONOSUPPORT;
    1874         502 :         return -1;
    1875             : }
    1876             : 
    1877             : /* Disable BSD auditing */
    1878             : int cannot_audit(int x);
    1879           0 : int cannot_audit(int x)
    1880             : {
    1881             :         (void) x;
    1882             : 
    1883           0 :         return 1;
    1884             : }
    1885             : 
    1886             : /****************************
    1887             :  * CONSTRUCTOR
    1888             :  ***************************/
    1889             : 
    1890             : /*
    1891             :  * Handler executed before fork(2) processing starts.
    1892             :  */
    1893          24 : static void pwrap_thread_prepare(void)
    1894             : {
    1895          24 : }
    1896             : 
    1897             : /*
    1898             :  * Handler that is executed in the parent process after fork(2) processing
    1899             :  * completes.
    1900             :  */
    1901          24 : static void pwrap_thread_parent(void)
    1902             : {
    1903          24 : }
    1904             : 
    1905             : /*
    1906             :  * Handler that is executed in the child process after fork(2) processing
    1907             :  * completes.
    1908             :  */
    1909           0 : static void pwrap_thread_child(void)
    1910             : {
    1911           0 :         pwrap.initialised = false;
    1912           0 : }
    1913             : 
    1914         314 : void pwrap_constructor(void)
    1915             : {
    1916             :         /*
    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.
    1920             :         */
    1921         314 :         pthread_atfork(&pwrap_thread_prepare,
    1922             :                        &pwrap_thread_parent,
    1923             :                        &pwrap_thread_child);
    1924             : 
    1925             :         /*
    1926             :          * Here is safe place to call pwrap_init() and initialize data
    1927             :          * for main process.
    1928             :          */
    1929         314 :         pwrap_init();
    1930         314 : }
    1931             : 
    1932             : /****************************
    1933             :  * DESTRUCTOR
    1934             :  ***************************/
    1935             : 
    1936         278 : static int p_rmdirs_at(const char *path, int parent_fd)
    1937             : {
    1938         278 :         DIR *d = NULL;
    1939         278 :         struct dirent *dp = NULL;
    1940             :         struct stat sb;
    1941         278 :         char fd_str[64] = { 0 };
    1942             :         int path_fd;
    1943             :         int rc;
    1944             : 
    1945         278 :         switch(parent_fd) {
    1946         278 :         case AT_FDCWD:
    1947         278 :                 snprintf(fd_str, sizeof(fd_str), "CWD");
    1948         278 :                 break;
    1949           0 :         default:
    1950           0 :                 snprintf(fd_str, sizeof(fd_str), "fd=%d", parent_fd);
    1951           0 :                 break;
    1952             :         }
    1953             : 
    1954             :         /* If path is absolute, parent_fd is ignored. */
    1955         278 :         PWRAP_LOG(PWRAP_LOG_TRACE,
    1956             :                   "p_rmdirs_at removing %s at %s\n", path, fd_str);
    1957             : 
    1958         278 :         path_fd = openat(parent_fd,
    1959             :                          path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
    1960         278 :         if (path_fd == -1) {
    1961           0 :                 return -1;
    1962             :         }
    1963             : 
    1964         278 :         d = fdopendir(path_fd);
    1965         278 :         if (d == NULL) {
    1966           0 :                 close(path_fd);
    1967           0 :                 return -1;
    1968             :         }
    1969             : 
    1970        1390 :         while ((dp = readdir(d)) != NULL) {
    1971             :                 /* skip '.' and '..' */
    1972        1112 :                 if (dp->d_name[0] == '.' &&
    1973         556 :                         (dp->d_name[1] == '\0' ||
    1974         278 :                         (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
    1975         556 :                         continue;
    1976             :                 }
    1977             : 
    1978         556 :                 rc = fstatat(path_fd, dp->d_name,
    1979             :                              &sb, AT_SYMLINK_NOFOLLOW);
    1980         556 :                 if (rc != 0) {
    1981           0 :                         continue;
    1982             :                 }
    1983             : 
    1984         556 :                 if (S_ISDIR(sb.st_mode)) {
    1985           0 :                         rc = p_rmdirs_at(dp->d_name, path_fd);
    1986             :                 } else {
    1987         556 :                         rc = unlinkat(path_fd, dp->d_name, 0);
    1988             :                 }
    1989         556 :                 if (rc != 0) {
    1990           0 :                         continue;
    1991             :                 }
    1992             :         }
    1993         278 :         closedir(d);
    1994             : 
    1995         278 :         rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
    1996         278 :         if (rc != 0) {
    1997           0 :                 rc = errno;
    1998           0 :                 PWRAP_LOG(PWRAP_LOG_TRACE,
    1999             :                           "cannot unlink %s error %d\n", path, rc);
    2000           0 :                 return -1;
    2001             :         }
    2002             : 
    2003         278 :         return 0;
    2004             : }
    2005             : 
    2006         278 : static int p_rmdirs(const char *path)
    2007             : {
    2008             :         /*
    2009             :          * If path is absolute, p_rmdirs_at ignores parent_fd.
    2010             :          * If it's relative, start from cwd.
    2011             :          */
    2012         278 :         return p_rmdirs_at(path, AT_FDCWD);
    2013             : }
    2014             : 
    2015             : /*
    2016             :  * This function is called when the library is unloaded and makes sure that
    2017             :  * resources are freed.
    2018             :  */
    2019         314 : void pwrap_destructor(void)
    2020             : {
    2021             :         const char *env;
    2022             : 
    2023         314 :         PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
    2024             : 
    2025         314 :         if (pwrap.libpam.handle != NULL) {
    2026          98 :                 dlclose(pwrap.libpam.handle);
    2027             :         }
    2028             : 
    2029         314 :         if (pwrap.libpam_so != NULL) {
    2030         278 :                 free(pwrap.libpam_so);
    2031         278 :                 pwrap.libpam_so = NULL;
    2032             :         }
    2033             : 
    2034         314 :         if (!pwrap.initialised) {
    2035          36 :                 return;
    2036             :         }
    2037         278 :         pwrap.initialised = false;
    2038             : 
    2039         278 :         PWRAP_LOG(PWRAP_LOG_TRACE,
    2040             :                   "destructor called for pam_wrapper dir %s",
    2041             :                   pwrap.config_dir);
    2042         278 :         env = getenv("PAM_WRAPPER_KEEP_DIR");
    2043         278 :         if (env == NULL || env[0] != '1') {
    2044         278 :                 p_rmdirs(pwrap.config_dir);
    2045             :         }
    2046             : 
    2047         278 :         if (pwrap.config_dir != NULL) {
    2048         278 :                 free(pwrap.config_dir);
    2049         278 :                 pwrap.config_dir = NULL;
    2050             :         }
    2051             : }

Generated by: LCOV version 1.14