xref: /dflybsd-src/contrib/openpam/lib/libpam/openpam_configure.c (revision 29d19636ae9cd697677888037274b010470f879c)
110b5fe87SSascha Wildner /*-
210b5fe87SSascha Wildner  * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
310b5fe87SSascha Wildner  * Copyright (c) 2004-2015 Dag-Erling Smørgrav
410b5fe87SSascha Wildner  * All rights reserved.
510b5fe87SSascha Wildner  *
610b5fe87SSascha Wildner  * This software was developed for the FreeBSD Project by ThinkSec AS and
710b5fe87SSascha Wildner  * Network Associates Laboratories, the Security Research Division of
810b5fe87SSascha Wildner  * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
910b5fe87SSascha Wildner  * ("CBOSS"), as part of the DARPA CHATS research program.
1010b5fe87SSascha Wildner  *
1110b5fe87SSascha Wildner  * Redistribution and use in source and binary forms, with or without
1210b5fe87SSascha Wildner  * modification, are permitted provided that the following conditions
1310b5fe87SSascha Wildner  * are met:
1410b5fe87SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
1510b5fe87SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
1610b5fe87SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
1710b5fe87SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
1810b5fe87SSascha Wildner  *    documentation and/or other materials provided with the distribution.
1910b5fe87SSascha Wildner  * 3. The name of the author may not be used to endorse or promote
2010b5fe87SSascha Wildner  *    products derived from this software without specific prior written
2110b5fe87SSascha Wildner  *    permission.
2210b5fe87SSascha Wildner  *
2310b5fe87SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2410b5fe87SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2510b5fe87SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2610b5fe87SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2710b5fe87SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2810b5fe87SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2910b5fe87SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3010b5fe87SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3110b5fe87SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3210b5fe87SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3310b5fe87SSascha Wildner  * SUCH DAMAGE.
3410b5fe87SSascha Wildner  *
3510b5fe87SSascha Wildner  * $OpenPAM: openpam_configure.c 938 2017-04-30 21:34:42Z des $
3610b5fe87SSascha Wildner  */
3710b5fe87SSascha Wildner 
3810b5fe87SSascha Wildner #ifdef HAVE_CONFIG_H
3910b5fe87SSascha Wildner # include "config.h"
4010b5fe87SSascha Wildner #endif
4110b5fe87SSascha Wildner 
4210b5fe87SSascha Wildner #include <sys/param.h>
4310b5fe87SSascha Wildner 
4410b5fe87SSascha Wildner #include <errno.h>
4510b5fe87SSascha Wildner #include <stdio.h>
4610b5fe87SSascha Wildner #include <stdlib.h>
4710b5fe87SSascha Wildner #include <string.h>
4810b5fe87SSascha Wildner 
4910b5fe87SSascha Wildner #include <security/pam_appl.h>
5010b5fe87SSascha Wildner 
5110b5fe87SSascha Wildner #include "openpam_impl.h"
5210b5fe87SSascha Wildner #include "openpam_ctype.h"
5310b5fe87SSascha Wildner #include "openpam_strlcat.h"
5410b5fe87SSascha Wildner #include "openpam_strlcpy.h"
5510b5fe87SSascha Wildner 
5610b5fe87SSascha Wildner static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
5710b5fe87SSascha Wildner 
5810b5fe87SSascha Wildner /*
5910b5fe87SSascha Wildner  * Validate a service name.
6010b5fe87SSascha Wildner  *
6110b5fe87SSascha Wildner  * Returns a non-zero value if the argument points to a NUL-terminated
6210b5fe87SSascha Wildner  * string consisting entirely of characters in the POSIX portable filename
6310b5fe87SSascha Wildner  * character set, excluding the path separator character.
6410b5fe87SSascha Wildner  */
6510b5fe87SSascha Wildner static int
valid_service_name(const char * name)6610b5fe87SSascha Wildner valid_service_name(const char *name)
6710b5fe87SSascha Wildner {
6810b5fe87SSascha Wildner 	const char *p;
6910b5fe87SSascha Wildner 
7010b5fe87SSascha Wildner 	if (OPENPAM_FEATURE(RESTRICT_SERVICE_NAME)) {
7110b5fe87SSascha Wildner 		/* path separator not allowed */
7210b5fe87SSascha Wildner 		for (p = name; *p != '\0'; ++p)
7310b5fe87SSascha Wildner 			if (!is_pfcs(*p))
7410b5fe87SSascha Wildner 				return (0);
7510b5fe87SSascha Wildner 	} else {
7610b5fe87SSascha Wildner 		/* path separator allowed */
7710b5fe87SSascha Wildner 		for (p = name; *p != '\0'; ++p)
7810b5fe87SSascha Wildner 			if (!is_pfcs(*p) && *p != '/')
7910b5fe87SSascha Wildner 				return (0);
8010b5fe87SSascha Wildner 	}
8110b5fe87SSascha Wildner 	return (1);
8210b5fe87SSascha Wildner }
8310b5fe87SSascha Wildner 
8410b5fe87SSascha Wildner /*
8510b5fe87SSascha Wildner  * Parse the facility name.
8610b5fe87SSascha Wildner  *
8710b5fe87SSascha Wildner  * Returns the corresponding pam_facility_t value, or -1 if the argument
8810b5fe87SSascha Wildner  * is not a valid facility name.
8910b5fe87SSascha Wildner  */
9010b5fe87SSascha Wildner static pam_facility_t
parse_facility_name(const char * name)9110b5fe87SSascha Wildner parse_facility_name(const char *name)
9210b5fe87SSascha Wildner {
9310b5fe87SSascha Wildner 	int i;
9410b5fe87SSascha Wildner 
9510b5fe87SSascha Wildner 	for (i = 0; i < PAM_NUM_FACILITIES; ++i)
9610b5fe87SSascha Wildner 		if (strcmp(pam_facility_name[i], name) == 0)
9710b5fe87SSascha Wildner 			return (i);
9810b5fe87SSascha Wildner 	return ((pam_facility_t)-1);
9910b5fe87SSascha Wildner }
10010b5fe87SSascha Wildner 
10110b5fe87SSascha Wildner /*
10210b5fe87SSascha Wildner  * Parse the control flag.
10310b5fe87SSascha Wildner  *
10410b5fe87SSascha Wildner  * Returns the corresponding pam_control_t value, or -1 if the argument is
10510b5fe87SSascha Wildner  * not a valid control flag name.
10610b5fe87SSascha Wildner  */
10710b5fe87SSascha Wildner static pam_control_t
parse_control_flag(const char * name)10810b5fe87SSascha Wildner parse_control_flag(const char *name)
10910b5fe87SSascha Wildner {
11010b5fe87SSascha Wildner 	int i;
11110b5fe87SSascha Wildner 
11210b5fe87SSascha Wildner 	for (i = 0; i < PAM_NUM_CONTROL_FLAGS; ++i)
11310b5fe87SSascha Wildner 		if (strcmp(pam_control_flag_name[i], name) == 0)
11410b5fe87SSascha Wildner 			return (i);
11510b5fe87SSascha Wildner 	return ((pam_control_t)-1);
11610b5fe87SSascha Wildner }
11710b5fe87SSascha Wildner 
11810b5fe87SSascha Wildner /*
11910b5fe87SSascha Wildner  * Validate a file name.
12010b5fe87SSascha Wildner  *
12110b5fe87SSascha Wildner  * Returns a non-zero value if the argument points to a NUL-terminated
12210b5fe87SSascha Wildner  * string consisting entirely of characters in the POSIX portable filename
12310b5fe87SSascha Wildner  * character set, including the path separator character.
12410b5fe87SSascha Wildner  */
12510b5fe87SSascha Wildner static int
valid_module_name(const char * name)12610b5fe87SSascha Wildner valid_module_name(const char *name)
12710b5fe87SSascha Wildner {
12810b5fe87SSascha Wildner 	const char *p;
12910b5fe87SSascha Wildner 
13010b5fe87SSascha Wildner 	if (OPENPAM_FEATURE(RESTRICT_MODULE_NAME)) {
13110b5fe87SSascha Wildner 		/* path separator not allowed */
13210b5fe87SSascha Wildner 		for (p = name; *p != '\0'; ++p)
13310b5fe87SSascha Wildner 			if (!is_pfcs(*p))
13410b5fe87SSascha Wildner 				return (0);
13510b5fe87SSascha Wildner 	} else {
13610b5fe87SSascha Wildner 		/* path separator allowed */
13710b5fe87SSascha Wildner 		for (p = name; *p != '\0'; ++p)
13810b5fe87SSascha Wildner 			if (!is_pfcs(*p) && *p != '/')
13910b5fe87SSascha Wildner 				return (0);
14010b5fe87SSascha Wildner 	}
14110b5fe87SSascha Wildner 	return (1);
14210b5fe87SSascha Wildner }
14310b5fe87SSascha Wildner 
14410b5fe87SSascha Wildner typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
14510b5fe87SSascha Wildner 
14610b5fe87SSascha Wildner /*
14710b5fe87SSascha Wildner  * Extracts given chains from a policy file.
14810b5fe87SSascha Wildner  *
14910b5fe87SSascha Wildner  * Returns the number of policy entries which were found for the specified
15010b5fe87SSascha Wildner  * service and facility, or -1 if a system error occurred or a syntax
15110b5fe87SSascha Wildner  * error was encountered.
15210b5fe87SSascha Wildner  */
15310b5fe87SSascha Wildner 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)15410b5fe87SSascha Wildner openpam_parse_chain(pam_handle_t *pamh,
15510b5fe87SSascha Wildner 	const char *service,
15610b5fe87SSascha Wildner 	pam_facility_t facility,
15710b5fe87SSascha Wildner 	FILE *f,
15810b5fe87SSascha Wildner 	const char *filename,
15910b5fe87SSascha Wildner 	openpam_style_t style)
16010b5fe87SSascha Wildner {
16110b5fe87SSascha Wildner 	pam_chain_t *this, **next;
16210b5fe87SSascha Wildner 	pam_facility_t fclt;
16310b5fe87SSascha Wildner 	pam_control_t ctlf;
16410b5fe87SSascha Wildner 	char *name, *servicename, *modulename;
16510b5fe87SSascha Wildner 	int count, lineno, ret, serrno;
16610b5fe87SSascha Wildner 	char **wordv, *word;
16710b5fe87SSascha Wildner 	int i, wordc;
16810b5fe87SSascha Wildner 
16910b5fe87SSascha Wildner 	count = 0;
17010b5fe87SSascha Wildner 	this = NULL;
17110b5fe87SSascha Wildner 	name = NULL;
17210b5fe87SSascha Wildner 	lineno = 0;
17310b5fe87SSascha Wildner 	wordc = 0;
17410b5fe87SSascha Wildner 	wordv = NULL;
17510b5fe87SSascha Wildner 	while ((wordv = openpam_readlinev(f, &lineno, &wordc)) != NULL) {
17610b5fe87SSascha Wildner 		/* blank line? */
17710b5fe87SSascha Wildner 		if (wordc == 0) {
17810b5fe87SSascha Wildner 			FREEV(wordc, wordv);
17910b5fe87SSascha Wildner 			continue;
18010b5fe87SSascha Wildner 		}
18110b5fe87SSascha Wildner 		i = 0;
18210b5fe87SSascha Wildner 
18310b5fe87SSascha Wildner 		/* check service name if necessary */
18410b5fe87SSascha Wildner 		if (style == pam_conf_style &&
18510b5fe87SSascha Wildner 		    strcmp(wordv[i++], service) != 0) {
18610b5fe87SSascha Wildner 			FREEV(wordc, wordv);
18710b5fe87SSascha Wildner 			continue;
18810b5fe87SSascha Wildner 		}
18910b5fe87SSascha Wildner 
19010b5fe87SSascha Wildner 		/* check facility name */
19110b5fe87SSascha Wildner 		if ((word = wordv[i++]) == NULL ||
19210b5fe87SSascha Wildner 		    (fclt = parse_facility_name(word)) == (pam_facility_t)-1) {
19310b5fe87SSascha Wildner 			openpam_log(PAM_LOG_ERROR,
19410b5fe87SSascha Wildner 			    "%s(%d): missing or invalid facility",
19510b5fe87SSascha Wildner 			    filename, lineno);
19610b5fe87SSascha Wildner 			errno = EINVAL;
19710b5fe87SSascha Wildner 			goto fail;
19810b5fe87SSascha Wildner 		}
19910b5fe87SSascha Wildner 		if (facility != fclt && facility != PAM_FACILITY_ANY) {
20010b5fe87SSascha Wildner 			FREEV(wordc, wordv);
20110b5fe87SSascha Wildner 			continue;
20210b5fe87SSascha Wildner 		}
20310b5fe87SSascha Wildner 
20410b5fe87SSascha Wildner 		/* check for "include" */
20510b5fe87SSascha Wildner 		if ((word = wordv[i++]) != NULL &&
20610b5fe87SSascha Wildner 		    strcmp(word, "include") == 0) {
20710b5fe87SSascha Wildner 			if ((servicename = wordv[i++]) == NULL ||
20810b5fe87SSascha Wildner 			    !valid_service_name(servicename)) {
20910b5fe87SSascha Wildner 				openpam_log(PAM_LOG_ERROR,
21010b5fe87SSascha Wildner 				    "%s(%d): missing or invalid service name",
21110b5fe87SSascha Wildner 				    filename, lineno);
21210b5fe87SSascha Wildner 				errno = EINVAL;
21310b5fe87SSascha Wildner 				goto fail;
21410b5fe87SSascha Wildner 			}
21510b5fe87SSascha Wildner 			if (wordv[i] != NULL) {
21610b5fe87SSascha Wildner 				openpam_log(PAM_LOG_ERROR,
21710b5fe87SSascha Wildner 				    "%s(%d): garbage at end of line",
21810b5fe87SSascha Wildner 				    filename, lineno);
21910b5fe87SSascha Wildner 				errno = EINVAL;
22010b5fe87SSascha Wildner 				goto fail;
22110b5fe87SSascha Wildner 			}
22210b5fe87SSascha Wildner 			ret = openpam_load_chain(pamh, servicename, fclt);
22310b5fe87SSascha Wildner 			FREEV(wordc, wordv);
22410b5fe87SSascha Wildner 			if (ret < 0) {
22510b5fe87SSascha Wildner 				/*
22610b5fe87SSascha Wildner 				 * Bogus errno, but this ensures that the
22710b5fe87SSascha Wildner 				 * outer loop does not just ignore the
22810b5fe87SSascha Wildner 				 * error and keep searching.
22910b5fe87SSascha Wildner 				 */
23010b5fe87SSascha Wildner 				if (errno == ENOENT)
23110b5fe87SSascha Wildner 					errno = EINVAL;
23210b5fe87SSascha Wildner 				goto fail;
23310b5fe87SSascha Wildner 			}
23410b5fe87SSascha Wildner 			continue;
23510b5fe87SSascha Wildner 		}
23610b5fe87SSascha Wildner 
23710b5fe87SSascha Wildner 		/* get control flag */
23810b5fe87SSascha Wildner 		if (word == NULL || /* same word we compared to "include" */
23910b5fe87SSascha Wildner 		    (ctlf = parse_control_flag(word)) == (pam_control_t)-1) {
24010b5fe87SSascha Wildner 			openpam_log(PAM_LOG_ERROR,
24110b5fe87SSascha Wildner 			    "%s(%d): missing or invalid control flag",
24210b5fe87SSascha Wildner 			    filename, lineno);
24310b5fe87SSascha Wildner 			errno = EINVAL;
24410b5fe87SSascha Wildner 			goto fail;
24510b5fe87SSascha Wildner 		}
24610b5fe87SSascha Wildner 
24710b5fe87SSascha Wildner 		/* get module name */
24810b5fe87SSascha Wildner 		if ((modulename = wordv[i++]) == NULL ||
24910b5fe87SSascha Wildner 		    !valid_module_name(modulename)) {
25010b5fe87SSascha Wildner 			openpam_log(PAM_LOG_ERROR,
25110b5fe87SSascha Wildner 			    "%s(%d): missing or invalid module name",
25210b5fe87SSascha Wildner 			    filename, lineno);
25310b5fe87SSascha Wildner 			errno = EINVAL;
25410b5fe87SSascha Wildner 			goto fail;
25510b5fe87SSascha Wildner 		}
25610b5fe87SSascha Wildner 
257*29d19636Szrj 		/*
258*29d19636Szrj 		 * Check if blacklisted.  Legacy support for removed previously
259*29d19636Szrj 		 * enabled modules only.
260*29d19636Szrj 		 */
261*29d19636Szrj 		if ((strcmp(modulename, "pam_opie.so") == 0) ||
262*29d19636Szrj 		    (strcmp(modulename, "pam_opieaccess.so") == 0)) {
263*29d19636Szrj 			openpam_log(PAM_LOG_ERROR,
264*29d19636Szrj 			    "ignoring blacklisted %s module,"
265*29d19636Szrj 			    " update your /etc/pam.d/ configs",
266*29d19636Szrj 			    modulename);
267*29d19636Szrj 			FREEV(wordc, wordv);
268*29d19636Szrj 			continue;
269*29d19636Szrj 		}
270*29d19636Szrj 
27110b5fe87SSascha Wildner 		/* allocate new entry */
27210b5fe87SSascha Wildner 		if ((this = calloc(1, sizeof *this)) == NULL)
27310b5fe87SSascha Wildner 			goto syserr;
27410b5fe87SSascha Wildner 		this->flag = ctlf;
27510b5fe87SSascha Wildner 
27610b5fe87SSascha Wildner 		/* load module */
27710b5fe87SSascha Wildner 		if ((this->module = openpam_load_module(modulename)) == NULL) {
27810b5fe87SSascha Wildner 			if (errno == ENOENT)
27910b5fe87SSascha Wildner 				errno = ENOEXEC;
28010b5fe87SSascha Wildner 			goto fail;
28110b5fe87SSascha Wildner 		}
28210b5fe87SSascha Wildner 
28310b5fe87SSascha Wildner 		/*
28410b5fe87SSascha Wildner 		 * The remaining items in wordv are the module's
28510b5fe87SSascha Wildner 		 * arguments.  We could set this->optv = wordv + i, but
28610b5fe87SSascha Wildner 		 * then free(this->optv) wouldn't work.  Instead, we free
28710b5fe87SSascha Wildner 		 * the words we've already consumed, shift the rest up,
28810b5fe87SSascha Wildner 		 * and clear the tail end of the array.
28910b5fe87SSascha Wildner 		 */
29010b5fe87SSascha Wildner 		this->optc = wordc - i;
29110b5fe87SSascha Wildner 		for (i = 0; i < wordc - this->optc; ++i) {
29210b5fe87SSascha Wildner 			FREE(wordv[i]);
29310b5fe87SSascha Wildner 		}
29410b5fe87SSascha Wildner 		for (i = 0; i < this->optc; ++i) {
29510b5fe87SSascha Wildner 			wordv[i] = wordv[wordc - this->optc + i];
29610b5fe87SSascha Wildner 			wordv[wordc - this->optc + i] = NULL;
29710b5fe87SSascha Wildner 		}
29810b5fe87SSascha Wildner 		this->optv = wordv;
29910b5fe87SSascha Wildner 		wordv = NULL;
30010b5fe87SSascha Wildner 		wordc = 0;
30110b5fe87SSascha Wildner 
30210b5fe87SSascha Wildner 		/* hook it up */
30310b5fe87SSascha Wildner 		for (next = &pamh->chains[fclt]; *next != NULL;
30410b5fe87SSascha Wildner 		     next = &(*next)->next)
30510b5fe87SSascha Wildner 			/* nothing */ ;
30610b5fe87SSascha Wildner 		*next = this;
30710b5fe87SSascha Wildner 		this = NULL;
30810b5fe87SSascha Wildner 		++count;
30910b5fe87SSascha Wildner 	}
31010b5fe87SSascha Wildner 	/*
31110b5fe87SSascha Wildner 	 * The loop ended because openpam_readword() returned NULL, which
31210b5fe87SSascha Wildner 	 * can happen for four different reasons: an I/O error (ferror(f)
31310b5fe87SSascha Wildner 	 * is true), a memory allocation failure (ferror(f) is false,
31410b5fe87SSascha Wildner 	 * feof(f) is false, errno is non-zero), the file ended with an
31510b5fe87SSascha Wildner 	 * unterminated quote or backslash escape (ferror(f) is false,
31610b5fe87SSascha Wildner 	 * feof(f) is true, errno is non-zero), or the end of the file was
31710b5fe87SSascha Wildner 	 * reached without error (ferror(f) is false, feof(f) is true,
31810b5fe87SSascha Wildner 	 * errno is zero).
31910b5fe87SSascha Wildner 	 */
32010b5fe87SSascha Wildner 	if (ferror(f) || errno != 0)
32110b5fe87SSascha Wildner 		goto syserr;
32210b5fe87SSascha Wildner 	if (!feof(f))
32310b5fe87SSascha Wildner 		goto fail;
32410b5fe87SSascha Wildner 	fclose(f);
32510b5fe87SSascha Wildner 	return (count);
32610b5fe87SSascha Wildner syserr:
32710b5fe87SSascha Wildner 	serrno = errno;
32810b5fe87SSascha Wildner 	openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
32910b5fe87SSascha Wildner 	errno = serrno;
33010b5fe87SSascha Wildner 	/* fall through */
33110b5fe87SSascha Wildner fail:
33210b5fe87SSascha Wildner 	serrno = errno;
33310b5fe87SSascha Wildner 	if (this && this->optc && this->optv)
33410b5fe87SSascha Wildner 		FREEV(this->optc, this->optv);
33510b5fe87SSascha Wildner 	FREE(this);
33610b5fe87SSascha Wildner 	FREEV(wordc, wordv);
33710b5fe87SSascha Wildner 	FREE(wordv);
33810b5fe87SSascha Wildner 	FREE(name);
33910b5fe87SSascha Wildner 	fclose(f);
34010b5fe87SSascha Wildner 	errno = serrno;
34110b5fe87SSascha Wildner 	return (-1);
34210b5fe87SSascha Wildner }
34310b5fe87SSascha Wildner 
34410b5fe87SSascha Wildner /*
34510b5fe87SSascha Wildner  * Read the specified chains from the specified file.
34610b5fe87SSascha Wildner  *
34710b5fe87SSascha Wildner  * Returns 0 if the file exists but does not contain any matching lines.
34810b5fe87SSascha Wildner  *
34910b5fe87SSascha Wildner  * Returns -1 and sets errno to ENOENT if the file does not exist.
35010b5fe87SSascha Wildner  *
35110b5fe87SSascha Wildner  * Returns -1 and sets errno to some other non-zero value if the file
35210b5fe87SSascha Wildner  * exists but is unsafe or unreadable, or an I/O error occurs.
35310b5fe87SSascha Wildner  */
35410b5fe87SSascha Wildner static int
openpam_load_file(pam_handle_t * pamh,const char * service,pam_facility_t facility,const char * filename,openpam_style_t style)35510b5fe87SSascha Wildner openpam_load_file(pam_handle_t *pamh,
35610b5fe87SSascha Wildner 	const char *service,
35710b5fe87SSascha Wildner 	pam_facility_t facility,
35810b5fe87SSascha Wildner 	const char *filename,
35910b5fe87SSascha Wildner 	openpam_style_t style)
36010b5fe87SSascha Wildner {
36110b5fe87SSascha Wildner 	FILE *f;
36210b5fe87SSascha Wildner 	int ret, serrno;
36310b5fe87SSascha Wildner 
36410b5fe87SSascha Wildner 	/* attempt to open the file */
36510b5fe87SSascha Wildner 	if ((f = fopen(filename, "r")) == NULL) {
36610b5fe87SSascha Wildner 		serrno = errno;
36710b5fe87SSascha Wildner 		openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR,
36810b5fe87SSascha Wildner 		    "%s: %m", filename);
36910b5fe87SSascha Wildner 		errno = serrno;
37010b5fe87SSascha Wildner 		RETURNN(-1);
37110b5fe87SSascha Wildner 	} else {
37210b5fe87SSascha Wildner 		openpam_log(PAM_LOG_DEBUG, "found %s", filename);
37310b5fe87SSascha Wildner 	}
37410b5fe87SSascha Wildner 
37510b5fe87SSascha Wildner 	/* verify type, ownership and permissions */
37610b5fe87SSascha Wildner 	if (OPENPAM_FEATURE(VERIFY_POLICY_FILE) &&
37710b5fe87SSascha Wildner 	    openpam_check_desc_owner_perms(filename, fileno(f)) != 0) {
37810b5fe87SSascha Wildner 		/* already logged the cause */
37910b5fe87SSascha Wildner 		serrno = errno;
38010b5fe87SSascha Wildner 		fclose(f);
38110b5fe87SSascha Wildner 		errno = serrno;
38210b5fe87SSascha Wildner 		RETURNN(-1);
38310b5fe87SSascha Wildner 	}
38410b5fe87SSascha Wildner 
38510b5fe87SSascha Wildner 	/* parse the file */
38610b5fe87SSascha Wildner 	ret = openpam_parse_chain(pamh, service, facility,
38710b5fe87SSascha Wildner 	    f, filename, style);
38810b5fe87SSascha Wildner 	RETURNN(ret);
38910b5fe87SSascha Wildner }
39010b5fe87SSascha Wildner 
39110b5fe87SSascha Wildner /*
39210b5fe87SSascha Wildner  * Locates the policy file for a given service and reads the given chains
39310b5fe87SSascha Wildner  * from it.
39410b5fe87SSascha Wildner  *
39510b5fe87SSascha Wildner  * Returns the number of policy entries which were found for the specified
39610b5fe87SSascha Wildner  * service and facility, or -1 if a system error occurred or a syntax
39710b5fe87SSascha Wildner  * error was encountered.
39810b5fe87SSascha Wildner  */
39910b5fe87SSascha Wildner static int
openpam_load_chain(pam_handle_t * pamh,const char * service,pam_facility_t facility)40010b5fe87SSascha Wildner openpam_load_chain(pam_handle_t *pamh,
40110b5fe87SSascha Wildner 	const char *service,
40210b5fe87SSascha Wildner 	pam_facility_t facility)
40310b5fe87SSascha Wildner {
40410b5fe87SSascha Wildner 	const char *p, **path;
40510b5fe87SSascha Wildner 	char filename[PATH_MAX];
40610b5fe87SSascha Wildner 	size_t len;
40710b5fe87SSascha Wildner 	openpam_style_t style;
40810b5fe87SSascha Wildner 	int ret;
40910b5fe87SSascha Wildner 
41010b5fe87SSascha Wildner 	ENTERS(facility < 0 ? "any" : pam_facility_name[facility]);
41110b5fe87SSascha Wildner 
41210b5fe87SSascha Wildner 	/* either absolute or relative to cwd */
41310b5fe87SSascha Wildner 	if (strchr(service, '/') != NULL) {
41410b5fe87SSascha Wildner 		if ((p = strrchr(service, '.')) != NULL && strcmp(p, ".conf") == 0)
41510b5fe87SSascha Wildner 			style = pam_conf_style;
41610b5fe87SSascha Wildner 		else
41710b5fe87SSascha Wildner 			style = pam_d_style;
41810b5fe87SSascha Wildner 		ret = openpam_load_file(pamh, service, facility,
41910b5fe87SSascha Wildner 		    service, style);
42010b5fe87SSascha Wildner 		RETURNN(ret);
42110b5fe87SSascha Wildner 	}
42210b5fe87SSascha Wildner 
42310b5fe87SSascha Wildner 	/* search standard locations */
42410b5fe87SSascha Wildner 	for (path = openpam_policy_path; *path != NULL; ++path) {
42510b5fe87SSascha Wildner 		/* construct filename */
42610b5fe87SSascha Wildner 		len = strlcpy(filename, *path, sizeof filename);
42710b5fe87SSascha Wildner 		if (len >= sizeof filename) {
42810b5fe87SSascha Wildner 			errno = ENAMETOOLONG;
42910b5fe87SSascha Wildner 			RETURNN(-1);
43010b5fe87SSascha Wildner 		}
43110b5fe87SSascha Wildner 		if (filename[len - 1] == '/') {
43210b5fe87SSascha Wildner 			len = strlcat(filename, service, sizeof filename);
43310b5fe87SSascha Wildner 			if (len >= sizeof filename) {
43410b5fe87SSascha Wildner 				errno = ENAMETOOLONG;
43510b5fe87SSascha Wildner 				RETURNN(-1);
43610b5fe87SSascha Wildner 			}
43710b5fe87SSascha Wildner 			style = pam_d_style;
43810b5fe87SSascha Wildner 		} else {
43910b5fe87SSascha Wildner 			style = pam_conf_style;
44010b5fe87SSascha Wildner 		}
44110b5fe87SSascha Wildner 		ret = openpam_load_file(pamh, service, facility,
44210b5fe87SSascha Wildner 		    filename, style);
44310b5fe87SSascha Wildner 		/* success */
44410b5fe87SSascha Wildner 		if (ret > 0)
44510b5fe87SSascha Wildner 			RETURNN(ret);
44610b5fe87SSascha Wildner 		/* the file exists, but an error occurred */
44710b5fe87SSascha Wildner 		if (ret == -1 && errno != ENOENT)
44810b5fe87SSascha Wildner 			RETURNN(ret);
44910b5fe87SSascha Wildner 		/* in pam.d style, an empty file counts as a hit */
45010b5fe87SSascha Wildner 		if (ret == 0 && style == pam_d_style)
45110b5fe87SSascha Wildner 			RETURNN(ret);
45210b5fe87SSascha Wildner 	}
45310b5fe87SSascha Wildner 
45410b5fe87SSascha Wildner 	/* no hit */
45510b5fe87SSascha Wildner 	errno = ENOENT;
45610b5fe87SSascha Wildner 	RETURNN(-1);
45710b5fe87SSascha Wildner }
45810b5fe87SSascha Wildner 
45910b5fe87SSascha Wildner /*
46010b5fe87SSascha Wildner  * OpenPAM internal
46110b5fe87SSascha Wildner  *
46210b5fe87SSascha Wildner  * Configure a service
46310b5fe87SSascha Wildner  */
46410b5fe87SSascha Wildner 
46510b5fe87SSascha Wildner int
openpam_configure(pam_handle_t * pamh,const char * service)46610b5fe87SSascha Wildner openpam_configure(pam_handle_t *pamh,
46710b5fe87SSascha Wildner 	const char *service)
46810b5fe87SSascha Wildner {
46910b5fe87SSascha Wildner 	pam_facility_t fclt;
47010b5fe87SSascha Wildner 	int serrno;
47110b5fe87SSascha Wildner 
47210b5fe87SSascha Wildner 	ENTERS(service);
47310b5fe87SSascha Wildner 	if (!valid_service_name(service)) {
47410b5fe87SSascha Wildner 		openpam_log(PAM_LOG_ERROR, "invalid service name");
47510b5fe87SSascha Wildner 		RETURNC(PAM_SYSTEM_ERR);
47610b5fe87SSascha Wildner 	}
47710b5fe87SSascha Wildner 	if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) {
47810b5fe87SSascha Wildner 		if (errno != ENOENT)
47910b5fe87SSascha Wildner 			goto load_err;
48010b5fe87SSascha Wildner 	}
48110b5fe87SSascha Wildner 	for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
48210b5fe87SSascha Wildner 		if (pamh->chains[fclt] != NULL)
48310b5fe87SSascha Wildner 			continue;
48410b5fe87SSascha Wildner 		if (OPENPAM_FEATURE(FALLBACK_TO_OTHER)) {
48510b5fe87SSascha Wildner 			if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0)
48610b5fe87SSascha Wildner 				goto load_err;
48710b5fe87SSascha Wildner 		}
48810b5fe87SSascha Wildner 	}
48910b5fe87SSascha Wildner 	RETURNC(PAM_SUCCESS);
49010b5fe87SSascha Wildner load_err:
49110b5fe87SSascha Wildner 	serrno = errno;
49210b5fe87SSascha Wildner 	openpam_clear_chains(pamh->chains);
49310b5fe87SSascha Wildner 	errno = serrno;
49410b5fe87SSascha Wildner 	RETURNC(PAM_SYSTEM_ERR);
49510b5fe87SSascha Wildner }
49610b5fe87SSascha Wildner 
49710b5fe87SSascha Wildner /*
49810b5fe87SSascha Wildner  * NODOC
49910b5fe87SSascha Wildner  *
50010b5fe87SSascha Wildner  * Error codes:
50110b5fe87SSascha Wildner  *	PAM_SYSTEM_ERR
50210b5fe87SSascha Wildner  */
503