2 * Copyright (c) 2001-2003 Networks Associates Technology, Inc.
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
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
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
34 * $P4: //depot/projects/openpam/lib/openpam_configure.c#11 $
43 #include <security/pam_appl.h>
45 #include "openpam_impl.h"
47 const char *_pam_facility_name
[PAM_NUM_FACILITIES
] = {
48 [PAM_ACCOUNT
] = "account",
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.
69 match_word(const char *str
, const char *word
)
72 while (*str
&& tolower(*str
) == tolower(*word
))
74 return (*str
== ' ' && *word
== '\0');
78 * Return a pointer to the next word (or the final NUL) in a string.
81 next_word(const char *str
)
84 /* skip current word */
85 while (*str
&& *str
!= ' ')
94 * Return a malloc()ed copy of the first word in a string.
97 dup_word(const char *str
)
102 for (end
= str
; *end
&& *end
!= ' '; ++end
)
104 if (asprintf(&word
, "%.*s", (int)(end
- str
), str
) < 0)
110 * Return the length of the first word in a string.
113 wordlen(const char *str
)
117 for (i
= 0; str
[i
] && str
[i
] != ' '; ++i
)
122 typedef enum { pam_conf_style
, pam_d_style
} openpam_style_t
;
125 * Extracts given chains from a policy file.
128 openpam_read_chain(pam_handle_t
*pamh
,
130 pam_facility_t facility
,
131 const char *filename
,
132 openpam_style_t style
)
134 pam_chain_t
*this, **next
;
136 int count
, i
, lineno
, ret
;
142 if ((f
= fopen(filename
, "r")) == NULL
) {
143 openpam_log(errno
== ENOENT
? PAM_LOG_DEBUG
: PAM_LOG_NOTICE
,
149 while ((line
= openpam_readline(f
, &lineno
, NULL
)) != NULL
) {
152 /* match service name */
153 if (style
== pam_conf_style
) {
154 if (!match_word(p
, service
)) {
161 /* match facility name */
162 for (fclt
= 0; fclt
< PAM_NUM_FACILITIES
; ++fclt
)
163 if (match_word(p
, _pam_facility_name
[fclt
]))
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
);
171 if (facility
!= fclt
&& facility
!= PAM_FACILITY_ANY
) {
177 /* include other chain */
178 if (match_word(p
, "include")) {
180 if (*next_word(p
) != '\0')
181 openpam_log(PAM_LOG_NOTICE
,
182 "%s(%d): garbage at end of 'include' line",
184 if ((name
= dup_word(p
)) == NULL
)
186 ret
= openpam_load_chain(pamh
, name
, fclt
);
195 /* allocate new entry */
196 if ((this = calloc(1, sizeof *this)) == NULL
)
200 for (ctlf
= 0; ctlf
< PAM_NUM_CONTROL_FLAGS
; ++ctlf
)
201 if (match_word(p
, _pam_control_flag_name
[ctlf
]))
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
);
214 openpam_log(PAM_LOG_ERROR
,
215 "%s(%d): missing module name",
219 if ((name
= dup_word(p
)) == NULL
)
221 this->module
= openpam_load_module(name
);
223 if (this->module
== NULL
)
227 p
= q
= next_word(p
);
232 this->optv
= calloc(this->optc
+ 1, sizeof(char *));
233 if (this->optv
== NULL
)
235 for (i
= 0; i
< this->optc
; ++i
) {
236 if ((this->optv
[i
] = dup_word(p
)) == NULL
)
242 for (next
= &pamh
->chains
[fclt
]; *next
!= NULL
;
243 next
= &(*next
)->next
)
257 openpam_log(PAM_LOG_ERROR
, "%s: %m", filename
);
265 static const char *openpam_policy_path
[] = {
268 "/usr/local/etc/pam.d/",
269 "/usr/local/etc/pam.conf",
274 * Locates the policy file for a given service and reads the given chains
278 openpam_load_chain(pam_handle_t
*pamh
,
280 pam_facility_t facility
)
287 for (path
= openpam_policy_path
; *path
!= NULL
; ++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
);
298 r
= openpam_read_chain(pamh
, service
, facility
,
299 *path
, pam_conf_style
);
310 * Configure a service
314 openpam_configure(pam_handle_t
*pamh
,
319 if (openpam_load_chain(pamh
, service
, PAM_FACILITY_ANY
) < 0)
322 for (fclt
= 0; fclt
< PAM_NUM_FACILITIES
; ++fclt
) {
323 if (pamh
->chains
[fclt
] != NULL
)
325 if (openpam_load_chain(pamh
, PAM_OTHER
, fclt
) < 0)
328 return (PAM_SUCCESS
);
330 openpam_clear_chains(pamh
->chains
);
331 return (PAM_SYSTEM_ERR
);