source: openpam/trunk/lib/openpam_dispatch.c @ 186

Last change on this file since 186 was 186, checked in by des, 11 years ago

Record which primitive is currently executing before calling the
service module. Use that information to generate a much better
error message when indirect recursion is detected.

Instrument openpam_dispatch()'s entry and exit points.

File size: 6.1 KB
Line 
1/*-
2 * Copyright (c) 2002 Networks Associates Technology, Inc.
3 * All rights reserved.
4 *
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.
9 *
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.
21 *
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.
33 *
34 * $P4: //depot/projects/openpam/lib/openpam_dispatch.c#18 $
35 */
36
37#include <sys/param.h>
38
39#include <security/pam_appl.h>
40
41#include "openpam_impl.h"
42
43#if !defined(OPENPAM_RELAX_CHECKS)
44static void _openpam_check_error_code(int, int);
45#else
46#define _openpam_check_error_code(a, b)
47#endif /* !defined(OPENPAM_RELAX_CHECKS) */
48
49/*
50 * OpenPAM internal
51 *
52 * Execute a module chain
53 */
54
55int
56openpam_dispatch(pam_handle_t *pamh,
57        int primitive,
58        int flags)
59{
60        pam_chain_t *chain;
61        int err, fail, r;
62
63        ENTER();
64        if (pamh == NULL)
65                RETURNC(PAM_SYSTEM_ERR);
66
67        /* prevent recursion */
68        if (pamh->current != NULL) {
69                openpam_log(PAM_LOG_ERROR,
70                    "%s() called while %s::%s() is in progress",
71                    _pam_func_name[primitive],
72                    pamh->current->module->path,
73                    _pam_sm_func_name[pamh->primitive]);
74                RETURNC(PAM_ABORT);
75        }
76
77        /* pick a chain */
78        switch (primitive) {
79        case PAM_SM_AUTHENTICATE:
80        case PAM_SM_SETCRED:
81                chain = pamh->chains[PAM_AUTH];
82                break;
83        case PAM_SM_ACCT_MGMT:
84                chain = pamh->chains[PAM_ACCOUNT];
85                break;
86        case PAM_SM_OPEN_SESSION:
87        case PAM_SM_CLOSE_SESSION:
88                chain = pamh->chains[PAM_SESSION];
89                break;
90        case PAM_SM_CHAUTHTOK:
91                chain = pamh->chains[PAM_PASSWORD];
92                break;
93        default:
94                RETURNC(PAM_SYSTEM_ERR);
95        }
96
97        /* execute */
98        for (err = fail = 0; chain != NULL; chain = chain->next) {
99                openpam_log(PAM_LOG_DEBUG, "calling %s() in %s",
100                    _pam_sm_func_name[primitive], chain->module->path);
101                if (chain->module->func[primitive] == NULL) {
102                        openpam_log(PAM_LOG_ERROR, "%s: no %s()",
103                            chain->module->path, _pam_sm_func_name[primitive]);
104                        continue;
105                } else {
106                        pamh->primitive = primitive;
107                        pamh->current = chain;
108                        r = (chain->module->func[primitive])(pamh, flags,
109                            chain->optc, (const char **)chain->optv);
110                        pamh->current = NULL;
111                        openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s",
112                            chain->module->path, _pam_sm_func_name[primitive],
113                            pam_strerror(pamh, r));
114                }
115
116                if (r == PAM_IGNORE)
117                        continue;
118                if (r == PAM_SUCCESS) {
119                        /*
120                         * For pam_setcred() and pam_chauthtok() with the
121                         * PAM_PRELIM_CHECK flag, treat "sufficient" as
122                         * "optional".
123                         */
124                        if ((chain->flag == PAM_SUFFICIENT ||
125                            chain->flag == PAM_BINDING) && !fail &&
126                            primitive != PAM_SM_SETCRED &&
127                            !(primitive == PAM_SM_CHAUTHTOK &&
128                                (flags & PAM_PRELIM_CHECK)))
129                                break;
130                        continue;
131                }
132
133                _openpam_check_error_code(primitive, r);
134
135                /*
136                 * Record the return code from the first module to
137                 * fail.  If a required module fails, record the
138                 * return code from the first required module to fail.
139                 */
140                if (err == 0)
141                        err = r;
142                if ((chain->flag == PAM_REQUIRED ||
143                    chain->flag == PAM_BINDING) && !fail) {
144                        openpam_log(PAM_LOG_DEBUG, "required module failed");
145                        fail = 1;
146                        err = r;
147                }
148
149                /*
150                 * If a requisite module fails, terminate the chain
151                 * immediately.
152                 */
153                if (chain->flag == PAM_REQUISITE) {
154                        openpam_log(PAM_LOG_DEBUG, "requisite module failed");
155                        fail = 1;
156                        break;
157                }
158        }
159
160        if (!fail && err != PAM_NEW_AUTHTOK_REQD)
161                err = PAM_SUCCESS;
162        RETURNC(err);
163}
164
165#if !defined(OPENPAM_RELAX_CHECKS)
166static void
167_openpam_check_error_code(int primitive, int r)
168{
169        /* common error codes */
170        if (r == PAM_SUCCESS ||
171            r == PAM_SERVICE_ERR ||
172            r == PAM_BUF_ERR ||
173            r == PAM_CONV_ERR ||
174            r == PAM_PERM_DENIED ||
175            r == PAM_ABORT)
176                return;
177
178        /* specific error codes */
179        switch (primitive) {
180        case PAM_SM_AUTHENTICATE:
181                if (r == PAM_AUTH_ERR ||
182                    r == PAM_CRED_INSUFFICIENT ||
183                    r == PAM_AUTHINFO_UNAVAIL ||
184                    r == PAM_USER_UNKNOWN ||
185                    r == PAM_MAXTRIES)
186                        return;
187                break;
188        case PAM_SM_SETCRED:
189                if (r == PAM_CRED_UNAVAIL ||
190                    r == PAM_CRED_EXPIRED ||
191                    r == PAM_USER_UNKNOWN ||
192                    r == PAM_CRED_ERR)
193                        return;
194                break;
195        case PAM_SM_ACCT_MGMT:
196                if (r == PAM_USER_UNKNOWN ||
197                    r == PAM_AUTH_ERR ||
198                    r == PAM_NEW_AUTHTOK_REQD ||
199                    r == PAM_ACCT_EXPIRED)
200                        return;
201                break;
202        case PAM_SM_OPEN_SESSION:
203        case PAM_SM_CLOSE_SESSION:
204                if (r == PAM_SESSION_ERR)
205                        return;
206                break;
207        case PAM_SM_CHAUTHTOK:
208                if (r == PAM_PERM_DENIED ||
209                    r == PAM_AUTHTOK_ERR ||
210                    r == PAM_AUTHTOK_RECOVERY_ERR ||
211                    r == PAM_AUTHTOK_LOCK_BUSY ||
212                    r == PAM_AUTHTOK_DISABLE_AGING ||
213                    r == PAM_TRY_AGAIN)
214                        return;
215                break;
216        }
217
218        openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d",
219            _pam_sm_func_name[primitive], r);
220}
221#endif /* !defined(OPENPAM_RELAX_CHECKS) */
222
223/*
224 * NODOC
225 *
226 * Error codes:
227 */
Note: See TracBrowser for help on using the repository browser.