xref: /freebsd/crypto/krb5/src/clients/kpasswd/kpasswd.c (revision 4b15965daa99044daf184221b7c283bf7f2d7e66)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 
3 #include "k5-platform.h"
4 #include <locale.h>
5 #include <sys/types.h>
6 
7 #ifndef _WIN32
8 #include <unistd.h>
9 #endif
10 
11 #include <krb5.h>
12 
13 #define P1 _("Enter new password")
14 #define P2 _("Enter it again")
15 
16 #ifdef HAVE_PWD_H
17 #include <pwd.h>
18 
19 static void
20 get_name_from_passwd_file(char *program_name, krb5_context context,
21                           krb5_principal *me)
22 {
23     struct passwd *pw;
24     krb5_error_code ret;
25 
26     pw = getpwuid(getuid());
27     if (pw != NULL) {
28         ret = krb5_parse_name(context, pw->pw_name, me);
29         if (ret) {
30             com_err(program_name, ret, _("when parsing name %s"), pw->pw_name);
31             exit(1);
32         }
33     } else {
34         fprintf(stderr, _("Unable to identify user from password file\n"));
35         exit(1);
36     }
37 }
38 #else /* HAVE_PWD_H */
39 static void
40 get_name_from_passwd_file(char *program_name, krb5_context context,
41                           krb5_principal *me)
42 {
43     fprintf(stderr, _("Unable to identify user\n"));
44     exit(1);
45 }
46 #endif /* HAVE_PWD_H */
47 
48 int main(int argc, char *argv[])
49 {
50     krb5_error_code ret;
51     krb5_context context;
52     krb5_principal princ = NULL;
53     char *pname, *message;
54     char pw[1024];
55     krb5_ccache ccache;
56     krb5_get_init_creds_opt *opts = NULL;
57     krb5_creds creds;
58     unsigned int pwlen;
59     int result_code;
60     krb5_data result_code_string, result_string;
61 
62     setlocale(LC_ALL, "");
63     if (argc > 2) {
64         fprintf(stderr, _("usage: %s [principal]\n"), argv[0]);
65         exit(1);
66     }
67 
68     pname = argv[1];
69 
70     ret = krb5_init_context(&context);
71     if (ret) {
72         com_err(argv[0], ret, _("initializing kerberos library"));
73         exit(1);
74     }
75     ret = krb5_get_init_creds_opt_alloc(context, &opts);
76     if (ret) {
77         com_err(argv[0], ret, _("allocating krb5_get_init_creds_opt"));
78         exit(1);
79     }
80 
81     /*
82      * In order, use the first of:
83      * - A name specified on the command line
84      * - The principal name from an existing ccache
85      * - The name corresponding to the ruid of the process
86      *
87      * Otherwise, it's an error.
88      * We always attempt to open the default ccache in order to use FAST if
89      * possible.
90      */
91     ret = krb5_cc_default(context, &ccache);
92     if (ret) {
93         com_err(argv[0], ret, _("opening default ccache"));
94         exit(1);
95     }
96     ret = krb5_cc_get_principal(context, ccache, &princ);
97     if (ret && ret != KRB5_CC_NOTFOUND && ret != KRB5_FCC_NOFILE) {
98         com_err(argv[0], ret, _("getting principal from ccache"));
99         exit(1);
100     } else if (princ != NULL) {
101         ret = krb5_get_init_creds_opt_set_fast_ccache(context, opts, ccache);
102         if (ret) {
103             com_err(argv[0], ret, _("while setting FAST ccache"));
104             exit(1);
105         }
106     }
107     ret = krb5_cc_close(context, ccache);
108     if (ret) {
109         com_err(argv[0], ret, _("closing ccache"));
110         exit(1);
111     }
112     if (pname != NULL) {
113         krb5_free_principal(context, princ);
114         princ = NULL;
115         ret = krb5_parse_name(context, pname, &princ);
116         if (ret) {
117             com_err(argv[0], ret, _("parsing client name"));
118             exit(1);
119         }
120     }
121     if (princ == NULL)
122         get_name_from_passwd_file(argv[0], context, &princ);
123 
124     krb5_get_init_creds_opt_set_tkt_life(opts, 5 * 60);
125     krb5_get_init_creds_opt_set_renew_life(opts, 0);
126     krb5_get_init_creds_opt_set_forwardable(opts, 0);
127     krb5_get_init_creds_opt_set_proxiable(opts, 0);
128 
129     ret = krb5_get_init_creds_password(context, &creds, princ, NULL,
130                                        krb5_prompter_posix, NULL, 0,
131                                        "kadmin/changepw", opts);
132     if (ret) {
133         if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY) {
134             com_err(argv[0], 0,
135                     _("Password incorrect while getting initial ticket"));
136         } else {
137             com_err(argv[0], ret, _("getting initial ticket"));
138         }
139 
140         krb5_get_init_creds_opt_free(context, opts);
141         exit(1);
142     }
143 
144     pwlen = sizeof(pw);
145     ret = krb5_read_password(context, P1, P2, pw, &pwlen);
146     if (ret) {
147         com_err(argv[0], ret, _("while reading password"));
148         krb5_get_init_creds_opt_free(context, opts);
149         exit(1);
150     }
151 
152     ret = krb5_change_password(context, &creds, pw, &result_code,
153                                &result_code_string, &result_string);
154     if (ret) {
155         com_err(argv[0], ret, _("changing password"));
156         krb5_get_init_creds_opt_free(context, opts);
157         exit(1);
158     }
159 
160     if (result_code) {
161         if (krb5_chpw_message(context, &result_string, &message) != 0)
162             message = NULL;
163         printf("%.*s%s%s\n",
164                (int)result_code_string.length, result_code_string.data,
165                message ? ": " : "", message ? message : NULL);
166         krb5_free_string(context, message);
167         krb5_get_init_creds_opt_free(context, opts);
168         exit(2);
169     }
170 
171     free(result_string.data);
172     free(result_code_string.data);
173     krb5_get_init_creds_opt_free(context, opts);
174 
175     printf(_("Password changed.\n"));
176     exit(0);
177 }
178