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