source: trunk/third/cns/src/admin/kdb_util.c @ 8789

Revision 8789, 13.4 KB checked in by ghudson, 28 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r8788, which included commits to RCS files with non-trunk default branches.
Line 
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
37Principal aprinc;
38
39static des_cblock master_key, new_master_key;
40static des_key_schedule master_key_schedule, new_master_key_schedule;
41
42#define zaptime(foo) memset((char *)(foo), 0, sizeof(*(foo)))
43
44extern long kdb_get_master_key(), kdb_verify_master_key();
45extern char *malloc();
46extern int errno;
47
48main(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
141clear_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
154struct callback_args {
155    void (*cv_key)();
156    FILE *output_file;
157};
158
159static 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
197dump_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
211load_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
279print_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*/
296update_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
323void
324convert_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
353convert_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
380void
381convert_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
408convert_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
467long
468time_explode(cp)
469register 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}
Note: See TracBrowser for help on using the repository browser.