(root)/
Linux-PAM-1.5.3/
libpam/
include/
pam_inline.h
       1  /*
       2   * Copyright (c) 2020 Dmitry V. Levin <ldv@altlinux.org>
       3   *
       4   * Handy inline functions and macros providing some convenient functionality
       5   * to libpam and its modules.
       6   */
       7  
       8  #ifndef PAM_INLINE_H
       9  #define PAM_INLINE_H
      10  
      11  #include "pam_cc_compat.h"
      12  #include <stdlib.h>
      13  #include <string.h>
      14  #include <unistd.h>
      15  #include <errno.h>
      16  
      17  /*
      18   * Evaluates to
      19   * - a syntax error if the argument is 0,
      20   * 0, otherwise.
      21   */
      22  #define PAM_FAIL_BUILD_ON_ZERO(e_)	(sizeof(int[-1 + 2 * !!(e_)]) * 0)
      23  
      24  /*
      25   * Evaluates to
      26   * 1, if the given type is known to be a non-array type
      27   * 0, otherwise.
      28   */
      29  #define PAM_IS_NOT_ARRAY(a_)		PAM_IS_SAME_TYPE((a_), &(a_)[0])
      30  
      31  /*
      32   * Evaluates to
      33   * - a syntax error if the argument is not an array,
      34   * 0, otherwise.
      35   */
      36  #define PAM_MUST_BE_ARRAY(a_)		PAM_FAIL_BUILD_ON_ZERO(!PAM_IS_NOT_ARRAY(a_))
      37  /*
      38   * Evaluates to
      39   * - a syntax error if the argument is an array,
      40   * 0, otherwise.
      41   */
      42  #define PAM_MUST_NOT_BE_ARRAY(a_)	PAM_FAIL_BUILD_ON_ZERO(PAM_IS_NOT_ARRAY(a_))
      43  
      44  /* Evaluates to the number of elements in the specified array.  */
      45  #define PAM_ARRAY_SIZE(a_)		(sizeof(a_) / sizeof((a_)[0]) + PAM_MUST_BE_ARRAY(a_))
      46  
      47  /*
      48   * Returns NULL if STR does not start with PREFIX,
      49   * or a pointer to the first char in STR after PREFIX.
      50   * The length of PREFIX is specified by PREFIX_LEN.
      51   */
      52  static inline const char *
      53  pam_str_skip_prefix_len(const char *str, const char *prefix, size_t prefix_len)
      54  {
      55  	return strncmp(str, prefix, prefix_len) ? NULL : str + prefix_len;
      56  }
      57  
      58  #define pam_str_skip_prefix(str_, prefix_)	\
      59  	pam_str_skip_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_))
      60  
      61  /*
      62   * Returns NULL if STR does not start with PREFIX
      63   * (ignoring the case of the characters),
      64   * or a pointer to the first char in STR after PREFIX.
      65   * The length of PREFIX is specified by PREFIX_LEN.
      66   */
      67  static inline const char *
      68  pam_str_skip_icase_prefix_len(const char *str, const char *prefix, size_t prefix_len)
      69  {
      70  	return strncasecmp(str, prefix, prefix_len) ? NULL : str + prefix_len;
      71  }
      72  
      73  #define pam_str_skip_icase_prefix(str_, prefix_)	\
      74  	pam_str_skip_icase_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_))
      75  
      76  
      77  /*
      78   * Macros to securely erase memory
      79   */
      80  
      81  #ifdef HAVE_MEMSET_EXPLICIT
      82  static inline void pam_overwrite_n(void *ptr, size_t len)
      83  {
      84  	if (ptr)
      85  		memset_explicit(ptr, len);
      86  }
      87  #elif defined HAVE_EXPLICIT_BZERO
      88  static inline void pam_overwrite_n(void *ptr, size_t len)
      89  {
      90  	if (ptr)
      91  		explicit_bzero(ptr, len);
      92  }
      93  #else
      94  static inline void pam_overwrite_n(void *ptr, size_t len)
      95  {
      96  	if (ptr) {
      97  		ptr = memset(ptr, '\0', len);
      98  		__asm__ __volatile__ ("" : : "r"(ptr) : "memory");
      99  	}
     100  }
     101  #endif
     102  
     103  #define pam_overwrite_string(x)                      \
     104  do {                                                 \
     105  	char *xx__ = (x) + PAM_MUST_NOT_BE_ARRAY(x); \
     106  	if (xx__)                                    \
     107  		pam_overwrite_n(xx__, strlen(xx__)); \
     108  } while(0)
     109  
     110  #define pam_overwrite_array(x) pam_overwrite_n(x, sizeof(x) + PAM_MUST_BE_ARRAY(x))
     111  
     112  #define pam_overwrite_object(x) pam_overwrite_n(x, sizeof(*(x)) + PAM_MUST_NOT_BE_ARRAY(x))
     113  
     114  static inline void
     115  pam_drop_response(struct pam_response *reply, int replies)
     116  {
     117  	int reply_i;
     118  
     119  	for (reply_i = 0; reply_i < replies; ++reply_i) {
     120  		if (reply[reply_i].resp) {
     121  			pam_overwrite_string(reply[reply_i].resp);
     122  			free(reply[reply_i].resp);
     123  		}
     124  	}
     125  	free(reply);
     126  }
     127  
     128  
     129  static inline int
     130  pam_read_passwords(int fd, int npass, char **passwords)
     131  {
     132  	/*
     133  	 * The passwords array must contain npass preallocated
     134  	 * buffers of length PAM_MAX_RESP_SIZE + 1.
     135  	 */
     136  	int rbytes = 0;
     137  	int offset = 0;
     138  	int i = 0;
     139  	char *pptr;
     140  	while (npass > 0) {
     141  		rbytes = read(fd, passwords[i]+offset, PAM_MAX_RESP_SIZE+1-offset);
     142  
     143  		if (rbytes < 0) {
     144  			if (errno == EINTR) {
     145  				continue;
     146  			}
     147  			break;
     148  		}
     149  		if (rbytes == 0) {
     150  			break;
     151  		}
     152  
     153  		while (npass > 0 &&
     154  		       (pptr = memchr(passwords[i] + offset, '\0', rbytes)) != NULL) {
     155  			++pptr; /* skip the '\0' */
     156  			rbytes -= pptr - (passwords[i] + offset);
     157  			i++;
     158  			offset = 0;
     159  			npass--;
     160  			if (rbytes > 0) {
     161  				if (npass > 0) {
     162  					memcpy(passwords[i], pptr, rbytes);
     163  				}
     164  				pam_overwrite_n(pptr, rbytes);
     165  			}
     166  		}
     167  		offset += rbytes;
     168  	}
     169  
     170  	/* clear up */
     171  	if (offset > 0 && npass > 0) {
     172  		pam_overwrite_n(passwords[i], offset);
     173  	}
     174  
     175  	return i;
     176  }
     177  
     178  #endif /* PAM_INLINE_H */