MFC r1.28:
[dragonfly.git] / contrib / openpam / lib / openpam_configure.c
blob348f224b1f8f0741356e858b472db13b306562ca
1 /*-
2 * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
3 * All rights reserved.
5 * This software was developed for the FreeBSD Project by ThinkSec AS and
6 * Network Associates Laboratories, the Security Research Division of
7 * Network Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
8 * ("CBOSS"), as part of the DARPA CHATS research program.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior written
20 * permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * $P4: //depot/projects/openpam/lib/openpam_configure.c#11 $
37 #include <ctype.h>
38 #include <errno.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
43 #include <security/pam_appl.h>
45 #include "openpam_impl.h"
47 const char *_pam_facility_name[PAM_NUM_FACILITIES] = {
48 [PAM_ACCOUNT] = "account",
49 [PAM_AUTH] = "auth",
50 [PAM_PASSWORD] = "password",
51 [PAM_SESSION] = "session",
54 const char *_pam_control_flag_name[PAM_NUM_CONTROL_FLAGS] = {
55 [PAM_BINDING] = "binding",
56 [PAM_OPTIONAL] = "optional",
57 [PAM_REQUIRED] = "required",
58 [PAM_REQUISITE] = "requisite",
59 [PAM_SUFFICIENT] = "sufficient",
62 static int openpam_load_chain(pam_handle_t *, const char *, pam_facility_t);
65 * Matches a word against the first one in a string.
66 * Returns non-zero if they match.
68 static int
69 match_word(const char *str, const char *word)
72 while (*str && tolower(*str) == tolower(*word))
73 ++str, ++word;
74 return (*str == ' ' && *word == '\0');
78 * Return a pointer to the next word (or the final NUL) in a string.
80 static const char *
81 next_word(const char *str)
84 /* skip current word */
85 while (*str && *str != ' ')
86 ++str;
87 /* skip whitespace */
88 while (*str == ' ')
89 ++str;
90 return (str);
94 * Return a malloc()ed copy of the first word in a string.
96 static char *
97 dup_word(const char *str)
99 const char *end;
100 char *word;
102 for (end = str; *end && *end != ' '; ++end)
103 /* nothing */ ;
104 if (asprintf(&word, "%.*s", (int)(end - str), str) < 0)
105 return (NULL);
106 return (word);
110 * Return the length of the first word in a string.
112 static int
113 wordlen(const char *str)
115 int i;
117 for (i = 0; str[i] && str[i] != ' '; ++i)
118 /* nothing */ ;
119 return (i);
122 typedef enum { pam_conf_style, pam_d_style } openpam_style_t;
125 * Extracts given chains from a policy file.
127 static int
128 openpam_read_chain(pam_handle_t *pamh,
129 const char *service,
130 pam_facility_t facility,
131 const char *filename,
132 openpam_style_t style)
134 pam_chain_t *this, **next;
135 const char *p, *q;
136 int count, i, lineno, ret;
137 pam_facility_t fclt;
138 pam_control_t ctlf;
139 char *line, *name;
140 FILE *f;
142 if ((f = fopen(filename, "r")) == NULL) {
143 openpam_log(errno == ENOENT ? PAM_LOG_DEBUG : PAM_LOG_NOTICE,
144 "%s: %m", filename);
145 return (0);
147 this = NULL;
148 count = lineno = 0;
149 while ((line = openpam_readline(f, &lineno, NULL)) != NULL) {
150 p = line;
152 /* match service name */
153 if (style == pam_conf_style) {
154 if (!match_word(p, service)) {
155 FREE(line);
156 continue;
158 p = next_word(p);
161 /* match facility name */
162 for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt)
163 if (match_word(p, _pam_facility_name[fclt]))
164 break;
165 if (fclt == PAM_NUM_FACILITIES) {
166 openpam_log(PAM_LOG_NOTICE,
167 "%s(%d): invalid facility '%.*s' (ignored)",
168 filename, lineno, wordlen(p), p);
169 goto fail;
171 if (facility != fclt && facility != PAM_FACILITY_ANY) {
172 FREE(line);
173 continue;
175 p = next_word(p);
177 /* include other chain */
178 if (match_word(p, "include")) {
179 p = next_word(p);
180 if (*next_word(p) != '\0')
181 openpam_log(PAM_LOG_NOTICE,
182 "%s(%d): garbage at end of 'include' line",
183 filename, lineno);
184 if ((name = dup_word(p)) == NULL)
185 goto syserr;
186 ret = openpam_load_chain(pamh, name, fclt);
187 FREE(name);
188 if (ret < 0)
189 goto fail;
190 count += ret;
191 FREE(line);
192 continue;
195 /* allocate new entry */
196 if ((this = calloc(1, sizeof *this)) == NULL)
197 goto syserr;
199 /* control flag */
200 for (ctlf = 0; ctlf < PAM_NUM_CONTROL_FLAGS; ++ctlf)
201 if (match_word(p, _pam_control_flag_name[ctlf]))
202 break;
203 if (ctlf == PAM_NUM_CONTROL_FLAGS) {
204 openpam_log(PAM_LOG_ERROR,
205 "%s(%d): invalid control flag '%.*s'",
206 filename, lineno, wordlen(p), p);
207 goto fail;
209 this->flag = ctlf;
211 /* module name */
212 p = next_word(p);
213 if (*p == '\0') {
214 openpam_log(PAM_LOG_ERROR,
215 "%s(%d): missing module name",
216 filename, lineno);
217 goto fail;
219 if ((name = dup_word(p)) == NULL)
220 goto syserr;
221 this->module = openpam_load_module(name);
222 FREE(name);
223 if (this->module == NULL)
224 goto fail;
226 /* module options */
227 p = q = next_word(p);
228 while (*q != '\0') {
229 ++this->optc;
230 q = next_word(q);
232 this->optv = calloc(this->optc + 1, sizeof(char *));
233 if (this->optv == NULL)
234 goto syserr;
235 for (i = 0; i < this->optc; ++i) {
236 if ((this->optv[i] = dup_word(p)) == NULL)
237 goto syserr;
238 p = next_word(p);
241 /* hook it up */
242 for (next = &pamh->chains[fclt]; *next != NULL;
243 next = &(*next)->next)
244 /* nothing */ ;
245 *next = this;
246 this = NULL;
247 ++count;
249 /* next please... */
250 FREE(line);
252 if (!feof(f))
253 goto syserr;
254 fclose(f);
255 return (count);
256 syserr:
257 openpam_log(PAM_LOG_ERROR, "%s: %m", filename);
258 fail:
259 FREE(this);
260 FREE(line);
261 fclose(f);
262 return (-1);
265 static const char *openpam_policy_path[] = {
266 "/etc/pam.d/",
267 "/etc/pam.conf",
268 "/usr/local/etc/pam.d/",
269 "/usr/local/etc/pam.conf",
270 NULL
274 * Locates the policy file for a given service and reads the given chains
275 * from it.
277 static int
278 openpam_load_chain(pam_handle_t *pamh,
279 const char *service,
280 pam_facility_t facility)
282 const char **path;
283 char *filename;
284 size_t len;
285 int r;
287 for (path = openpam_policy_path; *path != NULL; ++path) {
288 len = strlen(*path);
289 if ((*path)[len - 1] == '/') {
290 if (asprintf(&filename, "%s%s", *path, service) < 0) {
291 openpam_log(PAM_LOG_ERROR, "asprintf(): %m");
292 return (-PAM_BUF_ERR);
294 r = openpam_read_chain(pamh, service, facility,
295 filename, pam_d_style);
296 FREE(filename);
297 } else {
298 r = openpam_read_chain(pamh, service, facility,
299 *path, pam_conf_style);
301 if (r != 0)
302 return (r);
304 return (0);
308 * OpenPAM internal
310 * Configure a service
314 openpam_configure(pam_handle_t *pamh,
315 const char *service)
317 pam_facility_t fclt;
319 if (openpam_load_chain(pamh, service, PAM_FACILITY_ANY) < 0)
320 goto load_err;
322 for (fclt = 0; fclt < PAM_NUM_FACILITIES; ++fclt) {
323 if (pamh->chains[fclt] != NULL)
324 continue;
325 if (openpam_load_chain(pamh, PAM_OTHER, fclt) < 0)
326 goto load_err;
328 return (PAM_SUCCESS);
329 load_err:
330 openpam_clear_chains(pamh->chains);
331 return (PAM_SYSTEM_ERR);
335 * NODOC
337 * Error codes:
338 * PAM_SYSTEM_ERR