RCS file: kadmin/RCS/Imakefile,v retrieving revision 4.9 diff -c -r4.9 kadmin/Imakefile *** /tmp/,RCSt1019447 Tue Jul 21 22:35:36 1992 --- kadmin/Imakefile Tue Jul 21 00:42:46 1992 *************** *** 22,29 **** USRCS = ksrvutil.c UOBJS = ksrvutil.o ! SRCS = $(SSRCS) $(PSRCS) $(ASRCS) $(USRCS) SRCDIR=$(SRCTOP)/kadmin CODE=$(SRCS) Imakefile kadmin_cmds.ct kadm_server.h --- 22,33 ---- USRCS = ksrvutil.c UOBJS = ksrvutil.o ! GSRCS = get_srvtab.c ! GOBJS = get_srvtab.o + + SRCS = $(SSRCS) $(PSRCS) $(ASRCS) $(USRCS) $(GSRCS) + SRCDIR=$(SRCTOP)/kadmin CODE=$(SRCS) Imakefile kadmin_cmds.ct kadm_server.h *************** *** 40,46 **** --- 44,52 ---- program(ksrvutil,$(UOBJS),${COM_ERR_DEP} ${KADM_LIBDEP} ${KRB_LIBDEP} ${DES_LIBDEP},${COM_ERR} ${KADM_LIB} ${KRB_LIB} ${DES_LIB},${PROGDIR}) program(kadmind,$(SOBJS),${HESIOD_LIBDEP} ${COM_ERR_DEP} ${ACL_LIBDEP} ${KADM_LIBDEP} ${KDB_LIBDEP} ${KRB_LIBDEP} ${DES_LIBDEP},${HESIOD_LIB} ${COM_ERR} ${ACL_LIB} ${KADM_LIB} ${KDB_LIB} ${KRB_LIB} ${DES_LIB},${DAEMDIR}) program(build_pwfile,build_pwfile.o,${DES_LIBDEP},${KDB_LIB} ${DES_LIB},${PROGDIR}) + program(get_srvtab,$(GOBJS),${COM_ERR_DEP} ${KADM_LIBDEP} ${KRB_LIBDEP} ${DES_LIBDEP},${COM_ERR} ${KADM_LIB} ${KRB_LIB} ${DES_LIB},${PROGDIR}) depend:: ${CODE} + RCS file: kadmin/RCS/admin_server.c,v retrieving revision 4.10 diff -c -r4.10 kadmin/admin_server.c *** /tmp/,RCSt1019452 Tue Jul 21 22:35:39 1992 --- kadmin/admin_server.c Tue Jul 21 17:56:54 1992 *************** *** 290,295 **** --- 290,298 ---- int more; int status; + /* Must do it here, since this is after the fork() call */ + des_init_random_number_generator(server_parm.master_key); + if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) log("setsockopt keepalive: %d",errno); RCS file: kadmin/RCS/kadm_funcs.c,v retrieving revision 4.5 diff -c -r4.5 kadmin/kadm_funcs.c *** /tmp/,RCSt1019457 Tue Jul 21 22:35:41 1992 --- kadmin/kadm_funcs.c Tue Jul 21 21:47:31 1992 *************** *** 21,26 **** --- 21,27 ---- the actual database manipulation code */ + #include #include #include #include *************** *** 55,60 **** --- 56,64 ---- case MODACL: (void) sprintf(filename, "%s%s", acldir, MOD_ACL_FILE); break; + case STABACL: + (void) sprintf(filename, "%s%s", acldir, STAB_ACL_FILE); + break; } return(acl_check(filename, checkname)); } *************** *** 541,543 **** --- 545,680 ---- } return(0); } + + /* + * This routine checks to see if a principal should be considered an + * allowable service name which can be changed by kadm_change_srvtab. + * + * We do this check by using the ACL library. This makes the + * (relatively) reasonable assumption that both the name and the + * instance will not contain '.' or '@'. + */ + kadm_check_srvtab(name, instance) + char *name; + char *instance; + { + FILE *f; + char filename[MAXPATHLEN]; + char buf[ANAME_SZ], *cp; + + (void) sprintf(filename, "%s%s", acldir, STAB_SERVICES_FILE); + if (!acl_check(filename, name)) + return(KADM_NOT_SERV_PRINC); + + (void) sprintf(filename, "%s%s", acldir, STAB_HOSTS_FILE); + if (acl_check(filename, instance)) + return(KADM_NOT_SERV_PRINC); + return 0; + } + + /* + * Routine to allow some people to change the key of a srvtab + * principal to a random key, which the admin server will return to + * the client. + */ + #define failsrvtab(code) { (void) log("change_srvtab: FAILED changing '%s.%s' by '%s.%s@%s' (%s)", values->name, values->instance, rname, rinstance, rrealm, error_message(code)); return code; } + + kadm_chg_srvtab(rname, rinstance, rrealm, values) + char *rname; /* requestors name */ + char *rinstance; /* requestors instance */ + char *rrealm; /* requestors realm */ + Kadm_vals *values; + { + int numfound, more, ret; + des_cblock new_key; + Principal principal; + + if (!check_access(rname, rinstance, rrealm, STABACL)) + failsrvtab(KADM_UNAUTH); + if (wildcard(rname) || wildcard(rinstance)) + failsrvtab(KADM_ILL_WILDCARD); + if (ret = kadm_check_srvtab(values->name, values->instance)) + failsrvtab(ret); + + /* + * OK, get the entry + */ + numfound = kerb_get_principal(values->name, values->instance, + &principal, 1, &more); + if (numfound == -1) { + failsrvtab(KADM_DB_INUSE); + } else if (numfound) { + principal.key_version++; + } else { + /* + * This is a new srvtab entry that we're creating + */ + strcpy(principal.name, values->name, ANAME_SZ); + strcpy(principal.instance, values->instance, INST_SZ); + + principal.exp_date = 946702799; /* Happy new century */ + strncpy(principal.exp_date_txt, "12/31/99", DATE_SZ); + + principal.attributes = 0; + principal.max_life = 255; + + principal.key_version = 1; + } + + #ifdef NOENCRYPTION + bzero(new_key, sizeof(new_key)); + new_key[0] = 127; + #else + des_new_random_key(new_key); + #endif + /* + * Store the new key in the return structure; also fill in the + * rest of the fields. + */ + bcopy(new_key, &values->key_low, 4); + bcopy(((long *) new_key) + 1, &values->key_high, 4); + values->max_life = principal.key_version; + values->exp_date = principal.exp_date; + values->attributes = principal.attributes; + bzero(values->fields, sizeof(values->fields)); + SET_FIELD(KADM_NAME, values->fields); + SET_FIELD(KADM_INST, values->fields); + SET_FIELD(KADM_EXPDATE, values->fields); + SET_FIELD(KADM_ATTR, values->fields); + SET_FIELD(KADM_MAXLIFE, values->fields); + SET_FIELD(KADM_DESKEY, values->fields); + + /* + * Encrypt the new key with the master key, and then update + * the database record + */ + kdb_encrypt_key (new_key, new_key, server_parm.master_key, + server_parm.master_key_schedule, ENCRYPT); + bcopy(new_key, &principal.key_low, 4); + bcopy(((long *) new_key) + 1, &principal.key_high, 4); + bzero(new_key, sizeof(des_cblock)); + + principal.kdc_key_ver = server_parm.master_key_version; + + principal.mod_date = time(0); + principal.old = 0; + strncpy(principal.mod_name, rname, ANAME_SZ); + strncpy(principal.mod_instance, rinstance, INST_SZ); + + more = kerb_put_principal(&principal, 1); + if (more == -1) { + failsrvtab(KADM_DB_INUSE); + } else if (more) { + failsrvtab(KADM_UK_SERROR); + } else { + (void) log("change_srvtab: service '%s.%s' %s by %s.%s@%s.", + values->name, values->instance, + numfound ? "changed" : "created", + rname, rinstance, rrealm); + return KADM_DATA; + } + } + + #undef failsrvtab + + RCS file: kadmin/RCS/kadm_ser_wrap.c,v retrieving revision 4.6 diff -c -r4.6 kadmin/kadm_ser_wrap.c *** /tmp/,RCSt1019464 Tue Jul 21 22:35:46 1992 --- kadmin/kadm_ser_wrap.c Mon Jul 20 17:19:51 1992 *************** *** 183,188 **** --- 183,192 ---- retval = kadm_ser_ckpw(msg_st.app_data+1,(int) msg_st.app_length,&ad, &retdat, &retlen); break; + case CHG_STAB: + retval = kadm_ser_stab(msg_st.app_data+1,(int) msg_st.app_length,&ad, + &retdat, &retlen); + break; default: clr_cli_secrets(); errpkt(dat, dat_len, KADM_NO_OPCODE); RCS file: kadmin/RCS/kadm_server.c,v retrieving revision 4.5 diff -c -r4.5 kadmin/kadm_server.c *** /tmp/,RCSt1019470 Tue Jul 21 22:35:48 1992 --- kadmin/kadm_server.c Tue Jul 21 22:33:59 1992 *************** *** 120,126 **** *outlen = 0; } ! return(kadm_change(ad->pname, ad->pinst, ad->prealm, newkey)); } /* --- 120,129 ---- *outlen = 0; } ! retval = kadm_change(ad->pname, ad->pinst, ad->prealm, newkey); ! keylow = keyhigh = 0; ! bzero(newkey, sizeof(newkey)); ! return retval; } /* *************** *** 148,153 **** --- 151,157 ---- if ((status = kadm_add_entry(ad->pname, ad->pinst, ad->prealm, &values, &retvals)) == KADM_DATA) { *outlen = vals_to_stream(&retvals,datout); + retvals.key_low = retvals.key_high = 0; return KADM_SUCCESS; } else { *outlen = 0; *************** *** 183,188 **** --- 187,193 ---- if ((status = kadm_mod_entry(ad->pname, ad->pinst, ad->prealm, &vals1, &vals2, &retvals)) == KADM_DATA) { *outlen = vals_to_stream(&retvals,datout); + retvals.key_low = retvals.key_high = 0; return KADM_SUCCESS; } else { *outlen = 0; *************** *** 221,226 **** --- 226,232 ---- if ((status = kadm_get_entry(ad->pname, ad->pinst, ad->prealm, &values, fl, &retvals)) == KADM_DATA) { *outlen = vals_to_stream(&retvals,datout); + retvals.key_low = retvals.key_high = 0; return KADM_SUCCESS; } else { *outlen = 0; *************** *** 270,277 **** keyhigh = ntohl(keyhigh); bcopy((char *)&keyhigh, (char *)(((long *)newkey) + 1), 4); bcopy((char *)&keylow, (char *)newkey, 4); ! if (retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm, newkey, ! no_pword ? 0 : pword)) { *outlen = strlen(check_pw_msg)+strlen(pw_blurb)+1; if (*datout = (u_char *) malloc(*outlen)) { strcpy(*datout, check_pw_msg); --- 276,286 ---- keyhigh = ntohl(keyhigh); bcopy((char *)&keyhigh, (char *)(((long *)newkey) + 1), 4); bcopy((char *)&keylow, (char *)newkey, 4); ! keylow = keyhigh = 0; ! retval = kadm_approve_pw(ad->pname, ad->pinst, ad->prealm, newkey, ! no_pword ? 0 : pword); ! bzero(newkey, sizeof(newkey)); ! if (retval) { *outlen = strlen(check_pw_msg)+strlen(pw_blurb)+1; if (*datout = (u_char *) malloc(*outlen)) { strcpy(*datout, check_pw_msg); *************** *** 290,292 **** --- 299,334 ---- return(0); } + /* + kadm_ser_stab - the server side of the change_srvtab routine + recieves : KTEXT, {values} + returns : CKSUM, RETCODE, {values} + acl : su, sms (as register or dealloc) + + Creates or modifies the specified service principal to have a random + key, which is sent back to the client. The key version is returned in + the max_life field of the values structure. It's a hack, but it's a + backwards compatible hack.... + */ + kadm_ser_stab(dat, len, ad, datout, outlen) + u_char *dat; + int len; + AUTH_DAT *ad; + u_char **datout; + int *outlen; + { + Kadm_vals values; + int status; + + if ((status = stream_to_vals(dat, &values, len)) < 0) + return KADM_LENGTH_ERROR; + status = kadm_chg_srvtab(ad->pname, ad->pinst, ad->prealm, &values); + if (status == KADM_DATA) { + *outlen = vals_to_stream(&values,datout); + values.key_low = values.key_high = 0; + return KADM_SUCCESS; + } else { + *outlen = 0; + return status; + } + } RCS file: kadmin/RCS/kadm_server.h,v retrieving revision 4.3 diff -c -r4.3 kadmin/kadm_server.h *** /tmp/,RCSt1019475 Tue Jul 21 22:35:50 1992 --- kadmin/kadm_server.h Tue Jul 21 00:17:11 1992 *************** *** 51,55 **** --- 51,58 ---- #define ADD_ACL_FILE "/admin_acl.add" #define GET_ACL_FILE "/admin_acl.get" #define MOD_ACL_FILE "/admin_acl.mod" + #define STAB_ACL_FILE "/admin_acl.srvtab" + #define STAB_SERVICES_FILE "/admin_stab_services" + #define STAB_HOSTS_FILE "/admin_stab_bad_hosts" #endif /* KADM_SERVER_DEFS */ *** /dev/null Tue Jul 21 21:44:16 1992 --- kadmin/get_srvtab.c Tue Jul 21 22:12:22 1992 *************** *** 0 **** --- 1,350 ---- + /* + * $Source:$ + * $Author:$ + * + * Copyright 1992 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * Remotely generate a srvtab file for a particular host. + */ + + #include + #include + #include + #include + #include + #include + #include + #include + + #include "kadm_server.h" + + #define MAX_SERVICES 16 + #define MAX_HOSTS 128 + + int n_services, n_hosts; + char *service_names[MAX_SERVICES], *host_names[MAX_HOSTS]; + + char myname[ANAME_SZ]; + char myinst[INST_SZ]; + char myrealm[REALM_SZ]; + + char realm[REALM_SZ]; + char *progname; + + #define TRUE 1 + #define FALSE 0 + + #define BAD_PW 1 + #define GOOD_PW 0 + + #define PE_NO 0 + #define PE_YES 1 + #define PE_UNSURE 2 + + void clean_up(); + + usage() + { + fprintf (stderr, + "Usage: %s [-h] host1 ... hostN [-s service1 ... serviceN] [-r realm]\n", + progname); + fprintf(stderr, "Default is %s -s rcmd rvdsrv -h\n", progname); + exit (3); + } + + PRS(argc, argv) + int argc; + char **argv; + { + int reading_service, saw_service_arg, ret; + struct passwd *pw; + char tktstring[MAXPATHLEN]; + + progname = argv[0]; + + bzero(realm, sizeof(realm)); + reading_service = FALSE; + saw_service_arg = FALSE; + + n_services = 2; + n_hosts = 0; + + service_names[0] = "rcmd"; + service_names[1] = "rvdsrv"; + + myname[0] = myinst[0] = myrealm[0] = 0; + + while (--argc) { + argv++; + if (strcmp (*argv, "-s") == 0) { + /* this is the only way not to include rcmd */ + /* and rvdsrv or to add other services */ + if (!saw_service_arg) { + saw_service_arg = TRUE; + n_services = 0; + } + reading_service = TRUE; + continue; + } + if (strcmp (*argv, "-h") == 0) { + reading_service = FALSE; + continue; + } + if (strcmp (*argv, "-u") == 0) { + reading_service = FALSE; + argc--; argv++; + if (!argc) { + fprintf (stderr, + "%s: -u given but no principal.\n", + progname); + exit(2); + } + ret = kname_parse(myname, myinst, myrealm, *argv); + if (ret) { + fprintf(stderr, + "%s: invalid principal format.\n", + progname); + exit(2); + } + continue; + } + if (strcmp (*argv, "-r") == 0) { + reading_service = FALSE; + argc--; argv++; + if (!argc) { + fprintf (stderr, + "%s: -r given but no realm.\n", + progname); + exit (2); + } + strcpy (realm, *argv); + continue; + } + if (reading_service) { + if (n_services == MAX_SERVICES) { + fprintf (stderr, + "%s, Max number (%i) of services exceeded, need to recompile.\n", + progname, MAX_SERVICES); + exit(1); + } + service_names[n_services++] = *argv; + } + /* otherwise default to reading a host name */ + else { + if (*argv[0] == '-') + usage(); + if (n_hosts == MAX_HOSTS) { + fprintf (stderr, "%s, Max number (%i) of hosts exceeded, need to recompile.\n", + progname, MAX_HOSTS); + exit(1); + } + host_names[n_hosts++] = *argv; + } + } + + if ((n_services <= 0) || (n_hosts <= 0)) + usage(); + + if (!realm[0]) + if (krb_get_lrealm(realm, 1) != KSUCCESS) { + fprintf(stderr, "%s: couldn't get local realm\n", + progname); + exit(1); + } + + if (!myname[0]) { + pw = getpwuid((int) getuid()); + if (!pw) { + fprintf(stderr, + "You aren't in the password file. Who are you?\n"); + exit(1); + } + (void) strcpy(myname, pw->pw_name); + (void) strcpy(myinst, "root"); + (void) strcpy(myrealm, realm); + } + + if (!myrealm[0]) { + strcpy(myrealm, realm); + } + + ret = kadm_init_link(PWSERV_NAME, KRB_MASTER, realm); + if (ret != KADM_SUCCESS) { + fprintf(stderr, "%s: Couldn't initialize kadmin link: %s\n", + progname, error_message(ret)); + exit(1); + } + + (void) umask(077); + + /* + * OK, create the temporary ticket file; and get the tickets + */ + (void) sprintf(tktstring, "/tmp/tkt_adm_%d",getpid()); + krb_set_tkt_string(tktstring); + ret = get_admin_password(); + if (ret) { + fprintf(stderr, "%s: Couldn't get admin password.\n", + progname); + exit(1); + } + return 0; + } + + main(argc, argv) + int argc; + char **argv; + { + int i; + + PRS(argc, argv); + + for (i = 0; i < n_hosts; i++) { + make_srvtab (service_names, n_services, host_names[i]); + } + clean_up(); + exit(0); + } + + make_srvtab (services, n_services, host) + char *services[]; + int n_services; + char *host; + { + char buf[MAXPATHLEN]; + FILE *fout; + int i, ret; + int warned = 0; + Kadm_vals values; + + sprintf(buf, "%s-new-srvtab", host); + if ((fout = fopen(buf, "w")) == NULL) { + fprintf(stderr, "Couldn't create file '%s'.\n", buf); + return -1; + } + + printf("\n\tMaking srvtab for '%s'....\n", buf); + + for (i = 0; i < n_services; i++) { + if (!princ_exists(services[i], host, realm)) { + if (!warned) + printf("\n\007Warning: the following service(s) do not yet exist:\n"); + printf("\t%s.%s\n", services[i], host); + warned++; + } + } + if (warned) { + printf("If you proceed, they will be created. Do you wish to proceed(Y/N)? "); + fgets(buf, sizeof(buf), stdin); + if ((buf[0] != 'Y') && (buf[0] != 'y')) + return -1; + } + + for (i = 0; i < n_services; i++) { + ret = kadm_change_srvtab(services[i], host, &values); + if (ret) { + fprintf(stderr, "Couldn't get srvtab entry %s.%s: %s\n", + services[i], host, error_message(ret)); + continue; + } + fwrite(values.name, strlen(values.name) + 1, 1, fout); + fwrite(values.instance, strlen(values.instance) + 1, 1, fout); + fwrite(realm, strlen(realm) + 1, 1, fout); + /* Note: really max_lifetime is really key_version */ + fwrite(&values.max_life, sizeof(values.max_life), 1, fout); + fwrite(&values.key_low, sizeof(long), 1, fout); + fwrite(&values.key_high, sizeof(long), 1, fout); + values.key_low = values.key_high = 0; + } + fclose(fout); + printf("\n"); + return(0); + } + + #ifdef NOENCRYPTION + #define read_long_pw_string placebo_read_pw_string + #else + #define read_long_pw_string des_read_pw_string + #endif + extern int read_long_pw_string(); + + int + get_admin_password() + { + int status; + char admin_passwd[MAX_KPW_LEN]; /* Admin's password */ + char buf[1024]; + int ticket_life = 1; /* minimum ticket lifetime */ + + sprintf(buf, "Password for %s.%s@%s:", myname, myinst, myrealm); + if (princ_exists(myname, myinst, myrealm) != PE_NO) { + if (read_long_pw_string(admin_passwd, sizeof(admin_passwd)-1, + buf, 0)) { + fprintf(stderr, "Error reading admin password.\n"); + goto bad; + } + status = krb_get_pw_in_tkt(myname, myinst, myrealm, PWSERV_NAME, + KADM_SINST, ticket_life, admin_passwd); + bzero(admin_passwd, sizeof(admin_passwd)); + } + else + status = KDC_PR_UNKNOWN; + + switch(status) { + case GT_PW_OK: + return(GOOD_PW); + case KDC_PR_UNKNOWN: + printf("Principal %s.%s@%s does not exist.\n", myname, myinst, + myrealm); + goto bad; + case GT_PW_BADPW: + printf("Incorrect admin password.\n"); + goto bad; + default: + com_err(progname, status+krb_err_base, + "while getting password tickets"); + goto bad; + } + + bad: + bzero(admin_passwd, sizeof(admin_passwd)); + (void) dest_tkt(); + return(BAD_PW); + } + + void + clean_up() + { + (void) dest_tkt(); + return; + } + + void + quit() + { + printf("Cleaning up and exiting.\n"); + clean_up(); + exit(0); + } + + int + princ_exists(name, instance, realm) + char *name; + char *instance; + char *realm; + { + int status; + + status = krb_get_pw_in_tkt(name, instance, realm, "krbtgt", realm, 1, ""); + + if ((status == KSUCCESS) || (status == INTK_BADPW)) + return(PE_YES); + else if (status == KDC_PR_UNKNOWN) + return(PE_NO); + else + return(PE_UNSURE); + } + RCS file: lib/kadm/RCS/kadm_cli_wrap.c,v retrieving revision 4.8 diff -c -r4.8 lib/kadm/kadm_cli_wrap.c *** /tmp/,RCSt1019481 Tue Jul 21 22:35:56 1992 --- lib/kadm/kadm_cli_wrap.c Tue Jul 21 03:13:08 1992 *************** *** 344,349 **** --- 344,394 ---- } /* + * kadm_change_srvtab + * receives : name, instance + * returns : values + * + * Asks the admin server to change the srvtab key for the specified + * name, instance pair. The name, instance pair must be a valid + * server principal. + */ + kadm_change_srvtab(name, instance, values) + char *name, *instance; + Kadm_vals *values; + { + u_char *st, *st2; /* st will hold the stream of values */ + int st_len; /* st2 the final stream with opcode */ + int retc; /* return code from call */ + u_char *ret_st; + int ret_sz; + Kadm_vals vals; + + bzero((char *) &vals, sizeof(vals)); + strncpy(vals.name, name, sizeof(vals.name)); + strncpy(vals.instance, instance, sizeof(vals.instance)); + SET_FIELD(KADM_NAME,vals.fields); + SET_FIELD(KADM_INST,vals.fields); + + if ((retc = kadm_cli_conn()) != KADM_SUCCESS) + return(retc); + st_len = vals_to_stream(&vals, &st); + st2 = (u_char *) malloc((unsigned)(1 + st_len)); + *st2 = (u_char) CHG_STAB; /* here's the opcode */ + bcopy((char *) st, (char *) st2 + 1, st_len); /* append st on */ + retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz); + free((char *)st); + free((char *)st2); + if (retc == KADM_SUCCESS) { + /* ret_st has vals */ + if (stream_to_vals(ret_st, values, ret_sz) < 0) + retc = KADM_LENGTH_ERROR; + free((char *)ret_st); + } + kadm_cli_disconn(); + return(retc); + } + + /* * kadm_cli_send * recieves : opcode, packet, packet length, serv_name, serv_inst * returns : return code from the packet build, the server, or RCS file: lib/kadm/RCS/kadm_err.et,v retrieving revision 4.1 diff -c -r4.1 lib/kadm/kadm_err.et *** /tmp/,RCSt1019487 Tue Jul 21 22:35:59 1992 --- lib/kadm/kadm_err.et Mon Jul 20 22:19:52 1992 *************** *** 50,55 **** --- 50,58 ---- ec KADM_ILL_WILDCARD, "Illegal use of wildcard" ec KADM_DB_INUSE, "Database locked or in use" + ec KADM_INSECURE_PW, "Insecure password rejected" ec KADM_PW_MISMATCH, "Cleartext password and DES key did not match" + + ec KADM_NOT_SERV_PRINC, "Invalid principal for change srvtab request" end