1
0
Fork 0
pam/libpam/include/pam_inline.h
Daniel Baumann 82f0236850
Adding upstream version 1.7.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 06:53:43 +02:00

212 lines
5.3 KiB
C

/*
* Copyright (c) 2020 Dmitry V. Levin <ldv@altlinux.org>
*
* Handy inline functions and macros providing some convenient functionality
* to libpam and its modules.
*/
#ifndef PAM_INLINE_H
#define PAM_INLINE_H
#include "pam_cc_compat.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
/*
* Evaluates to
* - a syntax error if the argument is 0,
* 0, otherwise.
*/
#define PAM_FAIL_BUILD_ON_ZERO(e_) (sizeof(int[-1 + 2 * !!(e_)]) * 0)
/*
* Evaluates to
* 1, if the given type is known to be a non-array type
* 0, otherwise.
*/
#define PAM_IS_NOT_ARRAY(a_) PAM_IS_SAME_TYPE((a_), &(a_)[0])
/*
* Evaluates to
* - a syntax error if the argument is not an array,
* 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_))
/*
* Zero-extend a signed integer type to unsigned long long.
*/
# define zero_extend_signed_to_ull(v_) \
(sizeof(v_) == sizeof(char) ? (unsigned long long) (unsigned char) (v_) : \
sizeof(v_) == sizeof(short) ? (unsigned long long) (unsigned short) (v_) : \
sizeof(v_) == sizeof(int) ? (unsigned long long) (unsigned int) (v_) : \
sizeof(v_) == sizeof(long) ? (unsigned long long) (unsigned long) (v_) : \
(unsigned long long) (v_))
/*
* Sign-extend an unsigned integer type to long long.
*/
# define sign_extend_unsigned_to_ll(v_) \
(sizeof(v_) == sizeof(char) ? (long long) (signed char) (v_) : \
sizeof(v_) == sizeof(short) ? (long long) (signed short) (v_) : \
sizeof(v_) == sizeof(int) ? (long long) (signed int) (v_) : \
sizeof(v_) == sizeof(long) ? (long long) (signed long) (v_) : \
(long long) (v_))
/*
* Returns NULL if STR does not start with PREFIX,
* or a pointer to the first char in STR after PREFIX.
* The length of PREFIX is specified by PREFIX_LEN.
*/
static inline const char *
pam_str_skip_prefix_len(const char *str, const char *prefix, size_t prefix_len)
{
return strncmp(str, prefix, prefix_len) ? NULL : str + prefix_len;
}
#define pam_str_skip_prefix(str_, prefix_) \
pam_str_skip_prefix_len((str_), (prefix_), sizeof(prefix_) - 1 + PAM_MUST_BE_ARRAY(prefix_))
/*
* Returns NULL if STR does not start with PREFIX
* (ignoring the case of the characters),
* or a pointer to the first char in STR after PREFIX.
* The length of PREFIX is specified by PREFIX_LEN.
*/
static inline const char *
pam_str_skip_icase_prefix_len(const char *str, const char *prefix, size_t prefix_len)
{
return strncasecmp(str, prefix, prefix_len) ? NULL : str + prefix_len;
}
#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, '\0', 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;
}
static inline int
pam_consttime_streq(const char *userinput, const char *secret) {
volatile const char *u = userinput, *s = secret;
volatile int ret = 0;
do {
ret |= *u ^ *s;
s += !!*s;
} while (*u++ != '\0');
return ret == 0;
}
#endif /* PAM_INLINE_H */