1 | /* |
---|
2 | * Copyright 1987, 1988 by the Massachusetts Institute of Technology. |
---|
3 | * |
---|
4 | * For copying and distribution information, please see the file |
---|
5 | * <mit-copyright.h>. |
---|
6 | * |
---|
7 | * Kerberos database manipulation utility. This program allows you to |
---|
8 | * dump a kerberos database to an ascii readable file and load this |
---|
9 | * file into the database. Read locking of the database is done during a |
---|
10 | * dump operation. NO LOCKING is done during a load operation. Loads |
---|
11 | * should happen with other processes shutdown. |
---|
12 | * |
---|
13 | * Written July 9, 1987 by Jeffrey I. Schiller |
---|
14 | */ |
---|
15 | |
---|
16 | #include <mit-copyright.h> |
---|
17 | #include <stdio.h> |
---|
18 | #include <sys/types.h> |
---|
19 | #include <netinet/in.h> |
---|
20 | |
---|
21 | #ifdef NEED_TIME_H |
---|
22 | #include <time.h> |
---|
23 | #endif |
---|
24 | #include <sys/time.h> |
---|
25 | |
---|
26 | #include <string.h> |
---|
27 | #include <des.h> |
---|
28 | #include <krb.h> |
---|
29 | #include <sys/file.h> |
---|
30 | #ifdef NEED_SYS_FCNTL_H |
---|
31 | #include <sys/fcntl.h> |
---|
32 | #endif |
---|
33 | #include <krb_db.h> |
---|
34 | |
---|
35 | #define TRUE 1 |
---|
36 | |
---|
37 | Principal aprinc; |
---|
38 | |
---|
39 | static des_cblock master_key, new_master_key; |
---|
40 | static des_key_schedule master_key_schedule, new_master_key_schedule; |
---|
41 | |
---|
42 | #define zaptime(foo) memset((char *)(foo), 0, sizeof(*(foo))) |
---|
43 | |
---|
44 | extern long kdb_get_master_key(), kdb_verify_master_key(); |
---|
45 | extern char *malloc(); |
---|
46 | extern int errno; |
---|
47 | |
---|
48 | main(argc, argv) |
---|
49 | int argc; |
---|
50 | char **argv; |
---|
51 | { |
---|
52 | FILE *file; |
---|
53 | enum { |
---|
54 | OP_LOAD, |
---|
55 | OP_DUMP, |
---|
56 | OP_SLAVE_DUMP, |
---|
57 | OP_NEW_MASTER, |
---|
58 | OP_CONVERT_OLD_DB |
---|
59 | } op; |
---|
60 | char *file_name; |
---|
61 | char *prog = argv[0]; |
---|
62 | char *db_name; |
---|
63 | |
---|
64 | if (argc != 3 && argc != 4) { |
---|
65 | fprintf(stderr, "Usage: %s operation file-name [database name].\n", |
---|
66 | argv[0]); |
---|
67 | exit(1); |
---|
68 | } |
---|
69 | if (argc == 3) |
---|
70 | db_name = DBM_FILE; |
---|
71 | else |
---|
72 | db_name = argv[3]; |
---|
73 | |
---|
74 | if (kerb_db_set_name (db_name) != 0) { |
---|
75 | perror("Can't open database"); |
---|
76 | exit(1); |
---|
77 | } |
---|
78 | |
---|
79 | if (!strcmp(argv[1], "load")) |
---|
80 | op = OP_LOAD; |
---|
81 | else if (!strcmp(argv[1], "dump")) |
---|
82 | op = OP_DUMP; |
---|
83 | else if (!strcmp(argv[1], "slave_dump")) |
---|
84 | op = OP_SLAVE_DUMP; |
---|
85 | else if (!strcmp(argv[1], "new_master_key")) |
---|
86 | op = OP_NEW_MASTER; |
---|
87 | else if (!strcmp(argv[1], "convert_old_db")) |
---|
88 | op = OP_CONVERT_OLD_DB; |
---|
89 | else { |
---|
90 | fprintf(stderr, |
---|
91 | "%s: %s is an invalid operation.\n", prog, argv[1]); |
---|
92 | fprintf(stderr, |
---|
93 | "%s: Valid operations are \"dump\", \"slave_dump\",", argv[0]); |
---|
94 | fprintf(stderr, |
---|
95 | "\"load\", \"new_master_key\", and \"convert_old_db\".\n"); |
---|
96 | exit(1); |
---|
97 | } |
---|
98 | |
---|
99 | file_name = argv[2]; |
---|
100 | file = fopen(file_name, op == OP_LOAD ? "r" : "w"); |
---|
101 | if (file == NULL) { |
---|
102 | fprintf(stderr, "%s: Unable to open %s\n", prog, argv[2]); |
---|
103 | (void) fflush(stderr); |
---|
104 | perror("open"); |
---|
105 | exit(1); |
---|
106 | } |
---|
107 | |
---|
108 | switch (op) { |
---|
109 | case OP_DUMP: |
---|
110 | if ((dump_db (db_name, file, (void (*)()) 0) == EOF) || |
---|
111 | (fclose(file) == EOF)) { |
---|
112 | fprintf(stderr, "error on file %s:", file_name); |
---|
113 | perror(""); |
---|
114 | exit(1); |
---|
115 | } |
---|
116 | break; |
---|
117 | case OP_SLAVE_DUMP: |
---|
118 | if ((dump_db (db_name, file, (void (*)()) 0) == EOF) || |
---|
119 | (fclose(file) == EOF)) { |
---|
120 | fprintf(stderr, "error on file %s:", file_name); |
---|
121 | perror(""); |
---|
122 | exit(1); |
---|
123 | } |
---|
124 | update_ok_file (file_name); |
---|
125 | break; |
---|
126 | case OP_LOAD: |
---|
127 | load_db (db_name, file); |
---|
128 | break; |
---|
129 | case OP_NEW_MASTER: |
---|
130 | convert_new_master_key (db_name, file); |
---|
131 | printf("Don't forget to do a `kdb_util load %s' to reload the database!\n", file_name); |
---|
132 | break; |
---|
133 | case OP_CONVERT_OLD_DB: |
---|
134 | convert_old_format_db (db_name, file); |
---|
135 | printf("Don't forget to do a `kdb_util load %s' to reload the database!\n", file_name); |
---|
136 | break; |
---|
137 | } |
---|
138 | exit(0); |
---|
139 | } |
---|
140 | |
---|
141 | clear_secrets () |
---|
142 | { |
---|
143 | memset((char *)master_key, 0, sizeof (des_cblock)); |
---|
144 | memset((char *)master_key_schedule, 0, sizeof (Key_schedule)); |
---|
145 | memset((char *)new_master_key, 0, sizeof (des_cblock)); |
---|
146 | memset((char *)new_master_key_schedule, 0, sizeof (Key_schedule)); |
---|
147 | } |
---|
148 | |
---|
149 | /* cv_key is a procedure which takes a principle and changes its key, |
---|
150 | either for a new method of encrypting the keys, or a new master key. |
---|
151 | if cv_key is null no transformation of key is done (other than net byte |
---|
152 | order). */ |
---|
153 | |
---|
154 | struct callback_args { |
---|
155 | void (*cv_key)(); |
---|
156 | FILE *output_file; |
---|
157 | }; |
---|
158 | |
---|
159 | static int dump_db_1(arg, principal) |
---|
160 | char *arg; |
---|
161 | Principal *principal; |
---|
162 | { /* replace null strings with "*" */ |
---|
163 | struct callback_args *a = (struct callback_args *)arg; |
---|
164 | |
---|
165 | if (principal->instance[0] == '\0') { |
---|
166 | principal->instance[0] = '*'; |
---|
167 | principal->instance[1] = '\0'; |
---|
168 | } |
---|
169 | if (principal->mod_name[0] == '\0') { |
---|
170 | principal->mod_name[0] = '*'; |
---|
171 | principal->mod_name[1] = '\0'; |
---|
172 | } |
---|
173 | if (principal->mod_instance[0] == '\0') { |
---|
174 | principal->mod_instance[0] = '*'; |
---|
175 | principal->mod_instance[1] = '\0'; |
---|
176 | } |
---|
177 | if (a->cv_key != NULL) { |
---|
178 | (*a->cv_key) (principal); |
---|
179 | } |
---|
180 | fprintf(a->output_file, "%s %s %d %d %d %d %x %x", |
---|
181 | principal->name, |
---|
182 | principal->instance, |
---|
183 | principal->max_life, |
---|
184 | principal->kdc_key_ver, |
---|
185 | principal->key_version, |
---|
186 | principal->attributes, |
---|
187 | htonl (principal->key_low), |
---|
188 | htonl (principal->key_high)); |
---|
189 | print_time(a->output_file, principal->exp_date); |
---|
190 | print_time(a->output_file, principal->mod_date); |
---|
191 | fprintf(a->output_file, " %s %s\n", |
---|
192 | principal->mod_name, |
---|
193 | principal->mod_instance); |
---|
194 | return 0; |
---|
195 | } |
---|
196 | |
---|
197 | dump_db (db_file, output_file, cv_key) |
---|
198 | char *db_file; |
---|
199 | FILE *output_file; |
---|
200 | void (*cv_key)(); |
---|
201 | { |
---|
202 | struct callback_args a; |
---|
203 | |
---|
204 | a.cv_key = cv_key; |
---|
205 | a.output_file = output_file; |
---|
206 | |
---|
207 | kerb_db_iterate (dump_db_1, (char *)&a); |
---|
208 | return fflush(output_file); |
---|
209 | } |
---|
210 | |
---|
211 | load_db (db_file, input_file) |
---|
212 | char *db_file; |
---|
213 | FILE *input_file; |
---|
214 | { |
---|
215 | char exp_date_str[50]; |
---|
216 | char mod_date_str[50]; |
---|
217 | int temp1, temp2, temp3; |
---|
218 | long time_explode(); |
---|
219 | int code; |
---|
220 | #ifndef HAVE_SYS_ERRLIST_DECL |
---|
221 | extern char *sys_errlist[]; |
---|
222 | #endif |
---|
223 | char *temp_db_file; |
---|
224 | temp1 = strlen(db_file)+2; |
---|
225 | temp_db_file = malloc (temp1); |
---|
226 | strcpy(temp_db_file, db_file); |
---|
227 | strcat(temp_db_file, "~"); |
---|
228 | |
---|
229 | /* Create the database */ |
---|
230 | if ((code = kerb_db_create(temp_db_file)) != 0) { |
---|
231 | fprintf(stderr, "Couldn't create temp database %s: %s\n", |
---|
232 | temp_db_file, sys_errlist[code]); |
---|
233 | exit(1); |
---|
234 | } |
---|
235 | kerb_db_set_name(temp_db_file); |
---|
236 | for (;;) { /* explicit break on eof from fscanf */ |
---|
237 | memset((char *)&aprinc, 0, sizeof(aprinc)); |
---|
238 | if (fscanf(input_file, |
---|
239 | "%s %s %d %d %d %hd %x %x %s %s %s %s\n", |
---|
240 | aprinc.name, |
---|
241 | aprinc.instance, |
---|
242 | &temp1, |
---|
243 | &temp2, |
---|
244 | &temp3, |
---|
245 | &aprinc.attributes, |
---|
246 | &aprinc.key_low, |
---|
247 | &aprinc.key_high, |
---|
248 | exp_date_str, |
---|
249 | mod_date_str, |
---|
250 | aprinc.mod_name, |
---|
251 | aprinc.mod_instance) == EOF) |
---|
252 | break; |
---|
253 | aprinc.key_low = ntohl (aprinc.key_low); |
---|
254 | aprinc.key_high = ntohl (aprinc.key_high); |
---|
255 | aprinc.max_life = (unsigned char) temp1; |
---|
256 | aprinc.kdc_key_ver = (unsigned char) temp2; |
---|
257 | aprinc.key_version = (unsigned char) temp3; |
---|
258 | aprinc.exp_date = time_explode(exp_date_str); |
---|
259 | aprinc.mod_date = time_explode(mod_date_str); |
---|
260 | if (aprinc.instance[0] == '*') |
---|
261 | aprinc.instance[0] = '\0'; |
---|
262 | if (aprinc.mod_name[0] == '*') |
---|
263 | aprinc.mod_name[0] = '\0'; |
---|
264 | if (aprinc.mod_instance[0] == '*') |
---|
265 | aprinc.mod_instance[0] = '\0'; |
---|
266 | if (kerb_db_put_principal(&aprinc, 1) != 1) { |
---|
267 | fprintf(stderr, "Couldn't store %s.%s: %s; load aborted\n", |
---|
268 | aprinc.name, aprinc.instance, |
---|
269 | sys_errlist[errno]); |
---|
270 | exit(1); |
---|
271 | }; |
---|
272 | } |
---|
273 | if ((code = kerb_db_rename(temp_db_file, db_file)) != 0) |
---|
274 | perror("database rename failed"); |
---|
275 | (void) fclose(input_file); |
---|
276 | free(temp_db_file); |
---|
277 | } |
---|
278 | |
---|
279 | print_time(file, timeval) |
---|
280 | FILE *file; |
---|
281 | unsigned long timeval; |
---|
282 | { |
---|
283 | struct tm *tm; |
---|
284 | struct tm *gmtime(); |
---|
285 | time_t timeval2 = timeval; |
---|
286 | tm = gmtime(&timeval2); |
---|
287 | fprintf(file, " %04d%02d%02d%02d%02d", |
---|
288 | tm->tm_year < 1900 ? tm->tm_year + 1900: tm->tm_year, |
---|
289 | tm->tm_mon + 1, |
---|
290 | tm->tm_mday, |
---|
291 | tm->tm_hour, |
---|
292 | tm->tm_min); |
---|
293 | } |
---|
294 | |
---|
295 | /*ARGSUSED*/ |
---|
296 | update_ok_file (file_name) |
---|
297 | char *file_name; |
---|
298 | { |
---|
299 | /* handle slave locking/failure stuff */ |
---|
300 | char *file_ok; |
---|
301 | int fd; |
---|
302 | static char ok[]=".dump_ok"; |
---|
303 | |
---|
304 | if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1)) |
---|
305 | == NULL) { |
---|
306 | fprintf(stderr, "kdb_util: out of memory.\n"); |
---|
307 | (void) fflush (stderr); |
---|
308 | perror ("malloc"); |
---|
309 | exit (1); |
---|
310 | } |
---|
311 | strcpy(file_ok, file_name); |
---|
312 | strcat(file_ok, ok); |
---|
313 | if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0400)) < 0) { |
---|
314 | fprintf(stderr, "Error creating 'ok' file, '%s'", file_ok); |
---|
315 | perror(""); |
---|
316 | (void) fflush (stderr); |
---|
317 | exit (1); |
---|
318 | } |
---|
319 | free(file_ok); |
---|
320 | close(fd); |
---|
321 | } |
---|
322 | |
---|
323 | void |
---|
324 | convert_key_new_master (p) |
---|
325 | Principal *p; |
---|
326 | { |
---|
327 | des_cblock key; |
---|
328 | |
---|
329 | /* leave null keys alone */ |
---|
330 | if ((p->key_low == 0) && (p->key_high == 0)) return; |
---|
331 | |
---|
332 | /* move current key to des_cblock for encryption, special case master key |
---|
333 | since that's changing */ |
---|
334 | if ((strncmp (p->name, KERB_M_NAME, ANAME_SZ) == 0) && |
---|
335 | (strncmp (p->instance, KERB_M_INST, INST_SZ) == 0)) { |
---|
336 | memcpy((char *) key, (char *)new_master_key, sizeof (des_cblock)); |
---|
337 | (p->key_version)++; |
---|
338 | } else { |
---|
339 | memcpy((char *)key, (char *)&(p->key_low), sizeof(KRB_INT32)); |
---|
340 | memcpy((char *) (((KRB_INT32 *) key) + 1), (char *)&(p->key_high), sizeof(KRB_INT32)); |
---|
341 | kdb_encrypt_key (key, key, master_key, master_key_schedule, DECRYPT); |
---|
342 | } |
---|
343 | |
---|
344 | kdb_encrypt_key (key, key, new_master_key, new_master_key_schedule, ENCRYPT); |
---|
345 | |
---|
346 | memcpy((char *)&(p->key_low), (char *)key, sizeof(KRB_INT32)); |
---|
347 | memcpy((char *)&(p->key_high), (char *)(((KRB_INT32 *) key) + 1), sizeof(KRB_INT32)); |
---|
348 | memset((char *)key, 0, sizeof (key)); /* a little paranoia ... */ |
---|
349 | |
---|
350 | (p->kdc_key_ver)++; |
---|
351 | } |
---|
352 | |
---|
353 | convert_new_master_key (db_file, out) |
---|
354 | char *db_file; |
---|
355 | FILE *out; |
---|
356 | { |
---|
357 | |
---|
358 | printf ("\n\nEnter the CURRENT master key.\n"); |
---|
359 | if (kdb_get_master_key (TRUE, master_key, master_key_schedule, 0) != 0) { |
---|
360 | fprintf (stderr, "Couldn't get master key.\n"); |
---|
361 | clear_secrets (); |
---|
362 | exit (-1); |
---|
363 | } |
---|
364 | |
---|
365 | if (kdb_verify_master_key (master_key, master_key_schedule, stderr) < 0) { |
---|
366 | clear_secrets (); |
---|
367 | exit (-1); |
---|
368 | } |
---|
369 | |
---|
370 | printf ("\n\nNow enter the NEW master key. Do not forget it!!\n"); |
---|
371 | if (kdb_get_master_key (TRUE, new_master_key, new_master_key_schedule, 1) != 0) { |
---|
372 | fprintf (stderr, "Couldn't get new master key.\n"); |
---|
373 | clear_secrets (); |
---|
374 | exit (-1); |
---|
375 | } |
---|
376 | |
---|
377 | dump_db (db_file, out, convert_key_new_master); |
---|
378 | } |
---|
379 | |
---|
380 | void |
---|
381 | convert_key_old_db (p) |
---|
382 | Principal *p; |
---|
383 | { |
---|
384 | des_cblock key; |
---|
385 | |
---|
386 | /* leave null keys alone */ |
---|
387 | if ((p->key_low == 0) && (p->key_high == 0)) return; |
---|
388 | |
---|
389 | memcpy((char *)key, (char *)&(p->key_low), sizeof(KRB_INT32)); |
---|
390 | memcpy((char *)(((KRB_INT32 *) key) + 1), (char *)&(p->key_high), sizeof(KRB_INT32)); |
---|
391 | |
---|
392 | #ifndef NOENCRYPTION |
---|
393 | /* get clear key, old style */ |
---|
394 | (void) des_pcbc_encrypt ((des_cblock *) key, (des_cblock *) key, |
---|
395 | (long) sizeof(des_cblock), |
---|
396 | master_key_schedule, (des_cblock *)master_key_schedule, |
---|
397 | DECRYPT); |
---|
398 | #endif |
---|
399 | |
---|
400 | /* make new key, new style */ |
---|
401 | kdb_encrypt_key (key, key, master_key, master_key_schedule, ENCRYPT); |
---|
402 | |
---|
403 | memcpy((char *)&(p->key_low), (char *)key, sizeof(KRB_INT32)); |
---|
404 | memcpy((char *)&(p->key_high), (char *)(((KRB_INT32 *) key) + 1), sizeof(KRB_INT32)); |
---|
405 | memset((char *)key, 0, sizeof (key)); /* a little paranoia ... */ |
---|
406 | } |
---|
407 | |
---|
408 | convert_old_format_db (db_file, out) |
---|
409 | char *db_file; |
---|
410 | FILE *out; |
---|
411 | { |
---|
412 | des_cblock key_from_db; |
---|
413 | Principal principal_data[1]; |
---|
414 | int n, more; |
---|
415 | |
---|
416 | if (kdb_get_master_key (TRUE, master_key, master_key_schedule, 0) != 0L) { |
---|
417 | fprintf (stderr, "Couldn't get master key.\n"); |
---|
418 | clear_secrets(); |
---|
419 | exit (-1); |
---|
420 | } |
---|
421 | |
---|
422 | /* can't call kdb_verify_master_key because this is an old style db */ |
---|
423 | /* lookup the master key version */ |
---|
424 | n = kerb_get_principal(KERB_M_NAME, KERB_M_INST, principal_data, |
---|
425 | 1 /* only one please */, &more); |
---|
426 | if ((n != 1) || more) { |
---|
427 | fprintf(stderr, |
---|
428 | "Kerberos error on master key lookup, %d found.\n", |
---|
429 | n); |
---|
430 | exit (-1); |
---|
431 | } |
---|
432 | |
---|
433 | /* set up the master key */ |
---|
434 | fprintf(stderr, "Current Kerberos master key version is %d.\n", |
---|
435 | principal_data[0].kdc_key_ver); |
---|
436 | |
---|
437 | /* |
---|
438 | * now use the master key to decrypt (old style) the key in the db, had better |
---|
439 | * be the same! |
---|
440 | */ |
---|
441 | memcpy((char *)&key_from_db, (char *)&principal_data[0].key_low, sizeof(KRB_INT32)); |
---|
442 | memcpy((char *)(((KRB_INT32 *) &key_from_db) + 1), |
---|
443 | (char *)&principal_data[0].key_high, sizeof(KRB_INT32)); |
---|
444 | #ifndef NOENCRYPTION |
---|
445 | (void) des_pcbc_encrypt (&key_from_db, &key_from_db, |
---|
446 | (long) sizeof(key_from_db), |
---|
447 | master_key_schedule, |
---|
448 | (des_cblock *) master_key_schedule, DECRYPT); |
---|
449 | #endif |
---|
450 | /* the decrypted database key had better equal the master key */ |
---|
451 | n = memcmp((char *) master_key, (char *) &key_from_db, |
---|
452 | sizeof(master_key)); |
---|
453 | memset((char *)key_from_db, 0, sizeof(key_from_db)); |
---|
454 | |
---|
455 | if (n) { |
---|
456 | fprintf(stderr, "\n\07\07verify_master_key: Invalid master key, "); |
---|
457 | fprintf(stderr, "does not match database.\n"); |
---|
458 | exit (-1); |
---|
459 | } |
---|
460 | |
---|
461 | fprintf(stderr, "Master key verified.\n"); |
---|
462 | (void) fflush(stderr); |
---|
463 | |
---|
464 | dump_db (db_file, out, convert_key_old_db); |
---|
465 | } |
---|
466 | |
---|
467 | long |
---|
468 | time_explode(cp) |
---|
469 | register char *cp; |
---|
470 | { |
---|
471 | char wbuf[5]; |
---|
472 | struct tm tp; |
---|
473 | long maketime(); |
---|
474 | int local; |
---|
475 | |
---|
476 | zaptime(&tp); /* clear out the struct */ |
---|
477 | |
---|
478 | if (strlen(cp) > 10) { /* new format */ |
---|
479 | (void) strncpy(wbuf, cp, 4); |
---|
480 | wbuf[4] = 0; |
---|
481 | tp.tm_year = atoi(wbuf); |
---|
482 | cp += 4; /* step over the year */ |
---|
483 | local = 0; /* GMT */ |
---|
484 | } else { /* old format: local time, |
---|
485 | year is 2 digits, assuming 19xx */ |
---|
486 | wbuf[0] = *cp++; |
---|
487 | wbuf[1] = *cp++; |
---|
488 | wbuf[2] = 0; |
---|
489 | tp.tm_year = 1900 + atoi(wbuf); |
---|
490 | local = 1; /* local */ |
---|
491 | } |
---|
492 | |
---|
493 | wbuf[0] = *cp++; |
---|
494 | wbuf[1] = *cp++; |
---|
495 | wbuf[2] = 0; |
---|
496 | tp.tm_mon = atoi(wbuf)-1; |
---|
497 | |
---|
498 | wbuf[0] = *cp++; |
---|
499 | wbuf[1] = *cp++; |
---|
500 | tp.tm_mday = atoi(wbuf); |
---|
501 | |
---|
502 | wbuf[0] = *cp++; |
---|
503 | wbuf[1] = *cp++; |
---|
504 | tp.tm_hour = atoi(wbuf); |
---|
505 | |
---|
506 | wbuf[0] = *cp++; |
---|
507 | wbuf[1] = *cp++; |
---|
508 | tp.tm_min = atoi(wbuf); |
---|
509 | |
---|
510 | |
---|
511 | return(maketime(&tp, local)); |
---|
512 | } |
---|