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 *
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 
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 
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 
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
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 
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 }
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 
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