diff options
| author | Cy Schubert <cy@FreeBSD.org> | 2025-04-17 02:13:41 +0000 |
|---|---|---|
| committer | Cy Schubert <cy@FreeBSD.org> | 2025-05-27 16:20:06 +0000 |
| commit | 24f0b4ca2d565cdbb4fe7839ff28320706bf2386 (patch) | |
| tree | bc9ce87edb73f767f5580887d0fc8c643b9d7a49 /pam-util/vector.c | |
pam-krb5: Import/add pam-krb5 from eyeire.orgvendor/pam-krb5/4.11vendor/pam-krb5
From https://www.eyrie.org/~eagle/software/pam-krb5/:
pam-krb5 provides a Kerberos PAM module that supports authentication,
user ticket cache handling, simple authorization (via .k5login or
checking Kerberos principals against local usernames), and password
changing. It can be configured through either options in the PAM
configuration itself or through entries in the system krb5.conf file,
and it tries to work around PAM implementation flaws in commonly-used
PAM-enabled applications such as OpenSSH and xdm. It supports both
PKINIT and FAST to the extent that the underlying Kerberos libraries
support these features.
The reason for this import is to provide an MIT KRB5 compatible
pam_krb5 PAM module. The existing pam_krb5 in FreeBS only works
with Heimdal.
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'pam-util/vector.c')
| -rw-r--r-- | pam-util/vector.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/pam-util/vector.c b/pam-util/vector.c new file mode 100644 index 000000000000..012a9aef24a3 --- /dev/null +++ b/pam-util/vector.c @@ -0,0 +1,289 @@ +/* + * Vector handling (counted lists of char *'s). + * + * A vector is a table for handling a list of strings with less overhead than + * linked list. The intention is for vectors, once allocated, to be reused; + * this saves on memory allocations once the array of char *'s reaches a + * stable size. + * + * This is based on the util/vector.c library, but that library uses xmalloc + * routines to exit the program if memory allocation fails. This is a + * modified version of the vector library that instead returns false on + * failure to allocate memory, allowing the caller to do appropriate recovery. + * + * Vectors require list of strings, not arbitrary binary data, and cannot + * handle data elements containing nul characters. + * + * Only the portions of the vector library used by PAM modules are + * implemented. + * + * The canonical version of this file is maintained in the rra-c-util package, + * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>. + * + * Written by Russ Allbery <eagle@eyrie.org> + * Copyright 2017-2018 Russ Allbery <eagle@eyrie.org> + * Copyright 2010-2011, 2014 + * The Board of Trustees of the Leland Stanford Junior University + * + * Copying and distribution of this file, with or without modification, are + * permitted in any medium without royalty provided the copyright notice and + * this notice are preserved. This file is offered as-is, without any + * warranty. + * + * SPDX-License-Identifier: FSFAP + */ + +#include <config.h> +#include <portable/system.h> + +#include <pam-util/vector.h> + + +/* + * Allocate a new, empty vector. Returns NULL if memory allocation fails. + */ +struct vector * +vector_new(void) +{ + struct vector *vector; + + vector = calloc(1, sizeof(struct vector)); + vector->allocated = 1; + vector->strings = calloc(1, sizeof(char *)); + return vector; +} + + +/* + * Allocate a new vector that's a copy of an existing vector. Returns NULL if + * memory allocation fails. + */ +struct vector * +vector_copy(const struct vector *old) +{ + struct vector *vector; + size_t i; + + vector = vector_new(); + if (!vector_resize(vector, old->count)) { + vector_free(vector); + return NULL; + } + vector->count = old->count; + for (i = 0; i < old->count; i++) { + vector->strings[i] = strdup(old->strings[i]); + if (vector->strings[i] == NULL) { + vector_free(vector); + return NULL; + } + } + return vector; +} + + +/* + * Resize a vector (using reallocarray to resize the table). Return false if + * memory allocation fails. + */ +bool +vector_resize(struct vector *vector, size_t size) +{ + size_t i; + char **strings; + + if (vector->count > size) { + for (i = size; i < vector->count; i++) + free(vector->strings[i]); + vector->count = size; + } + if (size == 0) + size = 1; + strings = reallocarray(vector->strings, size, sizeof(char *)); + if (strings == NULL) + return false; + vector->strings = strings; + vector->allocated = size; + return true; +} + + +/* + * Add a new string to the vector, resizing the vector as necessary. The + * vector is resized an element at a time; if a lot of resizes are expected, + * vector_resize should be called explicitly with a more suitable size. + * Return false if memory allocation fails. + */ +bool +vector_add(struct vector *vector, const char *string) +{ + size_t next = vector->count; + + if (vector->count == vector->allocated) + if (!vector_resize(vector, vector->allocated + 1)) + return false; + vector->strings[next] = strdup(string); + if (vector->strings[next] == NULL) + return false; + vector->count++; + return true; +} + + +/* + * Empty a vector but keep the allocated memory for the pointer table. + */ +void +vector_clear(struct vector *vector) +{ + size_t i; + + for (i = 0; i < vector->count; i++) + if (vector->strings[i] != NULL) + free(vector->strings[i]); + vector->count = 0; +} + + +/* + * Free a vector completely. + */ +void +vector_free(struct vector *vector) +{ + if (vector == NULL) + return; + vector_clear(vector); + free(vector->strings); + free(vector); +} + + +/* + * Given a vector that we may be reusing, clear it out. If the first argument + * is NULL, allocate a new vector. Used by vector_split*. Returns NULL if + * memory allocation fails. + */ +static struct vector * +vector_reuse(struct vector *vector) +{ + if (vector == NULL) + return vector_new(); + else { + vector_clear(vector); + return vector; + } +} + + +/* + * Given a string and a set of separators expressed as a string, count the + * number of strings that it will split into when splitting on those + * separators. + */ +static size_t +split_multi_count(const char *string, const char *seps) +{ + const char *p; + size_t count; + + if (*string == '\0') + return 0; + for (count = 1, p = string + 1; *p != '\0'; p++) + if (strchr(seps, *p) != NULL && strchr(seps, p[-1]) == NULL) + count++; + + /* + * If the string ends in separators, we've overestimated the number of + * strings by one. + */ + if (strchr(seps, p[-1]) != NULL) + count--; + return count; +} + + +/* + * Given a string, split it at any of the provided separators to form a + * vector, copying each string segment. If the third argument isn't NULL, + * reuse that vector; otherwise, allocate a new one. Any number of + * consecutive separators are considered a single separator. Returns NULL on + * memory allocation failure, after which the provided vector may only have + * partial results. + */ +struct vector * +vector_split_multi(const char *string, const char *seps, struct vector *vector) +{ + const char *p, *start; + size_t i, count; + bool created = false; + + if (vector == NULL) + created = true; + vector = vector_reuse(vector); + if (vector == NULL) + return NULL; + + count = split_multi_count(string, seps); + if (vector->allocated < count && !vector_resize(vector, count)) + goto fail; + + vector->count = 0; + for (start = string, p = string, i = 0; *p != '\0'; p++) + if (strchr(seps, *p) != NULL) { + if (start != p) { + vector->strings[i] = strndup(start, (size_t)(p - start)); + if (vector->strings[i] == NULL) + goto fail; + i++; + vector->count++; + } + start = p + 1; + } + if (start != p) { + vector->strings[i] = strndup(start, (size_t)(p - start)); + if (vector->strings[i] == NULL) + goto fail; + vector->count++; + } + return vector; + +fail: + if (created) + vector_free(vector); + return NULL; +} + + +/* + * Given a vector and a path to a program, exec that program with the vector + * as its arguments. This requires adding a NULL terminator to the vector and + * casting it appropriately. Returns 0 on success and -1 on error, like exec + * does. + */ +int +vector_exec(const char *path, struct vector *vector) +{ + if (vector->allocated == vector->count) + if (!vector_resize(vector, vector->count + 1)) + return -1; + vector->strings[vector->count] = NULL; + return execv(path, (char *const *) vector->strings); +} + + +/* + * Given a vector, a path to a program, and the environment, exec that program + * with the vector as its arguments and the given environment. This requires + * adding a NULL terminator to the vector and casting it appropriately. + * Returns 0 on success and -1 on error, like exec does. + */ +int +vector_exec_env(const char *path, struct vector *vector, + const char *const env[]) +{ + if (vector->allocated == vector->count) + if (!vector_resize(vector, vector->count + 1)) + return -1; + vector->strings[vector->count] = NULL; + return execve(path, (char *const *) vector->strings, (char *const *) env); +} |
