File: api-account.c

package info (click to toggle)
libpam-krb5 4.3-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,840 kB
  • ctags: 333
  • sloc: sh: 10,220; ansic: 3,845; makefile: 54
file content (114 lines) | stat: -rw-r--r-- 3,792 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/*
 * Implements the PAM account group API (pam_sm_acct_mgmt).
 *
 * We don't have much to do for account management, but we do recheck the
 * user's authorization against .k5login (or whatever equivalent we've been
 * configured for).
 *
 * Copyright 2005, 2006, 2007, 2008, 2009 Russ Allbery <rra@stanford.edu>
 * Copyright 2005 Andres Salomon <dilinger@debian.org>
 * Copyright 1999, 2000 Frank Cusack <fcusack@fcusack.com>
 *
 * See LICENSE for licensing terms.
 */

/* Get prototypes for the account management functions. */
#define PAM_SM_ACCOUNT

#include <config.h>
#include <portable/pam.h>

#include <errno.h>
#include <krb5.h>
#include <stdlib.h>
#include <string.h>

#include <internal.h>

/*
 * Check the authorization of the user.  It's not entirely clear what this
 * function is supposed to do, but rechecking .k5login and friends makes the
 * most sense.
 */
int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    struct pam_args *args;
    struct context *ctx;
    int pamret, retval;
    const char *name;

    args = pamk5_args_parse(pamh, flags, argc, argv);
    if (args == NULL) {
        pamk5_crit(NULL, "cannot allocate memory: %s", strerror(errno));
        pamret = PAM_AUTH_ERR;
        goto done;
    }
    pamret = pamk5_context_fetch(args);
    ENTRY(args, flags);

    /*
     * Succeed if the user did not use krb5 to login.  Ideally, we should
     * probably fail and require that the user set up policy properly in their
     * PAM configuration, but it's not common for the user to do so and that's
     * not how other krb5 PAM modules work.  If we don't do this, root logins
     * with the system root password fail, which is a bad failure mode.
     */
    if (pamret != PAM_SUCCESS || args->ctx == NULL) {
        pamret = PAM_IGNORE;
        pamk5_debug(args, "skipping non-Kerberos login");
        goto done;
    }
    ctx = args->ctx;

    /* If the account was expired, here's where we actually fail. */
    if (ctx->expired) {
        pamk5_debug(args, "account password is expired");
        pamret = PAM_NEW_AUTHTOK_REQD;
        goto done;
    }

    /*
     * Re-retrieve the user rather than trusting our context; it's conceivable
     * the application could have changed it.  We have to cast &name to void *
     * due to C's broken type system.
     *
     * Use pam_get_item rather than pam_get_user here since the user should be
     * set by the time we get to this point.  If we would have to prompt for a
     * user, something is definitely broken and we should fail.
     */
    retval = pam_get_item(pamh, PAM_USER, (PAM_CONST void **) &name);
    if (retval != PAM_SUCCESS || name == NULL) {
        pamk5_err_pam(args, retval, "unable to retrieve user");
        pamret = PAM_AUTH_ERR;
        goto done;
    }
    if (ctx->name != NULL)
        free(ctx->name);
    ctx->name = strdup(name);

    /*
     * If we have a ticket cache, then we can apply an additional bit of
     * paranoia.  Rather than trusting princ in the context, extract the
     * principal from the Kerberos ticket cache we actually received and then
     * validate that.  This should make no difference in practice, but it's a
     * bit more thorough.
     */
    if (ctx->cache != NULL) {
        pamk5_debug(args, "retrieving principal from cache");
        if (ctx->princ != NULL)
            krb5_free_principal(ctx->context, ctx->princ);
        retval = krb5_cc_get_principal(ctx->context, ctx->cache, &ctx->princ);
        if (retval != 0) {
            pamk5_err_krb5(args, retval, "cannot get principal from cache");
            pamret = PAM_AUTH_ERR;
            goto done;
        }
    }
    pamret = pamk5_authorized(args);

done:
    EXIT(args, pamret);
    pamk5_args_free(args);
    return pamret;
}