summaryrefslogtreecommitdiffstats
path: root/src/clients/kpasswd/kpasswd.c
blob: 9f4952bb82d8b4a1835b8519118a7305cf0d6264 (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#include <locale.h>
#include <stdio.h>
#include <sys/types.h>
#include "k5-platform.h"

#ifndef _WIN32
#include <unistd.h>
#endif

#include <krb5.h>

#define P1 _("Enter new password")
#define P2 _("Enter it again")

#ifdef HAVE_PWD_H
#include <pwd.h>

static
void get_name_from_passwd_file(program_name, kcontext, me)
    char * program_name;
    krb5_context kcontext;
    krb5_principal * me;
{
    struct passwd *pw;
    krb5_error_code code;
    if ((pw = getpwuid(getuid()))) {
        if ((code = krb5_parse_name(kcontext, pw->pw_name, me))) {
            com_err(program_name, code, _("when parsing name %s"),
                    pw->pw_name);
            exit(1);
        }
    } else {
        fprintf(stderr, _("Unable to identify user from password file\n"));
        exit(1);
    }
}
#else /* HAVE_PWD_H */
void get_name_from_passwd_file(kcontext, me)
    krb5_context kcontext;
    krb5_principal * me;
{
    fprintf(stderr, _("Unable to identify user\n"));
    exit(1);
}
#endif /* HAVE_PWD_H */

int main(int argc, char *argv[])
{
    krb5_error_code ret;
    krb5_context context;
    krb5_principal princ = NULL;
    char *pname;
    krb5_ccache ccache;
    krb5_get_init_creds_opt *opts = NULL;
    krb5_creds creds;
    char *message;

    char pw[1024];
    unsigned int pwlen;
    int result_code;
    krb5_data result_code_string, result_string;

    setlocale(LC_ALL, "");
    if (argc > 2) {
        fprintf(stderr, _("usage: %s [principal]\n"), argv[0]);
        exit(1);
    }

    pname = argv[1];

    ret = krb5_init_context(&context);
    if (ret) {
        com_err(argv[0], ret, _("initializing kerberos library"));
        exit(1);
    }
    if ((ret = krb5_get_init_creds_opt_alloc(context, &opts))) {
        com_err(argv[0], ret, _("allocating krb5_get_init_creds_opt"));
        exit(1);
    }

    /* in order, use the first of:
       - a name specified on the command line
       - the principal name from an existing ccache
       - the name corresponding to the ruid of the process

       otherwise, it's an error.
       We always attempt to open the default ccache in order to use FAST if
       possible.
    */
    ret = krb5_cc_default(context, &ccache);
    if (ret != 0) {
        com_err(argv[0], ret, _("opening default ccache"));
        exit(1);
    }
    ret = krb5_cc_get_principal(context, ccache, &princ);
    if (ret != 0 && ret != KRB5_CC_NOTFOUND && ret != KRB5_FCC_NOFILE) {
        com_err(argv[0], ret, _("getting principal from ccache"));
        exit(1);
    } else {
        if (princ != NULL) {
            ret = krb5_get_init_creds_opt_set_fast_ccache(context, opts,
                                                          ccache);
            if (ret) {
                com_err(argv[0], ret, _("while setting FAST ccache"));
                exit(1);
            }
        }
    }
    ret = krb5_cc_close(context, ccache);
    if (ret != 0) {
        com_err(argv[0], ret, _("closing ccache"));
        exit(1);
    }
    if (pname) {
        krb5_free_principal(context, princ);
        princ = NULL;
        if ((ret = krb5_parse_name(context, pname, &princ))) {
            com_err(argv[0], ret, _("parsing client name"));
            exit(1);
        }
    }
    if (princ == NULL)
        get_name_from_passwd_file(argv[0], context, &princ);

    krb5_get_init_creds_opt_set_tkt_life(opts, 5*60);
    krb5_get_init_creds_opt_set_renew_life(opts, 0);
    krb5_get_init_creds_opt_set_forwardable(opts, 0);
    krb5_get_init_creds_opt_set_proxiable(opts, 0);

    if ((ret = krb5_get_init_creds_password(context, &creds, princ, NULL,
                                            krb5_prompter_posix, NULL,
                                            0, "kadmin/changepw", opts))) {
        if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY)
            com_err(argv[0], 0,
                    _("Password incorrect while getting initial ticket"));
        else
            com_err(argv[0], ret, _("getting initial ticket"));
        krb5_get_init_creds_opt_free(context, opts);
        exit(1);
    }

    pwlen = sizeof(pw);
    if ((ret = krb5_read_password(context, P1, P2, pw, &pwlen))) {
        com_err(argv[0], ret, _("while reading password"));
        krb5_get_init_creds_opt_free(context, opts);
        exit(1);
    }

    if ((ret = krb5_change_password(context, &creds, pw,
                                    &result_code, &result_code_string,
                                    &result_string))) {
        com_err(argv[0], ret, _("changing password"));
        krb5_get_init_creds_opt_free(context, opts);
        exit(1);
    }

    if (result_code) {
        if (krb5_chpw_message(context, &result_string, &message) != 0)
            message = NULL;
        printf("%.*s%s%s\n",
               (int) result_code_string.length, result_code_string.data,
               message ? ": " : "", message ? message : NULL);
        krb5_free_string(context, message);
        krb5_get_init_creds_opt_free(context, opts);
        exit(2);
    }

    if (result_string.data != NULL)
        free(result_string.data);
    if (result_code_string.data != NULL)
        free(result_code_string.data);
    krb5_get_init_creds_opt_free(context, opts);

    printf(_("Password changed.\n"));
    exit(0);
}