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 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 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 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 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 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 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