diff options
Diffstat (limited to 'libpam/include/pam_inline.h')
-rw-r--r-- | libpam/include/pam_inline.h | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/libpam/include/pam_inline.h b/libpam/include/pam_inline.h index ec05fe43..7721c0b7 100644 --- a/libpam/include/pam_inline.h +++ b/libpam/include/pam_inline.h @@ -9,7 +9,10 @@ #define PAM_INLINE_H #include "pam_cc_compat.h" +#include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <errno.h> /* * Evaluates to @@ -31,6 +34,12 @@ * 0, otherwise. */ #define PAM_MUST_BE_ARRAY(a_) PAM_FAIL_BUILD_ON_ZERO(!PAM_IS_NOT_ARRAY(a_)) +/* + * Evaluates to + * - a syntax error if the argument is an array, + * 0, otherwise. + */ +#define PAM_MUST_NOT_BE_ARRAY(a_) PAM_FAIL_BUILD_ON_ZERO(PAM_IS_NOT_ARRAY(a_)) /* Evaluates to the number of elements in the specified array. */ #define PAM_ARRAY_SIZE(a_) (sizeof(a_) / sizeof((a_)[0]) + PAM_MUST_BE_ARRAY(a_)) @@ -64,4 +73,106 @@ pam_str_skip_icase_prefix_len(const char *str, const char *prefix, size_t prefix #define pam_str_skip_icase_prefix(str_, prefix_) \ pam_str_skip_icase_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_)) + +/* + * Macros to securely erase memory + */ + +#ifdef HAVE_MEMSET_EXPLICIT +static inline void pam_overwrite_n(void *ptr, size_t len) +{ + if (ptr) + memset_explicit(ptr, len); +} +#elif defined HAVE_EXPLICIT_BZERO +static inline void pam_overwrite_n(void *ptr, size_t len) +{ + if (ptr) + explicit_bzero(ptr, len); +} +#else +static inline void pam_overwrite_n(void *ptr, size_t len) +{ + if (ptr) { + ptr = memset(ptr, '\0', len); + __asm__ __volatile__ ("" : : "r"(ptr) : "memory"); + } +} +#endif + +#define pam_overwrite_string(x) \ +do { \ + char *xx__ = (x) + PAM_MUST_NOT_BE_ARRAY(x); \ + if (xx__) \ + pam_overwrite_n(xx__, strlen(xx__)); \ +} while(0) + +#define pam_overwrite_array(x) pam_overwrite_n(x, sizeof(x) + PAM_MUST_BE_ARRAY(x)) + +#define pam_overwrite_object(x) pam_overwrite_n(x, sizeof(*(x)) + PAM_MUST_NOT_BE_ARRAY(x)) + +static inline void +pam_drop_response(struct pam_response *reply, int replies) +{ + int reply_i; + + for (reply_i = 0; reply_i < replies; ++reply_i) { + if (reply[reply_i].resp) { + pam_overwrite_string(reply[reply_i].resp); + free(reply[reply_i].resp); + } + } + free(reply); +} + + +static inline int +pam_read_passwords(int fd, int npass, char **passwords) +{ + /* + * The passwords array must contain npass preallocated + * buffers of length PAM_MAX_RESP_SIZE + 1. + */ + int rbytes = 0; + int offset = 0; + int i = 0; + char *pptr; + while (npass > 0) { + rbytes = read(fd, passwords[i]+offset, PAM_MAX_RESP_SIZE+1-offset); + + if (rbytes < 0) { + if (errno == EINTR) { + continue; + } + break; + } + if (rbytes == 0) { + break; + } + + while (npass > 0 && + (pptr = memchr(passwords[i] + offset, '\0', rbytes)) != NULL) { + ++pptr; /* skip the '\0' */ + rbytes -= pptr - (passwords[i] + offset); + i++; + offset = 0; + npass--; + if (rbytes > 0) { + if (npass > 0) { + memcpy(passwords[i], pptr, rbytes); + } + pam_overwrite_n(pptr, rbytes); + } + } + offset += rbytes; + } + + /* clear up */ + if (offset > 0 && npass > 0) { + pam_overwrite_n(passwords[i], offset); + } + + return i; +} + #endif /* PAM_INLINE_H */ |