NFS server: Record bwrite() error in nfsrv_commit.
[dragonfly.git] / contrib / openpam / lib / openpam_dispatch.c
1 /*-
2  * Copyright (c) 2002-2003 Networks Associates Technology, Inc.
3  * Copyright (c) 2004-2007 Dag-Erling Smørgrav
4  * All rights reserved.
5  *
6  * This software was developed for the FreeBSD Project by ThinkSec AS and
7  * Network Associates Laboratories, the Security Research Division of
8  * Network Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
9  * ("CBOSS"), as part of the DARPA CHATS research program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote
20  *    products derived from this software without specific prior written
21  *    permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $Id: openpam_dispatch.c 408 2007-12-21 11:36:24Z des $
36  */
37
38 #include <sys/param.h>
39
40 #include <security/pam_appl.h>
41
42 #include "openpam_impl.h"
43
44 #if !defined(OPENPAM_RELAX_CHECKS)
45 static void _openpam_check_error_code(int, int);
46 #else
47 #define _openpam_check_error_code(a, b)
48 #endif /* !defined(OPENPAM_RELAX_CHECKS) */
49
50 /*
51  * OpenPAM internal
52  *
53  * Execute a module chain
54  */
55
56 int
57 openpam_dispatch(pam_handle_t *pamh,
58         int primitive,
59         int flags)
60 {
61         pam_chain_t *chain;
62         int err, fail, r;
63 #ifdef DEBUG
64         int debug;
65 #endif
66
67         ENTER();
68         if (pamh == NULL)
69                 RETURNC(PAM_SYSTEM_ERR);
70
71         /* prevent recursion */
72         if (pamh->current != NULL) {
73                 openpam_log(PAM_LOG_ERROR,
74                     "%s() called while %s::%s() is in progress",
75                     _pam_func_name[primitive],
76                     pamh->current->module->path,
77                     _pam_sm_func_name[pamh->primitive]);
78                 RETURNC(PAM_ABORT);
79         }
80
81         /* pick a chain */
82         switch (primitive) {
83         case PAM_SM_AUTHENTICATE:
84         case PAM_SM_SETCRED:
85                 chain = pamh->chains[PAM_AUTH];
86                 break;
87         case PAM_SM_ACCT_MGMT:
88                 chain = pamh->chains[PAM_ACCOUNT];
89                 break;
90         case PAM_SM_OPEN_SESSION:
91         case PAM_SM_CLOSE_SESSION:
92                 chain = pamh->chains[PAM_SESSION];
93                 break;
94         case PAM_SM_CHAUTHTOK:
95                 chain = pamh->chains[PAM_PASSWORD];
96                 break;
97         default:
98                 RETURNC(PAM_SYSTEM_ERR);
99         }
100
101         /* execute */
102         for (err = fail = 0; chain != NULL; chain = chain->next) {
103                 if (chain->module->func[primitive] == NULL) {
104                         openpam_log(PAM_LOG_ERROR, "%s: no %s()",
105                             chain->module->path, _pam_sm_func_name[primitive]);
106                         continue;
107                 } else {
108                         pamh->primitive = primitive;
109                         pamh->current = chain;
110 #ifdef DEBUG
111                         debug = (openpam_get_option(pamh, "debug") != NULL);
112                         if (debug)
113                                 ++_openpam_debug;
114                         openpam_log(PAM_LOG_DEBUG, "calling %s() in %s",
115                             _pam_sm_func_name[primitive], chain->module->path);
116 #endif
117                         r = (chain->module->func[primitive])(pamh, flags,
118                             chain->optc, (const char **)chain->optv);
119                         pamh->current = NULL;
120 #ifdef DEBUG
121                         openpam_log(PAM_LOG_DEBUG, "%s: %s(): %s",
122                             chain->module->path, _pam_sm_func_name[primitive],
123                             pam_strerror(pamh, r));
124                         if (debug)
125                                 --_openpam_debug;
126 #endif
127                 }
128
129                 if (r == PAM_IGNORE)
130                         continue;
131                 if (r == PAM_SUCCESS) {
132                         /*
133                          * For pam_setcred() and pam_chauthtok() with the
134                          * PAM_PRELIM_CHECK flag, treat "sufficient" as
135                          * "optional".
136                          */
137                         if ((chain->flag == PAM_SUFFICIENT ||
138                             chain->flag == PAM_BINDING) && !fail &&
139                             primitive != PAM_SM_SETCRED &&
140                             !(primitive == PAM_SM_CHAUTHTOK &&
141                                 (flags & PAM_PRELIM_CHECK)))
142                                 break;
143                         continue;
144                 }
145
146                 _openpam_check_error_code(primitive, r);
147
148                 /*
149                  * Record the return code from the first module to
150                  * fail.  If a required module fails, record the
151                  * return code from the first required module to fail.
152                  */
153                 if (err == 0)
154                         err = r;
155                 if ((chain->flag == PAM_REQUIRED ||
156                     chain->flag == PAM_BINDING) && !fail) {
157                         openpam_log(PAM_LOG_DEBUG, "required module failed");
158                         fail = 1;
159                         err = r;
160                 }
161
162                 /*
163                  * If a requisite module fails, terminate the chain
164                  * immediately.
165                  */
166                 if (chain->flag == PAM_REQUISITE) {
167                         openpam_log(PAM_LOG_DEBUG, "requisite module failed");
168                         fail = 1;
169                         break;
170                 }
171         }
172
173         if (!fail && err != PAM_NEW_AUTHTOK_REQD)
174                 err = PAM_SUCCESS;
175         RETURNC(err);
176 }
177
178 #if !defined(OPENPAM_RELAX_CHECKS)
179 static void
180 _openpam_check_error_code(int primitive, int r)
181 {
182         /* common error codes */
183         if (r == PAM_SUCCESS ||
184             r == PAM_SERVICE_ERR ||
185             r == PAM_BUF_ERR ||
186             r == PAM_CONV_ERR ||
187             r == PAM_PERM_DENIED ||
188             r == PAM_ABORT)
189                 return;
190
191         /* specific error codes */
192         switch (primitive) {
193         case PAM_SM_AUTHENTICATE:
194                 if (r == PAM_AUTH_ERR ||
195                     r == PAM_CRED_INSUFFICIENT ||
196                     r == PAM_AUTHINFO_UNAVAIL ||
197                     r == PAM_USER_UNKNOWN ||
198                     r == PAM_MAXTRIES)
199                         return;
200                 break;
201         case PAM_SM_SETCRED:
202                 if (r == PAM_CRED_UNAVAIL ||
203                     r == PAM_CRED_EXPIRED ||
204                     r == PAM_USER_UNKNOWN ||
205                     r == PAM_CRED_ERR)
206                         return;
207                 break;
208         case PAM_SM_ACCT_MGMT:
209                 if (r == PAM_USER_UNKNOWN ||
210                     r == PAM_AUTH_ERR ||
211                     r == PAM_NEW_AUTHTOK_REQD ||
212                     r == PAM_ACCT_EXPIRED)
213                         return;
214                 break;
215         case PAM_SM_OPEN_SESSION:
216         case PAM_SM_CLOSE_SESSION:
217                 if (r == PAM_SESSION_ERR)
218                         return;
219                 break;
220         case PAM_SM_CHAUTHTOK:
221                 if (r == PAM_PERM_DENIED ||
222                     r == PAM_AUTHTOK_ERR ||
223                     r == PAM_AUTHTOK_RECOVERY_ERR ||
224                     r == PAM_AUTHTOK_LOCK_BUSY ||
225                     r == PAM_AUTHTOK_DISABLE_AGING ||
226                     r == PAM_TRY_AGAIN)
227                         return;
228                 break;
229         }
230
231         openpam_log(PAM_LOG_ERROR, "%s(): unexpected return value %d",
232             _pam_sm_func_name[primitive], r);
233 }
234 #endif /* !defined(OPENPAM_RELAX_CHECKS) */
235
236 /*
237  * NODOC
238  *
239  * Error codes:
240  */