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