1f7e6344dSDag-Erling Smørgrav /*-
2f7e6344dSDag-Erling Smørgrav * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
3*f3b0ac34SDag-Erling Smørgrav * Copyright (c) 2004-2015 Dag-Erling Smørgrav
4f7e6344dSDag-Erling Smørgrav * All rights reserved.
5f7e6344dSDag-Erling Smørgrav *
6f7e6344dSDag-Erling Smørgrav * This software was developed for the FreeBSD Project by ThinkSec AS and
7f7e6344dSDag-Erling Smørgrav * Network Associates Laboratories, the Security Research Division of
8f7e6344dSDag-Erling Smørgrav * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
9f7e6344dSDag-Erling Smørgrav * ("CBOSS"), as part of the DARPA CHATS research program.
10f7e6344dSDag-Erling Smørgrav *
11f7e6344dSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without
12f7e6344dSDag-Erling Smørgrav * modification, are permitted provided that the following conditions
13f7e6344dSDag-Erling Smørgrav * are met:
14f7e6344dSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright
15f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer.
16f7e6344dSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright
17f7e6344dSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the
18f7e6344dSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution.
19f7e6344dSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote
20f7e6344dSDag-Erling Smørgrav * products derived from this software without specific prior written
21f7e6344dSDag-Erling Smørgrav * permission.
22f7e6344dSDag-Erling Smørgrav *
23f7e6344dSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24f7e6344dSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25f7e6344dSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26f7e6344dSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27f7e6344dSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28f7e6344dSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29f7e6344dSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30f7e6344dSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31f7e6344dSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32f7e6344dSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33f7e6344dSDag-Erling Smørgrav * SUCH DAMAGE.
34f7e6344dSDag-Erling Smørgrav */
35f7e6344dSDag-Erling Smørgrav
36f7e6344dSDag-Erling Smørgrav #ifdef HAVE_CONFIG_H
37f7e6344dSDag-Erling Smørgrav # include "config.h"
38f7e6344dSDag-Erling Smørgrav #endif
39f7e6344dSDag-Erling Smørgrav
40f7e6344dSDag-Erling Smørgrav #include <sys/param.h>
41f7e6344dSDag-Erling Smørgrav
42f7e6344dSDag-Erling Smørgrav #include <errno.h>
43f7e6344dSDag-Erling Smørgrav #include <stdio.h>
44f7e6344dSDag-Erling Smørgrav #include <stdlib.h>
45f7e6344dSDag-Erling Smørgrav #include <string.h>
46f7e6344dSDag-Erling Smørgrav
47f7e6344dSDag-Erling Smørgrav #include <security/pam_appl.h>
48f7e6344dSDag-Erling Smørgrav
49f7e6344dSDag-Erling Smørgrav #include "openpam_impl.h"
50f7e6344dSDag-Erling Smørgrav #include "openpam_ctype.h"
51f7e6344dSDag-Erling Smørgrav #include "openpam_strlcat.h"
52f7e6344dSDag-Erling Smørgrav #include "openpam_strlcpy.h"
53f7e6344dSDag-Erling Smørgrav
54f7e6344dSDag-Erling Smørgrav static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
55f7e6344dSDag-Erling Smørgrav
56f7e6344dSDag-Erling Smørgrav /*
57f7e6344dSDag-Erling Smørgrav * Validate a service name.
58f7e6344dSDag-Erling Smørgrav *
59f7e6344dSDag-Erling Smørgrav * Returns a non-zero value if the argument points to a NUL-terminated
60f7e6344dSDag-Erling Smørgrav * string consisting entirely of characters in the POSIX portable filename
61f7e6344dSDag-Erling Smørgrav * character set, excluding the path separator character.
62f7e6344dSDag-Erling Smørgrav */
63f7e6344dSDag-Erling Smørgrav static int
valid_service_name(const char * name)64f7e6344dSDag-Erling Smørgrav valid_service_name(const char *name)
65f7e6344dSDag-Erling Smørgrav {
66f7e6344dSDag-Erling Smørgrav const char *p;
67f7e6344dSDag-Erling Smørgrav
68f7e6344dSDag-Erling Smørgrav if (OPENPAM_FEATURE(RESTRICT_SERVICE_NAME)) {
69f7e6344dSDag-Erling Smørgrav /* path separator not allowed */
70f7e6344dSDag-Erling Smørgrav for (p = name; *p != '\0'; ++p)
71f7e6344dSDag-Erling Smørgrav if (!is_pfcs(*p))
72f7e6344dSDag-Erling Smørgrav return (0);
73f7e6344dSDag-Erling Smørgrav } else {
74f7e6344dSDag-Erling Smørgrav /* path separator allowed */
75f7e6344dSDag-Erling Smørgrav for (p = name; *p != '\0'; ++p)
76f7e6344dSDag-Erling Smørgrav if (!is_pfcs(*p) && *p != '/')
77f7e6344dSDag-Erling Smørgrav return (0);
78f7e6344dSDag-Erling Smørgrav }
79f7e6344dSDag-Erling Smørgrav return (1);
80f7e6344dSDag-Erling Smørgrav }
81f7e6344dSDag-Erling Smørgrav
82f7e6344dSDag-Erling Smørgrav /*
83f7e6344dSDag-Erling Smørgrav * Parse the facility name.
84f7e6344dSDag-Erling Smørgrav *
85f7e6344dSDag-Erling Smørgrav * Returns the corresponding pam_facility_t value, or -1 if the argument
86f7e6344dSDag-Erling Smørgrav * is not a valid facility name.
87f7e6344dSDag-Erling Smørgrav */
88f7e6344dSDag-Erling Smørgrav static pam_facility_t
parse_facility_name(const char * name)89f7e6344dSDag-Erling Smørgrav parse_facility_name(const char *name)
90f7e6344dSDag-Erling Smørgrav {
91f7e6344dSDag-Erling Smørgrav int i;
92f7e6344dSDag-Erling Smørgrav
93f7e6344dSDag-Erling Smørgrav for (i = 0; i < PAM_NUM_FACILITIES; ++i)
94f7e6344dSDag-Erling Smørgrav if (strcmp(pam_facility_name[i], name) == 0)
95f7e6344dSDag-Erling Smørgrav return (i);
96f7e6344dSDag-Erling Smørgrav return ((pam_facility_t)-1);
97f7e6344dSDag-Erling Smørgrav }
98f7e6344dSDag-Erling Smørgrav
99f7e6344dSDag-Erling Smørgrav /*
100f7e6344dSDag-Erling Smørgrav * Parse the control flag.
101f7e6344dSDag-Erling Smørgrav *
102f7e6344dSDag-Erling Smørgrav * Returns the corresponding pam_control_t value, or -1 if the argument is
103f7e6344dSDag-Erling Smørgrav * not a valid control flag name.
104f7e6344dSDag-Erling Smørgrav */
105f7e6344dSDag-Erling Smørgrav static pam_control_t
parse_control_flag(const char * name)106f7e6344dSDag-Erling Smørgrav parse_control_flag(const char *name)
107f7e6344dSDag-Erling Smørgrav {
108f7e6344dSDag-Erling Smørgrav int i;
109f7e6344dSDag-Erling Smørgrav
110f7e6344dSDag-Erling Smørgrav for (i = 0; i < PAM_NUM_CONTROL_FLAGS; ++i)
111f7e6344dSDag-Erling Smørgrav if (strcmp(pam_control_flag_name[i], name) == 0)
112f7e6344dSDag-Erling Smørgrav return (i);
113f7e6344dSDag-Erling Smørgrav return ((pam_control_t)-1);
114f7e6344dSDag-Erling Smørgrav }
115f7e6344dSDag-Erling Smørgrav
116f7e6344dSDag-Erling Smørgrav /*
117f7e6344dSDag-Erling Smørgrav * Validate a file name.
118f7e6344dSDag-Erling Smørgrav *
119f7e6344dSDag-Erling Smørgrav * Returns a non-zero value if the argument points to a NUL-terminated
120f7e6344dSDag-Erling Smørgrav * string consisting entirely of characters in the POSIX portable filename
121f7e6344dSDag-Erling Smørgrav * character set, including the path separator character.
122f7e6344dSDag-Erling Smørgrav */
123f7e6344dSDag-Erling Smørgrav static int
valid_module_name(const char * name)124f7e6344dSDag-Erling Smørgrav valid_module_name(const char *name)
125f7e6344dSDag-Erling Smørgrav {
126f7e6344dSDag-Erling Smørgrav const char *p;
127f7e6344dSDag-Erling Smørgrav
128f7e6344dSDag-Erling Smørgrav if (OPENPAM_FEATURE(RESTRICT_MODULE_NAME)) {
129f7e6344dSDag-Erling Smørgrav /* path separator not allowed */
130f7e6344dSDag-Erling Smørgrav for (p = name; *p != '\0'; ++p)
131f7e6344dSDag-Erling Smørgrav if (!is_pfcs(*p))
132f7e6344dSDag-Erling Smørgrav return (0);
133f7e6344dSDag-Erling Smørgrav } else {
134f7e6344dSDag-Erling Smørgrav /* path separator allowed */
135f7e6344dSDag-Erling Smørgrav for (p = name; *p != '\0'; ++p)
136f7e6344dSDag-Erling Smørgrav if (!is_pfcs(*p) && *p != '/')
137f7e6344dSDag-Erling Smørgrav return (0);
138f7e6344dSDag-Erling Smørgrav }
139f7e6344dSDag-Erling Smørgrav return (1);
140f7e6344dSDag-Erling Smørgrav }
141f7e6344dSDag-Erling Smørgrav
142f7e6344dSDag-Erling Smørgrav typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
143f7e6344dSDag-Erling Smørgrav
144f7e6344dSDag-Erling Smørgrav /*
145f7e6344dSDag-Erling Smørgrav * Extracts given chains from a policy file.
146f7e6344dSDag-Erling Smørgrav *
147f7e6344dSDag-Erling Smørgrav * Returns the number of policy entries which were found for the specified
148f7e6344dSDag-Erling Smørgrav * service and facility, or -1 if a system error occurred or a syntax
149f7e6344dSDag-Erling Smørgrav * error was encountered.
150f7e6344dSDag-Erling Smørgrav */
151f7e6344dSDag-Erling Smørgrav 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)152f7e6344dSDag-Erling Smørgrav openpam_parse_chain(pam_handle_t *pamh,
153f7e6344dSDag-Erling Smørgrav const char *service,
154f7e6344dSDag-Erling Smørgrav pam_facility_t facility,
155f7e6344dSDag-Erling Smørgrav FILE *f,
156f7e6344dSDag-Erling Smørgrav const char *filename,
157f7e6344dSDag-Erling Smørgrav openpam_style_t style)
158f7e6344dSDag-Erling Smørgrav {
159f7e6344dSDag-Erling Smørgrav pam_chain_t *this, **next;
160f7e6344dSDag-Erling Smørgrav pam_facility_t fclt;
161f7e6344dSDag-Erling Smørgrav pam_control_t ctlf;
162f7e6344dSDag-Erling Smørgrav char *name, *servicename, *modulename;
163f7e6344dSDag-Erling Smørgrav int count, lineno, ret, serrno;
164f7e6344dSDag-Erling Smørgrav char **wordv, *word;
165f7e6344dSDag-Erling Smørgrav int i, wordc;
166f7e6344dSDag-Erling Smørgrav
167f7e6344dSDag-Erling Smørgrav count = 0;
168f7e6344dSDag-Erling Smørgrav this = NULL;
169f7e6344dSDag-Erling Smørgrav name = NULL;
170f7e6344dSDag-Erling Smørgrav lineno = 0;
171f7e6344dSDag-Erling Smørgrav wordc = 0;
172f7e6344dSDag-Erling Smørgrav wordv = NULL;
173f7e6344dSDag-Erling Smørgrav while ((wordv = openpam_readlinev(f, &lineno, &wordc)) != NULL) {
174f7e6344dSDag-Erling Smørgrav /* blank line? */
175f7e6344dSDag-Erling Smørgrav if (wordc == 0) {
176f7e6344dSDag-Erling Smørgrav FREEV(wordc, wordv);
177f7e6344dSDag-Erling Smørgrav continue;
178f7e6344dSDag-Erling Smørgrav }
179f7e6344dSDag-Erling Smørgrav i = 0;
180f7e6344dSDag-Erling Smørgrav
181f7e6344dSDag-Erling Smørgrav /* check service name if necessary */
182f7e6344dSDag-Erling Smørgrav if (style == pam_conf_style &&
183f7e6344dSDag-Erling Smørgrav strcmp(wordv[i++], service) != 0) {
184f7e6344dSDag-Erling Smørgrav FREEV(wordc, wordv);
185f7e6344dSDag-Erling Smørgrav continue;
186f7e6344dSDag-Erling Smørgrav }
187f7e6344dSDag-Erling Smørgrav
188f7e6344dSDag-Erling Smørgrav /* check facility name */
189f7e6344dSDag-Erling Smørgrav if ((word = wordv[i++]) == NULL ||
190f7e6344dSDag-Erling Smørgrav (fclt = parse_facility_name(word)) == (pam_facility_t)-1) {
191f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR,
192f7e6344dSDag-Erling Smørgrav "%s(%d): missing or invalid facility",
193f7e6344dSDag-Erling Smørgrav filename, lineno);
1941fecd13eSXin LI errno = EINVAL;
195f7e6344dSDag-Erling Smørgrav goto fail;
196f7e6344dSDag-Erling Smørgrav }
197f7e6344dSDag-Erling Smørgrav if (facility != fclt && facility != PAM_FACILITY_ANY) {
198f7e6344dSDag-Erling Smørgrav FREEV(wordc, wordv);
199f7e6344dSDag-Erling Smørgrav continue;
200f7e6344dSDag-Erling Smørgrav }
201f7e6344dSDag-Erling Smørgrav
202f7e6344dSDag-Erling Smørgrav /* check for "include" */
203f7e6344dSDag-Erling Smørgrav if ((word = wordv[i++]) != NULL &&
204f7e6344dSDag-Erling Smørgrav strcmp(word, "include") == 0) {
205f7e6344dSDag-Erling Smørgrav if ((servicename = wordv[i++]) == NULL ||
206f7e6344dSDag-Erling Smørgrav !valid_service_name(servicename)) {
207f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR,
208f7e6344dSDag-Erling Smørgrav "%s(%d): missing or invalid service name",
209f7e6344dSDag-Erling Smørgrav filename, lineno);
2101fecd13eSXin LI errno = EINVAL;
211f7e6344dSDag-Erling Smørgrav goto fail;
212f7e6344dSDag-Erling Smørgrav }
213f7e6344dSDag-Erling Smørgrav if (wordv[i] != NULL) {
214f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR,
215f7e6344dSDag-Erling Smørgrav "%s(%d): garbage at end of line",
216f7e6344dSDag-Erling Smørgrav filename, lineno);
2171fecd13eSXin LI errno = EINVAL;
218f7e6344dSDag-Erling Smørgrav goto fail;
219f7e6344dSDag-Erling Smørgrav }
220f7e6344dSDag-Erling Smørgrav ret = openpam_load_chain(pamh, servicename, fclt);
221f7e6344dSDag-Erling Smørgrav FREEV(wordc, wordv);
2221fecd13eSXin LI if (ret < 0) {
2231fecd13eSXin LI /*
2241fecd13eSXin LI * Bogus errno, but this ensures that the
2251fecd13eSXin LI * outer loop does not just ignore the
2261fecd13eSXin LI * error and keep searching.
2271fecd13eSXin LI */
2281fecd13eSXin LI if (errno == ENOENT)
2291fecd13eSXin LI errno = EINVAL;
230f7e6344dSDag-Erling Smørgrav goto fail;
2311fecd13eSXin LI }
232f7e6344dSDag-Erling Smørgrav continue;
233f7e6344dSDag-Erling Smørgrav }
234f7e6344dSDag-Erling Smørgrav
235f7e6344dSDag-Erling Smørgrav /* get control flag */
236f7e6344dSDag-Erling Smørgrav if (word == NULL || /* same word we compared to "include" */
237f7e6344dSDag-Erling Smørgrav (ctlf = parse_control_flag(word)) == (pam_control_t)-1) {
238f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR,
239f7e6344dSDag-Erling Smørgrav "%s(%d): missing or invalid control flag",
240f7e6344dSDag-Erling Smørgrav filename, lineno);
2411fecd13eSXin LI errno = EINVAL;
242f7e6344dSDag-Erling Smørgrav goto fail;
243f7e6344dSDag-Erling Smørgrav }
244f7e6344dSDag-Erling Smørgrav
245f7e6344dSDag-Erling Smørgrav /* get module name */
246f7e6344dSDag-Erling Smørgrav if ((modulename = wordv[i++]) == NULL ||
247f7e6344dSDag-Erling Smørgrav !valid_module_name(modulename)) {
248f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR,
249f7e6344dSDag-Erling Smørgrav "%s(%d): missing or invalid module name",
250f7e6344dSDag-Erling Smørgrav filename, lineno);
2511fecd13eSXin LI errno = EINVAL;
252f7e6344dSDag-Erling Smørgrav goto fail;
253f7e6344dSDag-Erling Smørgrav }
254f7e6344dSDag-Erling Smørgrav
255f7e6344dSDag-Erling Smørgrav /* allocate new entry */
256f7e6344dSDag-Erling Smørgrav if ((this = calloc(1, sizeof *this)) == NULL)
257f7e6344dSDag-Erling Smørgrav goto syserr;
258f7e6344dSDag-Erling Smørgrav this->flag = ctlf;
259f7e6344dSDag-Erling Smørgrav
260f7e6344dSDag-Erling Smørgrav /* load module */
2611fecd13eSXin LI if ((this->module = openpam_load_module(modulename)) == NULL) {
2621fecd13eSXin LI if (errno == ENOENT)
2631fecd13eSXin LI errno = ENOEXEC;
264f7e6344dSDag-Erling Smørgrav goto fail;
2651fecd13eSXin LI }
266f7e6344dSDag-Erling Smørgrav
267f7e6344dSDag-Erling Smørgrav /*
268f7e6344dSDag-Erling Smørgrav * The remaining items in wordv are the module's
269f7e6344dSDag-Erling Smørgrav * arguments. We could set this->optv = wordv + i, but
270f7e6344dSDag-Erling Smørgrav * then free(this->optv) wouldn't work. Instead, we free
271f7e6344dSDag-Erling Smørgrav * the words we've already consumed, shift the rest up,
272f7e6344dSDag-Erling Smørgrav * and clear the tail end of the array.
273f7e6344dSDag-Erling Smørgrav */
274f7e6344dSDag-Erling Smørgrav this->optc = wordc - i;
275f7e6344dSDag-Erling Smørgrav for (i = 0; i < wordc - this->optc; ++i) {
276f7e6344dSDag-Erling Smørgrav FREE(wordv[i]);
277f7e6344dSDag-Erling Smørgrav }
278f7e6344dSDag-Erling Smørgrav for (i = 0; i < this->optc; ++i) {
279f7e6344dSDag-Erling Smørgrav wordv[i] = wordv[wordc - this->optc + i];
280f7e6344dSDag-Erling Smørgrav wordv[wordc - this->optc + i] = NULL;
281f7e6344dSDag-Erling Smørgrav }
282f7e6344dSDag-Erling Smørgrav this->optv = wordv;
283f7e6344dSDag-Erling Smørgrav wordv = NULL;
284f7e6344dSDag-Erling Smørgrav wordc = 0;
285f7e6344dSDag-Erling Smørgrav
286f7e6344dSDag-Erling Smørgrav /* hook it up */
287f7e6344dSDag-Erling Smørgrav for (next = &pamh->chains[fclt]; *next != NULL;
288f7e6344dSDag-Erling Smørgrav next = &(*next)->next)
289f7e6344dSDag-Erling Smørgrav /* nothing */ ;
290f7e6344dSDag-Erling Smørgrav *next = this;
291f7e6344dSDag-Erling Smørgrav this = NULL;
292f7e6344dSDag-Erling Smørgrav ++count;
293f7e6344dSDag-Erling Smørgrav }
294f7e6344dSDag-Erling Smørgrav /*
295f7e6344dSDag-Erling Smørgrav * The loop ended because openpam_readword() returned NULL, which
296f7e6344dSDag-Erling Smørgrav * can happen for four different reasons: an I/O error (ferror(f)
297f7e6344dSDag-Erling Smørgrav * is true), a memory allocation failure (ferror(f) is false,
2981fecd13eSXin LI * feof(f) is false, errno is non-zero), the file ended with an
2991fecd13eSXin LI * unterminated quote or backslash escape (ferror(f) is false,
3001fecd13eSXin LI * feof(f) is true, errno is non-zero), or the end of the file was
3011fecd13eSXin LI * reached without error (ferror(f) is false, feof(f) is true,
3021fecd13eSXin LI * errno is zero).
303f7e6344dSDag-Erling Smørgrav */
304f7e6344dSDag-Erling Smørgrav if (ferror(f) || errno != 0)
305f7e6344dSDag-Erling Smørgrav goto syserr;
306f7e6344dSDag-Erling Smørgrav if (!feof(f))
307f7e6344dSDag-Erling Smørgrav goto fail;
308f7e6344dSDag-Erling Smørgrav fclose(f);
309f7e6344dSDag-Erling Smørgrav return (count);
310f7e6344dSDag-Erling Smørgrav syserr:
311f7e6344dSDag-Erling Smørgrav serrno = errno;
312f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
313f7e6344dSDag-Erling Smørgrav errno = serrno;
314f7e6344dSDag-Erling Smørgrav /* fall through */
315f7e6344dSDag-Erling Smørgrav fail:
316f7e6344dSDag-Erling Smørgrav serrno = errno;
317f7e6344dSDag-Erling Smørgrav if (this && this->optc && this->optv)
318f7e6344dSDag-Erling Smørgrav FREEV(this->optc, this->optv);
319f7e6344dSDag-Erling Smørgrav FREE(this);
320f7e6344dSDag-Erling Smørgrav FREEV(wordc, wordv);
321f7e6344dSDag-Erling Smørgrav FREE(wordv);
322f7e6344dSDag-Erling Smørgrav FREE(name);
323f7e6344dSDag-Erling Smørgrav fclose(f);
324f7e6344dSDag-Erling Smørgrav errno = serrno;
325f7e6344dSDag-Erling Smørgrav return (-1);
326f7e6344dSDag-Erling Smørgrav }
327f7e6344dSDag-Erling Smørgrav
328f7e6344dSDag-Erling Smørgrav /*
329f7e6344dSDag-Erling Smørgrav * Read the specified chains from the specified file.
330f7e6344dSDag-Erling Smørgrav *
331f7e6344dSDag-Erling Smørgrav * Returns 0 if the file exists but does not contain any matching lines.
332f7e6344dSDag-Erling Smørgrav *
333f7e6344dSDag-Erling Smørgrav * Returns -1 and sets errno to ENOENT if the file does not exist.
334f7e6344dSDag-Erling Smørgrav *
335f7e6344dSDag-Erling Smørgrav * Returns -1 and sets errno to some other non-zero value if the file
336f7e6344dSDag-Erling Smørgrav * exists but is unsafe or unreadable, or an I/O error occurs.
337f7e6344dSDag-Erling Smørgrav */
338f7e6344dSDag-Erling Smørgrav static int
openpam_load_file(pam_handle_t * pamh,const char * service,pam_facility_t facility,const char * filename,openpam_style_t style)339f7e6344dSDag-Erling Smørgrav openpam_load_file(pam_handle_t *pamh,
340f7e6344dSDag-Erling Smørgrav const char *service,
341f7e6344dSDag-Erling Smørgrav pam_facility_t facility,
342f7e6344dSDag-Erling Smørgrav const char *filename,
343f7e6344dSDag-Erling Smørgrav openpam_style_t style)
344f7e6344dSDag-Erling Smørgrav {
345f7e6344dSDag-Erling Smørgrav FILE *f;
346f7e6344dSDag-Erling Smørgrav int ret, serrno;
347f7e6344dSDag-Erling Smørgrav
348f7e6344dSDag-Erling Smørgrav /* attempt to open the file */
349f7e6344dSDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) {
350f7e6344dSDag-Erling Smørgrav serrno = errno;
351f7e6344dSDag-Erling Smørgrav openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_ERROR,
352f7e6344dSDag-Erling Smørgrav "%s: %m", filename);
353f7e6344dSDag-Erling Smørgrav errno = serrno;
354f7e6344dSDag-Erling Smørgrav RETURNN(-1);
355f7e6344dSDag-Erling Smørgrav } else {
356f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_DEBUG, "found %s", filename);
357f7e6344dSDag-Erling Smørgrav }
358f7e6344dSDag-Erling Smørgrav
359f7e6344dSDag-Erling Smørgrav /* verify type, ownership and permissions */
360f7e6344dSDag-Erling Smørgrav if (OPENPAM_FEATURE(VERIFY_POLICY_FILE) &&
361f7e6344dSDag-Erling Smørgrav openpam_check_desc_owner_perms(filename, fileno(f)) != 0) {
362f7e6344dSDag-Erling Smørgrav /* already logged the cause */
363f7e6344dSDag-Erling Smørgrav serrno = errno;
364f7e6344dSDag-Erling Smørgrav fclose(f);
365f7e6344dSDag-Erling Smørgrav errno = serrno;
366f7e6344dSDag-Erling Smørgrav RETURNN(-1);
367f7e6344dSDag-Erling Smørgrav }
368f7e6344dSDag-Erling Smørgrav
369f7e6344dSDag-Erling Smørgrav /* parse the file */
370f7e6344dSDag-Erling Smørgrav ret = openpam_parse_chain(pamh, service, facility,
371f7e6344dSDag-Erling Smørgrav f, filename, style);
372f7e6344dSDag-Erling Smørgrav RETURNN(ret);
373f7e6344dSDag-Erling Smørgrav }
374f7e6344dSDag-Erling Smørgrav
375f7e6344dSDag-Erling Smørgrav /*
376f7e6344dSDag-Erling Smørgrav * Locates the policy file for a given service and reads the given chains
377f7e6344dSDag-Erling Smørgrav * from it.
378f7e6344dSDag-Erling Smørgrav *
379f7e6344dSDag-Erling Smørgrav * Returns the number of policy entries which were found for the specified
380f7e6344dSDag-Erling Smørgrav * service and facility, or -1 if a system error occurred or a syntax
381f7e6344dSDag-Erling Smørgrav * error was encountered.
382f7e6344dSDag-Erling Smørgrav */
383f7e6344dSDag-Erling Smørgrav static int
openpam_load_chain(pam_handle_t * pamh,const char * service,pam_facility_t facility)384f7e6344dSDag-Erling Smørgrav openpam_load_chain(pam_handle_t *pamh,
385f7e6344dSDag-Erling Smørgrav const char *service,
386f7e6344dSDag-Erling Smørgrav pam_facility_t facility)
387f7e6344dSDag-Erling Smørgrav {
388f7e6344dSDag-Erling Smørgrav const char *p, **path;
389f7e6344dSDag-Erling Smørgrav char filename[PATH_MAX];
390f7e6344dSDag-Erling Smørgrav size_t len;
391f7e6344dSDag-Erling Smørgrav openpam_style_t style;
392f7e6344dSDag-Erling Smørgrav int ret;
393f7e6344dSDag-Erling Smørgrav
394f7e6344dSDag-Erling Smørgrav ENTERS(facility < 0 ? "any" : pam_facility_name[facility]);
395f7e6344dSDag-Erling Smørgrav
396f7e6344dSDag-Erling Smørgrav /* either absolute or relative to cwd */
397f7e6344dSDag-Erling Smørgrav if (strchr(service, '/') != NULL) {
398f7e6344dSDag-Erling Smørgrav if ((p = strrchr(service, '.')) != NULL && strcmp(p, ".conf") == 0)
399f7e6344dSDag-Erling Smørgrav style = pam_conf_style;
400f7e6344dSDag-Erling Smørgrav else
401f7e6344dSDag-Erling Smørgrav style = pam_d_style;
402f7e6344dSDag-Erling Smørgrav ret = openpam_load_file(pamh, service, facility,
403f7e6344dSDag-Erling Smørgrav service, style);
404f7e6344dSDag-Erling Smørgrav RETURNN(ret);
405f7e6344dSDag-Erling Smørgrav }
406f7e6344dSDag-Erling Smørgrav
407f7e6344dSDag-Erling Smørgrav /* search standard locations */
408f7e6344dSDag-Erling Smørgrav for (path = openpam_policy_path; *path != NULL; ++path) {
409f7e6344dSDag-Erling Smørgrav /* construct filename */
410f7e6344dSDag-Erling Smørgrav len = strlcpy(filename, *path, sizeof filename);
411*f3b0ac34SDag-Erling Smørgrav if (len >= sizeof filename) {
412*f3b0ac34SDag-Erling Smørgrav errno = ENAMETOOLONG;
413*f3b0ac34SDag-Erling Smørgrav RETURNN(-1);
414*f3b0ac34SDag-Erling Smørgrav }
415f7e6344dSDag-Erling Smørgrav if (filename[len - 1] == '/') {
416f7e6344dSDag-Erling Smørgrav len = strlcat(filename, service, sizeof filename);
417f7e6344dSDag-Erling Smørgrav if (len >= sizeof filename) {
418f7e6344dSDag-Erling Smørgrav errno = ENAMETOOLONG;
419f7e6344dSDag-Erling Smørgrav RETURNN(-1);
420f7e6344dSDag-Erling Smørgrav }
421f7e6344dSDag-Erling Smørgrav style = pam_d_style;
422f7e6344dSDag-Erling Smørgrav } else {
423f7e6344dSDag-Erling Smørgrav style = pam_conf_style;
424f7e6344dSDag-Erling Smørgrav }
425f7e6344dSDag-Erling Smørgrav ret = openpam_load_file(pamh, service, facility,
426f7e6344dSDag-Erling Smørgrav filename, style);
4271fecd13eSXin LI /* success */
4281fecd13eSXin LI if (ret > 0)
4291fecd13eSXin LI RETURNN(ret);
430f7e6344dSDag-Erling Smørgrav /* the file exists, but an error occurred */
431f7e6344dSDag-Erling Smørgrav if (ret == -1 && errno != ENOENT)
432f7e6344dSDag-Erling Smørgrav RETURNN(ret);
433f7e6344dSDag-Erling Smørgrav /* in pam.d style, an empty file counts as a hit */
434f7e6344dSDag-Erling Smørgrav if (ret == 0 && style == pam_d_style)
435f7e6344dSDag-Erling Smørgrav RETURNN(ret);
436f7e6344dSDag-Erling Smørgrav }
437f7e6344dSDag-Erling Smørgrav
438f7e6344dSDag-Erling Smørgrav /* no hit */
4391fecd13eSXin LI errno = ENOENT;
4401fecd13eSXin LI RETURNN(-1);
441f7e6344dSDag-Erling Smørgrav }
442f7e6344dSDag-Erling Smørgrav
443f7e6344dSDag-Erling Smørgrav /*
444f7e6344dSDag-Erling Smørgrav * OpenPAM internal
445f7e6344dSDag-Erling Smørgrav *
446f7e6344dSDag-Erling Smørgrav * Configure a service
447f7e6344dSDag-Erling Smørgrav */
448f7e6344dSDag-Erling Smørgrav
449f7e6344dSDag-Erling Smørgrav int
openpam_configure(pam_handle_t * pamh,const char * service)450f7e6344dSDag-Erling Smørgrav openpam_configure(pam_handle_t *pamh,
451f7e6344dSDag-Erling Smørgrav const char *service)
452f7e6344dSDag-Erling Smørgrav {
453f7e6344dSDag-Erling Smørgrav pam_facility_t fclt;
454f7e6344dSDag-Erling Smørgrav int serrno;
455f7e6344dSDag-Erling Smørgrav
456f7e6344dSDag-Erling Smørgrav ENTERS(service);
457f7e6344dSDag-Erling Smørgrav if (!valid_service_name(service)) {
458f7e6344dSDag-Erling Smørgrav openpam_log(PAM_LOG_ERROR, "invalid service name");
459f7e6344dSDag-Erling Smørgrav RETURNC(PAM_SYSTEM_ERR);
460f7e6344dSDag-Erling Smørgrav }
4611fecd13eSXin LI if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0) {
4621fecd13eSXin LI if (errno != ENOENT)
463f7e6344dSDag-Erling Smørgrav goto load_err;
4641fecd13eSXin LI }
465f7e6344dSDag-Erling Smørgrav for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
466f7e6344dSDag-Erling Smørgrav if (pamh->chains[fclt] != NULL)
467f7e6344dSDag-Erling Smørgrav continue;
468*f3b0ac34SDag-Erling Smørgrav if (OPENPAM_FEATURE(FALLBACK_TO_OTHER)) {
469f7e6344dSDag-Erling Smørgrav if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0)
470f7e6344dSDag-Erling Smørgrav goto load_err;
471f7e6344dSDag-Erling Smørgrav }
472*f3b0ac34SDag-Erling Smørgrav }
473f7e6344dSDag-Erling Smørgrav RETURNC(PAM_SUCCESS);
474f7e6344dSDag-Erling Smørgrav load_err:
475f7e6344dSDag-Erling Smørgrav serrno = errno;
476f7e6344dSDag-Erling Smørgrav openpam_clear_chains(pamh->chains);
477f7e6344dSDag-Erling Smørgrav errno = serrno;
478f7e6344dSDag-Erling Smørgrav RETURNC(PAM_SYSTEM_ERR);
479f7e6344dSDag-Erling Smørgrav }
480f7e6344dSDag-Erling Smørgrav
481f7e6344dSDag-Erling Smørgrav /*
482f7e6344dSDag-Erling Smørgrav * NODOC
483f7e6344dSDag-Erling Smørgrav *
484f7e6344dSDag-Erling Smørgrav * Error codes:
485f7e6344dSDag-Erling Smørgrav * PAM_SYSTEM_ERR
486f7e6344dSDag-Erling Smørgrav */
487