1 /* 2 * Implements the PAM authorization function (pam_acct_mgmt). 3 * 4 * We don't have much to do for account management, but we do recheck the 5 * user's authorization against .k5login (or whatever equivalent we've been 6 * configured for). 7 * 8 * Copyright 2005-2009, 2014, 2020-2021 Russ Allbery <eagle@eyrie.org> 9 * Copyright 2011 10 * The Board of Trustees of the Leland Stanford Junior University 11 * Copyright 2005 Andres Salomon <dilinger@debian.org> 12 * Copyright 1999-2000 Frank Cusack <fcusack@fcusack.com> 13 * 14 * SPDX-License-Identifier: BSD-3-clause or GPL-1+ 15 */ 16 17 /* Get prototypes for the account management functions. */ 18 #define PAM_SM_ACCOUNT 19 20 #include <config.h> 21 #include <portable/krb5.h> 22 #include <portable/pam.h> 23 #include <portable/system.h> 24 25 #include <errno.h> 26 27 #include <module/internal.h> 28 #include <pam-util/args.h> 29 #include <pam-util/logging.h> 30 31 32 /* 33 * Check the authorization of the user. It's not entirely clear what this 34 * function is supposed to do, but rechecking .k5login and friends makes the 35 * most sense. 36 */ 37 int 38 pamk5_account(struct pam_args *args) 39 { 40 struct context *ctx; 41 int retval; 42 const char *name; 43 44 /* If the account was expired, here's where we actually fail. */ 45 ctx = args->config->ctx; 46 if (ctx->expired) { 47 pam_syslog(args->pamh, LOG_INFO, "user %s account password is expired", 48 ctx->name); 49 return PAM_NEW_AUTHTOK_REQD; 50 } 51 52 /* 53 * Re-retrieve the user rather than trusting our context; it's conceivable 54 * the application could have changed it. We have to cast &name due to 55 * C's broken type system. 56 * 57 * Use pam_get_item rather than pam_get_user here since the user should be 58 * set by the time we get to this point. If we would have to prompt for a 59 * user, something is definitely broken and we should fail. 60 */ 61 retval = pam_get_item(args->pamh, PAM_USER, (PAM_CONST void **) &name); 62 if (retval != PAM_SUCCESS || name == NULL) { 63 putil_err_pam(args, retval, "unable to retrieve user"); 64 return PAM_AUTH_ERR; 65 } 66 if (ctx->name != name) { 67 free(ctx->name); 68 ctx->name = strdup(name); 69 args->user = ctx->name; 70 } 71 72 /* 73 * If we have a ticket cache, then we can apply an additional bit of 74 * paranoia. Rather than trusting princ in the context, extract the 75 * principal from the Kerberos ticket cache we actually received and then 76 * validate that. This should make no difference in practice, but it's a 77 * bit more thorough. 78 */ 79 if (ctx->cache != NULL) { 80 putil_debug(args, "retrieving principal from cache"); 81 if (ctx->princ != NULL) { 82 krb5_free_principal(ctx->context, ctx->princ); 83 ctx->princ = NULL; 84 } 85 retval = krb5_cc_get_principal(ctx->context, ctx->cache, &ctx->princ); 86 if (retval != 0) { 87 putil_err_krb5(args, retval, "cannot get principal from cache"); 88 return PAM_AUTH_ERR; 89 } 90 } 91 return pamk5_authorized(args); 92 } 93