PERFORCE change 31858 for review
Dag-Erling Smorgrav
des at FreeBSD.org
Sun May 25 09:34:35 PDT 2003
http://perforce.freebsd.org/chv.cgi?CH=31858
Change 31858 by des at 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
More information about the p4-projects
mailing list