~ubuntu-branches/ubuntu/quantal/libpam-krb5/quantal-201405130549

1.1.5 by Russ Allbery
Import upstream version 3.5
1
/*
2
 * Implements the PAM password group API (pam_sm_chauthtok).
3
 *
1.2.3 by Russ Allbery
Import upstream version 4.3
4
 * Copyright 2005, 2006, 2007, 2008, 2009 Russ Allbery <rra@stanford.edu>
1.1.8 by Russ Allbery
Import upstream version 3.10
5
 * Copyright 2005 Andres Salomon <dilinger@debian.org>
6
 * Copyright 1999, 2000 Frank Cusack <fcusack@fcusack.com>
1.1.10 by Steve Langasek
Import upstream version 3.13
7
 *
1.1.8 by Russ Allbery
Import upstream version 3.10
8
 * See LICENSE for licensing terms.
1.1.5 by Russ Allbery
Import upstream version 3.5
9
 */
10
11
/* Get declarations for the password functions. */
12
#define PAM_SM_PASSWORD
13
1.1.14 by Russ Allbery
Import upstream version 4.1
14
#include <config.h>
15
#include <portable/pam.h>
1.1.5 by Russ Allbery
Import upstream version 3.5
16
17
#include <errno.h>
18
#include <string.h>
19
1.1.14 by Russ Allbery
Import upstream version 4.1
20
#include <internal.h>
1.1.5 by Russ Allbery
Import upstream version 3.5
21
1.1.9 by Russ Allbery
Import upstream version 3.11
22
23
/*
24
 * The main PAM interface for password changing.
25
 */
