xref: /freebsd/contrib/pam-krb5/module/account.c (revision bf6873c5786e333d679a7838d28812febf479a8a)
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