/* * kadmin/v5client/kadmin5.c * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * */ /* * kadmin5.c - Perform administrative functions using the new * administrative protocol. */ #include "k5-int.h" #include "com_err.h" #include "adm.h" #include "kadmin5.h" #if HAVE_PWD_H #include #endif /* HAVE_PWD_H */ #if HAVE_REGEX_H #include #endif /* HAVE_REGEX_H */ /* * Global storage. */ int exit_status = 0; krb5_context kcontext; krb5_ccache ccache2use = (krb5_ccache) NULL; char *programname = (char *) NULL; char *requestname = (char *) NULL; krb5_boolean multiple = 0; char *principal_name = (char *) NULL; char *password_prompt = (char *) NULL; char *ccname2use = (char *) NULL; krb5_timestamp ticket_life = 0; krb5_boolean delete_ccache = 0; extern krb5_kt_ops krb5_ktf_writable_ops; /* * Own storage */ static char *realm_name = (char *) NULL; #if !HAVE_RE_COMP && !HAVE_REGCOMP static char *re_string = (char *) NULL; #endif /* !HAVE_RE_COMP && !HAVE_REGCOMP */ /* * Static strings. */ static const char *help_option = "-help"; static const char *verbose_option = "-verbose"; static const char *force_option = "-force"; static const char *kadmin_instance = "kadmin"; static const char *wr_ktab_type = "WRFILE"; static const char *gent_opterr_fmt = "- cannot decode protocol"; static const char *db_print_header = "------------------------------------\n"; static const char *db_print_1_fmt = "Principal: %s (key version %d)\n"; static const char *db_print_2_fmt = "Maximum ticket lifetime: %s\n"; static const char *db_print_2a_fmt = "Maximum renewable lifetime: %s\n"; static const char *db_print_3_fmt = "Principal expiration: %s\n"; static const char *db_print_3a_fmt = "Password expiration: %s\n"; static const char *db_print_4_fmt = "Last password change: %s\n"; static const char *db_print_5_fmt = "Last successful entry: %s\n"; static const char *db_print_6_fmt = "Last unsuccessful entry: %s"; static const char *db_print_6_opt_fmt = " - failed %d times"; static const char *db_print_7_fmt = "Last modified by: %s (%s)\n\t[master version %d]\n"; static const char *db_print_8_fmt = "Flags: %s\n"; static const char *db_print_9_fmt = "Salt: %s"; static const char *db_print_9a_fmt = ", %s"; static const char *db_print_trailer = "------------------------------------\n"; static const char *db_indef_dt_msg = "indefinite"; static const char *db_never_msg = "never"; static const char *db_none_msg = "none"; static const char *sprinc_usage_fmt = "usage is %s principal [...]"; static const char *add_usage_fmt = "usage is %s principal [attributes...]"; static const char *add_prompt1_fmt = " Enter new password for %s : "; static const char *add_prompt2_fmt = "Re-enter new password for %s : "; static const char *add_succ_fmt = "principal %s added"; static const char *add_protoerr_fmt = "- protocol encode error"; static const char *add_noconf_fmt = "password not confirmed"; static const char *add_synerr_fmt = "syntax error"; static const char *cpw_usage_fmt = "usage is %s principal"; static const char *cpw_prompt1_fmt = " Enter new password for %s: "; static const char *cpw_prompt2_fmt = "Re-enter new password for %s: "; static const char *cpw_succ_fmt = "password changed for %s"; static const char *cpw_nochange_fmt = "password not changed for %s"; static const char *dprinc_usage_fmt = "usage is %s [%s] principal [...]"; static const char *del_conf_fmt = "Enter '%c' to delete principal %s: "; static const char del_conf_char = 'y'; static const char *del_princ_fmt = "principal %s deleted."; static const char *del_noconf_fmt = "not confirmed - principal %s not deleted"; static const char *xst_ktab_name_fmt = "%s:%s-new-srvtab"; static const char *xst_k4tab_name_fmt = "%s-new-v4-srvtab"; static const char *xst_dfl_ktname = "DEFAULT"; static const char *xst_usage_fmt = "usage is %s instance principal [...]"; static const char *xst_wr_reg_fmt = "(%s) cannot register writeable keytable"; static const char *xst_inst2long_fmt = "'%s' is too long for a filename, using '%s' instead"; static const char *xst_nokeytab_fmt = "cannot open key table %s"; static const char *xst_nodeskey_fmt = "%s does not have a DES key"; static const char *xst_adderr_fmt = "cannot add entry %s"; static const char *xst_success_fmt = "extracted entry %s to key table %s"; static const char *xst_proto_fmt = "cannot decode service key table entry from protocol"; static const char *xst_kclose_fmt = "cannot close key table %s"; static const char *mod_usage_fmt = "usage is %s principal [attributes...]"; static const char *mod_succ_fmt = "principal %s modified."; static const char *mod_protoerr_fmt = "protocol encode error"; static const char *mod_synerr_fmt = "syntax error"; static const char *rprinc_usage_fmt = "usage is %s [%s] principal principal"; static const char *ren_conf_fmt = "Enter '%c' to rename principal %s to %s: "; static const char ren_conf_char = 'y'; static const char *ren_princ_fmt = "principal %s renamed to %s."; static const char *ren_noconf_fmt = "not confirmed - principal %s not renamed to %s."; #if HAVE_RE_COMP || HAVE_REGCOMP static const char *lprinc_usage_fmt = "usage is %s [%s] "; #else /* HAVE_RE_COMP || HAVE_REGCOMP */ static const char *lprinc_usage_fmt = "usage is %s [%s] princpal"; #endif /* HAVE_RE_COMP || HAVE_REGCOMP */ static const char *lprinc_all_regexp = ".*"; static const char *lprinc_regexp_fmt = "%s - regular expression error: %s"; static const char *lprinc_regsrch_fmt = "%s on %s - RE search error: %s"; static const char *lprinc_first_msg = "first database entry"; static const char *cant_get_fmt = "cannot get entry for %s"; static const char *no_memory_fmt = "cannot get memory"; static const char *lang_usage_fmt = "usage is %s language"; static const char *cd_cannot_fmt = "cannot change directory to %s"; static const char *cd_usage_fmt = "usage is %s directory"; static const char *pwd_mess_fmt = "Current directory is %s\n"; static const char *pwd_err_fmt = "cannot get current directory: %s"; static const char *pwd_usage_fmt = "usage is %s"; static const char *kadmin_badtime_fmt = "%s is a bad time value"; static const char *kadmin_usage_fmt = "usage is %s [-c ccache] [-r realm] [-p principal] [-l lifetime] [-dms] [command ...]"; static const char *kadmin_sd_err_fmt = "-d and -s are mutually exclusive"; static const char *kadmin_defrealm_msg = ": cannot get default realm"; static const char *kadmin_srealm_fmt = ": cannot set realm to \"%s\""; static const char *kadmin_ccache_fmt = ": cannot find credential cache %s"; static const char *kadmin_nopname_msg = ": cannot find a principal name"; static const char *kadmin_unparse_msg = ": cannot flatten principal name"; static const char *kadmin_nocomp_msg = ": no components in principal name"; static const char *kadmin_noprompt_msg = ": cannot make password prompt"; static const char *kadmin_pprompt_fmt = "Enter password for %s: "; #if !HAVE_RE_COMP && !HAVE_REGCOMP /* * re_comp() - Compile a regular expression for subsequent usage by re_exec * * This routine is only a shell. Null expressions or expressions matching * lprinc_all_regexp are taken to match everything, all others are * interpreted as "string".*. */ static char * re_comp(rstring) char *rstring; { if (strlen(rstring) && strcmp(rstring, lprinc_all_regexp)) { re_string = rstring; } else { re_string = (char *) NULL; } return((char *) NULL); } /* * re_exec() - Attempt to match a string to a regular expression previously * specified to re_comp(). * * This routine is only a shell. */ static int re_exec(sstring) char *sstring; { if (re_string) return(strncmp(sstring, re_string, strlen(re_string)) ? 0 : 1); else return(1); } #endif /* !HAVE_RE_COMP && !HAVE_REGCOMP */ /* * kadmin_get_entry() - Get a principal entry. */ static krb5_error_code kadmin_get_entry(pname, validp, dbentp, nextp) char *pname; krb5_ui_4 *validp; krb5_db_entry *dbentp; char **nextp; { krb5_error_code kret; krb5_int32 proto_stat; krb5_int32 ncomps; krb5_data *complist; char *pword; if (!(kret = net_do_proto(KRB5_ADM_INQ_PRINC_CMD, pname, (char *) NULL, 0, (krb5_data *) NULL, &proto_stat, &ncomps, &complist))) { if (proto_stat == KRB5_ADM_SUCCESS) { *nextp = (char *) malloc((size_t) complist[0].length + 1); if (*nextp) { strncpy(*nextp, complist[0].data, (size_t) complist[0].length); (*nextp)[complist[0].length] = '\0'; } if (!(kret = krb5_adm_proto_to_dbent(kcontext, ncomps-1, &complist[1], validp, dbentp, &pword))) { if (pword) krb5_xfree(pword); } else { com_err(requestname, kret, gent_opterr_fmt); } krb5_free_adm_data(kcontext, ncomps, complist); } else kret = EIO; } return(kret); } /* * kadmin_princ_entry() - Print out a database entry. */ static void kadmin_print_entry(name, valid, dbentp) char *name; krb5_ui_4 valid; krb5_db_entry *dbentp; { printf(db_print_header); printf(db_print_1_fmt, name, ((valid & KRB5_ADM_M_KVNO) ? dbentp->kvno : -1)); printf(db_print_2_fmt, ((valid & KRB5_ADM_M_MAXLIFE) ? delta2string(dbentp->max_life) : db_indef_dt_msg)); printf(db_print_2a_fmt, ((valid & KRB5_ADM_M_MAXRENEWLIFE) ? delta2string(dbentp->max_renewable_life) : db_indef_dt_msg)); printf(db_print_3_fmt, ((valid & KRB5_ADM_M_EXPIRATION) ? abs2string(dbentp->expiration) : db_never_msg)); printf(db_print_3a_fmt, ((valid & KRB5_ADM_M_PWEXPIRATION) ? abs2string(dbentp->pw_expiration) : db_never_msg)); printf(db_print_4_fmt, ((valid & KRB5_ADM_M_LASTPWCHANGE) ? abs2string(dbentp->last_pwd_change) : db_never_msg)); printf(db_print_5_fmt, ((valid & KRB5_ADM_M_LASTSUCCESS) ? abs2string(dbentp->last_success) : db_never_msg)); if ((valid & KRB5_ADM_M_FAILCOUNT) && (dbentp->fail_auth_count > 0)) { printf(db_print_6_fmt, ((valid & KRB5_ADM_M_LASTFAILED) ? abs2string(dbentp->last_failed) : db_never_msg)); printf(db_print_6_opt_fmt, dbentp->fail_auth_count); printf("\n"); } if (valid & KRB5_ADM_M_MODNAME) { char *mname; if (!krb5_unparse_name(kcontext, dbentp->mod_name, &mname)) { printf(db_print_7_fmt, mname, ((valid & KRB5_ADM_M_MODDATE) ? abs2string(dbentp->mod_date) : db_never_msg), ((valid & KRB5_ADM_M_MKVNO) ? dbentp->mkvno : -1)); krb5_xfree(mname); } } printf(db_print_8_fmt, ((valid & KRB5_ADM_M_FLAGS) ? dbflags2string(dbentp->attributes) : "")); if (valid & KRB5_ADM_M_SALTTYPE) { printf(db_print_9_fmt, salt2string(dbentp->salt_type)); if (dbentp->salt_type != dbentp->alt_salt_type) printf(db_print_9a_fmt, salt2string(dbentp->alt_salt_type)); printf("\n"); } printf(db_print_trailer); } /* * Dispatch procedures. */ /* * kadmin_show_principal() - Show a principal. */ void kadmin_show_principal(argc, argv) int argc; char *argv[]; { int i; krb5_error_code kret; char *xxx; krb5_ui_4 valid; krb5_db_entry *dbentry; requestname = argv[0]; if (argc == 1) { com_err(argv[0], 0, sprinc_usage_fmt, argv[0]); return; } for (i=1; i= sizeof(keytab_name)) { com_err(requestname, 0, xst_inst2long_fmt, instance, xst_dfl_ktname); sprintf(keytab_name, xst_ktab_name_fmt, wr_ktab_type, xst_dfl_ktname); } else sprintf(keytab_name, xst_ktab_name_fmt, wr_ktab_type, instance); actname = &keytab_name[strlen(wr_ktab_type)+1]; if (kret = krb5_kt_resolve(kcontext, keytab_name, &keytab_id)) { com_err(requestname, kret, xst_nokeytab_fmt, actname); return; } memset((char *) &keytab_entry, 0, sizeof(krb5_keytab_entry)); for (i=0; i= sizeof(keytab_name)) { com_err(requestname, 0, xst_inst2long_fmt, instance, xst_dfl_ktname); sprintf(keytab_name, xst_k4tab_name_fmt, xst_dfl_ktname); } else sprintf(keytab_name, xst_k4tab_name_fmt, instance); if ((v4tab = fopen(keytab_name, "w")) == NULL) { com_err(requestname, errno, xst_nokeytab_fmt, keytab_name); return; } memset((char *) &keytab_entry, 0, sizeof(krb5_keytab_entry)); for (i=0; i 0) { if (!strcmp(argv[0], force_option)) { force = 1; argc--; argv++; } if (argc != 2) uerr++; } else uerr++; if (uerr) { com_err(requestname, 0, rprinc_usage_fmt, requestname, force_option); return; } doit = 0; if (force) { doit = 1; } else { int c; printf(ren_conf_fmt, ren_conf_char, argv[0], argv[1]); if (getchar() == ren_conf_char) doit = 1; while (((c = getchar()) != '\n') && (c != EOF)); } if (doit) { if (!(kret = net_do_proto(KRB5_ADM_REN_PRINC_CMD, argv[0], argv[1], 0, (krb5_data *) NULL, &proto_stat, &ncomps, &complist))) { if (proto_stat == KRB5_ADM_SUCCESS) { com_err(programname, 0, ren_princ_fmt, argv[0], argv[1]); krb5_free_adm_data(kcontext, ncomps, complist); } } } else { com_err(programname, 0, ren_noconf_fmt, argv[0], argv[1]); } } /* * kadmin_list() - List principals. */ void kadmin_list(argc, argv) int argc; char *argv[]; { krb5_error_code kret; int error; int i; krb5_boolean verbose; char *re_result; #if HAVE_REGCOMP regex_t match_exp; regmatch_t match_match; int match_error; char match_errmsg[BUFSIZ]; size_t errmsg_size; #endif /* HAVE_REGCOMP */ #if HAVE_RE_COMP && !HAVE_REGCOMP extern char *re_comp(); #endif /* HAVE_RE_COMP && !HAVE_REGCOMP */ requestname = argv[0]; error = 0; verbose = 0; for (i=1; i 0) { krb5_data *dp; dp = krb5_princ_component(kcontext, me, 0); if (user = (char *) malloc((size_t) dp->length + 1)) { strncpy(user, dp->data, (size_t) dp->length); user[dp->length] = '\0'; } else { kret = ENOMEM; } } else { com_err(argv[0], 0, kadmin_nocomp_msg); exit(1); } } /* Then try our default credentials cache */ else if (!(kret = krb5_cc_default(kcontext, &ccache)) && !(kret = krb5_cc_get_principal(kcontext, ccache, &me))) { /* Use our first component, if it exists. */ if (krb5_princ_size(kcontext, me) > 0) { krb5_data *dp; dp = krb5_princ_component(kcontext, me, 0); if (user = (char *) malloc((size_t) dp->length + 1)) { strncpy(user, dp->data, (size_t) dp->length); user[dp->length] = '\0'; } else { kret = ENOMEM; } } else { com_err(argv[0], 0, kadmin_nocomp_msg); exit(1); } } else if (user = getenv("USER")) { char *xxx; xxx = (char *) malloc(strlen(user)+1); if (xxx) { strcpy(xxx, user); kret = 0; } user = xxx; } #if HAVE_PWD_H else if (pw = getpwuid(getuid())) { if (user = (char *) malloc(strlen(pw->pw_name)+1)) { strcpy(user, pw->pw_name); kret = 0; } else kret = ENOMEM; } #endif /* HAVE_PWD_H */ if (user) { if (principal_name = (char *) malloc(strlen(user)+1+ strlen(kadmin_instance)+1+ strlen(realm_name)+1)) { sprintf(principal_name, "%s/%s@%s", user, kadmin_instance, realm_name); free(user); } else kret = ENOMEM; } if (kret || !user) { com_err(argv[0], kret, kadmin_nopname_msg); exit(1); } if (ccache) krb5_cc_close(kcontext, ccache); if (me) krb5_free_principal(kcontext, me); } /* Formulate the password prompt while we're here */ if (password_prompt = (char *) malloc(strlen(kadmin_pprompt_fmt)+ strlen(principal_name)+1)) { sprintf(password_prompt, kadmin_pprompt_fmt, principal_name); } else { com_err(argv[0], ENOMEM, kadmin_noprompt_msg); exit(1); } /* See if something's left, e.g. a request */ if (argc > optind) { size_t n2alloc; int i; n2alloc = 0; for (i=optind; i