summaryrefslogtreecommitdiffstats
path: root/lib/openpam_configure.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2008-12-13 22:45:22 +0000
committerdes <des@FreeBSD.org>2008-12-13 22:45:22 +0000
commit646ea20decc87530f871e5c56e96980c93fcf391 (patch)
tree9151e2f3daf5644596ed8a0e176d5e719b780a10 /lib/openpam_configure.c
parent5bb985da807ca1473ce8a14def069f52914bce8e (diff)
downloadFreeBSD-src-646ea20decc87530f871e5c56e96980c93fcf391.zip
FreeBSD-src-646ea20decc87530f871e5c56e96980c93fcf391.tar.gz
Flatten and clean up.
Diffstat (limited to 'lib/openpam_configure.c')
-rw-r--r--lib/openpam_configure.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/lib/openpam_configure.c b/lib/openpam_configure.c
new file mode 100644
index 0000000..f9197ad
--- /dev/null
+++ b/lib/openpam_configure.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
+ * Copyright (c) 2004-2007 Dag-Erling Smørgrav
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by ThinkSec AS and
+ * Network Associates Laboratories, the Security Research Division of
+ * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: openpam_configure.c 408 2007-12-21 11:36:24Z des $
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <security/pam_appl.h>
+
+#include "openpam_impl.h"
+
+const char *_pam_facility_name[PAM_NUM_FACILITIES] = {
+ [PAM_ACCOUNT] = "account",
+ [PAM_AUTH] = "auth",
+ [PAM_PASSWORD] = "password",
+ [PAM_SESSION] = "session",
+};
+
+const char *_pam_control_flag_name[PAM_NUM_CONTROL_FLAGS] = {
+ [PAM_BINDING] = "binding",
+ [PAM_OPTIONAL] = "optional",
+ [PAM_REQUIRED] = "required",
+ [PAM_REQUISITE] = "requisite",
+ [PAM_SUFFICIENT] = "sufficient",
+};
+
+static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
+
+/*
+ * 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 && tolower(*str) == tolower(*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 && *str != ' ')
+ ++str;
+ /* skip whitespace */
+ while (*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 && *end != ' '; ++end)
+ /* nothing */ ;
+ if (asprintf(&word, "%.*s", (int)(end - str), str) < 0)
+ return (NULL);
+ return (word);
+}
+
+/*
+ * Return the length of the first word in a string.
+ */
+static int
+wordlen(const char *str)
+{
+ int i;
+
+ for (i = 0; str[i] && str[i] != ' '; ++i)
+ /* nothing */ ;
+ return (i);
+}
+
+typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
+
+/*
+ * Extracts given chains from a policy file.
+ */
+static int
+openpam_read_chain(pam_handle_t *pamh,
+ const char *service,
+ pam_facility_t facility,
+ const char *filename,
+ openpam_style_t style)
+{
+ pam_chain_t *this, **next;
+ const char *p, *q;
+ int count, i, lineno, ret;
+ pam_facility_t fclt;
+ pam_control_t ctlf;
+ char *line, *name;
+ FILE *f;
+
+ if ((f = fopen(filename, "r")) == NULL) {
+ openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE,
+ "%s: %m", filename);
+ return (0);
+ }
+ this = NULL;
+ count = lineno = 0;
+ while ((line = openpam_readline(f, &lineno, NULL)) != NULL) {
+ p = line;
+
+ /* match service name */
+ if (style == pam_conf_style) {
+ if (!match_word(p, service)) {
+ FREE(line);
+ continue;
+ }
+ p = next_word(p);
+ }
+
+ /* match facility name */
+ for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt)
+ if (match_word(p, _pam_facility_name[fclt]))
+ break;
+ if (fclt == PAM_NUM_FACILITIES) {
+ openpam_log(PAM_LOG_NOTICE,
+ "%s(%d): invalid facility '%.*s' (ignored)",
+ filename, lineno, wordlen(p), p);
+ goto fail;
+ }
+ if (facility != fclt && facility != PAM_FACILITY_ANY) {
+ FREE(line);
+ continue;
+ }
+ p = next_word(p);
+
+ /* include other chain */
+ if (match_word(p, "include")) {
+ p = next_word(p);
+ if (*next_word(p) != '\0')
+ openpam_log(PAM_LOG_NOTICE,
+ "%s(%d): garbage at end of 'include' line",
+ filename, lineno);
+ if ((name = dup_word(p)) == NULL)
+ goto syserr;
+ ret = openpam_load_chain(pamh, name, fclt);
+ FREE(name);
+ if (ret < 0)
+ goto fail;
+ count += ret;
+ FREE(line);
+ continue;
+ }
+
+ /* allocate new entry */
+ if ((this = calloc(1, sizeof *this)) == NULL)
+ goto syserr;
+
+ /* control flag */
+ for (ctlf = 0; ctlf < PAM_NUM_CONTROL_FLAGS; ++ctlf)
+ if (match_word(p, _pam_control_flag_name[ctlf]))
+ break;
+ if (ctlf == PAM_NUM_CONTROL_FLAGS) {
+ openpam_log(PAM_LOG_ERROR,
+ "%s(%d): invalid control flag '%.*s'",
+ filename, lineno, wordlen(p), p);
+ goto fail;
+ }
+ this->flag = ctlf;
+
+ /* module name */
+ p = next_word(p);
+ if (*p == '\0') {
+ openpam_log(PAM_LOG_ERROR,
+ "%s(%d): missing module name",
+ filename, lineno);
+ goto fail;
+ }
+ if ((name = dup_word(p)) == NULL)
+ goto syserr;
+ this->module = openpam_load_module(name);
+ FREE(name);
+ if (this->module == NULL)
+ goto fail;
+
+ /* module options */
+ p = q = next_word(p);
+ while (*q != '\0') {
+ ++this->optc;
+ q = next_word(q);
+ }
+ this->optv = calloc(this->optc + 1, sizeof(char *));
+ if (this->optv == NULL)
+ goto syserr;
+ for (i = 0; i < this->optc; ++i) {
+ if ((this->optv[i] = dup_word(p)) == NULL)
+ goto syserr;
+ p = next_word(p);
+ }
+
+ /* hook it up */
+ for (next = &pamh->chains[fclt]; *next != NULL;
+ next = &(*next)->next)
+ /* nothing */ ;
+ *next = this;
+ this = NULL;
+ ++count;
+
+ /* next please... */
+ FREE(line);
+ }
+ 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 (-1);
+}
+
+static const char *openpam_policy_path[] = {
+ "/etc/pam.d/",
+ "/etc/pam.conf",
+ "/usr/local/etc/pam.d/",
+ "/usr/local/etc/pam.conf",
+ NULL
+};
+
+/*
+ * Locates the policy file for a given service and reads the given chains
+ * from it.
+ */
+static int
+openpam_load_chain(pam_handle_t *pamh,
+ const char *service,
+ pam_facility_t facility)
+{
+ const char **path;
+ char *filename;
+ size_t len;
+ int r;
+
+ for (path = openpam_policy_path; *path != NULL; ++path) {
+ len = strlen(*path);
+ if ((*path)[len - 1] == '/') {
+ if (asprintf(&filename, "%s%s", *path, service) < 0) {
+ openpam_log(PAM_LOG_ERROR, "asprintf(): %m");
+ return (-PAM_BUF_ERR);
+ }
+ r = openpam_read_chain(pamh, service, facility,
+ filename, pam_d_style);
+ FREE(filename);
+ } else {
+ r = openpam_read_chain(pamh, service, facility,
+ *path, pam_conf_style);
+ }
+ if (r != 0)
+ return (r);
+ }
+ return (0);
+}
+
+/*
+ * OpenPAM internal
+ *
+ * Configure a service
+ */
+
+int
+openpam_configure(pam_handle_t *pamh,
+ const char *service)
+{
+ pam_facility_t fclt;
+
+ if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0)
+ goto load_err;
+
+ for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
+ if (pamh->chains[fclt] != NULL)
+ continue;
+ if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0)
+ goto load_err;
+ }
+ return (PAM_SUCCESS);
+ load_err:
+ openpam_clear_chains(pamh->chains);
+ return (PAM_SYSTEM_ERR);
+}
+
+/*
+ * NODOC
+ *
+ * Error codes:
+ * PAM_SYSTEM_ERR
+ */
OpenPOWER on IntegriCloud