Date: Sun, 25 May 2003 09:34:32 -0700 (PDT) From: Dag-Erling Smorgrav <des@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 31858 for review Message-ID: <200305251634.h4PGYWoH090708@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=31858 Change 31858 by des@des.at.des.thinksec.com on 2003/05/25 09:34:31 Overhaul the configuration parser. This adds support for continuation lines and policy inclusion. Affected files ... .. //depot/projects/openpam/MANIFEST#15 edit .. //depot/projects/openpam/doc/man/Makefile#12 edit .. //depot/projects/openpam/include/security/openpam.h#22 edit .. //depot/projects/openpam/lib/Makefile#20 edit .. //depot/projects/openpam/lib/openpam_configure.c#8 edit .. //depot/projects/openpam/lib/openpam_impl.h#25 edit .. //depot/projects/openpam/lib/openpam_load.c#17 edit .. //depot/projects/openpam/lib/openpam_readline.c#1 add Differences ... ==== //depot/projects/openpam/MANIFEST#15 (text+ko) ==== @@ -1,5 +1,5 @@ # -# $P4: //depot/projects/openpam/MANIFEST#14 $ +# $P4: //depot/projects/openpam/MANIFEST#15 $ # CREDITS HISTORY @@ -78,6 +78,7 @@ lib/openpam_load.c lib/openpam_log.c lib/openpam_nullconv.c +lib/openpam_readline.c lib/openpam_restore_cred.c lib/openpam_set_option.c lib/openpam_static.c ==== //depot/projects/openpam/doc/man/Makefile#12 (text+ko) ==== @@ -32,7 +32,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $P4: //depot/projects/openpam/doc/man/Makefile#11 $ +# $P4: //depot/projects/openpam/doc/man/Makefile#12 $ # GENDOC = ${.CURDIR}/../../misc/gendoc.pl @@ -73,6 +73,7 @@ OMAN += openpam_get_option.3 OMAN += openpam_log.3 OMAN += openpam_nullconv.3 +OMAN += openpam_readline.3 OMAN += openpam_restore_cred.3 OMAN += openpam_set_option.3 OMAN += openpam_ttyconv.3 ==== //depot/projects/openpam/include/security/openpam.h#22 (text+ko) ==== @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/openpam/include/security/openpam.h#21 $ + * $P4: //depot/projects/openpam/include/security/openpam.h#22 $ */ #ifndef _SECURITY_OPENPAM_H_INCLUDED @@ -119,6 +119,17 @@ va_list _ap); /* + * Read cooked lines. + * Checking for FOPEN_MAX is a fairly reliable way to detect the presence + * of <stdio.h> + */ +#ifdef FOPEN_MAX +char * +openpam_readline(FILE *_f, + size_t *_lenp); +#endif + +/* * Log levels */ enum { ==== //depot/projects/openpam/lib/Makefile#20 (text+ko) ==== @@ -31,7 +31,7 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# $P4: //depot/projects/openpam/lib/Makefile#19 $ +# $P4: //depot/projects/openpam/lib/Makefile#20 $ # LIB = pam @@ -57,6 +57,7 @@ SRCS += openpam_load.c SRCS += openpam_log.c SRCS += openpam_nullconv.c +SRCS += openpam_readline.c SRCS += openpam_restore_cred.c SRCS += openpam_set_option.c SRCS += openpam_static.c ==== //depot/projects/openpam/lib/openpam_configure.c#8 (text+ko) ==== @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2002 Networks Associates Technology, Inc. + * Copyright (c) 2001-2003 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by ThinkSec AS and @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/openpam/lib/openpam_configure.c#7 $ + * $P4: //depot/projects/openpam/lib/openpam_configure.c#8 $ */ #include <ctype.h> @@ -44,169 +44,191 @@ #include "openpam_impl.h" -#define PAM_CONF_STYLE 0 -#define PAM_D_STYLE 1 -#define MAX_LINE_LEN 1024 -#define MAX_OPTIONS 256 +static int openpam_load_chain(pam_chain_t **, const char *, const char *); + +/* + * Matches a word against the first one in a string. + * Returns non-zero if they match. + */ +static int +match_word(const char *str, const char *word) +{ + + while (*str && *str == *word) + ++str, ++word; + return (*str == ' ' && *word == '\0'); +} + +/* + * Return a pointer to the next word (or the final NUL) in a string. + */ +static const char * +next_word(const char *str) +{ + + /* skip current word */ + while (*str && !isspace(*str)) + ++str; + /* skip whitespace */ + while (isspace(*str)) + ++str; + return (str); +} + +/* + * Return a malloc()ed copy of the first word in a string. + */ +static char * +dup_word(const char *str) +{ + const char *end; + char *word; + + for (end = str; *end && !isspace(*end); ++end) + /* nothing */ ; + if (asprintf(&word, "%.*s", (int)(end - str), str) < 0) + return (NULL); + return (word); +} + +typedef enum { pam_conf_style, pam_d_style } openpam_style_t; +/* + * Extracts a given chain from a policy file. + */ static int -openpam_read_policy_file(pam_chain_t *policy[], +openpam_read_chain(pam_chain_t **chain, const char *service, + const char *facility, const char *filename, - int style) + openpam_style_t style) { - char buf[MAX_LINE_LEN], *p, *q; - const char *optv[MAX_OPTIONS + 1]; - int ch, chain, flag, line, optc, n, r; - size_t len; + pam_chain_t *this, **next; + const char *p, *q; + int count, i, ret; + char *line, *name; FILE *f; - n = 0; - if ((f = fopen(filename, "r")) == NULL) { - openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE, + openpam_log(errno == ENOENT ? PAM_LOG_NOTICE : PAM_LOG_ERROR, "%s: %m", filename); return (0); } - openpam_log(PAM_LOG_DEBUG, "looking for '%s' in %s", - service, filename); + next = chain; + this = *next = NULL; + count = 0; + while ((line = openpam_readline(f, NULL)) != NULL) { + p = line; - for (line = 1; fgets(buf, MAX_LINE_LEN, f) != NULL; ++line) { - if ((len = strlen(buf)) == 0) - continue; + /* match service name */ + if (style == pam_conf_style) { + if (!match_word(p, service)) { + FREE(line); + continue; + } + p = next_word(p); + } - /* check for overflow */ - if (buf[--len] != '\n' && !feof(f)) { - openpam_log(PAM_LOG_ERROR, "%s: line %d too long", - filename, line); - openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d", - filename, line); - while ((ch = fgetc(f)) != EOF) - if (ch == '\n') - break; + /* match facility name */ + if (!match_word(p, facility)) { + FREE(line); continue; } + p = next_word(p); - /* strip comments and trailing whitespace */ - if ((p = strchr(buf, '#')) != NULL) - len = p - buf ? p - buf - 1 : p - buf; - while (len > 0 && isspace(buf[len - 1])) - --len; - if (len == 0) + /* include other chain */ + if (match_word(p, "include")) { + p = next_word(p); + if (*next_word(p) != '\0') + openpam_log(PAM_LOG_NOTICE, + "%s: garbage at end of 'include' line", + filename); + if ((name = dup_word(p)) == NULL) + goto syserr; + ret = openpam_load_chain(next, name, facility); + FREE(name); + while (*next != NULL) { + next = &(*next)->next; + ++count; + } + FREE(line); + if (ret < 0) + goto fail; continue; - buf[len] = '\0'; - p = q = buf; - - /* check service name */ - if (style == PAM_CONF_STYLE) { - for (q = p = buf; *q != '\0' && !isspace(*q); ++q) - /* nothing */; - if (*q == '\0') - goto syntax_error; - *q++ = '\0'; - if (strcmp(p, service) != 0) - continue; - openpam_log(PAM_LOG_DEBUG, "%s: line %d matches '%s'", - filename, line, service); } + /* allocate new entry */ + if ((this = calloc(1, sizeof *this)) == NULL) + goto syserr; - /* get module type */ - for (p = q; isspace(*p); ++p) - /* nothing */; - for (q = p; *q != '\0' && !isspace(*q); ++q) - /* nothing */; - if (q == p || *q == '\0') - goto syntax_error; - *q++ = '\0'; - if (strcmp(p, "auth") == 0) { - chain = PAM_AUTH; - } else if (strcmp(p, "account") == 0) { - chain = PAM_ACCOUNT; - } else if (strcmp(p, "session") == 0) { - chain = PAM_SESSION; - } else if (strcmp(p, "password") == 0) { - chain = PAM_PASSWORD; + /* control flag */ + if (match_word(p, "required")) { + this->flag = PAM_REQUIRED; + } else if (match_word(p, "requisite")) { + this->flag = PAM_REQUISITE; + } else if (match_word(p, "sufficient")) { + this->flag = PAM_SUFFICIENT; + } else if (match_word(p, "optional")) { + this->flag = PAM_OPTIONAL; + } else if (match_word(p, "binding")) { + this->flag = PAM_BINDING; } else { + q = next_word(p); openpam_log(PAM_LOG_ERROR, - "%s: invalid module type on line %d: '%s'", - filename, line, p); - continue; + "%s: invalid control flag '%.*s'", + filename, (int)(q - p), p); + goto fail; } - /* get control flag */ - for (p = q; isspace(*p); ++p) - /* nothing */; - for (q = p; *q != '\0' && !isspace(*q); ++q) - /* nothing */; - if (q == p || *q == '\0') - goto syntax_error; - *q++ = '\0'; - if (strcmp(p, "required") == 0) { - flag = PAM_REQUIRED; - } else if (strcmp(p, "requisite") == 0) { - flag = PAM_REQUISITE; - } else if (strcmp(p, "sufficient") == 0) { - flag = PAM_SUFFICIENT; - } else if (strcmp(p, "optional") == 0) { - flag = PAM_OPTIONAL; - } else if (strcmp(p, "binding") == 0) { - flag = PAM_BINDING; - } else { + /* module name */ + p = next_word(p); + q = next_word(p); + if (*p == '\0') { openpam_log(PAM_LOG_ERROR, - "%s: invalid control flag on line %d: '%s'", - filename, line, p); - continue; + "%s: missing module name", filename); + goto fail; } + if ((name = dup_word(p)) == NULL) + goto syserr; + this->module = openpam_load_module(name); + FREE(name); + if (this->module == NULL) + goto fail; - /* get module name */ - for (p = q; isspace(*p); ++p) - /* nothing */; - for (q = p; *q != '\0' && !isspace(*q); ++q) - /* nothing */; - if (q == p) - goto syntax_error; - - /* get options */ - for (optc = 0; *q != '\0' && optc < MAX_OPTIONS; ++optc) { - *q++ = '\0'; - while (isspace(*q)) - ++q; - optv[optc] = q; - while (*q != '\0' && !isspace(*q)) - ++q; + /* module options */ + while (*q != '\0') { + ++this->optc; + q = next_word(q); } - optv[optc] = NULL; - if (*q != '\0') { - *q = '\0'; - openpam_log(PAM_LOG_ERROR, - "%s: too many options on line %d", - filename, line); + this->optv = calloc(this->optc + 1, sizeof(char *)); + if (this->optv == NULL) + goto syserr; + for (i = 0; i < this->optc; ++i) { + p = next_word(p); + if ((this->optv[i] = dup_word(p)) == NULL) + goto syserr; } - /* - * Finally, add the module at the end of the - * appropriate chain and bump the counter. - */ - r = openpam_add_module(policy, chain, flag, p, optc, optv); - if (r != PAM_SUCCESS) - return (-r); - ++n; - continue; - syntax_error: - openpam_log(PAM_LOG_ERROR, "%s: syntax error on line %d", - filename, line); - openpam_log(PAM_LOG_DEBUG, "%s: line %d: [%s]", - filename, line, q); - openpam_log(PAM_LOG_ERROR, "%s: ignoring line %d", - filename, line); + /* hook it up */ + *next = this; + next = &this->next; + this = NULL; + ++count; + + /* next please... */ + FREE(line); } - - if (ferror(f)) - openpam_log(PAM_LOG_ERROR, "%s: %m", filename); - + if (!feof(f)) + goto syserr; + fclose(f); + return (count); + syserr: + openpam_log(PAM_LOG_ERROR, "%s: %m", filename); + fail: + FREE(this); + FREE(line); fclose(f); - return (n); + return (-1); } static const char *openpam_policy_path[] = { @@ -217,9 +239,14 @@ NULL }; +/* + * Locates the policy file for a given service and reads the given chain + * from it. + */ static int -openpam_load_policy(pam_chain_t *policy[], - const char *service) +openpam_load_chain(pam_chain_t **chain, + const char *service, + const char *facility) { const char **path; char *filename; @@ -229,27 +256,30 @@ for (path = openpam_policy_path; *path != NULL; ++path) { len = strlen(*path); if ((*path)[len - 1] == '/') { - filename = malloc(len + strlen(service) + 1); - if (filename == NULL) { - openpam_log(PAM_LOG_ERROR, "malloc(): %m"); + if (asprintf(&filename, "%s%s", *path, service) < 0) { + openpam_log(PAM_LOG_ERROR, "asprintf(): %m"); return (-PAM_BUF_ERR); } - strcpy(filename, *path); - strcat(filename, service); - r = openpam_read_policy_file(policy, - service, filename, PAM_D_STYLE); + r = openpam_read_chain(chain, service, facility, + filename, pam_d_style); FREE(filename); } else { - r = openpam_read_policy_file(policy, - service, *path, PAM_CONF_STYLE); + r = openpam_read_chain(chain, service, facility, + *path, pam_conf_style); } if (r != 0) return (r); } - return (0); } +const char *_pam_chain_name[PAM_NUM_CHAINS] = { + [PAM_AUTH] = "auth", + [PAM_ACCOUNT] = "account", + [PAM_SESSION] = "session", + [PAM_PASSWORD] = "password" +}; + /* * OpenPAM internal * @@ -260,34 +290,20 @@ openpam_configure(pam_handle_t *pamh, const char *service) { - pam_chain_t *other[PAM_NUM_CHAINS] = { 0 }; - int i, n, r; + int i, ret; - /* try own configuration first */ - r = openpam_load_policy(pamh->chains, service); - if (r < 0) - return (-r); - for (i = n = 0; i < PAM_NUM_CHAINS; ++i) { - if (pamh->chains[i] != NULL) - ++n; - } - if (n == PAM_NUM_CHAINS) - return (PAM_SUCCESS); - - /* fill in the blanks with "other" */ - openpam_load_policy(other, PAM_OTHER); - if (r < 0) - return (-r); - for (i = n = 0; i < PAM_NUM_CHAINS; ++i) { - if (pamh->chains[i] == NULL) { - pamh->chains[i] = other[i]; - other[i] = NULL; + for (i = 0; i < PAM_NUM_CHAINS; ++i) { + ret = openpam_load_chain(&pamh->chains[i], + service, _pam_chain_name[i]); + if (ret == 0) + ret = openpam_load_chain(&pamh->chains[i], + PAM_OTHER, _pam_chain_name[i]); + if (ret < 0) { + openpam_clear_chains(pamh->chains); + return (PAM_SYSTEM_ERR); } - if (pamh->chains[i] != NULL) - ++n; } - openpam_clear_chains(other); - return (n > 0 ? PAM_SUCCESS : PAM_SYSTEM_ERR); + return (PAM_SUCCESS); } /* @@ -295,5 +311,4 @@ * * Error codes: * PAM_SYSTEM_ERR - * PAM_BUF_ERR */ ==== //depot/projects/openpam/lib/openpam_impl.h#25 (text+ko) ==== @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/openpam/lib/openpam_impl.h#24 $ + * $P4: //depot/projects/openpam/lib/openpam_impl.h#25 $ */ #ifndef _OPENPAM_IMPL_H_INCLUDED @@ -112,17 +112,16 @@ #define PAM_OTHER "other" -int openpam_configure(pam_handle_t *, const char *); -int openpam_dispatch(pam_handle_t *, int, int); -int openpam_findenv(pam_handle_t *, const char *, size_t); -int openpam_add_module(pam_chain_t **, int, int, - const char *, int, const char **); -void openpam_clear_chains(pam_chain_t **); +int openpam_configure(pam_handle_t *, const char *); +int openpam_dispatch(pam_handle_t *, int, int); +int openpam_findenv(pam_handle_t *, const char *, size_t); +pam_module_t *openpam_load_module(const char *); +void openpam_clear_chains(pam_chain_t **); #ifdef OPENPAM_STATIC_MODULES -pam_module_t *openpam_static(const char *); +pam_module_t *openpam_static(const char *); #endif -pam_module_t *openpam_dynamic(const char *); +pam_module_t *openpam_dynamic(const char *); #define FREE(p) do { free((p)); (p) = NULL; } while (0) ==== //depot/projects/openpam/lib/openpam_load.c#17 (text+ko) ==== @@ -31,7 +31,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $P4: //depot/projects/openpam/lib/openpam_load.c#16 $ + * $P4: //depot/projects/openpam/lib/openpam_load.c#17 $ */ #include <dlfcn.h> @@ -67,7 +67,7 @@ * found modules to speed up the process. */ -static pam_module_t * +pam_module_t * openpam_load_module(const char *path) { pam_module_t *module; @@ -160,48 +160,6 @@ FREE(chain); } -/* - * Add a module to a chain. - */ - -int -openpam_add_module(pam_chain_t *policy[], - int chain, - int flag, - const char *modpath, - int optc, - const char *optv[]) -{ - pam_chain_t *new, *iterator; - - if ((new = calloc(1, sizeof *new)) == NULL) - goto buf_err; - if ((new->optv = malloc(sizeof(char *) * (optc + 1))) == NULL) - goto buf_err; - while (optc--) - if ((new->optv[new->optc++] = strdup(*optv++)) == NULL) - goto buf_err; - new->optv[new->optc] = NULL; - new->flag = flag; - if ((new->module = openpam_load_module(modpath)) == NULL) { - openpam_destroy_chain(new); - return (PAM_OPEN_ERR); - } - if ((iterator = policy[chain]) != NULL) { - while (iterator->next != NULL) - iterator = iterator->next; - iterator->next = new; - } else { - policy[chain] = new; - } - return (PAM_SUCCESS); - - buf_err: - openpam_log(PAM_LOG_ERROR, "%m"); - openpam_destroy_chain(new); - return (PAM_BUF_ERR); -} - /* * Clear the chains and release the modules
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200305251634.h4PGYWoH090708>
