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