diff options
Diffstat (limited to 'src/kadmin/cli')
| -rw-r--r-- | src/kadmin/cli/ChangeLog | 28 | ||||
| -rw-r--r-- | src/kadmin/cli/Makefile.in | 19 | ||||
| -rw-r--r-- | src/kadmin/cli/Makefile.ov | 28 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/Makefile | 11 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/Makefile.in | 45 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/configure.in | 15 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/getdate.y | 1006 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/kadmin.c | 958 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/kadmin_ct.ct | 67 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/memmove.c | 144 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/setenv.c | 165 | ||||
| -rw-r--r-- | src/kadmin/cli/attic/ss_wrapper.c | 56 | ||||
| -rw-r--r-- | src/kadmin/cli/configure.in | 20 | ||||
| -rw-r--r-- | src/kadmin/cli/dump.c | 1485 | ||||
| -rw-r--r-- | src/kadmin/cli/getdate.y | 1009 | ||||
| -rw-r--r-- | src/kadmin/cli/kadmin.1 | 473 | ||||
| -rw-r--r-- | src/kadmin/cli/kadmin.c | 1322 | ||||
| -rw-r--r-- | src/kadmin/cli/kadmin_ct.ct | 79 | ||||
| -rw-r--r-- | src/kadmin/cli/keytab.c | 420 | ||||
| -rw-r--r-- | src/kadmin/cli/memmove.c | 144 | ||||
| -rw-r--r-- | src/kadmin/cli/setenv.c | 165 | ||||
| -rw-r--r-- | src/kadmin/cli/ss_wrapper.c | 61 | ||||
| -rw-r--r-- | src/kadmin/cli/strftime.c | 469 |
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 *) ¶ms, 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, + ¶ms.keysalts, + ¶ms.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, + ¶ms, + KADM5_STRUCT_VERSION, + KADM5_API_VERSION_2, + &handle); + else if (use_keytab) + retval = kadm5_init_with_skey(princstr, keytab_name, + KADM5_ADMIN_SERVICE, + ¶ms, + KADM5_STRUCT_VERSION, + KADM5_API_VERSION_2, + &handle); + else + retval = kadm5_init_with_password(princstr, password, + KADM5_ADMIN_SERVICE, + ¶ms, + 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; +} |
