1*0d9d0fd8Schristos /* $NetBSD: openpam_configure.c,v 1.5 2023/06/30 21:46:20 christos Exp $ */
2201780c4Schristos
376e8c542Schristos /*-
476e8c542Schristos * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
54cb4af11Schristos * Copyright (c) 2004-2015 Dag-Erling Smørgrav
676e8c542Schristos * All rights reserved.
776e8c542Schristos *
876e8c542Schristos * This software was developed for the FreeBSD Project by ThinkSec AS and
976e8c542Schristos * Network Associates Laboratories, the Security Research Division of
1076e8c542Schristos * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
1176e8c542Schristos * ("CBOSS"), as part of the DARPA CHATS research program.
1276e8c542Schristos *
1376e8c542Schristos * Redistribution and use in source and binary forms, with or without
1476e8c542Schristos * modification, are permitted provided that the following conditions
1576e8c542Schristos * are met:
1676e8c542Schristos * 1. Redistributions of source code must retain the above copyright
1776e8c542Schristos * notice, this list of conditions and the following disclaimer.
1876e8c542Schristos * 2. Redistributions in binary form must reproduce the above copyright
1976e8c542Schristos * notice, this list of conditions and the following disclaimer in the
2076e8c542Schristos * documentation and/or other materials provided with the distribution.
2176e8c542Schristos * 3. The name of the author may not be used to endorse or promote
2276e8c542Schristos * products derived from this software without specific prior written
2376e8c542Schristos * permission.
2476e8c542Schristos *
2576e8c542Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2676e8c542Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2776e8c542Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2876e8c542Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2976e8c542Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3076e8c542Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3176e8c542Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3276e8c542Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3376e8c542Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3476e8c542Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3576e8c542Schristos * SUCH DAMAGE.
3676e8c542Schristos */
3776e8c542Schristos
3876e8c542Schristos #ifdef HAVE_CONFIG_H
3976e8c542Schristos # include "config.h"
4076e8c542Schristos #endif
4176e8c542Schristos
42201780c4Schristos #include <sys/cdefs.h>
43*0d9d0fd8Schristos __RCSID("$NetBSD: openpam_configure.c,v 1.5 2023/06/30 21:46:20 christos Exp $");
44201780c4Schristos
4576e8c542Schristos #include <sys/param.h>
4676e8c542Schristos
4776e8c542Schristos #include <errno.h>
4876e8c542Schristos #include <stdio.h>
4976e8c542Schristos #include <stdlib.h>
5076e8c542Schristos #include <string.h>
5176e8c542Schristos
5276e8c542Schristos #include <security/pam_appl.h>
5376e8c542Schristos
5476e8c542Schristos #include "openpam_impl.h"
5576e8c542Schristos #include "openpam_ctype.h"
5676e8c542Schristos #include "openpam_strlcat.h"
5776e8c542Schristos #include "openpam_strlcpy.h"
5876e8c542Schristos
5976e8c542Schristos static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
6076e8c542Schristos
6176e8c542Schristos /*
6276e8c542Schristos * Validate a service name.
6376e8c542Schristos *
6476e8c542Schristos * Returns a non-zero value if the argument points to a NUL-terminated
6576e8c542Schristos * string consisting entirely of characters in the POSIX portable filename
6676e8c542Schristos * character set, excluding the path separator character.
6776e8c542Schristos */
6876e8c542Schristos static int
valid_service_name(const char * name)6976e8c542Schristos valid_service_name(const char *name)
7076e8c542Schristos {
7176e8c542Schristos const char *p;
7276e8c542Schristos
7376e8c542Schristos if (OPENPAM_FEATURE(RESTRICT_SERVICE_NAME)) {
7476e8c542Schristos /* path separator not allowed */
7576e8c542Schristos for (p = name; *p != '\0'; ++p)
7676e8c542Schristos if (!is_pfcs(*p))
7776e8c542Schristos return (0);
7876e8c542Schristos } else {
7976e8c542Schristos /* path separator allowed */
8076e8c542Schristos for (p = name; *p != '\0'; ++p)
8176e8c542Schristos if (!is_pfcs(*p) && *p != '/')
8276e8c542Schristos return (0);
8376e8c542Schristos }
8476e8c542Schristos return (1);
8576e8c542Schristos }
8676e8c542Schristos
8776e8c542Schristos /*
8876e8c542Schristos * Parse the facility name.
8976e8c542Schristos *
9076e8c542Schristos * Returns the corresponding pam_facility_t value, or -1 if the argument
9176e8c542Schristos * is not a valid facility name.
9276e8c542Schristos */
9376e8c542Schristos static pam_facility_t
parse_facility_name(const char * name)9476e8c542Schristos parse_facility_name(const char *name)
9576e8c542Schristos {
9676e8c542Schristos int i;
9776e8c542Schristos
9876e8c542Schristos for (i = 0; i < PAM_NUM_FACILITIES; ++i)
9976e8c542Schristos if (strcmp(pam_facility_name[i], name) == 0)
10076e8c542Schristos return (i);
10176e8c542Schristos return ((pam_facility_t)-1);
10276e8c542Schristos }
10376e8c542Schristos
10476e8c542Schristos /*
10576e8c542Schristos * Parse the control flag.
10676e8c542Schristos *
10776e8c542Schristos * Returns the corresponding pam_control_t value, or -1 if the argument is
10876e8c542Schristos * not a valid control flag name.
10976e8c542Schristos */
11076e8c542Schristos static pam_control_t
parse_control_flag(const char * name)11176e8c542Schristos parse_control_flag(const char *name)
11276e8c542Schristos {
113201780c4Schristos pam_control_t i;
11476e8c542Schristos
115201780c4Schristos for (i = PAM_BINDING; i < PAM_NUM_CONTROL_FLAGS; ++i)
11676e8c542Schristos if (strcmp(pam_control_flag_name[i], name) == 0)
11776e8c542Schristos return (i);
11876e8c542Schristos return ((pam_control_t)-1);
11976e8c542Schristos }
12076e8c542Schristos
12176e8c542Schristos /*
12276e8c542Schristos * Validate a file name.
12376e8c542Schristos *
12476e8c542Schristos * Returns a non-zero value if the argument points to a NUL-terminated
12576e8c542Schristos * string consisting entirely of characters in the POSIX portable filename
12676e8c542Schristos * character set, including the path separator character.
12776e8c542Schristos */
12876e8c542Schristos static int
valid_module_name(const char * name)12976e8c542Schristos valid_module_name(const char *name)
13076e8c542Schristos {
13176e8c542Schristos const char *p;
13276e8c542Schristos
13376e8c542Schristos if (OPENPAM_FEATURE(RESTRICT_MODULE_NAME)) {
13476e8c542Schristos /* path separator not allowed */
13576e8c542Schristos for (p = name; *p != '\0'; ++p)
13676e8c542Schristos if (!is_pfcs(*p))
13776e8c542Schristos return (0);
13876e8c542Schristos } else {
13976e8c542Schristos /* path separator allowed */
14076e8c542Schristos for (p = name; *p != '\0'; ++p)
14176e8c542Schristos if (!is_pfcs(*p) && *p != '/')
14276e8c542Schristos return (0);
14376e8c542Schristos }
14476e8c542Schristos return (1);
14576e8c542Schristos }
14676e8c542Schristos
14776e8c542Schristos typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
14876e8c542Schristos
14976e8c542Schristos /*
15076e8c542Schristos * Extracts given chains from a policy file.
15176e8c542Schristos *
15276e8c542Schristos * Returns the number of policy entries which were found for the specified
15376e8c542Schristos * service and facility, or -1 if a system error occurred or a syntax
15476e8c542Schristos * error was encountered.
15576e8c542Schristos */
15676e8c542Schristos static int
openpam_parse_chain(pam_handle_t * pamh,const char * service,pam_facility_t facility,FILE * f,const char * filename,openpam_style_t style)15776e8c542Schristos openpam_parse_chain(pam_handle_t *pamh,
15876e8c542Schristos const char *service,
15976e8c542Schristos pam_facility_t facility,
16076e8c542Schristos FILE *f,
16176e8c542Schristos const char *filename,
16276e8c542Schristos openpam_style_t style)
16376e8c542Schristos {
16476e8c542Schristos pam_chain_t *this, **next;
16576e8c542Schristos pam_facility_t fclt;
16676e8c542Schristos pam_control_t ctlf;
16776e8c542Schristos char *name, *servicename, *modulename;
16876e8c542Schristos int count, lineno, ret, serrno;
16976e8c542Schristos char **wordv, *word;
17076e8c542Schristos int i, wordc;
17176e8c542Schristos
17276e8c542Schristos count = 0;
17376e8c542Schristos this = NULL;
17476e8c542Schristos name = NULL;
17576e8c542Schristos lineno = 0;
17676e8c542Schristos wordc = 0;
17776e8c542Schristos wordv = NULL;
17876e8c542Schristos while ((wordv = openpam_readlinev(f, &lineno, &wordc)) != NULL) {
17976e8c542Schristos /* blank line? */
18076e8c542Schristos if (wordc == 0) {
18176e8c542Schristos FREEV(wordc, wordv);
18276e8c542Schristos continue;
18376e8c542Schristos }
18476e8c542Schristos i = 0;
18576e8c542Schristos
18676e8c542Schristos /* check service name if necessary */
18776e8c542Schristos if (style == pam_conf_style &&
18876e8c542Schristos strcmp(wordv[i++], service) != 0) {
18976e8c542Schristos FREEV(wordc, wordv);
19076e8c542Schristos continue;
19176e8c542Schristos }
19276e8c542Schristos
19376e8c542Schristos /* check facility name */
19476e8c542Schristos if ((word = wordv[i++]) == NULL ||
19576e8c542Schristos (fclt = parse_facility_name(word)) == (pam_facility_t)-1) {
19676e8c542Schristos openpam_log(PAM_LOG_ERROR,
19776e8c542Schristos "%s(%d): missing or invalid facility",
19876e8c542Schristos filename, lineno);
19976e8c542Schristos errno = EINVAL;
20076e8c542Schristos goto fail;
20176e8c542Schristos }
20276e8c542Schristos if (facility != fclt && facility != PAM_FACILITY_ANY) {
20376e8c542Schristos FREEV(wordc, wordv);
20476e8c542Schristos continue;
20576e8c542Schristos }
20676e8c542Schristos
20776e8c542Schristos /* check for "include" */
20876e8c542Schristos if ((word = wordv[i++]) != NULL &&
20976e8c542Schristos strcmp(word, "include") == 0) {
21076e8c542Schristos if ((servicename = wordv[i++]) == NULL ||
21176e8c542Schristos !valid_service_name(servicename)) {
21276e8c542Schristos openpam_log(PAM_LOG_ERROR,
21376e8c542Schristos "%s(%d): missing or invalid service name",
21476e8c542Schristos filename, lineno);
21576e8c542Schristos errno = EINVAL;
21676e8c542Schristos goto fail;
21776e8c542Schristos }
21876e8c542Schristos if (wordv[i] != NULL) {
21976e8c542Schristos openpam_log(PAM_LOG_ERROR,
22076e8c542Schristos "%s(%d): garbage at end of line",
22176e8c542Schristos filename, lineno);
22276e8c542Schristos errno = EINVAL;
22376e8c542Schristos goto fail;
22476e8c542Schristos }
22576e8c542Schristos ret = openpam_load_chain(pamh, servicename, fclt);
22676e8c542Schristos FREEV(wordc, wordv);
22776e8c542Schristos if (ret < 0) {
22876e8c542Schristos /*
22976e8c542Schristos * Bogus errno, but this ensures that the
23076e8c542Schristos * outer loop does not just ignore the
23176e8c542Schristos * error and keep searching.
23276e8c542Schristos */
23376e8c542Schristos if (errno == ENOENT)
23476e8c542Schristos errno = EINVAL;
23576e8c542Schristos goto fail;
23676e8c542Schristos }
23776e8c542Schristos continue;
23876e8c542Schristos }
23976e8c542Schristos
24076e8c542Schristos /* get control flag */
24176e8c542Schristos if (word == NULL || /* same word we compared to "include" */
24276e8c542Schristos (ctlf = parse_control_flag(word)) == (pam_control_t)-1) {
24376e8c542Schristos openpam_log(PAM_LOG_ERROR,
24476e8c542Schristos "%s(%d): missing or invalid control flag",
24576e8c542Schristos filename, lineno);
24676e8c542Schristos errno = EINVAL;
24776e8c542Schristos goto fail;
24876e8c542Schristos }
24976e8c542Schristos
25076e8c542Schristos /* get module name */
25176e8c542Schristos if ((modulename = wordv[i++]) == NULL ||
25276e8c542Schristos !valid_module_name(modulename)) {
25376e8c542Schristos openpam_log(PAM_LOG_ERROR,
25476e8c542Schristos "%s(%d): missing or invalid module name",
25576e8c542Schristos filename, lineno);
25676e8c542Schristos errno = EINVAL;
25776e8c542Schristos goto fail;
25876e8c542Schristos }
25976e8c542Schristos
26076e8c542Schristos /* allocate new entry */
261201780c4Schristos if ((this = calloc((size_t)1, sizeof *this)) == NULL)
26276e8c542Schristos goto syserr;
263da40fa17Sjoerg this->flag = (int)ctlf;
26476e8c542Schristos
26576e8c542Schristos /* load module */
26676e8c542Schristos if ((this->module = openpam_load_module(modulename)) == NULL) {
26776e8c542Schristos if (errno == ENOENT)
26876e8c542Schristos errno = ENOEXEC;
26976e8c542Schristos goto fail;
27076e8c542Schristos }
27176e8c542Schristos
27276e8c542Schristos /*
27376e8c542Schristos * The remaining items in wordv are the module's
27476e8c542Schristos * arguments. We could set this->optv = wordv + i, but
27576e8c542Schristos * then free(this->optv) wouldn't work. Instead, we free
27676e8c542Schristos * the words we've already consumed, shift the rest up,
27776e8c542Schristos * and clear the tail end of the array.
27876e8c542Schristos */
27976e8c542Schristos this->optc = wordc - i;
28076e8c542Schristos for (i = 0; i < wordc - this->optc; ++i) {
28176e8c542Schristos FREE(wordv[i]);
28276e8c542Schristos }
28376e8c542Schristos for (i = 0; i < this->optc; ++i) {
28476e8c542Schristos wordv[i] = wordv[wordc - this->optc + i];
28576e8c542Schristos wordv[wordc - this->optc + i] = NULL;
28676e8c542Schristos }
28776e8c542Schristos this->optv = wordv;
28876e8c542Schristos wordv = NULL;
28976e8c542Schristos wordc = 0;
29076e8c542Schristos
29176e8c542Schristos /* hook it up */
29276e8c542Schristos for (next = &pamh->chains[fclt]; *next != NULL;
29376e8c542Schristos next = &(*next)->next)
29476e8c542Schristos /* nothing */ ;
29576e8c542Schristos *next = this;
29676e8c542Schristos this = NULL;
29776e8c542Schristos ++count;
29876e8c542Schristos }
29976e8c542Schristos /*
30076e8c542Schristos * The loop ended because openpam_readword() returned NULL, which
30176e8c542Schristos * can happen for four different reasons: an I/O error (ferror(f)
30276e8c542Schristos * is true), a memory allocation failure (ferror(f) is false,
30376e8c542Schristos * feof(f) is false, errno is non-zero), the file ended with an
30476e8c542Schristos * unterminated quote or backslash escape (ferror(f) is false,
30576e8c542Schristos * feof(f) is true, errno is non-zero), or the end of the file was
30676e8c542Schristos * reached without error (ferror(f) is false, feof(f) is true,
30776e8c542Schristos * errno is zero).
30876e8c542Schristos */
30976e8c542Schristos if (ferror(f) || errno != 0)
31076e8c542Schristos goto syserr;
31176e8c542Schristos if (!feof(f))
31276e8c542Schristos goto fail;
31376e8c542Schristos fclose(f);
31476e8c542Schristos return (count);
31576e8c542Schristos syserr:
31676e8c542Schristos serrno = errno;
31776e8c542Schristos openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
31876e8c542Schristos errno = serrno;
31976e8c542Schristos /* fall through */
32076e8c542Schristos fail:
32176e8c542Schristos serrno = errno;
32276e8c542Schristos if (this && this->optc && this->optv)
32376e8c542Schristos FREEV(this->optc, this->optv);
32476e8c542Schristos FREE(this);
32576e8c542Schristos FREEV(wordc, wordv);
32676e8c542Schristos FREE(wordv);
32776e8c542Schristos FREE(name);
32876e8c542Schristos fclose(f);
32976e8c542Schristos errno = serrno;
33076e8c542Schristos return (-1);
33176e8c542Schristos }
33276e8c542Schristos
33376e8c542Schristos /*
33476e8c542Schristos * Read the specified chains from the specified file.
33576e8c542Schristos *
33676e8c542Schristos * Returns 0 if the file exists but does not contain any matching lines.
33776e8c542Schristos *
33876e8c542Schristos * Returns -1 and sets errno to ENOENT if the file does not exist.
33976e8c542Schristos *
34076e8c542Schristos * Returns -1 and sets errno to some other non-zero value if the file
34176e8c542Schristos * exists but is unsafe or unreadable, or an I/O error occurs.
34276e8c542Schristos */
34376e8c542Schristos static int
openpam_load_file(pam_handle_t * pamh,const char * service,pam_facility_t facility,const char * filename,openpam_style_t style)34476e8c542Schristos openpam_load_file(pam_handle_t *pamh,
34576e8c542Schristos const char *service,
34676e8c542Schristos pam_facility_t facility,
34776e8c542Schristos const char *filename,
34876e8c542Schristos openpam_style_t style)
34976e8c542Schristos {
35076e8c542Schristos FILE *f;
35176e8c542Schristos int ret, serrno;
35276e8c542Schristos
35376e8c542Schristos /* attempt to open the file */
35476e8c542Schristos if ((f = fopen(filename, "r")) == NULL) {
35576e8c542Schristos serrno = errno;
35676e8c542Schristos openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR,
35776e8c542Schristos "%s: %m", filename);
35876e8c542Schristos errno = serrno;
35976e8c542Schristos RETURNN(-1);
36076e8c542Schristos } else {
36176e8c542Schristos openpam_log(PAM_LOG_DEBUG, "found %s", filename);
36276e8c542Schristos }
36376e8c542Schristos
36476e8c542Schristos /* verify type, ownership and permissions */
36576e8c542Schristos if (OPENPAM_FEATURE(VERIFY_POLICY_FILE) &&
36676e8c542Schristos openpam_check_desc_owner_perms(filename, fileno(f)) != 0) {
36776e8c542Schristos /* already logged the cause */
36876e8c542Schristos serrno = errno;
36976e8c542Schristos fclose(f);
37076e8c542Schristos errno = serrno;
37176e8c542Schristos RETURNN(-1);
37276e8c542Schristos }
37376e8c542Schristos
37476e8c542Schristos /* parse the file */
37576e8c542Schristos ret = openpam_parse_chain(pamh, service, facility,
37676e8c542Schristos f, filename, style);
37776e8c542Schristos RETURNN(ret);
37876e8c542Schristos }
37976e8c542Schristos
38076e8c542Schristos /*
38176e8c542Schristos * Locates the policy file for a given service and reads the given chains
38276e8c542Schristos * from it.
38376e8c542Schristos *
38476e8c542Schristos * Returns the number of policy entries which were found for the specified
38576e8c542Schristos * service and facility, or -1 if a system error occurred or a syntax
38676e8c542Schristos * error was encountered.
38776e8c542Schristos */
38876e8c542Schristos static int
openpam_load_chain(pam_handle_t * pamh,const char * service,pam_facility_t facility)38976e8c542Schristos openpam_load_chain(pam_handle_t *pamh,
39076e8c542Schristos const char *service,
39176e8c542Schristos pam_facility_t facility)
39276e8c542Schristos {
39376e8c542Schristos const char *p, **path;
39476e8c542Schristos char filename[PATH_MAX];
39576e8c542Schristos size_t len;
39676e8c542Schristos openpam_style_t style;
39776e8c542Schristos int ret;
39876e8c542Schristos
39976e8c542Schristos ENTERS(facility < 0 ? "any" : pam_facility_name[facility]);
40076e8c542Schristos
40176e8c542Schristos /* either absolute or relative to cwd */
40276e8c542Schristos if (strchr(service, '/') != NULL) {
40376e8c542Schristos if ((p = strrchr(service, '.')) != NULL && strcmp(p, ".conf") == 0)
40476e8c542Schristos style = pam_conf_style;
40576e8c542Schristos else
40676e8c542Schristos style = pam_d_style;
40776e8c542Schristos ret = openpam_load_file(pamh, service, facility,
40876e8c542Schristos service, style);
40976e8c542Schristos RETURNN(ret);
41076e8c542Schristos }
41176e8c542Schristos
41276e8c542Schristos /* search standard locations */
41376e8c542Schristos for (path = openpam_policy_path; *path != NULL; ++path) {
41476e8c542Schristos /* construct filename */
41576e8c542Schristos len = strlcpy(filename, *path, sizeof filename);
4164cb4af11Schristos if (len >= sizeof filename) {
4174cb4af11Schristos errno = ENAMETOOLONG;
4184cb4af11Schristos RETURNN(-1);
4194cb4af11Schristos }
42076e8c542Schristos if (filename[len - 1] == '/') {
42176e8c542Schristos len = strlcat(filename, service, sizeof filename);
42276e8c542Schristos if (len >= sizeof filename) {
42376e8c542Schristos errno = ENAMETOOLONG;
42476e8c542Schristos RETURNN(-1);
42576e8c542Schristos }
42676e8c542Schristos style = pam_d_style;
42776e8c542Schristos } else {
42876e8c542Schristos style = pam_conf_style;
42976e8c542Schristos }
43076e8c542Schristos ret = openpam_load_file(pamh, service, facility,
43176e8c542Schristos filename, style);
43276e8c542Schristos /* success */
43376e8c542Schristos if (ret > 0)
43476e8c542Schristos RETURNN(ret);
43576e8c542Schristos /* the file exists, but an error occurred */
43676e8c542Schristos if (ret == -1 && errno != ENOENT)
43776e8c542Schristos RETURNN(ret);
43876e8c542Schristos /* in pam.d style, an empty file counts as a hit */
43976e8c542Schristos if (ret == 0 && style == pam_d_style)
44076e8c542Schristos RETURNN(ret);
44176e8c542Schristos }
44276e8c542Schristos
44376e8c542Schristos /* no hit */
44476e8c542Schristos errno = ENOENT;
44576e8c542Schristos RETURNN(-1);
44676e8c542Schristos }
44776e8c542Schristos
44876e8c542Schristos /*
44976e8c542Schristos * OpenPAM internal
45076e8c542Schristos *
45176e8c542Schristos * Configure a service
45276e8c542Schristos */
45376e8c542Schristos
45476e8c542Schristos int
openpam_configure(pam_handle_t * pamh,const char * service)45576e8c542Schristos openpam_configure(pam_handle_t *pamh,
45676e8c542Schristos const char *service)
45776e8c542Schristos {
45876e8c542Schristos pam_facility_t fclt;
45976e8c542Schristos int serrno;
46076e8c542Schristos
46176e8c542Schristos ENTERS(service);
46276e8c542Schristos if (!valid_service_name(service)) {
46376e8c542Schristos openpam_log(PAM_LOG_ERROR, "invalid service name");
46476e8c542Schristos RETURNC(PAM_SYSTEM_ERR);
46576e8c542Schristos }
46676e8c542Schristos if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) {
46776e8c542Schristos if (errno != ENOENT)
46876e8c542Schristos goto load_err;
46976e8c542Schristos }
47076e8c542Schristos for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
47176e8c542Schristos if (pamh->chains[fclt] != NULL)
47276e8c542Schristos continue;
4734cb4af11Schristos if (OPENPAM_FEATURE(FALLBACK_TO_OTHER)) {
47476e8c542Schristos if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0)
47576e8c542Schristos goto load_err;
47676e8c542Schristos }
4774cb4af11Schristos }
478201780c4Schristos #ifdef __NetBSD__
479201780c4Schristos /*
480201780c4Schristos * On NetBSD we require the AUTH chain to have a binding,
481201780c4Schristos * a required, or requisite module.
482201780c4Schristos */
483201780c4Schristos {
484201780c4Schristos pam_chain_t *this = pamh->chains[PAM_AUTH];
485201780c4Schristos for (; this != NULL; this = this->next)
486201780c4Schristos if (this->flag == PAM_BINDING ||
487201780c4Schristos this->flag == PAM_REQUIRED ||
488201780c4Schristos this->flag == PAM_REQUISITE)
489201780c4Schristos break;
490201780c4Schristos if (this == NULL) {
491201780c4Schristos openpam_log(PAM_LOG_ERROR,
492201780c4Schristos "No required, requisite, or binding component "
493201780c4Schristos "in service %s, facility %s",
494201780c4Schristos service, pam_facility_name[PAM_AUTH]);
495201780c4Schristos goto load_err;
496201780c4Schristos }
497201780c4Schristos }
498201780c4Schristos #endif
49976e8c542Schristos RETURNC(PAM_SUCCESS);
50076e8c542Schristos load_err:
50176e8c542Schristos serrno = errno;
50276e8c542Schristos openpam_clear_chains(pamh->chains);
50376e8c542Schristos errno = serrno;
50476e8c542Schristos RETURNC(PAM_SYSTEM_ERR);
50576e8c542Schristos }
50676e8c542Schristos
50776e8c542Schristos /*
50876e8c542Schristos * NODOC
50976e8c542Schristos *
51076e8c542Schristos * Error codes:
51176e8c542Schristos * PAM_SYSTEM_ERR
51276e8c542Schristos */
513