third_party: Fix a typo in the option name
[samba.git] / third_party / pam_wrapper / pam_wrapper.c
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
38 #include <ftw.h>
39
40 #ifdef HAVE_SECURITY_PAM_APPL_H
41 #include <security/pam_appl.h>
42 #endif
43 #ifdef HAVE_SECURITY_PAM_MODULES_H
44 #include <security/pam_modules.h>
45 #endif
46 #ifdef HAVE_SECURITY_PAM_EXT_H
47 #include <security/pam_ext.h>
48 #endif
49
50 #include "pwrap_compat.h"
51
52 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
53 # define PWRAP_THREAD __thread
54 #else
55 # define PWRAP_THREAD
56 #endif
57
58 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
59 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
60 #else
61 #define CONSTRUCTOR_ATTRIBUTE
62 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
63
64 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
65 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
66 #else
67 #define DESTRUCTOR_ATTRIBUTE
68 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
69
70 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
71 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
72 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
73 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
74 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
75
76 /* GCC have printf type attribute check. */
77 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
78 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
79 #else
80 #define PRINTF_ATTRIBUTE(a,b)
81 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
82
83 #ifndef SAFE_FREE
84 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
85 #endif
86
87 #ifndef discard_const
88 #define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
89 #endif
90
91 #ifndef discard_const_p
92 #define discard_const_p(type, ptr) ((type *)discard_const(ptr))
93 #endif
94
95 /*****************
96  * LOGGING
97  *****************/
98
99 enum pwrap_dbglvl_e {
100         PWRAP_LOG_ERROR = 0,
101         PWRAP_LOG_WARN,
102         PWRAP_LOG_DEBUG,
103         PWRAP_LOG_TRACE
104 };
105
106 static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
107                       const char *function,
108                       const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
109 # define PWRAP_LOG(dbglvl, ...) pwrap_log((dbglvl), __func__, __VA_ARGS__)
110
111 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
112                        const char *function,
113                        const char *format,
114                        va_list args) PRINTF_ATTRIBUTE(3, 0);
115
116 static void pwrap_vlog(enum pwrap_dbglvl_e dbglvl,
117                        const char *function,
118                        const char *format,
119                        va_list args)
120 {
121         char buffer[1024];
122         const char *d;
123         unsigned int lvl = 0;
124         const char *prefix = "PWRAP";
125
126         d = getenv("PAM_WRAPPER_DEBUGLEVEL");
127         if (d != NULL) {
128                 lvl = atoi(d);
129         }
130
131         if (lvl < dbglvl) {
132                 return;
133         }
134
135         vsnprintf(buffer, sizeof(buffer), format, args);
136
137         switch (dbglvl) {
138         case PWRAP_LOG_ERROR:
139                 prefix = "PWRAP_ERROR";
140                 break;
141         case PWRAP_LOG_WARN:
142                 prefix = "PWRAP_WARN";
143                 break;
144         case PWRAP_LOG_DEBUG:
145                 prefix = "PWRAP_DEBUG";
146                 break;
147         case PWRAP_LOG_TRACE:
148                 prefix = "PWRAP_TRACE";
149                 break;
150         }
151
152         fprintf(stderr,
153                 "%s(%d) - %s: %s\n",
154                 prefix,
155                 (int)getpid(),
156                 function,
157                 buffer);
158 }
159
160 static void pwrap_log(enum pwrap_dbglvl_e dbglvl,
161                       const char *function,
162                       const char *format, ...)
163 {
164         va_list va;
165
166         va_start(va, format);
167         pwrap_vlog(dbglvl, function, format, va);
168         va_end(va);
169 }
170
171 /*****************
172  * LIBC
173  *****************/
174
175 #define LIBPAM_NAME "libpam.so.0"
176
177 typedef int (*__libpam_pam_start)(const char *service_name,
178                                   const char *user,
179                                   const struct pam_conv *pam_conversation,
180                                   pam_handle_t **pamh);
181
182 typedef int (*__libpam_pam_end)(pam_handle_t *pamh, int pam_status);
183
184 typedef int (*__libpam_pam_authenticate)(pam_handle_t *pamh, int flags);
185
186 typedef int (*__libpam_pam_chauthtok)(pam_handle_t *pamh, int flags);
187
188 typedef int (*__libpam_pam_acct_mgmt)(pam_handle_t *pamh, int flags);
189
190 typedef int (*__libpam_pam_putenv)(pam_handle_t *pamh, const char *name_value);
191
192 typedef const char * (*__libpam_pam_getenv)(pam_handle_t *pamh, const char *name);
193
194 typedef char ** (*__libpam_pam_getenvlist)(pam_handle_t *pamh);
195
196 typedef int (*__libpam_pam_open_session)(pam_handle_t *pamh, int flags);
197
198 typedef int (*__libpam_pam_close_session)(pam_handle_t *pamh, int flags);
199
200 typedef int (*__libpam_pam_setcred)(pam_handle_t *pamh, int flags);
201
202 typedef int (*__libpam_pam_get_item)(const pam_handle_t *pamh,
203                                      int item_type,
204                                      const void **item);
205
206 typedef int (*__libpam_pam_set_item)(pam_handle_t *pamh,
207                                      int item_type,
208                                      const void *item);
209
210 typedef int (*__libpam_pam_get_data)(const pam_handle_t *pamh,
211                                      const char *module_data_name,
212                                      const void **data);
213
214 typedef int (*__libpam_pam_set_data)(pam_handle_t *pamh,
215                                      const char *module_data_name,
216                                      void *data,
217                                      void (*cleanup)(pam_handle_t *pamh,
218                                                      void *data,
219                                                      int error_status));
220
221 typedef int (*__libpam_pam_vprompt)(pam_handle_t *pamh,
222                                     int style,
223                                     char **response,
224                                     const char *fmt,
225                                     va_list args);
226
227 typedef const char * (*__libpam_pam_strerror)(pam_handle_t *pamh,
228                                               int errnum);
229
230 #ifdef HAVE_PAM_VSYSLOG
231 typedef void (*__libpam_pam_vsyslog)(const pam_handle_t *pamh,
232                                      int priority,
233                                      const char *fmt,
234                                      va_list args);
235 #endif
236
237 #define PWRAP_SYMBOL_ENTRY(i) \
238         union { \
239                 __libpam_##i f; \
240                 void *obj; \
241         } _libpam_##i
242
243 struct pwrap_libpam_symbols {
244         PWRAP_SYMBOL_ENTRY(pam_start);
245         PWRAP_SYMBOL_ENTRY(pam_end);
246         PWRAP_SYMBOL_ENTRY(pam_authenticate);
247         PWRAP_SYMBOL_ENTRY(pam_chauthtok);
248         PWRAP_SYMBOL_ENTRY(pam_acct_mgmt);
249         PWRAP_SYMBOL_ENTRY(pam_putenv);
250         PWRAP_SYMBOL_ENTRY(pam_getenv);
251         PWRAP_SYMBOL_ENTRY(pam_getenvlist);
252         PWRAP_SYMBOL_ENTRY(pam_open_session);
253         PWRAP_SYMBOL_ENTRY(pam_close_session);
254         PWRAP_SYMBOL_ENTRY(pam_setcred);
255         PWRAP_SYMBOL_ENTRY(pam_get_item);
256         PWRAP_SYMBOL_ENTRY(pam_set_item);
257         PWRAP_SYMBOL_ENTRY(pam_get_data);
258         PWRAP_SYMBOL_ENTRY(pam_set_data);
259         PWRAP_SYMBOL_ENTRY(pam_vprompt);
260         PWRAP_SYMBOL_ENTRY(pam_strerror);
261 #ifdef HAVE_PAM_VSYSLOG
262         PWRAP_SYMBOL_ENTRY(pam_vsyslog);
263 #endif
264 };
265
266 struct pwrap {
267         struct {
268                 void *handle;
269                 struct pwrap_libpam_symbols symbols;
270         } libpam;
271
272         bool enabled;
273         bool initialised;
274         char *config_dir;
275         char *libpam_so;
276 };
277
278 static struct pwrap pwrap;
279
280 /*********************************************************
281  * PWRAP PROTOTYPES
282  *********************************************************/
283
284 bool pam_wrapper_enabled(void);
285 void pwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
286 void pwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
287
288 /*********************************************************
289  * PWRAP LIBC LOADER FUNCTIONS
290  *********************************************************/
291
292 enum pwrap_lib {
293     PWRAP_LIBPAM,
294 };
295
296 static void *pwrap_load_lib_handle(enum pwrap_lib lib)
297 {
298         int flags = RTLD_LAZY;
299         void *handle = NULL;
300
301 #ifdef RTLD_DEEPBIND
302         flags |= RTLD_DEEPBIND;
303 #endif
304
305         switch (lib) {
306         case PWRAP_LIBPAM:
307                 handle = pwrap.libpam.handle;
308                 if (handle == NULL) {
309                         handle = dlopen(pwrap.libpam_so, flags);
310                         if (handle != NULL) {
311                                 PWRAP_LOG(PWRAP_LOG_DEBUG,
312                                           "Opened %s\n", pwrap.libpam_so);
313                                 pwrap.libpam.handle = handle;
314                                 break;
315                         }
316                 }
317                 break;
318         }
319
320         if (handle == NULL) {
321                 PWRAP_LOG(PWRAP_LOG_ERROR,
322                           "Failed to dlopen library: %s\n",
323                           dlerror());
324                 exit(-1);
325         }
326
327         return handle;
328 }
329
330 static void *_pwrap_bind_symbol(enum pwrap_lib lib, const char *fn_name)
331 {
332         void *handle;
333         void *func;
334
335         handle = pwrap_load_lib_handle(lib);
336
337         func = dlsym(handle, fn_name);
338         if (func == NULL) {
339                 PWRAP_LOG(PWRAP_LOG_ERROR,
340                           "Failed to find %s: %s\n",
341                           fn_name, dlerror());
342                 exit(-1);
343         }
344
345         return func;
346 }
347
348 #define pwrap_bind_symbol_libpam(sym_name) \
349         if (pwrap.libpam.symbols._libpam_##sym_name.obj == NULL) { \
350                 pwrap.libpam.symbols._libpam_##sym_name.obj = \
351                         _pwrap_bind_symbol(PWRAP_LIBPAM, #sym_name); \
352         } \
353
354 /*
355  * IMPORTANT
356  *
357  * Functions especially from libpam need to be loaded individually, you can't
358  * load all at once or gdb will segfault at startup. The same applies to
359  * valgrind and has probably something todo with with the linker.
360  * So we need load each function at the point it is called the first time.
361  */
362 static int libpam_pam_start(const char *service_name,
363                             const char *user,
364                             const struct pam_conv *pam_conversation,
365                             pam_handle_t **pamh)
366 {
367         pwrap_bind_symbol_libpam(pam_start);
368
369         return pwrap.libpam.symbols._libpam_pam_start.f(service_name,
370                                                         user,
371                                                         pam_conversation,
372                                                         pamh);
373 }
374
375 static int libpam_pam_end(pam_handle_t *pamh, int pam_status)
376 {
377         pwrap_bind_symbol_libpam(pam_end);
378
379         return pwrap.libpam.symbols._libpam_pam_end.f(pamh, pam_status);
380 }
381
382 static int libpam_pam_authenticate(pam_handle_t *pamh, int flags)
383 {
384         pwrap_bind_symbol_libpam(pam_authenticate);
385
386         return pwrap.libpam.symbols._libpam_pam_authenticate.f(pamh, flags);
387 }
388
389 static int libpam_pam_chauthtok(pam_handle_t *pamh, int flags)
390 {
391         pwrap_bind_symbol_libpam(pam_chauthtok);
392
393         return pwrap.libpam.symbols._libpam_pam_chauthtok.f(pamh, flags);
394 }
395
396 static int libpam_pam_acct_mgmt(pam_handle_t *pamh, int flags)
397 {
398         pwrap_bind_symbol_libpam(pam_acct_mgmt);
399
400         return pwrap.libpam.symbols._libpam_pam_acct_mgmt.f(pamh, flags);
401 }
402
403 static int libpam_pam_putenv(pam_handle_t *pamh, const char *name_value)
404 {
405         pwrap_bind_symbol_libpam(pam_putenv);
406
407         return pwrap.libpam.symbols._libpam_pam_putenv.f(pamh, name_value);
408 }
409
410 static const char *libpam_pam_getenv(pam_handle_t *pamh, const char *name)
411 {
412         pwrap_bind_symbol_libpam(pam_getenv);
413
414         return pwrap.libpam.symbols._libpam_pam_getenv.f(pamh, name);
415 }
416
417 static char **libpam_pam_getenvlist(pam_handle_t *pamh)
418 {
419         pwrap_bind_symbol_libpam(pam_getenvlist);
420
421         return pwrap.libpam.symbols._libpam_pam_getenvlist.f(pamh);
422 }
423
424 static int libpam_pam_open_session(pam_handle_t *pamh, int flags)
425 {
426         pwrap_bind_symbol_libpam(pam_open_session);
427
428         return pwrap.libpam.symbols._libpam_pam_open_session.f(pamh, flags);
429 }
430
431 static int libpam_pam_close_session(pam_handle_t *pamh, int flags)
432 {
433         pwrap_bind_symbol_libpam(pam_close_session);
434
435         return pwrap.libpam.symbols._libpam_pam_close_session.f(pamh, flags);
436 }
437
438 static int libpam_pam_setcred(pam_handle_t *pamh, int flags)
439 {
440         pwrap_bind_symbol_libpam(pam_setcred);
441
442         return pwrap.libpam.symbols._libpam_pam_setcred.f(pamh, flags);
443 }
444
445 static int libpam_pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
446 {
447         pwrap_bind_symbol_libpam(pam_get_item);
448
449         return pwrap.libpam.symbols._libpam_pam_get_item.f(pamh, item_type, item);
450 }
451
452 static int libpam_pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
453 {
454         pwrap_bind_symbol_libpam(pam_set_item);
455
456         return pwrap.libpam.symbols._libpam_pam_set_item.f(pamh, item_type, item);
457 }
458
459 static int libpam_pam_get_data(const pam_handle_t *pamh,
460                                const char *module_data_name,
461                                const void **data)
462 {
463         pwrap_bind_symbol_libpam(pam_get_data);
464
465         return pwrap.libpam.symbols._libpam_pam_get_data.f(pamh,
466                                                            module_data_name,
467                                                            data);
468 }
469
470 static int libpam_pam_set_data(pam_handle_t *pamh,
471                                const char *module_data_name,
472                                void *data,
473                                void (*cleanup)(pam_handle_t *pamh,
474                                                void *data,
475                                                int error_status))
476 {
477         pwrap_bind_symbol_libpam(pam_set_data);
478
479         return pwrap.libpam.symbols._libpam_pam_set_data.f(pamh,
480                                                            module_data_name,
481                                                            data,
482                                                            cleanup);
483 }
484
485 static int libpam_pam_vprompt(pam_handle_t *pamh,
486                               int style,
487                               char **response,
488                               const char *fmt,
489                               va_list args)
490 {
491         pwrap_bind_symbol_libpam(pam_vprompt);
492
493         return pwrap.libpam.symbols._libpam_pam_vprompt.f(pamh,
494                                                           style,
495                                                           response,
496                                                           fmt,
497                                                           args);
498 }
499
500 #ifdef HAVE_PAM_STRERROR_CONST
501 static const char *libpam_pam_strerror(const pam_handle_t *pamh, int errnum)
502 #else
503 static const char *libpam_pam_strerror(pam_handle_t *pamh, int errnum)
504 #endif
505 {
506         pwrap_bind_symbol_libpam(pam_strerror);
507
508         return pwrap.libpam.symbols._libpam_pam_strerror.f(discard_const_p(pam_handle_t, pamh), errnum);
509 }
510
511 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
512 static void libpam_pam_vsyslog(const pam_handle_t *pamh,
513                                int priority,
514                                const char *fmt,
515                                va_list args)
516 {
517 #ifdef HAVE_PAM_VSYSLOG
518         pwrap_bind_symbol_libpam(pam_vsyslog);
519
520         pwrap.libpam.symbols._libpam_pam_vsyslog.f(pamh,
521                                                    priority,
522                                                    fmt,
523                                                    args);
524 #endif
525 }
526 #endif
527
528 /*********************************************************
529  * PWRAP INIT
530  *********************************************************/
531
532 #define BUFFER_SIZE 32768
533
534 /* copy file from src to dst, overwrites dst */
535 static int p_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
536 {
537         int srcfd = -1;
538         int dstfd = -1;
539         int rc = -1;
540         ssize_t bread, bwritten;
541         struct stat sb;
542         char buf[BUFFER_SIZE];
543         int cmp;
544
545         cmp = strcmp(src, dst);
546         if (cmp == 0) {
547                 return -1;
548         }
549
550         srcfd = open(src, O_RDONLY, 0);
551         if (srcfd < 0) {
552                 return -1;
553         }
554
555         if (mode == 0) {
556                 rc = fstat(srcfd, &sb);
557                 if (rc != 0) {
558                         rc = -1;
559                         goto out;
560                 }
561                 mode = sb.st_mode;
562         }
563
564         dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
565         if (dstfd < 0) {
566                 rc = -1;
567                 goto out;
568         }
569
570         for (;;) {
571                 char *p;
572                 bread = read(srcfd, buf, BUFFER_SIZE);
573                 if (bread == 0) {
574                         /* done */
575                         break;
576                 } else if (bread < 0) {
577                         errno = EIO;
578                         rc = -1;
579                         goto out;
580                 }
581
582                 /* EXTRA UGLY HACK */
583                 if (pdir != NULL) {
584                         p = buf;
585
586                         while (p < buf + BUFFER_SIZE) {
587                                 if (*p == '/') {
588                                         cmp = memcmp(p, "/etc/pam.d", 10);
589                                         if (cmp == 0) {
590                                                 memcpy(p, pdir, 10);
591                                         }
592                                 }
593                                 p++;
594                         }
595                 }
596
597                 bwritten = write(dstfd, buf, bread);
598                 if (bwritten < 0) {
599                         errno = EIO;
600                         rc = -1;
601                         goto out;
602                 }
603
604                 if (bread != bwritten) {
605                         errno = EFAULT;
606                         rc = -1;
607                         goto out;
608                 }
609         }
610
611         rc = 0;
612 out:
613         if (srcfd != -1) {
614                 close(srcfd);
615         }
616         if (dstfd != -1) {
617                 close(dstfd);
618         }
619         if (rc < 0) {
620                 unlink(dst);
621         }
622
623         return rc;
624 }
625
626 /* Do not pass any flag if not defined */
627 #ifndef FTW_ACTIONRETVAL
628 #define FTW_ACTIONRETVAL 0
629 #endif
630
631 /* Action return values */
632 #ifndef FTW_STOP
633 #define FTW_STOP -1
634 #endif
635
636 #ifndef FTW_CONTINUE
637 #define FTW_CONTINUE 0
638 #endif
639
640 #ifndef FTW_SKIP_SUBTREE
641 #define FTW_SKIP_SUBTREE 0
642 #endif
643
644 static int copy_ftw(const char *fpath,
645                     const struct stat *sb,
646                     int typeflag,
647                     struct FTW *ftwbuf)
648 {
649         int rc;
650         char buf[BUFFER_SIZE];
651
652         switch (typeflag) {
653         case FTW_D:
654         case FTW_DNR:
655                 /* We want to copy the directories from this directory */
656                 if (ftwbuf->level == 0) {
657                         return FTW_CONTINUE;
658                 }
659                 return FTW_SKIP_SUBTREE;
660         case FTW_F:
661                 break;
662         default:
663                 return FTW_CONTINUE;
664         }
665
666         rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
667         if (rc >= BUFFER_SIZE) {
668                 return FTW_STOP;
669         }
670
671         PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
672         rc = p_copy(fpath, buf, NULL, sb->st_mode);
673         if (rc != 0) {
674                 return FTW_STOP;
675         }
676
677         return FTW_CONTINUE;
678 }
679
680 static int copy_confdir(const char *src)
681 {
682         int rc;
683
684         PWRAP_LOG(PWRAP_LOG_DEBUG,
685                   "Copy config files from %s to %s",
686                   src,
687                   pwrap.config_dir);
688         rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
689         if (rc != 0) {
690                 return -1;
691         }
692
693         return 0;
694 }
695
696 static int p_rmdirs(const char *path);
697
698 static void pwrap_clean_stale_dirs(const char *dir)
699 {
700         size_t len = strlen(dir);
701         char pidfile[len + 5];
702         ssize_t rc;
703         char buf[8] = {0};
704         long int tmp;
705         pid_t pid;
706         int fd;
707
708         snprintf(pidfile,
709                  sizeof(pidfile),
710                  "%s/pid",
711                  dir);
712
713         /* read the pidfile */
714         fd = open(pidfile, O_RDONLY);
715         if (fd < 0) {
716                 if (errno == ENOENT) {
717                         PWRAP_LOG(PWRAP_LOG_TRACE,
718                                   "pidfile %s missing, nothing to do\n",
719                                   pidfile);
720                 } else {
721                         PWRAP_LOG(PWRAP_LOG_ERROR,
722                                   "Failed to open pidfile %s - error: %s",
723                                   pidfile, strerror(errno));
724                 }
725                 return;
726         }
727
728         rc = read(fd, buf, sizeof(buf));
729         close(fd);
730         if (rc < 0) {
731                 PWRAP_LOG(PWRAP_LOG_ERROR,
732                           "Failed to read pidfile %s - error: %s",
733                           pidfile, strerror(errno));
734                 return;
735         }
736
737         buf[sizeof(buf) - 1] = '\0';
738
739         tmp = strtol(buf, NULL, 10);
740         if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
741                 PWRAP_LOG(PWRAP_LOG_ERROR,
742                           "Failed to parse pid, buf=%s",
743                           buf);
744                 return;
745         }
746
747         pid = (pid_t)(tmp & 0xFFFF);
748
749         rc = kill(pid, 0);
750         if (rc == -1) {
751                 PWRAP_LOG(PWRAP_LOG_TRACE,
752                           "Remove stale pam_wrapper dir: %s",
753                           dir);
754                 p_rmdirs(dir);
755         }
756
757         return;
758 }
759
760 static void pwrap_init(void)
761 {
762         char tmp_config_dir[] = "/tmp/pam.X";
763         size_t len = strlen(tmp_config_dir);
764         const char *env;
765         uint32_t i;
766         int rc;
767         char pam_library[128] = { 0 };
768         char libpam_path[1024] = { 0 };
769         ssize_t ret;
770         FILE *pidfile;
771         char pidfile_path[1024] = { 0 };
772
773         if (!pam_wrapper_enabled()) {
774                 return;
775         }
776
777         if (pwrap.initialised) {
778                 return;
779         }
780
781         PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
782
783         for (i = 0; i < 36; i++) {
784                 struct stat sb;
785                 char c;
786
787                 if (i < 10) {
788                         c = (char)(i + 48);
789                 } else {
790                         c = (char)(i + 87);
791                 }
792
793                 tmp_config_dir[len - 1] = c;
794                 rc = lstat(tmp_config_dir, &sb);
795                 if (rc == 0) {
796                         PWRAP_LOG(PWRAP_LOG_TRACE,
797                                   "Check if pam_wrapper dir %s is a "
798                                   "stale directory",
799                                   tmp_config_dir);
800                         pwrap_clean_stale_dirs(tmp_config_dir);
801                         continue;
802                 } else if (errno == ENOENT) {
803                         break;
804                 }
805         }
806
807         if (i == 36) {
808                 PWRAP_LOG(PWRAP_LOG_ERROR,
809                           "Failed to find a possible path to create "
810                           "pam_wrapper config dir: %s",
811                           tmp_config_dir);
812                 exit(1);
813         }
814
815         pwrap.config_dir = strdup(tmp_config_dir);
816         if (pwrap.config_dir == NULL) {
817                 PWRAP_LOG(PWRAP_LOG_ERROR,
818                           "No memory");
819                 exit(1);
820         }
821         PWRAP_LOG(PWRAP_LOG_TRACE,
822                   "pam_wrapper config dir: %s",
823                   tmp_config_dir);
824
825         rc = mkdir(pwrap.config_dir, 0755);
826         if (rc != 0) {
827                 PWRAP_LOG(PWRAP_LOG_ERROR,
828                           "Failed to create pam_wrapper config dir: %s - %s",
829                           tmp_config_dir, strerror(errno));
830         }
831
832         /* Create file with the PID of the the process */
833         ret = snprintf(pidfile_path, sizeof(pidfile_path),
834                        "%s/pid", pwrap.config_dir);
835         if (ret < 0) {
836                 p_rmdirs(pwrap.config_dir);
837                 exit(1);
838         }
839
840         pidfile = fopen(pidfile_path, "w");
841         if (pidfile == NULL) {
842                 p_rmdirs(pwrap.config_dir);
843                 exit(1);
844         }
845
846         rc = fprintf(pidfile, "%d", getpid());
847         fclose(pidfile);
848         if (rc <= 0) {
849                 p_rmdirs(pwrap.config_dir);
850                 exit(1);
851         }
852
853         /* create lib subdirectory */
854         snprintf(libpam_path,
855                  sizeof(libpam_path),
856                  "%s/lib",
857                  pwrap.config_dir);
858
859         rc = mkdir(libpam_path, 0755);
860         if (rc != 0) {
861                 PWRAP_LOG(PWRAP_LOG_ERROR,
862                           "Failed to create pam_wrapper config dir: %s - %s",
863                           tmp_config_dir, strerror(errno));
864                 p_rmdirs(pwrap.config_dir);
865                 exit(1);
866         }
867
868         snprintf(libpam_path,
869                  sizeof(libpam_path),
870                  "%s/lib/%s",
871                  pwrap.config_dir,
872                  LIBPAM_NAME);
873
874         pwrap.libpam_so = strdup(libpam_path);
875         if (pwrap.libpam_so == NULL) {
876                 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
877                 p_rmdirs(pwrap.config_dir);
878                 exit(1);
879         }
880
881         /* copy libpam.so.0 */
882         snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
883         PWRAP_LOG(PWRAP_LOG_TRACE,
884                   "PAM path: %s",
885                   libpam_path);
886
887         ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
888         PWRAP_LOG(PWRAP_LOG_TRACE,
889                   "PAM library: %s",
890                   pam_library);
891         if (ret <= 0) {
892                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
893                 p_rmdirs(pwrap.config_dir);
894                 exit(1);
895         }
896
897         if (pam_library[0] == '/') {
898                 snprintf(libpam_path,
899                          sizeof(libpam_path),
900                          "%s",
901                          pam_library);
902         } else {
903                 char libpam_path_cp[sizeof(libpam_path)];
904                 char *dname;
905
906                 strncpy(libpam_path_cp, libpam_path, sizeof(libpam_path_cp));
907                 libpam_path_cp[sizeof(libpam_path_cp) - 1] = '\0';
908
909                 dname = dirname(libpam_path_cp);
910                 if (dname == NULL) {
911                         PWRAP_LOG(PWRAP_LOG_ERROR,
912                                   "No directory component in %s", libpam_path);
913                         p_rmdirs(pwrap.config_dir);
914                         exit(1);
915                 }
916
917                 snprintf(libpam_path,
918                          sizeof(libpam_path),
919                          "%s/%s",
920                          dname,
921                          pam_library);
922         }
923         PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
924
925         PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
926         rc = p_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
927         if (rc != 0) {
928                 PWRAP_LOG(PWRAP_LOG_ERROR,
929                           "Failed to copy %s - error: %s",
930                           LIBPAM_NAME,
931                           strerror(errno));
932                 p_rmdirs(pwrap.config_dir);
933                 exit(1);
934         }
935
936         pwrap.initialised = true;
937
938         env = getenv("PAM_WRAPPER_SERVICE_DIR");
939         if (env == NULL) {
940                 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
941                 p_rmdirs(pwrap.config_dir);
942                 exit(1);
943         }
944
945         rc = copy_confdir(env);
946         if (rc != 0) {
947                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
948                 p_rmdirs(pwrap.config_dir);
949                 exit(1);
950         }
951
952         setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
953
954         PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
955 }
956
957 bool pam_wrapper_enabled(void)
958 {
959         const char *env;
960
961         pwrap.enabled = false;
962
963         env = getenv("PAM_WRAPPER");
964         if (env != NULL && env[0] == '1') {
965                 pwrap.enabled = true;
966         }
967
968         if (pwrap.enabled) {
969                 pwrap.enabled = false;
970
971                 env = getenv("PAM_WRAPPER_SERVICE_DIR");
972                 if (env != NULL && env[0] != '\0') {
973                         pwrap.enabled = true;
974                 }
975         }
976
977         return pwrap.enabled;
978 }
979
980 /****************************
981  * CONSTRUCTOR
982  ***************************/
983 void pwrap_constructor(void)
984 {
985         /*
986          * Here is safe place to call pwrap_init() and initialize data
987          * for main process.
988          */
989         pwrap_init();
990 }
991
992
993 #ifdef HAVE_OPENPAM
994 static int pwrap_openpam_start(const char *service_name,
995                                const char *user,
996                                const struct pam_conv *pam_conversation,
997                                pam_handle_t **pamh)
998 {
999         int rv;
1000         char fullpath[1024];
1001
1002         rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1003         if (rv != PAM_SUCCESS) {
1004                 PWRAP_LOG(PWRAP_LOG_ERROR,
1005                           "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1006                 return rv;
1007         }
1008
1009         rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1010         if (rv != PAM_SUCCESS) {
1011                 PWRAP_LOG(PWRAP_LOG_ERROR,
1012                           "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1013                 return rv;
1014         }
1015
1016         rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1017         if (rv != PAM_SUCCESS) {
1018                 PWRAP_LOG(PWRAP_LOG_ERROR,
1019                           "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1020                 return rv;
1021         }
1022
1023         rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1024         if (rv != PAM_SUCCESS) {
1025                 PWRAP_LOG(PWRAP_LOG_ERROR,
1026                           "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1027                 return rv;
1028         }
1029
1030         snprintf(fullpath,
1031                  sizeof(fullpath),
1032                  "%s/%s",
1033                  pwrap.config_dir,
1034                  service_name);
1035
1036         return libpam_pam_start(fullpath,
1037                                 user,
1038                                 pam_conversation,
1039                                 pamh);
1040 }
1041 #endif
1042
1043 static int pwrap_pam_start(const char *service_name,
1044                            const char *user,
1045                            const struct pam_conv *pam_conversation,
1046                            pam_handle_t **pamh)
1047 {
1048         PWRAP_LOG(PWRAP_LOG_TRACE,
1049                   "pam_start service=%s, user=%s",
1050                   service_name,
1051                   user);
1052
1053 #ifdef HAVE_OPENPAM
1054         return pwrap_openpam_start(service_name,
1055                                    user,
1056                                    pam_conversation,
1057                                    pamh);
1058 #else
1059         return libpam_pam_start(service_name,
1060                                 user,
1061                                 pam_conversation,
1062                                 pamh);
1063 #endif
1064 }
1065
1066
1067 int pam_start(const char *service_name,
1068               const char *user,
1069               const struct pam_conv *pam_conversation,
1070               pam_handle_t **pamh)
1071 {
1072         return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1073 }
1074
1075 static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1076 {
1077         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1078         return libpam_pam_end(pamh, pam_status);
1079 }
1080
1081
1082 int pam_end(pam_handle_t *pamh, int pam_status)
1083 {
1084         return pwrap_pam_end(pamh, pam_status);
1085 }
1086
1087 static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1088 {
1089         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1090         return libpam_pam_authenticate(pamh, flags);
1091 }
1092
1093 int pam_authenticate(pam_handle_t *pamh, int flags)
1094 {
1095         return pwrap_pam_authenticate(pamh, flags);
1096 }
1097
1098 static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1099 {
1100         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1101         return libpam_pam_chauthtok(pamh, flags);
1102 }
1103
1104 int pam_chauthtok(pam_handle_t *pamh, int flags)
1105 {
1106         return pwrap_pam_chauthtok(pamh, flags);
1107 }
1108
1109 static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1110 {
1111         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1112         return libpam_pam_acct_mgmt(pamh, flags);
1113 }
1114
1115 int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1116 {
1117         return pwrap_pam_acct_mgmt(pamh, flags);
1118 }
1119
1120 static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1121 {
1122         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1123         return libpam_pam_putenv(pamh, name_value);
1124 }
1125
1126 int pam_putenv(pam_handle_t *pamh, const char *name_value)
1127 {
1128         return pwrap_pam_putenv(pamh, name_value);
1129 }
1130
1131 static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1132 {
1133         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1134         return libpam_pam_getenv(pamh, name);
1135 }
1136
1137 const char *pam_getenv(pam_handle_t *pamh, const char *name)
1138 {
1139         return pwrap_pam_getenv(pamh, name);
1140 }
1141
1142 static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1143 {
1144         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1145         return libpam_pam_getenvlist(pamh);
1146 }
1147
1148 char **pam_getenvlist(pam_handle_t *pamh)
1149 {
1150         return pwrap_pam_getenvlist(pamh);
1151 }
1152
1153 static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1154 {
1155         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1156         return libpam_pam_open_session(pamh, flags);
1157 }
1158
1159 int pam_open_session(pam_handle_t *pamh, int flags)
1160 {
1161         return pwrap_pam_open_session(pamh, flags);
1162 }
1163
1164 static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1165 {
1166         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1167         return libpam_pam_close_session(pamh, flags);
1168 }
1169
1170 int pam_close_session(pam_handle_t *pamh, int flags)
1171 {
1172         return pwrap_pam_close_session(pamh, flags);
1173 }
1174
1175 static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1176 {
1177         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1178         return libpam_pam_setcred(pamh, flags);
1179 }
1180
1181 int pam_setcred(pam_handle_t *pamh, int flags)
1182 {
1183         return pwrap_pam_setcred(pamh, flags);
1184 }
1185
1186 static const char *pwrap_get_service(const char *libpam_service)
1187 {
1188 #ifdef HAVE_OPENPAM
1189         const char *service_name;
1190
1191         PWRAP_LOG(PWRAP_LOG_TRACE,
1192                   "internal PAM_SERVICE=%s", libpam_service);
1193         service_name = strrchr(libpam_service, '/');
1194         if (service_name != NULL && service_name[0] == '/') {
1195                 service_name++;
1196         }
1197         PWRAP_LOG(PWRAP_LOG_TRACE,
1198                   "PAM_SERVICE=%s", service_name);
1199         return service_name;
1200 #else
1201         return libpam_service;
1202 #endif
1203 }
1204
1205 static int pwrap_pam_get_item(const pam_handle_t *pamh,
1206                               int item_type,
1207                               const void **item)
1208 {
1209         int rc;
1210         const char *svc;
1211
1212         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1213
1214         rc = libpam_pam_get_item(pamh, item_type, item);
1215
1216         if (rc == PAM_SUCCESS) {
1217                 switch(item_type) {
1218                 case PAM_USER:
1219                         PWRAP_LOG(PWRAP_LOG_TRACE,
1220                                   "pwrap_get_item PAM_USER=%s",
1221                                   (const char *)*item);
1222                         break;
1223                 case PAM_SERVICE:
1224                         svc = pwrap_get_service((const char *) *item);
1225
1226                         PWRAP_LOG(PWRAP_LOG_TRACE,
1227                                   "pwrap_get_item PAM_SERVICE=%s",
1228                                   svc);
1229                         *item = svc;
1230                         break;
1231                 case PAM_USER_PROMPT:
1232                         PWRAP_LOG(PWRAP_LOG_TRACE,
1233                                   "pwrap_get_item PAM_USER_PROMPT=%s",
1234                                   (const char *)*item);
1235                         break;
1236                 case PAM_TTY:
1237                         PWRAP_LOG(PWRAP_LOG_TRACE,
1238                                   "pwrap_get_item PAM_TTY=%s",
1239                                   (const char *)*item);
1240                         break;
1241                 case PAM_RUSER:
1242                         PWRAP_LOG(PWRAP_LOG_TRACE,
1243                                   "pwrap_get_item PAM_RUSER=%s",
1244                                   (const char *)*item);
1245                         break;
1246                 case PAM_RHOST:
1247                         PWRAP_LOG(PWRAP_LOG_TRACE,
1248                                   "pwrap_get_item PAM_RHOST=%s",
1249                                   (const char *)*item);
1250                         break;
1251                 case PAM_AUTHTOK:
1252                         PWRAP_LOG(PWRAP_LOG_TRACE,
1253                                   "pwrap_get_item PAM_AUTHTOK=%s",
1254                                   (const char *)*item);
1255                         break;
1256                 case PAM_OLDAUTHTOK:
1257                         PWRAP_LOG(PWRAP_LOG_TRACE,
1258                                   "pwrap_get_item PAM_OLDAUTHTOK=%s",
1259                                   (const char *)*item);
1260                         break;
1261                 case PAM_CONV:
1262                         PWRAP_LOG(PWRAP_LOG_TRACE,
1263                                   "pwrap_get_item PAM_CONV=%p",
1264                                   (const void *)*item);
1265                         break;
1266                 default:
1267                         PWRAP_LOG(PWRAP_LOG_TRACE,
1268                                   "pwrap_get_item item_type=%d item=%p",
1269                                   item_type, (const void *)*item);
1270                         break;
1271                 }
1272         } else {
1273                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1274         }
1275
1276         return rc;
1277 }
1278
1279 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1280 {
1281         return pwrap_pam_get_item(pamh, item_type, item);
1282 }
1283
1284 static int pwrap_pam_set_item(pam_handle_t *pamh,
1285                               int item_type,
1286                               const void *item)
1287 {
1288         int rc;
1289
1290         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1291
1292         rc = libpam_pam_set_item(pamh, item_type, item);
1293         if (rc == PAM_SUCCESS) {
1294                 switch(item_type) {
1295                 case PAM_USER:
1296                         PWRAP_LOG(PWRAP_LOG_TRACE,
1297                                   "pwrap_set_item PAM_USER=%s",
1298                                   (const char *)item);
1299                         break;
1300                 case PAM_SERVICE:
1301                         PWRAP_LOG(PWRAP_LOG_TRACE,
1302                                   "pwrap_set_item PAM_SERVICE=%s",
1303                                   (const char *)item);
1304                         break;
1305                 case PAM_USER_PROMPT:
1306                         PWRAP_LOG(PWRAP_LOG_TRACE,
1307                                   "pwrap_set_item PAM_USER_PROMPT=%s",
1308                                   (const char *)item);
1309                         break;
1310                 case PAM_TTY:
1311                         PWRAP_LOG(PWRAP_LOG_TRACE,
1312                                   "pwrap_set_item PAM_TTY=%s",
1313                                   (const char *)item);
1314                         break;
1315                 case PAM_RUSER:
1316                         PWRAP_LOG(PWRAP_LOG_TRACE,
1317                                   "pwrap_set_item PAM_RUSER=%s",
1318                                   (const char *)item);
1319                         break;
1320                 case PAM_RHOST:
1321                         PWRAP_LOG(PWRAP_LOG_TRACE,
1322                                   "pwrap_set_item PAM_RHOST=%s",
1323                                   (const char *)item);
1324                         break;
1325                 case PAM_AUTHTOK:
1326                         PWRAP_LOG(PWRAP_LOG_TRACE,
1327                                   "pwrap_set_item PAM_AUTHTOK=%s",
1328                                   (const char *)item);
1329                         break;
1330                 case PAM_OLDAUTHTOK:
1331                         PWRAP_LOG(PWRAP_LOG_TRACE,
1332                                   "pwrap_set_item PAM_OLDAUTHTOK=%s",
1333                                   (const char *)item);
1334                         break;
1335                 case PAM_CONV:
1336                         PWRAP_LOG(PWRAP_LOG_TRACE,
1337                                   "pwrap_set_item PAM_CONV=%p",
1338                                   item);
1339                         break;
1340                 default:
1341                         PWRAP_LOG(PWRAP_LOG_TRACE,
1342                                   "pwrap_set_item item_type=%d item=%p",
1343                                   item_type, item);
1344                         break;
1345                 }
1346         } else {
1347                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1348         }
1349
1350         return rc;
1351 }
1352
1353 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1354 {
1355         return pwrap_pam_set_item(pamh, item_type, item);
1356 }
1357
1358 static int pwrap_pam_get_data(const pam_handle_t *pamh,
1359                               const char *module_data_name,
1360                               const void **data)
1361 {
1362         PWRAP_LOG(PWRAP_LOG_TRACE,
1363                   "pwrap_get_data module_data_name=%s", module_data_name);
1364         return libpam_pam_get_data(pamh, module_data_name, data);
1365 }
1366
1367 int pam_get_data(const pam_handle_t *pamh,
1368                  const char *module_data_name,
1369                  const void **data)
1370 {
1371         return pwrap_pam_get_data(pamh, module_data_name, data);
1372 }
1373
1374 static int pwrap_pam_set_data(pam_handle_t *pamh,
1375                               const char *module_data_name,
1376                               void *data,
1377                               void (*cleanup)(pam_handle_t *pamh,
1378                                               void *data,
1379                                               int error_status))
1380 {
1381         PWRAP_LOG(PWRAP_LOG_TRACE,
1382                   "pwrap_set_data module_data_name=%s data=%p",
1383                   module_data_name, data);
1384         return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1385 }
1386
1387 int pam_set_data(pam_handle_t *pamh,
1388                  const char *module_data_name,
1389                  void *data,
1390                  void (*cleanup)(pam_handle_t *pamh,
1391                                  void *data,
1392                                  int error_status))
1393 {
1394         return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1395 }
1396
1397 #ifdef HAVE_PAM_VPROMPT_CONST
1398 static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1399 #else
1400 static int pwrap_pam_vprompt(pam_handle_t *pamh,
1401 #endif
1402                              int style,
1403                              char **response,
1404                              const char *fmt,
1405                              va_list args)
1406 {
1407         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1408         return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1409                                   style,
1410                                   response,
1411                                   fmt,
1412                                   args);
1413 }
1414
1415 #ifdef HAVE_PAM_VPROMPT_CONST
1416 int pam_vprompt(const pam_handle_t *pamh,
1417                 int style,
1418                 char **response,
1419                 const char *fmt,
1420                 va_list args)
1421 #else
1422 int pam_vprompt(pam_handle_t *pamh,
1423                 int style,
1424                 char **response,
1425                 const char *fmt,
1426                 va_list args)
1427 #endif
1428 {
1429         return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1430                                  style,
1431                                  response,
1432                                  fmt,
1433                                  args);
1434 }
1435
1436 #ifdef HAVE_PAM_PROMPT_CONST
1437 int pam_prompt(const pam_handle_t *pamh,
1438                int style,
1439                char **response,
1440                const char *fmt, ...)
1441 #else
1442 int pam_prompt(pam_handle_t *pamh,
1443                int style,
1444                char **response,
1445                const char *fmt, ...)
1446 #endif
1447 {
1448         va_list args;
1449         int rv;
1450
1451         va_start(args, fmt);
1452         rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1453                                style,
1454                                response,
1455                                fmt,
1456                                args);
1457         va_end(args);
1458
1459         return rv;
1460 }
1461
1462 #ifdef HAVE_PAM_STRERROR_CONST
1463 static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1464 #else
1465 static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1466 #endif
1467 {
1468         const char *str;
1469
1470         pwrap_init();
1471
1472         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1473
1474         str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1475                                   errnum);
1476
1477         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1478
1479         return str;
1480 }
1481
1482 #ifdef HAVE_PAM_STRERROR_CONST
1483 const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1484 #else
1485 const char *pam_strerror(pam_handle_t *pamh, int errnum)
1486 #endif
1487 {
1488         return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1489                                   errnum);
1490 }
1491
1492 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1493
1494 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1495                               int priority,
1496                               const char *fmt,
1497                               va_list args) PRINTF_ATTRIBUTE(3, 0);
1498
1499 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1500                               int priority,
1501                               const char *fmt,
1502                               va_list args)
1503 {
1504         const char *d;
1505         char syslog_str[32] = {0};
1506         enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1507
1508         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1509
1510         d = getenv("PAM_WRAPPER_USE_SYSLOG");
1511         if (d != NULL && d[0] == '1') {
1512                 libpam_pam_vsyslog(pamh, priority, fmt, args);
1513                 return;
1514         }
1515
1516         switch(priority) {
1517         case 0: /* LOG_EMERG */
1518         case 1: /* LOG_ALERT */
1519         case 2: /* LOG_CRIT */
1520         case 3: /* LOG_ERR */
1521                 dbglvl = PWRAP_LOG_ERROR;
1522                 break;
1523         case 4: /* LOG_WARN */
1524                 dbglvl = PWRAP_LOG_WARN;
1525                 break;
1526         case 5: /* LOG_NOTICE */
1527         case 6: /* LOG_INFO */
1528         case 7: /* LOG_DEBUG */
1529                 dbglvl = PWRAP_LOG_DEBUG;
1530                 break;
1531         default:
1532                 dbglvl = PWRAP_LOG_TRACE;
1533                 break;
1534         }
1535
1536         snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1537
1538         pwrap_vlog(dbglvl, syslog_str, fmt, args);
1539 }
1540 #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1541
1542 #ifdef HAVE_PAM_VSYSLOG
1543 void pam_vsyslog(const pam_handle_t *pamh,
1544                  int priority,
1545                  const char *fmt,
1546                  va_list args)
1547 {
1548         pwrap_pam_vsyslog(pamh, priority, fmt, args);
1549 }
1550 #endif
1551
1552 #ifdef HAVE_PAM_SYSLOG
1553 void pam_syslog(const pam_handle_t *pamh,
1554                 int priority,
1555                 const char *fmt, ...)
1556 {
1557         va_list args;
1558
1559         va_start(args, fmt);
1560         pwrap_pam_vsyslog(pamh, priority, fmt, args);
1561         va_end(args);
1562 }
1563 #endif
1564
1565 /* This might be called by pam_end() running with sshd */
1566 int audit_open(void);
1567 int audit_open(void)
1568 {
1569         /*
1570          * Tell the application that the kernel doesn't
1571          * have audit compiled in.
1572          */
1573         errno = EPROTONOSUPPORT;
1574         return -1;
1575 }
1576
1577 /* Disable BSD auditing */
1578 int cannot_audit(int x);
1579 int cannot_audit(int x)
1580 {
1581         (void) x;
1582
1583         return 1;
1584 }
1585
1586 /****************************
1587  * DESTRUCTOR
1588  ***************************/
1589
1590 static int p_rmdirs_at(const char *path, int parent_fd)
1591 {
1592         DIR *d;
1593         struct dirent *dp;
1594         struct stat sb;
1595         int path_fd;
1596         int rc;
1597
1598         /* If path is absolute, parent_fd is ignored. */
1599         PWRAP_LOG(PWRAP_LOG_TRACE,
1600                   "p_rmdirs_at removing %s at %d\n", path, parent_fd);
1601
1602         path_fd = openat(parent_fd,
1603                          path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1604         if (path_fd == -1) {
1605                 return -1;
1606         }
1607
1608         d = fdopendir(path_fd);
1609         if (d == NULL) {
1610                 close(path_fd);
1611                 return -1;
1612         }
1613
1614         while ((dp = readdir(d)) != NULL) {
1615                 /* skip '.' and '..' */
1616                 if (dp->d_name[0] == '.' &&
1617                         (dp->d_name[1] == '\0' ||
1618                         (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
1619                         continue;
1620                 }
1621
1622                 rc = fstatat(path_fd, dp->d_name,
1623                              &sb, AT_SYMLINK_NOFOLLOW);
1624                 if (rc != 0) {
1625                         continue;
1626                 }
1627
1628                 if (S_ISDIR(sb.st_mode)) {
1629                         rc = p_rmdirs_at(dp->d_name, path_fd);
1630                 } else {
1631                         rc = unlinkat(path_fd, dp->d_name, 0);
1632                 }
1633                 if (rc != 0) {
1634                         continue;
1635                 }
1636         }
1637         closedir(d);
1638
1639         rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
1640         if (rc != 0) {
1641                 rc = errno;
1642                 PWRAP_LOG(PWRAP_LOG_TRACE,
1643                           "cannot unlink %s error %d\n", path, rc);
1644                 return -1;
1645         }
1646
1647         return 0;
1648 }
1649
1650 static int p_rmdirs(const char *path)
1651 {
1652         /*
1653          * If path is absolute, p_rmdirs_at ignores parent_fd.
1654          * If it's relative, start from cwd.
1655          */
1656         return p_rmdirs_at(path, AT_FDCWD);
1657 }
1658
1659 /*
1660  * This function is called when the library is unloaded and makes sure that
1661  * resources are freed.
1662  */
1663 void pwrap_destructor(void)
1664 {
1665         const char *env;
1666
1667         PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
1668
1669         if (pwrap.libpam.handle != NULL) {
1670                 dlclose(pwrap.libpam.handle);
1671         }
1672
1673         if (pwrap.libpam_so != NULL) {
1674                 free(pwrap.libpam_so);
1675                 pwrap.libpam_so = NULL;
1676         }
1677
1678         if (!pwrap.initialised) {
1679                 return;
1680         }
1681
1682         PWRAP_LOG(PWRAP_LOG_TRACE,
1683                   "destructor called for pam_wrapper dir %s",
1684                   pwrap.config_dir);
1685         env = getenv("PAM_WRAPPER_KEEP_DIR");
1686         if (env == NULL || env[0] != '1') {
1687                 p_rmdirs(pwrap.config_dir);
1688         }
1689
1690         if (pwrap.config_dir != NULL) {
1691                 free(pwrap.config_dir);
1692                 pwrap.config_dir = NULL;
1693         }
1694 }