summaryrefslogtreecommitdiffstats
path: root/src/kadmin/cli
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/cli')
-rw-r--r--src/kadmin/cli/ChangeLog28
-rw-r--r--src/kadmin/cli/Makefile.in19
-rw-r--r--src/kadmin/cli/Makefile.ov28
-rw-r--r--src/kadmin/cli/attic/Makefile11
-rw-r--r--src/kadmin/cli/attic/Makefile.in45
-rw-r--r--src/kadmin/cli/attic/configure.in15
-rw-r--r--src/kadmin/cli/attic/getdate.y1006
-rw-r--r--src/kadmin/cli/attic/kadmin.c958
-rw-r--r--src/kadmin/cli/attic/kadmin_ct.ct67
-rw-r--r--src/kadmin/cli/attic/memmove.c144
-rw-r--r--src/kadmin/cli/attic/setenv.c165
-rw-r--r--src/kadmin/cli/attic/ss_wrapper.c56
-rw-r--r--src/kadmin/cli/configure.in20
-rw-r--r--src/kadmin/cli/dump.c1485
-rw-r--r--src/kadmin/cli/getdate.y1009
-rw-r--r--src/kadmin/cli/kadmin.1473
-rw-r--r--src/kadmin/cli/kadmin.c1322
-rw-r--r--src/kadmin/cli/kadmin_ct.ct79
-rw-r--r--src/kadmin/cli/keytab.c420
-rw-r--r--src/kadmin/cli/memmove.c144
-rw-r--r--src/kadmin/cli/setenv.c165
-rw-r--r--src/kadmin/cli/ss_wrapper.c61
-rw-r--r--src/kadmin/cli/strftime.c469
23 files changed, 8189 insertions, 0 deletions
diff --git a/src/kadmin/cli/ChangeLog b/src/kadmin/cli/ChangeLog
new file mode 100644
index 000000000..a69639b86
--- /dev/null
+++ b/src/kadmin/cli/ChangeLog
@@ -0,0 +1,28 @@
+Fri Jul 19 16:10:39 1996 Marc Horowitz <marc@mit.edu>
+
+ * ss_wrapper.c (main): ss_execute_line was being called with three
+ args. There are only two, so no error was ever being returned.
+
+Thu Jul 18 19:14:51 1996 Marc Horowitz <marc@mit.edu>
+
+ * attic/configure.in: removed SS_RULES
+
+ * keytab.c (etype_string): ifdef out des3 reference
+
+ * configure.in: removed SS_RULES
+
+Mon Jul 15 16:56:43 1996 Barry Jaspan <bjaspan@mit.edu>
+
+ * kadmin.1, keytab.c (kadmin_keytab_add): change ktadd usage to
+ accept -glob
+
+Tue Jul 9 16:15:46 1996 Marc Horowitz <marc@mit.edu>
+
+ * Makefile.in: complete rewrite
+ * configure.in: add the necessary USE_*_LIBRARY macros
+
+Mon Jul 8 16:45:20 1996 Barry Jaspan <bjaspan@mit.edu>
+
+ * kadmin.1: Update man page for kadm5 changes and functionality.
+
+
diff --git a/src/kadmin/cli/Makefile.in b/src/kadmin/cli/Makefile.in
new file mode 100644
index 000000000..c605dd81f
--- /dev/null
+++ b/src/kadmin/cli/Makefile.in
@@ -0,0 +1,19 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE)
+
+PROG = kadmin
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
+
+all:: $(PROG).local $(PROG)
+
+$(PROG).local: $(OBJS) $(SRVDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG).local $(OBJS) $(SRVLIBS)
+
+$(PROG): $(OBJS) $(CLNTDEPLIBS)
+ $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(CLNTLIBS)
+
+install::
+ $(INSTALL_PROGRAM) $(PROG).local ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+ $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG)
+
+clean::
+ $(RM) $(PROG).local $(PROG) $(OBJS)
diff --git a/src/kadmin/cli/Makefile.ov b/src/kadmin/cli/Makefile.ov
new file mode 100644
index 000000000..5163bebb8
--- /dev/null
+++ b/src/kadmin/cli/Makefile.ov
@@ -0,0 +1,28 @@
+TOP = ..
+include $(TOP)/config.mk/template
+
+PROG = kadmin
+SRCS = kadmin.c kadmin_ct.c ss_wrapper.c getdate.c keytab.c
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKRB5_ALL) \
+ $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+DEPENDS = kadmin_ct.c getdate.c
+
+expand NormalProgram
+
+PROG = kadmin.local
+LIBS = $(LIBADMSRV) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKDB5) \
+ $(LIBKRB5_ALL) $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) \
+ $(BSDLIB) $(NETLIB) $(REGEXLIB)
+
+expand NormalProgram
+
+depend:: $(SRCS)
+clean:: ; -rm -f getdate.c y.tab.h kadmin_ct.c
+
+install::
+ $(INSTCMD) kadmin.1 $(INSTALL_MANDIR)/cat1/kadmin.1
+
+# needed until we run makedepend
+kadmin_ct.c: kadmin_ct.ct
+kadmin_ct.o: kadmin_ct.c
diff --git a/src/kadmin/cli/attic/Makefile b/src/kadmin/cli/attic/Makefile
new file mode 100644
index 000000000..79e432fe4
--- /dev/null
+++ b/src/kadmin/cli/attic/Makefile
@@ -0,0 +1,11 @@
+TOP = ../..
+include $(TOP)/config.mk/template
+
+SRCS = kadmin.c kadmin_ct.ct ss_wrapper.c getdate.y
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o
+PROG = cli_secure_admin
+
+LIBS = $(LIBADMCLNT) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBKRB5_ALL) \
+ $(LIBSS) $(LIBDYN) $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB)
+
+expand NormalProgram
diff --git a/src/kadmin/cli/attic/Makefile.in b/src/kadmin/cli/attic/Makefile.in
new file mode 100644
index 000000000..160016af9
--- /dev/null
+++ b/src/kadmin/cli/attic/Makefile.in
@@ -0,0 +1,45 @@
+CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) $(OVSECINC)
+OVSECROOT=/home/tlyu/ovsecure
+OVSECSTAGE=/afs/dev.mit.edu/reference/ovsecure/sunos/stage
+OVSECINC=-I$(OVSECROOT)/include -I$(OVSECSTAGE)/include
+OVSECLIB=-L$(OVSECSTAGE)/lib -lclient -lcommon -lrpclib -ldyn
+LDFLAGS = -g
+LIBOBJS=@LIBOBJS@
+ISODELIB=$(OVSECROOT)/lib/libisode.a
+COMERRLIB=$(OVSECROOT)/lib/libcom_err.a
+SSLIB=$(OVSECSTAGE)/lib/libss.a
+DBMLIB=$(OVSECROOT)/lib/libdb.a
+KDBLIB=$(OVSECROOT)/lib/libkdb5.a
+
+all::
+
+KLIB = $(OVSECROOT)/lib/libgssapi_krb5.a $(OVSECROOT)/lib/libkrb5.a $(OVSECROOT)/lib/libcrypto.a $(ISODELIB) $(SSLIB) $(COMERRLIB) $(DBMLIB)
+DEPKLIB = $(TOPLIBD)/libgssapi_krb5.a $(TOPLIBD)/libkrb5.a $(TOPLIBD)/libcrypto.a $(SSLIB) $(COMERRLIB) $(DBMLIB)
+
+SRCS =
+
+OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o $(LIBOBJS)
+
+all:: kadmin
+kadmin.o:
+ $(CC) -c $(CCOPTS) $(OVSECINC) $(DEFS) kadmin.c
+getdate.c getdate.h: getdate.y
+ $(RM) getdate.c getdate.h y.tab.*
+ $(YACC) -d $(srcdir)/getdate.y
+ $(MV) y.tab.c getdate.c
+ $(MV) y.tab.h getdate.h
+
+kadmin: $(OBJS)
+ $(CC) -o kadmin $(CFLAGS) $(OBJS) $(OVSECLIB) $(KLIB) $(LIBS)
+
+# needed until we run makedepend
+kadmin_ct.c: kadmin_ct.ct
+
+kadmin_ct.o: kadmin_ct.c
+
+clean::
+ $(RM) kadmin $(OBJS) kadmin_ct.c getdate.c getdate.h y.tab.c y.tab.h
+
+# testing rule for building getdate
+getdate: getdate.c
+ $(CC) -o getdate $(CFLAGS) -DTEST getdate.c
diff --git a/src/kadmin/cli/attic/configure.in b/src/kadmin/cli/attic/configure.in
new file mode 100644
index 000000000..8cca51316
--- /dev/null
+++ b/src/kadmin/cli/attic/configure.in
@@ -0,0 +1,15 @@
+AC_INIT(getdate.y)
+WITH_CCOPTS
+CONFIG_RULES
+AC_SET_BUILDTOP
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+AC_HAVE_FUNCS(ftime timezone)
+AC_CHECK_LIB(ndbm,main)
+AC_CHECK_LIB(dbm,main)
+AC_REPLACE_FUNCS([setenv memmove])
+KRB_INCLUDE
+ISODE_INCLUDE
+WITH_KRB5ROOT
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/cli/attic/getdate.y b/src/kadmin/cli/attic/getdate.y
new file mode 100644
index 000000000..6b03e73bb
--- /dev/null
+++ b/src/kadmin/cli/attic/getdate.y
@@ -0,0 +1,1006 @@
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+** send any email to Rich.
+**
+** This grammar has nine shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+#undef static
+#endif
+
+/* The following block of alloca-related preprocessor directives is here
+ solely to allow compilation by non GNU-C compilers of the C parser
+ produced from this file by old versions of bison. Newer versions of
+ bison include a block similar to this one in bison.simple. */
+
+#ifdef __GNUC__
+#undef alloca
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+void *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+ short timezone; /* Minutes west of GMT */
+ short dstflag; /* Field not used */
+};
+#endif /* defined(HAVE_SYS_TIMEB_H) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm *gmtime();
+extern struct tm *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yylex ();
+static int yyerror ();
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] =
+ "$Header$";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+ char *s;
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+ time_t Month;
+ time_t Day;
+ time_t Year;
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+ DSTMODE DSTmode;
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+ time_t Start;
+ time_t Future;
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+ time_t Start;
+ time_t DayOrdinal;
+ time_t DayNumber;
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+ time_t Start;
+ time_t RelMonth;
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+ char *buff;
+{
+ register char *p;
+ register char *q;
+ register const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex()
+{
+ register char c;
+ register char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds. */
+static time_t
+difftm(a, b)
+ struct tm *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ return
+ (
+ (
+ (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ /* + difference in years * 365 */
+ + (time_t)(ay-by) * 365
+ )*24 + (a->tm_hour - b->tm_hour)
+ )*60 + (a->tm_min - b->tm_min)
+ )*60 + (a->tm_sec - b->tm_sec);
+}
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+ (void)time(&ftz.time);
+
+ if (! (tm = gmtime (&ftz.time)))
+ return -1;
+ gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
+ ftz.timezone = difftm (&gmt, localtime (&ftz.time)) / 60;
+ }
+
+ tm = localtime(&now->time);
+ yyYear = tm->tm_year;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = now->timezone;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = now->time;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+main(ac, av)
+ int ac;
+ char *av[];
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff, (struct timeb *)NULL);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/src/kadmin/cli/attic/kadmin.c b/src/kadmin/cli/attic/kadmin.c
new file mode 100644
index 000000000..91d2a71e4
--- /dev/null
+++ b/src/kadmin/cli/attic/kadmin.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright 1994 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.
+ *
+ * kadmin.c: base functions for a kadmin command line interface using
+ * the OVSecure library
+ */
+
+#include <krb5/krb5.h>
+#include <krb5/los-proto.h>
+#include <krb5/ext-proto.h>
+#include <krb5/kdb.h>
+#include <ovsec_admin/admin.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <math.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/timeb.h>
+
+/* special struct to convert flag names for principals
+ to actual krb5_flags for a principal */
+struct pflag {
+ char *flagname; /* name of flag as typed to CLI */
+ int flaglen; /* length of string (not counting -,+) */
+ krb5_flags theflag; /* actual principal flag to set/clear */
+ int set; /* 0 means clear, 1 means set (on '-') */
+};
+
+static struct pflag flags[] = {
+{"allow_postdated", 15, KRB5_KDB_DISALLOW_POSTDATED, 1},
+{"allow_forwardable", 17, KRB5_KDB_DISALLOW_FORWARDABLE, 1},
+{"allow_tgs_req", 13, KRB5_KDB_DISALLOW_TGT_BASED, 1},
+{"allow_renewable", 15, KRB5_KDB_DISALLOW_RENEWABLE, 1},
+{"allow_proxiable", 15, KRB5_KDB_DISALLOW_PROXIABLE, 1},
+{"allow_dup_skey", 14, KRB5_KDB_DISALLOW_DUP_SKEY, 1},
+{"allow_tix", 9, KRB5_KDB_DISALLOW_ALL_TIX, 1},
+{"requires_preauth", 16, KRB5_KDB_REQUIRES_PRE_AUTH, 0},
+{"requres_hwauth", 14, KRB5_KDB_REQUIRES_HW_AUTH, 0},
+{"needchange", 10, KRB5_KDB_REQUIRES_PWCHANGE, 0},
+{"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1},
+{"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 }
+};
+
+static char *prflags[] = {
+ "DISALLOW_POSTDATED", /* 0x00000001 */
+ "DISALLOW_FORWARDABLE", /* 0x00000002 */
+ "DISALLOW_TGT_BASED", /* 0x00000004 */
+ "DISALLOW_RENEWABLE", /* 0x00000008 */
+ "DISALLOW_PROXIABLE", /* 0x00000010 */
+ "DISALLOW_DUP_SKEY", /* 0x00000020 */
+ "DISALLOW_ALL_TIX", /* 0x00000040 */
+ "REQUIRES_PRE_AUTH", /* 0x00000080 */
+ "REQUIRES_HW_AUTH", /* 0x00000100 */
+ "REQUIRES_PWCHANGE", /* 0x00000200 */
+ "UNKNOWN_0x00000400", /* 0x00000400 */
+ "UNKNOWN_0x00000800", /* 0x00000800 */
+ "DISALLOW_SVR", /* 0x00001000 */
+ "PWCHANGE_SERVICE" /* 0x00002000 */
+};
+
+char *getenv();
+struct passwd *getpwuid();
+int exit_status = 0;
+char *def_realm = NULL;
+
+void *ovsec_hndl = NULL;
+
+void usage()
+{
+ fprintf(stderr,
+ "usage: kadmin [-r realm] [-p principal] [-k keytab] [-q query]\n");
+ exit(1);
+}
+
+/* this is a wrapper to go around krb5_parse_principal so we can set
+ the default realm up properly */
+krb5_error_code kadmin_parse_name(name, principal)
+ char *name;
+ krb5_principal *principal;
+{
+ char *cp, *fullname;
+ krb5_error_code retval;
+
+ /* assumes def_realm is initialized! */
+ fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
+ if (fullname == NULL)
+ return ENOMEM;
+ strcpy(fullname, name);
+ cp = strchr(fullname, '@');
+ while (cp) {
+ if (cp - fullname && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '@');
+ }
+ if (cp == NULL) {
+ strcat(fullname, "@");
+ strcat(fullname, def_realm);
+ }
+ retval = krb5_parse_name(fullname, principal);
+ free(fullname);
+ return retval;
+}
+
+char *kadmin_startup(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ char *princstr = NULL, *keytab = NULL, *query = NULL;
+ char *luser, *canon, *cp;
+ int optchar, freeprinc = 0;
+ struct passwd *pw;
+ ovsec_kadm_ret_t retval;
+ krb5_ccache cc;
+ krb5_principal princ;
+
+ while ((optchar = getopt(argc, argv, "r:p:k:q:")) != EOF) {
+ switch (optchar) {
+ case 'r':
+ def_realm = optarg;
+ break;
+ case 'p':
+ princstr = optarg;
+ break;
+ case 'k':
+ fprintf(stderr, "kadmin: -k not supported yet\n");
+ exit(1);
+ break;
+ case 'q':
+ query = optarg;
+ break;
+ default:
+ usage();
+ }
+ }
+ if (def_realm == NULL && krb5_get_default_realm(&def_realm)) {
+ if (freeprinc)
+ free(princstr);
+ fprintf(stderr, "kadmin: unable to get default realm\n");
+ exit(1);
+ }
+ if (princstr == NULL) {
+ if (!krb5_cc_default(&cc) && !krb5_cc_get_principal(cc, &princ)) {
+ char *realm = NULL;
+ if (krb5_unparse_name(princ, &canon)) {
+ fprintf(stderr,
+ "kadmin: unable to canonicalize principal\n");
+ krb5_free_principal(princ);
+ exit(1);
+ }
+ /* strip out realm of principal if it's there */
+ realm = strchr(canon, '@');
+ while (realm) {
+ if (realm - canon && *(realm - 1) != '\\')
+ break;
+ else
+ realm = strchr(realm, '@');
+ }
+ if (realm)
+ *realm++ = '\0';
+ cp = strchr(canon, '/');
+ while (cp) {
+ if (cp - canon && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '/');
+ }
+ if (cp != NULL)
+ *cp = '\0';
+ princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
+ (realm ? 1 + strlen(realm) : 0) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, canon);
+ strcat(princstr, "/admin");
+ if (realm) {
+ strcat(princstr, "@");
+ strcat(princstr, realm);
+ }
+ free(canon);
+ krb5_free_principal(princ);
+ freeprinc++;
+ } else if (luser = getenv("USER")) {
+ princstr = malloc(strlen(luser) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, luser);
+ strcat(princstr, "/admin");
+ strcat(princstr, "@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else if (pw = getpwuid(getuid())) {
+ princstr = malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "kadmin: out of memory\n");
+ exit(1);
+ }
+ strcpy(princstr, pw->pw_name);
+ strcat(princstr, "/admin@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else {
+ fprintf(stderr, "kadmin: unable to figure out a principal name\n");
+ exit(1);
+ }
+ }
+ retval = ovsec_kadm_init_with_password(princstr, NULL,
+ OVSEC_KADM_ADMIN_SERVICE,
+ def_realm,
+ OVSEC_KADM_STRUCT_VERSION,
+ OVSEC_KADM_API_VERSION_1,
+ &ovsec_hndl);
+ if (freeprinc)
+ free(princstr);
+ if (retval) { /* assume kadm_init does init_ets() */
+ com_err("kadmin", retval, "while initializing kadmin interface");
+ exit(1);
+ }
+ return query;
+}
+
+int quit()
+{
+ ovsec_kadm_destroy(ovsec_hndl);
+ /* insert more random cleanup here */
+}
+
+void kadmin_delprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_ret_t retval;
+ krb5_principal princ;
+ char *canon;
+ char reply[5];
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "delete_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "delete_principal: bad arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("delete_principal", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(princ, &canon);
+ if (retval) {
+ com_err("delete_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(princ);
+ return;
+ }
+ if (argc == 2) {
+ printf("Are you sure you want to delete the principal \"%s\"? (yes/no): ", canon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr, "Principal \"%s\" not deleted\n", canon);
+ free(canon);
+ krb5_free_principal(princ);
+ return;
+ }
+ }
+ retval = ovsec_kadm_delete_principal(ovsec_hndl, princ);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("delete_principal", retval,
+ "while deleteing principal \"%s\"", canon);
+ free(canon);
+ return;
+ }
+ printf("Principal \"%s\" deleted.\nMake sure that you have removed this principal from all ACLs before reusing.\n", canon);
+ free(canon);
+ return;
+}
+
+void kadmin_renprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_principal oldprinc, newprinc;
+ char *oldcanon, *newcanon;
+ char reply[5];
+ ovsec_kadm_ret_t retval;
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "rename_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 4 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "rename_principal: bad arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 2], &oldprinc);
+ if (retval) {
+ com_err("rename_principal", retval, "while parsing old principal");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &newprinc);
+ if (retval) {
+ krb5_free_principal(oldprinc);
+ com_err("rename_principal", retval, "while parsing new principal");
+ return;
+ }
+ retval = krb5_unparse_name(oldprinc, &oldcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing old principal");
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ retval = krb5_unparse_name(newprinc, &newcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing new principal");
+ free(oldcanon);
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ if (argc == 3) {
+ printf("Are you sure you want to rename the principal \"%s\" to \"%s\"? (yes/no): ",
+ oldcanon, newcanon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr,
+ "rename_principal: \"%s\" NOT renamed to \"%s\".\n",
+ oldcanon, newcanon);
+ free(newcanon);
+ free(oldcanon);
+ krb5_free_principal(newprinc);
+ krb5_free_principal(oldprinc);
+ return;
+ }
+ }
+ retval = ovsec_kadm_rename_principal(ovsec_hndl, oldprinc, newprinc);
+ krb5_free_principal(oldprinc);
+ krb5_free_principal(newprinc);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while renaming \"%s\" to \"%s\".", oldcanon,
+ newcanon);
+ free(newcanon);
+ free(oldcanon);
+ return;
+ }
+ printf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
+ oldcanon, newcanon, newcanon);
+ return;
+}
+
+void kadmin_cpw(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_ret_t retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+ char *canon;
+ krb5_principal princ;
+
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, "change_password: too many arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("change_password", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(princ, &canon);
+ if (retval) {
+ com_err("change_password", retval, "while canonicalizing principal");
+ krb5_free_principal(princ);
+ return;
+ }
+ if ((argc == 4) && (strlen(argv[1]) == 3) && !strcmp("-pw", argv[1])) {
+ retval = ovsec_kadm_chpass_principal(ovsec_hndl, princ, argv[2]);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else if ((argc == 3) && (strlen(argv[1]) == 8) &&
+ !strcmp("-randkey", argv[1])) {
+ krb5_keyblock *newkey = NULL;
+ retval = ovsec_kadm_randkey_principal(ovsec_hndl, princ, &newkey);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while randomizing key for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ memset(newkey->contents, 0, newkey->length);
+ printf("Key for \"%s\" randomized.\n", canon);
+ free(canon);
+ return;
+ } else if (argc == 2) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("change_password", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(princ);
+ return;
+ }
+ retval = ovsec_kadm_chpass_principal(ovsec_hndl, princ, newpw);
+ krb5_free_principal(princ);
+ memset(newpw, 0, sizeof (newpw));
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ }
+ fprintf(stderr, "change_password: bad arguments\n");
+ free(canon);
+ krb5_free_principal(princ);
+ return;
+}
+
+int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, caller)
+ int argc;
+ char *argv[];
+ ovsec_kadm_principal_ent_t oprinc;
+ u_int32 *mask;
+ char **pass, *caller;
+{
+ int i, j;
+ struct timeb now;
+ krb5_error_code retval;
+
+ *mask = 0;
+ *pass = NULL;
+ ftime(&now);
+ for (i = 1; i < argc - 1; i++) {
+ if (strlen(argv[i]) == 7 &&
+ !strcmp("-expire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->princ_expire_time = get_date(argv[i], now);
+ *mask |= OVSEC_KADM_PRINC_EXPIRE_TIME;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 9 &&
+ !strcmp("-pwexpire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->pw_expiration = get_date(argv[i], now);
+ *mask |= OVSEC_KADM_PW_EXPIRATION;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-maxlife", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->max_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_MAX_LIFE;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 5 &&
+ !strcmp("-kvno", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->kvno = atoi(argv[i]);
+ *mask |= OVSEC_KADM_KVNO;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-policy", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->policy = argv[i];
+ *mask |= OVSEC_KADM_POLICY;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 12 &&
+ !strcmp("-clearpolicy", argv[i])) {
+ oprinc->policy = NULL;
+ *mask |= OVSEC_KADM_POLICY_CLR;
+ continue;
+ }
+ if (strlen(argv[i]) == 3 &&
+ !strcmp("-pw", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ *pass = argv[i];
+ continue;
+ }
+ }
+ for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
+ if (strlen(argv[i]) == flags[j].flaglen + 1 &&
+ !strcmp(flags[j].flagname,
+ &argv[i][1] /* strip off leading + or - */)) {
+ if (flags[j].set && argv[i][0] == '-' ||
+ !flags[j].set && argv[i][0] == '+') {
+ oprinc->attributes |= flags[j].theflag;
+ *mask |= OVSEC_KADM_ATTRIBUTES;
+ break;
+ } else if (flags[j].set && argv[i][0] == '+' ||
+ !flags[j].set && argv[i][0] == '-') {
+ oprinc->attributes &= ~flags[j].theflag;
+ *mask |= OVSEC_KADM_ATTRIBUTES;
+ break;
+ } else {
+ return -1;
+ }
+ }
+ }
+ return -1;
+ }
+ if (i != argc - 1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ }
+ retval = kadmin_parse_name(argv[i], &oprinc->principal);
+ if (retval) {
+ com_err(caller, retval, "while parsing principal");
+ return -1;
+ }
+ return 0;
+}
+
+void kadmin_addprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_rec princ;
+ u_int32 mask;
+ char *pass, *canon;
+ krb5_error_code retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, "add_principal")) {
+ fprintf(stderr, "add_principal: bad arguments\n");
+ return;
+ }
+ retval = krb5_unparse_name(princ.principal, &canon);
+ if (retval) {
+ com_err("add_principal",
+ retval, "while canonicalizing principal");
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ if (pass == NULL) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ pass = newpw;
+ }
+ mask |= OVSEC_KADM_PRINCIPAL;
+ retval = ovsec_kadm_create_principal(ovsec_hndl, &princ, mask, pass);
+ krb5_free_principal(princ.principal);
+ if (retval) {
+ com_err("add_principal", retval, "while creating \"%s\".",
+ canon);
+ free(canon);
+ return;
+ }
+ printf("Principal \"%s\" created.\n", canon);
+ free(canon);
+}
+
+void kadmin_modprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_rec princ;
+ u_int32 mask;
+ krb5_error_code retval;
+ char *pass, *canon;
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, "modify_principal")) {
+ fprintf(stderr, "modify_principal: bad arguments\n");
+ return;
+ }
+ retval = krb5_unparse_name(princ.principal, &canon);
+ if (retval) {
+ com_err("modify_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(princ.principal);
+ return;
+ }
+ retval = ovsec_kadm_modify_principal(ovsec_hndl, &princ, mask);
+ if (retval) {
+ com_err("modify_principal", retval, "while modifying \"%s\".",
+ argv[argc - 1]);
+ return;
+ }
+}
+
+void kadmin_getprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ ovsec_kadm_principal_ent_t dprinc;
+ krb5_principal princ;
+ krb5_error_code retval;
+ char *canon, *modcanon;
+ int i;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "get_principal: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
+ fprintf(stderr, "get_principal: bad arguments\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("get_principal", retval, "while parsing principal");
+ return;
+ }
+ retval = krb5_unparse_name(princ, &canon);
+ if (retval) {
+ com_err("get_principal", retval, "while canonicalizing principal");
+ krb5_free_principal(princ);
+ return;
+ }
+ retval = ovsec_kadm_get_principal(ovsec_hndl, princ, &dprinc);
+ krb5_free_principal(princ);
+ if (retval) {
+ com_err("get_principal", retval, "while retrieving \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ retval = krb5_unparse_name(dprinc->mod_name, &modcanon);
+ if (retval) {
+ com_err("get_principal", retval, "while unparsing modname");
+ ovsec_kadm_free_principal_ent(ovsec_hndl, dprinc);
+ free(canon);
+ return;
+ }
+ if (argc == 2) {
+ printf("Principal: %s\n", canon);
+ printf("Expiration date: %d\n", dprinc->princ_expire_time);
+ printf("Last password change: %d\n", dprinc->last_pwd_change);
+ printf("Password expiration date: %d\n", dprinc->pw_expiration);
+ printf("Maximum life: %d\n", dprinc->max_life);
+ printf("Last modified: by %s\n\ton %d\n",
+ modcanon, dprinc->mod_date);
+ printf("Attributes: ");
+ for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
+ if (dprinc->attributes & (krb5_flags) 1 << i)
+ printf(" %s", prflags[i]);
+ }
+ printf("\n");
+ printf("Key version: %d\n", dprinc->kvno);
+ printf("Master key version: %d\n", dprinc->mkvno);
+ printf("Policy: %s\n", dprinc->policy);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\n",
+ canon, dprinc->princ_expire_time, dprinc->last_pwd_change,
+ dprinc->pw_expiration, dprinc->max_life, modcanon,
+ dprinc->mod_date, dprinc->attributes, dprinc->kvno,
+ dprinc->mkvno, dprinc->policy);
+ }
+ free(modcanon);
+ ovsec_kadm_free_principal_ent(ovsec_hndl, dprinc);
+ free(canon);
+}
+
+int kadmin_parse_policy_args(argc, argv, policy, mask, caller)
+ int argc;
+ char *argv[];
+ ovsec_kadm_policy_ent_t policy;
+ u_int32 *mask;
+ char *caller;
+{
+ int i;
+ struct timeb now;
+ krb5_error_code retval;
+
+ ftime(&now);
+ *mask = 0;
+ for (i = 1; i < argc - 1; i++) {
+ if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-maxlife")) {
+ if (++i > argc -2)
+ return -1;
+ else {
+ policy->pw_max_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_PW_MAX_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-minlife")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_life = get_date(argv[i], now) - now.time;
+ *mask |= OVSEC_KADM_PW_MIN_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 10 &&
+ !strcmp(argv[i], "-minlength")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_length = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_MIN_LENGTH;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 11 &&
+ !strcmp(argv[i], "-minclasses")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_classes = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_MIN_CLASSES;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-history")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_history_num = atoi(argv[i]);
+ *mask |= OVSEC_KADM_PW_HISTORY_NUM;
+ continue;
+ }
+ } else
+ return -1;
+ }
+ if (i != argc -1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ } else
+ return 0;
+}
+
+void kadmin_addpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
+ fprintf(stderr, "add_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ mask |= OVSEC_KADM_POLICY;
+ retval = ovsec_kadm_create_policy(ovsec_hndl, &policy, mask);
+ if (retval) {
+ com_err("add_policy", retval, "while creating policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_modpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ u_int32 mask;
+ ovsec_kadm_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
+ "modify_policy")) {
+ fprintf(stderr, "modify_policy: bad arguments\n");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ retval = ovsec_kadm_modify_policy(ovsec_hndl, &policy, mask);
+ if (retval) {
+ com_err("modify_policy", retval, "while modifying policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_delpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ char reply[5];
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "delete_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-force", argv[1]) : 1)) {
+ fprintf(stderr, "delete_policy: bad arguments\n");
+ return;
+ }
+ if (argc == 2) {
+ printf("Are you sure you want to delete the policy \"%s\"? (yes/no): ", argv[1]);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr, "Policy \"%s\" not deleted.\n", argv[1]);
+ return;
+ }
+ }
+ retval = ovsec_kadm_delete_policy(ovsec_hndl, argv[argc - 1]);
+ if (retval) {
+ com_err("delete_policy:", retval, "while deleting policy \"%s\"",
+ argv[argc - 1]);
+ return;
+ }
+ return;
+}
+
+void kadmin_getpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ ovsec_kadm_policy_ent_t policy;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "get_policy: wrong number of arguments\n");
+ return;
+ }
+ if (argc == 3 &&
+ (strlen(argv[1]) == 6 ? strcmp("-terse", argv[1]) : 1)) {
+ fprintf(stderr, "get_policy: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_policy(ovsec_hndl, argv[argc - 1], &policy);
+ if (retval) {
+ com_err("get_policy", retval, "while retrieving policy \"%s\".",
+ argv[argc - 1]);
+ return;
+ }
+ if (argc == 2) {
+ printf("Policy: %s\n", policy->policy);
+ printf("Maximum password life: %d\n", policy->pw_max_life);
+ printf("Minimum password life: %d\n", policy->pw_min_life);
+ printf("Minimum password length: %d\n", policy->pw_min_length);
+ printf("Minimum number of password character classes: %d\n",
+ policy->pw_min_classes);
+ printf("Number of old keys kept: %d\n", policy->pw_history_num);
+ printf("Reference count: %d\n", policy->policy_refcnt);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ policy->policy, policy->pw_max_life, policy->pw_min_life,
+ policy->pw_min_length, policy->pw_min_classes,
+ policy->pw_history_num, policy->policy_refcnt);
+ }
+ ovsec_kadm_free_policy_ent(ovsec_hndl, policy);
+ return;
+}
+
+kadmin_getprivs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE"};
+ krb5_error_code retval;
+ int i;
+ u_int32 plist;
+
+ if (argc != 1) {
+ fprintf(stderr, "get_privs: bad arguments\n");
+ return;
+ }
+ retval = ovsec_kadm_get_privs(ovsec_hndl, &plist);
+ if (retval) {
+ com_err("get_privs", retval, "while retrieving privileges");
+ return;
+ }
+ printf("current privileges:");
+ for (i = 0; i < sizeof (privs) / sizeof (char *); i++) {
+ if (plist & 1 << i)
+ printf(" %s", privs[i]);
+ }
+ printf("\n");
+ return;
+}
diff --git a/src/kadmin/cli/attic/kadmin_ct.ct b/src/kadmin/cli/attic/kadmin_ct.ct
new file mode 100644
index 000000000..f5a67ed53
--- /dev/null
+++ b/src/kadmin/cli/attic/kadmin_ct.ct
@@ -0,0 +1,67 @@
+# Copyright 1994 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 kadmin CLI for OVSecure
+#
+
+command_table kadmin_cmds;
+
+request kadmin_addprinc, "Add principal",
+ add_prinicpal, addprinc, ank;
+
+request kadmin_delprinc, "Delete principal",
+ delete_principal, delprinc;
+
+request kadmin_modprinc, "Modify principal",
+ modify_principal, modprinc;
+
+request kadmin_renprinc, "Rename principal",
+ rename_principal, renprinc;
+
+request kadmin_cpw, "Change password",
+ change_password, cpw;
+
+request kadmin_getprinc, "Get principal",
+ get_principal, getprinc;
+
+request kadmin_addpol, "Add policy",
+ add_policy, addpol;
+
+request kadmin_modpol, "Modify policy",
+ modify_policy, modpol;
+
+request kadmin_delpol, "Delete policy",
+ delete_policy, delpol;
+
+request kadmin_getpol, "Get policy",
+ get_policy, getpol;
+
+request kadmin_getprivs, "Get privileges",
+ get_privs, getprivs;
+
+# 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/cli/attic/memmove.c b/src/kadmin/cli/attic/memmove.c
new file mode 100644
index 000000000..abc91e923
--- /dev/null
+++ b/src/kadmin/cli/attic/memmove.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MEMMOVE
+
+/* based on @(#)bcopy.c 5.11 (Berkeley) 6/21/91 */
+
+#include <krb5/osconf.h>
+#include <krb5/config.h>
+#ifdef USE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef int word; /* "word" used for optimal copy speed */
+
+#define wsize sizeof(word)
+#define wmask (wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+ void *dst0;
+ const void *src0;
+ register size_t length;
+{
+ register char *dst = dst0;
+ register const char *src = src0;
+ register size_t t;
+
+ if (length == 0 || dst == src) /* nothing to do */
+ goto done;
+
+ /*
+ * Macros: loop-t-times; and loop-t-times, t>0
+ */
+#define TLOOP(s) if (t) TLOOP1(s)
+#define TLOOP1(s) do { s; } while (--t)
+
+ if ((unsigned long)dst < (unsigned long)src) {
+ /*
+ * Copy forward.
+ */
+ t = (int)src; /* only need low bits */
+ if ((t | (int)dst) & wmask) {
+ /*
+ * Try to align operands. This cannot be done
+ * unless the low bits match.
+ */
+ if ((t ^ (int)dst) & wmask || length < wsize)
+ t = length;
+ else
+ t = wsize - (t & wmask);
+ length -= t;
+ TLOOP1(*dst++ = *src++);
+ }
+ /*
+ * Copy whole words, then mop up any trailing bytes.
+ */
+ t = length / wsize;
+ TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+ t = length & wmask;
+ TLOOP(*dst++ = *src++);
+ } else {
+ /*
+ * Copy backwards. Otherwise essentially the same.
+ * Alignment works as before, except that it takes
+ * (t&wmask) bytes to align, not wsize-(t&wmask).
+ */
+ src += length;
+ dst += length;
+ t = (int)src;
+ if ((t | (int)dst) & wmask) {
+ if ((t ^ (int)dst) & wmask || length <= wsize)
+ t = length;
+ else
+ t &= wmask;
+ length -= t;
+ TLOOP1(*--dst = *--src);
+ }
+ t = length / wsize;
+ TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+ t = length & wmask;
+ TLOOP(*--dst = *--src);
+ }
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ return (dst0);
+#else
+ return;
+#endif
+}
diff --git a/src/kadmin/cli/attic/setenv.c b/src/kadmin/cli/attic/setenv.c
new file mode 100644
index 000000000..a2432c3d6
--- /dev/null
+++ b/src/kadmin/cli/attic/setenv.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)setenv.c 8.1 (Berkeley) 6/4/93 */
+/* based on @(#)getenv.c 8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __P
+#define __P(x) ()
+#endif
+char *__findenv __P((const char *, int *));
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+setenv(name, value, rewrite)
+ register const char *name;
+ register const char *value;
+ int rewrite;
+{
+ extern char **environ;
+ static int alloced; /* if allocated space before */
+ register char *c;
+ int l_value, offset;
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = __findenv(name, &offset))) { /* find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /* old larger; copy over */
+ while (*c++ = *value++);
+ return (0);
+ }
+ } else { /* create new slot */
+ register int cnt;
+ register char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced) { /* just increase size */
+ environ = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!environ)
+ return (-1);
+ }
+ else { /* get new space */
+ alloced = 1; /* copy old entries into it */
+ p = (char **)malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ memcpy(p, environ, cnt * sizeof(char *));
+ environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; *c++ = *value++;);
+ return (0);
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+ const char *name;
+{
+ extern char **environ;
+ register char **p;
+ int offset;
+
+ while (__findenv(name, &offset)) /* if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
+
+/*
+ * __findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ */
+static char *
+__findenv(name, offset)
+ register const char *name;
+ int *offset;
+{
+ extern char **environ;
+ register int len;
+ register const char *np;
+ register char **p, *c;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (c = *p) != NULL; ++p)
+ if (strncmp(c, name, len) == 0 && c[len] == '=') {
+ *offset = p - environ;
+ return (c + len + 1);
+ }
+ return (NULL);
+}
diff --git a/src/kadmin/cli/attic/ss_wrapper.c b/src/kadmin/cli/attic/ss_wrapper.c
new file mode 100644
index 000000000..f7bbda516
--- /dev/null
+++ b/src/kadmin/cli/attic/ss_wrapper.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 1994 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 for kadmin
+ */
+
+#include <krb5/krb5.h>
+#include <ss/ss.h>
+#include <stdio.h>
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+
+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("kadmin", "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);
+ if (code != 0) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/cli/configure.in b/src/kadmin/cli/configure.in
new file mode 100644
index 000000000..713d7d212
--- /dev/null
+++ b/src/kadmin/cli/configure.in
@@ -0,0 +1,20 @@
+AC_INIT(getdate.y)
+WITH_CCOPTS
+CONFIG_RULES
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_HAVE_HEADERS(unistd.h sys/timeb.h alloca.h)
+AC_HAVE_FUNCS(ftime timezone)
+AC_CHECK_LIB(ndbm,main)
+AC_CHECK_LIB(dbm,main)
+AC_REPLACE_FUNCS([setenv memmove strftime])
+KRB_INCLUDE
+USE_KADMCLNT_LIBRARY
+USE_GSSAPI_LIBRARY
+USE_KADMSRV_LIBRARY
+USE_GSSRPC_LIBRARY
+USE_DYN_LIBRARY
+USE_KDB5_LIBRARY
+USE_SS_LIBRARY
+KRB5_LIBRARIES
+V5_AC_OUTPUT_MAKEFILE
diff --git a/src/kadmin/cli/dump.c b/src/kadmin/cli/dump.c
new file mode 100644
index 000000000..2c5e4e753
--- /dev/null
+++ b/src/kadmin/cli/dump.c
@@ -0,0 +1,1485 @@
+/*
+ * admin/edit/dump.c
+ *
+ * Copyright 1990,1991 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.
+ *
+ * Dump a KDC database. This file was originally written to be part
+ * of kdb5_edit but has now been adapted for kadmin.
+ */
+
+#include <stdio.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+struct dump_args {
+ char *programname;
+ FILE *ofile;
+ krb5_context context;
+ int verbose;
+};
+
+/* External data */
+extern int exit_status;
+extern krb5_context context;
+extern void *handle;
+
+/* Strings */
+
+static const char k5beta5_dump_header[] = "kdb5_edit load_dump version 2.0\n";
+static const char k5_dump_header[] = "kdb5_edit load_dump version 3.0\n";
+static const char kadm5_dump_header[] = "kadm5 load_dump version 4.0\n";
+
+static const char null_mprinc_name[] = "kdb5_dump@MISSING";
+
+/* Message strings */
+static const char regex_err[] = "%s: regular expression error - %s\n";
+static const char regex_merr[] = "%s: regular expression match error - %s\n";
+static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n";
+static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n";
+static const char nokeys_err[] = "%s: cannot find any standard key for %s\n";
+static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n";
+static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n";
+static const char oflock_error[] = "%s: cannot lock %s (%s)\n";
+static const char dumprec_err[] = "%s: error performing %s dump (%s)\n";
+static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n";
+static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: ";
+static const char read_name_string[] = "name string";
+static const char read_key_type[] = "key type";
+static const char read_key_data[] = "key data";
+static const char read_pr_data1[] = "first set of principal attributes";
+static const char read_mod_name[] = "modifier name";
+static const char read_pr_data2[] = "second set of principal attributes";
+static const char read_salt_data[] = "salt data";
+static const char read_akey_type[] = "alternate key type";
+static const char read_akey_data[] = "alternate key data";
+static const char read_asalt_type[] = "alternate salt type";
+static const char read_asalt_data[] = "alternate salt data";
+static const char read_exp_data[] = "expansion data";
+static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n";
+static const char add_princ_fmt[] = "%s\n";
+static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n";
+static const char read_err_fmt[] = "%s(%d): cannot read %s\n";
+static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n";
+static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n";
+static const char err_line_fmt[] = "%s: error processing line %d of %s\n";
+static const char head_bad_fmt[] = "%s: dump header bad in %s\n";
+static const char read_bytecnt[] = "record byte count";
+static const char read_encdata[] = "encoded data";
+static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n";
+static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n";
+static const char read_nint_data[] = "principal static attributes";
+static const char read_tcontents[] = "tagged data contents";
+static const char read_ttypelen[] = "tagged data type and length";
+static const char read_kcontents[] = "key data contents";
+static const char read_ktypelen[] = "key data type and length";
+static const char read_econtents[] = "extra data contents";
+static const char k5beta5_fmt_name[] = "Kerberos version 5 old format";
+static const char k5beta6_fmt_name[] = "Kerberos version 5 beta 6 format";
+static const char lusage_err_fmt[] = "%s: usage is %s [%s] [%s] [%s] filename dbname\n";
+static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n";
+static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n";
+static const char stdin_name[] = "standard input";
+static const char restfail_fmt[] = "%s: %s restore failed\n";
+static const char close_err_fmt[] = "%s: cannot close database (%s)\n";
+static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n";
+static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n";
+static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n";
+static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n";
+static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n";
+static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n";
+
+static const char oldoption[] = "-old";
+static const char verboseoption[] = "-verbose";
+static const char updateoption[] = "-update";
+static const char dump_tmptrail[] = "~";
+
+/* Can't use krb5_dbe_find_enctype because we have a */
+/* kadm5_principal_ent_t and not a krb5_db_entry */
+static krb5_error_code
+find_enctype(dbentp, enctype, salttype, kentp)
+ kadm5_principal_ent_rec *dbentp;
+ krb5_enctype enctype;
+ krb5_int32 salttype;
+ krb5_key_data **kentp;
+{
+ int i;
+ int maxkvno;
+ krb5_key_data *datap;
+
+ maxkvno = -1;
+ datap = (krb5_key_data *) NULL;
+ for (i=0; i<dbentp->n_key_data; i++) {
+ if ((dbentp->key_data[i].key_data_type[0] == enctype) &&
+ ((dbentp->key_data[i].key_data_type[1] == salttype) ||
+ (salttype < 0))) {
+ maxkvno = dbentp->key_data[i].key_data_kvno;
+ datap = &dbentp->key_data[i];
+ }
+ }
+ if (maxkvno >= 0) {
+ *kentp = datap;
+ return(0);
+ }
+ return(ENOENT);
+}
+
+
+/*
+ * dump_k5beta5_header() - Make a dump header that is recognizable by Kerberos
+ * Version 5 Beta 5 and previous releases.
+ */
+static krb5_error_code
+dump_k5beta5_header(arglist)
+ struct dump_args *arglist;
+{
+ /* The old header consists of the leading string */
+ fprintf(arglist->ofile, k5beta5_dump_header);
+ return(0);
+}
+
+
+/*
+ * dump_k5beta5_iterator() - Dump an entry in a format that is usable
+ * by Kerberos Version 5 Beta 5 and previous
+ * releases.
+ */
+static krb5_error_code
+dump_k5beta5_iterator(ptr, name, entry)
+ krb5_pointer ptr;
+ char *name;
+ kadm5_principal_ent_rec *entry;
+{
+ krb5_error_code retval;
+ struct dump_args *arg;
+ char *mod_name;
+ krb5_tl_data *pwchg;
+ krb5_key_data *pkey, *akey, nullkey;
+ int i;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+ mod_name = (char *) NULL;
+ memset(&nullkey, 0, sizeof(nullkey));
+
+ /*
+ * Deserialize the modifier record.
+ */
+ mod_name = (char *) NULL;
+ pkey = akey = (krb5_key_data *) NULL;
+
+ /*
+ * Flatten the modifier name.
+ */
+ if ((retval = krb5_unparse_name(arg->context,
+ entry->mod_name,
+ &mod_name)))
+ fprintf(stderr, mname_unp_err, arg->programname,
+ error_message(retval));
+
+ /*
+ * Find the 'primary' key and the 'alternate' key.
+ */
+ if ((retval = find_enctype(entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_NORMAL,
+ &pkey)) &&
+ (retval = find_enctype(entry,
+ ENCTYPE_DES_CBC_CRC,
+ KRB5_KDB_SALTTYPE_V4,
+ &akey))) {
+ fprintf(stderr, nokeys_err, arg->programname, name);
+ krb5_xfree(mod_name);
+ return(retval);
+ }
+
+ /* If we only have one type, then ship it out as the primary. */
+ if (!pkey && akey) {
+ pkey = akey;
+ akey = &nullkey;
+ }
+ else {
+ if (!akey)
+ akey = &nullkey;
+ }
+
+ /*
+ * First put out strings representing the length of the variable
+ * length data in this record, then the name and the primary key type.
+ */
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t", strlen(name),
+ strlen(mod_name),
+ (krb5_int32) pkey->key_data_length[0],
+ (krb5_int32) akey->key_data_length[0],
+ (krb5_int32) pkey->key_data_length[1],
+ (krb5_int32) akey->key_data_length[1],
+ name,
+ (krb5_int32) pkey->key_data_type[0]);
+ for (i=0; i<pkey->key_data_length[0]; i++) {
+ fprintf(arg->ofile, "%02x", pkey->key_data_contents[0][i]);
+ }
+ /*
+ * Second, print out strings representing the standard integer
+ * data in this record.
+ */
+ fprintf(arg->ofile,
+ "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%s\t%u\t%u\t%u\t",
+ (krb5_int32) pkey->key_data_kvno,
+ entry->max_life, entry->max_renewable_life,
+ 1 /* Fake mkvno */, entry->princ_expire_time, entry->pw_expiration,
+ entry->last_pwd_change, entry->last_success, entry->last_failed,
+ entry->fail_auth_count, mod_name, entry->mod_date,
+ entry->attributes, pkey->key_data_type[1]);
+
+ /* Pound out the salt data, if present. */
+ for (i=0; i<pkey->key_data_length[1]; i++) {
+ fprintf(arg->ofile, "%02x", pkey->key_data_contents[1][i]);
+ }
+ /* Pound out the alternate key type and contents */
+ fprintf(arg->ofile, "\t%u\t", akey->key_data_type[0]);
+ for (i=0; i<akey->key_data_length[0]; i++) {
+ fprintf(arg->ofile, "%02x", akey->key_data_contents[0][i]);
+ }
+ /* Pound out the alternate salt type and contents */
+ fprintf(arg->ofile, "\t%u\t", akey->key_data_type[1]);
+ for (i=0; i<akey->key_data_length[1]; i++) {
+ fprintf(arg->ofile, "%02x", akey->key_data_contents[1][i]);
+ }
+ /* Pound out the expansion data. (is null) */
+ for (i=0; i < 8; i++) {
+ fprintf(arg->ofile, "\t%u", 0);
+ }
+ fprintf(arg->ofile, ";\n");
+ /* If we're blabbing, do it */
+ if (arg->verbose)
+ fprintf(stderr, "%s\n", name);
+ krb5_xfree(mod_name);
+
+ return(0);
+}
+
+
+/*
+ * dump_k5beta6_header() - Output the k5beta6 dump header.
+ */
+static krb5_error_code
+dump_k5beta6_header(arglist)
+ struct dump_args *arglist;
+{
+ /* The k5beta6 header consists of the leading string */
+ fprintf(arglist->ofile, k5_dump_header);
+ return(0);
+}
+
+
+/*
+ * dump_k5beta6_iterator() - Output a dump record in k5beta6 format.
+ */
+static krb5_error_code
+dump_k5beta6_iterator(ptr, name, entry)
+ krb5_pointer ptr;
+ char *name;
+ kadm5_principal_ent_rec *entry;
+{
+ krb5_error_code retval = 0;
+ struct dump_args *arg;
+ krb5_tl_data *tlp, *etl;
+ krb5_key_data *kdata;
+ int counter, i, j;
+
+ /* Initialize */
+ arg = (struct dump_args *) ptr;
+
+ /*
+ * We'd like to just blast out the contents as they would appear in
+ * the database so that we can just suck it back in, but it doesn't
+ * lend itself to easy editing.
+ */
+
+ /*
+ * The dump format is as follows:
+ * len strlen(name) n_tl_data n_key_data e_length
+ * name
+ * attributes max_life max_renewable_life expiration
+ * pw_expiration last_success last_failed fail_auth_count
+ * n_tl_data*[type length <contents>]
+ * n_key_data*[ver kvno ver*(type length <contents>)]
+ * <e_data>
+ * Fields which are not encapsulated by angle-brackets are to appear
+ * verbatim. Bracketed fields absence is indicated by a -1 in its
+ * place
+ */
+
+ /*
+ * Make sure that the tagged list is reasonably correct, and find
+ * E_DATA while we're at it.
+ */
+ counter = 0;
+ etl = NULL;
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ if (tlp->tl_data_type == KRB5_TL_KADM5_E_DATA)
+ etl = tlp;
+ counter++;
+ }
+
+ if (counter == entry->n_tl_data) {
+ /* Pound out header */
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
+ KRB5_KDB_V1_BASE_LENGTH + (etl ? etl->tl_data_length : 0),
+ strlen(name),
+ (int) entry->n_tl_data,
+ (int) entry->n_key_data,
+ etl ? etl->tl_data_length : 0,
+ name);
+ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ entry->attributes,
+ entry->max_life,
+ entry->max_renewable_life,
+ entry->princ_expire_time,
+ entry->pw_expiration,
+ entry->last_success,
+ entry->last_failed,
+ entry->fail_auth_count);
+ /* Pound out tagged data. */
+ for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
+ /* skip E_DATA since it is included later */
+ if (tlp->tl_data_type == KRB5_TL_KADM5_E_DATA)
+ continue;
+
+ fprintf(arg->ofile, "%d\t%d\t",
+ (int) tlp->tl_data_type,
+ (int) tlp->tl_data_length);
+ if (tlp->tl_data_length)
+ for (i=0; i<tlp->tl_data_length; i++)
+ fprintf(arg->ofile, "%02x", tlp->tl_data_contents[i]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+ fprintf(arg->ofile, "\t");
+ }
+
+ /* Pound out key data */
+ for (counter=0; counter<entry->n_key_data; counter++) {
+ kdata = &entry->key_data[counter];
+ fprintf(arg->ofile, "%d\t%d\t",
+ (int) kdata->key_data_ver,
+ (int) kdata->key_data_kvno);
+ for (i=0; i<kdata->key_data_ver; i++) {
+ fprintf(arg->ofile, "%d\t%d\t",
+ kdata->key_data_type[i],
+ kdata->key_data_length[i]);
+ if (kdata->key_data_length[i])
+ for (j=0; j<kdata->key_data_length[i]; j++)
+ fprintf(arg->ofile, "%02x",
+ kdata->key_data_contents[i][j]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+ fprintf(arg->ofile, "\t");
+ }
+ }
+
+ /* Pound out extra data */
+ if (etl && etl->tl_data_length)
+ for (i=0; i<etl->tl_data_length; i++)
+ fprintf(arg->ofile, "%02x", etl->tl_data_contents[i]);
+ else
+ fprintf(arg->ofile, "%d", -1);
+
+ /* Print trailer */
+ fprintf(arg->ofile, ";\n");
+
+ if (arg->verbose)
+ fprintf(stderr, "%s\n", name);
+ }
+ else {
+ fprintf(stderr, sdump_tl_inc_err,
+ arg->programname, name, counter, (int) entry->n_tl_data);
+ retval = EINVAL;
+ }
+ return(retval);
+}
+
+
+/*
+ * usage is:
+ * dump_db [-old] [-verbose] [filename|- [principals...]]
+ */
+void dump_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+ struct dump_args arglist;
+ int error;
+ char *programname;
+ char *ofile;
+ krb5_error_code kret;
+ krb5_error_code (*dump_iterator) PROTOTYPE((krb5_pointer,
+ char *,
+ kadm5_principal_ent_rec *));
+ krb5_error_code (*dump_header) PROTOTYPE((struct dump_args *));
+ const char * dump_name;
+ int aindex, num, i;
+ krb5_boolean locked;
+ char **princs;
+ kadm5_principal_ent_rec princ_ent;
+ krb5_principal princ;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ ofile = (char *) NULL;
+ error = 0;
+ dump_iterator = dump_k5beta6_iterator;
+ dump_header = dump_k5beta6_header;
+ dump_name = k5beta6_fmt_name;
+ arglist.verbose = 0;
+
+ /*
+ * Parse the qualifiers.
+ */
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption)) {
+ dump_iterator = dump_k5beta5_iterator;
+ dump_header = dump_k5beta5_header;
+ dump_name = k5beta5_fmt_name;
+ }
+ else if (!strcmp(argv[aindex], verboseoption)) {
+ arglist.verbose++;
+ }
+ else
+ break;
+ }
+
+ if (aindex < argc) {
+ ofile = argv[aindex];
+ aindex++;
+ }
+
+ /* this works because of the way aindex and argc are used below */
+ if (aindex == argc) {
+ argv[aindex] = "*";
+ argc++;
+ }
+
+ locked = 0;
+ if (ofile) {
+ /*
+ * Make sure that we don't open and truncate on the fopen,
+ * since that may hose an on-going kprop process.
+ *
+ * We could also control this by opening for read and
+ * write, doing an flock with LOCK_EX, and then
+ * truncating the file once we have gotten the lock,
+ * but that would involve more OS dependencies than I
+ * want to get into.
+ */
+ unlink(ofile);
+ if (!(f = fopen(ofile, "w"))) {
+ fprintf(stderr, ofopen_error,
+ programname, ofile, error_message(errno));
+ exit_status++;
+ goto cleanup;
+ }
+ if ((kret = krb5_lock_file(context,
+ fileno(f),
+ KRB5_LOCKMODE_EXCLUSIVE))) {
+ fprintf(stderr, oflock_error,
+ programname, ofile, error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+ else
+ locked = 1;
+ } else {
+ f = stdout;
+ }
+
+ arglist.programname = programname;
+ arglist.ofile = f;
+ arglist.context = context;
+
+ if (kret = (*dump_header)(&arglist)) {
+ fprintf(stderr, dumphdr_err,
+ programname, dump_name, error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+
+ while (aindex < argc) {
+ if (kret = kadm5_get_principals(handle, argv[aindex],
+ &princs, &num)) {
+ fprintf(stderr, "%s: error retrieving principals "
+ "matching %s: (%s)\n", programname,
+ argv[aindex], error_message(kret));
+ exit_status++;
+ goto cleanup;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (kret = krb5_parse_name(context, princs[i],
+ &princ)) {
+ com_err(programname, kret,
+ "while parsing principal name");
+ exit_status++;
+ break;
+ }
+ if (kret = kadm5_get_principal(handle, princ,
+ &princ_ent,
+ KADM5_PRINCIPAL_NORMAL_MASK |
+ KADM5_KEY_DATA|KADM5_TL_DATA)){
+ com_err(programname, kret,
+ "while retrieving principal entry");
+ krb5_free_principal(context, princ);
+ exit_status++;
+ break;
+ }
+ if (kret = (*dump_iterator)(&arglist, princs[i], &princ_ent)) {
+ exit_status++;
+ krb5_free_principal(context, princ);
+ kadm5_free_principal_ent(handle, &princ_ent);
+ break;
+ }
+
+ krb5_free_principal(context, princ);
+ kadm5_free_principal_ent(handle, &princ_ent);
+ }
+
+ kadm5_free_name_list(handle, princs, num);
+ aindex++;
+ if (kret)
+ goto cleanup;
+ }
+
+cleanup:
+ if (ofile)
+ fclose(f);
+
+ if (locked)
+ (void) krb5_lock_file(context, fileno(f), KRB5_LOCKMODE_UNLOCK);
+}
+
+
+/*
+ * Read a string of bytes while counting the number of lines passed.
+ */
+static int
+read_string(f, buf, len, lp)
+ FILE *f;
+ char *buf;
+ int len;
+ int *lp;
+{
+ int c;
+ int i, retval;
+
+ retval = 0;
+ for (i=0; i<len; i++) {
+ c = (char) fgetc(f);
+ if (c < 0) {
+ retval = 1;
+ break;
+ }
+ if (c == '\n')
+ (*lp)++;
+ buf[i] = (char) c;
+ }
+ buf[len] = '\0';
+ return(retval);
+}
+
+/*
+ * Read a string of two character representations of bytes.
+ */
+static int
+read_octet_string(f, buf, len)
+ FILE *f;
+ krb5_octet *buf;
+ int len;
+{
+ int c;
+ int i, retval;
+
+ retval = 0;
+ for (i=0; i<len; i++) {
+ if (fscanf(f, "%02x", &c) != 1) {
+ retval = 1;
+ break;
+ }
+ buf[i] = (krb5_octet) c;
+ }
+ return(retval);
+}
+
+/*
+ * Find the end of an old format record.
+ */
+static void
+find_record_end(f, fn, lineno)
+ FILE *f;
+ char *fn;
+ int lineno;
+{
+ int ch;
+
+ if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
+ fprintf(stderr, trash_end_fmt, fn, lineno);
+ while (ch != '\n') {
+ putc(ch, stderr);
+ ch = fgetc(f);
+ }
+ putc(ch, stderr);
+ }
+}
+
+#if 0
+/*
+ * process_k5beta5_record() - Handle a dump record in old format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5beta5_record(fname, context, filep, verbose, linenop)
+ char *fname;
+ krb5_context context;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+{
+ int nmatched;
+ int retval;
+ krb5_db_entry dbent;
+ int name_len, mod_name_len, key_len;
+ int alt_key_len, salt_len, alt_salt_len;
+ char *name;
+ char *mod_name;
+ int tmpint1, tmpint2, tmpint3;
+ int error;
+ const char *try2read;
+ int i;
+ krb5_key_data *pkey, *akey;
+ krb5_timestamp last_pwd_change, mod_date;
+ krb5_principal mod_princ;
+ krb5_error_code kret;
+
+ try2read = (char *) NULL;
+ (*linenop)++;
+ retval = 1;
+ memset((char *)&dbent, 0, sizeof(dbent));
+
+ /* Make sure we've got key_data entries */
+ if (krb5_dbe_create_key_data(context, &dbent) ||
+ krb5_dbe_create_key_data(context, &dbent)) {
+ krb5_db_free_principal(context, &dbent, 1);
+ return(1);
+ }
+ pkey = &dbent.key_data[0];
+ akey = &dbent.key_data[1];
+
+ /*
+ * Match the sizes. 6 tokens to match.
+ */
+ nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
+ &name_len, &mod_name_len, &key_len,
+ &alt_key_len, &salt_len, &alt_salt_len);
+ if (nmatched == 6) {
+ pkey->key_data_length[0] = key_len;
+ akey->key_data_length[0] = alt_key_len;
+ pkey->key_data_length[1] = salt_len;
+ akey->key_data_length[1] = alt_salt_len;
+ name = (char *) NULL;
+ mod_name = (char *) NULL;
+ /*
+ * Get the memory for the variable length fields.
+ */
+ if ((name = (char *) malloc((size_t) (name_len + 1))) &&
+ (mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
+ (!key_len ||
+ (pkey->key_data_contents[0] =
+ (krb5_octet *) malloc((size_t) (key_len + 1)))) &&
+ (!alt_key_len ||
+ (akey->key_data_contents[0] =
+ (krb5_octet *) malloc((size_t) (alt_key_len + 1)))) &&
+ (!salt_len ||
+ (pkey->key_data_contents[1] =
+ (krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
+ (!alt_salt_len ||
+ (akey->key_data_contents[1] =
+ (krb5_octet *) malloc((size_t) (alt_salt_len + 1))))
+ ) {
+ error = 0;
+
+ /* Read the principal name */
+ if (read_string(filep, name, name_len, linenop)) {
+ try2read = read_name_string;
+ error++;
+ }
+ /* Read the key type */
+ if (!error && (fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
+ try2read = read_key_type;
+ error++;
+ }
+ pkey->key_data_type[0] = tmpint1;
+ /* Read the old format key */
+ if (!error && read_octet_string(filep,
+ pkey->key_data_contents[0],
+ pkey->key_data_length[0])) {
+ try2read = read_key_data;
+ error++;
+ }
+ /* convert to a new format key */
+ /* the encrypted version is stored as the unencrypted key length
+ (4 bytes, MSB first) followed by the encrypted key. */
+ if ((pkey->key_data_length[0] > 4)
+ && (pkey->key_data_contents[0][0] == 0)
+ && (pkey->key_data_contents[0][1] == 0)) {
+ /* this really does look like an old key, so drop and swap */
+ /* the *new* length is 2 bytes, LSB first, sigh. */
+ size_t shortlen = pkey->key_data_length[0]-4+2;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *origdata = pkey->key_data_contents[0];
+ shortcopy[0] = origdata[3];
+ shortcopy[1] = origdata[2];
+ memcpy(shortcopy+2,origdata+4,shortlen-2);
+ free(origdata);
+ pkey->key_data_length[0] = shortlen;
+ pkey->key_data_contents[0] = shortcopy;
+ }
+
+ /* Read principal attributes */
+ if (!error && (fscanf(filep,
+ "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t",
+ &tmpint1, &dbent.max_life,
+ &dbent.max_renewable_life,
+ &tmpint2, &dbent.expiration,
+ &dbent.pw_expiration, &last_pwd_change,
+ &dbent.last_success, &dbent.last_failed,
+ &tmpint3) != 10)) {
+ try2read = read_pr_data1;
+ error++;
+ }
+ pkey->key_data_kvno = tmpint1;
+ dbent.fail_auth_count = tmpint3;
+ /* Read modifier name */
+ if (!error && read_string(filep,
+ mod_name,
+ mod_name_len,
+ linenop)) {
+ try2read = read_mod_name;
+ error++;
+ }
+ /* Read second set of attributes */
+ if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
+ &mod_date, &dbent.attributes,
+ &tmpint1) != 3)) {
+ try2read = read_pr_data2;
+ error++;
+ }
+ pkey->key_data_type[1] = tmpint1;
+ /* Read salt data */
+ if (!error && read_octet_string(filep,
+ pkey->key_data_contents[1],
+ pkey->key_data_length[1])) {
+ try2read = read_salt_data;
+ error++;
+ }
+ /* Read alternate key type */
+ if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+ try2read = read_akey_type;
+ error++;
+ }
+ akey->key_data_type[0] = tmpint1;
+ /* Read alternate key */
+ if (!error && read_octet_string(filep,
+ akey->key_data_contents[0],
+ akey->key_data_length[0])) {
+ try2read = read_akey_data;
+ error++;
+ }
+
+ /* convert to a new format key */
+ /* the encrypted version is stored as the unencrypted key length
+ (4 bytes, MSB first) followed by the encrypted key. */
+ if ((akey->key_data_length[0] > 4)
+ && (akey->key_data_contents[0][0] == 0)
+ && (akey->key_data_contents[0][1] == 0)) {
+ /* this really does look like an old key, so drop and swap */
+ /* the *new* length is 2 bytes, LSB first, sigh. */
+ size_t shortlen = akey->key_data_length[0]-4+2;
+ char *shortcopy = (krb5_octet *) malloc(shortlen);
+ char *origdata = akey->key_data_contents[0];
+ shortcopy[0] = origdata[3];
+ shortcopy[1] = origdata[2];
+ memcpy(shortcopy+2,origdata+4,shortlen-2);
+ free(origdata);
+ akey->key_data_length[0] = shortlen;
+ akey->key_data_contents[0] = shortcopy;
+ }
+
+ /* Read alternate salt type */
+ if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
+ try2read = read_asalt_type;
+ error++;
+ }
+ akey->key_data_type[1] = tmpint1;
+ /* Read alternate salt data */
+ if (!error && read_octet_string(filep,
+ akey->key_data_contents[1],
+ akey->key_data_length[1])) {
+ try2read = read_asalt_data;
+ error++;
+ }
+ /* Read expansion data - discard it */
+ if (!error) {
+ for (i=0; i<8; i++) {
+ if (fscanf(filep, "\t%u", &tmpint1) != 1) {
+ try2read = read_exp_data;
+ error++;
+ break;
+ }
+ }
+ if (!error)
+ find_record_end(filep, fname, *linenop);
+ }
+
+ /*
+ * If no error, then we're done reading. Now parse the names
+ * and store the database dbent.
+ */
+ if (!error) {
+ if (!(kret = krb5_parse_name(context,
+ name,
+ &dbent.princ))) {
+ if (!(kret = krb5_parse_name(context,
+ mod_name,
+ &mod_princ))) {
+ if (!(kret =
+ krb5_dbe_update_mod_princ_data(context,
+ &dbent,
+ mod_date,
+ mod_princ)) &&
+ !(kret =
+ krb5_dbe_update_last_pwd_change(context,
+ &dbent,
+ last_pwd_change))) {
+ int one = 1;
+
+ dbent.len = KRB5_KDB_V1_BASE_LENGTH;
+ pkey->key_data_ver = (pkey->key_data_type[1] || pkey->key_data_length[1]) ?
+ 2 : 1;
+ akey->key_data_ver = (akey->key_data_type[1] || akey->key_data_length[1]) ?
+ 2 : 1;
+ if ((pkey->key_data_type[0] ==
+ akey->key_data_type[0]) &&
+ (pkey->key_data_type[1] ==
+ akey->key_data_type[1]))
+ dbent.n_key_data--;
+ else if ((akey->key_data_type[0] == 0)
+ && (akey->key_data_length[0] == 0)
+ && (akey->key_data_type[1] == 0)
+ && (akey->key_data_length[1] == 0))
+ dbent.n_key_data--;
+ if ((kret = krb5_db_put_principal(context,
+ &dbent,
+ &one)) ||
+ (one != 1)) {
+ fprintf(stderr, store_err_fmt,
+ fname, *linenop, name,
+ error_message(kret));
+ error++;
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, add_princ_fmt, name);
+ retval = 0;
+ }
+ dbent.n_key_data = 2;
+ }
+ krb5_free_principal(context, mod_princ);
+ }
+ else {
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, mod_name,
+ error_message(kret));
+ error++;
+ }
+ }
+ else {
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, name, error_message(kret));
+ error++;
+ }
+ }
+ else {
+ fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+ }
+ }
+ else {
+ fprintf(stderr, no_mem_fmt, fname, *linenop);
+ }
+
+ krb5_db_free_principal(context, &dbent, 1);
+ if (mod_name)
+ free(mod_name);
+ if (name)
+ free(name);
+ }
+ else {
+ if (nmatched != EOF)
+ fprintf(stderr, rhead_err_fmt, fname, *linenop);
+ else
+ retval = -1;
+ }
+ return(retval);
+}
+
+
+/*
+ * process_k5_record() - Handle a dump record in new format.
+ *
+ * Returns -1 for end of file, 0 for success and 1 for failure.
+ */
+static int
+process_k5_record(fname, context, filep, verbose, linenop)
+ char *fname;
+ krb5_context context;
+ FILE *filep;
+ int verbose;
+ int *linenop;
+{
+ int retval;
+ krb5_db_entry dbentry;
+ krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ int nread;
+ int error;
+ int i, j, one;
+ char *name;
+ krb5_key_data *kp, *kdatap;
+ krb5_tl_data **tlp, *tl;
+ krb5_octet *op;
+ krb5_error_code kret;
+ const char *try2read;
+
+ try2read = (char *) NULL;
+ memset((char *) &dbentry, 0, sizeof(dbentry));
+ (*linenop)++;
+ retval = 1;
+ name = (char *) NULL;
+ kp = (krb5_key_data *) NULL;
+ op = (krb5_octet *) NULL;
+ error = 0;
+ kret = 0;
+ nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
+ if (nread == 5) {
+ /* Get memory for flattened principal name */
+ if (!(name = (char *) malloc((size_t) t2 + 1)))
+ error++;
+
+ /* Get memory for and form tagged data linked list */
+ tlp = &dbentry.tl_data;
+ for (i=0; i<t3; i++) {
+ if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
+ memset(*tlp, 0, sizeof(krb5_tl_data));
+ tlp = &((*tlp)->tl_data_next);
+ dbentry.n_tl_data++;
+ }
+ else {
+ error++;
+ break;
+ }
+ }
+
+ /* Get memory for key list */
+ if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
+ (t4*sizeof(krb5_key_data)))))
+ error++;
+
+ /* Get memory for extra data */
+ if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
+ error++;
+
+ if (!error) {
+ dbentry.len = t1;
+ dbentry.n_key_data = t4;
+ dbentry.e_length = t5;
+ if (kp) {
+ memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
+ dbentry.key_data = kp;
+ kp = (krb5_key_data *) NULL;
+ }
+ if (op) {
+ memset(op, 0, (size_t) t5);
+ dbentry.e_data = op;
+ op = (krb5_octet *) NULL;
+ }
+
+ /* Read in and parse the principal name */
+ if (!read_string(filep, name, t2, linenop) &&
+ !(kret = krb5_parse_name(context, name, &dbentry.princ))) {
+
+ /* Get the fixed principal attributes */
+ nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
+ &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
+ if (nread == 8) {
+ dbentry.attributes = (krb5_flags) t2;
+ dbentry.max_life = (krb5_deltat) t3;
+ dbentry.max_renewable_life = (krb5_deltat) t4;
+ dbentry.expiration = (krb5_timestamp) t5;
+ dbentry.pw_expiration = (krb5_timestamp) t6;
+ dbentry.last_success = (krb5_timestamp) t7;
+ dbentry.last_failed = (krb5_timestamp) t8;
+ dbentry.fail_auth_count = (krb5_kvno) t9;
+ } else {
+ try2read = read_nint_data;
+ error++;
+ }
+
+ /* Get the tagged data */
+ if (!error && dbentry.n_tl_data) {
+ for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
+ nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ if (nread == 2) {
+ tl->tl_data_type = (krb5_int16) t1;
+ tl->tl_data_length = (krb5_int16) t2;
+ if (tl->tl_data_length) {
+ if (!(tl->tl_data_contents =
+ (krb5_octet *) malloc((size_t) t2+1)) ||
+ read_octet_string(filep,
+ tl->tl_data_contents,
+ t2)) {
+ try2read = read_tcontents;
+ error++;
+ break;
+ }
+ }
+ else {
+ /* Should be a null field */
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_tcontents;
+ break;
+ }
+ }
+ }
+ else {
+ try2read = read_ttypelen;
+ error++;
+ break;
+ }
+ }
+ }
+
+ /* Get the key data */
+ if (!error && dbentry.n_key_data) {
+ for (i=0; !error && (i<dbentry.n_key_data); i++) {
+ kdatap = &dbentry.key_data[i];
+ nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
+ if (nread == 2) {
+ kdatap->key_data_ver = (krb5_int16) t1;
+ kdatap->key_data_kvno = (krb5_int16) t2;
+
+ for (j=0; j<t1; j++) {
+ nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
+ if (nread == 2) {
+ kdatap->key_data_type[j] = t3;
+ kdatap->key_data_length[j] = t4;
+ if (t4) {
+ if (!(kdatap->key_data_contents[j] =
+ (krb5_octet *)
+ malloc((size_t) t4+1)) ||
+ read_octet_string(filep,
+ kdatap->key_data_contents[j],
+ t4)) {
+ try2read = read_kcontents;
+ error++;
+ break;
+ }
+ }
+ else {
+ /* Should be a null field */
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_kcontents;
+ break;
+ }
+ }
+ }
+ else {
+ try2read = read_ktypelen;
+ error++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Get the extra data */
+ if (!error && dbentry.e_length) {
+ if (read_octet_string(filep,
+ dbentry.e_data,
+ (int) dbentry.e_length)) {
+ try2read = read_econtents;
+ error++;
+ }
+ }
+ else {
+ nread = fscanf(filep, "%d", &t9);
+ if ((nread != 1) || (t9 != -1)) {
+ error++;
+ try2read = read_econtents;
+ }
+ }
+
+ /* Finally, find the end of the record. */
+ if (!error)
+ find_record_end(filep, fname, *linenop);
+
+ /*
+ * We have either read in all the data or choked.
+ */
+ if (!error) {
+ one = 1;
+ if ((kret = krb5_db_put_principal(context,
+ &dbentry,
+ &one))) {
+ fprintf(stderr, store_err_fmt,
+ fname, *linenop,
+ name, error_message(kret));
+ }
+ else {
+ if (verbose)
+ fprintf(stderr, add_princ_fmt, name);
+ retval = 0;
+ }
+ }
+ else {
+ fprintf(stderr, read_err_fmt, fname, *linenop, try2read);
+ }
+ }
+ else {
+ if (kret)
+ fprintf(stderr, parse_err_fmt,
+ fname, *linenop, name, error_message(kret));
+ else
+ fprintf(stderr, no_mem_fmt, fname, *linenop);
+ }
+ }
+ else {
+ fprintf(stderr, rhead_err_fmt, fname, *linenop);
+ }
+
+ if (op)
+ free(op);
+ if (kp)
+ free(kp);
+ if (name)
+ free(name);
+ krb5_db_free_principal(context, &dbentry, 1);
+ }
+ else {
+ if (nread == EOF)
+ retval = -1;
+ }
+ return(retval);
+}
+
+
+/*
+ * restore_k5beta5_compat() - Restore the database from a K5 Beta
+ * format dump file.
+ */
+static int
+restore_k5beta5_compat(programname, context, dumpfile, f, verbose)
+ const char *programname;
+ krb5_context context;
+ const char *dumpfile;
+ FILE *f;
+ int verbose;
+{
+ int error;
+ int lineno;
+ char buf[2*sizeof(k5beta5_dump_header)];
+
+ /*
+ * Get/check the header.
+ */
+ error = 0;
+ fgets(buf, sizeof(buf), f);
+ if (!strcmp(buf, k5beta5_dump_header)) {
+ lineno = 1;
+ /*
+ * Process the records.
+ */
+ while (!(error = process_k5beta5_record(dumpfile,
+ context,
+ f,
+ verbose,
+ &lineno)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ /*
+ * Close the input file.
+ */
+ if (f != stdin)
+ fclose(f);
+ }
+ else {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ error++;
+ }
+ return(error);
+}
+
+
+/*
+ * restore_dump() - Restore the database from a standard dump file.
+ */
+static int
+restore_dump(programname, context, dumpfile, f, verbose)
+ const char *programname;
+ krb5_context context;
+ const char *dumpfile;
+ FILE *f;
+ int verbose;
+{
+ int error;
+ int lineno;
+ char buf[2*sizeof(k5_dump_header)];
+
+ /*
+ * Get/check the header.
+ */
+ error = 0;
+ fgets(buf, sizeof(buf), f);
+ if (!strcmp(buf, k5_dump_header)) {
+ lineno = 1;
+ /*
+ * Process the records.
+ */
+ while (!(error = process_k5_record(dumpfile,
+ context,
+ f,
+ verbose,
+ &lineno)))
+ ;
+ if (error != -1)
+ fprintf(stderr, err_line_fmt, programname, lineno, dumpfile);
+ else
+ error = 0;
+
+ /*
+ * Close the input file.
+ */
+ if (f != stdin)
+ fclose(f);
+ }
+ else {
+ fprintf(stderr, head_bad_fmt, programname, dumpfile);
+ error++;
+ }
+ return(error);
+}
+
+/*
+ * Usage is
+ * load_db [-old] [-verbose] [-update] filename dbname
+ */
+void
+load_db(argc, argv)
+ int argc;
+ char **argv;
+{
+ krb5_error_code kret;
+ krb5_context context;
+ FILE *f;
+ extern char *optarg;
+ extern int optind;
+ const char *programname;
+ const char *dumpfile;
+ char *dbname;
+ char *dbname_tmp;
+ int (*restore_function) PROTOTYPE((const char *,
+ krb5_context,
+ const char *,
+ FILE *,
+ int));
+ const char * restore_name;
+ int update, verbose;
+ int aindex;
+
+ /*
+ * Parse the arguments.
+ */
+ programname = argv[0];
+ if (strrchr(programname, (int) '/'))
+ programname = strrchr(argv[0], (int) '/') + 1;
+ dumpfile = (char *) NULL;
+ dbname = (char *) NULL;
+ restore_function = restore_dump;
+ restore_name = standard_fmt_name;
+ update = 0;
+ verbose = 0;
+ exit_status = 0;
+ dbname_tmp = (char *) NULL;
+ for (aindex = 1; aindex < argc; aindex++) {
+ if (!strcmp(argv[aindex], oldoption)) {
+ restore_function = restore_k5beta5_compat;
+ restore_name = k5beta5_fmt_name;
+ }
+ else if (!strcmp(argv[aindex], verboseoption)) {
+ verbose = 1;
+ }
+ else if (!strcmp(argv[aindex], updateoption)) {
+ update = 1;
+ }
+ else
+ break;
+ }
+ if ((argc - aindex) != 2) {
+ fprintf(stderr, lusage_err_fmt, argv[0], argv[0],
+ oldoption, verboseoption, updateoption);
+ exit_status++;
+ return;
+ }
+
+ dumpfile = argv[aindex];
+ dbname = argv[aindex+1];
+ if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
+ strlen(dump_tmptrail)+1))) {
+ fprintf(stderr, no_name_mem_fmt, argv[0]);
+ exit_status++;
+ return;
+ }
+ strcpy(dbname_tmp, dbname);
+ strcat(dbname_tmp, dump_tmptrail);
+
+ /*
+ * Initialize the Kerberos context and error tables.
+ */
+ if ((kret = krb5_init_context(&context))) {
+ fprintf(stderr, ctx_err_fmt, programname);
+ free(dbname_tmp);
+ exit_status++;
+ return;
+ }
+ krb5_init_ets(context);
+
+ /*
+ * Open the dumpfile
+ */
+ if (dumpfile) {
+ if ((f = fopen(dumpfile, "r+"))) {
+ kret = krb5_lock_file(context, fileno(f), KRB5_LOCKMODE_SHARED);
+ }
+ }
+ else {
+ f = stdin;
+ }
+ if (f && !kret) {
+ /*
+ * Create the new database if not an update restoration.
+ */
+ if (update || !(kret = krb5_db_create(context, dbname_tmp))) {
+ /*
+ * Point ourselves at it.
+ */
+ if (!(kret = krb5_db_set_name(context,
+ (update) ? dbname : dbname_tmp))) {
+ /*
+ * Initialize the database.
+ */
+ if (!(kret = krb5_db_init(context))) {
+ if ((*restore_function)(programname,
+ context,
+ (dumpfile) ? dumpfile : stdin_name,
+ f,
+ verbose)) {
+ fprintf(stderr, restfail_fmt,
+ programname, restore_name);
+ exit_status++;
+ }
+ if ((kret = krb5_db_fini(context))) {
+ fprintf(stderr, close_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ fprintf(stderr, dbinit_err_fmt,
+ programname, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ fprintf(stderr, dbname_err_fmt,
+ programname,
+ (update) ? dbname : dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ /*
+ * If there was an error and this is not an update, then
+ * destroy the database.
+ */
+ if (!update) {
+ if (exit_status) {
+ if ((kret = kdb5_db_destroy(context, dbname))) {
+ fprintf(stderr, dbdelerr_fmt,
+ programname, dbname_tmp, error_message(kret));
+ exit_status++;
+ }
+ }
+ else {
+ if ((kret = krb5_db_rename(context,
+ dbname_tmp,
+ dbname))) {
+ fprintf(stderr, dbrenerr_fmt,
+ programname, dbname_tmp, dbname,
+ error_message(kret));
+ exit_status++;
+ }
+ }
+ }
+ }
+ else {
+ fprintf(stderr, dbcreaterr_fmt,
+ programname, dbname, error_message(kret));
+ exit_status++;
+ }
+ if (dumpfile) {
+ (void) krb5_lock_file(context, fileno(f), KRB5_LOCKMODE_UNLOCK);
+ fclose(f);
+ }
+ }
+ else {
+ fprintf(stderr, dfile_err_fmt, dumpfile, error_message(errno));
+ exit_status++;
+ }
+ free(dbname_tmp);
+ krb5_free_context(context);
+}
+#endif
diff --git a/src/kadmin/cli/getdate.y b/src/kadmin/cli/getdate.y
new file mode 100644
index 000000000..975a819f5
--- /dev/null
+++ b/src/kadmin/cli/getdate.y
@@ -0,0 +1,1009 @@
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+** send any email to Rich.
+**
+** This grammar has nine shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+#include <string.h>
+
+/* Since the code of getdate.y is not included in the Emacs executable
+ itself, there is no need to #define static in this file. Even if
+ the code were included in the Emacs executable, it probably
+ wouldn't do any harm to #undef it here; this will only cause
+ problems if we try to write to a static variable, which I don't
+ think this code needs to do. */
+#ifdef emacs
+#undef static
+#endif
+
+/* The following block of alloca-related preprocessor directives is here
+ solely to allow compilation by non GNU-C compilers of the C parser
+ produced from this file by old versions of bison. Newer versions of
+ bison include a block similar to this one in bison.simple. */
+
+#ifdef __GNUC__
+#undef alloca
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX /* for Bison */
+ #pragma alloca
+#else
+void *alloca ();
+#endif
+#endif
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+
+#include <types.h>
+#include <time.h>
+
+#else
+
+#include <sys/types.h>
+
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+#endif
+
+#ifdef timezone
+#undef timezone /* needed for sgi */
+#endif
+
+#if defined(HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#else
+/*
+** We use the obsolete `struct timeb' as part of our interface!
+** Since the system doesn't have it, we define it here;
+** our callers must do likewise.
+*/
+struct timeb {
+ time_t time; /* Seconds since the epoch */
+ unsigned short millitm; /* Field not used */
+ short timezone; /* Minutes west of GMT */
+ short dstflag; /* Field not used */
+};
+#endif /* defined(HAVE_SYS_TIMEB_H) */
+
+#endif /* defined(vms) */
+
+#if defined (STDC_HEADERS) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+extern struct tm *gmtime();
+extern struct tm *localtime();
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yylex ();
+static int yyerror ();
+
+#if !defined(lint) && !defined(SABER)
+static char RCS[] =
+ "$Header$";
+#endif /* !defined(lint) && !defined(SABER) */
+
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+ { "kst", tZONE, -HOUR(9) }, /* Korean Standard */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "kdt", tZONE, -HOUR(10) }, /* Korean Daylight */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(s)
+ char *s;
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(Hours, Minutes, Seconds, Meridian)
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+
+static time_t
+Convert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
+ time_t Month;
+ time_t Day;
+ time_t Year;
+ time_t Hours;
+ time_t Minutes;
+ time_t Seconds;
+ MERIDIAN Meridian;
+ DSTMODE DSTmode;
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ if (Year < EPOCH || Year > 1999
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(Start, Future)
+ time_t Start;
+ time_t Future;
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(Start, DayOrdinal, DayNumber)
+ time_t Start;
+ time_t DayOrdinal;
+ time_t DayNumber;
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(Start, RelMonth)
+ time_t Start;
+ time_t RelMonth;
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(buff)
+ char *buff;
+{
+ register char *p;
+ register char *q;
+ register const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex()
+{
+ register char c;
+ register char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds. */
+static time_t
+difftm(a, b)
+ struct tm *a, *b;
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ return
+ (
+ (
+ (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ /* + difference in years * 365 */
+ + (time_t)(ay-by) * 365
+ )*24 + (a->tm_hour - b->tm_hour)
+ )*60 + (a->tm_min - b->tm_min)
+ )*60 + (a->tm_sec - b->tm_sec);
+}
+
+time_t
+get_date(p, now)
+ char *p;
+ struct timeb *now;
+{
+ struct tm *tm, gmt;
+ struct timeb ftz;
+ time_t Start;
+ time_t tod;
+
+ yyInput = p;
+ if (now == NULL) {
+ now = &ftz;
+ (void)time(&ftz.time);
+
+ if (! (tm = gmtime (&ftz.time)))
+ return -1;
+ gmt = *tm; /* Make a copy, in case localtime modifies *tm. */
+ ftz.timezone = difftm (&gmt, localtime (&ftz.time)) / 60;
+ }
+
+ tm = localtime(&now->time);
+ yyYear = tm->tm_year;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = now->timezone;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = now->time;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+main(ac, av)
+ int ac;
+ char *av[];
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff, (struct timeb *)NULL);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/src/kadmin/cli/kadmin.1 b/src/kadmin/cli/kadmin.1
new file mode 100644
index 000000000..a8db58334
--- /dev/null
+++ b/src/kadmin/cli/kadmin.1
@@ -0,0 +1,473 @@
+KADMIN(8) USER_COMMANDS KADMIN(8)
+
+NAME
+ kadmin - a command line interface to the Kerberos KADM5
+ administration system
+
+SYNOPSIS
+ kadmin [-r realm] [-p principal] [-q query] [clnt|local args]
+ clnt args: [-p principal] [[-c ccache]|[-k [-t keytab]]]
+ [-w] [-s admin_server[:port]]
+ local args: [-d dbname] [-e \"enc:salt ...\"] [-m]
+
+DESCRIPTION
+ kadmin is a command-line interface to the Kerberos KADM5
+ administration system. It provides for the maintainance of
+ Kerberos principals, KADM5 policies, and service key tables
+ (keytabs). It exists as both a remote client, using Kerberos
+ authentication and an encrypted RPC to operate securely from
+ anywhere on the network, and as a local client intended to run
+ directly on the KDC without Kerberos authentication. The
+ local version provides all of the functionality of the now
+ obsolete kdb5_edit(8) except for database dump and load, which
+ is now provided by the kdb5_util(8) utility.
+
+COMMAND LINE ARGUMENTS
+ If -r is specified, then kadmin will use the specified realm
+ as the default database realm rather than the default realm
+ for the local machine.
+
+ The -q option allows the passing of a request directly to
+ kadmin, which will then exit. This can be useful for writing
+ scripts.
+
+ The remote version authenticates to the KADM5 server using the
+ service kadmin/admin, and therefore needs a client Kerberos
+ principal name as which to authenticate. The -p, -c, and -k
+ are designed to work together to specify which principal as
+ which to authenticate and where the service ticket or
+ password/key for that principal should be obtained. If given
+ the -p option, kadmin will use the specified principal to
+ authenticate. Otherwise, if given -c option then the primary
+ principal name of the ccache is used. Otherwise, if given the
+ -k option, the principal name host/<hostname> is used.
+ Otherwise, kadmin will append "/admin" to the primary
+ principal name of the default ccache, the value of the USER
+ environment variable, or the username as obtained with
+ getpwuid, in order of preference.
+
+ Once kadmin knows the principal name as which to authenticate,
+ it needs to acquire a Kerberos service ticket for the KADM5
+ server. If the -c ccache argument is specified, the ccache
+ should contain a service ticket for the kadmin/admin service;
+ it can be acquired with the kinit(1) program. Otherwise,
+ kadmin requests a new service ticket from the KDC and stores
+ it in its own temporary ccache. If the -k keytab argument is
+ specified, the keytab is used to decrypt the KDC response;
+ otherwise, a password is required. By default, the user is
+ prompted for the password on the TTY. However, if given the
+ -w option, kadmin will use the password provided on the
+ command line instead of prompting for one on the TTY.
+ WARNING! Placing the password for a Kerberos principal with
+ administration access into a shell script is EXTREMELY
+ DANGEROUS and should only be done if you are highly sure that
+ the script will not fall into the wrong hands.
+
+ If given the -d argument, kadmin will use the specified
+ database name instead of the default defined in kdc.conf.
+ Note that specifying a different KDC database name also
+ specifies a different name for the KADM5 policy database and
+ lock file.
+
+ If given the -e argument, kadmin will use the specified list
+ of encryption and salt type tuples instead of the values
+ specified in kdc.conf. This is useful, for example, if you
+ want to create a single principal with a particular key/salt
+ type without affecting any other principals.
+
+ If given the -m argument, kadmin will prompt for the Kerberos
+ master password on the command line instead of attempting to
+ use the stash file.
+
+DATE FORMAT
+ Various commands in kadmin can take a variety of
+ date formats, specifying durations or absolute times.
+ Examples of valid formats are:
+
+ 1 month ago
+ 2 hours ago
+ 400000 seconds ago
+ last year
+ last Monday
+ yesterday
+ a fortnight ago
+ 3/31/92 10:00:07 PST
+ January 23, 1987 10:05pm
+ 22:00 GMT
+
+ Dates which do not have the "ago" specifier default to being
+ absolute dates, unless they appear in a field where a duration
+ is expected. In that case the time specifier will be
+ interpreted as relative. Specifying "ago" on a duration may
+ result in unexpected behaviour.
+
+COMMAND DESCRIPTIONS
+
+add_principal [options] _newprinc_
+ creates the principal _newprinc_, prompting twice for a
+ password. This command requires the "add" privilege. This
+ command has the aliases "addprinc", "ank".
+
+ OPTIONS
+ -salt _salttype_
+ uses the specified salt instead of the default V5 salt
+ for generating the key. Valid values for _salttype_
+ are:
+ full_name (aliases "v5_salt", "normal")
+ name_only
+ realm_only
+ no_salt (alias "v4_salt")
+
+ -expire _expdate_
+ expiration date of the principal
+
+ -pwexpire _pwexpdate_
+ password expiration date
+
+ -maxlife _maxlife_
+ maximum ticket life of the principal
+
+ -kvno _kvno_
+ explicity set the key version number. This is not
+ recommended.
+
+ -policy _policy_
+ policy used by this principal. If no policy is
+ supplied, the principal will default to having no
+ policy, and a warning message will be printed.
+
+ {-|+}allow_tgs_req
+ "-allow_tgs_req" specifies that a TGS request for a
+ ticket for a service ticket for this principal is not
+ permitted. This option is useless for most things.
+ "+allow_tgs_req" clears this flag. The default is
+ "+allow_tgs_req". In effect, "-allow_tgs_req" sets
+ the KRB5_KDB_DISALLOW_TGT_BASED flag on the principal
+ in the database.
+
+ {-|+}allow_tix
+ "-allow_tix" forbids the issuance of any tickets for
+ this principal. "+allow_tix" clears this flag. The
+ default is "+allow_tix". In effect, "-allow_tix" sets
+ the KRB5_KDB_DISALLOW_ALL_TIX flag on the principal in
+ the database.
+
+ {-|+}needchange
+ "+needchange" sets a flag in attributes field to force
+ a password change; "-needchange" clears it. The
+ default is "-needchange". In effect, "+needchange"
+ sets the KRB5_KDB_REQUIRES_PWCHANGE flag on the
+ principal in the database.
+
+ {-|+}password_changing_service
+ "+password_changing_service" sets a flag in the
+ attributes field marking this as a password change
+ service principal (useless for most things).
+ "-password_changing_service" clears the flag. This
+ flag intentionally has a long name. The default is
+ "-password_changing_service". In effect,
+ "+password_changing_service" sets the
+ KRB5_KDB_PWCHANGE_SERVICE flag on the principal in the
+ database.
+
+ -randpass
+ sets the key of the principal to a random value
+
+ -pw _password_
+ sets the key of the principal to the specified string
+ and does not prompt for a password. This is not
+ recommended.
+
+ EXAMPLE
+ kadmin: addprinc tlyu/deity
+ WARNING: no policy specified for "tlyu/deity@ATHENA.MIT.EDU";
+ defaulting to no policy.
+ Enter password for principal tlyu/deity@ATHENA.MIT.EDU:
+ Re-enter password for principal tlyu/deity@ATHENA.MIT.EDU:
+ Principal "tlyu/deity@ATHENA.MIT.EDU" created.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_ADD (requires "add" privilege)
+ KADM5_BAD_MASK (shouldn't happen)
+ KADM5_DUP (principal exists already)
+ KADM5_UNK_POLICY (policy does not exist)
+ KADM5_PASS_Q_* (password quality violations)
+
+delete_principal [-force] _principal_
+ deletes the specified principal from the database. This
+ command prompts for deletion, unless the "-force" option is
+ given. This command requires the "delete" privilege. Aliased
+ to "delprinc".
+
+ EXAMPLE
+ kadmin: delprinc mwm_user
+ Are you sure you want to delete the principal
+ "mwm_user@ATHENA.MIT.EDU"? (yes/no): yes
+ Principal "mwm_user@ATHENA.MIT.EDU" deleted.
+ Make sure that you have removed this principal from
+ all ACLs before reusing.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_DELETE (reequires "delete" privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+
+modify_principal [options] _principal_
+ modifies the specified principal, changing the fields as
+ specified. The options are as above for "add_principal",
+ except that password changing is forbidden by this command.
+ In addition, the option "-clearpolicy" will remove clear the
+ current policy of a principal. This command requires the
+ "modify" privilege. Aliased to "modprinc".
+
+ ERRORS
+ KADM5_AUTH_MODIFY (requires "modify" privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+ KADM5_UNK_POLICY (policy does not exist)
+ KADM5_BAD_MASK (shouldn't happen)
+
+rename_principal [-force] _old_ _new_
+ rename the principal _old_ to _new_. Prompts for
+ confirmation, unless the "-force" option is given. Requires
+ both the "add" and "delete" privileges. Aliased to
+ "renprinc".
+
+ EXAMPLE
+ kadmin: renprinc tlyutest test0
+ Are you sure you want to rename the principal
+ "tlyutest@ATHENA.MIT.EDU" to
+ "test0@ATHENA.MIT.EDU"? (yes/no): yes
+ Principal "tlyutest@ATHENA.MIT.EDU" renamed to
+ "test0@ATHENA.MIT.EDU".
+ Make sure that you have removed "tlyutest@ATHENA.MIT.EDU" from
+ all ACLs before reusing.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_ADD (requires "add" privilege)
+ KADM5_AUTH_DELETE (requires "delete" privilege)
+ KADM5_UNK_PRINC (source principal does not exist)
+ KADM5_DUP (target principal already exists)
+
+change_password [options] _principal_
+ changes the password of _principal_. Prompts for a new
+ password if neither -randpass or -pw is specified. Requires
+ the "modify" privilege, or that the principal that is running
+ the program to be the same as the one changed. Aliased to
+ "cpw".
+
+ OPTIONS
+ -salt _salttype_
+ uses the specified salt instead of the default V5 salt
+ for generating the key. Options are the same as for
+ add_principal.
+
+ -randpass
+ sets the key of the principal to a random value
+
+ -pw _password_
+ set the password to the specified string. Not
+ recommended.
+
+ EXAMPLE
+ kadmin: cpw systest
+ Enter password for principal systest@ATHENA.MIT.EDU:
+ Re-enter password for principal systest@ATHENA.MIT.EDU:
+ Password for systest@ATHENA.MIT.EDU changed.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_MODIFY (requires the modify privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+ KADM5_PASS_Q_* (password policy violation errors)
+ KADM5_PADD_REUSE (password is in principal's password istory)
+ KADM5_PASS_TOOSOON (current password minimum life not xpired)
+
+get_principal [-terse] _principal_
+ gets the attributes of _principal_. Requires the "get"
+ privilege, or that the principal that is running the the
+ program to be the same as the one being listed. With the
+ "-terse" option, outputs fields as a quoted tab-separated
+ strings. Alias "getprinc".
+
+ EXAMPLES
+ kadmin: getprinc tlyu/deity
+ Principal: tlyu/deity@ATHENA.MIT.EDU
+ Key version: 3
+ Maximum life: 1 day 00:00:00
+ Maximum renewable life: 7 days 00:00:00
+ Master key version: 1
+ Expires: Mon Jan 18 22:14:07 EDT 2038
+ Password expires: Mon Sep 19 14:40:00 EDT 1994
+ Password last changed: Mon Jan 31 02:06:40 EDT 1994
+ Last modified: by tlyu/admin@ATHENA.MIT.EDU
+ on Wed Jul 13 18:27:08 EDT 1994
+ Attributes: DISALLOW_FORWARDABLE, DISALLOW_PROXIABLE,
+ REQUIRES_HW_AUTH
+ Salt type: DEFAULT
+ kadmin: getprinc systest
+ systest@ATHENA.MIT.EDU 3 86400 604800 1
+ 785926535 753241234 785900000
+ tlyu/admin@ATHENA.MIT.EDU 786100034 0
+ 0
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_GET (requires the get privilege)
+ KADM5_UNK_PRINC (principal does not exist)
+
+get_principals [expression]
+ Retrieves all or some principal names. _expression_ is a
+ shell-style glob expression that can contain the wild-card
+ characters ?, *, and []'s. All principal names matching the
+ expression are printed. If no expression is provided, the
+ expression "*" is assumed. If the expression does not contain
+ an "@" character, an "@" character followed by the local realm
+ is appended to the expression. Requires the "list" priviledge.
+ Alias "getprincs".
+
+ EXAMPLES
+ kadmin: getprincs test*
+ test3@SECURE-TEST.OV.COM
+ test2@SECURE-TEST.OV.COM
+ test1@SECURE-TEST.OV.COM
+ testuser@SECURE-TEST.OV.COM
+ kadmin:
+
+add_policy [options] _policy_
+ adds the named policy to the policy database. Requires the
+ "add" privilege. Aliased to "addpol".
+
+ OPTIONS
+ -maxlife _time_
+ sets the maximum lifetime of a password
+
+ -minlife _time_
+ sets the minimum lifetime of a password
+
+ -minlength _length_
+ sets the minimum length of a password
+
+ -minclasses _number_
+ sets the minimum number of character classes allowed
+ in a password
+
+ -history _number_
+ sets the number of past keys kept for a principal
+
+ ERRORS
+ KADM5_AUTH_ADD (requires the add privilege)
+ KADM5_DUP (policy already exists)
+
+delete_policy _policy_
+ deletes the named policy. Prompts for confirmation before
+ deletion. The command will fail if the policy is in use by
+ any principals. Requires the "delete" privilege. Alias
+ "delpol".
+
+ EXAMPLE
+ kadmin: del_policy guests
+ Are you sure you want to delete the policy "guests"?
+ (yes/no): yes
+ Policy "guests" deleted.
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_DELETE (requires the delete privilege)
+ KADM5_UNK_POLICY (policy does not exist)
+ KADM5_POLICY_REF (reference count on policy is not zero)
+
+modify_policy [options] _policy_
+ modifies the named policy. Options are as above for
+ "add_policy". Requires the "modify" privilege". Alias
+ "modpol".
+
+ ERRORS
+ KADM5_AUTH_MODIFY (requires the modify privilege)
+ KADM5_UNK_POLICY (policy does not exist)
+
+get_policy [-terse] _policy_
+ displays the values of the named policy. Requires the "get"
+ privilege. With the "-terse" flag, outputs the fields as
+ quoted strings separated by tabs. Alias "getpol".
+
+ EXAMPLES
+ kadmin: get_policy admin
+ Policy: admin
+ Maximum password life: 180 days 00:00:00
+ Minimum password life: 00:00:00
+ Minimum password length: 6
+ Minimum number of password character classes: 2
+ Number of old keys kept: 5
+ Reference count: 17
+ kadmin: get_policy -terse admin
+ admin 15552000 0 6 2 5 17
+ kadmin:
+
+ ERRORS
+ KADM5_AUTH_GET (requires the get privilege)
+ KADM5_UNK_POLICY (policy does not exist)
+
+get_policies [expression]
+ Retrieves all or some policy names. _expression_ is a
+ shell-style glob expression that can contain the wild-card
+ characters ?, *, and []'s. All policy names matching the
+ expression are printed. If no expression is provided, the
+ expression "*" is assumed. Requires the "list" priviledge.
+ Alias "getpols".
+
+ EXAMPLES
+ kadmin: getpols
+ test-pol
+ dict-only
+ once-a-min
+ test-pol-nopw
+ kadmin: getpols t*
+ test-pol
+ test-pol-nopw
+ kadmin:
+
+ktadd [-k keytab] [-q] [principal | -glob princ-exp] [...]
+ Adds principal or all principals matching princ-exp to a
+ keytab. princ-exp follows the same rules described for the
+ get_principals command. An entry for each of the principal's
+ unique encryption types is added, ignoring multiple keys with
+ the same encryption type but different salt types. If the -k
+ argument is not specified, the default keytab /etc/v5srvtab is
+ used. If the -q option is specified, less verbose status
+ information is displayed.
+
+ The -glob option requires the "list" privilege.
+
+ EXAMPLES
+ kadmin% ktadd -k /krb5/kadmind.keytab kadmin/admin kadmin/changepw
+ kadmin: Entry for principal kadmin/admin@ATHENA.MIT.EDU with
+ kvno 3, encryption type DES-CBC-CRC added to keytab
+ WRFILE:/krb5/kadmind.keytab.
+ kadmin: Entry for principal kadmin/changepw@ATHENA.MIT.EDU
+ with kvno 3, encryption type DES-CBC-CRC added to keytab
+ WRFILE:/krb5/kadmind.keytab.
+ kadmin:
+
+ktremove [-k keytab] [-q] principal [kvno|"all"|"old"]
+ Removes entries for the specified principal from a keytab. If
+ the string "all" is specified, all entries for that principal
+ are removed; if the string "old" is specified, all entries for
+ that principal except those with the highest kvno are removed.
+ Otherwise, the value specified is parsed as an integer, and
+ all entries whose kvno match that integer are removed. If the
+ -k argument is not specifeid, the default keytab /etc/v5srvtab
+ is used. If the -q is specified, less verbose status
+ information is displayed.
+
+ EXAMPLES
+ kadmin: ktremove -k /krb5/kadmind.keytab kadmin/admin
+ kadmin: Entry for principal kadmin/admin with kvno 3 removed
+ from keytab WRFILE:/krb5/kadmind.keytab.
+ kadmin:
+
+SEE ALSO
+ kerberos(1), kdb5_util(8)
+
+
diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c
new file mode 100644
index 000000000..e19383dd9
--- /dev/null
+++ b/src/kadmin/cli/kadmin.c
@@ -0,0 +1,1322 @@
+/*
+ * Copyright 1994 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.
+ *
+ * kadmin.c: base functions for a kadmin command line interface using
+ * the OVSecure library
+ */
+
+#include <krb5.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <math.h>
+#include <unistd.h>
+#include <pwd.h>
+/* #include <sys/timeb.h> */
+#include <time.h>
+
+/* special struct to convert flag names for principals
+ to actual krb5_flags for a principal */
+struct pflag {
+ char *flagname; /* name of flag as typed to CLI */
+ int flaglen; /* length of string (not counting -,+) */
+ krb5_flags theflag; /* actual principal flag to set/clear */
+ int set; /* 0 means clear, 1 means set (on '-') */
+};
+
+static struct pflag flags[] = {
+{"allow_postdated", 15, KRB5_KDB_DISALLOW_POSTDATED, 1},
+{"allow_forwardable", 17, KRB5_KDB_DISALLOW_FORWARDABLE, 1},
+{"allow_tgs_req", 13, KRB5_KDB_DISALLOW_TGT_BASED, 1},
+{"allow_renewable", 15, KRB5_KDB_DISALLOW_RENEWABLE, 1},
+{"allow_proxiable", 15, KRB5_KDB_DISALLOW_PROXIABLE, 1},
+{"allow_dup_skey", 14, KRB5_KDB_DISALLOW_DUP_SKEY, 1},
+{"allow_tix", 9, KRB5_KDB_DISALLOW_ALL_TIX, 1},
+{"requires_preauth", 16, KRB5_KDB_REQUIRES_PRE_AUTH, 0},
+{"requires_hwauth", 15, KRB5_KDB_REQUIRES_HW_AUTH, 0},
+{"needchange", 10, KRB5_KDB_REQUIRES_PWCHANGE, 0},
+{"allow_svr", 9, KRB5_KDB_DISALLOW_SVR, 1},
+{"password_changing_service", 25, KRB5_KDB_PWCHANGE_SERVICE, 0 }
+};
+
+static char *prflags[] = {
+ "DISALLOW_POSTDATED", /* 0x00000001 */
+ "DISALLOW_FORWARDABLE", /* 0x00000002 */
+ "DISALLOW_TGT_BASED", /* 0x00000004 */
+ "DISALLOW_RENEWABLE", /* 0x00000008 */
+ "DISALLOW_PROXIABLE", /* 0x00000010 */
+ "DISALLOW_DUP_SKEY", /* 0x00000020 */
+ "DISALLOW_ALL_TIX", /* 0x00000040 */
+ "REQUIRES_PRE_AUTH", /* 0x00000080 */
+ "REQUIRES_HW_AUTH", /* 0x00000100 */
+ "REQUIRES_PWCHANGE", /* 0x00000200 */
+ "UNKNOWN_0x00000400", /* 0x00000400 */
+ "UNKNOWN_0x00000800", /* 0x00000800 */
+ "DISALLOW_SVR", /* 0x00001000 */
+ "PWCHANGE_SERVICE" /* 0x00002000 */
+};
+
+char *getenv();
+struct passwd *getpwuid();
+int exit_status = 0;
+char *def_realm = NULL;
+char *whoami = NULL;
+time_t get_date();
+
+void *handle = NULL;
+krb5_context context;
+char *ccache_name = NULL;
+
+void usage()
+{
+ fprintf(stderr,
+ "Usage: %s [-r realm] [-p principal] [-q query] [clnt|local args]\n"
+ "\tclnt args: [-s admin_server[:port]] [[-c ccache]|[-k [-t keytab]]]\n"
+ "\tlocal args: [-d dbname] [-e \"enc:salt ...\"] [-m]\n", whoami);
+ exit(1);
+}
+
+char *strdur(duration)
+ time_t duration;
+{
+ static char out[50];
+ int days, hours, minutes, seconds;
+
+ days = duration / (24 * 3600);
+ duration %= 24 * 3600;
+ hours = duration / 3600;
+ duration %= 3600;
+ minutes = duration / 60;
+ duration %= 60;
+ seconds = duration;
+ sprintf(out, "%d %s %02d:%02d:%02d", days, days == 1 ? "day" : "days",
+ hours, minutes, seconds);
+ return out;
+}
+
+char *strdate(when)
+ krb5_timestamp when;
+{
+ struct tm *tm;
+ static char out[30];
+
+ time_t lcltim = when;
+ tm = localtime(&lcltim);
+ strftime(out, 30, "%a %b %d %H:%M:%S %Z %Y", tm);
+ return out;
+}
+
+/* this is a wrapper to go around krb5_parse_principal so we can set
+ the default realm up properly */
+krb5_error_code kadmin_parse_name(name, principal)
+ char *name;
+ krb5_principal *principal;
+{
+ char *cp, *fullname;
+ krb5_error_code retval;
+
+ /* assumes def_realm is initialized! */
+ fullname = (char *)malloc(strlen(name) + 1 + strlen(def_realm) + 1);
+ if (fullname == NULL)
+ return ENOMEM;
+ strcpy(fullname, name);
+ cp = strchr(fullname, '@');
+ while (cp) {
+ if (cp - fullname && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '@');
+ }
+ if (cp == NULL) {
+ strcat(fullname, "@");
+ strcat(fullname, def_realm);
+ }
+ retval = krb5_parse_name(context, fullname, principal);
+ free(fullname);
+ return retval;
+}
+
+char *kadmin_startup(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern krb5_kt_ops krb5_ktf_writable_ops;
+ extern char *optarg;
+ char *princstr = NULL, *keytab_name = NULL, *query = NULL;
+ char *password = NULL;
+ char *luser, *canon, *cp;
+ int optchar, freeprinc = 0, use_keytab = 0;
+ struct passwd *pw;
+ kadm5_ret_t retval;
+ krb5_ccache cc;
+ krb5_principal princ;
+ kadm5_config_params params;
+
+ memset((char *) &params, 0, sizeof(params));
+
+ if (retval = krb5_init_context(&context)) {
+ com_err(whoami, retval, "while initializing krb5 library");
+ exit(1);
+ }
+ krb5_init_ets(context);
+
+ while ((optchar = getopt(argc, argv, "r:p:kq:w:d:s:m:c:t:e:")) != EOF) {
+ switch (optchar) {
+ case 'r':
+ def_realm = optarg;
+ break;
+ case 'p':
+ princstr = optarg;
+ break;
+ case 'c':
+ ccache_name = optarg;
+ break;
+ case 'k':
+ use_keytab++;
+ break;
+ case 't':
+ keytab_name = optarg;
+ break;
+ case 'w':
+ password = optarg;
+ break;
+ case 'q':
+ query = optarg;
+ break;
+ case 'd':
+ params.dbname = optarg;
+ params.mask |= KADM5_CONFIG_DBNAME;
+ break;
+ case 's':
+ params.admin_server = optarg;
+ params.mask |= KADM5_CONFIG_ADMIN_SERVER;
+ break;
+ case 'm':
+ params.mkey_from_kbd = 1;
+ params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
+ break;
+ case 'e':
+ retval = krb5_string_to_keysalts(optarg,
+ ", \t",
+ ":.-",
+ 0,
+ &params.keysalts,
+ &params.num_keysalts);
+ if (retval) {
+ com_err(whoami, retval, "while parsing keysalts %s", optarg);
+ exit(1);
+ }
+ params.mask |= KADM5_CONFIG_ENCTYPES;
+ break;
+ default:
+ usage();
+ }
+ }
+ if ((ccache_name && use_keytab) ||
+ (keytab_name && !use_keytab))
+ usage();
+
+ if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) {
+ if (freeprinc)
+ free(princstr);
+ fprintf(stderr, "%s: unable to get default realm\n", whoami);
+ exit(1);
+ }
+
+ params.mask |= KADM5_CONFIG_REALM;
+ params.realm = def_realm;
+
+ /*
+ * Set cc to an open credentials cache, either specified by the -c
+ * argument or the default.
+ */
+ if (ccache_name == NULL) {
+ if (retval = krb5_cc_default(context, &cc)) {
+ com_err(whoami, retval,
+ "while opening default credentials cache");
+ exit(1);
+ }
+ } else {
+ if (retval = krb5_cc_resolve(context, ccache_name, &cc)) {
+ com_err(whoami, retval,
+ "while opening credentials cache %s", ccache_name);
+ exit(1);
+ }
+ }
+
+ /*
+ * If no principal name is specified: If a ccache was specified
+ * and its primary principal name can be read, it is used, else if
+ * a keytab was specified, the principal name is host/hostname,
+ * otherwise append "/admin" to the primary name of the default
+ * ccache, $USER, or pw_name.
+ *
+ * Gee, 100+ lines to figure out the client principal name. This
+ * should be compressed...
+ */
+
+ if (princstr == NULL) {
+ if (ccache_name != NULL &&
+ !krb5_cc_get_principal(context, cc, &princ)) {
+ if (retval = krb5_unparse_name(context, princ, &princstr)) {
+ com_err(whoami, retval,
+ "while canonicalizing principal name");
+ krb5_free_principal(context, princ);
+ exit(1);
+ }
+ krb5_free_principal(context, princ);
+ freeprinc++;
+ } else if (use_keytab != NULL) {
+ if (retval = krb5_sname_to_principal(context, NULL,
+ "host",
+ KRB5_NT_SRV_HST,
+ &princ)) {
+ com_err(whoami, retval,
+ "creating host service principal");
+ exit(1);
+ }
+ if (retval = krb5_unparse_name(context, princ, &princstr)) {
+ com_err(whoami, retval,
+ "while canonicalizing principal name");
+ krb5_free_principal(context, princ);
+ exit(1);
+ }
+ krb5_free_principal(context, princ);
+ freeprinc++;
+ } else if (!krb5_cc_get_principal(context, cc, &princ)) {
+ char *realm = NULL;
+ if (krb5_unparse_name(context, princ, &canon)) {
+ fprintf(stderr,
+ "%s: unable to canonicalize principal\n", whoami);
+ krb5_free_principal(context, princ);
+ exit(1);
+ }
+ /* strip out realm of principal if it's there */
+ realm = strchr(canon, '@');
+ while (realm) {
+ if (realm - canon && *(realm - 1) != '\\')
+ break;
+ else
+ realm = strchr(realm, '@');
+ }
+ if (realm)
+ *realm++ = '\0';
+ cp = strchr(canon, '/');
+ while (cp) {
+ if (cp - canon && *(cp - 1) != '\\')
+ break;
+ else
+ cp = strchr(cp, '/');
+ }
+ if (cp != NULL)
+ *cp = '\0';
+ princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ +
+ (realm ? 1 + strlen(realm) : 0) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "%s: out of memory\n", whoami);
+ exit(1);
+ }
+ strcpy(princstr, canon);
+ strcat(princstr, "/admin");
+ if (realm) {
+ strcat(princstr, "@");
+ strcat(princstr, realm);
+ }
+ free(canon);
+ krb5_free_principal(context, princ);
+ freeprinc++;
+ } else if (luser = getenv("USER")) {
+ princstr = (char *) malloc(strlen(luser) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "%s: out of memory\n", whoami);
+ exit(1);
+ }
+ strcpy(princstr, luser);
+ strcat(princstr, "/admin");
+ strcat(princstr, "@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else if (pw = getpwuid(getuid())) {
+ princstr = (char *) malloc(strlen(pw->pw_name) + 7 /* "/admin@" */
+ + strlen(def_realm) + 1);
+ if (princstr == NULL) {
+ fprintf(stderr, "%s: out of memory\n", whoami);
+ exit(1);
+ }
+ strcpy(princstr, pw->pw_name);
+ strcat(princstr, "/admin@");
+ strcat(princstr, def_realm);
+ freeprinc++;
+ } else {
+ fprintf(stderr, "%s: unable to figure out a principal name\n",
+ whoami);
+ exit(1);
+ }
+ }
+
+ /*
+ * Initialize the kadm5 connection. If we were given a ccache,
+ * use it. Otherwise, use/prompt for the password.
+ */
+ if (ccache_name)
+ retval = kadm5_init_with_creds(princstr, cc,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ else if (use_keytab)
+ retval = kadm5_init_with_skey(princstr, keytab_name,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ else
+ retval = kadm5_init_with_password(princstr, password,
+ KADM5_ADMIN_SERVICE,
+ &params,
+ KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_2,
+ &handle);
+ if (retval) {
+ com_err(whoami, retval, "while initializing %s interface", whoami);
+ if (retval == KADM5_BAD_CLIENT_PARAMS ||
+ retval == KADM5_BAD_SERVER_PARAMS)
+ usage();
+ exit(1);
+ }
+ if (freeprinc)
+ free(princstr);
+
+ if (retval = krb5_cc_close(context, cc)) {
+ com_err(whoami, retval, "while closing ccache %s",
+ ccache_name);
+ exit(1);
+ }
+
+ /* register the WRFILE keytab type and set it as the default */
+ if (retval = krb5_kt_register(context, &krb5_ktf_writable_ops)) {
+ com_err(whoami, retval,
+ "while registering writable key table functions");
+ exit(1);
+ }
+ {
+#define DEFAULT_KEYTAB "WRFILE:/etc/v5srvtab"
+ extern char *krb5_defkeyname;
+ krb5_defkeyname = DEFAULT_KEYTAB;
+ }
+
+ return query;
+}
+
+int quit()
+{
+ krb5_ccache cc;
+ int retval;
+
+ kadm5_destroy(handle);
+ if (ccache_name != NULL) {
+ fprintf(stderr,
+ "\n\a\a\aAdministration credentials NOT DESTROYED.\n");
+ }
+
+ /* insert more random cleanup here */
+}
+
+void kadmin_delprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_ret_t retval;
+ krb5_principal princ;
+ char *canon;
+ char reply[5];
+
+ if (! (argc == 2 ||
+ (argc == 3 && !strcmp("-force", argv[1])))) {
+ fprintf(stderr, "usage: delete_principal [-force] principal\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("delete_principal", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(context, princ, &canon);
+ if (retval) {
+ com_err("delete_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(context, princ);
+ return;
+ }
+ if (argc == 2) {
+ printf("Are you sure you want to delete the principal \"%s\"? (yes/no): ", canon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr, "Principal \"%s\" not deleted\n", canon);
+ free(canon);
+ krb5_free_principal(context, princ);
+ return;
+ }
+ }
+ retval = kadm5_delete_principal(handle, princ);
+ krb5_free_principal(context, princ);
+ if (retval) {
+ com_err("delete_principal", retval,
+ "while deleteing principal \"%s\"", canon);
+ free(canon);
+ return;
+ }
+ printf("Principal \"%s\" deleted.\nMake sure that you have removed this principal from all ACLs before reusing.\n", canon);
+ free(canon);
+ return;
+}
+
+void kadmin_renprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_principal oldprinc, newprinc;
+ char *oldcanon, *newcanon;
+ char reply[5];
+ kadm5_ret_t retval;
+
+ if (! (argc == 3 ||
+ (argc == 4 && !strcmp("-force", argv[1])))) {
+ fprintf(stderr, "usage: rename_principal [-force] old new\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 2], &oldprinc);
+ if (retval) {
+ com_err("rename_principal", retval, "while parsing old principal");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &newprinc);
+ if (retval) {
+ krb5_free_principal(context, oldprinc);
+ com_err("rename_principal", retval, "while parsing new principal");
+ return;
+ }
+ retval = krb5_unparse_name(context, oldprinc, &oldcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing old principal");
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ retval = krb5_unparse_name(context, newprinc, &newcanon);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while canonicalizing new principal");
+ free(oldcanon);
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ if (argc == 3) {
+ printf("Are you sure you want to rename the principal \"%s\" to \"%s\"? (yes/no): ",
+ oldcanon, newcanon);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr,
+ "rename_principal: \"%s\" NOT renamed to \"%s\".\n",
+ oldcanon, newcanon);
+ free(newcanon);
+ free(oldcanon);
+ krb5_free_principal(context, newprinc);
+ krb5_free_principal(context, oldprinc);
+ return;
+ }
+ }
+ retval = kadm5_rename_principal(handle, oldprinc, newprinc);
+ krb5_free_principal(context, oldprinc);
+ krb5_free_principal(context, newprinc);
+ if (retval) {
+ com_err("rename_principal", retval,
+ "while renaming \"%s\" to \"%s\".", oldcanon,
+ newcanon);
+ free(newcanon);
+ free(oldcanon);
+ return;
+ }
+ printf("Principal \"%s\" renamed to \"%s\".\nMake sure that you have removed \"%s\" from all ACLs before reusing.\n",
+ oldcanon, newcanon, newcanon);
+ return;
+}
+
+void kadmin_cpw(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_ret_t retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+ char *canon;
+ krb5_principal princ;
+
+ if (argc < 2) {
+ goto usage;
+ }
+
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("change_password", retval, "while parsing principal name");
+ return;
+ }
+ retval = krb5_unparse_name(context, princ, &canon);
+ if (retval) {
+ com_err("change_password", retval, "while canonicalizing principal");
+ krb5_free_principal(context, princ);
+ return;
+ }
+ if ((argc == 4) && (strlen(argv[1]) == 3) && !strcmp("-pw", argv[1])) {
+ retval = kadm5_chpass_principal(handle, princ, argv[2]);
+ krb5_free_principal(context, princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else if ((argc == 3) && (strlen(argv[1]) == 8) &&
+ !strcmp("-randkey", argv[1])) {
+ retval = kadm5_randkey_principal(handle, princ, NULL, NULL);
+ krb5_free_principal(context, princ);
+ if (retval) {
+ com_err("change_password", retval,
+ "while randomizing key for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Key for \"%s\" randomized.\n", canon);
+ free(canon);
+ return;
+ } else if (argc == 2) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ argv[1]);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ argv[1]);
+ retval = krb5_read_password(context, prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("change_password", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(context, princ);
+ return;
+ }
+ retval = kadm5_chpass_principal(handle, princ, newpw);
+ krb5_free_principal(context, princ);
+ memset(newpw, 0, sizeof (newpw));
+ if (retval) {
+ com_err("change_password", retval,
+ "while changing password for \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Password for \"%s\" changed.\n", canon);
+ free(canon);
+ return;
+ } else {
+ free(canon);
+ krb5_free_principal(context, princ);
+ usage:
+ fprintf(stderr,
+ "usage: change_password [-randpass] [-pw passowrd] "
+ "principal\n");
+ return;
+ }
+}
+
+int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey, caller)
+ int argc;
+ char *argv[];
+ kadm5_principal_ent_t oprinc;
+ long *mask;
+ char **pass;
+ int *randkey;
+ char *caller;
+{
+ int i, j, attrib_set;
+ time_t date;
+ time_t now;
+ krb5_error_code retval;
+
+ *mask = 0;
+ *pass = NULL;
+ time(&now);
+ *randkey = 0;
+ for (i = 1; i < argc - 1; i++) {
+ attrib_set = 0;
+ if (strlen(argv[i]) == 7 &&
+ !strcmp("-expire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ date = get_date(argv[i], NULL);
+ oprinc->princ_expire_time = date == (time_t)-1 ? 0 : date;
+ *mask |= KADM5_PRINC_EXPIRE_TIME;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 9 &&
+ !strcmp("-pwexpire", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ date = get_date(argv[i], NULL);
+ oprinc->pw_expiration = date == (time_t)-1 ? 0 : date;
+ *mask |= KADM5_PW_EXPIRATION;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-maxlife", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->max_life = get_date(argv[i], NULL) - now;
+ *mask |= KADM5_MAX_LIFE;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 5 &&
+ !strcmp("-kvno", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->kvno = atoi(argv[i]);
+ *mask |= KADM5_KVNO;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 7 &&
+ !strcmp("-policy", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ oprinc->policy = argv[i];
+ *mask |= KADM5_POLICY;
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 12 &&
+ !strcmp("-clearpolicy", argv[i])) {
+ oprinc->policy = NULL;
+ *mask |= KADM5_POLICY_CLR;
+ continue;
+ }
+ if (strlen(argv[i]) == 3 &&
+ !strcmp("-pw", argv[i])) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ *pass = argv[i];
+ continue;
+ }
+ }
+ if (strlen(argv[i]) == 8 &&
+ !strcmp("-randkey", argv[i])) {
+ ++*randkey;
+ continue;
+ }
+ for (j = 0; j < sizeof (flags) / sizeof (struct pflag); j++) {
+ if (strlen(argv[i]) == flags[j].flaglen + 1 &&
+ !strcmp(flags[j].flagname,
+ &argv[i][1] /* strip off leading + or - */)) {
+ if (flags[j].set && argv[i][0] == '-' ||
+ !flags[j].set && argv[i][0] == '+') {
+ oprinc->attributes |= flags[j].theflag;
+ *mask |= KADM5_ATTRIBUTES;
+ attrib_set++;
+ break;
+ } else if (flags[j].set && argv[i][0] == '+' ||
+ !flags[j].set && argv[i][0] == '-') {
+ oprinc->attributes &= ~flags[j].theflag;
+ *mask |= KADM5_ATTRIBUTES;
+ attrib_set++;
+ break;
+ } else {
+ return -1;
+ }
+ }
+ }
+ if (!attrib_set)
+ return -1; /* nothing was parsed */
+ }
+ if (i != argc - 1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ }
+ retval = kadmin_parse_name(argv[i], &oprinc->principal);
+ if (retval) {
+ com_err(caller, retval, "while parsing principal");
+ return -1;
+ }
+ return 0;
+}
+
+void kadmin_addmodprinc_usage(func)
+ char *func;
+{
+ fprintf(stderr, "usage: %s [options] principal\n", func);
+ fprintf(stderr, "\toptions are:\n");
+ fprintf(stderr, "\t\t[-salt salttype] [-expire expdate] [-pwexpire pwexpdate]\n\t\t[-maxlife maxtixlife] [-kvno kvno] [-policy policy]\n\t\t[-randkey] [-pw password] [{+|-}attribute]\n");
+ fprintf(stderr, "\tattributes are:\n");
+ fprintf(stderr, "\t\tallow_tgs_req, allow_tix, needchange, password_changing_service\n");
+}
+
+void kadmin_addprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_principal_ent_rec princ;
+ long mask;
+ int randkey = 0;
+ char *pass, *canon;
+ krb5_error_code retval;
+ static char newpw[1024];
+ static char prompt1[1024], prompt2[1024];
+
+ princ.attributes = 0;
+ if (kadmin_parse_princ_args(argc, argv,
+ &princ, &mask, &pass, &randkey,
+ "add_principal")) {
+ kadmin_addmodprinc_usage("add_principal");
+ return;
+ }
+ retval = krb5_unparse_name(context, princ.principal, &canon);
+ if (retval) {
+ com_err("add_principal",
+ retval, "while canonicalizing principal");
+ krb5_free_principal(context, princ.principal);
+ return;
+ }
+ if (randkey) { /* do special stuff if -randkey specified */
+ princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; /* set notix */
+ mask |= KADM5_ATTRIBUTES;
+ pass = "dummy";
+ } else if (pass == NULL) {
+ int i = sizeof (newpw) - 1;
+
+ sprintf(prompt1, "Enter password for principal \"%.900s\": ",
+ canon);
+ sprintf(prompt2,
+ "Re-enter password for principal \"%.900s\": ",
+ canon);
+ retval = krb5_read_password(context, prompt1, prompt2,
+ newpw, &i);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while reading password for \"%s\".", canon);
+ free(canon);
+ krb5_free_principal(context, princ.principal);
+ return;
+ }
+ pass = newpw;
+ }
+ mask |= KADM5_PRINCIPAL;
+ retval = kadm5_create_principal(handle, &princ, mask, pass);
+ if (retval) {
+ com_err("add_principal", retval, "while creating \"%s\".",
+ canon);
+ krb5_free_principal(context, princ.principal);
+ free(canon);
+ return;
+ }
+ if (randkey) { /* more special stuff for -randkey */
+ retval = kadm5_randkey_principal(handle, princ.principal,
+ NULL, NULL);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while randomizing key for \"%s\".", canon);
+ krb5_free_principal(context, princ.principal);
+ free(canon);
+ return;
+ }
+ princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX; /* clear notix */
+ mask = KADM5_ATTRIBUTES;
+ retval = kadm5_modify_principal(handle, &princ, mask);
+ if (retval) {
+ com_err("add_principal", retval,
+ "while clearing DISALLOW_ALL_TIX for \"%s\".", canon);
+ krb5_free_principal(context, princ.principal);
+ free(canon);
+ return;
+ }
+ }
+ krb5_free_principal(context, princ.principal);
+ printf("Principal \"%s\" created.\n", canon);
+ free(canon);
+}
+
+void kadmin_modprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_principal_ent_rec princ, oldprinc;
+ krb5_principal kprinc;
+ long mask;
+ krb5_error_code retval;
+ char *pass, *canon;
+ int randkey = 0;
+
+ if (argc < 2) {
+ kadmin_addmodprinc_usage("modify_principal");
+ return;
+ }
+
+ retval = kadmin_parse_name(argv[argc - 1], &kprinc);
+ if (retval) {
+ com_err("modify_principal", retval, "while parsing principal");
+ return;
+ }
+ retval = krb5_unparse_name(context, kprinc, &canon);
+ if (retval) {
+ com_err("modify_principal", retval,
+ "while canonicalizing principal");
+ krb5_free_principal(context, kprinc);
+ return;
+ }
+ retval = kadm5_get_principal(handle, kprinc, &oldprinc,
+ KADM5_PRINCIPAL_NORMAL_MASK);
+ krb5_free_principal(context, kprinc);
+ if (retval) {
+ com_err("modify_principal", retval, "while getting \"%s\".",
+ canon);
+ free(canon);
+ return;
+ }
+ princ.attributes = oldprinc.attributes;
+ kadm5_free_principal_ent(handle, &oldprinc);
+ retval = kadmin_parse_princ_args(argc, argv,
+ &princ, &mask,
+ &pass, &randkey,
+ "modify_principal");
+ if (retval) {
+ kadmin_addmodprinc_usage("modify_principal");
+ free(canon);
+ return;
+ }
+ if (randkey) {
+ fprintf(stderr, "modify_principal: -randkey not allowed\n");
+ krb5_free_principal(context, princ.principal);
+ free(canon);
+ return;
+ }
+ retval = kadm5_modify_principal(handle, &princ, mask);
+ krb5_free_principal(context, princ.principal);
+ if (retval) {
+ com_err("modify_principal", retval,
+ "while modifying \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ printf("Principal \"%s\" modified.\n", canon);
+ free(canon);
+}
+
+void kadmin_getprinc(argc, argv)
+ int argc;
+ char *argv[];
+{
+ kadm5_principal_ent_rec dprinc;
+ krb5_principal princ;
+ krb5_error_code retval;
+ char *canon, *modcanon;
+ int i;
+
+ if (! (argc == 2 ||
+ (argc == 3 && !strcmp("-terse", argv[1])))) {
+ fprintf(stderr, "usage: get_principal [-terse] principal\n");
+ return;
+ }
+ retval = kadmin_parse_name(argv[argc - 1], &princ);
+ if (retval) {
+ com_err("get_principal", retval, "while parsing principal");
+ return;
+ }
+ retval = krb5_unparse_name(context, princ, &canon);
+ if (retval) {
+ com_err("get_principal", retval, "while canonicalizing principal");
+ krb5_free_principal(context, princ);
+ return;
+ }
+ retval = kadm5_get_principal(handle, princ, &dprinc,
+ KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA);
+ krb5_free_principal(context, princ);
+ if (retval) {
+ com_err("get_principal", retval, "while retrieving \"%s\".", canon);
+ free(canon);
+ return;
+ }
+ retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon);
+ if (retval) {
+ com_err("get_principal", retval, "while unparsing modname");
+ kadm5_free_principal_ent(handle, &dprinc);
+ free(canon);
+ return;
+ }
+ if (argc == 2) {
+ printf("Principal: %s\n", canon);
+ printf("Expiration date: %s\n", strdate(dprinc.princ_expire_time));
+ printf("Last password change: %s\n",
+ strdate(dprinc.last_pwd_change));
+ printf("Password expiration date: %s\n",
+ dprinc.pw_expiration ?
+ strdate(dprinc.pw_expiration) : "[none]");
+ printf("Maximum ticket life: %s\n", strdur(dprinc.max_life));
+ printf("Last modified: by %s\n\ton %s\n",
+ modcanon, strdate(dprinc.mod_date));
+ printf("Last successful authentication: %s\n",
+ strdate(dprinc.last_success));
+ printf("Last failed authentication: %s\n",
+ strdate(dprinc.last_failed));
+ printf("Failed password attempts: %d\n",
+ dprinc.fail_auth_count);
+ printf("Number of keys: %d\n", dprinc.n_key_data);
+ for (i = 0; i < dprinc.n_key_data; i++) {
+ krb5_key_data *key_data = &dprinc.key_data[i];
+ char enctype[BUFSIZ], salttype[BUFSIZ];
+
+ if (krb5_enctype_to_string(key_data->key_data_type[0],
+ enctype, sizeof(enctype)))
+ sprintf(enctype, "<Encryption type 0x%x>",
+ key_data->key_data_type[0]);
+ printf("Key: vno %d, %s, ", key_data->key_data_kvno, enctype);
+ if (key_data->key_data_ver > 1) {
+ if (krb5_salttype_to_string(key_data->key_data_type[1],
+ salttype, sizeof(salttype)))
+ sprintf(salttype, "<Salt type 0x%x>",
+ key_data->key_data_type[1]);
+ printf("%s\n", salttype);
+ } else
+ printf("no salt\n");
+ }
+
+ printf("Attributes:");
+ for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) {
+ if (dprinc.attributes & (krb5_flags) 1 << i)
+ printf(" %s", prflags[i]);
+ }
+ printf("\n");
+ printf("Policy: %s\n", dprinc.policy ? dprinc.policy : "[none]");
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t\"%s\"\t%d\t%d\t%d\t%d\t\"%s\""
+ "\t%d\t%d\t%d\t%d\t%d",
+ canon, dprinc.princ_expire_time, dprinc.last_pwd_change,
+ dprinc.pw_expiration, dprinc.max_life, modcanon,
+ dprinc.mod_date, dprinc.attributes, dprinc.kvno,
+ dprinc.mkvno, dprinc.policy,
+ dprinc.max_renewable_life, dprinc.last_success,
+ dprinc.last_failed, dprinc.fail_auth_count,
+ dprinc.n_key_data);
+ for (i = 0; i < dprinc.n_key_data; i++)
+ printf("\t%d\t%d\t%d\t%d",
+ dprinc.key_data[i].key_data_ver,
+ dprinc.key_data[i].key_data_kvno,
+ dprinc.key_data[i].key_data_type[0],
+ dprinc.key_data[i].key_data_type[1]);
+ printf("\n");
+ }
+ free(modcanon);
+ kadm5_free_principal_ent(handle, &dprinc);
+ free(canon);
+}
+
+void kadmin_getprincs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ char *exp, **names;
+ int i, count;
+
+ exp = NULL;
+ if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
+ fprintf(stderr, "usage: get_principals [expression]\n");
+ return;
+ }
+ retval = kadm5_get_principals(handle, exp, &names, &count);
+ if (retval) {
+ com_err("get_principals", retval, "while retrieving list.");
+ return;
+ }
+ for (i = 0; i < count; i++)
+ printf("%s\n", names[i]);
+ kadm5_free_name_list(handle, names, count);
+}
+
+int kadmin_parse_policy_args(argc, argv, policy, mask, caller)
+ int argc;
+ char *argv[];
+ kadm5_policy_ent_t policy;
+ long *mask;
+ char *caller;
+{
+ int i;
+ time_t now;
+ time_t date;
+ krb5_error_code retval;
+
+ time(&now);
+ *mask = 0;
+ for (i = 1; i < argc - 1; i++) {
+ if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-maxlife")) {
+ if (++i > argc -2)
+ return -1;
+ else {
+ date = get_date(argv[i], NULL);
+ policy->pw_max_life =
+ (date == (time_t)-1 ? 0 : date) - now;
+ *mask |= KADM5_PW_MAX_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-minlife")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ date = get_date(argv[i], NULL);
+ policy->pw_min_life =
+ (date == (time_t)-1 ? 0 : date) - now;
+ *mask |= KADM5_PW_MIN_LIFE;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 10 &&
+ !strcmp(argv[i], "-minlength")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_length = atoi(argv[i]);
+ *mask |= KADM5_PW_MIN_LENGTH;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 11 &&
+ !strcmp(argv[i], "-minclasses")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_min_classes = atoi(argv[i]);
+ *mask |= KADM5_PW_MIN_CLASSES;
+ continue;
+ }
+ } else if (strlen(argv[i]) == 8 &&
+ !strcmp(argv[i], "-history")) {
+ if (++i > argc - 2)
+ return -1;
+ else {
+ policy->pw_history_num = atoi(argv[i]);
+ *mask |= KADM5_PW_HISTORY_NUM;
+ continue;
+ }
+ } else
+ return -1;
+ }
+ if (i != argc -1) {
+ fprintf(stderr, "%s: parser lost count!\n", caller);
+ return -1;
+ } else
+ return 0;
+}
+
+void kadmin_addmodpol_usage(func)
+ char *func;
+{
+ fprintf(stderr, "usage; %s [options] policy\n", func);
+ fprintf(stderr, "\toptions are:\n");
+ fprintf(stderr, "\t\t[-maxlife time] [-minlife time] [-minlength length]\n\t\t[-minclasses number] [-history number]\n");
+}
+
+void kadmin_addpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ long mask;
+ kadm5_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask, "add_policy")) {
+ kadmin_addmodpol_usage("add_policy");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ mask |= KADM5_POLICY;
+ retval = kadm5_create_policy(handle, &policy, mask);
+ if (retval) {
+ com_err("add_policy", retval, "while creating policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_modpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ long mask;
+ kadm5_policy_ent_rec policy;
+
+ if (kadmin_parse_policy_args(argc, argv, &policy, &mask,
+ "modify_policy")) {
+ kadmin_addmodpol_usage("modify_policy");
+ return;
+ } else {
+ policy.policy = argv[argc - 1];
+ retval = kadm5_modify_policy(handle, &policy, mask);
+ if (retval) {
+ com_err("modify_policy", retval, "while modifying policy \"%s\".",
+ policy.policy);
+ return;
+ }
+ }
+ return;
+}
+
+void kadmin_delpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ char reply[5];
+
+ if (! (argc == 2 ||
+ (argc == 3 && !strcmp("-force", argv[1])))) {
+ fprintf(stderr, "usage: delete_policy [-force] policy\n");
+ return;
+ }
+ if (argc == 2) {
+ printf("Are you sure you want to delete the policy \"%s\"? (yes/no): ", argv[1]);
+ fgets(reply, sizeof (reply), stdin);
+ if (strcmp("yes\n", reply)) {
+ fprintf(stderr, "Policy \"%s\" not deleted.\n", argv[1]);
+ return;
+ }
+ }
+ retval = kadm5_delete_policy(handle, argv[argc - 1]);
+ if (retval) {
+ com_err("delete_policy:", retval, "while deleting policy \"%s\"",
+ argv[argc - 1]);
+ return;
+ }
+ return;
+}
+
+void kadmin_getpol(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ kadm5_policy_ent_rec policy;
+
+ if (! (argc == 2 ||
+ (argc == 3 && !strcmp("-terse", argv[1])))) {
+ fprintf(stderr, "usage: get_policy [-terse] policy\n");
+ return;
+ }
+ retval = kadm5_get_policy(handle, argv[argc - 1], &policy);
+ if (retval) {
+ com_err("get_policy", retval, "while retrieving policy \"%s\".",
+ argv[argc - 1]);
+ return;
+ }
+ if (argc == 2) {
+ printf("Policy: %s\n", policy.policy);
+ printf("Maximum password life: %d\n", policy.pw_max_life);
+ printf("Minimum password life: %d\n", policy.pw_min_life);
+ printf("Minimum password length: %d\n", policy.pw_min_length);
+ printf("Minimum number of password character classes: %d\n",
+ policy.pw_min_classes);
+ printf("Number of old keys kept: %d\n", policy.pw_history_num);
+ printf("Reference count: %d\n", policy.policy_refcnt);
+ } else {
+ printf("\"%s\"\t%d\t%d\t%d\t%d\t%d\t%d\n",
+ policy.policy, policy.pw_max_life, policy.pw_min_life,
+ policy.pw_min_length, policy.pw_min_classes,
+ policy.pw_history_num, policy.policy_refcnt);
+ }
+ kadm5_free_policy_ent(handle, &policy);
+ return;
+}
+
+void kadmin_getpols(argc, argv)
+ int argc;
+ char *argv[];
+{
+ krb5_error_code retval;
+ char *exp, **names;
+ int i, count;
+
+ exp = NULL;
+ if (! (argc == 1 || (argc == 2 && (exp = argv[1])))) {
+ fprintf(stderr, "usage: get_policies [expression]\n");
+ return;
+ }
+ retval = kadm5_get_policies(handle, exp, &names, &count);
+ if (retval) {
+ com_err("get_policies", retval, "while retrieving list.");
+ return;
+ }
+ for (i = 0; i < count; i++)
+ printf("%s\n", names[i]);
+ kadm5_free_name_list(handle, names, count);
+}
+
+kadmin_getprivs(argc, argv)
+ int argc;
+ char *argv[];
+{
+ static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE"};
+ krb5_error_code retval;
+ int i;
+ long plist;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: get_privs\n");
+ return;
+ }
+ retval = kadm5_get_privs(handle, &plist);
+ if (retval) {
+ com_err("get_privs", retval, "while retrieving privileges");
+ return;
+ }
+ printf("current privileges:");
+ for (i = 0; i < sizeof (privs) / sizeof (char *); i++) {
+ if (plist & 1 << i)
+ printf(" %s", privs[i]);
+ }
+ printf("\n");
+ return;
+}
diff --git a/src/kadmin/cli/kadmin_ct.ct b/src/kadmin/cli/kadmin_ct.ct
new file mode 100644
index 000000000..d22229bf0
--- /dev/null
+++ b/src/kadmin/cli/kadmin_ct.ct
@@ -0,0 +1,79 @@
+# Copyright 1994 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 kadmin CLI for OVSecure
+#
+
+command_table kadmin_cmds;
+
+request kadmin_addprinc, "Add principal",
+ add_prinicpal, addprinc, ank;
+
+request kadmin_delprinc, "Delete principal",
+ delete_principal, delprinc;
+
+request kadmin_modprinc, "Modify principal",
+ modify_principal, modprinc;
+
+request kadmin_renprinc, "Rename principal",
+ rename_principal, renprinc;
+
+request kadmin_cpw, "Change password",
+ change_password, cpw;
+
+request kadmin_getprinc, "Get principal",
+ get_principal, getprinc;
+
+request kadmin_getprincs, "Get principals",
+ get_principals, getprincs;
+
+request kadmin_addpol, "Add policy",
+ add_policy, addpol;
+
+request kadmin_modpol, "Modify policy",
+ modify_policy, modpol;
+
+request kadmin_delpol, "Delete policy",
+ delete_policy, delpol;
+
+request kadmin_getpol, "Get policy",
+ get_policy, getpol;
+
+request kadmin_getpols, "Get policies",
+ get_policies, getpols;
+
+request kadmin_getprivs, "Get privileges",
+ get_privs, getprivs;
+
+request kadmin_keytab_add, "Add entry(s) to a keytab",
+ ktadd, xst;
+
+request kadmin_keytab_remove, "Remove entry(s) from a keytab",
+ ktremove, ktrem;
+
+# 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/cli/keytab.c b/src/kadmin/cli/keytab.c
new file mode 100644
index 000000000..4b51140b5
--- /dev/null
+++ b/src/kadmin/cli/keytab.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
+ *
+ * $Id$
+ * $Source$
+ */
+
+#if !defined(lint) && !defined(__CODECENTER__)
+static char *rcsid = "$Header$";
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <krb5.h>
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+static int add_principal(void *handle, char *keytab_str, krb5_keytab keytab,
+ char *princ_str);
+static int remove_principal(char *keytab_str, krb5_keytab keytab, char
+ *princ_str, char *kvno_str);
+static char *etype_string(krb5_enctype enctype);
+
+extern char *krb5_defkeyname;
+extern char *whoami;
+extern krb5_context context;
+extern void *handle;
+static int quiet;
+
+void add_usage()
+{
+ fprintf(stderr, "Usage: ktadd [-k[eytab] keytab] [-q] [principal | -glob princ-exp] [...]\n");
+}
+
+void rem_usage()
+{
+ fprintf(stderr, "Usage: ktremove [-k[eytab] keytab] [-q] principal [kvno|\"all\"|\"old\"]\n");
+}
+
+int process_keytab(krb5_context context, char **keytab_str,
+ krb5_keytab *keytab)
+{
+ int code;
+
+ if (*keytab_str == NULL) {
+ if (! (*keytab_str = strdup(krb5_defkeyname))) {
+ com_err(whoami, ENOMEM, "while creating keytab name");
+ return 1;
+ }
+ code = krb5_kt_default(context, keytab);
+ if (code != 0) {
+ com_err(whoami, code, "while opening default keytab");
+ free(*keytab_str);
+ return 1;
+ }
+ } else {
+ if (strchr(*keytab_str, ':') != NULL) {
+ *keytab_str = strdup(*keytab_str);
+ if (*keytab_str == NULL) {
+ com_err(whoami, ENOMEM, "while creating keytab name");
+ return 1;
+ }
+ } else {
+ char *tmp = *keytab_str;
+
+ *keytab_str = (char *)
+ malloc(strlen("WRFILE:")+strlen(tmp)+1);
+ if (*keytab_str == NULL) {
+ com_err(whoami, ENOMEM, "while creating keytab name");
+ return 1;
+ }
+ sprintf(*keytab_str, "WRFILE:%s", tmp);
+ }
+
+ code = krb5_kt_resolve(context, *keytab_str, keytab);
+ if (code != 0) {
+ com_err(whoami, code, "while resolving keytab %s", *keytab_str);
+ free(keytab_str);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void kadmin_keytab_add(int argc, char **argv)
+{
+ krb5_keytab keytab = 0;
+ char *princ_str, *keytab_str = NULL, **princs;
+ int code, num, i;
+
+ argc--; argv++;
+ while (argc) {
+ if (strncmp(*argv, "-k", 2) == 0) {
+ argc--; argv++;
+ if (!argc || keytab_str) {
+ add_usage();
+ return;
+ }
+ keytab_str = *argv;
+ } else if (strcmp(*argv, "-q") == 0) {
+ quiet++;
+ } else
+ break;
+ argc--; argv++;
+ }
+
+ if (argc == 0) {
+ add_usage();
+ return;
+ }
+
+ if (process_keytab(context, &keytab_str, &keytab))
+ return;
+
+ while (*argv) {
+ if (strcmp(*argv, "-glob") == 0) {
+ if (*++argv == NULL) {
+ add_usage();
+ break;
+ }
+
+ if (code = kadm5_get_principals(handle, *argv, &princs, &num)) {
+ com_err(whoami, code, "while expanding expression \"%s\".",
+ *argv);
+ argv++;
+ continue;
+ }
+
+ for (i = 0; i < num; i++)
+ (void) add_principal(handle, keytab_str, keytab,
+ princs[i]);
+ kadm5_free_name_list(handle, princs, num);
+ } else
+ (void) add_principal(handle, keytab_str, keytab, *argv);
+ argv++;
+ }
+
+ code = krb5_kt_close(context, keytab);
+ if (code != 0)
+ com_err(whoami, code, "while closing keytab");
+
+ free(keytab_str);
+}
+
+void kadmin_keytab_remove(int argc, char **argv)
+{
+ krb5_keytab keytab = 0;
+ char *princ_str, *keytab_str = NULL;
+ int code;
+
+ argc--; argv++;
+ while (argc) {
+ if (strncmp(*argv, "-k", 2) == 0) {
+ argc--; argv++;
+ if (!argc || keytab_str) {
+ rem_usage();
+ return;
+ }
+ keytab_str = *argv;
+ } else if (strcmp(*argv, "-q") == 0) {
+ quiet++;
+ } else
+ break;
+ argc--; argv++;
+ }
+
+ if (argc != 1 && argc != 2) {
+ rem_usage();
+ return;
+ }
+ if (process_keytab(context, &keytab_str, &keytab))
+ return;
+
+ (void) remove_principal(keytab_str, keytab, argv[0], argv[1]);
+
+ code = krb5_kt_close(context, keytab);
+ if (code != 0)
+ com_err(whoami, code, "while closing keytab");
+
+ free(keytab_str);
+}
+
+int add_principal(void *handle, char *keytab_str, krb5_keytab keytab,
+ char *princ_str)
+{
+ kadm5_principal_ent_rec princ_rec;
+ krb5_principal princ;
+ krb5_keytab_entry new_entry;
+ krb5_keyblock *keys;
+ int code, code2, mask, nkeys, i;
+
+ (void) memset((char *)&princ_rec, 0, sizeof(princ_rec));
+
+ princ = NULL;
+ keys = NULL;
+ nkeys = 0;
+
+ code = krb5_parse_name(context, princ_str, &princ);
+ if (code != 0) {
+ com_err(whoami, code, "while parsing -add principal name %s",
+ princ_str);
+ goto cleanup;
+ }
+
+ code = kadm5_randkey_principal(handle, princ, &keys, &nkeys);
+ if (code != 0) {
+ if (code == KADM5_UNK_PRINC) {
+ fprintf(stderr, "%s: Principal %s does not exist.\n",
+ whoami, princ_str);
+ } else
+ com_err(whoami, code, "while changing %s's key",
+ princ_str);
+ goto cleanup;
+ }
+
+ code = kadm5_get_principal(handle, princ, &princ_rec,
+ KADM5_PRINCIPAL_NORMAL_MASK);
+ if (code != 0) {
+ com_err(whoami, code, "while retrieving principal");
+ goto cleanup;
+ }
+
+ for (i = 0; i < nkeys; i++) {
+ memset((char *) &new_entry, 0, sizeof(new_entry));
+ new_entry.principal = princ;
+ new_entry.key = keys[i];
+ new_entry.vno = princ_rec.kvno;
+
+ code = krb5_kt_add_entry(context, keytab, &new_entry);
+ if (code != 0) {
+ com_err(whoami, code, "while adding key to keytab");
+ (void) kadm5_free_principal_ent(handle, &princ_rec);
+ goto cleanup;
+ }
+
+ if (!quiet)
+ printf("%s: Entry for principal %s with kvno %d, "
+ "encryption type %s added to keytab %s.\n",
+ whoami, princ_str, princ_rec.kvno,
+ etype_string(keys[i].enctype), keytab_str);
+ }
+
+ code = kadm5_free_principal_ent(handle, &princ_rec);
+ if (code != 0) {
+ com_err(whoami, code, "while freeing principal entry");
+ goto cleanup;
+ }
+
+cleanup:
+ if (nkeys) {
+ for (i = 0; i < nkeys; i++)
+ krb5_free_keyblock(context, &keys[i]);
+ free(keys);
+ }
+ if (princ)
+ krb5_free_principal(context, princ);
+
+ return code;
+}
+
+int remove_principal(char *keytab_str, krb5_keytab keytab, char
+ *princ_str, char *kvno_str)
+{
+ krb5_principal princ;
+ krb5_keytab_entry entry;
+ krb5_kt_cursor cursor;
+ enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
+ int code, kvno, did_something;
+
+ code = krb5_parse_name(context, princ_str, &princ);
+ if (code != 0) {
+ com_err(whoami, code, "while parsing principal name %s",
+ princ_str);
+ return code;
+ }
+
+ mode = UNDEF;
+ if (kvno_str == NULL) {
+ mode = HIGH;
+ kvno = 0;
+ } else if (strcmp(kvno_str, "all") == 0) {
+ mode = ALL;
+ kvno = 0;
+ } else if (strcmp(kvno_str, "old") == 0) {
+ mode = OLD;
+ kvno = 0;
+ } else {
+ mode = SPEC;
+ kvno = atoi(kvno_str);
+ }
+
+ /* kvno is set to specified value for SPEC, 0 otherwise */
+ code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
+ if (code != 0) {
+ if (code == ENOENT) {
+ fprintf(stderr, "%s: Keytab %s does not exist.\n",
+ whoami, keytab_str);
+ } else if (code == KRB5_KT_NOTFOUND) {
+ if (mode != SPEC)
+ fprintf(stderr, "%s: No entry for principal "
+ "%s exists in keytab %s\n",
+ whoami, princ_str, keytab_str);
+ else
+ fprintf(stderr, "%s: No entry for principal "
+ "%s with kvno %d exists in keytab "
+ "%s.\n", whoami, princ_str, kvno,
+ keytab_str);
+ } else {
+ com_err(whoami, code, "while retrieving highest kvno "
+ "from keytab");
+ }
+ return code;
+ }
+
+ /* set kvno to spec'ed value for SPEC, highest kvno otherwise */
+ kvno = entry.vno;
+ krb5_kt_free_entry(context, &entry);
+
+ code = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (code != 0) {
+ com_err(whoami, code, "while starting keytab scan");
+ return code;
+ }
+
+ did_something = 0;
+ while ((code = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
+ if (krb5_principal_compare(context, princ, entry.principal) &&
+ ((mode == ALL) ||
+ (mode == SPEC && entry.vno == kvno) ||
+ (mode == OLD && entry.vno != kvno) ||
+ (mode == HIGH && entry.vno == kvno))) {
+
+ /*
+ * Ack! What a kludge... the scanning functions lock
+ * the keytab so entries cannot be removed while they
+ * are operating.
+ */
+ code = krb5_kt_end_seq_get(context, keytab, &cursor);
+ if (code != 0) {
+ com_err(whoami, code, "while temporarily ending "
+ "keytab scan");
+ return code;
+ }
+ code = krb5_kt_remove_entry(context, keytab, &entry);
+ if (code != 0) {
+ com_err(whoami, code, "while deleting entry from keytab");
+ return code;
+ }
+ code = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (code != 0) {
+ com_err(whoami, code, "while restarting keytab scan");
+ return code;
+ }
+
+ did_something++;
+ if (!quiet)
+ printf("%s: Entry for principal %s with kvno %d "
+ "removed from keytab %s.\n", whoami,
+ princ_str, entry.vno, keytab_str);
+ }
+ krb5_kt_free_entry(context, &entry);
+ }
+ if (code && code != KRB5_KT_END) {
+ com_err(whoami, code, "while scanning keytab");
+ return code;
+ }
+ if (code = krb5_kt_end_seq_get(context, keytab, &cursor)) {
+ com_err(whoami, code, "while ending keytab scan");
+ return code;
+ }
+
+ /*
+ * If !did_someting then mode must be OLD or we would have
+ * already returned with an error. But check it anyway just to
+ * prevent unexpected error messages...
+ */
+ if (!did_something && mode == OLD) {
+ fprintf(stderr, "%s: There is only one entry for principal "
+ "%s in keytab %s\n", whoami, princ_str, keytab_str);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * etype_string(enctype): return a string representation of the
+ * encryption type. XXX copied from klist.c; this should be a
+ * library function, or perhaps just #defines
+ */
+static char *etype_string(enctype)
+ krb5_enctype enctype;
+{
+ static char buf[12];
+
+ switch (enctype) {
+ case ENCTYPE_DES_CBC_CRC:
+ return "DES-CBC-CRC";
+ break;
+ case ENCTYPE_DES_CBC_MD4:
+ return "DES-CBC-MD4";
+ break;
+ case ENCTYPE_DES_CBC_MD5:
+ return "DES-CBC-MD5";
+ break;
+#if 0
+ case ENCTYPE_DES3_CBC_MD5:
+ return "DES3-CBC-MD5";
+ break;
+#endif
+ default:
+ sprintf(buf, "etype %d", enctype);
+ return buf;
+ break;
+ }
+}
diff --git a/src/kadmin/cli/memmove.c b/src/kadmin/cli/memmove.c
new file mode 100644
index 000000000..abc91e923
--- /dev/null
+++ b/src/kadmin/cli/memmove.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MEMMOVE
+
+/* based on @(#)bcopy.c 5.11 (Berkeley) 6/21/91 */
+
+#include <krb5/osconf.h>
+#include <krb5/config.h>
+#ifdef USE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+/*
+ * sizeof(word) MUST BE A POWER OF TWO
+ * SO THAT wmask BELOW IS ALL ONES
+ */
+typedef int word; /* "word" used for optimal copy speed */
+
+#define wsize sizeof(word)
+#define wmask (wsize - 1)
+
+/*
+ * Copy a block of memory, handling overlap.
+ * This is the routine that actually implements
+ * (the portable versions of) bcopy, memcpy, and memmove.
+ */
+#ifdef MEMCOPY
+void *
+memcpy(dst0, src0, length)
+#else
+#ifdef MEMMOVE
+void *
+memmove(dst0, src0, length)
+#else
+void
+bcopy(src0, dst0, length)
+#endif
+#endif
+ void *dst0;
+ const void *src0;
+ register size_t length;
+{
+ register char *dst = dst0;
+ register const char *src = src0;
+ register size_t t;
+
+ if (length == 0 || dst == src) /* nothing to do */
+ goto done;
+
+ /*
+ * Macros: loop-t-times; and loop-t-times, t>0
+ */
+#define TLOOP(s) if (t) TLOOP1(s)
+#define TLOOP1(s) do { s; } while (--t)
+
+ if ((unsigned long)dst < (unsigned long)src) {
+ /*
+ * Copy forward.
+ */
+ t = (int)src; /* only need low bits */
+ if ((t | (int)dst) & wmask) {
+ /*
+ * Try to align operands. This cannot be done
+ * unless the low bits match.
+ */
+ if ((t ^ (int)dst) & wmask || length < wsize)
+ t = length;
+ else
+ t = wsize - (t & wmask);
+ length -= t;
+ TLOOP1(*dst++ = *src++);
+ }
+ /*
+ * Copy whole words, then mop up any trailing bytes.
+ */
+ t = length / wsize;
+ TLOOP(*(word *)dst = *(word *)src; src += wsize; dst += wsize);
+ t = length & wmask;
+ TLOOP(*dst++ = *src++);
+ } else {
+ /*
+ * Copy backwards. Otherwise essentially the same.
+ * Alignment works as before, except that it takes
+ * (t&wmask) bytes to align, not wsize-(t&wmask).
+ */
+ src += length;
+ dst += length;
+ t = (int)src;
+ if ((t | (int)dst) & wmask) {
+ if ((t ^ (int)dst) & wmask || length <= wsize)
+ t = length;
+ else
+ t &= wmask;
+ length -= t;
+ TLOOP1(*--dst = *--src);
+ }
+ t = length / wsize;
+ TLOOP(src -= wsize; dst -= wsize; *(word *)dst = *(word *)src);
+ t = length & wmask;
+ TLOOP(*--dst = *--src);
+ }
+done:
+#if defined(MEMCOPY) || defined(MEMMOVE)
+ return (dst0);
+#else
+ return;
+#endif
+}
diff --git a/src/kadmin/cli/setenv.c b/src/kadmin/cli/setenv.c
new file mode 100644
index 000000000..a2432c3d6
--- /dev/null
+++ b/src/kadmin/cli/setenv.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* based on @(#)setenv.c 8.1 (Berkeley) 6/4/93 */
+/* based on @(#)getenv.c 8.1 (Berkeley) 6/4/93 */
+
+#ifndef __STDC__
+#define const
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __P
+#define __P(x) ()
+#endif
+char *__findenv __P((const char *, int *));
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+setenv(name, value, rewrite)
+ register const char *name;
+ register const char *value;
+ int rewrite;
+{
+ extern char **environ;
+ static int alloced; /* if allocated space before */
+ register char *c;
+ int l_value, offset;
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((c = __findenv(name, &offset))) { /* find if already exists */
+ if (!rewrite)
+ return (0);
+ if (strlen(c) >= l_value) { /* old larger; copy over */
+ while (*c++ = *value++);
+ return (0);
+ }
+ } else { /* create new slot */
+ register int cnt;
+ register char **p;
+
+ for (p = environ, cnt = 0; *p; ++p, ++cnt);
+ if (alloced) { /* just increase size */
+ environ = (char **)realloc((char *)environ,
+ (size_t)(sizeof(char *) * (cnt + 2)));
+ if (!environ)
+ return (-1);
+ }
+ else { /* get new space */
+ alloced = 1; /* copy old entries into it */
+ p = (char **)malloc((size_t)(sizeof(char *) * (cnt + 2)));
+ if (!p)
+ return (-1);
+ memcpy(p, environ, cnt * sizeof(char *));
+ environ = p;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (c = (char *)name; *c && *c != '='; ++c); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((size_t)((int)(c - name) + l_value + 2))))
+ return (-1);
+ for (c = environ[offset]; (*c = *name++) && *c != '='; ++c);
+ for (*c++ = '='; *c++ = *value++;);
+ return (0);
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+ const char *name;
+{
+ extern char **environ;
+ register char **p;
+ int offset;
+
+ while (__findenv(name, &offset)) /* if set multiple times */
+ for (p = &environ[offset];; ++p)
+ if (!(*p = *(p + 1)))
+ break;
+}
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ const char *name;
+{
+ int offset;
+
+ return (__findenv(name, &offset));
+}
+
+/*
+ * __findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ */
+static char *
+__findenv(name, offset)
+ register const char *name;
+ int *offset;
+{
+ extern char **environ;
+ register int len;
+ register const char *np;
+ register char **p, *c;
+
+ if (name == NULL || environ == NULL)
+ return (NULL);
+ for (np = name; *np && *np != '='; ++np)
+ continue;
+ len = np - name;
+ for (p = environ; (c = *p) != NULL; ++p)
+ if (strncmp(c, name, len) == 0 && c[len] == '=') {
+ *offset = p - environ;
+ return (c + len + 1);
+ }
+ return (NULL);
+}
diff --git a/src/kadmin/cli/ss_wrapper.c b/src/kadmin/cli/ss_wrapper.c
new file mode 100644
index 000000000..89e94b36b
--- /dev/null
+++ b/src/kadmin/cli/ss_wrapper.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright 1994 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 for kadmin
+ */
+
+#include <krb5.h>
+#include <ss/ss.h>
+#include <stdio.h>
+#include <string.h>
+
+extern ss_request_table kadmin_cmds;
+extern int exit_status;
+extern char *kadmin_startup();
+extern char *whoami;
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *request;
+ krb5_error_code retval;
+ int sci_idx, code = 0;
+
+ whoami = ((whoami = strrchr(argv[0], '/')) ? whoami+1 : argv[0]);
+
+ request = kadmin_startup(argc, argv);
+ sci_idx = ss_create_invocation(whoami, "5.0", (char *) NULL,
+ &kadmin_cmds, &retval);
+ if (retval) {
+ ss_perror(sci_idx, retval, "creating invocation");
+ exit(1);
+ }
+ if (request) {
+ code = ss_execute_line(sci_idx, request);
+ if (code != 0) {
+ ss_perror(sci_idx, code, request);
+ exit_status++;
+ }
+ } else
+ ss_listen(sci_idx, &retval);
+ return quit() ? 1 : exit_status;
+}
diff --git a/src/kadmin/cli/strftime.c b/src/kadmin/cli/strftime.c
new file mode 100644
index 000000000..484852a72
--- /dev/null
+++ b/src/kadmin/cli/strftime.c
@@ -0,0 +1,469 @@
+/* strftime - custom formatting of date and/or time
+ Copyright (C) 1989, 1991, 1992 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Note: this version of strftime lacks locale support,
+ but it is standalone.
+
+ Performs `%' substitutions similar to those in printf. Except
+ where noted, substituted fields have a fixed size; numeric fields are
+ padded if necessary. Padding is with zeros by default; for fields
+ that display a single number, padding can be changed or inhibited by
+ following the `%' with one of the modifiers described below. Unknown
+ field specifiers are copied as normal characters. All other
+ characters are copied to the output without change.
+
+ Supports a superset of the ANSI C field specifiers.
+
+ Literal character fields:
+ % %
+ n newline
+ t tab
+
+ Numeric modifiers (a nonstandard extension):
+ - do not pad the field
+ _ pad the field with spaces
+
+ Time fields:
+ %H hour (00..23)
+ %I hour (01..12)
+ %k hour ( 0..23)
+ %l hour ( 1..12)
+ %M minute (00..59)
+ %p locale's AM or PM
+ %r time, 12-hour (hh:mm:ss [AP]M)
+ %R time, 24-hour (hh:mm)
+ %s time in seconds since 00:00:00, Jan 1, 1970 (a nonstandard extension)
+ %S second (00..61)
+ %T time, 24-hour (hh:mm:ss)
+ %X locale's time representation (%H:%M:%S)
+ %Z time zone (EDT), or nothing if no time zone is determinable
+
+ Date fields:
+ %a locale's abbreviated weekday name (Sun..Sat)
+ %A locale's full weekday name, variable length (Sunday..Saturday)
+ %b locale's abbreviated month name (Jan..Dec)
+ %B locale's full month name, variable length (January..December)
+ %c locale's date and time (Sat Nov 04 12:02:33 EST 1989)
+ %C century (00..99)
+ %d day of month (01..31)
+ %e day of month ( 1..31)
+ %D date (mm/dd/yy)
+ %h same as %b
+ %j day of year (001..366)
+ %m month (01..12)
+ %U week number of year with Sunday as first day of week (00..53)
+ %w day of week (0..6)
+ %W week number of year with Monday as first day of week (00..53)
+ %x locale's date representation (mm/dd/yy)
+ %y last two digits of year (00..99)
+ %Y year (1970...)
+
+ David MacKenzie <djm@gnu.ai.mit.edu> */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#if defined(TM_IN_SYS_TIME) || (!defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME))
+#include <sys/time.h>
+#else
+#include <time.h>
+#endif
+
+#ifndef STDC_HEADERS
+time_t mktime ();
+#endif
+
+#if defined(HAVE_TZNAME)
+extern char *tzname[2];
+#endif
+
+/* Types of padding for numbers in date and time. */
+enum padding
+{
+ none, blank, zero
+};
+
+static char const* const days[] =
+{
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+};
+
+static char const * const months[] =
+{
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"
+};
+
+/* Add character C to STRING and increment LENGTH,
+ unless LENGTH would exceed MAX. */
+
+#define add_char(c) \
+ do \
+ { \
+ if (length + 1 <= max) \
+ string[length++] = (c); \
+ } \
+ while (0)
+
+/* Add a 2 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num2 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Add a 3 digit number to STRING, padding if specified.
+ Return the number of characters added, up to MAX. */
+
+static int
+add_num3 (string, num, max, pad)
+ char *string;
+ int num;
+ int max;
+ enum padding pad;
+{
+ int top = num / 100;
+ int mid = (num - top * 100) / 10;
+ int length = 0;
+
+ if (top == 0 && pad == blank)
+ add_char (' ');
+ else if (top != 0 || pad == zero)
+ add_char (top + '0');
+ if (mid == 0 && top == 0 && pad == blank)
+ add_char (' ');
+ else if (mid != 0 || top != 0 || pad == zero)
+ add_char (mid + '0');
+ add_char (num % 10 + '0');
+ return length;
+}
+
+/* Like strncpy except return the number of characters copied. */
+
+static int
+add_str (to, from, max)
+ char *to;
+ const char *from;
+ int max;
+{
+ int i;
+
+ for (i = 0; from[i] && i <= max; ++i)
+ to[i] = from[i];
+ return i;
+}
+
+static int
+add_num_time_t (string, max, num)
+ char *string;
+ int max;
+ time_t num;
+{
+ /* This buffer is large enough to hold the character representation
+ (including the trailing NUL) of any unsigned decimal quantity
+ whose binary representation fits in 128 bits. */
+ char buf[40];
+ int length;
+
+ if (sizeof (num) > 16)
+ abort ();
+ sprintf (buf, "%lu", (unsigned long) num);
+ length = add_str (string, buf, max);
+ return length;
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Sundays. */
+
+static int
+sun_week (tm)
+ struct tm *tm;
+{
+ int dl;
+
+ /* Set `dl' to the day in the year of the last day of the week previous
+ to the one containing the day specified in TM. If the day specified
+ in TM is in the first week of the year, `dl' will be negative or 0.
+ Otherwise, calculate the number of complete weeks before our week
+ (dl / 7) and add any partial week at the start of the year (dl % 7). */
+ dl = tm->tm_yday - tm->tm_wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+/* Return the week in the year of the time in TM, with the weeks
+ starting on Mondays. */
+
+static int
+mon_week (tm)
+ struct tm *tm;
+{
+ int dl, wday;
+
+ if (tm->tm_wday == 0)
+ wday = 6;
+ else
+ wday = tm->tm_wday - 1;
+ dl = tm->tm_yday - wday;
+ return dl <= 0 ? 0 : dl / 7 + (dl % 7 != 0);
+}
+
+#if !defined(HAVE_TM_ZONE) && !defined(HAVE_TZNAME)
+char *
+zone_name (tp)
+ struct tm *tp;
+{
+ char *timezone ();
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday (&tv, &tz);
+ return timezone (tz.tz_minuteswest, tp->tm_isdst);
+}
+#endif
+
+/* Format the time given in TM according to FORMAT, and put the
+ results in STRING.
+ Return the number of characters (not including terminating null)
+ that were put into STRING, or 0 if the length would have
+ exceeded MAX. */
+
+size_t
+strftime (string, max, format, tm)
+ char *string;
+ size_t max;
+ const char *format;
+ const struct tm *tm;
+{
+ enum padding pad; /* Type of padding to apply. */
+ size_t length = 0; /* Characters put in STRING so far. */
+
+ for (; *format && length < max; ++format)
+ {
+ if (*format != '%')
+ add_char (*format);
+ else
+ {
+ ++format;
+ /* Modifiers: */
+ if (*format == '-')
+ {
+ pad = none;
+ ++format;
+ }
+ else if (*format == '_')
+ {
+ pad = blank;
+ ++format;
+ }
+ else
+ pad = zero;
+
+ switch (*format)
+ {
+ /* Literal character fields: */
+ case 0:
+ case '%':
+ add_char ('%');
+ break;
+ case 'n':
+ add_char ('\n');
+ break;
+ case 't':
+ add_char ('\t');
+ break;
+ default:
+ add_char (*format);
+ break;
+
+ /* Time fields: */
+ case 'H':
+ case 'k':
+ length +=
+ add_num2 (&string[length], tm->tm_hour, max - length,
+ *format == 'H' ? pad : blank);
+ break;
+ case 'I':
+ case 'l':
+ {
+ int hour12;
+
+ if (tm->tm_hour == 0)
+ hour12 = 12;
+ else if (tm->tm_hour > 12)
+ hour12 = tm->tm_hour - 12;
+ else
+ hour12 = tm->tm_hour;
+ length +=
+ add_num2 (&string[length], hour12, max - length,
+ *format == 'I' ? pad : blank);
+ }
+ break;
+ case 'M':
+ length +=
+ add_num2 (&string[length], tm->tm_min, max - length, pad);
+ break;
+ case 'p':
+ if (tm->tm_hour < 12)
+ add_char ('A');
+ else
+ add_char ('P');
+ add_char ('M');
+ break;
+ case 'r':
+ length +=
+ strftime (&string[length], max - length, "%I:%M:%S %p", tm);
+ break;
+ case 'R':
+ length +=
+ strftime (&string[length], max - length, "%H:%M", tm);
+ break;
+
+ case 's':
+ {
+ struct tm writable_tm;
+ writable_tm = *tm;
+ length += add_num_time_t (&string[length], max - length,
+ mktime (&writable_tm));
+ }
+ break;
+
+ case 'S':
+ length +=
+ add_num2 (&string[length], tm->tm_sec, max - length, pad);
+ break;
+ case 'T':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'X':
+ length +=
+ strftime (&string[length], max - length, "%H:%M:%S", tm);
+ break;
+ case 'Z':
+#ifdef HAVE_TM_ZONE
+ length += add_str (&string[length], tm->tm_zone, max - length);
+#else
+#ifdef HAVE_TZNAME
+ if (tm->tm_isdst && tzname[1] && *tzname[1])
+ length += add_str (&string[length], tzname[1], max - length);
+ else
+ length += add_str (&string[length], tzname[0], max - length);
+#else
+ length += add_str (&string[length], zone_name (tm), max - length);
+#endif
+#endif
+ break;
+
+ /* Date fields: */
+ case 'a':
+ add_char (days[tm->tm_wday][0]);
+ add_char (days[tm->tm_wday][1]);
+ add_char (days[tm->tm_wday][2]);
+ break;
+ case 'A':
+ length +=
+ add_str (&string[length], days[tm->tm_wday], max - length);
+ break;
+ case 'b':
+ case 'h':
+ add_char (months[tm->tm_mon][0]);
+ add_char (months[tm->tm_mon][1]);
+ add_char (months[tm->tm_mon][2]);
+ break;
+ case 'B':
+ length +=
+ add_str (&string[length], months[tm->tm_mon], max - length);
+ break;
+ case 'c':
+ length +=
+ strftime (&string[length], max - length,
+ "%a %b %d %H:%M:%S %Z %Y", tm);
+ break;
+ case 'C':
+ length +=
+ add_num2 (&string[length], (tm->tm_year + 1900) / 100,
+ max - length, pad);
+ break;
+ case 'd':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, pad);
+ break;
+ case 'e':
+ length +=
+ add_num2 (&string[length], tm->tm_mday, max - length, blank);
+ break;
+ case 'D':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'j':
+ length +=
+ add_num3 (&string[length], tm->tm_yday + 1, max - length, pad);
+ break;
+ case 'm':
+ length +=
+ add_num2 (&string[length], tm->tm_mon + 1, max - length, pad);
+ break;
+ case 'U':
+ length +=
+ add_num2 (&string[length], sun_week (tm), max - length, pad);
+ break;
+ case 'w':
+ add_char (tm->tm_wday + '0');
+ break;
+ case 'W':
+ length +=
+ add_num2 (&string[length], mon_week (tm), max - length, pad);
+ break;
+ case 'x':
+ length +=
+ strftime (&string[length], max - length, "%m/%d/%y", tm);
+ break;
+ case 'y':
+ length +=
+ add_num2 (&string[length], tm->tm_year % 100,
+ max - length, pad);
+ break;
+ case 'Y':
+ add_char ((tm->tm_year + 1900) / 1000 + '0');
+ length +=
+ add_num3 (&string[length],
+ (1900 + tm->tm_year) % 1000, max - length, zero);
+ break;
+ }
+ }
+ }
+ add_char (0);
+ return length - 1;
+}