Checkin new administrative client
authorPaul Park <pjpark@mit.edu>
Tue, 9 May 1995 19:58:24 +0000 (19:58 +0000)
committerPaul Park <pjpark@mit.edu>
Tue, 9 May 1995 19:58:24 +0000 (19:58 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5782 dc483132-0cff-0310-8789-dd5450dbe970

12 files changed:
src/kadmin/v5client/.Sanitize [new file with mode: 0644]
src/kadmin/v5client/.cvsignore [new file with mode: 0644]
src/kadmin/v5client/ChangeLog [new file with mode: 0644]
src/kadmin/v5client/Makefile.in [new file with mode: 0644]
src/kadmin/v5client/configure.in [new file with mode: 0644]
src/kadmin/v5client/convert.c [new file with mode: 0644]
src/kadmin/v5client/kadmin5.M [new file with mode: 0644]
src/kadmin/v5client/kadmin5.c [new file with mode: 0644]
src/kadmin/v5client/kadmin5.h [new file with mode: 0644]
src/kadmin/v5client/kadmin5_ct.ct [new file with mode: 0644]
src/kadmin/v5client/network.c [new file with mode: 0644]
src/kadmin/v5client/ss_wrapper.c [new file with mode: 0644]

diff --git a/src/kadmin/v5client/.Sanitize b/src/kadmin/v5client/.Sanitize
new file mode 100644 (file)
index 0000000..f85c410
--- /dev/null
@@ -0,0 +1,43 @@
+# Sanitize.in for Kerberos V5
+
+# Each directory to survive it's way into a release will need a file
+# like this one called "./.Sanitize".  All keyword lines must exist,
+# and must exist in the order specified by this file.  Each directory
+# in the tree will be processed, top down, in the following order.
+
+# Hash started lines like this one are comments and will be deleted
+# before anything else is done.  Blank lines will also be squashed
+# out.
+
+# The lines between the "Do-first:" line and the "Things-to-keep:"
+# line are executed as a /bin/sh shell script before anything else is
+# done in this 
+
+Do-first:
+
+# All files listed between the "Things-to-keep:" line and the
+# "Files-to-sed:" line will be kept.  All other files will be removed.
+# Directories listed in this section will have their own Sanitize
+# called.  Directories not listed will be removed in their entirety
+# with rm -rf.
+
+Things-to-keep:
+
+.cvsignore
+ChangeLog
+Makefile.in
+configure
+configure.in
+convert.c
+kadmin5.M
+kadmin5.c
+kadmin5.h
+kadmin5_ct.ct
+network.c
+ss_wrapper.c
+
+Things-to-lose:
+
+Do-last:
+
+# End of file.
diff --git a/src/kadmin/v5client/.cvsignore b/src/kadmin/v5client/.cvsignore
new file mode 100644 (file)
index 0000000..e8c05a6
--- /dev/null
@@ -0,0 +1 @@
+configure
diff --git a/src/kadmin/v5client/ChangeLog b/src/kadmin/v5client/ChangeLog
new file mode 100644 (file)
index 0000000..bafbabd
--- /dev/null
@@ -0,0 +1,4 @@
+
+Tue May 9 15:56:40 EDT 1995    Paul Park       (pjpark@mit.edu)
+       First checkin of new administrative client.
+
diff --git a/src/kadmin/v5client/Makefile.in b/src/kadmin/v5client/Makefile.in
new file mode 100644 (file)
index 0000000..08db709
--- /dev/null
@@ -0,0 +1,53 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+LDFLAGS = -g
+
+COMERRLIB=$(BUILDTOP)/util/et/libcom_err.a
+SSLIB=$(BUILDTOP)/util/ss/libss.a
+DBMLIB=
+KDBLIB=$(TOPLIBD)/libkdb5.a 
+DEPKDBLIB=$(TOPLIBD)/libkdb5.a 
+KADMLIB=$(TOPLIBD)/libkadm.a
+DEPKADMLIB=$(TOPLIBD)/libkadm.a
+
+all::
+
+KLIB = $(TOPLIBD)/libkrb5.a $(KRB4_LIB) $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+DEPKLIB = $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+
+
+DEPLIBS = $(DEPKDBLIB) $(DEPKLIB) $(DEPKADMLIB)
+LOCAL_LIBRARIES = $(KDBLIB) $(KADMLIB) $(KLIB)
+LOCALINCLUDE=
+
+OBJS= kadmin5.o \
+       kadmin5_ct.o \
+       network.o \
+       convert.o \
+       ss_wrapper.o \
+       $(LIBOBJS)
+
+SRCS= $(srcdir)/kadmin5.c \
+       $(srcdir)/kadmin5_ct.c \
+       $(srcdir)/ss_wrapper.c
+
+all:: kadmin5
+
+kadmin5: kadmin5.o $(DEPLIBS) $(OBJS)
+       $(CC) $(CFLAGS) -o kadmin5 $(OBJS) $(LOCAL_LIBRARIES) $(LIBS)
+
+install::
+       $(INSTALL_PROGRAM) kadmin5 ${DESTDIR}$(ADMIN_BINDIR)/kadmin5
+       $(INSTALL_DATA) $(srcdir)/kadmin5.M ${DESTDIR}$(ADMIN_MANDIR)/kadmin5.8
+
+# needed until we run makedepend
+kadmin5_ct.c: kadmin5_ct.ct
+
+kadmin5_ct.o: kadmin5_ct.c
+
+clean::
+       $(RM) kadmin5_ct.c
+
+depend:: kadmin5_ct.c
+
+clean::
+       $(RM) kadmin5
diff --git a/src/kadmin/v5client/configure.in b/src/kadmin/v5client/configure.in
new file mode 100644 (file)
index 0000000..d870e25
--- /dev/null
@@ -0,0 +1,16 @@
+AC_INIT(kadmin5.c)
+WITH_CCOPTS
+CONFIG_RULES
+AC_SET_BUILDTOP
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(pwd.h)
+AC_HAVE_FUNCS(strptime re_comp regcomp getcwd)
+AC_CONST
+WITH_NETLIB
+AC_CHECK_LIB(ndbm,main)
+AC_CHECK_LIB(dbm,main)
+SS_RULES
+KRB_INCLUDE
+WITH_KRB5ROOT
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/v5client/convert.c b/src/kadmin/v5client/convert.c
new file mode 100644 (file)
index 0000000..dc9dced
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+ * kadmin/v5client/convert.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.
+ *
+ */
+
+/*
+ * convert.c   - Perform various conversions for kadmin5.
+ */
+#include "k5-int.h"
+#include "adm.h"
+#include "kadmin5.h"
+\f
+/* Size of static buffers for conversions */
+#define        BUFFER_SIZE     512
+
+/* Forward declarations */
+static krb5_boolean get_integer PROTOTYPE((char *, const char *, void *));
+static krb5_boolean get_datestring PROTOTYPE((char *, const char *, void *));
+static krb5_boolean get_saltstring PROTOTYPE((char *, const char *, void *));
+/* static krb5_boolean get_deltastring PROTOTYPE((char *, const char *, void *)); */
+
+/* Local data structure for flag to string and option to flag operations */
+struct flagtable {
+    krb5_flags         f_value;
+    const char         *f_string;
+    const char                 *f_option;
+    krb5_boolean       f_sense;
+};
+
+/* Local data structure for option parsing */
+struct opttable {
+    krb5_ui_4          o_value;
+    const char         *o_option;
+    krb5_boolean       (*o_dispatch) PROTOTYPE((char *,
+                                                const char *,
+                                                void *));
+    void               *o_arg;
+};
+
+/*
+ * Static strings.
+ */
+static const char *dt_output_fmt       = "%d %s %d:%d:%d";
+static const char *dt_output_noday_fmt = "%d:%d:%d";
+static const char *dt_output_donly_fmt = "%d %s";
+static const char *dt_day_singular     = "day";
+static const char *dt_day_plural       = "days";
+static const char *dbflag_bit_fmt      = "Bit-%d";
+static const char *salt_norm_name      = "Normal";
+static const char *salt_v4_name                = "Kerberos V4";
+static const char *salt_norealm_name   = "NoRealm";
+static const char *salt_orealm_name    = "OnlyRealm";
+static const char *salt_special_name   = "Special";
+static const char *salt_ufo_fmt                = "Unknown(%d)";
+static const char *salt_norm_spec      = "v5";
+static const char *salt_v4_spec                = "v4";
+static const char *salt_norealm_spec   = "norealm";
+static const char *salt_orealm_spec    = "onlyrealm";
+static const char *salt_special_spec   = "special";
+static const char *o_not_int_fmt       = "%s does not specify an integer value for %s";
+static const char *o_val_req_fmt       = "value required for %s";
+static const char *o_not_time_fmt      = "%s does not specify a valid time value for %s";
+static const char *o_not_salt_fmt      = "%s does not specify a valid salt type for %s";
+static const char *o_opt_ufo_fmt       = "%s is unrecognized";
+static const char *help_option_head    = "%s: valid options are:\n";
+static const char *help_flag_head      = "%s: additional principal flags are:\n";
+
+static const char flg_out_pdate[]      = "Not Postdateable";
+static const char flg_in_pdate[]       = "postdateable";
+static const char flg_out_fwd[]                = "Not Forwardable";
+static const char flg_in_fwd[]         = "forwardable";
+static const char flg_out_tgs[]                = "No TGT-based Requests";
+static const char flg_in_tgs[]         = "tgt_req";
+static const char flg_out_renew[]      = "Not Renewable";
+static const char flg_in_renew[]       = "renewable";
+static const char flg_out_proxy[]      = "Not Proxiable";
+static const char flg_in_proxy[]       = "proxiable";
+static const char flg_out_dskey[]      = "No DUP_SKEY Requests";
+static const char flg_in_dskey[]       = "dup_skey";
+static const char flg_out_tix[]                = "All Tickets Disallowed";
+static const char flg_in_tix[]         = "allow_tickets";
+static const char flg_out_pauth[]      = "Preauthorization Required";
+static const char flg_in_pauth[]       = "preauth";
+static const char flg_out_hauth[]      = "HW Authorization Required";
+static const char flg_in_hauth[]       = "hwauth";
+static const char flg_out_pwchg[]      = "Password Change Required";
+static const char flg_in_pwchg[]       = "pwchange_req";
+static const char flg_out_svr[]                = "Server Disallowed";
+static const char flg_in_svr[]         = "server";
+static const char flg_out_pwsvc[]      = "Password Changing Service";
+static const char flg_in_pwsvc[]       = "pwservice";
+static const char flg_out_md5[]                = "DES MD5 supported";
+static const char flg_in_md5[]         = "md5";
+
+static const char opt_kvno[]           = "kvno";
+static const char opt_maxlife[]                = "maxlife";
+static const char opt_maxrenewlife[]   = "maxrenewlife";
+static const char opt_expiration[]     = "expiration";
+static const char opt_pwexpiration[]   = "pwexpiration";
+static const char opt_randomkey[]      = "randomkey";
+static const char opt_salttype[]       = "salttype";
+
+/*
+ * Formatting buffers
+ */
+static char            dt_outbuf[BUFFER_SIZE];
+static char            abs_outbuf[BUFFER_SIZE];
+static char            db_outbuf[BUFFER_SIZE];
+static char            salt_outbuf[BUFFER_SIZE];
+static krb5_db_entry   opt_dbent;
+
+/* Flag to string and option to flag table */
+static struct flagtable flagtable[] = {
+/* flag                                        output string      input option sen */
+{ KRB5_KDB_DISALLOW_POSTDATED,         flg_out_pdate,     flg_in_pdate, 0 },
+{ KRB5_KDB_DISALLOW_FORWARDABLE,       flg_out_fwd,       flg_in_fwd, 0 },
+{ KRB5_KDB_DISALLOW_TGT_BASED,         flg_out_tgs,       flg_in_tgs, 0 },
+{ KRB5_KDB_DISALLOW_RENEWABLE,         flg_out_renew,     flg_in_renew, 0 },
+{ KRB5_KDB_DISALLOW_PROXIABLE,         flg_out_proxy,     flg_in_proxy, 0 },
+{ KRB5_KDB_DISALLOW_DUP_SKEY,          flg_out_dskey,     flg_in_dskey, 0 },
+{ KRB5_KDB_DISALLOW_ALL_TIX,           flg_out_tix,       flg_in_tix, 0 },
+{ KRB5_KDB_REQUIRES_PRE_AUTH,          flg_out_pauth,     flg_in_pauth, 1 },
+{ KRB5_KDB_REQUIRES_HW_AUTH,           flg_out_hauth,     flg_in_hauth, 1 },
+{ KRB5_KDB_REQUIRES_PWCHANGE,          flg_out_pwchg,     flg_in_pwchg, 1 },
+{ KRB5_KDB_DISALLOW_SVR,               flg_out_svr,       flg_in_svr, 0 },
+{ KRB5_KDB_PWCHANGE_SERVICE,           flg_out_pwsvc,     flg_in_pwsvc, 1 },
+{ KRB5_KDB_SUPPORT_DESMD5,             flg_out_md5,       flg_in_md5, 1 },
+};
+
+/* Option string parse table */
+static struct opttable opttable[] = {
+/* flag                                option                  dispatch routine
+      argument */
+{ KRB5_ADM_M_KVNO,             opt_kvno,               get_integer,
+      (void *) &opt_dbent.kvno },
+{ KRB5_ADM_M_MAXLIFE,          opt_maxlife,            get_integer,
+      (void *) &opt_dbent.max_life },
+{ KRB5_ADM_M_MAXRENEWLIFE,     opt_maxrenewlife,       get_integer,
+      (void *) &opt_dbent.max_renewable_life },
+{ KRB5_ADM_M_EXPIRATION,       opt_expiration,         get_datestring,
+      (void *) &opt_dbent.expiration },
+{ KRB5_ADM_M_PWEXPIRATION,     opt_pwexpiration,       get_datestring,
+      (void *) &opt_dbent.pw_expiration },
+{ KRB5_ADM_M_SALTTYPE,         opt_salttype,           get_saltstring,
+      (void *) &opt_dbent },
+};
+
+/* strptime formats table to recognize absolute dates */
+/*
+ * Recognize character string times of the format.
+ *      1) yymmddhhmmss                (doesn't work under OSF/1)
+ *      2) yy.mm.dd.hh.mm.ss
+ *      3) yymmddhhmm
+ *      4) hhmmss (relative to today)
+ *      5) hhmm (relative to today)
+ *      6) hh:mm:ss (relative to today)
+ *      7) hh:mm (relative to today)
+ *      8) locale-dependent short format (mm/dd/yy:hh:mm:ss in usa)
+ *      9) dd-text_month-yyyy:hh:mm:ss
+ *      10) dd-text_month-yyyy:hh:mm
+ */
+static char *absformats[] =
+{
+    "%y%m%d%H%M%S",            /* yymmddhhmmss */
+    "%y.%m.%d.%H.%M.%S",       /* yy.mm.dd.hh.mm.ss */
+    "%y%m%d%H%M",              /* yymmddhhmm */
+    "%H%M%S",                  /* hhmmss */
+    "%H%M",                    /* hhmm */
+    "%T",                      /* hh:mm:ss */
+    "%R",                      /* hh:mm */
+    "%x:%X",                   /* locale-dependent short format */
+    "%d-%b-%Y:T",              /* dd-month-yyyy:hh:mm:ss */
+    "%d-%b-%Y:R"               /* dd-month-yyyy:hh:mm */
+};
+\f
+#if    !HAVE_STRPTIME
+/*
+ * Rudimentary version of strptime for systems which don't have it.
+ */
+static char *
+strptime( char *buf, char *format, struct tm *tm )
+{
+    int year, month, day, hour, minute, second;
+    char *bp;
+    
+    /*
+     * We only understand two formats:
+     *    %y%m%d%H%M%S
+     * This is fixed length, 12 characters.
+     *    %y.%m.%d.%H.%M.%S
+     * This is fixed length, 17 characters.
+     */
+    bp = (char *) NULL;
+    if ((strcmp(format,"%y%m%d%H%M%S") == 0) &&
+       (sscanf(buf, "%02d%02d%02d%02d%02d%02d",
+               &year, &month, &day, &hour, &minute, &second) == 6)) {
+       tm->tm_year = year;
+       tm->tm_mon = month - 1;
+       tm->tm_mday = day;
+       tm->tm_hour = hour;
+       tm->tm_min = minute;
+       tm->tm_sec = second;
+       bp = &buf[12];
+    }
+    else {
+       if ((strcmp(format,"%y.%m.%d.%H.%M.%S") == 0) &&
+           (sscanf(buf, "%02d.%02d.%02d.%02d.%02d.%02d",
+                   &year, &month, &day, &hour, &minute, &second) == 6)) {
+           tm->tm_year = year;
+           tm->tm_mon = month - 1;
+           tm->tm_mday = day;
+           tm->tm_hour = hour;
+           tm->tm_min = minute;
+           tm->tm_sec = second;
+           bp = &buf[17];
+       }
+    }
+    return(bp);
+}
+#endif /* HAVE_STRPTIME */
+\f
+/*
+ * delta2string()      - Convert delta time value to string.
+ *
+ * WARNING: the returned output buffer is static.
+ */
+char *
+delta2string(dt)
+    krb5_deltat        dt;
+{
+    int                days, hours, minutes, seconds;
+
+    days = dt / (24*3600);
+    dt %= 24 * 3600;
+    hours = dt / 3600;
+    dt %= 3600;
+    minutes = dt / 60;
+    dt %= 60;
+    seconds = dt;
+
+    if (days) {
+       if (hours || minutes || seconds)
+           sprintf(dt_outbuf, dt_output_fmt, days,
+                   ((days > 1) ? dt_day_plural : dt_day_singular),
+                   hours, minutes, seconds);
+       else
+           sprintf(dt_outbuf, dt_output_donly_fmt, days,
+                   ((days > 1) ? dt_day_plural : dt_day_singular));
+    }
+    else
+       sprintf(dt_outbuf, dt_output_noday_fmt, hours, minutes, seconds);
+    return(dt_outbuf);
+}
+\f
+/*
+ * abs2string()        - Convert absolute Kerberos time to string.
+ *
+ * WARNING: the returned output buffer is static.
+ */
+char *
+abs2string(t)
+    krb5_timestamp     t;
+{
+    /*
+     * ctime returns <datestring>\n\0.
+     */
+    strcpy(abs_outbuf, ctime((time_t *) &t));
+    abs_outbuf[strlen(abs_outbuf)-1] = '\0';
+    return(abs_outbuf);
+}
+\f
+/*
+ * dbflags2string()    - Convert database flags to string.
+ *
+ * WARNING: the returned output buffer is static.
+ */
+char *
+dbflags2string(f)
+    krb5_flags f;
+{
+    int        bit;
+    int                i;
+    krb5_flags mask;
+    struct flagtable *fent;
+
+    mask = 1;
+    db_outbuf[0] = '\0';
+    for (bit=0; bit<(sizeof(krb5_flags)*8); bit++) {
+       if (f & mask) {
+           /* Bit is set, find it in the flag table */
+           fent = (struct flagtable *) NULL;
+           for (i=0; i<(sizeof(flagtable)/sizeof(flagtable[0])); i++) {
+               if (mask == flagtable[i].f_value) {
+                   fent = &flagtable[i];
+                   break;
+               }
+           }
+
+           /* Either print out table value or unknown bit value. */
+           if (fent)
+               strcat(db_outbuf, fent->f_string);
+           else
+               sprintf(&db_outbuf[strlen(db_outbuf)],
+                       dbflag_bit_fmt, bit);
+           strcat(db_outbuf, ", ");
+       }
+       mask <<= 1;
+    }
+    /*
+     * Clean up our trailing comma-space if present.
+     */
+    if (strlen(db_outbuf) > 2)
+       db_outbuf[strlen(db_outbuf)-2] = '\0';
+    return(db_outbuf);
+}
+\f
+/*
+ * salt2string()       - Convert salt type to string.
+ *
+ * WARNING: the returned output buffer is static.
+ */
+char *
+salt2string(stype)
+    krb5_int32 stype;
+{
+    switch (stype) {
+    case KRB5_KDB_SALTTYPE_NORMAL:
+       strcpy(salt_outbuf, salt_norm_name);
+       break;
+    case KRB5_KDB_SALTTYPE_V4:
+       strcpy(salt_outbuf, salt_v4_name);
+       break;
+    case KRB5_KDB_SALTTYPE_NOREALM:
+       strcpy(salt_outbuf, salt_norealm_name);
+       break;
+    case KRB5_KDB_SALTTYPE_ONLYREALM:
+       strcpy(salt_outbuf, salt_orealm_name);
+       break;
+    case KRB5_KDB_SALTTYPE_SPECIAL:
+       strcpy(salt_outbuf, salt_special_name);
+       break;
+    default:
+       sprintf(salt_outbuf, salt_ufo_fmt, stype);
+       break;
+    }
+    return(salt_outbuf);
+}
+\f
+/*
+ * string2salt()       - Convert string to salt type.
+ */
+static krb5_int32
+string2salt(sstring, goodp)
+    char               *sstring;
+    krb5_boolean       *goodp;
+{
+    if (!strcasecmp(sstring, salt_norm_spec)) {
+       *goodp = 1;
+       return(KRB5_KDB_SALTTYPE_NORMAL);
+    }
+    else if (!strcasecmp(sstring, salt_v4_spec)) {
+       *goodp = 1;
+       return(KRB5_KDB_SALTTYPE_V4);
+    }
+    else if (!strcasecmp(sstring, salt_norealm_spec)) {
+       *goodp = 1;
+       return(KRB5_KDB_SALTTYPE_NOREALM);
+    }
+    else if (!strcasecmp(sstring, salt_orealm_spec)) {
+       *goodp = 1;
+       return(KRB5_KDB_SALTTYPE_ONLYREALM);
+    }
+    else if (!strcasecmp(sstring, salt_special_spec)) {
+       *goodp = 1;
+       return(KRB5_KDB_SALTTYPE_SPECIAL);
+    }
+    else {
+       *goodp = 0;
+       return(-1);
+    }
+}
+\f
+/*
+ * get_integer()       - Test for an option and its integer value.
+ */
+static krb5_boolean
+get_integer(arg, value, optp)
+    char       *arg;
+    const char *value;
+    void       *optp;
+{
+    int                index;
+    krb5_boolean       good;
+    krb5_int32         *intp;
+
+    intp = (krb5_int32 *) optp;
+    good = 0;
+    /* Match the value */
+    if (!strncasecmp(arg, value, strlen(value))) {
+       /* If we have a match, look for value=<value> */
+       index = strlen(value);
+       if (arg[index] == '=') {
+           /* Match one integer argument */
+           if (sscanf(&arg[index+1], "%d", intp) == 1)
+               good = 1;
+           else
+               com_err(requestname, 0, o_not_int_fmt, &arg[index+1], value);
+       }
+       else
+           com_err(requestname, 0, o_val_req_fmt, value);
+    }
+    return(good);
+}
+\f
+/*
+ * get_datestring()    - Test for an option and its date value
+ */
+static krb5_boolean
+get_datestring(arg, value, optp)
+    char       *arg;
+    const char *value;
+    void       *optp;
+{
+    int                index;
+    krb5_timestamp     *tp;
+    krb5_boolean       good, found;
+    char               *retval;
+    int                        ti;
+    time_t             now;
+    struct tm          *tmp;
+    struct tm          timebuf;
+
+    tp = (krb5_timestamp *) optp;
+    good = 0;
+    found = 0;
+    /* Match the value */
+    if (!strncasecmp(arg, value, strlen(value))) {
+       /* If we have a match, look for value=<value> */
+       index = strlen(value);
+       if (arg[index] == '=') {
+           /* Prime with current time */
+           now = time((time_t *) NULL);
+           tmp = localtime(&now);
+           memcpy(&timebuf, tmp, sizeof(struct tm));
+           /* Match date argument */
+           for (ti=0; ti<(sizeof(absformats)/sizeof(absformats[0])); ti++) {
+               if (strptime(&arg[index+1], absformats[ti], &timebuf)) {
+                   found = 1;
+                   break;
+               }
+               memcpy(&timebuf, tmp, sizeof(struct tm));
+           }
+           if (found) {
+               *tp = (krb5_timestamp) mktime(&timebuf);
+               good = 1;
+           }
+           else
+               com_err(requestname, 0, o_not_time_fmt, &arg[index+1], value);
+       }
+       else
+           com_err(requestname, 0, o_val_req_fmt, value);
+    }
+    return(good);
+}
+\f
+/*
+ * get_saltstring()    - Test for an option and its salt type value
+ */
+static krb5_boolean
+get_saltstring(arg, value, optp)
+    char       *arg;
+    const char *value;
+    void       *optp;
+{
+    int                        index;
+    krb5_db_entry      *dbentp;
+    krb5_boolean       good;
+    char               *s1, *s2;
+
+    dbentp = (krb5_db_entry *) optp;
+    good = 0;
+    /* Match the value */
+    if (!strncasecmp(arg, value, strlen(value))) {
+       /* If we have a match, look for value=<value> */
+       index = strlen(value);
+       if (arg[index] == '=') {
+           if (s2 = strchr(&arg[index+1], (int) ',')) {
+               *s2 = '\0';
+               s2++;
+           }
+           s1 = &arg[index+1];
+           dbentp->salt_type = string2salt(s1, &good);
+           if (good) {
+               if (s2) {
+                   dbentp->alt_salt_type = string2salt(s2, &good);
+                   if (!good)
+                       com_err(requestname, 0, o_not_salt_fmt, s2, value);
+               }
+               else
+                   dbentp->alt_salt_type = KRB5_KDB_SALTTYPE_NORMAL;
+           }
+           else
+               com_err(requestname, 0, o_not_salt_fmt, s1, value);
+       }
+       else
+           com_err(requestname, 0, o_val_req_fmt, value);
+    }
+
+    return(good);
+}
+\f
+/*
+ * parse_princ_options()       - Parse an argument list for values.
+ *
+ * NOTE: The formatting buffer is static.
+ */
+krb5_boolean
+parse_princ_options(argc, argv, vmaskp, dbentp)
+    int                        argc;
+    char               *argv[];
+    krb5_ui_4          *vmaskp;
+    krb5_db_entry      *dbentp;
+{
+    int        i, oindex;
+    krb5_boolean       good;
+    krb5_boolean       found;
+
+    good = 1;
+    /* Copy in our values */
+    memcpy(&opt_dbent, dbentp, sizeof(krb5_db_entry));
+    for (i=0; i<argc; i++) {
+       found = 0;
+       /*
+        * First try the option table.
+        */
+       for (oindex=0; oindex<(sizeof(opttable)/sizeof(opttable[0]));
+            oindex++) {
+           if ((*opttable[oindex].o_dispatch)(argv[i],
+                                              opttable[oindex].o_option,
+                                              opttable[oindex].o_arg)) {
+               *vmaskp |= opttable[oindex].o_value;
+               found = 1;
+               break;
+           }
+       }
+
+       /*
+        * If we didn't find an option, try trapsing through the flag table.
+        */
+       if (!found) {
+           int                 ti, rindex;
+           krb5_boolean        sense;
+
+           found = 0;
+           rindex = 0;
+           sense = 1;
+           if ((argv[i][0] == '-') || (argv[i][0] == '+')) {
+               if (argv[i][0] == '-')
+                   sense = 0;
+               rindex = 1;
+           }
+           for (ti=0; ti<(sizeof(flagtable)/sizeof(flagtable[0])); ti++) {
+               if (!strncasecmp(&argv[i][rindex], flagtable[ti].f_option,
+                                strlen(flagtable[ti].f_option))) {
+                   found = 1;
+                   if (sense == flagtable[ti].f_sense)
+                       opt_dbent.attributes |= flagtable[ti].f_value;
+                   else
+                       opt_dbent.attributes &= ~flagtable[ti].f_value;
+                   *vmaskp |= KRB5_ADM_M_FLAGS;
+               }
+           }
+           if (!found) {
+               com_err(requestname, 0, o_opt_ufo_fmt, argv[i]);
+               good = 0;
+           }
+       }
+    }
+    /* Copy out our values, if good */
+    if (good)
+       memcpy(dbentp, &opt_dbent, sizeof(krb5_db_entry));
+    return(good);
+}
+\f
+/*
+ * help_princ_options()        - Print out a list of settable principal options.
+ */
+void
+help_princ_options()
+{
+    int index;
+    int ntable;
+
+    fprintf(stderr, help_option_head, requestname);
+    ntable = (sizeof(opttable)/sizeof(opttable[0]));
+    for (index=0; index<ntable-1; index++)
+       fprintf(stderr, "%s, ", opttable[index].o_option);
+    fprintf(stderr,"%s\n", opttable[ntable-1].o_option);
+    fprintf(stderr, help_flag_head, requestname);
+    ntable = (sizeof(flagtable)/sizeof(flagtable[0]));
+    for (index=0; index<ntable-1; index++)
+       fprintf(stderr, "[+/-]%s, ", flagtable[index].f_option);
+    fprintf(stderr, "[+/-]%s\n", flagtable[ntable-1].f_option);
+}
diff --git a/src/kadmin/v5client/kadmin5.M b/src/kadmin/v5client/kadmin5.M
new file mode 100644 (file)
index 0000000..f925652
--- /dev/null
@@ -0,0 +1,251 @@
+.\" $Source$
+.\" $Author$
+.\" $Id$
+.\" Copyright 1995 by the Massachusetts Institute of Technology.
+.\"
+.\" 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.
+.\" 
+.\"
+.TH KADMIN5 8 "Kerberos Version 5.0" "MIT Project Athena"
+.SH NAME
+kadmin5 \- administer a Kerberos principal database over the network.
+.SH SYNOPSIS
+.B kadmin5
+[
+.B \-r
+.I realm
+] [
+.B \-p
+.I principal
+] [
+.B \-m
+]
+[ command ... ]
+.br
+.SH FLAGS
+.PP
+.IP \-r
+.B realm
+specifies the default realm.
+.IP \-p
+.B principal
+specifies a principal name to use instead of the default 
+.I user
+.B /kadmind5@realm.
+.IP \-m
+specifies that multiple operations will be permitted for only one entry of the
+administrative principal's password.
+
+.SH DESCRIPTION
+This utility provides a network administration interface to the Kerberos
+master database.  Kerberos administrators use kadmin5 to register new
+users and services with the master database; to remove old users and services
+from the master database; to modify information about existing database
+entries; and to create service key tables from entries in the database.
+.PP
+The
+.I kadmin5
+communicates over the network with the
+.I kadmind5
+program, which runs on the system where the Kerberos master database resides.
+.I kadmind5
+performs the database operations which
+.I kadmin5
+specifies.
+.PP
+Principals who may perform administrative operations are controlled by the
+.I kadmind5
+access control list.  The default administrative principal is
+.I user
+.B /kadmind5@realm.
+.PP
+One command may be specified on the command line, or if no command is provided,
+an interactive command loop is entered for the administrator to enter commands.
+.PP
+.SH AVAILABLE COMMANDS
+
+The following is a list of commands and their aliases that the system
+administrator may use to manipulate the database:
+
+.IP show_principal,show
+Show the Kerberos database entry for a principal.
+
+.IP add_new_key,ank
+Add new entry to Kerberos database (prompting for new password).
+
+.IP change_pwd_key,cpw
+Change key of an entry in the Kerberos database (prompting for new password).
+
+.IP add_rnd_key,ark    
+Add new entry to Kerberos database, using a random key.
+
+.IP change_rnd_key,crk
+Change key of an entry in the Kerberos database (selecting a new random key).
+
+.IP delete_entry,delent,del
+Delete an entry from the database.
+
+.IP extract_srvtab,xst,ex_st
+Extract service key table entry/entries.
+
+.IP extract_v4_srvtab,xst4
+Extract service key table entry/entries in V4 format.
+
+.IP modify_entry,modent
+Modify database entry.
+
+.IP rename_entry,renent
+Rename database entry.
+
+.IP list_db,ldb      
+List database entries.
+
+.IP change_working_directory,cwd,cd
+Change working directory.
+
+.IP print_working_directory,pwd
+Print working directory.
+
+.IP list_requests,lr,?
+List available requests.
+
+.IP quit,exit,q
+Exit program.
+.PP
+.SH Principal Options
+For the
+.I add_new_key, add_rnd_key
+and
+.I modify_entry
+commands, an optional list of principal options may be specified.  The
+following options may be specified:
+.TP i
+.I kvno=<integer>
+Specifies the key version number for the principal.
+.TP i
+.I maxlife=<integer>
+Specifies the maximum ticket life for the principal in seconds.
+.TP i
+.I maxrenewlife=<integer>
+Specifies the maximum renewable ticket life for the principal in seconds.
+.TP i
+.I expiration=<date>
+Specifies the expiration date and time of the principal.  See below for the
+format of
+.I <date>.
+.TP i
+.I pwexpiration=<date>
+Specifies the expiration date and time of the principal's password.  See below for the format of
+.I <date>.
+.TP i
+.I salttype=[v5|v4|norealm|onlyrealm|special]
+Indicates the salt type.
+.TP i
+.I [+/-]postdateable
+Specifies that tickets for this principal [are/are not] postdateable.
+.TP i
+.I [+/-]forwardable
+Specifies that tickets for this principal [are/are not] forwardable.
+.TP i
+.I [+/-]tgt_req
+Specifies that TGT-based requests for this principal [are/are not] allowed.
+.TP i
+.I [+/-]renewable
+Specifies that tickets for this principal [are/are not] renewable.
+.TP i
+.I [+/-]proxiable
+Specifies that tickets for this principal [are/are not] proxiable.
+.TP i
+.I [+/-]dup_skey
+Specifies that tickets issued by this service [may/may not] be encrypted
+using the session key instead of the private key.
+.TP i
+.I [+/-]allow_tickets
+Specifies that tickets for this principal [are/are not] allowed.
+.TP i
+.I [+/-]preauth
+Specifies that preauthorization [is/is not] required for this principal.
+.TP i
+.I [+/-]hwauth
+Specifies that hardware preauthorization [is/is not] required for this
+principal.
+.TP i
+.I [+/-]pwchange_req
+Specifies that a password change [is/is not] required for this principal.
+.TP i
+.I [+/-]server
+Specifies that this principal [is/is not] allowed to be a service.
+.TP i
+.I [+/-]pwservice
+Specifies that this principal [is/is not] the password changing service.
+.TP i
+.I [+/-]md5
+Specifies that DES MD5 [is/is not] supported for this principal.
+
+.SH Date Format
+The format of <date>
+may be one of the following, where
+.I yy
+is the last two digits of the year;
+.I mm
+is the month number (with a leading zero if less than 10);
+.I dd
+is the day number in the month (with a leading zero if less than 10);
+.I HH
+is the hour number (24-hour clock);
+.I MM
+is the minute number; and
+.I SS
+is the second number:
+.TP i
+.I yy.mm.dd.HH.MM.SS
+e.g. 95.09.01.00.00.00 for midnight on September 1, 1995.
+.TP i
+.I yymmddHHMMSS
+e.g. 950901000000 for midnight on September 1, 1995.
+.PP
+If the
+.B strptime(3)
+function is available, then the following formats are also supported.
+.PP
+.TP i
+.I yymmddHHMM
+e.g. 9509010000 for midnight on September 1, 1995.
+.TP i
+.I HHMMSS
+e.g. 200000 for 8pm tonight.
+.TP i
+.I HHMM
+e.g. 2100 for 9pm tonight.
+.TP i
+.I HH:MM:SS
+e.g. 20:00:00 for 8pm tonight.
+.TP i
+.I HH:MM
+e.g. 21:00 for 9pm tonight.
+.TP i
+.I locale-dependent short format (mm/dd/yy:HH:MM:SS) in U.S.
+.e.g 01/09/95:00:00:00 for midnight on September 1, 1995.
+.TP i
+.I dd-<text-month>-yyyy:HH:MM:SS
+e.g. 01-Sep-1995:00:00:00 for midnight on September 1, 1995.
+.TP i
+.I dd-<text-month>-yyyy:HH:MM
+e.g. 01-Sep-1995:00:00 for midnight on September 1, 1995.
+.PP
+.SH SEE ALSO
+kadmind5(8), kpasswd(1), strptime(3)
diff --git a/src/kadmin/v5client/kadmin5.c b/src/kadmin/v5client/kadmin5.c
new file mode 100644 (file)
index 0000000..0538c9e
--- /dev/null
@@ -0,0 +1,1434 @@
+/*
+ * 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 <pwd.h>
+#endif /* HAVE_PWD_H */
+#if    HAVE_RE_COMP || HAVE_REGCOMP
+#include <regex.h>
+#endif /* HAVE_RE_COMP || HAVE_REGCOMP */
+
+/*
+ * Global storage.
+ */
+int            exit_status = 0;
+krb5_context   kcontext;
+char           *programname = (char *) NULL;
+char           *requestname = (char *) NULL;
+krb5_boolean   multiple = 0;
+char           *principal_name = (char *) NULL;
+char           *password_prompt = (char *) NULL;
+
+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     = "kadmin5";
+
+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] <regexp>";
+#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_usage_fmt    = "usage is %s [-r realm] [-p principal] [-m] [command ...]";
+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_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: ";
+\f
+#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 */
+\f
+/*
+ * 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);
+}
+\f
+/*
+ * 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);
+}
+\f
+/*
+ * 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<argc; i++) {
+       if (dbentry = (krb5_db_entry *) malloc(sizeof(krb5_db_entry))) {
+           memset((char *) dbentry, 0, sizeof(*dbentry));
+           kret = kadmin_get_entry(argv[i], &valid, dbentry, &xxx);
+           if (kret) {
+               com_err(argv[0], 0, cant_get_fmt, argv[i]);
+               break;
+           }
+           if (xxx)
+               free(xxx);
+           kadmin_print_entry(argv[i], valid, dbentry);
+           krb5_db_free_principal(kcontext, dbentry, 1);
+       }
+       else {
+           com_err(argv[0], 0, no_memory_fmt);
+       }
+    }
+}
+\f
+/*
+ * kadmin_add_new_key()        - Add a new principal.
+ */
+void
+kadmin_add_new_key(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    char               *p1, *p2;
+    char               *npass;
+    int                        nplen;
+    krb5_int32         proto_stat;
+    krb5_int32         nargs;
+    krb5_data          *arglist;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    char               *principal;
+    krb5_ui_4          valid;
+    krb5_db_entry      *dbentp;
+
+    requestname = argv[0];
+    if (argc < 2) {
+       com_err(argv[0], 0, add_usage_fmt, argv[0]);
+       help_princ_options();
+       return;
+    }
+    principal = argv[1];
+    argc -= 2;
+    argv += 2;
+
+    p1 = (char *) malloc(strlen(add_prompt1_fmt)+strlen(principal)+1);
+    p2 = (char *) malloc(strlen(add_prompt2_fmt)+strlen(principal)+1);
+    npass = (char *) malloc(KRB5_ADM_MAX_PASSWORD_LEN);
+    dbentp = (krb5_db_entry *) malloc(sizeof(krb5_db_entry));
+    if (p1 && p2 && npass && dbentp) {
+       memset((char *) dbentp, 0, sizeof(krb5_db_entry));
+       valid = 0;
+       if (parse_princ_options(argc, argv, &valid, dbentp)) {
+           valid |= KRB5_ADM_M_SET;    /* We are setting options */
+           sprintf(p1, add_prompt1_fmt, principal);
+           sprintf(p2, add_prompt2_fmt, principal);
+           nplen = KRB5_ADM_MAX_PASSWORD_LEN;
+           valid |= KRB5_ADM_M_PASSWORD;       /* We have a password */
+           if (!(kret = krb5_read_password(kcontext,
+                                           p1, p2, npass, &nplen))) {
+               npass[nplen] = '\0';
+               nargs = ncomps = 0;
+               if (!(kret = krb5_adm_dbent_to_proto(kcontext,
+                                                    valid,
+                                                    dbentp,
+                                                    npass,
+                                                    &nargs,
+                                                    &arglist)) &&
+                   !(kret = net_do_proto(KRB5_ADM_ADD_PRINC_CMD,
+                                         principal,
+                                         (char *) NULL,
+                                         nargs,
+                                         arglist,
+                                         &proto_stat,
+                                         &ncomps,
+                                         &complist))) {
+                   if (proto_stat == KRB5_ADM_SUCCESS) {
+                       com_err(programname, 0, add_succ_fmt, principal);
+                   }
+               }
+               else {
+                   com_err(requestname, kret, add_protoerr_fmt);
+               }
+               if (ncomps)
+                   krb5_free_adm_data(kcontext, ncomps, complist);
+               if (nargs) 
+                   krb5_free_adm_data(kcontext, nargs, arglist);
+               memset(npass, 0, KRB5_ADM_MAX_PASSWORD_LEN);
+           }
+           else {
+               com_err(requestname, 0, add_noconf_fmt);
+           }
+       }
+       else {
+           com_err(requestname, 0, add_synerr_fmt);
+           help_princ_options();
+       }
+    }
+    else {
+       com_err(requestname, 0, no_memory_fmt);
+    }
+    if (p1)
+       free(p1);
+    if (p2)
+       free(p2);
+    if (npass)
+       free(npass);
+    if (dbentp)
+       free(dbentp);
+}
+
+\f
+/*
+ * kadmin_change_pwd() - Change principal's password.
+ */
+void
+kadmin_change_pwd(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    char               *p1, *p2;
+    char               *npass;
+    int                        nplen;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+
+    requestname = argv[0];
+    if (argc != 2) {
+       com_err(argv[0], 0, cpw_usage_fmt, argv[0]);
+       return;
+    }
+    p1 = (char *) malloc(strlen(cpw_prompt1_fmt)+strlen(argv[1])+1);
+    p2 = (char *) malloc(strlen(cpw_prompt2_fmt)+strlen(argv[1])+1);
+    npass = (char *) malloc(KRB5_ADM_MAX_PASSWORD_LEN);
+    if (p1 && p2 && npass) {
+       sprintf(p1, cpw_prompt1_fmt, argv[1]);
+       sprintf(p2, cpw_prompt2_fmt, argv[1]);
+
+       nplen = KRB5_ADM_MAX_PASSWORD_LEN;
+       if (!(kret = krb5_read_password(kcontext, p1, p2, npass, &nplen))) {
+           npass[nplen] = '\0';
+           if (!(kret = net_do_proto(KRB5_ADM_CHG_OPW_CMD,
+                                     argv[1],
+                                     npass,
+                                     0,
+                                     (krb5_data *) NULL,
+                                     &proto_stat,
+                                     &ncomps,
+                                     &complist))) {
+               if (proto_stat == KRB5_ADM_SUCCESS) {
+                   com_err(programname, 0, cpw_succ_fmt, argv[1]);
+                   krb5_free_adm_data(kcontext, ncomps, complist);
+               }
+           }
+           memset(npass, 0, KRB5_ADM_MAX_PASSWORD_LEN);
+       }
+       else {
+           com_err(argv[0], kret, cpw_nochange_fmt, argv[1]);
+       }
+    }
+    else {
+       com_err(requestname, 0, no_memory_fmt);
+    }
+    if (p1)
+       free(p1);
+    if (p2)
+       free(p2);
+    if (npass)
+       free(npass);
+}
+\f
+/*
+ * kadmin_add_rnd_key()        - Add principal with random key.
+ */
+void
+kadmin_add_rnd_key(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         nargs;
+    krb5_data          *arglist;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    char               *principal;
+    krb5_ui_4          valid;
+    krb5_db_entry      *dbentp;
+
+    requestname = argv[0];
+    if (argc < 2) {
+       com_err(argv[0], 0, add_usage_fmt, argv[0]);
+       help_princ_options();
+       return;
+    }
+    principal = argv[1];
+    argc -= 2;
+    argv += 2;
+
+    dbentp = (krb5_db_entry *) malloc(sizeof(krb5_db_entry));
+    if (dbentp) {
+       memset((char *) dbentp, 0, sizeof(krb5_db_entry));
+       valid = 0;
+       if (parse_princ_options(argc, argv, &valid, dbentp)) {
+           valid |= KRB5_ADM_M_SET;    /* We are setting options */
+           valid |= KRB5_ADM_M_RANDOMKEY;      /* We have a random key */
+           ncomps = nargs = 0;
+           if (!(kret = krb5_adm_dbent_to_proto(kcontext,
+                                                valid,
+                                                dbentp,
+                                                (char *) NULL,
+                                                &nargs,
+                                                &arglist)) &&
+               !(kret = net_do_proto(KRB5_ADM_ADD_PRINC_CMD,
+                                     principal,
+                                     (char *) NULL,
+                                     nargs,
+                                     arglist,
+                                     &proto_stat,
+                                     &ncomps,
+                                     &complist))) {
+               if (proto_stat == KRB5_ADM_SUCCESS) {
+                   com_err(programname, 0, add_succ_fmt, principal);
+               }
+           }
+           else {
+               com_err(requestname, kret, add_protoerr_fmt);
+           }
+           if (ncomps)
+               krb5_free_adm_data(kcontext, ncomps, complist);
+           if (nargs)
+               krb5_free_adm_data(kcontext, nargs, arglist);
+       }
+       else {
+           com_err(requestname, 0, add_synerr_fmt);
+           help_princ_options();
+       }
+    }
+    else {
+       com_err(requestname, 0, no_memory_fmt);
+    }
+    if (dbentp)
+       free(dbentp);
+}
+\f
+/*
+ * kadmin_change_rnd() - Change random key.
+ */
+void
+kadmin_change_rnd(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+
+    requestname = argv[0];
+    if (argc != 2) {
+       com_err(argv[0], 0, cpw_usage_fmt, argv[0]);
+       return;
+    }
+    if (!(kret = net_do_proto(KRB5_ADM_CHG_ORPW_CMD,
+                             argv[1],
+                             (char *) NULL,
+                             0,
+                             (krb5_data *) NULL,
+                             &proto_stat,
+                             &ncomps,
+                             &complist))) {
+       if (proto_stat == KRB5_ADM_SUCCESS) {
+           com_err(programname, 0, cpw_succ_fmt, argv[1]);
+           krb5_free_adm_data(kcontext, ncomps, complist);
+       }
+    }
+}
+\f
+/*
+ * kadmin_delete_entry()       - Delete principal.
+ */
+void
+kadmin_delete_entry(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    int                        i;
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    krb5_boolean       force, doit;
+
+    requestname = argv[0];
+    force = 0;
+    if (argc == 1) {
+       com_err(argv[0], 0, dprinc_usage_fmt, argv[0], force_option);
+       return;
+
+    }
+    for (i=1; i<argc; i++) {
+       if (!strcmp(argv[i], force_option)) {
+           force = 1;
+           continue;
+       }
+       doit = 0;
+       if (force) {
+           doit = 1;
+       }
+       else {
+           int c;
+           printf(del_conf_fmt, del_conf_char, argv[i]);
+           if (getchar() == del_conf_char)
+               doit = 1;
+           while (((c = getchar()) != '\n') && (c != EOF));
+       }
+
+       if (doit) {
+           if (!(kret = net_do_proto(KRB5_ADM_DEL_PRINC_CMD,
+                                     argv[i],
+                                     (char *) NULL,
+                                     0,
+                                     (krb5_data *) NULL,
+                                     &proto_stat,
+                                     &ncomps,
+                                     &complist))) {
+               if (proto_stat == KRB5_ADM_SUCCESS) {
+                   com_err(programname, 0, del_princ_fmt, argv[i]);
+                   krb5_free_adm_data(kcontext, ncomps, complist);
+               }
+           }
+       }
+       else {
+           com_err(programname, 0, del_noconf_fmt, argv[i]);
+       }
+    }
+}
+\f
+/*
+ * kadmin_extract()    - Extract srvtab entry.
+ */
+void
+kadmin_extract(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    int                        i;
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    char               *instance;
+    krb5_boolean       force, doit;
+    krb5_keytab_entry  keytab_entry;
+    char               keytab_name[MAXPATHLEN+sizeof(wr_ktab_type)+2];
+    krb5_keytab                keytab_id;
+    char               *actname;
+
+    requestname = argv[0];
+    force = 0;
+    if (argc < 3) {
+       com_err(argv[0], 0, xst_usage_fmt, argv[0]);
+       return;
+
+    }
+    instance = argv[1];
+    argc -= 2;
+    argv += 2;
+
+    /*
+     * First prepare us for writeable keytable operations.
+     */
+    if (kret = krb5_kt_register(kcontext, &krb5_ktf_writable_ops)) {
+       if (kret != KRB5_KT_TYPE_EXISTS) {
+           com_err(programname, kret, xst_wr_reg_fmt, requestname);
+           return;
+       }
+    }
+
+    /*
+     * Format new srvtab name.
+     */
+    if (strlen(instance)+strlen(wr_ktab_type)+strlen(xst_ktab_name_fmt)-3
+       >= 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<argc; i++) {
+       if (!(kret = net_do_proto(KRB5_ADM_EXT_KEY_CMD,
+                                 instance,
+                                 argv[i],
+                                 0,
+                                 (krb5_data *) NULL,
+                                 &proto_stat,
+                                 &ncomps,
+                                 &complist))) {
+           if (proto_stat == KRB5_ADM_SUCCESS) {
+               if (!(kret = krb5_adm_proto_to_ktent(kcontext,
+                                                    ncomps,
+                                                    complist,
+                                                    &keytab_entry))) {
+                   if (kret = krb5_kt_add_entry(kcontext,
+                                                keytab_id,
+                                                &keytab_entry)) {
+                       com_err(requestname, kret, xst_adderr_fmt,
+                               argv[i], actname);
+                       break;
+                   }
+                   else
+                       com_err(requestname, 0, xst_success_fmt,
+                               argv[i], actname);
+                   if (keytab_entry.key.contents) {
+                       memset((char *) keytab_entry.key.contents, 0,
+                              (size_t) keytab_entry.key.length);
+                       krb5_xfree(keytab_entry.key.contents);
+                   }
+               }
+               else {
+                   com_err(requestname, kret, xst_proto_fmt);
+               }
+               memset((char *) &keytab_entry, 0, sizeof(krb5_keytab_entry));
+               krb5_free_adm_data(kcontext, ncomps, complist);
+           }
+       }
+    }
+    if (kret = krb5_kt_close(kcontext, keytab_id)) {
+       com_err(requestname, kret, xst_kclose_fmt, keytab_name);
+    }
+}
+\f
+/*
+ * kadmin_extract_v4() - Extract srvtab entry in V4 format.
+ */
+void
+kadmin_extract_v4(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    int                        i;
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    char               *instance;
+    krb5_boolean       force, doit;
+    krb5_keytab_entry  keytab_entry;
+    char               keytab_name[MAXPATHLEN+1];
+    FILE               *v4tab;
+
+    requestname = argv[0];
+    force = 0;
+    if (argc < 3) {
+       com_err(argv[0], 0, xst_usage_fmt, argv[0]);
+       return;
+
+    }
+    instance = argv[1];
+    argc -= 2;
+    argv += 2;
+
+    /*
+     * Format new srvtab name.
+     */
+    if (strlen(instance)+strlen(xst_k4tab_name_fmt)-3 >= 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<argc; i++) {
+       if (!(kret = net_do_proto(KRB5_ADM_EXT_KEY_CMD,
+                                 instance,
+                                 argv[i],
+                                 0,
+                                 (krb5_data *) NULL,
+                                 &proto_stat,
+                                 &ncomps,
+                                 &complist))) {
+           if (proto_stat == KRB5_ADM_SUCCESS) {
+               if (!(kret = krb5_adm_proto_to_ktent(kcontext,
+                                                    ncomps,
+                                                    complist,
+                                                    &keytab_entry))) {
+                   if (keytab_entry.key.keytype != 1) {
+                       com_err(requestname, 0, xst_nodeskey_fmt, argv[i]);
+                       break;
+                   }
+                   if ((fwrite(argv[i],
+                               strlen(argv[i])+1,
+                               1,
+                               v4tab) != 1) ||
+                       (fwrite(instance,
+                               strlen(instance)+1,
+                               1,
+                               v4tab) != 1) ||
+                       (fwrite(realm_name,
+                               strlen(realm_name)+1,
+                               1,
+                               v4tab) != 1) ||
+                       (fwrite((char *) &keytab_entry.vno,
+                               sizeof(keytab_entry.vno),
+                               1,
+                               v4tab) != 1) ||
+                       (fwrite((char *) keytab_entry.key.contents,
+                               keytab_entry.key.length,
+                               1,
+                               v4tab) != 1)) {
+                       com_err(requestname, kret, xst_adderr_fmt,
+                               argv[i], keytab_name);
+                       break;
+                   }
+                   else
+                       com_err(requestname, 0, xst_success_fmt,
+                               argv[i], keytab_name);
+                   if (keytab_entry.key.contents) {
+                       memset((char *) keytab_entry.key.contents, 0,
+                              (size_t) keytab_entry.key.length);
+                       krb5_xfree(keytab_entry.key.contents);
+                   }
+               }
+               else {
+                   com_err(requestname, kret, xst_proto_fmt);
+               }
+               memset((char *) &keytab_entry, 0, sizeof(krb5_keytab_entry));
+               krb5_free_adm_data(kcontext, ncomps, complist);
+           }
+       }
+    }
+    fclose(v4tab);
+}
+\f
+/*
+ * kadmin_modify()     - Modify principal.
+ */
+void
+kadmin_modify(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         nargs;
+    krb5_data          *arglist;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    char               *principal;
+    krb5_ui_4          valid;
+    krb5_db_entry      *dbentp;
+
+    requestname = argv[0];
+    if (argc < 2) {
+       com_err(argv[0], 0, mod_usage_fmt, argv[0]);
+       help_princ_options();
+       return;
+    }
+    principal = argv[1];
+    argc -= 2;
+    argv += 2;
+
+    dbentp = (krb5_db_entry *) malloc(sizeof(krb5_db_entry));
+    if (dbentp) {
+       memset((char *) dbentp, 0, sizeof(krb5_db_entry));
+       valid = 0;
+       if (parse_princ_options(argc, argv, &valid, dbentp)) {
+           valid |= KRB5_ADM_M_SET;    /* We are setting options */
+           nargs = ncomps = 0;
+           if (!(kret = krb5_adm_dbent_to_proto(kcontext,
+                                                valid,
+                                                dbentp,
+                                                (char *) NULL,
+                                                &nargs,
+                                                &arglist)) &&
+               !(kret = net_do_proto(KRB5_ADM_MOD_PRINC_CMD,
+                                     principal,
+                                     (char *) NULL,
+                                     nargs,
+                                     arglist,
+                                     &proto_stat,
+                                     &ncomps,
+                                     &complist))) {
+               if (proto_stat == KRB5_ADM_SUCCESS) {
+                   com_err(programname, 0, mod_succ_fmt, principal);
+               }
+           }
+           else {
+               com_err(requestname, kret, mod_protoerr_fmt);
+           }
+           if (ncomps)
+               krb5_free_adm_data(kcontext, ncomps, complist);
+           if (nargs)
+               krb5_free_adm_data(kcontext, nargs, arglist);
+       }
+       else {
+           com_err(requestname, 0, mod_synerr_fmt);
+           help_princ_options();
+       }
+    }
+    else {
+       com_err(requestname, 0, no_memory_fmt);
+    }
+    if (dbentp)
+       free(dbentp);
+}
+\f
+/*
+ * kadmin_rename()     - Rename principal.
+ */
+void
+kadmin_rename(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    int                        i;
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+    krb5_boolean       force, doit, uerr;
+
+    requestname = argv[0];
+    uerr = force = 0;
+
+    argc--; argv++;
+    if (argc > 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]);
+    }
+}
+\f
+/*
+ * 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;
+#if    HAVE_REGCOMP
+    if (match_error = regcomp(&match_exp, lprinc_all_regexp, REG_EXTENDED)) {
+       errmsg_size = regerror(match_error,
+                              &match_exp,
+                              match_errmsg,
+                              sizeof(match_errmsg));
+       com_err(requestname, 0, lprinc_regexp_fmt, lprinc_all_regexp,
+               match_errmsg);
+       return;
+    }
+#else  /* HAVE_REGCOMP */
+    re_comp(".*");     /* Accept everything */
+#endif /* HAVE_REGCOMP */
+    
+    for (i=1; i<argc; i++) {
+       if (!strcmp(argv[i], help_option)) {
+           com_err(argv[0], 0, lprinc_usage_fmt, argv[0], verbose_option);
+           error = 1;
+           break;
+       }
+       if (!strcmp(argv[i], verbose_option)) {
+           verbose = 1;
+           continue;
+       }
+#if    HAVE_REGCOMP
+       if (match_error = regcomp(&match_exp, argv[i], REG_EXTENDED)) {
+           errmsg_size = regerror(match_error,
+                                  &match_exp,
+                                  match_errmsg,
+                                  sizeof(match_errmsg));
+           com_err(requestname, 0, lprinc_regexp_fmt, argv[i], match_errmsg);
+           error = 1;
+       }
+       else
+           continue;
+#else  /* HAVE_REGCOMP */
+       if (!(re_result = re_comp(argv[i]))) {
+           continue;
+       }
+       else {
+           com_err(argv[0], 0, lprinc_regexp_fmt, re_result);
+           error = 1;
+       }
+#endif /* HAVE_REGCOMP */
+    }
+    if (!error) {
+       char            *next;
+       char            *nnext;
+       krb5_ui_4       valid;
+       krb5_db_entry   *dbentry;
+
+       if (dbentry = (krb5_db_entry *) malloc(sizeof(krb5_db_entry))) {
+           memset((char *) dbentry, 0, sizeof(*dbentry));
+           kret = kadmin_get_entry("", &valid, dbentry, &next);
+           if (kret) {
+               com_err(argv[0], 0, cant_get_fmt, lprinc_first_msg);
+               next = (char *) NULL;
+           }
+           else {
+               krb5_db_free_principal(kcontext, dbentry, 1);
+           }
+           while (next && strlen(next)) {
+               if (dbentry = (krb5_db_entry *)
+                   malloc(sizeof(krb5_db_entry))) {
+                   memset((char *) dbentry, 0, sizeof(*dbentry));
+                   kret = kadmin_get_entry(next, &valid, dbentry, &nnext);
+                   if (kret) {
+                       com_err(argv[0], 0, cant_get_fmt, lprinc_first_msg);
+                       break;
+                   }
+#if    HAVE_REGCOMP
+                   if (match_error = regexec(&match_exp,
+                                             next,
+                                             1,
+                                             &match_match,
+                                             0)) {
+                       if (match_error != REG_NOMATCH) {
+                           errmsg_size = regerror(match_error,
+                                                  &match_exp,
+                                                  match_errmsg,
+                                                  sizeof(match_errmsg));
+                           com_err(requestname, 0,
+                                   lprinc_regsrch_fmt,
+                                   argv[i],
+                                   next,
+                                   match_errmsg);
+                           error = 1;
+                       }
+                   }
+                   else {
+                       /*
+                        * We have a match.  See if it matches the whole
+                        * name.
+                        */
+                       if ((match_match.rm_so == 0) &&
+                           (match_match.rm_eo == strlen(next))) {
+                           if (verbose) {
+                               kadmin_print_entry(next, valid, dbentry);
+                           }
+                           else {
+                               printf("%s\n", next);
+                           }
+                       }
+                   }
+#else  /* HAVE_REGCOMP */
+                   if (re_exec(next)) {
+                       if (verbose) {
+                           kadmin_print_entry(next, valid, dbentry);
+                       }
+                       else {
+                           printf("%s\n", next);
+                       }
+                   }
+#endif /* HAVE_REGCOMP */
+                   free(next);
+                   next = nnext;
+                   krb5_db_free_principal(kcontext, dbentry, 1);
+               }
+           }
+       }
+       else {
+           com_err(argv[0], 0, no_memory_fmt);
+       }
+    }
+}
+\f
+#ifdef LANGUAGES_SUPPORTED
+/*
+ * kadmin_language()   - Tell server to enable output in target language.
+ */
+void
+kadmin_language(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    krb5_int32         proto_stat;
+    krb5_int32         ncomps;
+    krb5_data          *complist;
+
+    requestname = argv[0];
+    if (argc == 2) {
+       if (!(kret = net_do_proto(KRB5_ADM_LANGUAGE_CMD,
+                                 argv[1],
+                                 (char *) NULL,
+                                 0,
+                                 (krb5_data *) NULL,
+                                 &proto_stat,
+                                 &ncomps,
+                                 &complist))) {
+           if (proto_stat == KRB5_ADM_SUCCESS) {
+               krb5_free_adm_data(kcontext, ncomps, complist);
+           }
+           if (!(kret = net_do_proto(KRB5_ADM_MIME_CMD,
+                                     (char *) NULL,
+                                     (char *) NULL,
+                                     0,
+                                     (krb5_data *) NULL,
+                                     &proto_stat,
+                                     &ncomps,
+                                     &complist))) {
+               if (proto_stat == KRB5_ADM_SUCCESS) {
+                   krb5_free_adm_data(kcontext, ncomps, complist);
+               }
+           }
+       }
+    }
+    else
+       com_err(argv[0], 0, lang_usage_fmt, argv[0]);
+}
+#endif /* LANGUAGES_SUPPORTED */
+\f
+/*
+ * kadmin_cd() - Change working directory.
+ */
+void
+kadmin_cd(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    requestname = argv[0];
+    if (argc == 2) {
+       if (chdir(argv[1]) == -1) {
+           com_err(argv[0], errno, cd_cannot_fmt, argv[1]);
+       }
+    }
+    else {
+       com_err(argv[0], 0, cd_usage_fmt, argv[0]);
+    }
+}
+\f
+/*
+ * kadmin_pwd()        - Print working directory.
+ */
+void
+kadmin_pwd(argc, argv)
+    int        argc;
+    char       *argv[];
+{
+    char       cwd[MAXPATHLEN];
+
+    requestname = argv[0];
+    if (argc == 1) {
+       if (
+#if    HAVE_GETCWD
+           getcwd(cwd, MAXPATHLEN)
+#else  /* HAVE_GETCWD */
+           getwd(cwd)
+#endif /* HAVE_GETCWD */
+           )
+           printf(pwd_mess_fmt, cwd);
+       else
+           com_err(argv[0], errno, pwd_err_fmt, cwd);
+    }
+    else
+       com_err(argv[0], 0, pwd_usage_fmt, argv[0]);
+}
+\f
+/*
+ * Startup fuction
+ */
+char *
+kadmin_startup(argc, argv)
+    int                argc;
+    char       *argv[];
+{
+    krb5_error_code    kret;
+    int                        option;
+    extern char                *optarg;
+    extern int         optind;
+    char               *action = (char *) NULL;
+
+    programname = argv[0];
+    while ((option = getopt(argc, argv, "r:p:mt:")) != EOF) {
+       switch (option) {
+       case 'r':
+           realm_name = optarg;
+           break;
+       case 'p':
+           principal_name = optarg;
+           break;
+       case 'm':
+           multiple = 1;
+           break;
+       default:
+           com_err(argv[0], 0, kadmin_usage_fmt, argv[0]);
+           exit(1);
+       }
+    }
+
+    /* Now we do some real work */
+    krb5_init_context(&kcontext);
+    krb5_init_ets(kcontext);
+
+    /* Get or verify current realm */
+    if (!realm_name) {
+       kret = krb5_get_default_realm(kcontext, &realm_name);
+       if (kret) {
+           com_err(argv[0], kret, kadmin_defrealm_msg);
+           exit(2);
+       }
+    }
+    else {
+       kret = krb5_set_default_realm(kcontext, realm_name);
+       if (kret) {
+           com_err(argv[0], kret, kadmin_srealm_fmt, realm_name);
+           exit(3);
+       }
+    }
+
+    /* If no principal name, formulate a reasonable response */
+    if (!principal_name) {
+       krb5_principal  me;
+       krb5_ccache     ccache;
+       char            *user;
+#if    HAVE_PWD_H
+       struct passwd   *pw;
+#endif /* HAVE_PWD_H */
+
+       me = (krb5_principal) NULL;
+       ccache = (krb5_ccache) NULL;
+       user = (char *) NULL;
+
+       /* First try our default credentials cache */
+       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<argc; i++)
+           n2alloc += strlen(argv[i]) + 1;
+
+       if (action = (char *) malloc(n2alloc)) {
+           for (i=optind; i<argc; i++) {
+               strcat(action, argv[i]);
+               strcat(action, " ");
+           }
+       }
+    }
+    return(action);
+}
+
+/*
+ * Cleanup function.
+ */
+int
+kadmin_cleanup()
+{
+    if (password_prompt)
+       free(password_prompt);
+    net_disconnect(1);
+}
diff --git a/src/kadmin/v5client/kadmin5.h b/src/kadmin/v5client/kadmin5.h
new file mode 100644 (file)
index 0000000..85d6a62
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * kadmin/v5client/kadmin5.h
+ *
+ * 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.h   - Describe common interfaces between kadmin modules.
+ */
+#ifndef        KADMIN5_H__
+#define        KADMIN5_H__
+
+/*
+ * Global data.
+ */
+extern int             exit_status;
+extern krb5_context    kcontext;
+extern char            *programname;
+extern char            *requestname;
+extern krb5_boolean    multiple;
+extern char            *principal_name;
+extern char            *password_prompt;
+
+/*
+ * Function prototypes.
+ */
+/* network.c */
+void           print_proto_sreply
+                       PROTOTYPE((krb5_int32, krb5_data *));
+void           print_proto_error
+                       PROTOTYPE((char *,
+                                  krb5_int32,
+                                  krb5_int32,
+                                  krb5_data *));
+void           net_disconnect
+                       PROTOTYPE((krb5_boolean));
+krb5_error_code        net_do_proto
+                       PROTOTYPE((char *,
+                                  char *,
+                                  char *,
+                                  krb5_int32,
+                                  krb5_data *,
+                                  krb5_int32 *,
+                                  krb5_int32 *,
+                                  krb5_data **));
+
+/* convert.c */
+char *         delta2string PROTOTYPE((krb5_deltat));
+char *         abs2string PROTOTYPE((krb5_timestamp));
+char *         dbflags2string PROTOTYPE((krb5_flags));
+char *         salt2string PROTOTYPE((krb5_int32));
+krb5_boolean   parse_princ_options PROTOTYPE((int,
+                                              char **,
+                                              krb5_ui_4 *,
+                                              krb5_db_entry *));
+void           help_princ_options();
+
+/* kadmin5.c */
+void           kadmin_show_principal PROTOTYPE((int, char **));
+void           kadmin_add_new_key PROTOTYPE((int, char **));
+void           kadmin_change_pwd PROTOTYPE((int, char **));
+void           kadmin_add_rnd_key PROTOTYPE((int, char **));
+void           kadmin_change_rnd PROTOTYPE((int, char **));
+void           kadmin_add_v4_key PROTOTYPE((int, char **));
+void           kadmin_change_v4_key PROTOTYPE((int, char **));
+void           kadmin_delete_entry PROTOTYPE((int, char **));
+void           kadmin_extract PROTOTYPE((int, char **));
+void           kadmin_extract_v4 PROTOTYPE((int, char **));
+void           kadmin_modify PROTOTYPE((int, char **));
+void           kadmin_rename PROTOTYPE((int, char **));
+void           kadmin_list PROTOTYPE((int, char **));
+void           kadmin_language PROTOTYPE((int, char **));
+void           kadmin_mime PROTOTYPE((int, char **));
+void           kadmin_cd PROTOTYPE((int, char **));
+void           kadmin_pwd PROTOTYPE((int, char **));
+char *         kadmin_startup PROTOTYPE((int, char **));
+int            kadmin_cleanup();
+#endif /* KADMIN5_H__ */
+
diff --git a/src/kadmin/v5client/kadmin5_ct.ct b/src/kadmin/v5client/kadmin5_ct.ct
new file mode 100644 (file)
index 0000000..5defef6
--- /dev/null
@@ -0,0 +1,76 @@
+#      $Source$
+#      $Author$
+#      $Id$
+#
+# 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.
+# 
+# 
+# Command table for Kerberos administration client
+#
+
+command_table kadmin_cmds;
+
+request kadmin_show_principal, "Show the Kerberos database entry for a principal.",
+       show_principal, show;
+
+request kadmin_add_new_key, "Add new entry to Kerberos database (prompting for new password).",
+       add_new_key, ank;
+
+request kadmin_change_pwd, "Change key of an entry in the Kerberos database (prompting for new password).",
+       change_pwd_key, cpw;
+
+request kadmin_add_rnd_key, "Add new entry to Kerberos database, using a random key.",
+       add_rnd_key, ark;
+
+request kadmin_change_rnd, "Change key of an entry in the Kerberos database (selecting a new random key).",
+       change_rnd_key, crk;
+
+request kadmin_delete_entry, "Delete an entry from the database.",
+       delete_entry, delent, del;
+
+request kadmin_extract, "Extract service key table entry/entries.",
+       extract_srvtab, xst, ex_st;
+
+request kadmin_extract_v4, "Extract service key table entry/entries in V4 format.",
+       extract_v4_srvtab, xst4;
+
+request kadmin_modify, "Modify database entry.",
+       modify_entry, modent;
+
+request kadmin_rename, "Rename database entry.",
+       rename_entry, renent;
+
+request kadmin_list, "List database entries.",
+       list_db, ldb;
+
+request kadmin_cd, "Change working directory.",
+       change_working_directory, cwd, cd;
+
+request kadmin_pwd, "Print working directory.",
+       print_working_directory, pwd;
+
+# list_requests is generic -- unrelated to Kerberos
+request        ss_list_requests, "List available requests.",
+       list_requests, lr, "?";
+
+request        ss_quit, "Exit program.",
+       quit, exit, q;
+
+end;
diff --git a/src/kadmin/v5client/network.c b/src/kadmin/v5client/network.c
new file mode 100644 (file)
index 0000000..2c8b5b8
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * kadmin/v5client/network.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.
+ *
+ */
+
+/*
+ * network.c   - Handle network and protocol related functions for kadmin5.
+ */
+#include "k5-int.h"
+#include "com_err.h"
+#include "adm.h"
+#include "adm_proto.h"
+#include "kadmin5.h"
+\f
+/*
+ * Own storage.
+ */
+static int             server_socket = -1;
+static krb5_auth_context *server_auth_context = (krb5_auth_context *) NULL;
+static krb5_ccache     server_ccache = (krb5_ccache) NULL;
+static krb5_boolean    server_active = 0;
+static krb5_error_code server_stat = 0;
+static krb5_boolean    server_op_in_prog = 0;
+
+/*
+ * Static strings.
+ */
+static const char *kadmin_server_name  = "kadmin-server";
+static const char *proto_serv_supp_msg = "server response follows:";
+static const char *proto_serv_end_msg  = "end of server response.";
+static const char *proto_cmd_unsupp_fmt        = "(%s) %s protocol command not supported by server";
+static const char *proto_pw_unacc_fmt  = "(%s) password unacceptable to server";
+static const char *proto_bad_pw_fmt    = "(%s) bad password entered";
+static const char *proto_in_tkt_fmt    = "(%s) not an initial ticket";
+static const char *proto_cant_chg_fmt  = "(%s) cannot change password";
+static const char *proto_lang_uns_fmt  = "(%s) language not supported";
+static const char *proto_p_exists_fmt  = "(%s) principal already exists";
+static const char *proto_p_notexist_fmt        = "(%s) principal does not exist";
+static const char *proto_no_auth_fmt   = "(%s) not authorized for this operation";
+static const char *proto_bad_opt_fmt   = "(%s) option not recognized by server";
+static const char *proto_value_req_fmt = "(%s) value required for option";
+static const char *proto_system_err_fmt        = "(%s) remote system error";
+static const char *proto_ufo_err_fmt   = "- (%s) protocol command %s returned unexpected error %d";
+static const char *net_conn_err_fmt    = "- %s: cannot connect to server";
+\f
+/*
+ * print_proto_sreply()        - Print server's error reply strings.
+ */
+void
+print_proto_sreply(ncomps, complist)
+    krb5_int32 ncomps;
+    krb5_data  *complist;
+{
+    int i;
+
+    if (ncomps > 0) {
+       for (i=0; i<ncomps; i++)
+           com_err(kadmin_server_name, 0, complist[i].data);
+    }
+}
+\f
+/*
+ * print_proto_error() - Print protocol error message if appropriate.
+ */
+void
+print_proto_error(cmd, cstat, ncomps, complist)
+    char       *cmd;
+    krb5_int32 cstat;
+    krb5_int32 ncomps;
+    krb5_data  *complist;
+{
+    switch (cstat) {
+    case KRB5_ADM_SUCCESS:
+       break;
+    case KRB5_ADM_CMD_UNKNOWN:
+       com_err(programname, 0, proto_cmd_unsupp_fmt, requestname, cmd);
+       break;
+    case KRB5_ADM_PW_UNACCEPT:
+       com_err(programname, 0, proto_pw_unacc_fmt, requestname);
+       break;
+    case KRB5_ADM_BAD_PW:
+       com_err(programname, 0, proto_bad_pw_fmt, requestname);
+       break;
+    case KRB5_ADM_NOT_IN_TKT:
+       com_err(programname, 0, proto_in_tkt_fmt, requestname);
+       break;
+    case KRB5_ADM_CANT_CHANGE:
+       com_err(programname, 0, proto_cant_chg_fmt, requestname);
+       break;
+    case KRB5_ADM_LANG_NOT_SUPPORTED:
+       com_err(programname, 0, proto_lang_uns_fmt, requestname);
+       break;
+    case KRB5_ADM_P_ALREADY_EXISTS:
+       com_err(programname, 0, proto_p_exists_fmt, requestname);
+       break;
+    case KRB5_ADM_P_DOES_NOT_EXIST:
+       com_err(programname, 0, proto_p_notexist_fmt, requestname);
+       break;
+    case KRB5_ADM_NOT_AUTHORIZED:
+       com_err(programname, 0, proto_no_auth_fmt, requestname);
+       break;
+    case KRB5_ADM_BAD_OPTION:
+       com_err(programname, 0, proto_bad_opt_fmt, requestname);
+       break;
+    case KRB5_ADM_VALUE_REQUIRED:
+       com_err(programname, 0, proto_value_req_fmt, requestname);
+       break;
+    case KRB5_ADM_SYSTEM_ERROR:
+       com_err(programname, 0, proto_system_err_fmt, requestname);
+       break;
+    default:
+       com_err(programname, cstat, proto_ufo_err_fmt, requestname,
+               cmd, cstat);
+       break;
+    }
+    if (cstat != KRB5_ADM_SUCCESS)
+       print_proto_sreply(ncomps, complist);
+}
+\f
+/*
+ * net_connect()       - Connect to the administrative server if not already
+ *                       connected or a separate connection is required for
+ *                       each transaction.
+ */
+static krb5_error_code
+net_connect()
+{
+    krb5_error_code    kret = 0;
+
+    /*
+     * Drop the connection if we were in the middle of something before.
+     */
+    if (server_op_in_prog)
+       net_disconnect(1);
+
+    if (!multiple || !server_active) {
+       char opassword[KRB5_ADM_MAX_PASSWORD_LEN];
+
+       if (!(kret = server_stat = krb5_adm_connect(kcontext,
+                                                   principal_name,
+                                                   password_prompt,
+                                                   opassword,
+                                                   &server_socket,
+                                                   &server_auth_context,
+                                                   &server_ccache))) {
+           server_active = 1;
+           memset(opassword, 0, KRB5_ADM_MAX_PASSWORD_LEN);
+       }
+       else
+           com_err(programname, kret, net_conn_err_fmt, requestname);
+    }
+    return(kret);
+}
+\f
+/*
+ * kadmin_disconnect() - Disconnect from the server.  If there has been
+ *                       a server error, just close the socket.  Otherwise
+ *                       engage in the disconnection protocol.
+ */
+void
+net_disconnect(force)
+    krb5_boolean       force;
+{
+    /*
+     * Only need to do this if we think the connection is active.
+     */
+    if (server_active) {
+       /*
+        * Disconnect if:
+        *      1) this is a one-time-only connection.
+        *      2) there was an error on the connection.
+        *      3) somebody's forcing the disconnection.
+        */
+       if (!multiple || (server_stat != 0) || force) {
+           /* If the connection is still good, then send a QUIT command */
+           if ((server_stat == 0) && !server_op_in_prog) {
+               krb5_data       quit_data;
+               krb5_int32      quit_status;
+               krb5_int32      quit_ncomps;
+               krb5_data       *quit_reply;
+
+               quit_data.data = KRB5_ADM_QUIT_CMD;
+               quit_data.length = strlen(quit_data.data);
+               if (!(server_stat = krb5_send_adm_cmd(kcontext,
+                                                     &server_socket,
+                                                     server_auth_context,
+                                                     1,
+                                                     &quit_data)))
+                   server_stat = krb5_read_adm_reply(kcontext,
+                                                     &server_socket,
+                                                     server_auth_context,
+                                                     &quit_status,
+                                                     &quit_ncomps,
+                                                     &quit_reply);
+               if (!server_stat) {
+                   print_proto_error(KRB5_ADM_QUIT_CMD,
+                                     quit_status,
+                                     quit_ncomps,
+                                     quit_reply);
+                   krb5_free_adm_data(kcontext, quit_ncomps, quit_reply);
+               }
+           }
+           /* Break down the connection */
+           krb5_adm_disconnect(kcontext,
+                               &server_socket,
+                               server_auth_context,
+                               server_ccache);
+
+           /* Clean up our state. */
+           server_socket = -1;
+           server_auth_context = (krb5_auth_context *) NULL;
+           server_ccache = (krb5_ccache) NULL;
+           server_active = 0;
+           server_op_in_prog = 0;
+           server_stat = EINVAL;
+       }
+    }
+}
+\f
+/*
+ * net_do_proto()      - Perform a protocol request and return the results.
+ */
+krb5_error_code
+net_do_proto(cmd, arg1, arg2, nargs, argp, rstatp, ncompp, complistp)
+    char       *cmd;
+    char       *arg1;
+    char       *arg2;
+    krb5_int32 nargs;
+    krb5_data  *argp;
+    krb5_int32 *rstatp;
+    krb5_int32 *ncompp;
+    krb5_data  **complistp;
+{
+    krb5_error_code    kret;
+    krb5_int32         nprotoargs;
+    krb5_data          *protoargs;
+
+    /* Connect to the server, if necessary */
+    if (!(kret = net_connect())) {
+
+       /* Figure out how many things we need to prepend to the arguments */
+       nprotoargs = nargs + 1;
+       if (arg1)
+           nprotoargs++;
+       if (arg2)
+           nprotoargs++;
+
+       /* Get the space for the new argument list */
+       if (protoargs = (krb5_data *) malloc((size_t) nprotoargs *
+                                            sizeof(krb5_data))) {
+           int index = 0;
+
+           /* Copy in the command */
+           protoargs[index].data = cmd;
+           protoargs[index].length = strlen(cmd);
+           index++;
+
+           /* Copy in the optional arguments */
+           if (arg1) {
+               protoargs[index].data = arg1;
+               protoargs[index].length = strlen(arg1);
+               index++;
+           }
+           if (arg2) {
+               protoargs[index].data = arg2;
+               protoargs[index].length = strlen(arg2);
+               index++;
+           }
+
+           /* Copy in the argument list */
+           memcpy(&protoargs[index], argp,
+                  (size_t) (nargs*sizeof(krb5_data)));
+
+           server_op_in_prog = 1;
+           /*
+            * Now send the command.
+            */
+           if (!(kret = server_stat = krb5_send_adm_cmd(kcontext,
+                                                        &server_socket,
+                                                        server_auth_context,
+                                                        nprotoargs,
+                                                        protoargs))) {
+               /*
+                * If that was successful, then try to read the reply.
+                */
+               kret = server_stat = krb5_read_adm_reply(kcontext,
+                                                        &server_socket,
+                                                        server_auth_context,
+                                                        rstatp,
+                                                        ncompp,
+                                                        complistp);
+               print_proto_error(cmd, *rstatp, *ncompp, *complistp);
+           }
+           server_op_in_prog = 0;
+           free(protoargs);
+       }
+       else
+           kret = ENOMEM;
+       net_disconnect(0);
+    }
+    return(kret);
+}
diff --git a/src/kadmin/v5client/ss_wrapper.c b/src/kadmin/v5client/ss_wrapper.c
new file mode 100644 (file)
index 0000000..26ef6dc
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * kadmin/v5client/ss_wrapper.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.
+ */
+
+/*
+ * ss_wrapper.c        - ss wrapper for kadmin client.
+ */
+
+#include "krb5.h"
+#include <ss/ss.h>
+#include <stdio.h>
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+extern char *kadmin_startup();
+
+int main(argc, argv)
+    int argc;
+    char *argv[];
+{
+    char *request;
+    krb5_error_code retval;
+    int sci_idx, code = 0;
+
+    request = kadmin_startup(argc, argv);
+    sci_idx = ss_create_invocation("kadmin5", "5.0", (char *) NULL,
+                                  &kadmin_cmds, &retval);
+    if (retval) {
+       ss_perror(sci_idx, retval, "creating invocation");
+       exit(1);
+    }
+    if (request) {
+           (void) ss_execute_line(sci_idx, request, &code);
+           free(request);
+           if (code != 0) {
+                   ss_perror(sci_idx, code, request);
+                   exit_status++;
+           }
+    } else
+           ss_listen(sci_idx, &retval);
+    return kadmin_cleanup() ? 1 : exit_status;
+}