1.1.5 by Russ Allbery
Import upstream version 3.5
26
int
27
pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
28
{
29
    struct context *ctx = NULL;
30
    struct pam_args *args;
31
    int pamret = PAM_SUCCESS;
32
    int status;
1.1.6 by Russ Allbery
Import upstream version 3.8
33
    PAM_CONST char *user;
1.1.5 by Russ Allbery
Import upstream version 3.5
34
    char *pass = NULL;
35
36
    args = pamk5_args_parse(pamh, flags, argc, argv);
37
    if (args == NULL) {
1.1.14 by Russ Allbery
Import upstream version 4.1
38
        pamk5_crit(NULL, "cannot allocate memory: %s", strerror(errno));
1.1.5 by Russ Allbery
Import upstream version 3.5
39
        pamret = PAM_AUTHTOK_ERR;
40
        goto done;
41
    }
42
    pamret = pamk5_context_fetch(args);
43
    ENTRY(args, flags);
44
45
    /* We only support password changes. */
46
    if (!(flags & PAM_UPDATE_AUTHTOK) && !(flags & PAM_PRELIM_CHECK)) {
1.1.14 by Russ Allbery
Import upstream version 4.1
47
        pamk5_err(args, "invalid pam_chauthtok flags %d", flags);
1.1.5 by Russ Allbery
Import upstream version 3.5
48
        pamret = PAM_AUTHTOK_ERR;
49
        goto done;
50
    }
51
1.1.14 by Russ Allbery
Import upstream version 4.1
52
    /*
53
     * Check whether we should ignore this user.
54
     *
55
     * If we do ignore this user, and we're not in the preliminary check
56
     * phase, still prompt the user for the new password, but suppress our
57
     * banner.  This is a little strange, but it allows another module to be
58
     * stacked behind pam-krb5 with use_authtok and have it still work for
59
     * ignored users.
60
     *
61
     * We ignore the return status when prompting for the new password in this
62
     * case.  The worst thing that can happen is to fail to get the password,
63
     * in which case the other module will fail (or might even not care).
64
     */
1.1.5 by Russ Allbery
Import upstream version 3.5
65
    if (args->ignore_root || args->minimum_uid > 0) {
1.1.6 by Russ Allbery
Import upstream version 3.8
66
        status = pam_get_user(pamh, &user, NULL);
67
        if (status == PAM_SUCCESS && pamk5_should_ignore(args, user)) {
1.1.14 by Russ Allbery
Import upstream version 4.1
68
            if (flags & PAM_UPDATE_AUTHTOK) {
69
                if (args->banner != NULL) {
70
                    free(args->banner);
71
                    args->banner = NULL;
72
                }
73
                pamk5_password_prompt(args, NULL);
74
            }
13.1.1 by Russ Allbery
Return PAM_IGNORE for ignored users in pam_chauthtok instead of
75
            pamret = PAM_IGNORE;
1.1.5 by Russ Allbery
Import upstream version 3.5
76
            goto done;
77
        }
78
    }
79
80
    /*
81
     * If we weren't able to find an existing context to use, we're going
82
     * into this fresh and need to create a new context.
83
     */
84
    if (args->ctx == NULL) {
85
        pamret = pamk5_context_new(args);
86
        if (pamret != PAM_SUCCESS) {
1.1.14 by Russ Allbery
Import upstream version 4.1
87
            pamk5_debug_pam(args, pamret, "creating context failed");
1.1.5 by Russ Allbery
Import upstream version 3.5
88
            pamret = PAM_AUTHTOK_ERR;
89
            goto done;
90
        }
1.1.6 by Russ Allbery
Import upstream version 3.8
91
        pamret = pam_set_data(pamh, "pam_krb5", args->ctx,
92
                              pamk5_context_destroy);
1.1.5 by Russ Allbery
Import upstream version 3.5
93
        if (pamret != PAM_SUCCESS) {
1.1.14 by Russ Allbery
Import upstream version 4.1
94
            pamk5_err_pam(args, pamret, "cannot set context data");
1.1.5 by Russ Allbery
Import upstream version 3.5
95
            pamret = PAM_AUTHTOK_ERR;
96
            goto done;
97
        }
98
    }
99
    ctx = args->ctx;
100
1.1.9 by Russ Allbery
Import upstream version 3.11
101
    /* Tell the user what's going on if we're handling an expiration. */
102
    if (ctx->expired && ctx->creds == NULL)
103
        pamk5_conv(args, "Password expired.  You must change it now.",
104
                   PAM_TEXT_INFO, NULL);
105
1.1.13 by Russ Allbery
Import upstream version 4.0
106
    /*
107
     * Do the password change.  This may only get tickets if we're doing the
108
     * preliminary check phase.
109
     */
1.1.9 by Russ Allbery
Import upstream version 3.11
110
    pamret = pamk5_password_change(args, !(flags & PAM_UPDATE_AUTHTOK));
111
    if (!(flags & PAM_UPDATE_AUTHTOK))
112
        goto done;
1.1.5 by Russ Allbery
Import upstream version 3.5
113
114
    /*
1.1.9 by Russ Allbery
Import upstream version 3.11
115
     * If we were handling a password change for an expired password, now
116
     * try to get a ticket cache with the new password.
1.1.5 by Russ Allbery
Import upstream version 3.5
117
     */
1.1.9 by Russ Allbery
Import upstream version 3.11
118
    if (pamret == PAM_SUCCESS && ctx->expired) {
119
        krb5_creds *creds = NULL;
120
121
        pamk5_debug(args, "obtaining credentials with new password");
1.1.13 by Russ Allbery
Import upstream version 4.0
122
        args->force_first_pass = 1;
1.1.9 by Russ Allbery
Import upstream version 3.11
123
        pamret = pamk5_password_auth(args, NULL, &creds);
1.1.5 by Russ Allbery
Import upstream version 3.5
124
        if (pamret != PAM_SUCCESS)
125
            goto done;
1.1.9 by Russ Allbery
Import upstream version 3.11
126
        pamret = pamk5_cache_init_random(args, creds);
1.1.5 by Russ Allbery
Import upstream version 3.5
127
    }
128
129
done:
1.1.9 by Russ Allbery
Import upstream version 3.11
130
    if (pamret != PAM_SUCCESS) {
131
        if (pamret == PAM_SERVICE_ERR || pamret == PAM_AUTH_ERR)
132
            pamret = PAM_AUTHTOK_ERR;
133
        if (pamret == PAM_AUTHINFO_UNAVAIL)
134
            pamret = PAM_AUTHTOK_ERR;
135
    }
1.1.5 by Russ Allbery
Import upstream version 3.5
136
    EXIT(args, pamret);
137
    if (pass != NULL) {
138
        memset(pass, 0, strlen(pass));
139
        free(pass);
140
    }
141
    pamk5_args_free(args);
142
    return pamret;
143
}