1 | /* |
---|
2 | * kpasswd.c |
---|
3 | * |
---|
4 | * Copyright 1988 by the Massachusetts Institute of Technology. |
---|
5 | * |
---|
6 | * For copying and distribution information, please see the file |
---|
7 | * <mit-copyright.h>. |
---|
8 | * |
---|
9 | * change your password with kerberos |
---|
10 | */ |
---|
11 | |
---|
12 | #include <mit-copyright.h> |
---|
13 | /* |
---|
14 | * kpasswd |
---|
15 | * change your password with kerberos |
---|
16 | */ |
---|
17 | |
---|
18 | #include <stdio.h> |
---|
19 | #include <string.h> |
---|
20 | #include <sys/types.h> |
---|
21 | #include <sys/param.h> |
---|
22 | #include <pwd.h> |
---|
23 | #include <kadm_err.h> |
---|
24 | #include "kadm.h" |
---|
25 | |
---|
26 | extern void krb_set_tkt_string(); |
---|
27 | static int using_preauth = 0; |
---|
28 | |
---|
29 | static int oldhist[256], newhist[256]; |
---|
30 | |
---|
31 | main(argc,argv) |
---|
32 | int argc; |
---|
33 | char *argv[]; |
---|
34 | { |
---|
35 | char name[ANAME_SZ]; /* name of user */ |
---|
36 | char inst[INST_SZ]; /* instance of user */ |
---|
37 | char realm[REALM_SZ]; /* realm of user */ |
---|
38 | char default_name[ANAME_SZ]; |
---|
39 | char default_inst[INST_SZ]; |
---|
40 | char default_realm[REALM_SZ]; |
---|
41 | int realm_given = 0; /* True if realm was give on cmdline */ |
---|
42 | int use_default = 1; /* True if we should use default name */ |
---|
43 | int skip_old = 0; /* True if we should skip getting old pw */ |
---|
44 | struct passwd *pw; |
---|
45 | int status; /* return code */ |
---|
46 | des_cblock new_key; |
---|
47 | char pword[MAX_KPW_LEN]; /* storage for the password */ |
---|
48 | int c; |
---|
49 | extern char *optarg; |
---|
50 | extern int optind; |
---|
51 | char tktstring[MAXPATHLEN]; |
---|
52 | char *ret_st; |
---|
53 | |
---|
54 | void get_pw_new_key(); |
---|
55 | |
---|
56 | #ifdef NOENCRYPTION |
---|
57 | #define read_long_pw_string placebo_read_pw_string |
---|
58 | #else |
---|
59 | #define read_long_pw_string des_read_pw_string |
---|
60 | #endif |
---|
61 | int read_long_pw_string(); |
---|
62 | |
---|
63 | memset(name, 0, sizeof(name)); |
---|
64 | memset(inst, 0, sizeof(inst)); |
---|
65 | memset(realm, 0, sizeof(realm)); |
---|
66 | |
---|
67 | if (krb_get_tf_fullname(TKT_FILE, default_name, default_inst, |
---|
68 | default_realm) != KSUCCESS) { |
---|
69 | pw = getpwuid((int) getuid()); |
---|
70 | if (pw) |
---|
71 | (void) strcpy(default_name, pw->pw_name); |
---|
72 | else |
---|
73 | /* seems like a null name is kinda silly */ |
---|
74 | (void) strcpy(default_name, ""); |
---|
75 | strcpy(default_inst, ""); |
---|
76 | if (krb_get_lrealm(default_realm, 1) != KSUCCESS) |
---|
77 | strcpy(default_realm, KRB_REALM); |
---|
78 | } |
---|
79 | |
---|
80 | while ((c = getopt(argc, argv, "u:n:i:r:hp")) != EOF) { |
---|
81 | switch (c) { |
---|
82 | case 'u': |
---|
83 | if (status = kname_parse(name, inst, realm, optarg)) { |
---|
84 | fprintf(stderr, "Kerberos error: %s\n", |
---|
85 | krb_get_err_text(status)); |
---|
86 | exit(2); |
---|
87 | } |
---|
88 | if (realm[0]) |
---|
89 | realm_given++; |
---|
90 | else |
---|
91 | if (krb_get_lrealm(realm, 1) != KSUCCESS) |
---|
92 | strcpy(realm, KRB_REALM); |
---|
93 | break; |
---|
94 | case 'n': |
---|
95 | if (k_isname(optarg)) |
---|
96 | (void) strncpy(name, optarg, sizeof(name) - 1); |
---|
97 | else { |
---|
98 | fprintf(stderr, "Bad name: %s\n", optarg); |
---|
99 | usage(1); |
---|
100 | } |
---|
101 | break; |
---|
102 | case 'i': |
---|
103 | if (k_isinst(optarg)) |
---|
104 | (void) strncpy(inst, optarg, sizeof(inst) - 1); |
---|
105 | else { |
---|
106 | fprintf(stderr, "Bad instance: %s\n", optarg); |
---|
107 | usage(1); |
---|
108 | } |
---|
109 | (void) strcpy(inst, optarg); |
---|
110 | break; |
---|
111 | case 'r': |
---|
112 | if (k_isrealm(optarg)) { |
---|
113 | (void) strncpy(realm, optarg, sizeof(realm) - 1); |
---|
114 | realm_given++; |
---|
115 | } |
---|
116 | else { |
---|
117 | fprintf(stderr, "Bad realm: %s\n", optarg); |
---|
118 | usage(1); |
---|
119 | } |
---|
120 | break; |
---|
121 | case 'h': |
---|
122 | usage(0); |
---|
123 | break; |
---|
124 | case 'p': |
---|
125 | using_preauth++; |
---|
126 | break; |
---|
127 | default: |
---|
128 | usage(1); |
---|
129 | break; |
---|
130 | } |
---|
131 | use_default = 0; |
---|
132 | } |
---|
133 | if (optind < argc) |
---|
134 | usage(1); |
---|
135 | |
---|
136 | if (use_default) { |
---|
137 | strcpy(name, default_name); |
---|
138 | strcpy(inst, default_inst); |
---|
139 | strcpy(realm, default_realm); |
---|
140 | } |
---|
141 | else { |
---|
142 | if (!name[0]) |
---|
143 | strcpy(name, default_name); |
---|
144 | if (!realm[0]) |
---|
145 | strcpy(realm, default_realm); |
---|
146 | } |
---|
147 | |
---|
148 | (void) sprintf(tktstring, "/tmp/tkt_cpw_%d",getpid()); |
---|
149 | krb_set_tkt_string(tktstring); |
---|
150 | |
---|
151 | try_again: |
---|
152 | get_pw_new_key(new_key, pword, name, inst, realm, realm_given, skip_old); |
---|
153 | skip_old++; |
---|
154 | |
---|
155 | if ((status = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm)) |
---|
156 | != KADM_SUCCESS) { |
---|
157 | com_err(argv[0], status, "while initializing"); |
---|
158 | memset(pword, 0, sizeof(pword)); |
---|
159 | } else { |
---|
160 | #ifdef CHECK_ONLY |
---|
161 | status = kadm_check_pw(new_key, pword, (u_char **)&ret_st); |
---|
162 | #else |
---|
163 | status = kadm_change_pw2(new_key, pword, (u_char **)&ret_st); |
---|
164 | #endif |
---|
165 | memset(pword, 0, sizeof(pword)); |
---|
166 | if (ret_st) { |
---|
167 | printf("\n%s\n", ret_st); |
---|
168 | free(ret_st); |
---|
169 | } |
---|
170 | if (status != KADM_SUCCESS) |
---|
171 | com_err(argv[0], status, |
---|
172 | "while attempting to change password."); |
---|
173 | if (status == KADM_DB_INUSE) |
---|
174 | com_err(argv[0], 0, "Please try again later."); |
---|
175 | if (status == KADM_INSECURE_PW) { |
---|
176 | printf("Please choose another password.\n\n"); |
---|
177 | goto try_again; |
---|
178 | } |
---|
179 | } |
---|
180 | |
---|
181 | #ifdef CHECK_ONLY |
---|
182 | fprintf(stderr, "Passwrd NOT changed --- this is a test version of kpasswd.\n"); |
---|
183 | #else |
---|
184 | if (status != KADM_SUCCESS) |
---|
185 | fprintf(stderr,"Password NOT changed.\n"); |
---|
186 | else |
---|
187 | printf("Password changed.\n"); |
---|
188 | #endif |
---|
189 | |
---|
190 | (void) dest_tkt(); |
---|
191 | if (status) |
---|
192 | exit(2); |
---|
193 | else |
---|
194 | exit(0); |
---|
195 | } |
---|
196 | |
---|
197 | void get_pw_new_key(new_key, pword, name, inst, realm, print_realm, skip_old) |
---|
198 | des_cblock new_key; |
---|
199 | char *pword; |
---|
200 | char *name; |
---|
201 | char *inst; |
---|
202 | char *realm; |
---|
203 | int print_realm; /* True if realm was give on cmdline */ |
---|
204 | int skip_old; |
---|
205 | { |
---|
206 | char ppromp[40+ANAME_SZ+INST_SZ+REALM_SZ]; /* for the password prompt */ |
---|
207 | char npromp[40+ANAME_SZ+INST_SZ+REALM_SZ]; /* for the password prompt */ |
---|
208 | |
---|
209 | char local_realm[REALM_SZ]; |
---|
210 | int status, diff, i, d; |
---|
211 | char *s; |
---|
212 | |
---|
213 | /* |
---|
214 | * We don't care about failure; this is to determine whether or |
---|
215 | * not to print the realm in the prompt for a new password. |
---|
216 | */ |
---|
217 | (void) krb_get_lrealm(local_realm, 1); |
---|
218 | |
---|
219 | if (strcmp(local_realm, realm)) |
---|
220 | print_realm++; |
---|
221 | |
---|
222 | if (!skip_old) { |
---|
223 | (void) sprintf(ppromp,"Old password for %s%s%s%s%s:", |
---|
224 | name, *inst ? "." : "", inst, |
---|
225 | print_realm ? "@" : "", print_realm ? realm : ""); |
---|
226 | if (read_long_pw_string(pword, MAX_KPW_LEN-1, ppromp, 0)) { |
---|
227 | fprintf(stderr, "Error reading old password.\n"); |
---|
228 | exit(1); |
---|
229 | } |
---|
230 | |
---|
231 | if (using_preauth) |
---|
232 | status = krb_get_pw_in_tkt_preauth(name, inst, realm, PWSERV_NAME, |
---|
233 | KADM_SINST, 1, pword); |
---|
234 | else |
---|
235 | status = krb_get_pw_in_tkt(name, inst, realm, PWSERV_NAME, |
---|
236 | KADM_SINST, 1, pword); |
---|
237 | |
---|
238 | if (status != KSUCCESS) { |
---|
239 | if (status == INTK_BADPW) { |
---|
240 | printf("Incorrect old password.\n"); |
---|
241 | exit(0); |
---|
242 | } |
---|
243 | else { |
---|
244 | fprintf(stderr, "Kerberos error: %s\n", |
---|
245 | krb_get_err_text(status)); |
---|
246 | exit(1); |
---|
247 | } |
---|
248 | } |
---|
249 | for (i = 0; i < 256; i++) |
---|
250 | oldhist[i] = 0; |
---|
251 | for (s = pword; *s; s++) |
---|
252 | oldhist[*s & 0xff]++; |
---|
253 | } |
---|
254 | do { |
---|
255 | (void) sprintf(npromp,"New Password for %s%s%s%s%s:", |
---|
256 | name, *inst ? "." : "", inst, |
---|
257 | print_realm ? "@" : "", print_realm ? realm : ""); |
---|
258 | if (read_long_pw_string(pword, MAX_KPW_LEN-1, npromp, 1)) |
---|
259 | go_home("Error reading new password, password unchanged.\n",0); |
---|
260 | if (strlen(pword) == 0) |
---|
261 | printf("Null passwords are not allowed; try again.\n"); |
---|
262 | for (i = 0; i < 256; i++) |
---|
263 | newhist[i] = 0; |
---|
264 | for (s = pword; *s; s++) |
---|
265 | newhist[*s & 0xff]++; |
---|
266 | for (i = 0, diff = 0; i < 256; i++) { |
---|
267 | d = newhist[i] - oldhist[i]; |
---|
268 | if (d > 0) |
---|
269 | diff += d; |
---|
270 | else |
---|
271 | diff -= d; |
---|
272 | } |
---|
273 | if (diff < 3) { |
---|
274 | printf ("Password too similar to previous; try again.\n"); |
---|
275 | pword[0] = 0; |
---|
276 | } |
---|
277 | } while (strlen(pword) == 0); |
---|
278 | |
---|
279 | #ifdef NOENCRYPTION |
---|
280 | memset((char *) new_key, 0, sizeof(des_cblock)); |
---|
281 | new_key[0] = (unsigned char) 1; |
---|
282 | #else |
---|
283 | (void) des_string_to_key(pword, new_key); |
---|
284 | #endif |
---|
285 | } |
---|
286 | |
---|
287 | usage(value) |
---|
288 | int value; |
---|
289 | { |
---|
290 | fprintf(stderr, "Usage: "); |
---|
291 | fprintf(stderr, "kpasswd [-h ] [-n user] [-i instance] [-r realm] [-p] "); |
---|
292 | fprintf(stderr, "[-u fullname]\n"); |
---|
293 | exit(value); |
---|
294 | } |
---|
295 | |
---|
296 | go_home(str,x) |
---|
297 | char *str; |
---|
298 | int x; |
---|
299 | { |
---|
300 | fprintf(stderr, str, x); |
---|
301 | (void) dest_tkt(); |
---|
302 | exit(1); |
---|
303 | } |
---|
304 | |
---|
305 | /* ksrvutil can fail due to talking to the wrong KDC. kpasswd will only |
---|
306 | confuse the user, as the password will still get tickets, and that will |
---|
307 | suffice for the change. However, the user may find it confusing if they |
---|
308 | change passwords quickly and it doesn't work, so for now we have them |
---|
309 | talk to the master for everything. In the long run, we would want to |
---|
310 | change the protocol. |
---|
311 | */ |
---|
312 | krb_get_krbhst(h,r,n) |
---|
313 | char *h; |
---|
314 | char *r; |
---|
315 | int n; |
---|
316 | { |
---|
317 | return krb_get_admhst(h, r, n); |
---|
318 | } |
---|