1 /*
2 * $Source: /mit/kerberos/src/admin/RCS/kdb_edit.c,v $
3 * $Author: jtkohl $
4 *
5 * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute
6 * of Technology.
7 *
8 * For copying and distribution information, please see the file
9 * <mit-copyright.h>.
10 *
11 * This routine changes the Kerberos encryption keys for principals,
12 * i.e., users or services.
13 */
14
15 /*
16 * exit returns 0 ==> success -1 ==> error
17 */
18
19 #ifndef lint
20 static char rcsid_kdb_edit_c[] =
21 "$Header: kdb_edit.c,v 4.1 89/03/23 09:58:18 jtkohl Exp $";
22 #endif lint
23
24 #include <mit-copyright.h>
25
26 #include <stdio.h>
27 #include <signal.h>
28 #include <errno.h>
29 #include <strings.h>
30 #include <sys/ioctl.h>
31 #include <sys/file.h>
32 #include "time.h"
33 #include <des.h>
34 #include <krb.h>
35 #include <krb_db.h>
36 /* MKEYFILE is now defined in kdc.h */
37 #include <kdc.h>
38
39 extern char *errmsg();
40 extern int errno;
41 extern char *strcpy();
42
43 void sig_exit();
44
45 char prog[32];
46 char *progname = prog;
47 int nflag = 0;
48 int cflag;
49 int lflag;
50 int uflag;
51 int debug;
52 extern kerb_debug;
53 extern char *sys_errlist[];
54
55 Key_schedule KS;
56 C_Block new_key;
57 unsigned char *input;
58
59 unsigned char *ivec;
60 int i, j;
61 int more;
62
63 char *in_ptr;
64 char input_name[ANAME_SZ];
65 char input_instance[INST_SZ];
66 char input_string[ANAME_SZ];
67
68 #define MAX_PRINCIPAL 10
69 Principal principal_data[MAX_PRINCIPAL];
70
71 static Principal old_principal;
72 static Principal default_princ;
73
74 static C_Block master_key;
75 static C_Block session_key;
76 static Key_schedule master_key_schedule;
77 static char pw_str[255];
78 static long master_key_version;
79
80 #define gets(buf) _gets(buf, sizeof(buf)) /* hack */
81
82 char *
_gets(p,n)83 _gets(p, n)
84 char *p;
85 int n;
86 {
87 char *rv, *fgets();
88
89 if ((rv = fgets(p, n, stdin)) == NULL)
90 return (rv);
91 if (p = index(p, '\n'))
92 *p = '\0';
93 return (rv);
94 }
95
main(argc,argv)96 main(argc, argv)
97 int argc;
98 char *argv[];
99
100 {
101 /* Local Declarations */
102
103 long n;
104
105 prog[sizeof prog - 1] = '\0'; /* make sure terminated */
106 strncpy(prog, argv[0], sizeof prog - 1); /* salt away invoking
107 * program */
108
109 /* Assume a long is four bytes */
110 if (sizeof(long) != 4) {
111 fprintf(stdout, "%s: size of long is %d.\n", sizeof(long), prog);
112 exit(-1);
113 }
114 /* Assume <=32 signals */
115 if (NSIG > 32) {
116 fprintf(stderr, "%s: more than 32 signals defined.\n", prog);
117 exit(-1);
118 }
119 while (--argc > 0 && (*++argv)[0] == '-')
120 for (i = 1; argv[0][i] != '\0'; i++) {
121 switch (argv[0][i]) {
122
123 /* debug flag */
124 case 'd':
125 debug = 1;
126 continue;
127
128 /* debug flag */
129 case 'l':
130 kerb_debug |= 1;
131 continue;
132
133 case 'n': /* read MKEYFILE for master key */
134 nflag = 1;
135 continue;
136
137 default:
138 fprintf(stderr, "%s: illegal flag \"%c\"\n",
139 progname, argv[0][i]);
140 Usage(); /* Give message and die */
141 }
142 };
143
144 fprintf(stdout, "Opening database...\n");
145 fflush(stdout);
146 kerb_init();
147 if (argc > 0) {
148 if (kerb_db_set_name(*argv) != 0) {
149 fprintf(stderr, "Could not open altername database name\n");
150 exit(1);
151 }
152 }
153
154 #ifdef notdef
155 no_core_dumps(); /* diddle signals to avoid core dumps! */
156
157 /* ignore whatever is reasonable */
158 signal(SIGHUP, SIG_IGN);
159 signal(SIGINT, SIG_IGN);
160 signal(SIGTSTP, SIG_IGN);
161
162 #endif
163
164 if (kdb_get_master_key ((nflag == 0),
165 master_key, master_key_schedule) != 0) {
166 fprintf (stdout, "Couldn't read master key.\n");
167 fflush (stdout);
168 exit (-1);
169 }
170
171 if ((master_key_version = kdb_verify_master_key(master_key,
172 master_key_schedule,
173 stdout)) < 0)
174 exit (-1);
175
176 /* lookup the default values */
177 n = kerb_get_principal(KERB_DEFAULT_NAME, KERB_DEFAULT_INST,
178 &default_princ, 1, &more);
179 if (n != 1) {
180 fprintf(stderr,
181 "%s: Kerberos error on default value lookup, %d found.\n",
182 progname, n);
183 exit(-1);
184 }
185 fprintf(stdout, "Previous or default values are in [brackets] ,\n");
186 fprintf(stdout, "enter return to leave the same, or new value.\n");
187
188 while (change_principal()) {
189 }
190
191 cleanup();
192 }
193
change_principal()194 change_principal()
195 {
196 static char temp[255];
197 int creating = 0;
198 int editpw = 0;
199 int changed = 0;
200 long temp_long;
201 int n;
202 struct tm *tp, edate, *localtime();
203 long maketime();
204
205 fprintf(stdout, "\nPrincipal name: ");
206 fflush(stdout);
207 if (!gets(input_name) || *input_name == '\0')
208 return 0;
209 fprintf(stdout, "Instance: ");
210 fflush(stdout);
211 /* instance can be null */
212 gets(input_instance);
213 j = kerb_get_principal(input_name, input_instance, principal_data,
214 MAX_PRINCIPAL, &more);
215 if (!j) {
216 fprintf(stdout, "%s.%s not found, Create [y] ? ", input_name,
217 input_instance);
218 gets(temp); /* Default case should work, it didn't */
219 if (temp[0] != 'y' && temp[0] != 'Y' && temp[0] != '\0')
220 return -1;
221 /* make a new principal, fill in defaults */
222 j = 1;
223 creating = 1;
224 strcpy(principal_data[0].name, input_name);
225 strcpy(principal_data[0].instance, input_instance);
226 principal_data[0].old = NULL;
227 principal_data[0].exp_date = default_princ.exp_date;
228 principal_data[0].max_life = default_princ.max_life;
229 principal_data[0].attributes = default_princ.attributes;
230 principal_data[0].kdc_key_ver = (unsigned char) master_key_version;
231 principal_data[0].key_version = 0; /* bumped up later */
232 }
233 tp = localtime(&principal_data[0].exp_date);
234 (void) sprintf(principal_data[0].exp_date_txt, "%4d-%02d-%02d",
235 tp->tm_year > 1900 ? tp->tm_year : tp->tm_year + 1900,
236 tp->tm_mon + 1, tp->tm_mday); /* January is 0, not 1 */
237 for (i = 0; i < j; i++) {
238 for (;;) {
239 fprintf(stdout,
240 "Principal: %s, Instance: %s, kdc_key_ver: %d\n",
241 principal_data[i].name, principal_data[i].instance,
242 principal_data[i].kdc_key_ver);
243 editpw = 1;
244 changed = 0;
245 if (!creating) {
246 /*
247 * copy the existing data so we can use the old values
248 * for the qualifier clause of the replace
249 */
250 principal_data[i].old = (char *) &old_principal;
251 bcopy(&principal_data[i], &old_principal,
252 sizeof(old_principal));
253 printf("Change password [n] ? ");
254 gets(temp);
255 if (strcmp("y", temp) && strcmp("Y", temp))
256 editpw = 0;
257 }
258 /* password */
259 if (editpw) {
260 #ifdef NOENCRYPTION
261 placebo_read_pw_string(pw_str, sizeof pw_str,
262 "New Password: ", TRUE);
263 #else
264 des_read_pw_string(pw_str, sizeof pw_str,
265 "New Password: ", TRUE);
266 #endif
267 if (pw_str[0] == '\0' || !strcmp(pw_str, "RANDOM")) {
268 printf("Random password [y] ? ");
269 gets(temp);
270 if (!strcmp("n", temp) || !strcmp("N", temp)) {
271 /* no, use literal */
272 #ifdef NOENCRYPTION
273 bzero(new_key, sizeof(C_Block));
274 new_key[0] = 127;
275 #else
276 string_to_key(pw_str, new_key);
277 #endif
278 bzero(pw_str, sizeof pw_str); /* "RANDOM" */
279 } else {
280 #ifdef NOENCRYPTION
281 bzero(new_key, sizeof(C_Block));
282 new_key[0] = 127;
283 #else
284 random_key(new_key); /* yes, random */
285 #endif
286 bzero(pw_str, sizeof pw_str);
287 }
288 } else if (!strcmp(pw_str, "NULL")) {
289 printf("\nNull Key [y] ? ");
290 gets(temp);
291 if (!strcmp("n", temp) || !strcmp("N", temp)) {
292 /* no, use literal */
293 #ifdef NOENCRYPTION
294 bzero(new_key, sizeof(C_Block));
295 new_key[0] = 127;
296 #else
297 string_to_key(pw_str, new_key);
298 #endif
299 bzero(pw_str, sizeof pw_str); /* "NULL" */
300 } else {
301
302 principal_data[i].key_low = 0;
303 principal_data[i].key_high = 0;
304 goto null_key;
305 }
306 } else {
307 #ifdef NOENCRYPTION
308 bzero(new_key, sizeof(C_Block));
309 new_key[0] = 127;
310 #else
311 string_to_key(pw_str, new_key);
312 #endif
313 bzero(pw_str, sizeof pw_str);
314 }
315
316 /* seal it under the kerberos master key */
317 kdb_encrypt_key (new_key, new_key,
318 master_key, master_key_schedule,
319 ENCRYPT);
320 bcopy(new_key, &principal_data[i].key_low, 4);
321 bcopy(((long *) new_key) + 1,
322 &principal_data[i].key_high, 4);
323 bzero(new_key, sizeof(new_key));
324 null_key:
325 /* set master key version */
326 principal_data[i].kdc_key_ver =
327 (unsigned char) master_key_version;
328 /* bump key version # */
329 principal_data[i].key_version++;
330 fprintf(stdout,
331 "\nPrincipal's new key version = %d\n",
332 principal_data[i].key_version);
333 fflush(stdout);
334 changed = 1;
335 }
336 /* expiration date */
337 fprintf(stdout, "Expiration date (enter yyyy-mm-dd) [ %s ] ? ",
338 principal_data[i].exp_date_txt);
339 zaptime(&edate);
340 while (gets(temp) && ((n = strlen(temp)) >
341 sizeof(principal_data[0].exp_date_txt))) {
342 bad_date:
343 fprintf(stdout, "\07\07Date Invalid\n");
344 fprintf(stdout,
345 "Expiration date (enter yyyy-mm-dd) [ %s ] ? ",
346 principal_data[i].exp_date_txt);
347 zaptime(&edate);
348 }
349
350 if (*temp) {
351 if (sscanf(temp, "%d-%d-%d", &edate.tm_year,
352 &edate.tm_mon, &edate.tm_mday) != 3)
353 goto bad_date;
354 (void) strcpy(principal_data[i].exp_date_txt, temp);
355 edate.tm_mon--; /* January is 0, not 1 */
356 edate.tm_hour = 23; /* nearly midnight at the end of the */
357 edate.tm_min = 59; /* specified day */
358 edate.tm_zon = 1; /* local time, not GMT */
359 if (!(principal_data[i].exp_date = maketime(&edate)))
360 goto bad_date;
361 changed = 1;
362 }
363
364 /* maximum lifetime */
365 fprintf(stdout, "Max ticket lifetime (*5 minutes) [ %d ] ? ",
366 principal_data[i].max_life);
367 while (gets(temp) && *temp) {
368 if (sscanf(temp, "%d", &temp_long) != 1)
369 goto bad_life;
370 if (temp_long > 255 || (temp_long < 0)) {
371 bad_life:
372 fprintf(stdout, "\07\07Invalid, choose 0-255\n");
373 fprintf(stdout,
374 "Max ticket lifetime (*5 minutes) [ %d ] ? ",
375 principal_data[i].max_life);
376 continue;
377 }
378 changed = 1;
379 /* dont clobber */
380 principal_data[i].max_life = (unsigned short) temp_long;
381 break;
382 }
383
384 /* attributes */
385 fprintf(stdout, "Attributes [ %d ] ? ",
386 principal_data[i].attributes);
387 while (gets(temp) && *temp) {
388 if (sscanf(temp, "%d", &temp_long) != 1)
389 goto bad_att;
390 if (temp_long > 65535 || (temp_long < 0)) {
391 bad_att:
392 fprintf(stdout, "\07\07Invalid, choose 0-65535\n");
393 fprintf(stdout, "Attributes [ %d ] ? ",
394 principal_data[i].attributes);
395 continue;
396 }
397 changed = 1;
398 /* dont clobber */
399 principal_data[i].attributes =
400 (unsigned short) temp_long;
401 break;
402 }
403
404 /*
405 * remaining fields -- key versions and mod info, should
406 * not be directly manipulated
407 */
408 if (changed) {
409 if (kerb_put_principal(&principal_data[i], 1)) {
410 fprintf(stdout,
411 "\nError updating Kerberos database");
412 } else {
413 fprintf(stdout, "Edit O.K.");
414 }
415 } else {
416 fprintf(stdout, "Unchanged");
417 }
418
419
420 bzero(&principal_data[i].key_low, 4);
421 bzero(&principal_data[i].key_high, 4);
422 fflush(stdout);
423 break;
424 }
425 }
426 if (more) {
427 fprintf(stdout, "\nThere were more tuples found ");
428 fprintf(stdout, "than there were space for");
429 }
430 return 1;
431 }
432
433
no_core_dumps()434 no_core_dumps()
435 {
436
437 signal(SIGQUIT, sig_exit);
438 signal(SIGILL, sig_exit);
439 signal(SIGTRAP, sig_exit);
440 signal(SIGIOT, sig_exit);
441 signal(SIGEMT, sig_exit);
442 signal(SIGFPE, sig_exit);
443 signal(SIGBUS, sig_exit);
444 signal(SIGSEGV, sig_exit);
445 signal(SIGSYS, sig_exit);
446 }
447
448 void
sig_exit(sig,code,scp)449 sig_exit(sig, code, scp)
450 int sig, code;
451 struct sigcontext *scp;
452 {
453 cleanup();
454 fprintf(stderr,
455 "\nSignal caught, sig = %d code = %d old pc = 0x%X \nexiting",
456 sig, code, scp->sc_pc);
457 exit(-1);
458 }
459
460
cleanup()461 cleanup()
462 {
463
464 bzero(master_key, sizeof(master_key));
465 bzero(session_key, sizeof(session_key));
466 bzero(master_key_schedule, sizeof(master_key_schedule));
467 bzero(principal_data, sizeof(principal_data));
468 bzero(new_key, sizeof(new_key));
469 bzero(pw_str, sizeof(pw_str));
470 }
Usage()471 Usage()
472 {
473 fprintf(stderr, "Usage: %s [-n]\n", progname);
474 exit(1);
475 }
476
477 /* zaptime code taken from: */
478 /*
479 * PARTIME parse date/time string into a TM structure
480 *
481 * Usage:
482 * #include "time.h" -- expanded tm structure
483 * char *str; struct tm *tp;
484 * partime(str,tp);
485 * Returns:
486 * 0 if parsing failed
487 * else time values in specified TM structure (unspecified values
488 * set to TMNULL)
489 * Notes:
490 * This code is quasi-public; it may be used freely in like software.
491 * It is not to be sold, nor used in licensed software without
492 * permission of the author.
493 * For everyone's benefit, please report bugs and improvements!
494 * Copyright 1980 by Ken Harrenstien, SRI International.
495 * (ARPANET: KLH @ SRI)
496 */
497
zaptime(atm)498 zaptime(atm)
499 register struct tm *atm;
500 /* clears atm */
501 {
502 atm->tm_sec = TMNULL;
503 atm->tm_min = TMNULL;
504 atm->tm_hour = TMNULL;
505 atm->tm_mday = TMNULL;
506 atm->tm_mon = TMNULL;
507 atm->tm_year = TMNULL;
508 atm->tm_wday = TMNULL;
509 atm->tm_yday = TMNULL;
510 atm->tm_isdst = TMNULL;
511 atm->tm_zon = TMNULL;
512 atm->tm_ampm = TMNULL;
513 }
514