third_party: Update pam_wrapper to version 1.0.6
[metze/samba/wip.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, 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                 bread = read(srcfd, buf, BUFFER_SIZE);
571                 if (bread == 0) {
572                         /* done */
573                         break;
574                 } else if (bread < 0) {
575                         errno = EIO;
576                         rc = -1;
577                         goto out;
578                 }
579
580                 bwritten = write(dstfd, buf, bread);
581                 if (bwritten < 0) {
582                         errno = EIO;
583                         rc = -1;
584                         goto out;
585                 }
586
587                 if (bread != bwritten) {
588                         errno = EFAULT;
589                         rc = -1;
590                         goto out;
591                 }
592         }
593
594         rc = 0;
595 out:
596         if (srcfd != -1) {
597                 close(srcfd);
598         }
599         if (dstfd != -1) {
600                 close(dstfd);
601         }
602         if (rc < 0) {
603                 unlink(dst);
604         }
605
606         return rc;
607 }
608
609 /* Do not pass any flag if not defined */
610 #ifndef FTW_ACTIONRETVAL
611 #define FTW_ACTIONRETVAL 0
612 #endif
613
614 /* Action return values */
615 #ifndef FTW_STOP
616 #define FTW_STOP -1
617 #endif
618
619 #ifndef FTW_CONTINUE
620 #define FTW_CONTINUE 0
621 #endif
622
623 #ifndef FTW_SKIP_SUBTREE
624 #define FTW_SKIP_SUBTREE 0
625 #endif
626
627 static int copy_ftw(const char *fpath,
628                     const struct stat *sb,
629                     int typeflag,
630                     struct FTW *ftwbuf)
631 {
632         int rc;
633         char buf[BUFFER_SIZE];
634
635         switch (typeflag) {
636         case FTW_D:
637         case FTW_DNR:
638                 /* We want to copy the directories from this directory */
639                 if (ftwbuf->level == 0) {
640                         return FTW_CONTINUE;
641                 }
642                 return FTW_SKIP_SUBTREE;
643         case FTW_F:
644                 break;
645         default:
646                 return FTW_CONTINUE;
647         }
648
649         rc = snprintf(buf, BUFFER_SIZE, "%s/%s", pwrap.config_dir, fpath + ftwbuf->base);
650         if (rc >= BUFFER_SIZE) {
651                 return FTW_STOP;
652         }
653
654         PWRAP_LOG(PWRAP_LOG_TRACE, "Copying %s", fpath);
655         rc = p_copy(fpath, buf, sb->st_mode);
656         if (rc != 0) {
657                 return FTW_STOP;
658         }
659
660         return FTW_CONTINUE;
661 }
662
663 static int copy_confdir(const char *src)
664 {
665         int rc;
666
667         PWRAP_LOG(PWRAP_LOG_DEBUG,
668                   "Copy config files from %s to %s",
669                   src,
670                   pwrap.config_dir);
671         rc = nftw(src, copy_ftw, 1, FTW_ACTIONRETVAL);
672         if (rc != 0) {
673                 return -1;
674         }
675
676         return 0;
677 }
678
679 static int p_rmdirs(const char *path);
680
681 static void pwrap_clean_stale_dirs(const char *dir)
682 {
683         size_t len = strlen(dir);
684         char pidfile[len + 5];
685         ssize_t rc;
686         char buf[8] = {0};
687         long int tmp;
688         pid_t pid;
689         int fd;
690
691         snprintf(pidfile,
692                  sizeof(pidfile),
693                  "%s/pid",
694                  dir);
695
696         /* read the pidfile */
697         fd = open(pidfile, O_RDONLY);
698         if (fd < 0) {
699                 if (errno == ENOENT) {
700                         PWRAP_LOG(PWRAP_LOG_TRACE,
701                                   "pidfile %s missing, nothing to do\n",
702                                   pidfile);
703                 } else {
704                         PWRAP_LOG(PWRAP_LOG_ERROR,
705                                   "Failed to open pidfile %s - error: %s",
706                                   pidfile, strerror(errno));
707                 }
708                 return;
709         }
710
711         rc = read(fd, buf, sizeof(buf));
712         close(fd);
713         if (rc < 0) {
714                 PWRAP_LOG(PWRAP_LOG_ERROR,
715                           "Failed to read pidfile %s - error: %s",
716                           pidfile, strerror(errno));
717                 return;
718         }
719
720         buf[sizeof(buf) - 1] = '\0';
721
722         tmp = strtol(buf, NULL, 10);
723         if (tmp == 0 || tmp > 0xFFFF || errno == ERANGE) {
724                 PWRAP_LOG(PWRAP_LOG_ERROR,
725                           "Failed to parse pid, buf=%s",
726                           buf);
727                 return;
728         }
729
730         pid = (pid_t)(tmp & 0xFFFF);
731
732         rc = kill(pid, 0);
733         if (rc == -1) {
734                 PWRAP_LOG(PWRAP_LOG_TRACE,
735                           "Remove stale pam_wrapper dir: %s",
736                           dir);
737                 p_rmdirs(dir);
738         }
739
740         return;
741 }
742
743 static int pso_copy(const char *src, const char *dst, const char *pdir, mode_t mode)
744 {
745         int srcfd = -1;
746         int dstfd = -1;
747         int rc = -1;
748         ssize_t bread, bwritten;
749         struct stat sb;
750         char buf[10];
751         int cmp;
752         size_t to_read;
753         bool found_slash;
754
755         cmp = strcmp(src, dst);
756         if (cmp == 0) {
757                 return -1;
758         }
759
760         srcfd = open(src, O_RDONLY, 0);
761         if (srcfd < 0) {
762                 return -1;
763         }
764
765         if (mode == 0) {
766                 rc = fstat(srcfd, &sb);
767                 if (rc != 0) {
768                         rc = -1;
769                         goto out;
770                 }
771                 mode = sb.st_mode;
772         }
773
774         dstfd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, mode);
775         if (dstfd < 0) {
776                 rc = -1;
777                 goto out;
778         }
779
780         found_slash = false;
781         to_read = 1;
782
783         for (;;) {
784                 bread = read(srcfd, buf, to_read);
785                 if (bread == 0) {
786                         /* done */
787                         break;
788                 } else if (bread < 0) {
789                         errno = EIO;
790                         rc = -1;
791                         goto out;
792                 }
793
794                 to_read = 1;
795                 if (!found_slash && buf[0] == '/') {
796                         found_slash = true;
797                         to_read = 9;
798                 }
799
800                 if (found_slash && bread == 9) {
801                         cmp = memcmp(buf, "etc/pam.d", 9);
802                         if (cmp == 0) {
803                                 memcpy(buf, pdir + 1, 9);
804                         }
805                         found_slash = false;
806                 }
807
808                 bwritten = write(dstfd, buf, bread);
809                 if (bwritten < 0) {
810                         errno = EIO;
811                         rc = -1;
812                         goto out;
813                 }
814
815                 if (bread != bwritten) {
816                         errno = EFAULT;
817                         rc = -1;
818                         goto out;
819                 }
820         }
821
822         rc = 0;
823 out:
824         if (srcfd != -1) {
825                 close(srcfd);
826         }
827         if (dstfd != -1) {
828                 close(dstfd);
829         }
830         if (rc < 0) {
831                 unlink(dst);
832         }
833
834         return rc;
835 }
836
837 static void pwrap_init(void)
838 {
839         char tmp_config_dir[] = "/tmp/pam.X";
840         size_t len = strlen(tmp_config_dir);
841         const char *env;
842         struct stat sb;
843         int rc;
844         unsigned i;
845         char pam_library[128] = { 0 };
846         char libpam_path[1024] = { 0 };
847         ssize_t ret;
848         FILE *pidfile;
849         char pidfile_path[1024] = { 0 };
850         char letter;
851
852         if (!pam_wrapper_enabled()) {
853                 return;
854         }
855
856         if (pwrap.initialised) {
857                 return;
858         }
859
860         /*
861          * The name is selected to match/replace /etc/pam.d
862          * We start from a random alphanum trying letters until
863          * an available directory is found.
864          */
865         letter = 48 + (getpid() % 70);
866         for (i = 0; i < 127; i++) {
867                 if (isalpha(letter) || isdigit(letter)) {
868                         tmp_config_dir[len - 1] = letter;
869
870                         rc = lstat(tmp_config_dir, &sb);
871                         if (rc == 0) {
872                                 PWRAP_LOG(PWRAP_LOG_TRACE,
873                                           "Check if pam_wrapper dir %s is a "
874                                           "stale directory",
875                                           tmp_config_dir);
876                                 pwrap_clean_stale_dirs(tmp_config_dir);
877                         } else if (rc < 0) {
878                                 if (errno != ENOENT) {
879                                         continue;
880                                 }
881                                 break; /* found */
882                         }
883                 }
884
885                 letter++;
886                 letter %= 127;
887         }
888
889         if (i == 127) {
890                 PWRAP_LOG(PWRAP_LOG_ERROR,
891                           "Failed to find a possible path to create "
892                           "pam_wrapper config dir: %s",
893                           tmp_config_dir);
894                 exit(1);
895         }
896
897         PWRAP_LOG(PWRAP_LOG_DEBUG, "Initialize pam_wrapper");
898
899         pwrap_clean_stale_dirs(tmp_config_dir);
900
901         pwrap.config_dir = strdup(tmp_config_dir);
902         if (pwrap.config_dir == NULL) {
903                 PWRAP_LOG(PWRAP_LOG_ERROR,
904                           "No memory");
905                 exit(1);
906         }
907         PWRAP_LOG(PWRAP_LOG_TRACE,
908                   "pam_wrapper config dir: %s",
909                   tmp_config_dir);
910
911         rc = mkdir(pwrap.config_dir, 0755);
912         if (rc != 0) {
913                 PWRAP_LOG(PWRAP_LOG_ERROR,
914                           "Failed to create pam_wrapper config dir: %s - %s",
915                           tmp_config_dir, strerror(errno));
916         }
917
918         /* Create file with the PID of the the process */
919         ret = snprintf(pidfile_path, sizeof(pidfile_path),
920                        "%s/pid", pwrap.config_dir);
921         if (ret < 0) {
922                 p_rmdirs(pwrap.config_dir);
923                 exit(1);
924         }
925
926         pidfile = fopen(pidfile_path, "w");
927         if (pidfile == NULL) {
928                 p_rmdirs(pwrap.config_dir);
929                 exit(1);
930         }
931
932         rc = fprintf(pidfile, "%d", getpid());
933         fclose(pidfile);
934         if (rc <= 0) {
935                 p_rmdirs(pwrap.config_dir);
936                 exit(1);
937         }
938
939         /* create lib subdirectory */
940         snprintf(libpam_path,
941                  sizeof(libpam_path),
942                  "%s/lib",
943                  pwrap.config_dir);
944
945         rc = mkdir(libpam_path, 0755);
946         if (rc != 0) {
947                 PWRAP_LOG(PWRAP_LOG_ERROR,
948                           "Failed to create pam_wrapper config dir: %s - %s",
949                           tmp_config_dir, strerror(errno));
950                 p_rmdirs(pwrap.config_dir);
951                 exit(1);
952         }
953
954         snprintf(libpam_path,
955                  sizeof(libpam_path),
956                  "%s/lib/%s",
957                  pwrap.config_dir,
958                  LIBPAM_NAME);
959
960         pwrap.libpam_so = strdup(libpam_path);
961         if (pwrap.libpam_so == NULL) {
962                 PWRAP_LOG(PWRAP_LOG_ERROR, "No memory");
963                 p_rmdirs(pwrap.config_dir);
964                 exit(1);
965         }
966
967         /* copy libpam.so.0 */
968         snprintf(libpam_path, sizeof(libpam_path), "%s", PAM_LIBRARY);
969         PWRAP_LOG(PWRAP_LOG_TRACE,
970                   "PAM path: %s",
971                   libpam_path);
972
973         ret = readlink(libpam_path, pam_library, sizeof(pam_library) - 1);
974         PWRAP_LOG(PWRAP_LOG_TRACE,
975                   "PAM library: %s",
976                   pam_library);
977         if (ret <= 0) {
978                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to read %s link", LIBPAM_NAME);
979                 p_rmdirs(pwrap.config_dir);
980                 exit(1);
981         }
982
983         if (pam_library[0] == '/') {
984                 snprintf(libpam_path,
985                          sizeof(libpam_path),
986                          "%s",
987                          pam_library);
988         } else {
989                 char libpam_path_cp[1024] = {0};
990                 char *dname = NULL;
991
992                 snprintf(libpam_path_cp,
993                          sizeof(libpam_path_cp),
994                          "%s",
995                          libpam_path);
996
997                 dname = dirname(libpam_path_cp);
998                 if (dname == NULL) {
999                         PWRAP_LOG(PWRAP_LOG_ERROR,
1000                                   "No directory component in %s", libpam_path);
1001                         p_rmdirs(pwrap.config_dir);
1002                         exit(1);
1003                 }
1004
1005                 snprintf(libpam_path,
1006                          sizeof(libpam_path),
1007                          "%s/%s",
1008                          dname,
1009                          pam_library);
1010         }
1011         PWRAP_LOG(PWRAP_LOG_TRACE, "Reconstructed PAM path: %s", libpam_path);
1012
1013         PWRAP_LOG(PWRAP_LOG_DEBUG, "Copy %s to %s", libpam_path, pwrap.libpam_so);
1014         rc = pso_copy(libpam_path, pwrap.libpam_so, pwrap.config_dir, 0644);
1015         if (rc != 0) {
1016                 PWRAP_LOG(PWRAP_LOG_ERROR,
1017                           "Failed to copy %s - error: %s",
1018                           LIBPAM_NAME,
1019                           strerror(errno));
1020                 p_rmdirs(pwrap.config_dir);
1021                 exit(1);
1022         }
1023
1024         pwrap.initialised = true;
1025
1026         env = getenv("PAM_WRAPPER_SERVICE_DIR");
1027         if (env == NULL) {
1028                 PWRAP_LOG(PWRAP_LOG_ERROR, "No config file");
1029                 p_rmdirs(pwrap.config_dir);
1030                 exit(1);
1031         }
1032
1033         rc = copy_confdir(env);
1034         if (rc != 0) {
1035                 PWRAP_LOG(PWRAP_LOG_ERROR, "Failed to copy config files");
1036                 p_rmdirs(pwrap.config_dir);
1037                 exit(1);
1038         }
1039
1040         setenv("PAM_WRAPPER_RUNTIME_DIR", pwrap.config_dir, 1);
1041
1042         PWRAP_LOG(PWRAP_LOG_DEBUG, "Successfully initialized pam_wrapper");
1043 }
1044
1045 bool pam_wrapper_enabled(void)
1046 {
1047         const char *env;
1048
1049         pwrap.enabled = false;
1050
1051         env = getenv("PAM_WRAPPER");
1052         if (env != NULL && env[0] == '1') {
1053                 pwrap.enabled = true;
1054         }
1055
1056         if (pwrap.enabled) {
1057                 pwrap.enabled = false;
1058
1059                 env = getenv("PAM_WRAPPER_SERVICE_DIR");
1060                 if (env != NULL && env[0] != '\0') {
1061                         pwrap.enabled = true;
1062                 }
1063         }
1064
1065         return pwrap.enabled;
1066 }
1067
1068 /****************************
1069  * CONSTRUCTOR
1070  ***************************/
1071 void pwrap_constructor(void)
1072 {
1073         /*
1074          * Here is safe place to call pwrap_init() and initialize data
1075          * for main process.
1076          */
1077         pwrap_init();
1078 }
1079
1080
1081 #ifdef HAVE_OPENPAM
1082 static int pwrap_openpam_start(const char *service_name,
1083                                const char *user,
1084                                const struct pam_conv *pam_conversation,
1085                                pam_handle_t **pamh)
1086 {
1087         int rv;
1088         char fullpath[1024];
1089
1090         rv = openpam_set_feature(OPENPAM_RESTRICT_SERVICE_NAME, 0);
1091         if (rv != PAM_SUCCESS) {
1092                 PWRAP_LOG(PWRAP_LOG_ERROR,
1093                           "Cannot disable OPENPAM_RESTRICT_SERVICE_NAME");
1094                 return rv;
1095         }
1096
1097         rv = openpam_set_feature(OPENPAM_RESTRICT_MODULE_NAME, 0);
1098         if (rv != PAM_SUCCESS) {
1099                 PWRAP_LOG(PWRAP_LOG_ERROR,
1100                           "Cannot disable OPENPAM_RESTRICT_MODULE_NAME");
1101                 return rv;
1102         }
1103
1104         rv = openpam_set_feature(OPENPAM_VERIFY_MODULE_FILE, 0);
1105         if (rv != PAM_SUCCESS) {
1106                 PWRAP_LOG(PWRAP_LOG_ERROR,
1107                           "Cannot disable OPENPAM_VERIFY_MODULE_FILE");
1108                 return rv;
1109         }
1110
1111         rv = openpam_set_feature(OPENPAM_VERIFY_POLICY_FILE, 0);
1112         if (rv != PAM_SUCCESS) {
1113                 PWRAP_LOG(PWRAP_LOG_ERROR,
1114                           "Cannot disable OPENPAM_VERIFY_POLICY_FILE");
1115                 return rv;
1116         }
1117
1118         snprintf(fullpath,
1119                  sizeof(fullpath),
1120                  "%s/%s",
1121                  pwrap.config_dir,
1122                  service_name);
1123
1124         return libpam_pam_start(fullpath,
1125                                 user,
1126                                 pam_conversation,
1127                                 pamh);
1128 }
1129 #endif
1130
1131 static int pwrap_pam_start(const char *service_name,
1132                            const char *user,
1133                            const struct pam_conv *pam_conversation,
1134                            pam_handle_t **pamh)
1135 {
1136         PWRAP_LOG(PWRAP_LOG_TRACE,
1137                   "pam_start service=%s, user=%s",
1138                   service_name,
1139                   user);
1140
1141 #ifdef HAVE_OPENPAM
1142         return pwrap_openpam_start(service_name,
1143                                    user,
1144                                    pam_conversation,
1145                                    pamh);
1146 #else
1147         return libpam_pam_start(service_name,
1148                                 user,
1149                                 pam_conversation,
1150                                 pamh);
1151 #endif
1152 }
1153
1154
1155 int pam_start(const char *service_name,
1156               const char *user,
1157               const struct pam_conv *pam_conversation,
1158               pam_handle_t **pamh)
1159 {
1160         return pwrap_pam_start(service_name, user, pam_conversation, pamh);
1161 }
1162
1163 static int pwrap_pam_end(pam_handle_t *pamh, int pam_status)
1164 {
1165         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_end status=%d", pam_status);
1166         return libpam_pam_end(pamh, pam_status);
1167 }
1168
1169
1170 int pam_end(pam_handle_t *pamh, int pam_status)
1171 {
1172         return pwrap_pam_end(pamh, pam_status);
1173 }
1174
1175 static int pwrap_pam_authenticate(pam_handle_t *pamh, int flags)
1176 {
1177         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_authenticate flags=%d", flags);
1178         return libpam_pam_authenticate(pamh, flags);
1179 }
1180
1181 int pam_authenticate(pam_handle_t *pamh, int flags)
1182 {
1183         return pwrap_pam_authenticate(pamh, flags);
1184 }
1185
1186 static int pwrap_pam_chauthtok(pam_handle_t *pamh, int flags)
1187 {
1188         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_chauthtok flags=%d", flags);
1189         return libpam_pam_chauthtok(pamh, flags);
1190 }
1191
1192 int pam_chauthtok(pam_handle_t *pamh, int flags)
1193 {
1194         return pwrap_pam_chauthtok(pamh, flags);
1195 }
1196
1197 static int pwrap_pam_acct_mgmt(pam_handle_t *pamh, int flags)
1198 {
1199         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_acct_mgmt flags=%d", flags);
1200         return libpam_pam_acct_mgmt(pamh, flags);
1201 }
1202
1203 int pam_acct_mgmt(pam_handle_t *pamh, int flags)
1204 {
1205         return pwrap_pam_acct_mgmt(pamh, flags);
1206 }
1207
1208 static int pwrap_pam_putenv(pam_handle_t *pamh, const char *name_value)
1209 {
1210         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_putenv name_value=%s", name_value);
1211         return libpam_pam_putenv(pamh, name_value);
1212 }
1213
1214 int pam_putenv(pam_handle_t *pamh, const char *name_value)
1215 {
1216         return pwrap_pam_putenv(pamh, name_value);
1217 }
1218
1219 static const char *pwrap_pam_getenv(pam_handle_t *pamh, const char *name)
1220 {
1221         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenv name=%s", name);
1222         return libpam_pam_getenv(pamh, name);
1223 }
1224
1225 const char *pam_getenv(pam_handle_t *pamh, const char *name)
1226 {
1227         return pwrap_pam_getenv(pamh, name);
1228 }
1229
1230 static char **pwrap_pam_getenvlist(pam_handle_t *pamh)
1231 {
1232         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_getenvlist called");
1233         return libpam_pam_getenvlist(pamh);
1234 }
1235
1236 char **pam_getenvlist(pam_handle_t *pamh)
1237 {
1238         return pwrap_pam_getenvlist(pamh);
1239 }
1240
1241 static int pwrap_pam_open_session(pam_handle_t *pamh, int flags)
1242 {
1243         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_open_session flags=%d", flags);
1244         return libpam_pam_open_session(pamh, flags);
1245 }
1246
1247 int pam_open_session(pam_handle_t *pamh, int flags)
1248 {
1249         return pwrap_pam_open_session(pamh, flags);
1250 }
1251
1252 static int pwrap_pam_close_session(pam_handle_t *pamh, int flags)
1253 {
1254         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_close_session flags=%d", flags);
1255         return libpam_pam_close_session(pamh, flags);
1256 }
1257
1258 int pam_close_session(pam_handle_t *pamh, int flags)
1259 {
1260         return pwrap_pam_close_session(pamh, flags);
1261 }
1262
1263 static int pwrap_pam_setcred(pam_handle_t *pamh, int flags)
1264 {
1265         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_setcred flags=%d", flags);
1266         return libpam_pam_setcred(pamh, flags);
1267 }
1268
1269 int pam_setcred(pam_handle_t *pamh, int flags)
1270 {
1271         return pwrap_pam_setcred(pamh, flags);
1272 }
1273
1274 static const char *pwrap_get_service(const char *libpam_service)
1275 {
1276 #ifdef HAVE_OPENPAM
1277         const char *service_name;
1278
1279         PWRAP_LOG(PWRAP_LOG_TRACE,
1280                   "internal PAM_SERVICE=%s", libpam_service);
1281         service_name = strrchr(libpam_service, '/');
1282         if (service_name != NULL && service_name[0] == '/') {
1283                 service_name++;
1284         }
1285         PWRAP_LOG(PWRAP_LOG_TRACE,
1286                   "PAM_SERVICE=%s", service_name);
1287         return service_name;
1288 #else
1289         return libpam_service;
1290 #endif
1291 }
1292
1293 static int pwrap_pam_get_item(const pam_handle_t *pamh,
1294                               int item_type,
1295                               const void **item)
1296 {
1297         int rc;
1298         const char *svc;
1299
1300         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item called");
1301
1302         rc = libpam_pam_get_item(pamh, item_type, item);
1303
1304         if (rc == PAM_SUCCESS) {
1305                 switch(item_type) {
1306                 case PAM_USER:
1307                         PWRAP_LOG(PWRAP_LOG_TRACE,
1308                                   "pwrap_get_item PAM_USER=%s",
1309                                   (const char *)*item);
1310                         break;
1311                 case PAM_SERVICE:
1312                         svc = pwrap_get_service((const char *) *item);
1313
1314                         PWRAP_LOG(PWRAP_LOG_TRACE,
1315                                   "pwrap_get_item PAM_SERVICE=%s",
1316                                   svc);
1317                         *item = svc;
1318                         break;
1319                 case PAM_USER_PROMPT:
1320                         PWRAP_LOG(PWRAP_LOG_TRACE,
1321                                   "pwrap_get_item PAM_USER_PROMPT=%s",
1322                                   (const char *)*item);
1323                         break;
1324                 case PAM_TTY:
1325                         PWRAP_LOG(PWRAP_LOG_TRACE,
1326                                   "pwrap_get_item PAM_TTY=%s",
1327                                   (const char *)*item);
1328                         break;
1329                 case PAM_RUSER:
1330                         PWRAP_LOG(PWRAP_LOG_TRACE,
1331                                   "pwrap_get_item PAM_RUSER=%s",
1332                                   (const char *)*item);
1333                         break;
1334                 case PAM_RHOST:
1335                         PWRAP_LOG(PWRAP_LOG_TRACE,
1336                                   "pwrap_get_item PAM_RHOST=%s",
1337                                   (const char *)*item);
1338                         break;
1339                 case PAM_AUTHTOK:
1340                         PWRAP_LOG(PWRAP_LOG_TRACE,
1341                                   "pwrap_get_item PAM_AUTHTOK=%s",
1342                                   (const char *)*item);
1343                         break;
1344                 case PAM_OLDAUTHTOK:
1345                         PWRAP_LOG(PWRAP_LOG_TRACE,
1346                                   "pwrap_get_item PAM_OLDAUTHTOK=%s",
1347                                   (const char *)*item);
1348                         break;
1349                 case PAM_CONV:
1350                         PWRAP_LOG(PWRAP_LOG_TRACE,
1351                                   "pwrap_get_item PAM_CONV=%p",
1352                                   (const void *)*item);
1353                         break;
1354                 default:
1355                         PWRAP_LOG(PWRAP_LOG_TRACE,
1356                                   "pwrap_get_item item_type=%d item=%p",
1357                                   item_type, (const void *)*item);
1358                         break;
1359                 }
1360         } else {
1361                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_get_item failed rc=%d", rc);
1362         }
1363
1364         return rc;
1365 }
1366
1367 int pam_get_item(const pam_handle_t *pamh, int item_type, const void **item)
1368 {
1369         return pwrap_pam_get_item(pamh, item_type, item);
1370 }
1371
1372 static int pwrap_pam_set_item(pam_handle_t *pamh,
1373                               int item_type,
1374                               const void *item)
1375 {
1376         int rc;
1377
1378         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item called");
1379
1380         rc = libpam_pam_set_item(pamh, item_type, item);
1381         if (rc == PAM_SUCCESS) {
1382                 switch(item_type) {
1383                 case PAM_USER:
1384                         PWRAP_LOG(PWRAP_LOG_TRACE,
1385                                   "pwrap_set_item PAM_USER=%s",
1386                                   (const char *)item);
1387                         break;
1388                 case PAM_SERVICE:
1389                         PWRAP_LOG(PWRAP_LOG_TRACE,
1390                                   "pwrap_set_item PAM_SERVICE=%s",
1391                                   (const char *)item);
1392                         break;
1393                 case PAM_USER_PROMPT:
1394                         PWRAP_LOG(PWRAP_LOG_TRACE,
1395                                   "pwrap_set_item PAM_USER_PROMPT=%s",
1396                                   (const char *)item);
1397                         break;
1398                 case PAM_TTY:
1399                         PWRAP_LOG(PWRAP_LOG_TRACE,
1400                                   "pwrap_set_item PAM_TTY=%s",
1401                                   (const char *)item);
1402                         break;
1403                 case PAM_RUSER:
1404                         PWRAP_LOG(PWRAP_LOG_TRACE,
1405                                   "pwrap_set_item PAM_RUSER=%s",
1406                                   (const char *)item);
1407                         break;
1408                 case PAM_RHOST:
1409                         PWRAP_LOG(PWRAP_LOG_TRACE,
1410                                   "pwrap_set_item PAM_RHOST=%s",
1411                                   (const char *)item);
1412                         break;
1413                 case PAM_AUTHTOK:
1414                         PWRAP_LOG(PWRAP_LOG_TRACE,
1415                                   "pwrap_set_item PAM_AUTHTOK=%s",
1416                                   (const char *)item);
1417                         break;
1418                 case PAM_OLDAUTHTOK:
1419                         PWRAP_LOG(PWRAP_LOG_TRACE,
1420                                   "pwrap_set_item PAM_OLDAUTHTOK=%s",
1421                                   (const char *)item);
1422                         break;
1423                 case PAM_CONV:
1424                         PWRAP_LOG(PWRAP_LOG_TRACE,
1425                                   "pwrap_set_item PAM_CONV=%p",
1426                                   item);
1427                         break;
1428                 default:
1429                         PWRAP_LOG(PWRAP_LOG_TRACE,
1430                                   "pwrap_set_item item_type=%d item=%p",
1431                                   item_type, item);
1432                         break;
1433                 }
1434         } else {
1435                 PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_set_item failed rc=%d", rc);
1436         }
1437
1438         return rc;
1439 }
1440
1441 int pam_set_item(pam_handle_t *pamh, int item_type, const void *item)
1442 {
1443         return pwrap_pam_set_item(pamh, item_type, item);
1444 }
1445
1446 static int pwrap_pam_get_data(const pam_handle_t *pamh,
1447                               const char *module_data_name,
1448                               const void **data)
1449 {
1450         PWRAP_LOG(PWRAP_LOG_TRACE,
1451                   "pwrap_get_data module_data_name=%s", module_data_name);
1452         return libpam_pam_get_data(pamh, module_data_name, data);
1453 }
1454
1455 int pam_get_data(const pam_handle_t *pamh,
1456                  const char *module_data_name,
1457                  const void **data)
1458 {
1459         return pwrap_pam_get_data(pamh, module_data_name, data);
1460 }
1461
1462 static int pwrap_pam_set_data(pam_handle_t *pamh,
1463                               const char *module_data_name,
1464                               void *data,
1465                               void (*cleanup)(pam_handle_t *pamh,
1466                                               void *data,
1467                                               int error_status))
1468 {
1469         PWRAP_LOG(PWRAP_LOG_TRACE,
1470                   "pwrap_set_data module_data_name=%s data=%p",
1471                   module_data_name, data);
1472         return libpam_pam_set_data(pamh, module_data_name, data, cleanup);
1473 }
1474
1475 int pam_set_data(pam_handle_t *pamh,
1476                  const char *module_data_name,
1477                  void *data,
1478                  void (*cleanup)(pam_handle_t *pamh,
1479                                  void *data,
1480                                  int error_status))
1481 {
1482         return pwrap_pam_set_data(pamh, module_data_name, data, cleanup);
1483 }
1484
1485 #ifdef HAVE_PAM_VPROMPT_CONST
1486 static int pwrap_pam_vprompt(const pam_handle_t *pamh,
1487 #else
1488 static int pwrap_pam_vprompt(pam_handle_t *pamh,
1489 #endif
1490                              int style,
1491                              char **response,
1492                              const char *fmt,
1493                              va_list args)
1494 {
1495         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vprompt style=%d", style);
1496         return libpam_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1497                                   style,
1498                                   response,
1499                                   fmt,
1500                                   args);
1501 }
1502
1503 #ifdef HAVE_PAM_VPROMPT_CONST
1504 int pam_vprompt(const pam_handle_t *pamh,
1505                 int style,
1506                 char **response,
1507                 const char *fmt,
1508                 va_list args)
1509 #else
1510 int pam_vprompt(pam_handle_t *pamh,
1511                 int style,
1512                 char **response,
1513                 const char *fmt,
1514                 va_list args)
1515 #endif
1516 {
1517         return pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1518                                  style,
1519                                  response,
1520                                  fmt,
1521                                  args);
1522 }
1523
1524 #ifdef HAVE_PAM_PROMPT_CONST
1525 int pam_prompt(const pam_handle_t *pamh,
1526                int style,
1527                char **response,
1528                const char *fmt, ...)
1529 #else
1530 int pam_prompt(pam_handle_t *pamh,
1531                int style,
1532                char **response,
1533                const char *fmt, ...)
1534 #endif
1535 {
1536         va_list args;
1537         int rv;
1538
1539         va_start(args, fmt);
1540         rv = pwrap_pam_vprompt(discard_const_p(pam_handle_t, pamh),
1541                                style,
1542                                response,
1543                                fmt,
1544                                args);
1545         va_end(args);
1546
1547         return rv;
1548 }
1549
1550 #ifdef HAVE_PAM_STRERROR_CONST
1551 static const char *pwrap_pam_strerror(const pam_handle_t *pamh, int errnum)
1552 #else
1553 static const char *pwrap_pam_strerror(pam_handle_t *pamh, int errnum)
1554 #endif
1555 {
1556         const char *str;
1557
1558         pwrap_init();
1559
1560         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror errnum=%d", errnum);
1561
1562         str = libpam_pam_strerror(discard_const_p(pam_handle_t, pamh),
1563                                   errnum);
1564
1565         PWRAP_LOG(PWRAP_LOG_TRACE, "pam_strerror error=%s", str);
1566
1567         return str;
1568 }
1569
1570 #ifdef HAVE_PAM_STRERROR_CONST
1571 const char *pam_strerror(const pam_handle_t *pamh, int errnum)
1572 #else
1573 const char *pam_strerror(pam_handle_t *pamh, int errnum)
1574 #endif
1575 {
1576         return pwrap_pam_strerror(discard_const_p(pam_handle_t, pamh),
1577                                   errnum);
1578 }
1579
1580 #if defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG)
1581 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1582                               int priority,
1583                               const char *fmt,
1584                               va_list args) PRINTF_ATTRIBUTE(3, 0);
1585
1586 static void pwrap_pam_vsyslog(const pam_handle_t *pamh,
1587                               int priority,
1588                               const char *fmt,
1589                               va_list args)
1590 {
1591         const char *d;
1592         char syslog_str[32] = {0};
1593         enum pwrap_dbglvl_e dbglvl = PWRAP_LOG_TRACE;
1594
1595         PWRAP_LOG(PWRAP_LOG_TRACE, "pwrap_pam_vsyslog called");
1596
1597 #ifdef HAVE_PAM_VSYSLOG
1598         d = getenv("PAM_WRAPPER_USE_SYSLOG");
1599         if (d != NULL && d[0] == '1') {
1600                 libpam_pam_vsyslog(pamh, priority, fmt, args);
1601                 return;
1602         }
1603 #endif /* HAVE_PAM_VSYSLOG */
1604
1605         switch(priority) {
1606         case 0: /* LOG_EMERG */
1607         case 1: /* LOG_ALERT */
1608         case 2: /* LOG_CRIT */
1609         case 3: /* LOG_ERR */
1610                 dbglvl = PWRAP_LOG_ERROR;
1611                 break;
1612         case 4: /* LOG_WARN */
1613                 dbglvl = PWRAP_LOG_WARN;
1614                 break;
1615         case 5: /* LOG_NOTICE */
1616         case 6: /* LOG_INFO */
1617         case 7: /* LOG_DEBUG */
1618                 dbglvl = PWRAP_LOG_DEBUG;
1619                 break;
1620         default:
1621                 dbglvl = PWRAP_LOG_TRACE;
1622                 break;
1623         }
1624
1625         snprintf(syslog_str, sizeof(syslog_str), "SYSLOG(%d)", priority);
1626
1627         pwrap_vlog(dbglvl, syslog_str, fmt, args);
1628 }
1629 #endif /* defined(HAVE_PAM_VSYSLOG) || defined(HAVE_PAM_SYSLOG) */
1630
1631 #ifdef HAVE_PAM_VSYSLOG
1632 void pam_vsyslog(const pam_handle_t *pamh,
1633                  int priority,
1634                  const char *fmt,
1635                  va_list args)
1636 {
1637         pwrap_pam_vsyslog(pamh, priority, fmt, args);
1638 }
1639 #endif
1640
1641 #ifdef HAVE_PAM_SYSLOG
1642 void pam_syslog(const pam_handle_t *pamh,
1643                 int priority,
1644                 const char *fmt, ...)
1645 {
1646         va_list args;
1647
1648         va_start(args, fmt);
1649         pwrap_pam_vsyslog(pamh, priority, fmt, args);
1650         va_end(args);
1651 }
1652 #endif
1653
1654 /* This might be called by pam_end() running with sshd */
1655 int audit_open(void);
1656 int audit_open(void)
1657 {
1658         /*
1659          * Tell the application that the kernel doesn't
1660          * have audit compiled in.
1661          */
1662         errno = EPROTONOSUPPORT;
1663         return -1;
1664 }
1665
1666 /* Disable BSD auditing */
1667 int cannot_audit(int x);
1668 int cannot_audit(int x)
1669 {
1670         (void) x;
1671
1672         return 1;
1673 }
1674
1675 /****************************
1676  * DESTRUCTOR
1677  ***************************/
1678
1679 static int p_rmdirs_at(const char *path, int parent_fd)
1680 {
1681         DIR *d;
1682         struct dirent *dp;
1683         struct stat sb;
1684         int path_fd;
1685         int rc;
1686
1687         /* If path is absolute, parent_fd is ignored. */
1688         PWRAP_LOG(PWRAP_LOG_TRACE,
1689                   "p_rmdirs_at removing %s at %d\n", path, parent_fd);
1690
1691         path_fd = openat(parent_fd,
1692                          path, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
1693         if (path_fd == -1) {
1694                 return -1;
1695         }
1696
1697         d = fdopendir(path_fd);
1698         if (d == NULL) {
1699                 close(path_fd);
1700                 return -1;
1701         }
1702
1703         while ((dp = readdir(d)) != NULL) {
1704                 /* skip '.' and '..' */
1705                 if (dp->d_name[0] == '.' &&
1706                         (dp->d_name[1] == '\0' ||
1707                         (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) {
1708                         continue;
1709                 }
1710
1711                 rc = fstatat(path_fd, dp->d_name,
1712                              &sb, AT_SYMLINK_NOFOLLOW);
1713                 if (rc != 0) {
1714                         continue;
1715                 }
1716
1717                 if (S_ISDIR(sb.st_mode)) {
1718                         rc = p_rmdirs_at(dp->d_name, path_fd);
1719                 } else {
1720                         rc = unlinkat(path_fd, dp->d_name, 0);
1721                 }
1722                 if (rc != 0) {
1723                         continue;
1724                 }
1725         }
1726         closedir(d);
1727
1728         rc = unlinkat(parent_fd, path, AT_REMOVEDIR);
1729         if (rc != 0) {
1730                 rc = errno;
1731                 PWRAP_LOG(PWRAP_LOG_TRACE,
1732                           "cannot unlink %s error %d\n", path, rc);
1733                 return -1;
1734         }
1735
1736         return 0;
1737 }
1738
1739 static int p_rmdirs(const char *path)
1740 {
1741         /*
1742          * If path is absolute, p_rmdirs_at ignores parent_fd.
1743          * If it's relative, start from cwd.
1744          */
1745         return p_rmdirs_at(path, AT_FDCWD);
1746 }
1747
1748 /*
1749  * This function is called when the library is unloaded and makes sure that
1750  * resources are freed.
1751  */
1752 void pwrap_destructor(void)
1753 {
1754         const char *env;
1755
1756         PWRAP_LOG(PWRAP_LOG_TRACE, "entering pwrap_destructor");
1757
1758         if (pwrap.libpam.handle != NULL) {
1759                 dlclose(pwrap.libpam.handle);
1760         }
1761
1762         if (pwrap.libpam_so != NULL) {
1763                 free(pwrap.libpam_so);
1764                 pwrap.libpam_so = NULL;
1765         }
1766
1767         if (!pwrap.initialised) {
1768                 return;
1769         }
1770
1771         PWRAP_LOG(PWRAP_LOG_TRACE,
1772                   "destructor called for pam_wrapper dir %s",
1773                   pwrap.config_dir);
1774         env = getenv("PAM_WRAPPER_KEEP_DIR");
1775         if (env == NULL || env[0] != '1') {
1776                 p_rmdirs(pwrap.config_dir);
1777         }
1778
1779         if (pwrap.config_dir != NULL) {
1780                 free(pwrap.config_dir);
1781                 pwrap.config_dir = NULL;
1782         }
1783 }