xref: /freebsd/contrib/pam-krb5/module/public.c (revision bf6873c5786e333d679a7838d28812febf479a8a)
1 /*
2  * The public APIs of the pam-afs-session PAM module.
3  *
4  * Provides the public pam_sm_authenticate, pam_sm_setcred,
5  * pam_sm_open_session, pam_sm_close_session, and pam_sm_chauthtok functions.
6  * These must all be specified in the same file to work with the symbol export
7  * and linking mechanism used in OpenPAM, since OpenPAM will mark them all as
8  * static functions and export a function table instead.
9  *
10  * Written by Russ Allbery <eagle@eyrie.org>
11  * Copyright 2005-2009, 2017, 2020 Russ Allbery <eagle@eyrie.org>
12  * Copyright 2011
13  *     The Board of Trustees of the Leland Stanford Junior University
14  * Copyright 2005 Andres Salomon <dilinger@debian.org>
15  * Copyright 1999-2000 Frank Cusack <fcusack@fcusack.com>
16  *
17  * SPDX-License-Identifier: BSD-3-clause or GPL-1+
18  */
19 
20 /* Get prototypes for all of the functions. */
21 #define PAM_SM_ACCOUNT
22 #define PAM_SM_AUTH
23 #define PAM_SM_PASSWORD
24 #define PAM_SM_SESSION
25 
26 #include <config.h>
27 #include <portable/pam.h>
28 #include <portable/system.h>
29 
30 #include <module/internal.h>
31 #include <pam-util/args.h>
32 #include <pam-util/logging.h>
33 
34 
35 /*
36  * The main PAM interface for authorization checking.
37  */
38 PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t * pamh,int flags,int argc,const char ** argv)39 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
40 {
41     struct pam_args *args;
42     int pamret;
43 
44     args = pamk5_init(pamh, flags, argc, argv);
45     if (args == NULL) {
46         pamret = PAM_AUTH_ERR;
47         goto done;
48     }
49     pamret = pamk5_context_fetch(args);
50     ENTRY(args, flags);
51 
52     /*
53      * Succeed if the user did not use krb5 to login.  Ideally, we should
54      * probably fail and require that the user set up policy properly in their
55      * PAM configuration, but it's not common for the user to do so and that's
56      * not how other krb5 PAM modules work.  If we don't do this, root logins
57      * with the system root password fail, which is a bad failure mode.
58      */
59     if (pamret != PAM_SUCCESS || args->config->ctx == NULL) {
60         pamret = PAM_IGNORE;
61         putil_debug(args, "skipping non-Kerberos login");
62         goto done;
63     }
64 
65     pamret = pamk5_account(args);
66 
67 done:
68     EXIT(args, pamret);
69     pamk5_free(args);
70     return pamret;
71 }
72 
73 
74 /*
75  * The main PAM interface for authentication.  We also do authorization checks
76  * here, since many applications don't call pam_acct_mgmt.
77  */
78 PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh,int flags,int argc,const char ** argv)79 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
80 {
81     struct pam_args *args;
82     int pamret;
83 
84     args = pamk5_init(pamh, flags, argc, argv);
85     if (args == NULL) {
86         pamret = PAM_SERVICE_ERR;
87         goto done;
88     }
89     ENTRY(args, flags);
90 
91     pamret = pamk5_authenticate(args);
92 
93 done:
94     EXIT(args, pamret);
95     pamk5_free(args);
96     return pamret;
97 }
98 
99 
100 /*
101  * The main PAM interface, in the auth stack, for establishing credentials
102  * obtained during authentication.
103  */
104 PAM_EXTERN int
pam_sm_setcred(pam_handle_t * pamh,int flags,int argc,const char ** argv)105 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
106 {
107     struct pam_args *args;
108     bool refresh = false;
109     int pamret, allow;
110 
111     args = pamk5_init(pamh, flags, argc, argv);
112     if (args == NULL) {
113         pamret = PAM_SERVICE_ERR;
114         goto done;
115     }
116     ENTRY(args, flags);
117 
118     /*
119      * Special case.  Just free the context data, which will destroy the
120      * ticket cache as well.
121      */
122     if (flags & PAM_DELETE_CRED) {
123         pamret = pam_set_data(pamh, "pam_krb5", NULL, NULL);
124         if (pamret != PAM_SUCCESS)
125             putil_err_pam(args, pamret, "cannot clear context data");
126         goto done;
127     }
128 
129     /*
130      * Reinitialization requested, which means that rather than creating a new
131      * ticket cache and setting KRB5CCNAME, we should figure out the existing
132      * ticket cache and just refresh its tickets.
133      */
134     if (flags & (PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED))
135         refresh = true;
136     if (refresh && (flags & PAM_ESTABLISH_CRED)) {
137         putil_err(args, "requested establish and refresh at the same time");
138         pamret = PAM_SERVICE_ERR;
139         goto done;
140     }
141     allow = PAM_REINITIALIZE_CRED | PAM_REFRESH_CRED | PAM_ESTABLISH_CRED;
142     if (!(flags & allow)) {
143         putil_err(args, "invalid pam_setcred flags %d", flags);
144         pamret = PAM_SERVICE_ERR;
145         goto done;
146     }
147 
148     /* Do the work. */
149     pamret = pamk5_setcred(args, refresh);
150 
151     /*
152      * Never return PAM_IGNORE from pam_setcred since this can confuse the
153      * Linux PAM library, at least for applications that call pam_setcred
154      * without pam_authenticate (possibly because authentication was done
155      * some other way), when used with jumps with the [] syntax.  Since we
156      * do nothing in this case, and since the stack is already frozen from
157      * the auth group, success makes sense.
158      *
159      * Don't return an error here or the PAM stack will fail if pam-krb5 is
160      * used with [success=ok default=1], since jumps are treated as required
161      * during the second pass with pam_setcred.
162      */
163     if (pamret == PAM_IGNORE)
164         pamret = PAM_SUCCESS;
165 
166 done:
167     EXIT(args, pamret);
168     pamk5_free(args);
169     return pamret;
170 }
171 
172 
173 /*
174  * The main PAM interface for password changing.
175  */
176 PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)177 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
178 {
179     struct pam_args *args;
180     int pamret;
181 
182     args = pamk5_init(pamh, flags, argc, argv);
183     if (args == NULL) {
184         pamret = PAM_AUTHTOK_ERR;
185         goto done;
186     }
187     pamk5_context_fetch(args);
188     ENTRY(args, flags);
189 
190     /* We only support password changes. */
191     if (!(flags & PAM_UPDATE_AUTHTOK) && !(flags & PAM_PRELIM_CHECK)) {
192         putil_err(args, "invalid pam_chauthtok flags %d", flags);
193         pamret = PAM_AUTHTOK_ERR;
194         goto done;
195     }
196 
197     pamret = pamk5_password(args, (flags & PAM_PRELIM_CHECK) != 0);
198 
199 done:
200     EXIT(args, pamret);
201     pamk5_free(args);
202     return pamret;
203 }
204 
205 
206 /*
207  * The main PAM interface for opening a session.
208  */
209 PAM_EXTERN int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)210 pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
211 {
212     struct pam_args *args;
213     int pamret;
214 
215     args = pamk5_init(pamh, flags, argc, argv);
216     if (args == NULL) {
217         pamret = PAM_SERVICE_ERR;
218         goto done;
219     }
220     ENTRY(args, flags);
221     pamret = pamk5_setcred(args, 0);
222 
223 done:
224     EXIT(args, pamret);
225     pamk5_free(args);
226     return pamret;
227 }
228 
229 
230 /*
231  * The main PAM interface for closing a session.
232  */
233 PAM_EXTERN int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)234 pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
235                      const char **argv)
236 {
237     struct pam_args *args;
238     int pamret;
239 
240     args = pamk5_init(pamh, flags, argc, argv);
241     if (args == NULL) {
242         pamret = PAM_SERVICE_ERR;
243         goto done;
244     }
245     ENTRY(args, flags);
246     pamret = pam_set_data(pamh, "pam_krb5", NULL, NULL);
247     if (pamret != PAM_SUCCESS)
248         putil_err_pam(args, pamret, "cannot clear context data");
249 
250 done:
251     EXIT(args, pamret);
252     pamk5_free(args);
253     return pamret;
254 }
255 
256 
257 /* OpenPAM uses this macro to set up a table of entry points. */
258 #ifdef PAM_MODULE_ENTRY
259 PAM_MODULE_ENTRY("pam_krb5");
260 #endif
261