LCOV - code coverage report
Current view: top level - third_party/pam_wrapper - pam_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 459 713 64.4 %
Date: 2021-09-23 10:06:22 Functions: 39 59 66.1 %

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

Generated by: LCOV version 1.13