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