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
pamk5_account(struct pam_args * args)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