source: trunk/third/ksrvutil/ksrvutil.c @ 13550

Revision 13550, 18.5 KB checked in by ghudson, 25 years ago (diff)
krb5 changed the meaning of the last argument to des_read_pw_string(). Adapt.
Line 
1/*
2 * Copyright 1989 by the Massachusetts Institute of Technology.
3 *
4 * For copying and distribution information, please see the file
5 * <mit-copyright.h>.
6 *
7 * list and update contents of srvtab files
8 */
9
10#include <mit-copyright.h>
11/*
12 * ksrvutil
13 * list and update the contents of srvtab files
14 */
15
16#ifndef FALSE
17#define FALSE 0
18#endif
19
20#ifndef TRUE
21#define TRUE 1
22#endif
23
24#include <kadm.h>
25#include <krb_err.h>
26
27#include <sys/types.h>
28#include <sys/file.h>
29#include <sys/param.h>
30#include <stdio.h>
31#include <string.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <unistd.h>
35#include <errno.h>
36
37#ifdef NOENCRYPTION
38#define read_long_pw_string placebo_read_pw_string
39#else /* NOENCRYPTION */
40#define read_long_pw_string des_read_pw_string
41#endif /* NOENCRYPTION */
42int read_long_pw_string();
43
44#define SRVTAB_MODE 0600        /* rw------- */
45#define PAD "  "
46#define VNO_HEADER "Version"
47#define VNO_FORMAT "%4d   "
48#define KEY_HEADER "       Key       " /* 17 characters long */
49#define PRINC_HEADER "  Principal\n"
50#define PRINC_FORMAT "%s"
51
52static int use_preauth = 0;
53
54extern void krb_set_tkt_string();
55void leave();
56unsigned short get_mode();
57
58void
59copy_keyfile(progname, keyfile, backup_keyfile)
60  char *progname;
61  char *keyfile;
62  char *backup_keyfile;
63{
64    int keyfile_fd;
65    int backup_keyfile_fd;
66    int keyfile_mode;
67    char buf[BUFSIZ];           /* for copying keyfiles */
68    int rcount;                 /* for copying keyfiles */
69    int try_again;
70   
71    (void) memset((char *)buf, 0, sizeof(buf));
72   
73    do {
74        try_again = FALSE;
75        if ((keyfile_fd = open(keyfile, O_RDONLY, 0)) < 0) {
76            if (errno != ENOENT) {
77                (void)fprintf(stderr, "%s: Unable to read %s: %s\n", progname,
78                              keyfile, strerror(errno));
79                exit(1);
80            }
81            else {
82                try_again = TRUE;
83                if ((keyfile_fd =
84                     open(keyfile,
85                          O_WRONLY | O_TRUNC | O_CREAT, SRVTAB_MODE)) < 0) {
86                    (void) fprintf(stderr, "%s: Unable to create %s: %s\n",
87                                   progname, keyfile, strerror(errno));
88                    exit(1);
89                }
90                else
91                    if (close(keyfile_fd) < 0) {
92                        (void) fprintf(stderr, "%s: Failure closing %s: %s\n",
93                                       progname, keyfile, strerror(errno));
94                        exit(1);
95                    }
96            }
97        }
98    } while(try_again);
99
100    keyfile_mode = get_mode(keyfile);
101
102    if ((backup_keyfile_fd =
103         open(backup_keyfile, O_WRONLY | O_TRUNC | O_CREAT,
104              keyfile_mode)) < 0) {
105        (void) fprintf(stderr, "%s: Unable to write %s: %s\n", progname,
106                       backup_keyfile, strerror(errno));
107        exit(1);
108    }
109    do {
110        if ((rcount = read(keyfile_fd, (char *)buf, sizeof(buf))) < 0) {
111            (void) fprintf(stderr, "%s: Error reading %s: %s\n", progname,
112                           keyfile, strerror(errno));
113            exit(1);
114        }
115        if (rcount && (write(backup_keyfile_fd, buf, rcount) != rcount)) {
116            (void) fprintf(stderr, "%s: Error writing %s: %s\n", progname,
117                           backup_keyfile, strerror(errno));
118            exit(1);
119        }
120    } while (rcount);
121    if (close(backup_keyfile_fd) < 0) {
122        (void) fprintf(stderr, "%s: Error closing %s: %s\n", progname,
123                       backup_keyfile, strerror(errno));
124        exit(1);
125    }
126    if (close(keyfile_fd) < 0) {
127        (void) fprintf(stderr, "%s: Error closing %s: %s\n", progname,
128                       keyfile, strerror(errno));
129        exit(1);
130    }
131}
132
133void
134safe_read_stdin(prompt, buf, size)
135  char *prompt;
136  char *buf;
137  int size;
138{
139    (void) printf(prompt);
140    (void) fflush(stdout);
141    (void) memset(buf, 0, size);
142    if (read(0, buf, size - 1) < 0) {
143        (void) fprintf(stderr, "Failure reading from stdin: %s\n",
144                       strerror(errno));
145        leave((char *)NULL, 1);
146    }
147    fflush(stdin);
148    buf[strlen(buf)-1] = 0;
149}       
150 
151
152void
153safe_write(progname, filename, fd, buf, len)
154  char *progname;
155  char *filename;
156  int fd;
157  char *buf;
158  int len;
159{
160    if (write(fd, buf, len) != len) {
161        (void) fprintf(stderr, "%s: Failure writing to %s: %s\n", progname,
162                       filename, strerror(errno));
163        (void) close(fd);
164        leave("In progress srvtab in this file.", 1);
165    }
166}       
167
168int
169yn(string)
170  char *string;
171{
172    char ynbuf[5];
173
174    (void) printf("%s (y,n) [y] ", string);
175    for (;;) {
176        safe_read_stdin("", ynbuf, sizeof(ynbuf));
177       
178        if ((ynbuf[0] == 'n') || (ynbuf[0] == 'N'))
179            return(0);
180        else if ((ynbuf[0] == 'y') || (ynbuf[0] == 'Y') || (ynbuf[0] == 0))
181            return(1);
182        else {
183            (void) printf("Please enter 'y' or 'n': ");
184            fflush(stdout);
185        }
186    }
187}
188
189void
190append_srvtab(progname, filename, fd, sname, sinst,
191                   srealm, key_vno, key)
192  char *progname;
193  char *filename;
194  int fd;
195  char *sname;
196  char *sinst;
197  char *srealm;
198  unsigned char key_vno;
199  des_cblock key;
200{
201    /* Add one to append null */
202    safe_write(progname, filename, fd, sname, strlen(sname) + 1);
203    safe_write(progname, filename, fd, sinst, strlen(sinst) + 1);
204    safe_write(progname, filename, fd, srealm, strlen(srealm) + 1);
205    safe_write(progname, filename, fd, (char *)&key_vno, 1);
206    safe_write(progname, filename, fd, (char *)key, sizeof(des_cblock));
207#ifndef NO_FSYNC
208    (void) fsync(fd);
209#endif
210}   
211
212unsigned short
213get_mode(filename)
214  char *filename;
215{
216    struct stat statbuf;
217    unsigned short mode;
218
219    (void) memset((char *)&statbuf, 0, sizeof(statbuf));
220   
221    if (stat(filename, &statbuf) < 0)
222        mode = SRVTAB_MODE;
223    else
224        mode = statbuf.st_mode;
225
226    return(mode);
227}
228
229main(argc,argv)
230  int argc;
231  char *argv[];
232{
233    char sname[ANAME_SZ];       /* name of service */
234    char sinst[INST_SZ];        /* instance of service */
235    char srealm[REALM_SZ];      /* realm of service */
236    unsigned char key_vno;      /* key version number */
237    int real_kvno;              /* ... and one from the database */
238    int status;                 /* general purpose error status */
239    des_cblock new_key;
240    des_cblock old_key;
241    char change_tkt[MAXPATHLEN]; /* Ticket to use for key change */
242    char keyfile[MAXPATHLEN];   /* Original keyfile */
243    char work_keyfile[MAXPATHLEN]; /* Working copy of keyfile */
244    char backup_keyfile[MAXPATHLEN]; /* Backup copy of keyfile */
245    unsigned short keyfile_mode; /* Protections on keyfile */
246    int work_keyfile_fd = -1;   /* Initialize so that */
247    int backup_keyfile_fd = -1; /* compiler doesn't complain */
248    char local_realm[REALM_SZ]; /* local kerberos realm */
249    int i;
250    int interactive = FALSE;
251    int list = FALSE;
252    int change = FALSE;
253    int add = FALSE;
254    int key = FALSE;            /* do we show keys? */
255    int flag_delete = FALSE;
256    int arg_entered = FALSE;
257    int change_this_key = FALSE;
258    char databuf[BUFSIZ];
259    int first_printed = FALSE;  /* have we printed the first item? */
260   
261    int get_svc_new_key();
262    void get_key_from_password();
263    void print_key();
264    void print_name();
265   
266    initialize_krb_error_table();
267    initialize_kadm_error_table();
268
269    (void) memset((char *)sname, 0, sizeof(sname));
270    (void) memset((char *)sinst, 0, sizeof(sinst));
271    (void) memset((char *)srealm, 0, sizeof(srealm));
272   
273    (void) memset((char *)change_tkt, 0, sizeof(change_tkt));
274    (void) memset((char *)keyfile, 0, sizeof(keyfile));
275    (void) memset((char *)work_keyfile, 0, sizeof(work_keyfile));
276    (void) memset((char *)backup_keyfile, 0, sizeof(backup_keyfile));
277    (void) memset((char *)local_realm, 0, sizeof(local_realm));
278   
279    (void) sprintf(change_tkt, "/tmp/tkt_ksrvutil.%d", getpid());
280    krb_set_tkt_string(change_tkt);
281
282    /* This is used only as a default for adding keys */
283    if (krb_get_lrealm(local_realm, 1) != KSUCCESS)
284        (void) strcpy(local_realm, KRB_REALM);
285   
286    for (i = 1; i < argc; i++) {
287        if (strcmp(argv[i], "-i") == 0)
288            interactive++;
289        else if (strcmp(argv[i], "-k") == 0)
290            key++;
291        else if (strcmp(argv[i], "-p") == 0)
292            use_preauth++;
293        else if (strcmp(argv[i], "list") == 0) {
294            if (arg_entered)
295                usage();
296            else {
297                arg_entered++;
298                list++;
299            }
300        }
301        else if (strcmp(argv[i], "change") == 0) {
302            if (arg_entered)
303                usage();
304            else {
305                arg_entered++;
306                change++;
307            }
308        }
309        else if (strcmp(argv[i], "add") == 0) {
310            if (arg_entered)
311                usage();
312            else {
313                arg_entered++;
314                add++;
315            }
316        }
317        else if (strcmp(argv[i], "delete") == 0) {
318            if (arg_entered)
319                usage();
320            else {
321                arg_entered++;
322                flag_delete++;
323                interactive++;  /* deletion is only interactive for now */
324            }
325        }
326        else if (strcmp(argv[i], "-f") == 0) {
327            if (++i == argc)
328                usage();
329            else
330                (void) strcpy(keyfile, argv[i]);
331        }
332        else
333            usage();
334    }
335   
336    if (!arg_entered)
337        usage();
338
339    if (!keyfile[0])
340        (void) strcpy(keyfile, KEYFILE);
341   
342    (void) strcpy(work_keyfile, keyfile);
343    (void) strcpy(backup_keyfile, keyfile);
344   
345    if (change || flag_delete || add) {
346        (void) strcat(work_keyfile, ".work");
347        (void) strcat(backup_keyfile, ".old");
348       
349        copy_keyfile(argv[0], keyfile, backup_keyfile);
350    }
351   
352    if (add)
353        copy_keyfile(argv[0], backup_keyfile, work_keyfile);
354
355    keyfile_mode = get_mode(keyfile);
356
357    if (change || flag_delete || list) {
358        if ((backup_keyfile_fd = open(backup_keyfile, O_RDONLY, 0)) < 0) {
359            (void) fprintf(stderr, "%s: Unable to read %s: %s\n", argv[0],
360                           backup_keyfile, strerror(errno));
361            exit(1);
362        }
363    }
364
365    if (change || flag_delete) {
366        if ((work_keyfile_fd =
367             open(work_keyfile, O_WRONLY | O_CREAT | O_TRUNC,
368                  SRVTAB_MODE)) < 0) {
369            (void) fprintf(stderr, "%s: Unable to write %s: %s\n", argv[0],
370                           work_keyfile, strerror(errno));
371            exit(1);
372        }
373    }
374    else if (add) {
375        if ((work_keyfile_fd =
376             open(work_keyfile, O_APPEND|O_WRONLY|O_SYNC, SRVTAB_MODE)) < 0) {
377            (void) fprintf(stderr, "%s: Unable to open %s for append: %s\n",
378                           argv[0], work_keyfile, strerror(errno));
379            exit(1);
380        }
381    }
382   
383    if (change || flag_delete || list) {
384        while ((getst(backup_keyfile_fd, sname, SNAME_SZ) > 0) &&
385               (getst(backup_keyfile_fd, sinst, INST_SZ) > 0) &&
386               (getst(backup_keyfile_fd, srealm, REALM_SZ) > 0) &&
387               (read(backup_keyfile_fd, &key_vno, 1) > 0) &&
388               (read(backup_keyfile_fd,(char *)old_key,sizeof(old_key)) > 0)) {
389            if (list) {
390                if (!first_printed) {
391                    (void) printf(VNO_HEADER);
392                    (void) printf(PAD);
393                    if (key) {
394                        (void) printf(KEY_HEADER);
395                        (void) printf(PAD);
396                    }
397                    (void) printf(PRINC_HEADER);
398                    first_printed = 1;
399                }
400                (void) printf(VNO_FORMAT, key_vno);
401                (void) printf(PAD);
402                if (key) {
403                    print_key(old_key);
404                    (void) printf(PAD);
405                }
406                print_name(sname, sinst, srealm);
407                (void) printf("\n");
408            }
409            else if (change) {
410                (void) printf("\nPrincipal: ");
411                print_name(sname, sinst, srealm);
412                (void) printf("; version %d\n", key_vno);
413
414                status = get_kvno(sname, sinst, srealm, keyfile, &real_kvno);
415                if (!status) {
416                    if (key_vno != real_kvno) {
417                        (void) printf("Server reports key version %d -- ", real_kvno);
418                        if (yn("Fix keyfile to match?"))
419                            key_vno = real_kvno;
420                    }
421                       
422                    if (interactive)
423                        change_this_key = yn("Change this key?");
424                    else if (change)
425                        change_this_key = 1;
426                    else
427                        change_this_key = 0;
428                   
429                    if (change_this_key)
430                        (void) printf("Changing to version %d.\n", key_vno + 1);
431                    else if (change)
432                        (void) printf("Not changing this key.\n");
433                } else {
434                    com_err(argv[0], status + krb_err_base,
435                            "\nCouldn't get version number -- not changing this key");
436                    change_this_key = FALSE;
437                }
438                   
439                if (change_this_key) {
440                    /*
441                     * Pick a new key and determine whether or not
442                     * it is safe to change
443                     */
444                    if ((status =
445                         get_svc_new_key(new_key, sname, sinst,
446                                         srealm, keyfile)) == KADM_SUCCESS)
447                        key_vno++;
448                    else {
449                        (void) memcpy(new_key, old_key, sizeof(new_key));
450                        com_err(argv[0], status, "Key NOT changed");
451                        change_this_key = FALSE;
452                    }
453                }
454                else
455                    (void) memcpy(new_key, old_key, sizeof(new_key));
456                append_srvtab(argv[0], work_keyfile, work_keyfile_fd,
457                              sname, sinst, srealm, key_vno, new_key);
458                if (key && change_this_key) {
459                    (void) printf("Old key: ");
460                    print_key(old_key);
461                    (void) printf("; new key: ");
462                    print_key(new_key);
463                    (void) printf("\n");
464                }
465                if (change_this_key) {
466                    if ((status = kadm_change_pw(new_key)) == KADM_SUCCESS) {
467                        (void) printf("Key changed.\n");
468                        (void) dest_tkt();
469                    }
470                    else {
471                        com_err(argv[0], status,
472                                " attempting to change password.");
473                        (void) dest_tkt();
474                        /* XXX This knows the format of a keyfile */
475                        if (lseek(work_keyfile_fd, -9, SEEK_CUR) >= 0) {
476                            key_vno--;
477                            safe_write(argv[0], work_keyfile,
478                                       work_keyfile_fd, (char *)&key_vno, 1);
479                            safe_write(argv[0], work_keyfile, work_keyfile_fd,
480                                       (char *)old_key, sizeof(des_cblock));
481#ifndef NO_FSYNC
482                            (void) fsync(work_keyfile_fd);
483#endif
484                            (void) fprintf(stderr,"Key NOT changed.\n");
485                        }
486                        else {
487                            (void)fprintf(stderr,
488                                          "%s: Unable to revert keyfile: %s\n",
489                                          argv[0], strerror(errno));
490                            leave("", 1);
491                        }
492                    }
493                }
494            }
495            else if (flag_delete) {
496                (void) printf("\nPrincipal: ");
497                print_name(sname, sinst, srealm);
498                (void) printf("; version %d\n", key_vno);
499                change_this_key = yn("Delete this key?");
500               
501                if (change_this_key)
502                    (void) printf("Deleting this key.\n");
503                else
504                    (void) printf("Keeping this key.\n");
505               
506                if (!change_this_key) {
507                    append_srvtab(argv[0], work_keyfile, work_keyfile_fd,
508                                  sname, sinst, srealm, key_vno, old_key);
509                }
510                memset((char *)old_key, 0, sizeof(des_cblock));
511            }
512        }
513    }
514    else if (add) {
515        do {
516            do {
517                safe_read_stdin("Name: ", databuf, sizeof(databuf));
518                (void) strncpy(sname, databuf, sizeof(sname) - 1);
519                safe_read_stdin("Instance: ", databuf, sizeof(databuf));
520                (void) strncpy(sinst, databuf, sizeof(sinst) - 1);
521                safe_read_stdin("Realm: ", databuf, sizeof(databuf));
522                (void) strncpy(srealm, databuf, sizeof(srealm) - 1);
523                safe_read_stdin("Version number: ", databuf, sizeof(databuf));
524                key_vno = atoi(databuf);
525                if (!srealm[0])
526                    (void) strcpy(srealm, local_realm);
527                (void) printf("New principal: ");
528                print_name(sname, sinst, srealm);
529                (void) printf("; version %d\n", key_vno);
530            } while (!yn("Is this correct?"));
531            get_key_from_password(new_key);
532            if (key) {
533                (void) printf("Key: ");
534                print_key(new_key);
535                (void) printf("\n");
536            }
537            append_srvtab(argv[0], work_keyfile, work_keyfile_fd,
538                          sname, sinst, srealm, key_vno, new_key);
539            (void) printf("Key successfully added.\n");
540        } while (yn("Would you like to add another key?"));
541    }
542
543    if (change || flag_delete || list)
544        if (close(backup_keyfile_fd) < 0) {
545            (void) fprintf(stderr, "%s: Failure closing %s: %s\n",
546                           argv[0], backup_keyfile, strerror(errno));
547            (void) fprintf(stderr, "continuing...\n");
548        }
549   
550    if (change || flag_delete || add) {
551        if (close(work_keyfile_fd) < 0) {
552            (void) fprintf(stderr, "%s: Failure closing %s: %s\n",
553                           argv[0], work_keyfile, strerror(errno));
554            exit(1);
555        }
556        if (rename(work_keyfile, keyfile) < 0) {
557            (void) fprintf(stderr, "%s: Failure renaming %s to %s: %s\n",
558                           argv[0], work_keyfile, keyfile,
559                           strerror(errno));
560            exit(1);
561        }
562        (void) chmod(backup_keyfile, keyfile_mode);
563        (void) chmod(keyfile, keyfile_mode);
564        (void) printf("Old keyfile in %s.\n", backup_keyfile);
565    }
566
567    exit(0);
568}
569
570void
571print_key(key)
572  des_cblock key;
573{
574    int i;
575
576    for (i = 0; i < 4; i++)
577        (void) printf("%02x", key[i]);
578    (void) printf(" ");
579    for (i = 4; i < 8; i++)
580        (void) printf("%02x", key[i]);
581}
582
583void
584print_name(name, inst, realm)
585  char *name;
586  char *inst;
587  char *realm;
588{
589    (void) printf("%s%s%s%s%s", name, inst[0] ? "." : "", inst,
590                  realm[0] ? "@" : "", realm);
591}
592
593int
594get_svc_new_key(new_key, sname, sinst, srealm, keyfile)
595  des_cblock new_key;
596  char *sname;
597  char *sinst;
598  char *srealm;
599  char *keyfile;
600{
601    int status = KADM_SUCCESS;
602    CREDENTIALS c;
603
604    if (use_preauth)
605        status = krb_get_svc_in_tkt_preauth(sname, sinst, srealm, PWSERV_NAME,
606                                            KADM_SINST, 1, keyfile);
607    else
608        status = krb_get_svc_in_tkt(sname, sinst, srealm, PWSERV_NAME,
609                                    KADM_SINST, 1, keyfile);
610
611    if (status != KSUCCESS) {
612        /* propagate basic krb_err_txt errors via the error table */
613        return status + krb_err_base;
614    }
615
616    status = krb_get_cred(PWSERV_NAME, KADM_SINST, srealm, &c);
617   
618    if (status != KSUCCESS) {
619        /* propagate basic krb_err_txt errors via the error table */
620        return status + krb_err_base;
621    }
622
623    if ((status = kadm_init_link("changepw", KRB_MASTER, srealm)) ==
624        KADM_SUCCESS) {
625#ifdef NOENCRYPTION
626        (void) memset((char *) new_key, 0, sizeof(des_cblock));
627        new_key[0] = (unsigned char) 1;
628#else /* NOENCRYPTION */
629        des_init_random_number_generator(c.session);
630        (void) des_new_random_key(new_key);
631#endif /* NOENCRYPTION */
632        return(KADM_SUCCESS);
633    }
634    /* kadm_init_link returns com_err error values. */
635    return(status);
636}
637
638void
639get_key_from_password(key)
640  des_cblock key;
641{
642    char password[MAX_KPW_LEN]; /* storage for the password */
643
644    if (read_long_pw_string(password, sizeof(password)-1, "Password: ",
645                            "Verifying, please re-enter password: "))
646        leave("Error reading password.", 1);
647
648#ifdef NOENCRYPTION
649    (void) memset((char *) key, 0, sizeof(des_cblock));
650    key[0] = (unsigned char) 1;
651#else /* NOENCRYPTION */
652    (void) des_string_to_key(password, key);
653#endif /* NOENCRYPTION */
654    (void) memset((char *)password, 0, sizeof(password));
655}   
656
657usage()
658{
659    (void) fprintf(stderr, "Usage: ksrvutil [-f keyfile] [-i] [-k] [-p] ");
660    (void) fprintf(stderr, "{list | change | add | delete}\n");
661    (void) fprintf(stderr, "   -i causes the program to ask for ");
662    (void) fprintf(stderr, "confirmation before changing keys.\n");
663    (void) fprintf(stderr, "   -k causes the key to printed for list or ");
664    (void) fprintf(stderr, "change.\n");
665    (void) fprintf(stderr, "   -p causes the program to preauthenticate.\n");
666    exit(1);
667}
668
669void
670leave(str,x)
671char *str;
672int x;
673{
674    if (str)
675        (void) fprintf(stderr, "%s\n", str);
676    (void) dest_tkt();
677    exit(x);
678}
679/* simple routine to use the srvtab to get a ticket authenticating to
680   itself and then look at the credential to find out the current version
681   number.
682 */
683int get_kvno(sname, sinst, srealm, keyfile, kvno)
684     char *sname;
685     char *sinst;
686     char *srealm;
687     char *keyfile;
688     int *kvno;
689{
690  CREDENTIALS c;
691  int status;
692  if (use_preauth)
693    status = krb_get_svc_in_tkt_preauth(sname,sinst,srealm,sname,sinst,1,keyfile);
694  else
695    status = krb_get_svc_in_tkt(sname,sinst,srealm,sname,sinst,1,keyfile);
696  if (status != KSUCCESS) return status;
697
698  status = krb_get_cred(sname,sinst,srealm,&c);
699  if (status != KSUCCESS) return status;
700
701  *kvno = c.kvno;
702  return KSUCCESS;
703}
704
705
706/* Special trick: ksrvutil can get confused when talking to an out-of-date
707   slave, so make it always talk to an admin server first.
708 */
709krb_get_krbhst(h,r,n)
710    char *h;
711    char *r;
712    int n;
713{
714  return krb_get_admhst(h, r, n);
715}
Note: See TracBrowser for help on using the repository browser.