/* * Copyright 1989 by the Massachusetts Institute of Technology. * * For copying and distribution information, please see the file * Copyright.MIT. * * list and update contents of srvtab files */ #ifndef lint #if 0 static char rcsid_ksrvutil_c[] = "BonesHeader: /afs/athena.mit.edu/astaff/project/kerberos/src/kadmin/RCS/ksrvutil.c,v 4.1 89/09/26 09:33:49 jtkohl Exp "; #endif static const char rcsid[] = "$Id$"; #endif lint /* * ksrvutil * list and update the contents of srvtab files */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #include #include #include #include #include #include #include #include #ifdef NOENCRYPTION #define read_long_pw_string placebo_read_pw_string #else /* NOENCRYPTION */ #define read_long_pw_string des_read_pw_string #endif /* NOENCRYPTION */ int read_long_pw_string(); #define SRVTAB_MODE 0600 /* rw------- */ #define PAD " " #define VNO_HEADER "Version" #define VNO_FORMAT "%4d " #define KEY_HEADER " Key " /* 17 characters long */ #define PRINC_HEADER " Principal\n" #define PRINC_FORMAT "%s" extern int errno; extern void krb_set_tkt_string(); void leave(); unsigned short get_mode(); void copy_keyfile(progname, keyfile, backup_keyfile) char *progname; char *keyfile; char *backup_keyfile; { int keyfile_fd; int backup_keyfile_fd; int keyfile_mode; char buf[BUFSIZ]; /* for copying keyfiles */ int rcount; /* for copying keyfiles */ int try_again; (void) bzero((char *)buf, sizeof(buf)); do { try_again = FALSE; if ((keyfile_fd = open(keyfile, O_RDONLY, 0)) < 0) { if (errno != ENOENT) { err(1, "unable to read %s", keyfile); } else { try_again = TRUE; if ((keyfile_fd = open(keyfile, O_WRONLY | O_TRUNC | O_CREAT, SRVTAB_MODE)) < 0) { err(1, "unable to create %s", keyfile); } else if (close(keyfile_fd) < 0) { err(1, "failure closing %s", keyfile); } } } } while(try_again); keyfile_mode = get_mode(keyfile); if ((backup_keyfile_fd = open(backup_keyfile, O_WRONLY | O_TRUNC | O_CREAT, keyfile_mode)) < 0) { err(1, "unable to write %s", backup_keyfile); } do { if ((rcount = read(keyfile_fd, (char *)buf, sizeof(buf))) < 0) { err(1, "error reading %s", keyfile); } if (rcount && (write(backup_keyfile_fd, buf, rcount) != rcount)) { err(1, "error writing %s", backup_keyfile); } } while (rcount); if (close(backup_keyfile_fd) < 0) { err(1, "error closing %s", backup_keyfile); } if (close(keyfile_fd) < 0) { err(1, "error closing %s", keyfile); } } void safe_read_stdin(prompt, buf, size) char *prompt; char *buf; int size; { (void) printf(prompt); (void) fflush(stdout); (void) bzero(buf, size); if (read(0, buf, size - 1) < 0) { warn("failure reading from stdin"); leave((char *)NULL, 1); } fflush(stdin); buf[strlen(buf)-1] = 0; } void safe_write(progname, filename, fd, buf, len) char *progname; char *filename; int fd; char *buf; int len; { if (write(fd, buf, len) != len) { warn("failure writing %s", filename); close(fd); leave("In progress srvtab in this file.", 1); } } int yn(string) char *string; { char ynbuf[5]; (void) printf("%s (y,n) [y] ", string); for (;;) { safe_read_stdin("", ynbuf, sizeof(ynbuf)); if ((ynbuf[0] == 'n') || (ynbuf[0] == 'N')) return(0); else if ((ynbuf[0] == 'y') || (ynbuf[0] == 'Y') || (ynbuf[0] == 0)) return(1); else { (void) printf("Please enter 'y' or 'n': "); fflush(stdout); } } } void append_srvtab(progname, filename, fd, sname, sinst, srealm, key_vno, key) char *progname; char *filename; int fd; char *sname; char *sinst; char *srealm; unsigned char key_vno; des_cblock key; { /* Add one to append null */ safe_write(progname, filename, fd, sname, strlen(sname) + 1); safe_write(progname, filename, fd, sinst, strlen(sinst) + 1); safe_write(progname, filename, fd, srealm, strlen(srealm) + 1); safe_write(progname, filename, fd, (char *)&key_vno, 1); safe_write(progname, filename, fd, (char *)key, sizeof(des_cblock)); (void) fsync(fd); } unsigned short get_mode(filename) char *filename; { struct stat statbuf; unsigned short mode; (void) bzero((char *)&statbuf, sizeof(statbuf)); if (stat(filename, &statbuf) < 0) mode = SRVTAB_MODE; else mode = statbuf.st_mode; return(mode); } main(argc,argv) int argc; char *argv[]; { char sname[ANAME_SZ]; /* name of service */ char sinst[INST_SZ]; /* instance of service */ char srealm[REALM_SZ]; /* realm of service */ unsigned char key_vno; /* key version number */ int status; /* general purpose error status */ des_cblock new_key; des_cblock old_key; char change_tkt[MAXPATHLEN]; /* Ticket to use for key change */ char keyfile[MAXPATHLEN]; /* Original keyfile */ char work_keyfile[MAXPATHLEN]; /* Working copy of keyfile */ char backup_keyfile[MAXPATHLEN]; /* Backup copy of keyfile */ unsigned short keyfile_mode; /* Protections on keyfile */ int work_keyfile_fd = -1; /* Initialize so that */ int backup_keyfile_fd = -1; /* compiler doesn't complain */ char local_realm[REALM_SZ]; /* local kerberos realm */ int i; int interactive = FALSE; int list = FALSE; int change = FALSE; int add = FALSE; int key = FALSE; /* do we show keys? */ int arg_entered = FALSE; int change_this_key = FALSE; char databuf[BUFSIZ]; int first_printed = FALSE; /* have we printed the first item? */ int get_svc_new_key(); void get_key_from_password(); void print_key(); void print_name(); (void) bzero((char *)sname, sizeof(sname)); (void) bzero((char *)sinst, sizeof(sinst)); (void) bzero((char *)srealm, sizeof(srealm)); (void) bzero((char *)change_tkt, sizeof(change_tkt)); (void) bzero((char *)keyfile, sizeof(keyfile)); (void) bzero((char *)work_keyfile, sizeof(work_keyfile)); (void) bzero((char *)backup_keyfile, sizeof(backup_keyfile)); (void) bzero((char *)local_realm, sizeof(local_realm)); (void) sprintf(change_tkt, "/tmp/tkt_ksrvutil.%d", getpid()); krb_set_tkt_string(change_tkt); /* This is used only as a default for adding keys */ if (krb_get_lrealm(local_realm, 1) != KSUCCESS) (void) strcpy(local_realm, KRB_REALM); for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-i") == 0) interactive++; else if (strcmp(argv[i], "-k") == 0) key++; else if (strcmp(argv[i], "list") == 0) { if (arg_entered) usage(); else { arg_entered++; list++; } } else if (strcmp(argv[i], "change") == 0) { if (arg_entered) usage(); else { arg_entered++; change++; } } else if (strcmp(argv[i], "add") == 0) { if (arg_entered) usage(); else { arg_entered++; add++; } } else if (strcmp(argv[i], "-f") == 0) { if (++i == argc) usage(); else (void) strcpy(keyfile, argv[i]); } else usage(); } if (!arg_entered) usage(); if (!keyfile[0]) (void) strcpy(keyfile, KEYFILE); (void) strcpy(work_keyfile, keyfile); (void) strcpy(backup_keyfile, keyfile); if (change || add) { (void) strcat(work_keyfile, ".work"); (void) strcat(backup_keyfile, ".old"); copy_keyfile(argv[0], keyfile, backup_keyfile); } if (add) copy_keyfile(argv[0], backup_keyfile, work_keyfile); keyfile_mode = get_mode(keyfile); if (change || list) { if ((backup_keyfile_fd = open(backup_keyfile, O_RDONLY, 0)) < 0) { err(1, "unable to read %s", backup_keyfile); } } if (change) { if ((work_keyfile_fd = open(work_keyfile, O_WRONLY | O_CREAT | O_TRUNC, SRVTAB_MODE)) < 0) { err(1, "unable to write %s", work_keyfile); } } else if (add) { if ((work_keyfile_fd = open(work_keyfile, O_APPEND | O_WRONLY, SRVTAB_MODE)) < 0) { err(1, "unable to append to %s", work_keyfile); } } if (change || list) { while ((getst(backup_keyfile_fd, sname, SNAME_SZ) > 0) && (getst(backup_keyfile_fd, sinst, INST_SZ) > 0) && (getst(backup_keyfile_fd, srealm, REALM_SZ) > 0) && (read(backup_keyfile_fd, &key_vno, 1) > 0) && (read(backup_keyfile_fd,(char *)old_key,sizeof(old_key)) > 0)) { if (list) { if (!first_printed) { (void) printf(VNO_HEADER); (void) printf(PAD); if (key) { (void) printf(KEY_HEADER); (void) printf(PAD); } (void) printf(PRINC_HEADER); first_printed = 1; } (void) printf(VNO_FORMAT, key_vno); (void) printf(PAD); if (key) { print_key(old_key); (void) printf(PAD); } print_name(sname, sinst, srealm); (void) printf("\n"); } else if (change) { (void) printf("\nPrincipal: "); print_name(sname, sinst, srealm); (void) printf("; version %d\n", key_vno); if (interactive) change_this_key = yn("Change this key?"); else if (change) change_this_key = 1; else change_this_key = 0; if (change_this_key) (void) printf("Changing to version %d.\n", key_vno + 1); else if (change) (void) printf("Not changing this key.\n"); if (change_this_key) { /* * Pick a new key and determine whether or not * it is safe to change */ if ((status = get_svc_new_key(new_key, sname, sinst, srealm, keyfile)) == KADM_SUCCESS) key_vno++; else { (void) bcopy(old_key, new_key, sizeof(new_key)); (void) fprintf(stderr, "%s: Key NOT changed: %s\n", argv[0], krb_err_txt[status]); change_this_key = FALSE; } } else (void) bcopy(old_key, new_key, sizeof(new_key)); append_srvtab(argv[0], work_keyfile, work_keyfile_fd, sname, sinst, srealm, key_vno, new_key); if (key && change_this_key) { (void) printf("Old key: "); print_key(old_key); (void) printf("; new key: "); print_key(new_key); (void) printf("\n"); } if (change_this_key) { if ((status = kadm_change_pw(new_key)) == KADM_SUCCESS) { (void) printf("Key changed.\n"); (void) dest_tkt(); } else { com_err(argv[0], status, " attempting to change password."); (void) dest_tkt(); /* XXX This knows the format of a keyfile */ if (lseek(work_keyfile_fd, -9, L_INCR) >= 0) { key_vno--; safe_write(argv[0], work_keyfile, work_keyfile_fd, (char *)&key_vno, 1); safe_write(argv[0], work_keyfile, work_keyfile_fd, (char *)old_key, sizeof(des_cblock)); (void) fsync(work_keyfile_fd); (void) fprintf(stderr,"Key NOT changed.\n"); } else { warn("unable to revert keyfile"); leave("", 1); } } } } bzero((char *)old_key, sizeof(des_cblock)); bzero((char *)new_key, sizeof(des_cblock)); } } else if (add) { do { do { safe_read_stdin("Name: ", databuf, sizeof(databuf)); (void) strncpy(sname, databuf, sizeof(sname) - 1); safe_read_stdin("Instance: ", databuf, sizeof(databuf)); (void) strncpy(sinst, databuf, sizeof(sinst) - 1); safe_read_stdin("Realm: ", databuf, sizeof(databuf)); (void) strncpy(srealm, databuf, sizeof(srealm) - 1); safe_read_stdin("Version number: ", databuf, sizeof(databuf)); key_vno = atoi(databuf); if (!srealm[0]) (void) strcpy(srealm, local_realm); (void) printf("New principal: "); print_name(sname, sinst, srealm); (void) printf("; version %d\n", key_vno); } while (!yn("Is this correct?")); get_key_from_password(new_key); if (key) { (void) printf("Key: "); print_key(new_key); (void) printf("\n"); } append_srvtab(argv[0], work_keyfile, work_keyfile_fd, sname, sinst, srealm, key_vno, new_key); (void) printf("Key successfully added.\n"); } while (yn("Would you like to add another key?")); } if (change || list) if (close(backup_keyfile_fd) < 0) { warn("failure closing %s, continuing", backup_keyfile); } if (change || add) { if (close(work_keyfile_fd) < 0) { err(1, "failure closing %s", work_keyfile); } if (rename(work_keyfile, keyfile) < 0) { err(1, "failure renaming %s to %s", work_keyfile, keyfile); } (void) chmod(backup_keyfile, keyfile_mode); (void) chmod(keyfile, keyfile_mode); (void) printf("Old keyfile in %s.\n", backup_keyfile); } exit(0); } void print_key(key) des_cblock key; { int i; for (i = 0; i < 4; i++) (void) printf("%02x", key[i]); (void) printf(" "); for (i = 4; i < 8; i++) (void) printf("%02x", key[i]); } void print_name(name, inst, realm) char *name; char *inst; char *realm; { (void) printf("%s%s%s%s%s", name, inst[0] ? "." : "", inst, realm[0] ? "@" : "", realm); } int get_svc_new_key(new_key, sname, sinst, srealm, keyfile) des_cblock new_key; char *sname; char *sinst; char *srealm; char *keyfile; { int status = KADM_SUCCESS; if (((status = krb_get_svc_in_tkt(sname, sinst, srealm, PWSERV_NAME, KADM_SINST, 1, keyfile)) == KSUCCESS) && ((status = kadm_init_link("changepw", KRB_MASTER, srealm)) == KADM_SUCCESS)) { #ifdef NOENCRYPTION (void) bzero((char *) new_key, sizeof(des_cblock)); new_key[0] = (unsigned char) 1; #else /* NOENCRYPTION */ (void) des_random_key(new_key); #endif /* NOENCRYPTION */ return(KADM_SUCCESS); } return(status); } void get_key_from_password(key) des_cblock key; { char password[MAX_KPW_LEN]; /* storage for the password */ if (read_long_pw_string(password, sizeof(password)-1, "Password: ", 1)) leave("Error reading password.", 1); #ifdef NOENCRYPTION (void) bzero((char *) key, sizeof(des_cblock)); key[0] = (unsigned char) 1; #else /* NOENCRYPTION */ (void) des_string_to_key(password, key); #endif /* NOENCRYPTION */ (void) bzero((char *)password, sizeof(password)); } usage() { (void) fprintf(stderr, "Usage: ksrvutil [-f keyfile] [-i] [-k] "); (void) fprintf(stderr, "{list | change | add}\n"); (void) fprintf(stderr, " -i causes the program to ask for "); (void) fprintf(stderr, "confirmation before changing keys.\n"); (void) fprintf(stderr, " -k causes the key to printed for list or "); (void) fprintf(stderr, "change.\n"); exit(1); } void leave(str,x) char *str; int x; { if (str) (void) fprintf(stderr, "%s\n", str); (void) dest_tkt(); exit(x); }