# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # cmd/krb5/kadmin/Makefile include ../../Makefile.cmd SUBDIRS= cli dbutil ktutil kpasswd server kclient kdcmgr all : TARGET= all clean : TARGET= clean clobber : TARGET= clobber delete : TARGET= delete install : TARGET= install catalog : TARGET= catalog package : TARGET= package _msg: TARGET= _msg _msg: $(SUBDIRS) .KEEP_STATE: all clean clobber delete install catalog package: $(SUBDIRS) # install rule for install_h target install: $(SUBDIRS) check: $(CHECKHDRS) $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= kadmin kadmin.local SHFILES= k5srvutil CLOBBERFILES= $(SHFILES) KRB5SBINSHFILES= $(SHFILES:%=$(KRB5SBIN)/%) COMMON_OBJS = kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab.o RMT_OBJS= $(COMMON_OBJS) kadmin_rmt.o # Hammerhead: keytab_loc.o compiled with -D_KADMIN_LOCAL_ to exclude # kadm5_randkey_principal_old (only in libkadm5clnt, not libkadm5srv) LOC_OBJS= kadmin.o kadmin_ct.o ss_wrapper.o getdate.o keytab_loc.o kadmin_loc.o OBJS = $(COMMON_OBJS) $(RMT_OBJS) $(LOC_OBJS) include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = generic.po POFILES = kadmin.po k5srvutil.po DEFS = -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_TIMEB_H=1 \ -DHAVE_ALLOCA_H=1 -DHAVE_FTIME=1 -DHAVE_TIMEZONE CPPFLAGS += -I$(SRC)/uts/common/gssapi/include/ \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/cmd/krb5/iprop \ -I$(SRC)/lib/krb5 \ -I$(SRC)/lib/gss_mechs/mech_krb5/include $(DEFS) CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-unused-function CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-variable # because of labels from yacc getdate.o : CERRWARN += -Wno-unused-label SMATCH=off SHAREDLIBS = -lmech_krb5 -lss # Hammerhead: GNU ld needs rpath-link for transitive deps (libdyn, libkdb) via libkadm5srv LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/krb5 CLLIBS = $(LDLIBS) $(KRUNPATH) $(KERBRUNPATH) \ -L$(ROOT_KLIBDIR) -L$(KRB5LIB) $(SHAREDLIBS) -lkadm5clnt SRVLIBS = $(LDLIBS) $(KRUNPATH) $(KERBRUNPATH) \ -L$(ROOT_KLIBDIR) -L$(KRB5LIB) $(SHAREDLIBS) -lkadm5srv kadmin.local: DEFS += -D_KADMIN_LOCAL_ .KEEP_STATE: all: $(PROG) $(SHFILES) kadmin: $(RMT_OBJS) $(LINK.c) $(RMT_OBJS) -o $@ $(CLLIBS) $(POST_PROCESS) keytab_loc.o: keytab.c $(COMPILE.c) -D_KADMIN_LOCAL_ -o $@ $< $(POST_PROCESS_O) kadmin.local: $(LOC_OBJS) $(LINK.c) $(LOC_OBJS) -o $@ $(SRVLIBS) $(POST_PROCESS) $(SHFILES): $(SHFILES).sh $(RM) $(SHFILES) $(CP) $(SHFILES).sh $(SHFILES) install: $(KRB5SBINPROG) $(KRB5SBINSHFILES) clean: $(RM) $(OBJS) include ../../../Makefile.targ $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ kadmin.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po FRC: /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ %{ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* ** Originally written by Steven M. Bellovin while ** at the University of North Carolina at Chapel Hill. Later tweaked by ** a couple of people on Usenet. Completely overhauled by Rich $alz ** and Jim Berets 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 #else #include "config.h" #endif #endif #include /* 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 #else #ifdef _AIX /* for Bison */ #pragma alloca #else void *alloca (); #endif #endif #endif #include #include #if defined(HAVE_STDLIB_H) #include #endif /* 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 if that will be used. */ #if defined(vms) #include #include #else #include #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif #ifdef timezone #undef timezone /* needed for sgi */ #endif /* ** We use the obsolete `struct my_timeb' as part of our interface! ** Since the system doesn't have it, we define it here; ** our callers must do likewise. */ struct my_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(vms) */ #if defined (STDC_HEADERS) || defined (USG) #include #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. */ #ifndef bcopy #define bcopy(from, to, len) memcpy ((to), (from), (len)) #endif /* * The following is a hack so that it is easy to internationalize * statically declared strings. We define a wrapper function here that * will be a replacement for gettext. We the make gettext a macro that * just returns its argument, which now can be used with statically defined * strings. The conquence of this is that GETTEXT must be used to translate * a string at runtime and gettext must be used around string literals so * that xgettext command can extract them to a portable object database file. * * Thus to translate a string literal that is an argument to a function foo * the following will have to be performed: * * foo(GETTEXT(gettext("This is a test"))); * * The inner gettext call is for xgettext command to extract the string. * The C preprossesor will reduce the above to: * * foo(GETTEXT(("This ia a test")); */ #include static char * GETTEXT(const char *msgid) { return (gettext(msgid)); } #define gettext(s) (s) extern struct tm *gmtime(); extern struct tm *localtime(); #define yyparse getdate_yyparse #define yylex getdate_yylex #define yyerror getdate_yyerror static int getdate_yylex (void); static int getdate_yyerror (char *); #define EPOCH 1970 #define EPOCH_END 2099 /* Solaris 64 bit can support this at this point */ #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 tNEVER %type tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT %type tSEC_UNIT tSNUMBER tUNUMBER tZONE %type tMERIDIAN o_merid %% spec : /* NULL */ | spec item | tNEVER { yyYear = 1970; yyMonth = 1; yyDay = 1; yyHour = yyMinutes = yySeconds = 0; yyDSTmode = DSToff; yyTimezone = 0; /* gmt */ yyHaveDate++; } ; item : time { yyHaveTime++; } | zone { yyHaveZone++; } | date { yyHaveDate++; } | day { yyHaveDay++; } | rel { yyHaveRel++; } ; 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; } ; o_merid : /* NULL */ { $$ = MER24; } | tMERIDIAN { $$ = $1; } ; %% /* Month and day table. */ static TABLE const MonthDayTable[] = { { gettext("january"), tMONTH, 1 }, { gettext("february"), tMONTH, 2 }, { gettext("march"), tMONTH, 3 }, { gettext("april"), tMONTH, 4 }, { gettext("may"), tMONTH, 5 }, { gettext("june"), tMONTH, 6 }, { gettext("july"), tMONTH, 7 }, { gettext("august"), tMONTH, 8 }, { gettext("september"), tMONTH, 9 }, { gettext("sept"), tMONTH, 9 }, { gettext("october"), tMONTH, 10 }, { gettext("november"), tMONTH, 11 }, { gettext("december"), tMONTH, 12 }, { gettext("sunday"), tDAY, 0 }, { gettext("monday"), tDAY, 1 }, { gettext("tuesday"), tDAY, 2 }, { gettext("tues"), tDAY, 2 }, { gettext("wednesday"), tDAY, 3 }, { gettext("wednes"), tDAY, 3 }, { gettext("thursday"), tDAY, 4 }, { gettext("thur"), tDAY, 4 }, { gettext("thurs"), tDAY, 4 }, { gettext("friday"), tDAY, 5 }, { gettext("saturday"), tDAY, 6 }, { NULL } }; /* Time units table. */ static TABLE const UnitsTable[] = { { gettext("year"), tMONTH_UNIT, 12 }, { gettext("month"), tMONTH_UNIT, 1 }, { gettext("fortnight"), tMINUTE_UNIT, 14 * 24 * 60 }, { gettext("week"), tMINUTE_UNIT, 7 * 24 * 60 }, { gettext("day"), tMINUTE_UNIT, 1 * 24 * 60 }, { gettext("hour"), tMINUTE_UNIT, 60 }, { gettext("minute"), tMINUTE_UNIT, 1 }, { gettext("min"), tMINUTE_UNIT, 1 }, { gettext("second"), tSEC_UNIT, 1 }, { gettext("sec"), tSEC_UNIT, 1 }, { NULL } }; /* Assorted relative-time words. */ static TABLE const OtherTable[] = { { gettext("tomorrow"), tMINUTE_UNIT, 1 * 24 * 60 }, { gettext("yesterday"), tMINUTE_UNIT, -1 * 24 * 60 }, { gettext("today"), tMINUTE_UNIT, 0 }, { gettext("now"), tMINUTE_UNIT, 0 }, { gettext("last"), tUNUMBER, -1 }, { gettext("this"), tMINUTE_UNIT, 0 }, { gettext("next"), tUNUMBER, 2 }, { gettext("first"), tUNUMBER, 1 }, /* { gettext("second"), tUNUMBER, 2 }, */ { gettext("third"), tUNUMBER, 3 }, { gettext("fourth"), tUNUMBER, 4 }, { gettext("fifth"), tUNUMBER, 5 }, { gettext("sixth"), tUNUMBER, 6 }, { gettext("seventh"), tUNUMBER, 7 }, { gettext("eighth"), tUNUMBER, 8 }, { gettext("ninth"), tUNUMBER, 9 }, { gettext("tenth"), tUNUMBER, 10 }, { gettext("eleventh"), tUNUMBER, 11 }, { gettext("twelfth"), tUNUMBER, 12 }, { gettext("ago"), tAGO, 1 }, { gettext("never"), tNEVER, 0 }, { NULL } }; /* The timezone table. */ /* Some of these are commented out because a time_t can't store a float. */ static TABLE const TimezoneTable[] = { { gettext("gmt"), tZONE, HOUR( 0) }, /* Greenwich Mean */ { gettext("ut"), tZONE, HOUR( 0) }, /* Universal (Coordinated) */ { gettext("utc"), tZONE, HOUR( 0) }, { gettext("wet"), tZONE, HOUR( 0) }, /* Western European */ { gettext("bst"), tDAYZONE, HOUR( 0) }, /* British Summer */ { gettext("wat"), tZONE, HOUR( 1) }, /* West Africa */ { gettext("at"), tZONE, HOUR( 2) }, /* Azores */ #if 0 /* For completeness. BST is also British Summer, and GST is * also Guam Standard. */ { gettext("bst"), tZONE, HOUR( 3) }, /* Brazil Standard */ { gettext("gst"), tZONE, HOUR( 3) }, /* Greenland Standard */ #endif #if 0 { gettext("nft"), tZONE, HOUR(3.5) }, /* Newfoundland */ { gettext("nst"), tZONE, HOUR(3.5) }, /* Newfoundland Standard */ { gettext("ndt"), tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */ #endif { gettext("ast"), tZONE, HOUR( 4) }, /* Atlantic Standard */ { gettext("adt"), tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */ { gettext("est"), tZONE, HOUR( 5) }, /* Eastern Standard */ { gettext("edt"), tDAYZONE, HOUR( 5) }, /* Eastern Daylight */ { gettext("cst"), tZONE, HOUR( 6) }, /* Central Standard */ { gettext("cdt"), tDAYZONE, HOUR( 6) }, /* Central Daylight */ { gettext("mst"), tZONE, HOUR( 7) }, /* Mountain Standard */ { gettext("mdt"), tDAYZONE, HOUR( 7) }, /* Mountain Daylight */ { gettext("pst"), tZONE, HOUR( 8) }, /* Pacific Standard */ { gettext("pdt"), tDAYZONE, HOUR( 8) }, /* Pacific Daylight */ { gettext("yst"), tZONE, HOUR( 9) }, /* Yukon Standard */ { gettext("ydt"), tDAYZONE, HOUR( 9) }, /* Yukon Daylight */ { gettext("hst"), tZONE, HOUR(10) }, /* Hawaii Standard */ { gettext("hdt"), tDAYZONE, HOUR(10) }, /* Hawaii Daylight */ { gettext("cat"), tZONE, HOUR(10) }, /* Central Alaska */ { gettext("ahst"), tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */ { gettext("nt"), tZONE, HOUR(11) }, /* Nome */ { gettext("idlw"), tZONE, HOUR(12) }, /* International Date Line West */ { gettext("cet"), tZONE, -HOUR(1) }, /* Central European */ { gettext("met"), tZONE, -HOUR(1) }, /* Middle European */ { gettext("mewt"), tZONE, -HOUR(1) }, /* Middle European Winter */ { gettext("mest"), tDAYZONE, -HOUR(1) }, /* Middle European Summer */ { gettext("swt"), tZONE, -HOUR(1) }, /* Swedish Winter */ { gettext("sst"), tDAYZONE, -HOUR(1) }, /* Swedish Summer */ { gettext("fwt"), tZONE, -HOUR(1) }, /* French Winter */ { gettext("fst"), tDAYZONE, -HOUR(1) }, /* French Summer */ { gettext("eet"), tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */ { gettext("bt"), tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */ #if 0 { gettext("it"), tZONE, -HOUR(3.5) },/* Iran */ #endif { gettext("zp4"), tZONE, -HOUR(4) }, /* USSR Zone 3 */ { gettext("zp5"), tZONE, -HOUR(5) }, /* USSR Zone 4 */ #if 0 { gettext("ist"), tZONE, -HOUR(5.5) },/* Indian Standard */ #endif { gettext("zp6"), tZONE, -HOUR(6) }, /* USSR Zone 5 */ #if 0 /* For completeness. NST is also Newfoundland Stanard, and SST is * also Swedish Summer. */ { gettext("nst"), tZONE, -HOUR(6.5) },/* North Sumatra */ { gettext("sst"), tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */ #endif /* 0 */ { gettext("wast"), tZONE, -HOUR(7) }, /* West Australian Standard */ { gettext("wadt"), tDAYZONE, -HOUR(7) }, /* West Australian Daylight */ #if 0 { gettext("jt"), tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */ #endif { gettext("cct"), tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */ { gettext("jst"), tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */ { gettext("kst"), tZONE, -HOUR(9) }, /* Korean Standard */ #if 0 { gettext("cast"), tZONE, -HOUR(9.5) },/* Central Australian Standard */ { gettext("cadt"), tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */ #endif { gettext("east"), tZONE, -HOUR(10) }, /* Eastern Australian Standard */ { gettext("eadt"), tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */ { gettext("gst"), tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */ { gettext("kdt"), tZONE, -HOUR(10) }, /* Korean Daylight */ { gettext("nzt"), tZONE, -HOUR(12) }, /* New Zealand */ { gettext("nzst"), tZONE, -HOUR(12) }, /* New Zealand Standard */ { gettext("nzdt"), tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */ { gettext("idle"), tZONE, -HOUR(12) }, /* International Date Line East */ { 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 */ } /* * From hh:mm:ss [am|pm] mm/dd/yy [tz], compute and return the number * of seconds since 00:00:00 1/1/70 GMT. */ 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 < 1900) Year += 1900; DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 29 : 28; if (Year < EPOCH || Year > EPOCH_END || 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) && ((Year % 100 != 0) || (Year % 400 == 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; time_t ret; if (RelMonth == 0) return 0; tm = localtime(&Start); Month = 12 * tm->tm_year + tm->tm_mon + RelMonth; Year = Month / 12; Month = Month % 12 + 1; ret = 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); if (ret == -1) return ret; return DSTcorrect(Start, ret); } 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((int) *p)) *p = tolower((int) *p); if (strcmp(buff, gettext("am")) == 0 || strcmp(buff, gettext("a.m.")) == 0) { yylval.Meridian = MERam; return tMERIDIAN; } if (strcmp(buff, gettext("pm")) == 0 || strcmp(buff, gettext("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, GETTEXT(tp->name), 3) == 0) { yylval.Number = tp->value; return tp->type; } } else if (strcmp(buff, GETTEXT(tp->name)) == 0) { yylval.Number = tp->value; return tp->type; } } for (tp = TimezoneTable; tp->name; tp++) if (strcmp(buff, GETTEXT(tp->name)) == 0) { yylval.Number = tp->value; return tp->type; } if (strcmp(buff, gettext("dst")) == 0) return tDST; for (tp = UnitsTable; tp->name; tp++) if (strcmp(buff, GETTEXT(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, GETTEXT(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, GETTEXT(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, GETTEXT(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((int) *yyInput)) yyInput++; c = *yyInput; if (isdigit((int) c) || c == '-' || c == '+') { if (c == '-' || c == '+') { sign = c == '-' ? -1 : 1; if (!isdigit((int) (*++yyInput))) /* skip the '-' sign */ continue; } else sign = 0; for (yylval.Number = 0; isdigit((int) (c = *yyInput++)); ) yylval.Number = 10 * yylval.Number + c - '0'; yyInput--; if (sign < 0) yylval.Number = -yylval.Number; return sign ? tSNUMBER : tUNUMBER; } if (isalpha((int) c)) { for (p = buff; isalpha((int) (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); } /* For get_date extern declaration compatibility check... yuck. */ #include #include "kadmin.h" time_t get_date(p) char *p; { struct my_timeb *now = NULL; struct tm *tm, gmt; struct my_timeb ftz; time_t Start; time_t tod; time_t delta; yyInput = p; if (now == NULL) { now = &ftz; ftz.time = time((time_t *) 0); 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; /* * When yyparse returns, zero or more of yyHave{Time,Zone,Date,Day,Rel} * will have been incremented. The value is number of items of * that type that were found; for all but Rel, more than one is * illegal. * * For each yyHave indicator, the following values are set: * * yyHaveTime: * yyHour, yyMinutes, yySeconds: hh:mm:ss specified, initialized * to zeros above * yyMeridian: MERam, MERpm, or MER24 * yyTimeZone: time zone specified in minutes * yyDSTmode: DSToff if yyTimeZone is set, otherwise unchanged * (initialized above to DSTmaybe) * * yyHaveZone: * yyTimezone: as above * yyDSTmode: DSToff if a non-DST zone is specified, otherwise DSTon * XXX don't understand interaction with yyHaveTime zone info * * yyHaveDay: * yyDayNumber: 0-6 for Sunday-Saturday * yyDayOrdinal: val specified with day ("second monday", * Ordinal=2), otherwise 1 * * yyHaveDate: * yyMonth, yyDay, yyYear: mm/dd/yy specified, initialized to * today above * * yyHaveRel: * yyRelSeconds: seconds specified with MINUTE_UNITs ("3 hours") or * SEC_UNITs ("30 seconds") * yyRelMonth: months specified with MONTH_UNITs ("3 months", "1 * year") * * The code following yyparse turns these values into a single * date stamp. */ if (yyparse() || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) return -1; /* * If an absolute time specified, set Start to the equivalent Unix * timestamp. Otherwise, set Start to now, and if we do not have * a relatime time (ie: only yyHaveZone), decrement Start to the * beginning of today. * * By having yyHaveDay in the "absolute" list, "next Monday" means * midnight next Monday. Otherwise, "next Monday" would mean the * time right now, next Monday. It's not clear to me why the * current behavior is preferred. */ 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; } /* * Add in the relative time specified. RelativeMonth adds in the * months, accounting for the fact that the actual length of "3 * months" depends on where you start counting. * * XXX By having this separate from the previous block, we are * allowing dates like "10:00am 3 months", which means 3 months * from 10:00am today, or even "1/1/99 two days" which means two * days after 1/1/99. * * XXX Shouldn't this only be done if yyHaveRel, just for * thoroughness? */ Start += yyRelSeconds; delta = RelativeMonth(Start, yyRelMonth); if (delta == (time_t) -1) return -1; Start += delta; /* * Now, if you specified a day of week and counter, add it in. By * disallowing Date but allowing Time, you can say "5pm next * monday". * * XXX The yyHaveDay && !yyHaveDate restriction should be enforced * above and be able to cause failure. */ 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(gettext("Enter date, or blank line to exit.\n\t> ")); (void)fflush(stdout); while (gets(buff) && buff[0]) { d = get_date(buff, (struct my_timeb *)NULL); if (d == -1) (void)printf( gettext("Bad format - couldn't convert.\n")); else (void)printf("%s", ctime(&d)); (void)printf("\t> "); (void)fflush(stdout); } exit(0); /* NOTREACHED */ } #endif /* defined(TEST) */ #!/bin/sh # # # Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # TEXTDOMAIN=SUNW_OST_OSCMD export TEXTDOMAIN # list_princs keytab # returns a list of principals in the keytab # sorted and uniquified list_princs() { klist -k $keytab | tail +4 | awk '{print $2}' | sort | uniq } set_command() { if [ x$command != x ] ; then cmd_error `gettext "Only one command can be specified"` usage exit 1 fi command=$1 } #interactive_prompt prompt princ # If in interactive mode return true if the principal should be acted on # otherwise return true all the time # # SUNW14resync: If in interactive mode the default is now to return false # i.e. if in interactive mode unless the user types "Yes" or # "yes" false will be returned. # interactive_prompt() { if [ $interactive = 0 ] ; then return 0 fi PROMPT=`gettext "%s for %s? [yes no] "` Y1=`gettext "yes"` Y2=`gettext "Yes"` printf "$PROMPT" "$1" "$2" read ans case $ans in ${Y1}|${Y2}) return 0 ;; esac return 1 } cmd_error() { echo $@ 2>&1 } usage() { USAGE=`gettext "Usage: $0 [-i] [-f file] list|change|delete|delold"` echo $USAGE } change_key() { princs=`list_princs ` for princ in $princs; do ACTION=`gettext "Change key"` if interactive_prompt "$ACTION" $princ; then kadmin -k -t $keytab -p $princ -q "ktadd -k $keytab $princ" fi done } delete_old_keys() { princs=`list_princs ` for princ in $princs; do ACTION=`gettext "Delete old keys"` if interactive_prompt "$ACTION" $princ; then kadmin -k -t $keytab -p $princ -q "ktrem -k $keytab $princ old" fi done } delete_keys() { interactive=1 princs=`list_princs ` for princ in $princs; do ACTION=`gettext "Delete all keys"` if interactive_prompt "$ACTION" $princ; then kadmin -p $princ -k -t $keytab -q "ktrem -k $keytab $princ all" fi done } keytab=/etc/krb5/krb5.keytab interactive=0 CHANGE=`gettext "change"` DELOLD=`gettext "delold"` DELETE=`gettext "delete"` LIST=`gettext "list"` while [ $# -gt 0 ] ; do opt=$1 shift case $opt in "-f") keytab=$1 shift ;; "-i") interactive=1 ;; ${CHANGE}|${DELOLD}|${DELETE}|${LIST}) set_command $opt ;; *) ILLEGAL=`gettext "Illegal option: "` cmd_error $ILLEGAL $opt usage exit 1 ;; esac done case $command in $CHANGE) change_key ;; $DELOLD) delete_old_keys ;; $DELETE) delete_keys ;; $LIST) klist -k $keytab ;; *) usage ;; esac /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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 #include #include #include #include #include #include #include /* #include */ #include #include "kadmin.h" #include #include /* * Solaris: the following are needed for paging */ #include #include /* command name when called "locally" (i.e. non-networked client ) */ #define KADMIN_LOCAL_NAME "kadmin.local" /* functions defined in remote/local specific files */ extern void usage(const char *); /* 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 }, {"support_desmd5", 14, KRB5_KDB_SUPPORT_DESMD5, 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 */ "SUPPORT_DESMD5", /* 0x00004000 */ "NEW_PRINC", /* 0x00008000 */ }; char *getenv(); int exit_status = 0; char *def_realm = NULL; char *whoami = NULL; void *handle = NULL; krb5_context context; char *ccache_name = NULL; int locked = 0; static char *strdur(duration) time_t duration; { static char out[50]; int neg, days, hours, minutes, seconds; if (duration < 0) { duration *= -1; neg = 1; } else neg = 0; days = duration / (24 * 3600); duration %= 24 * 3600; hours = duration / 3600; duration %= 3600; minutes = duration / 60; duration %= 60; seconds = duration; snprintf(out, sizeof (out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "", days, days == 1 ? gettext("day") : gettext("days"), hours, minutes, seconds); return out; } static char *strdate(when) krb5_timestamp when; { struct tm *tm; static char out[40]; time_t lcltim = when; tm = localtime(&lcltim); strftime(out, sizeof(out), gettext("%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 */ static krb5_error_code kadmin_parse_name(name, principal) char *name; krb5_principal *principal; { char *cp, *fullname; krb5_error_code retval; if (name == NULL) return (EINVAL); /* 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 + 1, '@'); } if (cp == NULL) { strcat(fullname, "@"); strcat(fullname, def_realm); } retval = krb5_parse_name(context, fullname, principal); free(fullname); return retval; } static void extended_com_err_fn (const char *myprog, errcode_t code, const char *fmt, va_list args) { if (code) { const char *emsg; emsg = krb5_get_error_message (context, code); fprintf (stderr, "%s: %s ", myprog, emsg); krb5_free_error_message (context, emsg); } else { fprintf (stderr, "%s: ", myprog); } vfprintf (stderr, fmt, args); fprintf (stderr, "\n"); } char *kadmin_startup(argc, argv) int argc; char *argv[]; { 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; char **db_args = NULL; int db_args_size = 0; char *db_name = NULL; char *svcname = NULL; memset((char *) ¶ms, 0, sizeof(params)); if (strcmp (whoami, "kadmin.local") == 0) set_com_err_hook(extended_com_err_fn); retval = kadm5_init_krb5_context(&context); if (retval) { com_err(whoami, retval, gettext("while initializing krb5 library")); exit(1); } while ((optchar = getopt(argc, argv, "x:r:p:kq:w:d:s:mc:t:e:ON")) != EOF) { switch (optchar) { case 'x': db_args_size++; { char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); if (temp == NULL) { fprintf(stderr, gettext("%s: Cannot initialize. Not enough memory\n"), argv[0]); exit(1); } db_args = temp; } db_args[db_args_size-1] = optarg; db_args[db_args_size] = NULL; break; 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': /* now db_name is not a seperate argument. It has to be passed as part of the db_args */ if (!db_name) { db_name = malloc(strlen(optarg) + sizeof("dbname=")); } else { db_name = realloc(db_name, strlen(optarg) + sizeof("dbname=")); } strcpy(db_name, "dbname="); strcat(db_name, optarg); db_args_size++; { char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ if (temp == NULL) { fprintf(stderr, gettext("%s: Cannot initialize. Not enough memory\n"), argv[0]); exit(1); } db_args = temp; } db_args[db_args_size-1] = db_name; db_args[db_args_size] = NULL; 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, gettext("while parsing keysalts %s"), optarg); exit(1); } params.mask |= KADM5_CONFIG_ENCTYPES; break; case 'O': /* Undocumented option for testing only */ svcname = KADM5_ADMIN_SERVICE_P; break; default: usage(whoami); } } if ((ccache_name && use_keytab) || (keytab_name && !use_keytab)) usage(whoami); if (def_realm == NULL && krb5_get_default_realm(context, &def_realm)) { if (freeprinc) free(princstr); fprintf(stderr, gettext("%s: unable to get default realm\n"), whoami); exit(1); } params.mask |= KADM5_CONFIG_REALM; params.realm = def_realm; if (svcname == NULL) { if (kadm5_get_adm_host_srv_name(context, def_realm, &svcname)) { fprintf(stderr, gettext("%s: unable to get host based " "service name for realm %s\n"), whoami, def_realm); if (freeprinc) free(princstr); exit(1); } } /* * 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, gettext("while opening default " "credentials cache")); exit(1); } } else { if ((retval = krb5_cc_resolve(context, ccache_name, &cc))) { com_err(whoami, retval, gettext("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, gettext("while canonicalizing principal name")); krb5_free_principal(context, princ); exit(1); } krb5_free_principal(context, princ); freeprinc++; } else if (use_keytab != 0) { if ((retval = krb5_sname_to_principal(context, NULL, "host", KRB5_NT_SRV_HST, &princ))) { com_err(whoami, retval, gettext("creating host service principal")); exit(1); } if ((retval = krb5_unparse_name(context, princ, &princstr))) { com_err(whoami, retval, gettext("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, gettext("%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+1, '@'); } if (realm) *realm++ = '\0'; cp = strchr(canon, '/'); while (cp) { if (cp - canon && *(cp - 1) != '\\') break; else cp = strchr(cp+1, '/'); } if (cp != NULL) *cp = '\0'; princstr = (char*)malloc(strlen(canon) + 6 /* "/admin" */ + (realm ? 1 + strlen(realm) : 0) + 1); if (princstr == NULL) { fprintf(stderr, gettext("%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, gettext("%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, gettext("%s: out of memory\n"), whoami); exit(1); } strcpy(princstr, pw->pw_name); strcat(princstr, "/admin@"); strcat(princstr, def_realm); freeprinc++; } else { fprintf(stderr, gettext("%s: unable to figure out " "a principal name\n"), whoami); exit(1); } } retval = krb5_klog_init(context, "admin_server", whoami, 0); if (retval) { com_err(whoami, retval, "while setting up logging"); exit(1); } /* * Initialize the kadm5 connection. If we were given a ccache, * use it. Otherwise, use/prompt for the password. */ /* Solaris Kerberos: * Send warnings to stderr */ if (ccache_name) { fprintf(stderr, gettext("Authenticating as principal %s with existing credentials.\n"), princstr); retval = kadm5_init_with_creds(princstr, cc, svcname, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, db_args, &handle); } else if (use_keytab) { if (keytab_name) fprintf(stderr, gettext("Authenticating as principal %s with keytab %s.\n"), princstr, keytab_name); else fprintf(stderr, gettext("Authenticating as principal %s with default keytab.\n"), princstr); retval = kadm5_init_with_skey(princstr, keytab_name, svcname, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, db_args, &handle); } else { fprintf(stderr, gettext("Authenticating as principal %s with password.\n"), princstr); retval = kadm5_init_with_password(princstr, password, svcname, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, db_args, &handle); } if (retval) { if (retval == KADM5_RPC_ERROR_CANTENCODEARGS || retval == KADM5_RPC_ERROR_CANTDECODEARGS) { com_err(whoami, KADM5_RPC_ERROR, gettext("while initializing %s interface"), whoami); /* privacy-enabled mech probably not installed/configed */ com_err(whoami, retval, gettext("."), whoami); } else { com_err(whoami, retval, gettext("while initializing %s interface"), whoami); if (retval == KADM5_BAD_CLIENT_PARAMS || retval == KADM5_BAD_SERVER_PARAMS) usage(whoami); } exit(1); } if (freeprinc) free(princstr); if (db_name) free(db_name), db_name=NULL; if (db_args) free(db_args), db_args=NULL; if ((retval = krb5_cc_close(context, cc))) { com_err(whoami, retval, gettext("while closing ccache %s"), ccache_name); exit(1); } /* register the WRFILE keytab type and set it as the default */ { #define DEFAULT_KEYTAB "WRFILE:/etc/krb5/krb5.keytab" /* XXX krb5_defkeyname is an internal library global and should go away */ extern char *krb5_defkeyname; krb5_defkeyname = DEFAULT_KEYTAB; } if ((retval = kadm5_init_iprop(handle)) != 0) { com_err(whoami, retval, gettext("while mapping update log")); exit(1); } /* Solaris kerberos: fix memory leak */ if (svcname) free(svcname); return query; } int quit() { kadm5_ret_t retval; if (locked) { retval = kadm5_unlock(handle); if (retval) { com_err("quit", retval, gettext("while unlocking locked database")); return 1; } locked = 0; } kadm5_destroy(handle); if (ccache_name != NULL) { fprintf(stderr, gettext("\n\a\a\aAdministration credentials " "NOT DESTROYED.\n")); } /* insert more random cleanup here */ krb5_klog_close(context); krb5_free_context(context); context = NULL; return 0; } void kadmin_lock(argc, argv) int argc; char *argv[]; { kadm5_ret_t retval; if (locked) return; retval = kadm5_lock(handle); if (retval) { com_err("lock", retval, ""); return; } locked = 1; } void kadmin_unlock(argc, argv) int argc; char *argv[]; { kadm5_ret_t retval; if (!locked) return; retval = kadm5_unlock(handle); if (retval) { com_err("unlock", retval, ""); return; } locked = 0; } void kadmin_delprinc(argc, argv) int argc; char *argv[]; { kadm5_ret_t retval; krb5_principal princ; char *canon; char reply[32]; if (! (argc == 2 || (argc == 3 && !strcmp("-force", argv[1])))) { fprintf(stderr, "%s: delete_principal [-force] %s\n", gettext("usage"), gettext("principal")); return; } retval = kadmin_parse_name(argv[argc - 1], &princ); if (retval) { com_err("delete_principal", retval, gettext("while parsing principal name")); return; } retval = krb5_unparse_name(context, princ, &canon); if (retval) { com_err("delete_principal", retval, gettext("while canonicalizing principal")); krb5_free_principal(context, princ); return; } if (argc == 2) { printf(gettext("Are you sure you want to delete " "the principal \"%s\"? (yes/no): "), canon); fgets(reply, sizeof (reply), stdin); if (strncmp(gettext("yes\n"), reply, sizeof (reply)) && strncmp(gettext("y\n"), reply, sizeof (reply)) && strncmp(gettext("Y\n"), reply, sizeof (reply))) { fprintf(stderr, gettext("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, gettext("while deleting principal \"%s\""), canon); free(canon); return; } printf(gettext("Principal \"%s\" deleted.\n"), canon); printf(gettext("Make sure that you have removed this principal " "from all ACLs before reusing.\n")); free(canon); 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; char *pwarg = NULL; int n_ks_tuple = 0, randkey = 0; krb5_boolean keepold = FALSE; krb5_key_salt_tuple *ks_tuple = NULL; krb5_principal princ; char **db_args = NULL; int db_args_size = 0; int local_kadmin = 0; local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0); if (argc < 2) { goto usage; } for (argv++, argc--; argc > 1; argc--, argv++) { if (!strcmp("-x", *argv)) { argc--; if (argc < 1) { fprintf(stderr, gettext("change_password: missing db argument\n")); goto usage; } db_args_size++; { char **temp = realloc(db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ if (temp == NULL) { fprintf(stderr, gettext("change_password: Not enough memory\n")); free(db_args), db_args = NULL; exit(1); } db_args = temp; } db_args[db_args_size-1] = *++argv; db_args[db_args_size] = NULL; continue; } if (!strcmp("-pw", *argv)) { argc--; if (argc < 1) { fprintf(stderr, "change_password: %s", gettext("missing password arg\n")); goto usage; } pwarg = *++argv; continue; } if (!strcmp("-randkey", *argv)) { randkey++; continue; } if (!strcmp("-keepold", *argv)) { keepold = TRUE; continue; } if (!strcmp("-e", *argv)) { argc--; if (argc < 1) { fprintf(stderr, "change_password: %s", gettext("missing keysaltlist arg\n")); goto usage; } retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0, &ks_tuple, &n_ks_tuple); if (retval) { com_err("change_password", retval, gettext("while parsing keysalts %s"), *argv); return; } continue; } goto usage; } if (*argv == NULL) { com_err("change_password", 0, "missing principal name"); goto usage; } retval = kadmin_parse_name(*argv, &princ); if (retval) { com_err("change_password", retval, gettext("while parsing principal name")); if (ks_tuple != NULL) free(ks_tuple); if (db_args) free(db_args); goto usage; } retval = krb5_unparse_name(context, princ, &canon); if (retval) { com_err("change_password", retval, gettext("while canonicalizing principal")); krb5_free_principal(context, princ); if (ks_tuple != NULL) free(ks_tuple); if (db_args) free(db_args); return; } if (pwarg != NULL) { if (keepold || ks_tuple != NULL) { retval = kadm5_chpass_principal_3(handle, princ, keepold, n_ks_tuple, ks_tuple, pwarg); if (ks_tuple != NULL) free(ks_tuple); } else { retval = kadm5_chpass_principal(handle, princ, pwarg); } krb5_free_principal(context, princ); if (retval) { com_err("change_password", retval, gettext("while changing password for \"%s\"."), canon); free(canon); if (db_args) free(db_args); return; } printf(gettext("Password for \"%s\" changed.\n"), canon); free(canon); if (db_args) free(db_args); return; } else if (randkey) { if (keepold || ks_tuple != NULL || local_kadmin) { retval = kadm5_randkey_principal_3(handle, princ, keepold, n_ks_tuple, ks_tuple, NULL, NULL); if (ks_tuple != NULL) free(ks_tuple); } else { retval = kadm5_randkey_principal(handle, princ, NULL, NULL); } krb5_free_principal(context, princ); if (retval) { com_err("change_password", retval, gettext("while randomizing key for \"%s\"."), canon); free(canon); if (db_args) free(db_args); return; } printf(gettext("Key for \"%s\" randomized.\n"), canon); free(canon); if (db_args) free(db_args); return; } else if (argc == 1) { unsigned int i = sizeof (newpw) - 1; snprintf(prompt1, sizeof (prompt1), gettext("Enter password for principal \"%.900s\""), *argv); snprintf(prompt2, sizeof (prompt2), gettext("Re-enter password for principal \"%.900s\""), *argv); retval = krb5_read_password(context, prompt1, prompt2, newpw, &i); if (retval) { com_err("change_password", retval, gettext("while reading password for \"%s\"."), canon); free(canon); if (ks_tuple != NULL) free(ks_tuple); krb5_free_principal(context, princ); if (db_args) free(db_args); return; } if (keepold || ks_tuple != NULL) { retval = kadm5_chpass_principal_3(handle, princ, keepold, n_ks_tuple, ks_tuple, newpw); if (ks_tuple != NULL) free(ks_tuple); } else { retval = kadm5_chpass_principal(handle, princ, newpw); } krb5_free_principal(context, princ); memset(newpw, 0, sizeof (newpw)); if (retval) { com_err("change_password", retval, gettext("while changing password for \"%s\"."), canon); free(canon); if (db_args) free(db_args); return; } printf(gettext("Password for \"%s\" changed.\n"), canon); free(canon); if (db_args) free(db_args); return; } else { free(canon); krb5_free_principal(context, princ); usage: if (ks_tuple != NULL) free(ks_tuple); fprintf(stderr, "%s: change_password [-randkey] [-keepold] " "[-e keysaltlist] [-pw password] %s\n", gettext("usage"), gettext("principal")); return; } } static void kadmin_free_tl_data(kadm5_principal_ent_t princ) { krb5_tl_data *tl_data = princ->tl_data; int n_tl_data = princ->n_tl_data; int i; princ->n_tl_data = 0; princ->tl_data = NULL; for (i = 0; tl_data && (i < n_tl_data); i++) { krb5_tl_data *next = tl_data->tl_data_next; if (tl_data->tl_data_contents) free(tl_data->tl_data_contents); free(tl_data); tl_data = next; } } #define KRB5_TL_DB_ARGS 0x7fff static int kadmin_parse_princ_args(argc, argv, oprinc, mask, pass, randkey, ks_tuple, n_ks_tuple, caller) int argc; char *argv[]; kadm5_principal_ent_t oprinc; long *mask; char **pass; int *randkey; krb5_key_salt_tuple **ks_tuple; int *n_ks_tuple; char *caller; { int i, j, attrib_set; time_t date; time_t now; krb5_error_code retval; krb5_tl_data *tl_data, *tail = NULL; *mask = 0; *pass = NULL; *n_ks_tuple = 0; *ks_tuple = NULL; time(&now); *randkey = 0; for (i = 1; i < argc - 1; i++) { attrib_set = 0; if (strlen(argv[i]) == 2 && !strcmp("-x",argv[i])) { if (++i > argc - 2) return -1; tl_data = malloc(sizeof(krb5_tl_data)); if (tl_data == NULL) { fprintf(stderr, gettext("Not enough memory\n")); return ENOMEM; } memset(tl_data, 0, sizeof(krb5_tl_data)); tl_data->tl_data_type = KRB5_TL_DB_ARGS; tl_data->tl_data_length = strlen(argv[i])+1; tl_data->tl_data_contents = (unsigned char*)strdup(argv[i]); if (tail) { tail->tl_data_next = tl_data; } else { oprinc->tl_data = tl_data; } tail = tl_data; oprinc->n_tl_data++; if (tl_data->tl_data_contents == NULL) { fprintf(stderr, gettext("Not enough memory\n")); return ENOMEM; } *mask |= KADM5_TL_DATA; continue; } if (strlen(argv[i]) == 7 && !strcmp("-expire", argv[i])) { if (++i > argc - 2) return -1; else { date = get_date(argv[i]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date " "specification " "\"%s\".\n"), argv[i]); return -1; } oprinc->princ_expire_time = 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]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date " "specification " "\"%s\".\n"), argv[i]); return -1; } oprinc->pw_expiration = date; *mask |= KADM5_PW_EXPIRATION; continue; } } if (strlen(argv[i]) == 8 && !strcmp("-maxlife", argv[i])) { if (++i > argc - 2) return -1; else { date = get_date(argv[i]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date " "specification " "\"%s\".\n"), argv[i]); return -1; } oprinc->max_life = date - now; *mask |= KADM5_MAX_LIFE; continue; } } if (strlen(argv[i]) == 13 && !strcmp("-maxrenewlife", argv[i])) { if (++i > argc - 2) return -1; else { date = get_date(argv[i]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date " "specification " "\"%s\".\n"), argv[i]); return -1; } oprinc->max_renewable_life = date - now; *mask |= KADM5_MAX_RLIFE; 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; } if (!strcmp("-e", argv[i])) { if (++i > argc - 2) return -1; else { retval = krb5_string_to_keysalts(argv[i], ", \t", ":.-", 0, ks_tuple, n_ks_tuple); if (retval) { com_err(caller, retval, gettext("while parsing keysalts %s"), argv[i]); return -1; } } 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) { return -1; } retval = kadmin_parse_name(argv[i], &oprinc->principal); if (retval) { com_err(caller, retval, gettext("while parsing principal")); return -1; } return 0; } static void kadmin_addprinc_usage(func) char *func; { fprintf(stderr, "%s: %s %s\n", gettext("usage"), func, gettext("[options] principal")); fprintf(stderr, gettext("\toptions are:\n")); fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] " "[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] " "[-randkey] [-pw password]\n\t\t[-maxrenewlife maxrenewlife] " "[-e keysaltlist] [{+|-}attribute]\n"); fprintf(stderr, gettext("\tattributes are:\n")); fprintf(stderr, "%s%s%s", "\t\tallow_postdated allow_forwardable allow_tgs_req " "allow_renewable\n", "\t\tallow_proxiable allow_dup_skey allow_tix " "requires_preauth\n", "\t\trequires_hwauth needchange allow_svr " "password_changing_service\n"); } static void kadmin_modprinc_usage(func) char *func; { fprintf(stderr, "%s: %s %s\n", gettext("usage"), func, gettext("[options] principal")); fprintf(stderr, gettext("\toptions are:\n")); fprintf(stderr, "\t\t[-expire expdate] [-pwexpire pwexpdate] " "[-maxlife maxtixlife]\n\t\t[-kvno kvno] [-policy policy] " "[-clearpolicy]\n\t\t[-maxrenewlife maxrenewlife] " "[{+|-}attribute]\n"); fprintf(stderr, gettext("\tattributes are:\n")); fprintf(stderr, "%s%s%s", "\t\tallow_postdated allow_forwardable allow_tgs_req " "allow_renewable\n", "\t\tallow_proxiable allow_dup_skey allow_tix " "requires_preauth\n", "\t\trequires_hwauth needchange allow_svr " "password_changing_service\n"); } void kadmin_addprinc(argc, argv) int argc; char *argv[]; { kadm5_principal_ent_rec princ, dprinc; kadm5_policy_ent_rec defpol; long mask; int randkey = 0, i; int n_ks_tuple; krb5_key_salt_tuple *ks_tuple; char *pass, *canon; krb5_error_code retval; static char newpw[1024], dummybuf[256]; static char prompt1[1024], prompt2[1024]; int local_kadmin = 0; local_kadmin = (strcmp(whoami, KADMIN_LOCAL_NAME) == 0); if (dummybuf[0] == 0) { for (i = 0; i < 256; i++) dummybuf[i] = (i+1) % 256; } /* Zero all fields in request structure */ memset(&princ, 0, sizeof(princ)); memset(&dprinc, 0, sizeof(dprinc)); princ.attributes = dprinc.attributes = 0; if (kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass, &randkey, &ks_tuple, &n_ks_tuple, "add_principal")) { kadmin_addprinc_usage("add_principal"); kadmin_free_tl_data(&princ); /* need to free ks_tuple also??? */ return; } retval = krb5_unparse_name(context, princ.principal, &canon); if (retval) { com_err("add_principal", retval, gettext("while canonicalizing principal")); krb5_free_principal(context, princ.principal); if (ks_tuple != NULL) free(ks_tuple); kadmin_free_tl_data(&princ); return; } /* * If -policy was not specified, and -clearpolicy was not * specified, and the policy "default" exists, assign it. If * -clearpolicy was specified, then KADM5_POLICY_CLR should be * unset, since it is never valid for kadm5_create_principal. */ if ((! (mask & KADM5_POLICY)) && (! (mask & KADM5_POLICY_CLR))) { if (! kadm5_get_policy(handle, "default", &defpol)) { fprintf(stderr, gettext("NOTICE: no policy specified for %s; assigning \"default\"\n"), canon); princ.policy = "default"; mask |= KADM5_POLICY; (void) kadm5_free_policy_ent(handle, &defpol); } else fprintf(stderr, gettext("WARNING: no policy specified for %s; defaulting to no policy\n"), canon); } mask &= ~KADM5_POLICY_CLR; /* * Set 'notix' for randkey principals and also for principals which have * specified flag options on the cmdline. This is because we want to apply * generic flag settings from 'default_principal_flags' first (during * principal creation), followed by a kadm5_modify_principal() which * correctly applies the cli flag options. So, we do *not* want any tix * issued in the interim. */ if (randkey || (mask & KADM5_ATTRIBUTES)) princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; if (randkey) { mask |= KADM5_ATTRIBUTES; pass = dummybuf; } else if (pass == NULL) { unsigned int sz = sizeof (newpw) - 1; snprintf(prompt1, sizeof (prompt1), gettext("Enter password for principal \"%.900s\""), canon); snprintf(prompt2, sizeof (prompt1), gettext("Re-enter password for principal \"%.900s\""), canon); retval = krb5_read_password(context, prompt1, prompt2, newpw, &sz); if (retval) { com_err("add_principal", retval, gettext("while reading password for \"%s\"."), canon); free(canon); krb5_free_principal(context, princ.principal); kadmin_free_tl_data(&princ); return; } pass = newpw; } mask |= KADM5_PRINCIPAL; /* * If the client being used is local, always use the new * API so we get the full set of enctype support. */ if (ks_tuple != NULL || local_kadmin) { retval = kadm5_create_principal_3(handle, &princ, mask, n_ks_tuple, ks_tuple, pass); } else { retval = kadm5_create_principal(handle, &princ, mask, pass); } if (retval) { com_err("add_principal", retval, gettext("while creating \"%s\"."), canon); krb5_free_principal(context, princ.principal); free(canon); if (ks_tuple != NULL) free(ks_tuple); kadmin_free_tl_data(&princ); return; } if (randkey) { /* more special stuff for -randkey */ if (ks_tuple != NULL || local_kadmin) { retval = kadm5_randkey_principal_3(handle, princ.principal, FALSE, n_ks_tuple, ks_tuple, NULL, NULL); } else { retval = kadm5_randkey_principal(handle, princ.principal, NULL, NULL); } if (retval) { com_err("add_principal", retval, gettext("while randomizing key for \"%s\"."), canon); krb5_free_principal(context, princ.principal); free(canon); if (ks_tuple != NULL) free(ks_tuple); kadmin_free_tl_data(&princ); return; } } /* * We now retrieve the intersection set of the generic flag settings and * the ones specified on the cli & re-parse the princ args, just to make * sure we account for conflicts between 'default_principal_flags' and * the cmdline flag args. While we are here, also clear 'notix'. */ if (randkey || (mask & KADM5_ATTRIBUTES)) { retval = kadm5_get_principal(handle, princ.principal, &dprinc, KADM5_PRINCIPAL_NORMAL_MASK); if (retval == 0) { if (dprinc.attributes != 0) princ.attributes = dprinc.attributes; } else { com_err("add_principal", retval, gettext("while doing a get_principal on \"%s\"."), canon); printf(gettext("\nWarning: Principal \"%s\" could have incomplete " "flag settings, as a result of a failed get_principal.\n" "Check the 'default_principal_flags' setting in kdc.conf(5).\n" "If there is a mismatch, use modprinc in kadmin(8) to rectify " "the same.\n\n"), canon); } /* * Solaris Kerberos: We unset KRB5_KDB_DISALLOW_ALL_TIX before * kadmin_parse_princ_args is called, because -allow_tix may * have been an argument. We still have to unset here because * kadmin_parse_princ_args will not reset the attribute unless * it is was explicity defined. */ princ.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX; (void) kadmin_parse_princ_args(argc, argv, &princ, &mask, &pass, &randkey, &ks_tuple, &n_ks_tuple, "add_principal"); mask = KADM5_ATTRIBUTES; retval = kadm5_modify_principal(handle, &princ, mask); if (retval) { com_err("add_principal", retval, gettext("while doing a modify_principal to restore flag " "settings for \"%s\"."), canon); krb5_free_principal(context, princ.principal); free(canon); if (ks_tuple != NULL) free(ks_tuple); kadmin_free_tl_data(&princ); return; } } krb5_free_principal(context, princ.principal); printf(gettext("Principal \"%s\" created.\n"), canon); if (ks_tuple != NULL) free(ks_tuple); free(canon); kadmin_free_tl_data(&princ); } 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; int n_ks_tuple = 0; krb5_key_salt_tuple *ks_tuple; if (argc < 2) { kadmin_modprinc_usage("modify_principal"); return; } memset(&oldprinc, 0, sizeof(oldprinc)); memset(&princ, 0, sizeof(princ)); retval = kadmin_parse_name(argv[argc - 1], &kprinc); if (retval) { com_err("modify_principal", retval, gettext("while parsing principal")); return; } retval = krb5_unparse_name(context, kprinc, &canon); if (retval) { com_err("modify_principal", retval, gettext("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, gettext("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, &ks_tuple, &n_ks_tuple, "modify_principal"); if (ks_tuple != NULL) { free(ks_tuple); kadmin_modprinc_usage("modify_principal"); free(canon); kadmin_free_tl_data(&princ); return; } if (retval) { kadmin_modprinc_usage("modify_principal"); free(canon); kadmin_free_tl_data(&princ); return; } if (randkey) { fprintf(stderr, "modify_principal: -randkey %s ", gettext("not allowed\n")); krb5_free_principal(context, princ.principal); free(canon); kadmin_free_tl_data(&princ); return; } if (pass) { fprintf(stderr, "modify_principal: -pw %s change_password\n", gettext("not allowed; use")); krb5_free_principal(context, princ.principal); free(canon); kadmin_free_tl_data(&princ); return; } retval = kadm5_modify_principal(handle, &princ, mask); krb5_free_principal(context, princ.principal); if (retval) { com_err("modify_principal", retval, gettext("while modifying \"%s\"."), canon); free(canon); kadmin_free_tl_data(&princ); return; } printf(gettext("Principal \"%s\" modified.\n"), canon); kadmin_free_tl_data(&princ); 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, "%s: get_principal [-terse] %s\n", gettext("usage"), gettext("principal")); return; } memset(&dprinc, 0, sizeof(dprinc)); memset(&princ, 0, sizeof(princ)); retval = kadmin_parse_name(argv[argc - 1], &princ); if (retval) { com_err("get_principal", retval, gettext("while parsing principal")); return; } retval = krb5_unparse_name(context, princ, &canon); if (retval) { com_err("get_principal", retval, gettext("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, gettext("while retrieving \"%s\"."), canon); free(canon); return; } retval = krb5_unparse_name(context, dprinc.mod_name, &modcanon); if (retval) { com_err("get_principal", retval, gettext("while unparsing modname")); kadm5_free_principal_ent(handle, &dprinc); free(canon); return; } if (argc == 2) { printf(gettext("Principal: %s\n"), canon); printf(gettext("Expiration date: %s\n"), dprinc.princ_expire_time ? strdate(dprinc.princ_expire_time) : gettext("[never]")); printf(gettext("Last password change: %s\n"), dprinc.last_pwd_change ? strdate(dprinc.last_pwd_change) : gettext("[never]")); printf(gettext("Password expiration date: %s\n"), dprinc.pw_expiration ? strdate(dprinc.pw_expiration) : gettext("[none]")); printf(gettext("Maximum ticket life: %s\n"), strdur(dprinc.max_life)); printf(gettext("Maximum renewable life: %s\n"), strdur(dprinc.max_renewable_life)); printf(gettext("Last modified: %s (%s)\n"), strdate(dprinc.mod_date), modcanon); printf(gettext("Last successful authentication: %s\n"), dprinc.last_success ? strdate(dprinc.last_success) : gettext("[never]")); printf(gettext("Last failed authentication: %s\n"), dprinc.last_failed ? strdate(dprinc.last_failed) : gettext("[never]")); printf(gettext("Failed password attempts: %d\n"), dprinc.fail_auth_count); printf(gettext("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))) snprintf(enctype, sizeof (enctype), gettext(""), 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))) snprintf(salttype, sizeof(salttype), gettext(""), key_data->key_data_type[1]); printf("%s\n", salttype); } else printf(gettext("no salt\n")); } printf(gettext("Attributes:")); for (i = 0; i < sizeof (prflags) / sizeof (char *); i++) { if (dprinc.attributes & (krb5_flags) 1 << i) printf(" %s", prflags[i]); } printf("\n"); printf(gettext("Policy: %s\n"), dprinc.policy ? dprinc.policy : gettext("[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.policy : gettext("[none]"), 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 *expr, **names; int i, count; FILE *output; int fd; struct sigaction nsig, osig; sigset_t nmask, omask; int waitb; expr = NULL; if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) { fprintf(stderr, "%s: get_principals %s\n", gettext("usage"), gettext("[expression]")); return; } retval = kadm5_get_principals(handle, expr, &names, &count); if (retval) { com_err("get_principals", retval, gettext("while retrieving list.")); return; } /* * Solaris: the following code is used for paging */ sigemptyset(&nmask); sigaddset(&nmask, SIGINT); sigprocmask(SIG_BLOCK, &nmask, &omask); nsig.sa_handler = SIG_IGN; sigemptyset(&nsig.sa_mask); nsig.sa_flags = 0; sigaction(SIGINT, &nsig, &osig); fd = ss_pager_create(); output = fdopen(fd, "w"); sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); for (i = 0; i < count; i++) fprintf(output, "%s\n", names[i]); fclose(output); wait(&waitb); /* Solaris Kerberos: * Restore the original handler for SIGINT */ if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { perror("sigaction"); } kadm5_free_name_list(handle, names, count); } static 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; 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]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date specification \"%s\".\n"), argv[i]); return -1; } policy->pw_max_life = 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]); if (date == (time_t)-1) { fprintf(stderr, gettext("Invalid date specification \"%s\".\n"), argv[i]); return -1; } policy->pw_min_life = 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, gettext("%s: parser lost count!\n"), caller); return -1; } else return 0; } static void kadmin_addmodpol_usage(func) char *func; { fprintf(stderr, "%s: %s %s\n", gettext("usage"), func, gettext("[options] policy")); fprintf(stderr, gettext("\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; memset(&policy, 0, sizeof(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, gettext("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; memset(&policy, 0, sizeof(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, gettext("while modifying policy \"%s\"."), policy.policy); return; } } return; } void kadmin_delpol(argc, argv) int argc; char *argv[]; { krb5_error_code retval; char reply[32]; if (! (argc == 2 || (argc == 3 && !strcmp("-force", argv[1])))) { fprintf(stderr, "%s: delete_policy [-force] %s\n", gettext("usage"), gettext("policy")); return; } if (argc == 2) { printf(gettext("Are you sure you want to delete the policy " "\"%s\"? (yes/no): "), argv[1]); fgets(reply, sizeof (reply), stdin); if (strncmp(gettext("yes\n"), reply, sizeof (reply)) && strncmp(gettext("y\n"), reply, sizeof (reply)) && strncmp(gettext("Y\n"), reply, sizeof (reply)) ) { fprintf(stderr, gettext("Policy \"%s\" not deleted.\n"), argv[1]); return; } } retval = kadm5_delete_policy(handle, argv[argc - 1]); if (retval) { com_err("delete_policy:", retval, gettext("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, "%s: get_policy [-terse] %s\n", gettext("usage"), gettext("policy")); return; } retval = kadm5_get_policy(handle, argv[argc - 1], &policy); if (retval) { com_err("get_policy", retval, gettext("while retrieving policy \"%s\"."), argv[argc - 1]); return; } if (argc == 2) { printf(gettext("Policy: %s\n"), policy.policy); printf(gettext("Maximum password life: %ld\n"), policy.pw_max_life); printf(gettext("Minimum password life: %ld\n"), policy.pw_min_life); printf(gettext("Minimum password length: %ld\n"), policy.pw_min_length); printf(gettext("Minimum number of password " "character classes: %ld\n"), policy.pw_min_classes); printf(gettext("Number of old keys kept: %ld\n"), policy.pw_history_num); printf(gettext("Reference count: %ld\n"), policy.policy_refcnt); } else { printf("\"%s\"\t%ld\t%ld\t%ld\t%ld\t%ld\t%ld\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 *expr, **names; int i, count; /* Solaris Kerberos: * Use a pager for listing policies (similar to listing princs) */ FILE *output = NULL; int fd; struct sigaction nsig, osig; sigset_t nmask, omask; int waitb; expr = NULL; if (! (argc == 1 || (argc == 2 && (expr = argv[1])))) { fprintf(stderr, "%s: get_policies %s\n", gettext("usage"), gettext("[expression]\n")); return; } retval = kadm5_get_policies(handle, expr, &names, &count); if (retval) { com_err("get_policies", retval, gettext("while retrieving list.")); return; } if (sigemptyset(&nmask) == -1) { perror("sigemptyset"); kadm5_free_name_list(handle, names, count); return; } if (sigaddset(&nmask, SIGINT) == -1) { perror("sigaddset"); kadm5_free_name_list(handle, names, count); return; } if (sigemptyset(&nsig.sa_mask) == -1) { perror("sigemptyset"); kadm5_free_name_list(handle, names, count); return; } if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) { perror("sigprocmask"); kadm5_free_name_list(handle, names, count); return; } nsig.sa_handler = SIG_IGN; nsig.sa_flags = 0; if (sigaction(SIGINT, &nsig, &osig) == -1) { perror("sigaction"); if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { perror("sigprocmask"); } kadm5_free_name_list(handle, names, count); return; } fd = ss_pager_create(); if (fd == -1) { fprintf(stderr, "%s: failed to create pager\n", whoami); if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { perror("sigprocmask"); } if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { perror("sigaction"); } kadm5_free_name_list(handle, names, count); return; } output = fdopen(fd, "w"); if (output == NULL) { perror("fdopen"); } if (sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0) == -1) { perror("sigprocmask"); } if (output != NULL) { for (i = 0; i < count; i++) fprintf(output, "%s\n", names[i]); } if (output != NULL && fclose(output) != 0) { perror("fclose"); } if (wait(&waitb) == -1) { perror("wait"); } if (sigaction(SIGINT, &osig, (struct sigaction *)0) == -1) { perror("sigaction"); } kadm5_free_name_list(handle, names, count); } /* * kadmin/cli/kadmin.h * * Copyright 2001 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * Prototypes for kadmin functions called from SS library. */ #ifndef __KADMIN_H__ #define __KADMIN_H__ /* It would be nice if ss produced a header file we could reference */ extern char *kadmin_startup(int argc, char *argv[]); extern int quit (void); extern void kadmin_lock(int argc, char *argv[]); extern void kadmin_unlock(int argc, char *argv[]); extern void kadmin_delprinc(int argc, char *argv[]); extern void kadmin_cpw(int argc, char *argv[]); extern void kadmin_addprinc(int argc, char *argv[]); extern void kadmin_modprinc(int argc, char *argv[]); extern void kadmin_getprinc(int argc, char *argv[]); extern void kadmin_getprincs(int argc, char *argv[]); extern void kadmin_addpol(int argc, char *argv[]); extern void kadmin_modpol(int argc, char *argv[]); extern void kadmin_delpol(int argc, char *argv[]); extern void kadmin_getpol(int argc, char *argv[]); extern void kadmin_getpols(int argc, char *argv[]); extern void kadmin_getprivs(int argc, char *argv[]); extern void kadmin_keytab_add(int argc, char *argv[]); extern void kadmin_keytab_remove(int argc, char *argv[]); #ifdef TIME_WITH_SYS_TIME #include #include #else #ifdef HAVE_SYS_TIME_H #include #else #include #endif #endif extern time_t get_date(char *); /* Yucky global variables */ extern krb5_context context; extern char *krb5_defkeyname; extern char *whoami; extern void *handle; #endif /* __KADMIN_H__ */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* kadmin_ct.c - automatically generated from kadmin_ct.ct */ /* Above no longer appears to be true */ /* * I18n hack. We sill define gettext(s) to be s here. That way the info_strings * will be extracted to the .po file. */ #define gettext(s) s #include #ifndef __STDC__ #define const #endif static char const * const ssu00001[] = { "add_principal", "addprinc", "ank", (char const *)0 }; extern void kadmin_addprinc __SS_PROTO; static char const * const ssu00002[] = { "delete_principal", "delprinc", (char const *)0 }; extern void kadmin_delprinc __SS_PROTO; static char const * const ssu00003[] = { "modify_principal", "modprinc", (char const *)0 }; extern void kadmin_modprinc __SS_PROTO; static char const * const ssu00004[] = { "change_password", "cpw", (char const *)0 }; extern void kadmin_cpw __SS_PROTO; static char const * const ssu00005[] = { "get_principal", "getprinc", (char const *)0 }; extern void kadmin_getprinc __SS_PROTO; static char const * const ssu00006[] = { "list_principals", "listprincs", "get_principals", "getprincs", (char const *)0 }; extern void kadmin_getprincs __SS_PROTO; static char const * const ssu00007[] = { "add_policy", "addpol", (char const *)0 }; extern void kadmin_addpol __SS_PROTO; static char const * const ssu00008[] = { "modify_policy", "modpol", (char const *)0 }; extern void kadmin_modpol __SS_PROTO; static char const * const ssu00009[] = { "delete_policy", "delpol", (char const *)0 }; extern void kadmin_delpol __SS_PROTO; static char const * const ssu00010[] = { "get_policy", "getpol", (char const *)0 }; extern void kadmin_getpol __SS_PROTO; static char const * const ssu00011[] = { "list_policies", "listpols", "get_policies", "getpols", (char const *)0 }; extern void kadmin_getpols __SS_PROTO; static char const * const ssu00012[] = { "get_privs", "getprivs", (char const *)0 }; extern void kadmin_getprivs __SS_PROTO; static char const * const ssu00013[] = { "ktadd", "xst", (char const *)0 }; extern void kadmin_keytab_add __SS_PROTO; static char const * const ssu00014[] = { "ktremove", "ktrem", (char const *)0 }; extern void kadmin_keytab_remove __SS_PROTO; static char const * const ssu00015[] = { "lock", (char const *)0 }; extern void kadmin_lock __SS_PROTO; static char const * const ssu00016[] = { "unlock", (char const *)0 }; extern void kadmin_unlock __SS_PROTO; static char const * const ssu00017[] = { "list_requests", "lr", "?", (char const *)0 }; extern void ss_list_requests __SS_PROTO; static char const * const ssu00018[] = { "quit", "exit", "q", (char const *)0 }; extern void ss_quit __SS_PROTO; static ss_request_entry ssu00019[] = { { ssu00001, kadmin_addprinc, gettext("Add principal"), 0 }, { ssu00002, kadmin_delprinc, gettext("Delete principal"), 0 }, { ssu00003, kadmin_modprinc, gettext("Modify principal"), 0 }, { ssu00004, kadmin_cpw, gettext("Change password"), 0 }, { ssu00005, kadmin_getprinc, gettext("Get principal"), 0 }, { ssu00006, kadmin_getprincs, gettext("List principals"), 0 }, { ssu00007, kadmin_addpol, gettext("Add policy"), 0 }, { ssu00008, kadmin_modpol, gettext("Modify policy"), 0 }, { ssu00009, kadmin_delpol, gettext("Delete policy"), 0 }, { ssu00010, kadmin_getpol, gettext("Get policy"), 0 }, { ssu00011, kadmin_getpols, gettext("List policies"), 0 }, { ssu00012, kadmin_getprivs, gettext("Get privileges"), 0 }, { ssu00013, kadmin_keytab_add, gettext("Add entry(s) to a keytab"), 0 }, { ssu00014, kadmin_keytab_remove, gettext("Remove entry(s) from a keytab"), 0 }, { ssu00015, kadmin_lock, gettext("Lock database exclusively (use with extreme caution!)"), 0 }, { ssu00016, kadmin_unlock, gettext("Release exclusive database lock"), 0 }, { ssu00017, ss_list_requests, gettext("List available requests."), 0 }, { ssu00018, ss_quit, gettext("Exit program."), 0 }, { 0, 0, 0, 0 } }; ss_request_table kadmin_cmds = { 2, ssu00019 }; #undef gettext /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Contains kadmin.local specific code. */ #include #include #include #include #include void usage(char *whoami) { fprintf(stderr, "%s: %s [-r realm] [-p principal] [-q query] " "[-d dbname] [-e \"enc:salt ...\"] [-m] [-D]\n", gettext("Usage"), whoami); exit(1); } /* * Debugging function * Turns on low level debugging in db module * Requires that db library be compiled with -DDEBUG_DB flag */ /* ARGSUSED */ void debugEnable(int displayMsgs) { #if DEBUG_DB debugDisplayDB(displayMsgs); #endif #if DEBUG /* Solaris Kerberos: not supported */ /* debugDisplaySS(displayMsgs); */ #endif } void kadmin_getprivs(argc, argv) int argc; char *argv[]; { static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE", "LIST", "CHANGEPW"}; krb5_error_code retval; int i; long plist; /* for kadmin.local return all privilages */ printf(gettext("current privileges:")); for (i = 0; i < sizeof (privs) / 4; i++) { printf(" %s", gettext(privs[i])); } printf("\n"); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Contains remote client specific code. */ #include #include #include #include #include extern void *handle; void usage(char *whoami) { fprintf(stderr, "%s: %s [-r realm] [-p principal] [-q query] " "[-s admin_server[:port]] [[-c ccache]|[-k [-t keytab]]" "|[-w password]]\n", gettext("Usage"), whoami); exit(1); } /* * Debugging function - for remote admin client */ /* ARGSUSED */ void debugEnable(int displayMsgs) { #ifdef DEBUG /* Solaris Kerberos: not supported */ /* debugDisplaySS(displayMsgs); */ #endif } void kadmin_getprivs(argc, argv) int argc; char *argv[]; { static char *privs[] = {"GET", "ADD", "MODIFY", "DELETE", "LIST", "CHANGE"}; krb5_error_code retval; int i; long plist; if (argc != 1) { fprintf(stderr, "%s: get_privs\n", gettext("usage")); return; } retval = kadm5_get_privs(handle, &plist); if (retval) { com_err("get_privs", retval, gettext("while retrieving privileges")); return; } printf(gettext("current privileges:")); for (i = 0; i < sizeof (privs) / sizeof (char *); i++) { if (plist & 1 << i) printf(" %s", gettext(privs[i])); } printf("\n"); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * * $Id: keytab.c,v 1.28 2004/05/31 12:39:16 epeisach Exp $ * $Source: /cvs/krbdev/krb5/src/kadmin/cli/keytab.c,v $ */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * 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 FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if !defined(lint) && !defined(__CODECENTER__) static char *rcsid = "$Header: /cvs/krbdev/krb5/src/kadmin/cli/keytab.c,v 1.28 2004/05/31 12:39:16 epeisach Exp $"; #endif #include #include #include #include #include #include #include "kadmin.h" #include static int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, 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); static char *etype_istring(krb5_enctype enctype); static int quiet; static void add_usage() { fprintf(stderr, "%s: %s\n", gettext("Usage"), "ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] " "[principal | -glob princ-exp] [...]\n"); } static void rem_usage() { fprintf(stderr, "%s: %s\n", gettext("Usage"), "ktremove [-k[eytab] keytab] [-q] principal " "[kvno|\"all\"|\"old\"]\n"); } static int process_keytab(krb5_context my_context, char **keytab_str, krb5_keytab *keytab) { int code; char buf[BUFSIZ]; if (*keytab_str == NULL) { if (code = krb5_kt_default(my_context, keytab)) { com_err(whoami, code, gettext("while opening default keytab")); return 1; } if (code = krb5_kt_get_name(my_context, *keytab, buf, BUFSIZ)) { com_err(whoami, code, gettext("while retrieving keytab name")); return 1; } if (!(*keytab_str = strdup(buf))) { com_err(whoami, ENOMEM, gettext("while creating keytab name")); return 1; } } else { if (strchr(*keytab_str, ':') != NULL) { *keytab_str = strdup(*keytab_str); if (*keytab_str == NULL) { com_err(whoami, ENOMEM, gettext("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, gettext("while creating keytab name")); return 1; } sprintf(*keytab_str, "WRFILE:%s", tmp); } code = krb5_kt_resolve(my_context, *keytab_str, keytab); if (code != 0) { com_err(whoami, code, gettext("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 *keytab_str = NULL, **princs; int code, num, i; krb5_error_code retval; int n_ks_tuple = 0; krb5_boolean keepold = FALSE; krb5_key_salt_tuple *ks_tuple = NULL; argc--; argv++; quiet = 0; 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 if (strcmp(*argv, "-e") == 0) { argc--; if (argc < 1) { add_usage(); return; } retval = krb5_string_to_keysalts(*++argv, ", \t", ":.-", 0, &ks_tuple, &n_ks_tuple); if (retval) { com_err("ktadd", retval, gettext("while parsing keysalts %s"), *argv); return; } } 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; } code = kadm5_get_principals(handle, *argv, &princs, &num); if (code) { com_err(whoami, code, gettext("while expanding expression " "\"%s\"."), *argv); argv++; continue; } for (i = 0; i < num; i++) (void) add_principal(handle, keytab_str, keytab, keepold, n_ks_tuple, ks_tuple, princs[i]); kadm5_free_name_list(handle, princs, num); } else (void) add_principal(handle, keytab_str, keytab, keepold, n_ks_tuple, ks_tuple, *argv); argv++; } code = krb5_kt_close(context, keytab); if (code != 0) com_err(whoami, code, gettext("while closing keytab")); free(keytab_str); } void kadmin_keytab_remove(int argc, char **argv) { krb5_keytab keytab = 0; char *keytab_str = NULL; int code; argc--; argv++; quiet = 0; 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, gettext("while closing keytab")); free(keytab_str); } static int add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *princ_str) { kadm5_principal_ent_rec princ_rec; krb5_principal princ; krb5_keytab_entry new_entry; krb5_keyblock *keys; int code, nkeys, i; int nktypes = 0; krb5_key_salt_tuple *permitted_etypes = NULL; (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, gettext("while parsing -add principal name %s"), princ_str); goto cleanup; } if (ks_tuple == NULL) { krb5_enctype *ptr, *ktypes = NULL; code = krb5_get_permitted_enctypes(context, &ktypes); if (!code && ktypes && *ktypes) { krb5_int32 salttype; /* * Count the results. This is stupid, the API above * should have included an output param to indicate * the size of the list that is returned. */ for (ptr = ktypes; *ptr; ptr++) nktypes++; /* Allocate a new key-salt tuple set */ permitted_etypes = (krb5_key_salt_tuple *)malloc ( sizeof (krb5_key_salt_tuple) * nktypes); if (permitted_etypes == NULL) { free(ktypes); return (ENOMEM); } /* * Because the keysalt parameter doesn't matter for * keys stored in the keytab, use the default "normal" * salt for all keys */ (void) krb5_string_to_salttype("normal", &salttype); for (i = 0; i < nktypes; i++) { permitted_etypes[i].ks_enctype = ktypes[i]; permitted_etypes[i].ks_salttype = salttype; } free(ktypes); } else { if (ktypes) free(ktypes); goto cleanup; } } else { permitted_etypes = ks_tuple; nktypes = n_ks_tuple; } code = kadm5_randkey_principal_3(lhandle, princ, keepold, nktypes, permitted_etypes, &keys, &nkeys); #ifndef _KADMIN_LOCAL_ /* this block is not needed in the kadmin.local client */ /* * If the above call failed, we may be talking to an older * admin server, so try the older API. */ if (code == KADM5_RPC_ERROR) { code = kadm5_randkey_principal_old(handle, princ, &keys, &nkeys); } #endif /* !KADMIN_LOCAL */ if (code != 0) { if (code == KADM5_UNK_PRINC) { fprintf(stderr, gettext("%s: Principal %s does not exist.\n"), whoami, princ_str); /* Solaris Kerberos: Better error messages */ } else if (code == KRB5_BAD_ENCTYPE) { int i, et; fprintf(stderr, gettext("%s: Error from the remote system: " "%s while changing %s's key\n"), whoami, error_message(code), princ_str); if (nktypes) { et = permitted_etypes[0].ks_enctype; fprintf(stderr, gettext("%s: Encryption types " "requested: %s (%d)"), whoami, etype_istring(et), et); for (i = 1; i < nktypes; i++) { et = permitted_etypes[i].ks_enctype; fprintf(stderr, ", %s (%d)", etype_istring(et), et); } fprintf(stderr, "\n"); } } else { com_err(whoami, code, gettext("while changing %s's key"), princ_str); } goto cleanup; } code = kadm5_get_principal(lhandle, princ, &princ_rec, KADM5_PRINCIPAL_NORMAL_MASK); if (code != 0) { com_err(whoami, code, gettext("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, gettext("while adding key to keytab")); (void) kadm5_free_principal_ent(lhandle, &princ_rec); goto cleanup; } if (!quiet) printf(gettext("Entry for principal %s with kvno %d, " "encryption type %s added to keytab %s.\n"), princ_str, princ_rec.kvno, etype_string(keys[i].enctype), keytab_str); } code = kadm5_free_principal_ent(lhandle, &princ_rec); if (code != 0) { com_err(whoami, code, gettext("while freeing principal entry")); goto cleanup; } cleanup: if (nkeys) { for (i = 0; i < nkeys; i++) krb5_free_keyblock_contents(context, &keys[i]); free(keys); } if (princ) krb5_free_principal(context, princ); if (permitted_etypes != NULL && ks_tuple == NULL) free(permitted_etypes); 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, did_something; krb5_kvno kvno; code = krb5_parse_name(context, princ_str, &princ); if (code != 0) { com_err(whoami, code, gettext("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, gettext("%s: Keytab %s does not exist.\n"), whoami, keytab_str); } else if (code == KRB5_KT_NOTFOUND) { if (mode != SPEC) fprintf(stderr, gettext("%s: No entry for principal " "%s exists in keytab %s\n"), whoami, princ_str, keytab_str); else fprintf(stderr, gettext("%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, gettext("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, gettext("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, gettext("while temporarily " "ending keytab scan")); return code; } code = krb5_kt_remove_entry(context, keytab, &entry); if (code != 0) { com_err(whoami, code, gettext("while deleting entry " "from keytab")); return code; } code = krb5_kt_start_seq_get(context, keytab, &cursor); if (code != 0) { com_err(whoami, code, gettext("while restarting keytab scan")); return code; } did_something++; if (!quiet) printf(gettext("Entry for principal " "%s with kvno %d " "removed from keytab %s.\n"), princ_str, entry.vno, keytab_str); } krb5_kt_free_entry(context, &entry); } if (code && code != KRB5_KT_END) { com_err(whoami, code, gettext("while scanning keytab")); return code; } if ((code = krb5_kt_end_seq_get(context, keytab, &cursor))) { com_err(whoami, code, gettext("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, gettext("%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[100]; krb5_error_code ret; if ((ret = krb5_enctype_to_string(enctype, buf, sizeof(buf)))) sprintf(buf, "etype %d", enctype); return buf; } /* Solaris Kerberos */ static char *etype_istring(krb5_enctype enctype) { static char buf[100]; krb5_error_code ret; if ((ret = krb5_enctype_to_istring(enctype, buf, sizeof(buf)))) sprintf(buf, "unknown", enctype); return (buf); } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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 #include #include #include #include #include #include "kadmin.h" extern ss_request_table kadmin_cmds; extern int exit_status; 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]); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); 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, gettext("creating invocation")); exit(1); } (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if (request) { code = ss_execute_line(sci_idx, request); if (code != 0) { ss_perror(sci_idx, code, request); exit_status++; } } else retval = ss_listen(sci_idx); return quit() ? 1 : exit_status; } # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= kdb5_util OBJS = kdb5_util.o \ kdb5_create.o kadm5_create.o string_table.o kdb5_stash.o \ kdb5_destroy.o ovload.o strtok.o dump.o SRCS = $(OBJS:.o=.c) CLOBBERFILES += $(TESTPROG) ISRCHDR= iprop.h KRB5IPROPDIR= $(SRC)/cmd/krb5/iprop include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(PROG).po POFILES = generic.po CPPFLAGS += -I. -I$(SRC)/lib/gss_mechs/mech_krb5/include/kerberosIV \ -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/lib/gss_mechs/mech_krb5/include/krb5 \ -I$(SRC)/lib/krb5 \ -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(KRB5IPROPDIR) \ -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_GETCWD=1 \ -DHAVE_STRSTR=1 -DHAVE_COMPILE=1 -DHAVE_STEP=1 \ -DHAVE_KRB_DB_H=1 -DHAVE_KDC_H=1 -DKDB4_DISABLE \ -DUSE_KADM5_API_VERSION=2 CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-variable CERRWARN += -Wno-unused-function CERRWARN += -Wno-implicit-function-declaration # Hammerhead: Suppress pointer/int cast warnings in legacy code CERRWARN += -Wno-pointer-to-int-cast CERRWARN += -Wno-int-to-pointer-cast # not linted SMATCH=off LDFLAGS += $(KRUNPATH) $(KERBRUNPATH) # Hammerhead: GNU ld needs rpath-link for transitive deps (libdyn, libkdb) via libkadm5srv LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/krb5 LDLIBS += -L $(ROOT_KLIBDIR) -L $(KRB5LIB) -lkadm5srv -lkdb \ -lmech_krb5 -lnsl .KEEP_STATE: all: $(PROG) # Hammerhead: pre-generated (rpcgen + GNU cpp truncation bug) # iprop.h is now a committed source file. # Explicitly state the dependency on iprop.h $(OBJS): $(ISRCHDR) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) install: $(KRB5SBINPROG) clean: $(RM) $(OBJS) @# Hammerhead: do not delete pre-generated $(ISRCHDR) include ../../../Makefile.targ $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po FRC: /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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 */ #include #include #include #include #include #include #include #include "kdb5_util.h" #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP) #include #endif /* HAVE_REGEX_H */ /* * Needed for master key conversion. */ extern krb5_keyblock master_key; extern krb5_principal master_princ; static int mkey_convert; static krb5_keyblock new_master_key; static int backwards; static int recursive; /* * Use compile(3) if no regcomp present. */ #if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H) #define INIT char *sp = instring; #define GETC() (*sp++) #define PEEKC() (*sp) #define UNGETC(c) (--sp) #define RETURN(c) return(c) #define ERROR(c) #define RE_BUF_SIZE 1024 #include #endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */ struct dump_args { char *programname; FILE *ofile; krb5_context kcontext; char **names; int nnames; int verbose; }; static krb5_error_code dump_k5beta_iterator (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_k5beta6_iterator (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_k5beta6_iterator_ext (krb5_pointer, krb5_db_entry *, int); static krb5_error_code dump_iprop_iterator (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_k5beta7_princ (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_k5beta7_princ_ext (krb5_pointer, krb5_db_entry *, int); static krb5_error_code dump_k5beta7_princ_withpolicy (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_iprop_princ (krb5_pointer, krb5_db_entry *); static krb5_error_code dump_ov_princ (krb5_pointer, krb5_db_entry *); static void dump_k5beta7_policy (void *, osa_policy_ent_t); typedef krb5_error_code (*dump_func)(krb5_pointer, krb5_db_entry *); static int process_k5beta_record (char *, krb5_context, FILE *, int, int *); static int process_k5beta6_record (char *, krb5_context, FILE *, int, int *); static int process_k5beta7_record (char *, krb5_context, FILE *, int, int *); static int process_ov_record (char *, krb5_context, FILE *, int, int *); typedef krb5_error_code (*load_func)(char *, krb5_context, FILE *, int, int *); typedef struct _dump_version { char *name; char *header; int updateonly; int create_kadm5; dump_func dump_princ; osa_adb_iter_policy_func dump_policy; load_func load_record; } dump_version; dump_version old_version = { "Kerberos version 5 old format", "kdb5_edit load_dump version 2.0\n", 0, 1, dump_k5beta_iterator, NULL, process_k5beta_record }; dump_version beta6_version = { "Kerberos version 5 beta 6 format", "kdb5_edit load_dump version 3.0\n", 0, 1, dump_k5beta6_iterator, NULL, process_k5beta6_record }; dump_version beta7_version = { "Kerberos version 5", "kdb5_util load_dump version 4\n", 0, 0, dump_k5beta7_princ, dump_k5beta7_policy, process_k5beta7_record }; dump_version iprop_version = { "Kerberos iprop version", "iprop", 0, 0, dump_iprop_princ, dump_k5beta7_policy, process_k5beta7_record }; dump_version ov_version = { "OpenV*Secure V1.0", "OpenV*Secure V1.0\t", 1, 1, dump_ov_princ, dump_k5beta7_policy, process_ov_record }; dump_version r1_3_version = { "Kerberos version 5 release 1.3", "kdb5_util load_dump version 5\n", 0, 0, dump_k5beta7_princ_withpolicy, dump_k5beta7_policy, process_k5beta7_record, }; /* External data */ extern char *current_dbname; extern krb5_boolean dbactive; extern int exit_status; extern krb5_context util_context; extern kadm5_config_params global_params; /* Strings */ #define k5beta_dump_header "kdb5_edit load_dump version 2.0\n" static const char null_mprinc_name[] = "kdb5_dump@MISSING"; /* * We define gettext(s) to be s here, so that xgettext will extract the * strings to the .po file. At the end of the message section we will * undef gettext so that we can use it as a funtion. */ #define gettext(s) s /* Message strings */ static const char regex_err[] = gettext("%s: regular expression error - %s\n"); static const char regex_merr[] = gettext("%s: regular expression match error - %s\n"); static const char pname_unp_err[] = gettext("%s: cannot unparse principal name (%s)\n"); static const char mname_unp_err[] = gettext("%s: cannot unparse modifier name (%s)\n"); static const char nokeys_err[] = gettext("%s: cannot find any standard key for %s\n"); static const char sdump_tl_inc_err[] = gettext("%s: tagged data list inconsistency for %s " "(counted %d, stored %d)\n"); static const char stand_fmt_name[] = gettext("Kerberos version 5"); static const char old_fmt_name[] = gettext("Kerberos version 5 old format"); static const char b6_fmt_name[] = gettext("Kerberos version 5 beta 6 format"); static const char ofopen_error[] = gettext("%s: cannot open %s for writing (%s)\n"); static const char oflock_error[] = gettext("%s: cannot lock %s (%s)\n"); static const char dumprec_err[] = gettext("%s: error performing %s dump (%s)\n"); static const char dumphdr_err[] = gettext("%s: error dumping %s header (%s)\n"); static const char trash_end_fmt[] = gettext("%s(%d): ignoring trash at end of line: "); static const char read_name_string[] = gettext("name string"); static const char read_key_type[] = gettext("key type"); static const char read_key_data[] = gettext("key data"); static const char read_pr_data1[] = gettext("first set of principal attributes"); static const char read_mod_name[] = gettext("modifier name"); static const char read_pr_data2[] = gettext("second set of principal attributes"); static const char read_salt_data[] = gettext("salt data"); static const char read_akey_type[] = gettext("alternate key type"); static const char read_akey_data[] = gettext("alternate key data"); static const char read_asalt_type[] = gettext("alternate salt type"); static const char read_asalt_data[] = gettext("alternate salt data"); static const char read_exp_data[] = gettext("expansion data"); static const char store_err_fmt[] = gettext("%s(%d): cannot store %s(%s)\n"); static const char add_princ_fmt[] = gettext("%s\n"); static const char parse_err_fmt[] = gettext("%s(%d): cannot parse %s (%s)\n"); static const char read_err_fmt[] = gettext("%s(%d): cannot read %s\n"); static const char no_mem_fmt[] = gettext("%s(%d): no memory for buffers\n"); static const char rhead_err_fmt[] = gettext("%s(%d): cannot match size tokens\n"); static const char err_line_fmt[] = gettext("%s: error processing line %d of %s\n"); static const char head_bad_fmt[] = gettext("%s: dump header bad in %s\n"); static const char read_bytecnt[] = gettext("record byte count"); static const char read_encdata[] = gettext("encoded data"); static const char n_name_unp_fmt[] = gettext("%s(%s): cannot unparse name\n"); static const char n_dec_cont_fmt[] = gettext("%s(%s): cannot decode contents\n"); static const char read_nint_data[] = gettext("principal static attributes"); static const char read_tcontents[] = gettext("tagged data contents"); static const char read_ttypelen[] = gettext("tagged data type and length"); static const char read_kcontents[] = gettext("key data contents"); static const char read_ktypelen[] = gettext("key data type and length"); static const char read_econtents[] = gettext("extra data contents"); static const char k5beta_fmt_name[] = gettext("Kerberos version 5 old format"); static const char standard_fmt_name[] = gettext("Kerberos version 5 format"); static const char no_name_mem_fmt[] = gettext("%s: cannot get memory for temporary name\n"); static const char ctx_err_fmt[] = gettext("%s: cannot initialize Kerberos context\n"); static const char stdin_name[] = gettext("standard input"); static const char remaster_err_fmt[] = gettext("while re-encoding keys for principal %s with new master key"); static const char restfail_fmt[] = gettext("%s: %s restore failed\n"); static const char close_err_fmt[] = gettext("%s: cannot close database (%s)\n"); static const char dbinit_err_fmt[] = gettext("%s: cannot initialize database (%s)\n"); static const char dblock_err_fmt[] = gettext("%s: cannot initialize database lock (%s)\n"); static const char dbname_err_fmt[] = gettext("%s: cannot set database name to %s (%s)\n"); static const char dbdelerr_fmt[] = gettext("%s: cannot delete bad database %s (%s)\n"); static const char dbunlockerr_fmt[] = gettext("%s: cannot unlock database %s (%s)\n"); static const char dbrenerr_fmt[] = gettext("%s: cannot rename database %s to %s (%s)\n"); static const char dbcreaterr_fmt[] = gettext("%s: cannot create database %s (%s)\n"); static const char dfile_err_fmt[] = gettext("%s: cannot open %s (%s)\n"); /* * We now return you to your regularly scheduled program. */ #undef gettext static const char oldoption[] = "-old"; static const char b6option[] = "-b6"; static const char b7option[] = "-b7"; static const char ipropoption[] = "-i"; static const char verboseoption[] = "-verbose"; static const char updateoption[] = "-update"; static const char hashoption[] = "-hash"; static const char ovoption[] = "-ov"; static const char dump_tmptrail[] = "~"; /* * Re-encrypt the key_data with the new master key... */ static krb5_error_code master_key_convert(context, db_entry) krb5_context context; krb5_db_entry * db_entry; { krb5_error_code retval; krb5_keyblock v5plainkey, *key_ptr; krb5_keysalt keysalt; int i, j; krb5_key_data new_key_data, *key_data; krb5_boolean is_mkey; is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ); if (is_mkey && db_entry->n_key_data != 1) fprintf(stderr, gettext( "Master key db entry has %d keys, expecting only 1!\n"), db_entry->n_key_data); for (i=0; i < db_entry->n_key_data; i++) { key_data = &db_entry->key_data[i]; retval = krb5_dbekd_decrypt_key_data(context, &master_key, key_data, &v5plainkey, &keysalt); if (retval) return retval; memset(&new_key_data, 0, sizeof(new_key_data)); key_ptr = is_mkey ? &new_master_key : &v5plainkey; retval = krb5_dbekd_encrypt_key_data(context, &new_master_key, key_ptr, &keysalt, key_data->key_data_kvno, &new_key_data); if (retval) return retval; krb5_free_keyblock_contents(context, &v5plainkey); for (j = 0; j < key_data->key_data_ver; j++) { if (key_data->key_data_length[j]) { free(key_data->key_data_contents[j]); } } *key_data = new_key_data; } return 0; } /* * Update the "ok" file. */ void update_ok_file (file_name) char *file_name; { /* handle slave locking/failure stuff */ char *file_ok; int fd; static char ok[]=".dump_ok"; if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1)) == NULL) { com_err(progname, ENOMEM, gettext("while allocating filename " "for update_ok_file")); exit_status++; return; } strcpy(file_ok, file_name); strcat(file_ok, ok); if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) { com_err(progname, errno, gettext("while creating 'ok' file, '%s'"), file_ok); exit_status++; free(file_ok); return; } if (write(fd, "", 1) != 1) { com_err(progname, errno, gettext("while writing to 'ok' file, '%s'"), file_ok); exit_status++; free(file_ok); return; } free(file_ok); close(fd); return; } /* * name_matches() - See if a principal name matches a regular expression * or string. */ static int name_matches(name, arglist) char *name; struct dump_args *arglist; { #if HAVE_REGCOMP regex_t match_exp; regmatch_t match_match; int match_error; char match_errmsg[BUFSIZ]; size_t errmsg_size; #elif HAVE_REGEXP_H char regexp_buffer[RE_BUF_SIZE]; #elif HAVE_RE_COMP extern char *re_comp(); char *re_result; #endif /* HAVE_RE_COMP */ int i, match; /* * Plow, brute force, through the list of names/regular expressions. */ match = (arglist->nnames) ? 0 : 1; for (i=0; innames; i++) { #if HAVE_REGCOMP /* * Compile the regular expression. */ match_error = regcomp(&match_exp, arglist->names[i], REG_EXTENDED); if (match_error) { errmsg_size = regerror(match_error, &match_exp, match_errmsg, sizeof(match_errmsg)); fprintf(stderr, gettext(regex_err), arglist->programname, match_errmsg); break; } /* * See if we have a match. */ match_error = regexec(&match_exp, name, 1, &match_match, 0); if (match_error) { if (match_error != REG_NOMATCH) { errmsg_size = regerror(match_error, &match_exp, match_errmsg, sizeof(match_errmsg)); fprintf(stderr, gettext(regex_merr), arglist->programname, match_errmsg); break; } } else { /* * We have a match. See if it matches the whole * name. */ if ((match_match.rm_so == 0) && (match_match.rm_eo == strlen(name))) match = 1; } regfree(&match_exp); #elif HAVE_REGEXP_H /* * Compile the regular expression. */ compile(arglist->names[i], regexp_buffer, ®exp_buffer[RE_BUF_SIZE], '\0'); if (step(name, regexp_buffer)) { if ((loc1 == name) && (loc2 == &name[strlen(name)])) match = 1; } #elif HAVE_RE_COMP /* * Compile the regular expression. */ if (re_result = re_comp(arglist->names[i])) { fprintf(stderr, gettext(regex_err), arglist->programname, re_result); break; } if (re_exec(name)) match = 1; #else /* HAVE_RE_COMP */ /* * If no regular expression support, then just compare the strings. */ if (!strcmp(arglist->names[i], name)) match = 1; #endif /* HAVE_REGCOMP */ if (match) break; } return(match); } static krb5_error_code find_enctype(dbentp, enctype, salttype, kentp) krb5_db_entry *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; in_key_data; i++) { if (( (krb5_enctype)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); } #if 0 /* * dump_k5beta_header() - Make a dump header that is recognizable by Kerberos * Version 5 Beta 5 and previous releases. */ static krb5_error_code dump_k5beta_header(arglist) struct dump_args *arglist; { /* The old header consists of the leading string */ fprintf(arglist->ofile, k5beta_dump_header); return(0); } #endif /* * dump_k5beta_iterator() - Dump an entry in a format that is usable * by Kerberos Version 5 Beta 5 and previous * releases. */ static krb5_error_code dump_k5beta_iterator(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { krb5_error_code retval; struct dump_args *arg; char *name, *mod_name; krb5_principal mod_princ; krb5_key_data *pkey, *akey, nullkey; krb5_timestamp mod_date, last_pwd_change; int i; /* Initialize */ arg = (struct dump_args *) ptr; name = (char *) NULL; mod_name = (char *) NULL; memset(&nullkey, 0, sizeof(nullkey)); /* * Flatten the principal name. */ if ((retval = krb5_unparse_name(arg->kcontext, entry->princ, &name))) { fprintf(stderr, gettext(pname_unp_err), arg->programname, error_message(retval)); return(retval); } /* * Re-encode the keys in the new master key, if necessary. */ if (mkey_convert) { retval = master_key_convert(arg->kcontext, entry); if (retval) { com_err(arg->programname, retval, remaster_err_fmt, name); return retval; } } /* * If we don't have any match strings, or if our name matches, then * proceed with the dump, otherwise, just forget about it. */ if (!arg->nnames || name_matches(name, arg)) { /* * Deserialize the modifier record. */ mod_name = (char *) NULL; mod_princ = NULL; last_pwd_change = mod_date = 0; pkey = akey = (krb5_key_data *) NULL; if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext, entry, &mod_date, &mod_princ))) { if (mod_princ) { /* * Flatten the modifier name. */ if ((retval = krb5_unparse_name(arg->kcontext, mod_princ, &mod_name))) fprintf(stderr, gettext(mname_unp_err), arg->programname, error_message(retval)); krb5_free_principal(arg->kcontext, mod_princ); } } if (!mod_name) mod_name = strdup(null_mprinc_name); /* * Find the last password change record and set it straight. */ if ((retval = krb5_dbe_lookup_last_pwd_change(arg->kcontext, entry, &last_pwd_change))) { fprintf(stderr, gettext(nokeys_err), arg->programname, name); krb5_xfree(mod_name); krb5_xfree(name); return(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, gettext(nokeys_err), arg->programname, name); krb5_xfree(mod_name); krb5_xfree(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; ikey_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->expiration, entry->pw_expiration, last_pwd_change, entry->last_success, entry->last_failed, entry->fail_auth_count, mod_name, mod_date, entry->attributes, pkey->key_data_type[1]); /* Pound out the salt data, if present. */ for (i=0; ikey_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; ikey_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; ikey_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); } krb5_xfree(name); return(0); } /* * dump_k5beta6_iterator() - Output a dump record in krb5b6 format. */ static krb5_error_code dump_k5beta6_iterator(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { return dump_k5beta6_iterator_ext(ptr, entry, 0); } static krb5_error_code dump_k5beta6_iterator_ext(ptr, entry, kadm) krb5_pointer ptr; krb5_db_entry *entry; int kadm; { krb5_error_code retval; struct dump_args *arg; char *name; krb5_tl_data *tlp; krb5_key_data *kdata; int counter, skip, i, j; /* Initialize */ arg = (struct dump_args *) ptr; name = (char *) NULL; /* * Flatten the principal name. */ if ((retval = krb5_unparse_name(arg->kcontext, entry->princ, &name))) { fprintf(stderr, gettext(pname_unp_err), arg->programname, error_message(retval)); return(retval); } /* * Re-encode the keys in the new master key, if necessary. */ if (mkey_convert) { retval = master_key_convert(arg->kcontext, entry); if (retval) { com_err(arg->programname, retval, remaster_err_fmt, name); return retval; } } /* * If we don't have any match strings, or if our name matches, then * proceed with the dump, otherwise, just forget about it. */ if (!arg->nnames || name_matches(name, arg)) { /* * 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 ] * n_key_data*[ver kvno ver*(type length )] * * Fields which are not encapsulated by angle-brackets are to appear * verbatim. A bracketed field's absence is indicated by a -1 in its * place */ /* * Make sure that the tagged list is reasonably correct. */ counter = skip = 0; for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) { /* * don't dump tl data types we know aren't understood by * earlier revisions [krb5-admin/89] */ switch (tlp->tl_data_type) { case KRB5_TL_KADM_DATA: if (kadm) counter++; else skip++; break; default: counter++; break; } } if (counter + skip == entry->n_tl_data) { /* Pound out header */ fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t", (int) entry->len, strlen(name), counter, (int) entry->n_key_data, (int) entry->e_length, 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->expiration, 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) { if (tlp->tl_data_type == KRB5_TL_KADM_DATA && !kadm) continue; /* see above, [krb5-admin/89] */ 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; itl_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; countern_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; ikey_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; jkey_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 (entry->e_length) for (i=0; ie_length; i++) fprintf(arg->ofile, "%02x", entry->e_data[i]); else fprintf(arg->ofile, "%d", -1); /* Print trailer */ fprintf(arg->ofile, ";\n"); if (arg->verbose) fprintf(stderr, "%s\n", name); } else { fprintf(stderr, gettext(sdump_tl_inc_err), arg->programname, name, counter+skip, (int) entry->n_tl_data); retval = EINVAL; } } krb5_xfree(name); return(retval); } /* * dump_iprop_iterator() - Output a dump record in iprop format. */ static krb5_error_code dump_iprop_iterator(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { krb5_error_code retval; struct dump_args *arg; char *name; krb5_tl_data *tlp; krb5_key_data *kdata; int counter, i, j; /* Initialize */ arg = (struct dump_args *) ptr; name = (char *) NULL; /* * Flatten the principal name. */ if ((retval = krb5_unparse_name(arg->kcontext, entry->princ, &name))) { fprintf(stderr, gettext(pname_unp_err), arg->programname, error_message(retval)); return(retval); } /* * Re-encode the keys in the new master key, if necessary. */ if (mkey_convert) { retval = master_key_convert(arg->kcontext, entry); if (retval) { com_err(arg->programname, retval, remaster_err_fmt, name); return retval; } } /* * If we don't have any match strings, or if our name matches, then * proceed with the dump, otherwise, just forget about it. */ if (!arg->nnames || name_matches(name, arg)) { /* * 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 * ] n_key_data*[ver kvno ver*(type length * )] 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. */ counter = 0; for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) 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", (int) entry->len, strlen(name), (int) entry->n_tl_data, (int) entry->n_key_data, (int) entry->e_length, 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->expiration, 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) { 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; ikey_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 (entry->e_length) for (i=0; ie_length; i++) fprintf(arg->ofile, "%02x", entry->e_data[i]); else fprintf(arg->ofile, "%d", -1); /* Print trailer */ fprintf(arg->ofile, ";\n"); if (arg->verbose) fprintf(stderr, "%s\n", name); } else { fprintf(stderr, gettext(sdump_tl_inc_err), arg->programname, name, counter, (int) entry->n_tl_data); retval = EINVAL; } } krb5_xfree(name); return(retval); } /* * dump_k5beta7_iterator() - Output a dump record in krb5b7 format. */ static krb5_error_code dump_k5beta7_princ(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { return dump_k5beta7_princ_ext(ptr, entry, 0); } static krb5_error_code dump_k5beta7_princ_ext(ptr, entry, kadm) krb5_pointer ptr; krb5_db_entry *entry; int kadm; { krb5_error_code retval; struct dump_args *arg; char *name; int tmp_nnames; /* Initialize */ arg = (struct dump_args *) ptr; name = (char *) NULL; /* * Flatten the principal name. */ if ((retval = krb5_unparse_name(arg->kcontext, entry->princ, &name))) { fprintf(stderr, gettext(pname_unp_err), arg->programname, error_message(retval)); return(retval); } /* * If we don't have any match strings, or if our name matches, then * proceed with the dump, otherwise, just forget about it. */ if (!arg->nnames || name_matches(name, arg)) { fprintf(arg->ofile, "princ\t"); /* save the callee from matching the name again */ tmp_nnames = arg->nnames; arg->nnames = 0; retval = dump_k5beta6_iterator_ext(ptr, entry, kadm); arg->nnames = tmp_nnames; } free(name); return retval; } /* * dump_iprop_princ() - Output a dump record in iprop format. * This was created in order to dump more data, such as kadm5 tl */ static krb5_error_code dump_iprop_princ(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { krb5_error_code retval; struct dump_args *arg; char *name; int tmp_nnames; /* Initialize */ arg = (struct dump_args *) ptr; name = (char *) NULL; /* * Flatten the principal name. */ if ((retval = krb5_unparse_name(arg->kcontext, entry->princ, &name))) { fprintf(stderr, gettext(pname_unp_err), arg->programname, error_message(retval)); return(retval); } /* * If we don't have any match strings, or if our name matches, then * proceed with the dump, otherwise, just forget about it. */ if (!arg->nnames || name_matches(name, arg)) { fprintf(arg->ofile, "princ\t"); /* save the callee from matching the name again */ tmp_nnames = arg->nnames; arg->nnames = 0; retval = dump_iprop_iterator(ptr, entry); arg->nnames = tmp_nnames; } free(name); return (retval); } static krb5_error_code dump_k5beta7_princ_withpolicy(ptr, entry) krb5_pointer ptr; krb5_db_entry *entry; { return dump_k5beta7_princ_ext(ptr, entry, 1); } void dump_k5beta7_policy(void *data, osa_policy_ent_t entry) { struct dump_args *arg; arg = (struct dump_args *) data; fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name, entry->pw_min_life, entry->pw_max_life, entry->pw_min_length, entry->pw_min_classes, entry->pw_history_num, entry->policy_refcnt); } static void print_key_data(FILE *f, krb5_key_data *key_data) { int c; fprintf(f, "%d\t%d\t", key_data->key_data_type[0], key_data->key_data_length[0]); for(c = 0; c < key_data->key_data_length[0]; c++) fprintf(f, "%02x ", key_data->key_data_contents[0][c]); } /* * Function: print_princ * * Purpose: output osa_adb_princ_ent data in a human * readable format (which is a format suitable for * ovsec_adm_import consumption) * * Arguments: * data (input) pointer to a structure containing a FILE * * and a record counter. * entry (input) entry to get dumped. * void * * Requires: * nuttin * * Effects: * writes data to the specified file pointerp. * * Modifies: * nuttin * */ static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb) { char *princstr; int x, y, foundcrc; struct dump_args *arg; krb5_tl_data tl_data; osa_princ_ent_rec adb; XDR xdrs; arg = (struct dump_args *) ptr; /* * XXX Currently, lookup_tl_data always returns zero; it sets * tl_data->tl_data_length to zero if the type isn't found. * This should be fixed... */ /* * XXX Should this function do nothing for a principal with no * admin data, or print a record of "default" values? See * comment in server_kdb.c to help decide. */ tl_data.tl_data_type = KRB5_TL_KADM_DATA; if (krb5_dbe_lookup_tl_data(arg->kcontext, kdb, &tl_data) || (tl_data.tl_data_length == 0)) return 0; memset(&adb, 0, sizeof(adb)); xdrmem_create(&xdrs, (const caddr_t) tl_data.tl_data_contents, tl_data.tl_data_length, XDR_DECODE); if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) { xdr_destroy(&xdrs); return(KADM5_XDR_FAILURE); } xdr_destroy(&xdrs); krb5_unparse_name(arg->kcontext, kdb->princ, &princstr); fprintf(arg->ofile, "princ\t%s\t", princstr); if(adb.policy == NULL) fputc('\t', arg->ofile); else fprintf(arg->ofile, "%s\t", adb.policy); fprintf(arg->ofile, "%lx\t%d\t%d\t%d", adb.aux_attributes, adb.old_key_len,adb.old_key_next, adb.admin_history_kvno); for (x = 0; x < adb.old_key_len; x++) { foundcrc = 0; for (y = 0; y < adb.old_keys[x].n_key_data; y++) { krb5_key_data *key_data = &adb.old_keys[x].key_data[y]; if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC) continue; if (foundcrc) { fprintf(stderr, gettext("Warning! Multiple DES-CBC-CRC " "keys for principal %s; skipping " "duplicates.\n"), princstr); continue; } foundcrc++; fputc('\t', arg->ofile); print_key_data(arg->ofile, key_data); } if (!foundcrc) fprintf(stderr, gettext("Warning! No DES-CBC-CRC key " "for principal %s, cannot generate " "OV-compatible record; skipping\n"), princstr); } fputc('\n', arg->ofile); free(princstr); return 0; } /* * usage is: * dump_db [-i] [-old] [-b6] [-b7] [-ov] [-verbose] [-mkey_convert] * [-new_mkey_file mkey_file] [-rev] [-recurse] * [filename [principals...]] */ void dump_db(argc, argv) int argc; char **argv; { FILE *f; struct dump_args arglist; /* Solaris Kerberos */ #if 0 char *programname; #endif char *ofile; krb5_error_code kret, retval; dump_version *dump; int aindex; krb5_boolean locked; char *new_mkey_file = 0; bool_t dump_sno = FALSE; kdb_log_context *log_ctx; /* Solaris Kerberos: adding support for -rev/recurse flags */ int db_arg_index = 0; char *db_args[3] = {NULL, NULL, NULL}; /* * Parse the arguments. */ /* Solaris Kerberos */ #if 0 programname = argv[0]; if (strrchr(programname, (int) '/')) programname = strrchr(argv[0], (int) '/') + 1; #endif ofile = (char *) NULL; dump = &r1_3_version; arglist.verbose = 0; new_mkey_file = 0; mkey_convert = 0; backwards = 0; recursive = 0; log_ctx = util_context->kdblog_context; /* * Parse the qualifiers. */ for (aindex = 1; aindex < argc; aindex++) { if (!strcmp(argv[aindex], oldoption)) dump = &old_version; else if (!strcmp(argv[aindex], b6option)) dump = &beta6_version; else if (!strcmp(argv[aindex], b7option)) dump = &beta7_version; else if (!strcmp(argv[aindex], ovoption)) dump = &ov_version; else if (!strcmp(argv[aindex], ipropoption)) { if (log_ctx && log_ctx->iproprole) { dump = &iprop_version; /* * dump_sno is used to indicate if the serial * # should be populated in the output * file to be used later by iprop for updating * the slave's update log when loading */ dump_sno = TRUE; } else { fprintf(stderr, gettext("Iprop not enabled\n")); exit_status++; return; } } else if (!strcmp(argv[aindex], verboseoption)) arglist.verbose++; else if (!strcmp(argv[aindex], "-mkey_convert")) mkey_convert = 1; else if (!strcmp(argv[aindex], "-new_mkey_file")) { new_mkey_file = argv[++aindex]; mkey_convert = 1; } else if (!strcmp(argv[aindex], "-rev")) { /* Solaris Kerberos: adding support for -rev/recurse flags */ /* hack to pass args to db specific plugin */ db_args[db_arg_index++] = "rev"; } else if (!strcmp(argv[aindex], "-recurse")) { /* hack to pass args to db specific plugin */ db_args[db_arg_index++] = "recurse"; } else break; } arglist.names = (char **) NULL; arglist.nnames = 0; if (aindex < argc) { ofile = argv[aindex]; aindex++; if (aindex < argc) { arglist.names = &argv[aindex]; arglist.nnames = argc - aindex; } } /* * Make sure the database is open. The policy database only has * to be opened if we try a dump that uses it. */ if (!dbactive) { /* Solaris Kerberos */ com_err(progname, 0, Err_no_database); /* Solaris Kerberos */ exit_status++; return; } /* * If we're doing a master key conversion, set up for it. */ if (mkey_convert) { if (!valid_master_key) { /* TRUE here means read the keyboard, but only once */ retval = krb5_db_fetch_mkey(util_context, master_princ, global_params.enctype, TRUE, FALSE, (char *) NULL, 0, &master_key); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while reading master key")); exit(1); } retval = krb5_db_verify_master_key(util_context, master_princ, &master_key); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while verifying master key")); exit(1); } } if (!new_mkey_file) printf(gettext("Please enter new master key....\n")); if ((retval = krb5_db_fetch_mkey(util_context, master_princ, global_params.enctype, (new_mkey_file == 0) ? (krb5_boolean) 1 : 0, TRUE, new_mkey_file, 0, &new_master_key))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while reading new master key")); exit(1); } } kret = 0; locked = 0; if (ofile && strcmp(ofile, "-")) { /* * Discourage accidental dumping to filenames beginning with '-'. */ if (ofile[0] == '-') usage(); /* * 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"))) { /* Solaris Kerberos */ fprintf(stderr, gettext(ofopen_error), progname, ofile, error_message(errno)); exit_status++; return; } if ((kret = krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_EXCLUSIVE))) { /* Solaris Kerberos */ fprintf(stderr, gettext(oflock_error), progname, ofile, error_message(kret)); exit_status++; } else locked = 1; } else { f = stdout; } if (f && !(kret)) { /* Solaris Kerberos */ arglist.programname = progname; arglist.ofile = f; arglist.kcontext = util_context; fprintf(arglist.ofile, "%s", dump->header); if (dump_sno) { if (ulog_map(util_context, &global_params, FKCOMMAND)) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: Could not map log\n"), progname); exit_status++; goto error; } /* * We grab the lock twice (once again in the iterator call), * but that's ok since the lock func handles incr locks held. */ if (krb5_db_lock(util_context, KRB5_LOCKMODE_SHARED)) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: Couldn't grab lock\n"), progname); exit_status++; goto error; } fprintf(f, " %u", log_ctx->ulog->kdb_last_sno); fprintf(f, " %u", log_ctx->ulog->kdb_last_time.seconds); fprintf(f, " %u", log_ctx->ulog->kdb_last_time.useconds); } if (dump->header[strlen(dump->header)-1] != '\n') fputc('\n', arglist.ofile); /* Solaris Kerberos: adding support for -rev/recurse flags */ /* don't pass in db_args if there aren't any */ if ((kret = krb5_db_iterate(util_context, NULL, dump->dump_princ, (krb5_pointer) &arglist, db_arg_index > 0 ? (char **)&db_args : NULL))) { /* Solaris Kerberos */ fprintf(stderr, dumprec_err, progname, dump->name, error_message(kret)); exit_status++; if (dump_sno) (void) krb5_db_unlock(util_context); } if (dump->dump_policy && (kret = krb5_db_iter_policy( util_context, "*", dump->dump_policy, &arglist))) { /* Solaris Kerberos */ fprintf(stderr, gettext(dumprec_err), progname, dump->name, error_message(kret)); exit_status++; } error: if (ofile && f != stdout && !exit_status) { if (locked) { (void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK); locked = 0; } fclose(f); update_ok_file(ofile); } } if (locked) (void) krb5_lock_file(util_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; itl_data; (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE); pwchg = pwchg->tl_data_next); /* Check to see if we found one. */ linked = 0; if (!pwchg) { /* No, allocate a new one */ if ((pwchg = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) { memset(pwchg, 0, sizeof(krb5_tl_data)); if (!(pwchg->tl_data_contents = (krb5_octet *) malloc(sizeof(krb5_timestamp)))) { free(pwchg); pwchg = (krb5_tl_data *) NULL; } else { pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE; pwchg->tl_data_length = (krb5_int16) sizeof(krb5_timestamp); } } } else linked = 1; /* Do we have an entry? */ if (pwchg && pwchg->tl_data_contents) { /* Encode it */ krb5_kdb_encode_int32(last_pwd_change, pwchg->tl_data_contents); /* Link it in if necessary */ if (!linked) { pwchg->tl_data_next = dbentp->tl_data; dbentp->tl_data = pwchg; dbentp->n_tl_data++; } } else kret = ENOMEM; } return(kret); } #endif /* * process_k5beta_record() - Handle a dump record in old format. * * Returns -1 for end of file, 0 for success and 1 for failure. */ static int process_k5beta_record(fname, kcontext, filep, verbose, linenop) char *fname; krb5_context kcontext; 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; krb5_octet *shortcopy1 = NULL; /* SUNWresync121 memleak fix */ krb5_octet *shortcopy2 = NULL; 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(kcontext, &dbent) || krb5_dbe_create_key_data(kcontext, &dbent)) { krb5_db_free_principal(kcontext, &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; krb5_octet *origdata = pkey->key_data_contents[0]; shortcopy1 = (krb5_octet *) malloc(shortlen); if (shortcopy1) { shortcopy1[0] = origdata[3]; shortcopy1[1] = origdata[2]; memcpy(shortcopy1 + 2, origdata + 4, shortlen - 2); free(origdata); pkey->key_data_length[0] = shortlen; pkey->key_data_contents[0] = shortcopy1; } else { fprintf(stderr, gettext(no_mem_fmt), fname, *linenop); error++; } } /* 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; krb5_octet *origdata = akey->key_data_contents[0]; shortcopy2 = (krb5_octet *) malloc(shortlen); if (shortcopy2) { shortcopy2[0] = origdata[3]; shortcopy2[1] = origdata[2]; memcpy(shortcopy2 + 2, origdata + 4, shortlen - 2); free(origdata); akey->key_data_length[0] = shortlen; akey->key_data_contents[0] = shortcopy2; } else { fprintf(stderr, gettext(no_mem_fmt), fname, *linenop); error++; } } /* 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(kcontext, name, &dbent.princ))) { if (!(kret = krb5_parse_name(kcontext, mod_name, &mod_princ))) { if (!(kret = krb5_dbe_update_mod_princ_data(kcontext, &dbent, mod_date, mod_princ)) && !(kret = krb5_dbe_update_last_pwd_change(kcontext, &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--; dbent.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_KEY_DATA | KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT; if ((kret = krb5_db_put_principal(kcontext, &dbent, &one)) || (one != 1)) { fprintf(stderr, gettext(store_err_fmt), fname, *linenop, name, error_message(kret)); error++; } else { if (verbose) fprintf(stderr, gettext(add_princ_fmt), name); retval = 0; } dbent.n_key_data = 2; } krb5_free_principal(kcontext, mod_princ); } else { fprintf(stderr, gettext(parse_err_fmt), fname, *linenop, mod_name, error_message(kret)); error++; } } else { fprintf(stderr, gettext(parse_err_fmt), fname, *linenop, name, error_message(kret)); error++; } } else { fprintf(stderr, gettext(no_mem_fmt), fname, *linenop, try2read); } } else { fprintf(stderr, gettext(read_err_fmt), fname, *linenop); } krb5_db_free_principal(kcontext, &dbent, 1); if (mod_name) free(mod_name); if (name) free(name); } else { if (nmatched != EOF) fprintf(stderr, gettext(rhead_err_fmt), fname, *linenop); else retval = -1; } if (shortcopy1) free(shortcopy1); if (shortcopy2) free(shortcopy2); return(retval); } /* * process_k5beta6_record() - Handle a dump record in krb5b6 format. * * Returns -1 for end of file, 0 for success and 1 for failure. */ static int process_k5beta6_record(fname, kcontext, filep, verbose, linenop) char *fname; krb5_context kcontext; 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; itl_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(kcontext, 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; dbentry.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS | KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT; } else { try2read = read_nint_data; error++; } /* * Get the tagged data. * * Really, this code ought to discard tl data types * that it knows are special to the current version * and were not supported in the previous version. * But it's a pain to implement that here, and doing * it at dump time has almost as good an effect, so * that's what I did. [krb5-admin/89] */ 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; } /* test to set mask fields */ if (t1 == KRB5_TL_KADM_DATA) { XDR xdrs; osa_princ_ent_rec osa_princ_ent; /* * Assuming aux_attributes will always be * there */ dbentry.mask |= KADM5_AUX_ATTRIBUTES; /* test for an actual policy reference */ memset(&osa_princ_ent, 0, sizeof(osa_princ_ent)); xdrmem_create(&xdrs, (char *)tl->tl_data_contents, tl->tl_data_length, XDR_DECODE); if (xdr_osa_princ_ent_rec(&xdrs, &osa_princ_ent) && (osa_princ_ent.aux_attributes & KADM5_POLICY) && osa_princ_ent.policy != NULL) { dbentry.mask |= KADM5_POLICY; kdb_free_entry(NULL, NULL, &osa_princ_ent); } xdr_destroy(&xdrs); } } 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; } } if (!error) dbentry.mask |= KADM5_TL_DATA; } /* Get the key data */ if (!error && dbentry.n_key_data) { for (i=0; !error && (ikey_data_ver = (krb5_int16) t1; kdatap->key_data_kvno = (krb5_int16) t2; for (j=0; jkey_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; } } } } if (!error) dbentry.mask |= KADM5_KEY_DATA; } /* 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(kcontext, &dbentry, &one))) { fprintf(stderr, gettext(store_err_fmt), fname, *linenop, name, error_message(kret)); } else { if (verbose) fprintf(stderr, gettext( add_princ_fmt), name); retval = 0; } } else { fprintf(stderr, gettext(read_err_fmt), fname, *linenop, try2read); } } else { if (kret) fprintf(stderr, gettext(parse_err_fmt), fname, *linenop, name, error_message(kret)); else fprintf(stderr, gettext(no_mem_fmt), fname, *linenop); } } else { fprintf(stderr, gettext(rhead_err_fmt), fname, *linenop); } if (op) free(op); if (kp) free(kp); if (name) free(name); krb5_db_free_principal(kcontext, &dbentry, 1); } else { if (nread == EOF) retval = -1; } return(retval); } static int process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db) char *fname; krb5_context kcontext; FILE *filep; int verbose; int *linenop; void *pol_db; { osa_policy_ent_rec rec; char namebuf[1024]; int nread, ret; (*linenop)++; rec.name = namebuf; nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name, &rec.pw_min_life, &rec.pw_max_life, &rec.pw_min_length, &rec.pw_min_classes, &rec.pw_history_num, &rec.policy_refcnt); if (nread == EOF) return -1; else if (nread != 7) { fprintf(stderr, gettext("cannot parse policy on line %d (%d read)\n"), *linenop, nread); return 1; } if ((ret = krb5_db_create_policy(kcontext, &rec))) { if (ret && ((ret = krb5_db_put_policy(kcontext, &rec)))) { fprintf(stderr, gettext("cannot create policy on line %d: %s\n"), *linenop, error_message(ret)); return 1; } } if (verbose) fprintf(stderr, gettext("created policy %s\n"), rec.name); return 0; } /* * process_k5beta7_record() - Handle a dump record in krb5b7 format. * * Returns -1 for end of file, 0 for success and 1 for failure. */ static int process_k5beta7_record(fname, kcontext, filep, verbose, linenop) char *fname; krb5_context kcontext; FILE *filep; int verbose; int *linenop; { int nread; char rectype[100]; nread = fscanf(filep, "%100s\t", rectype); if (nread == EOF) return -1; else if (nread != 1) return 1; if (strcmp(rectype, "princ") == 0) process_k5beta6_record(fname, kcontext, filep, verbose, linenop); else if (strcmp(rectype, "policy") == 0) process_k5beta7_policy(fname, kcontext, filep, verbose, linenop); else { fprintf(stderr, gettext("unknown record type \"%s\" on line %d\n"), rectype, *linenop); return 1; } return 0; } /* * process_ov_record() - Handle a dump record in OpenV*Secure 1.0 format. * * Returns -1 for end of file, 0 for success and 1 for failure. */ static int process_ov_record(fname, kcontext, filep, verbose, linenop) char *fname; krb5_context kcontext; FILE *filep; int verbose; int *linenop; { int nread; char rectype[100]; nread = fscanf(filep, "%100s\t", rectype); if (nread == EOF) return -1; else if (nread != 1) return 1; if (strcmp(rectype, "princ") == 0) process_ov_principal(fname, kcontext, filep, verbose, linenop); else if (strcmp(rectype, "policy") == 0) process_k5beta7_policy(fname, kcontext, filep, verbose, linenop); else if (strcmp(rectype, "End") == 0) return -1; else { fprintf(stderr, gettext("unknown record type \"%s\" on line %d\n"), rectype, *linenop); return 1; } return 0; } /* * restore_dump() - Restore the database from any version dump file. */ static int restore_dump(programname, kcontext, dumpfile, f, verbose, dump) char *programname; krb5_context kcontext; char *dumpfile; FILE *f; int verbose; dump_version *dump; { int error; int lineno; error = 0; lineno = 1; /* * Process the records. */ while (!(error = (*dump->load_record)(dumpfile, kcontext, f, verbose, &lineno))) ; if (error != -1) fprintf(stderr, gettext(err_line_fmt), programname, lineno, dumpfile); else error = 0; return(error); } /* * Usage: load_db [-i] [-old] [-ov] [-b6] [-b7] [-verbose] [-update] [-hash] * filename */ void load_db(argc, argv) int argc; char **argv; { kadm5_config_params newparams; krb5_error_code kret; krb5_context kcontext; FILE *f; extern char *optarg; extern int optind; /* Solaris Kerberos */ #if 0 char *programname; #endif char *dumpfile; char *dbname; char *dbname_tmp; char buf[BUFSIZ]; dump_version *load; int update, verbose; int aindex; bool_t add_update = TRUE; char iheader[MAX_HEADER]; uint32_t caller, last_sno, last_seconds, last_useconds; kdb_log_context *log_ctx; int db_locked = 0; /* * Parse the arguments. */ /* Solaris Kerberos */ #if 0 programname = argv[0]; if (strrchr(programname, (int) '/')) programname = strrchr(argv[0], (int) '/') + 1; #endif dumpfile = (char *) NULL; dbname = global_params.dbname; load = NULL; update = 0; verbose = 0; exit_status = 0; dbname_tmp = (char *) NULL; log_ctx = util_context->kdblog_context; for (aindex = 1; aindex < argc; aindex++) { if (!strcmp(argv[aindex], oldoption)) load = &old_version; else if (!strcmp(argv[aindex], b6option)) load = &beta6_version; else if (!strcmp(argv[aindex], b7option)) load = &beta7_version; else if (!strcmp(argv[aindex], ovoption)) load = &ov_version; else if (!strcmp(argv[aindex], ipropoption)) { if (log_ctx && log_ctx->iproprole) { load = &iprop_version; add_update = FALSE; } else { fprintf(stderr, gettext("Iprop not enabled\n")); exit_status++; return; } } else if (!strcmp(argv[aindex], verboseoption)) verbose = 1; else if (!strcmp(argv[aindex], updateoption)) update = 1; else if (!strcmp(argv[aindex], hashoption)) { if (!add_db_arg("hash=true")) { com_err(progname, ENOMEM, "while parsing command arguments\n"); exit(1); } } else break; } if ((argc - aindex) != 1) { usage(); return; } dumpfile = argv[aindex]; if (!(dbname_tmp = (char *) malloc(strlen(dbname)+ strlen(dump_tmptrail)+1))) { /* Solaris Kerberos */ fprintf(stderr, gettext(no_name_mem_fmt), progname); exit_status++; return; } strcpy(dbname_tmp, dbname); strcat(dbname_tmp, dump_tmptrail); /* * Initialize the Kerberos context and error tables. */ if ((kret = kadm5_init_krb5_context(&kcontext))) { /* Solaris Kerberos */ fprintf(stderr, gettext(ctx_err_fmt), progname); free(dbname_tmp); exit_status++; return; } if( (kret = krb5_set_default_realm(kcontext, util_context->default_realm)) ) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: Unable to set the default realm\n"), progname); free(dbname_tmp); exit_status++; return; } if (log_ctx && log_ctx->iproprole) kcontext->kdblog_context = (void *)log_ctx; /* * Open the dumpfile */ if (dumpfile) { if ((f = fopen(dumpfile, "r")) == NULL) { /* Solaris Kerberos */ fprintf(stderr, gettext(dfile_err_fmt), progname, dumpfile, error_message(errno)); exit_status++; return; } if ((kret = krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_SHARED))) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: Cannot lock %s: %s\n"), progname, dumpfile, error_message(errno)); exit_status++; return; } } else f = stdin; /* * Auto-detect dump version if we weren't told, verify if we * were told. */ fgets(buf, sizeof(buf), f); if (load) { /* only check what we know; some headers only contain a prefix */ if (strncmp(buf, load->header, strlen(load->header)) != 0) { /* Solaris Kerberos */ fprintf(stderr, gettext(head_bad_fmt), progname, dumpfile); exit_status++; if (dumpfile) fclose(f); return; } } else { /* perhaps this should be in an array, but so what? */ if (strcmp(buf, old_version.header) == 0) load = &old_version; else if (strcmp(buf, beta6_version.header) == 0) load = &beta6_version; else if (strcmp(buf, beta7_version.header) == 0) load = &beta7_version; else if (strcmp(buf, r1_3_version.header) == 0) load = &r1_3_version; else if (strncmp(buf, ov_version.header, strlen(ov_version.header)) == 0) load = &ov_version; else { /* Solaris Kerberos */ fprintf(stderr, gettext(head_bad_fmt), progname, dumpfile); exit_status++; if (dumpfile) fclose(f); return; } } if (load->updateonly && !update) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: dump version %s can only " "be loaded with the -update flag\n"), progname, load->name); exit_status++; return; } /* * Cons up params for the new databases. If we are not in update * mode, we create an alternate database and then promote it to * be the live db. */ newparams = global_params; if (! update) { newparams.mask |= KADM5_CONFIG_DBNAME; newparams.dbname = dbname_tmp; if ((kret = kadm5_get_config_params(kcontext, 1, &newparams, &newparams))) { /* Solaris Kerberos */ com_err(progname, kret, gettext("while retreiving new " "configuration parameters")); exit_status++; return; } if (!add_db_arg("temporary")) { com_err(progname, ENOMEM, "computing parameters for database"); exit(1); } } /* * If not an update restoration, create the database. otherwise open */ if (!update) { if((kret = krb5_db_create(kcontext, db5util_db_args))) { const char *emsg = krb5_get_error_message(kcontext, kret); /* * See if something (like DAL KDB plugin) has set a specific error * message and use that otherwise use default. */ if (emsg != NULL) { /* Solaris Kerberos */ fprintf(stderr, "%s: %s\n", progname, emsg); krb5_free_error_message (kcontext, emsg); } else { /* Solaris Kerberos */ fprintf(stderr, dbcreaterr_fmt, progname, dbname, error_message(kret)); } exit_status++; kadm5_free_config_params(kcontext, &newparams); if (dumpfile) fclose(f); return; } } else { /* * Initialize the database. */ if ((kret = krb5_db_open(kcontext, db5util_db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) { const char *emsg = krb5_get_error_message(kcontext, kret); /* * See if something (like DAL KDB plugin) has set a specific * error message and use that otherwise use default. */ if (emsg != NULL) { /* Solaris Kerberos */ fprintf(stderr, "%s: %s\n", progname, emsg); krb5_free_error_message (kcontext, emsg); } else { /* Solaris Kerberos */ fprintf(stderr, dbinit_err_fmt, progname, error_message(kret)); } exit_status++; goto error; } } /* * If an update restoration, make sure the db is left unusable if * the update fails. */ if ((kret = krb5_db_lock(kcontext, update?KRB5_DB_LOCKMODE_PERMANENT: KRB5_DB_LOCKMODE_EXCLUSIVE))) { /* * Ignore a not supported error since there is nothing to do about it * anyway. */ if (kret != KRB5_PLUGIN_OP_NOTSUPP) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: %s while permanently locking database\n"), progname, error_message(kret)); exit_status++; goto error; } } else { db_locked = 1; } if (log_ctx && log_ctx->iproprole) { if (add_update) caller = FKCOMMAND; else caller = FKPROPD; if (ulog_map(kcontext, &global_params, caller)) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: Could not map log\n"), progname); exit_status++; goto error; } /* * We don't want to take out the ulog out from underneath * kadmind so we reinit the header log. * * We also don't want to add to the update log since we * are doing a whole sale replace of the db, because: * we could easily exceed # of update entries * we could implicity delete db entries during a replace * no advantage in incr updates when entire db is replaced */ if (!update) { memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t)); log_ctx->ulog->kdb_hmagic = KDB_HMAGIC; log_ctx->ulog->db_version_num = KDB_VERSION; log_ctx->ulog->kdb_state = KDB_STABLE; log_ctx->ulog->kdb_block = ULOG_BLOCK; log_ctx->iproprole = IPROP_NULL; if (!add_update) { sscanf(buf, "%s %u %u %u", iheader, &last_sno, &last_seconds, &last_useconds); log_ctx->ulog->kdb_last_sno = last_sno; log_ctx->ulog->kdb_last_time.seconds = last_seconds; log_ctx->ulog->kdb_last_time.useconds = last_useconds; } } } /* Solaris Kerberos */ if (restore_dump(progname, kcontext, (dumpfile) ? dumpfile : stdin_name, f, verbose, load)) { /* Solaris Kerberos */ fprintf(stderr, gettext(restfail_fmt), progname, load->name); exit_status++; } if (!update && load->create_kadm5 && ((kret = kadm5_create_magic_princs(&newparams, kcontext)))) { /* error message printed by create_magic_princs */ exit_status++; } if (db_locked && (kret = krb5_db_unlock(kcontext))) { /* change this error? */ /* Solaris Kerberos */ fprintf(stderr, gettext(dbunlockerr_fmt), progname, dbname, error_message(kret)); exit_status++; } #if 0 if ((kret = krb5_db_fini(kcontext))) { /* Solaris Kerberos */ fprintf(stderr, gettext(close_err_fmt), progname, error_message(kret)); exit_status++; } #endif /* close policy db below */ if (exit_status == 0 && !update) { kret = krb5_db_promote(kcontext, db5util_db_args); /* * Ignore a not supported error since there is nothing to do about it * anyway. */ if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) { /* Solaris Kerberos */ fprintf(stderr, gettext("%s: cannot make newly loaded database live (%s)\n"), progname, error_message(kret)); exit_status++; } } error: /* * If not an update: if there was an error, destroy the temp database, * otherwise rename it into place. * * If an update: if there was no error, unlock the database. */ if (!update) { if (exit_status) { kret = krb5_db_destroy(kcontext, db5util_db_args); /* * Ignore a not supported error since there is nothing to do about * it anyway. */ if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) { /* Solaris Kerberos */ fprintf(stderr, gettext(dbdelerr_fmt), progname, dbname, error_message(kret)); exit_status++; } } } if (dumpfile) { (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK); fclose(f); } if (dbname_tmp) free(dbname_tmp); krb5_free_context(kcontext); } /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * import_err.h: * This file is automatically generated; please do not edit it. */ #include #define IMPORT_NO_ERR (37349888L) #define IMPORT_BAD_FILE (37349889L) #define IMPORT_BAD_TOKEN (37349890L) #define IMPORT_BAD_VERSION (37349891L) #define IMPORT_BAD_RECORD (37349892L) #define IMPORT_BAD_FOOTER (37349893L) #define IMPORT_FAILED (37349894L) #define IMPORT_COUNT_MESSAGE (37349895L) #define IMPORT_MISMATCH_COUNT (37349896L) #define IMPORT_UNK_OPTION (37349897L) #define IMPORT_WARN_DB (37349898L) #define IMPORT_RENAME_FAILED (37349899L) #define IMPORT_EXTRA_DATA (37349900L) #define IMPORT_CONFIRM (37349901L) #define IMPORT_OPEN_DUMP (37349902L) #define IMPORT_IMPORT (37349903L) #define IMPORT_TTY (37349904L) #define IMPORT_RENAME_OPEN (37349905L) #define IMPORT_RENAME_LOCK (37349906L) #define IMPORT_RENAME_UNLOCK (37349907L) #define IMPORT_RENAME_CLOSE (37349908L) #define IMPORT_SINGLE_RECORD (37349909L) #define IMPORT_PLURAL_RECORDS (37349910L) #define IMPORT_GET_PARAMS (37349911L) #define ERROR_TABLE_BASE_imp (37349888L) extern const struct error_table et_imp_error_table; #if !defined(_WIN32) /* for compatibility with older versions... */ extern void initialize_imp_error_table (void) /*@modifies internalState@*/; #else #define initialize_imp_error_table() #endif #if !defined(_WIN32) #define init_imp_err_tbl initialize_imp_error_table #define imp_err_base ERROR_TABLE_BASE_imp #endif /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _IPROP_H_RPCGEN #define _IPROP_H_RPCGEN #include typedef struct { u_int utf8str_t_len; char *utf8str_t_val; } utf8str_t; typedef uint32_t kdb_sno_t; struct kdbe_time_t { uint32_t seconds; uint32_t useconds; }; typedef struct kdbe_time_t kdbe_time_t; struct kdbe_key_t { int32_t k_ver; int32_t k_kvno; struct { u_int k_enctype_len; int32_t *k_enctype_val; } k_enctype; struct { u_int k_contents_len; utf8str_t *k_contents_val; } k_contents; }; typedef struct kdbe_key_t kdbe_key_t; struct kdbe_data_t { int32_t k_magic; utf8str_t k_data; }; typedef struct kdbe_data_t kdbe_data_t; struct kdbe_princ_t { utf8str_t k_realm; struct { u_int k_components_len; kdbe_data_t *k_components_val; } k_components; int32_t k_nametype; }; typedef struct kdbe_princ_t kdbe_princ_t; struct kdbe_tl_t { int16_t tl_type; struct { u_int tl_data_len; char *tl_data_val; } tl_data; }; typedef struct kdbe_tl_t kdbe_tl_t; typedef struct { u_int kdbe_pw_hist_t_len; kdbe_key_t *kdbe_pw_hist_t_val; } kdbe_pw_hist_t; enum kdbe_attr_type_t { AT_ATTRFLAGS = 0, AT_MAX_LIFE = 1, AT_MAX_RENEW_LIFE = 2, AT_EXP = 3, AT_PW_EXP = 4, AT_LAST_SUCCESS = 5, AT_LAST_FAILED = 6, AT_FAIL_AUTH_COUNT = 7, AT_PRINC = 8, AT_KEYDATA = 9, AT_TL_DATA = 10, AT_LEN = 11, AT_MOD_PRINC = 12, AT_MOD_TIME = 13, AT_MOD_WHERE = 14, AT_PW_LAST_CHANGE = 15, AT_PW_POLICY = 16, AT_PW_POLICY_SWITCH = 17, AT_PW_HIST_KVNO = 18, AT_PW_HIST = 19 }; typedef enum kdbe_attr_type_t kdbe_attr_type_t; struct kdbe_val_t { kdbe_attr_type_t av_type; union { uint32_t av_attrflags; uint32_t av_max_life; uint32_t av_max_renew_life; uint32_t av_exp; uint32_t av_pw_exp; uint32_t av_last_success; uint32_t av_last_failed; uint32_t av_fail_auth_count; kdbe_princ_t av_princ; struct { u_int av_keydata_len; kdbe_key_t *av_keydata_val; } av_keydata; struct { u_int av_tldata_len; kdbe_tl_t *av_tldata_val; } av_tldata; int16_t av_len; uint32_t av_pw_last_change; kdbe_princ_t av_mod_princ; uint32_t av_mod_time; utf8str_t av_mod_where; utf8str_t av_pw_policy; bool_t av_pw_policy_switch; uint32_t av_pw_hist_kvno; struct { u_int av_pw_hist_len; kdbe_pw_hist_t *av_pw_hist_val; } av_pw_hist; struct { u_int av_extension_len; char *av_extension_val; } av_extension; } kdbe_val_t_u; }; typedef struct kdbe_val_t kdbe_val_t; typedef struct { u_int kdbe_t_len; kdbe_val_t *kdbe_t_val; } kdbe_t; struct kdb_incr_update_t { utf8str_t kdb_princ_name; kdb_sno_t kdb_entry_sno; kdbe_time_t kdb_time; kdbe_t kdb_update; bool_t kdb_deleted; bool_t kdb_commit; struct { u_int kdb_kdcs_seen_by_len; utf8str_t *kdb_kdcs_seen_by_val; } kdb_kdcs_seen_by; struct { u_int kdb_futures_len; char *kdb_futures_val; } kdb_futures; }; typedef struct kdb_incr_update_t kdb_incr_update_t; typedef struct { u_int kdb_ulog_t_len; kdb_incr_update_t *kdb_ulog_t_val; } kdb_ulog_t; enum update_status_t { UPDATE_OK = 0, UPDATE_ERROR = 1, UPDATE_FULL_RESYNC_NEEDED = 2, UPDATE_BUSY = 3, UPDATE_NIL = 4, UPDATE_PERM_DENIED = 5 }; typedef enum update_status_t update_status_t; struct kdb_last_t { kdb_sno_t last_sno; kdbe_time_t last_time; }; typedef struct kdb_last_t kdb_last_t; struct kdb_incr_result_t { kdb_last_t lastentry; kdb_ulog_t updates; update_status_t ret; }; typedef struct kdb_incr_result_t kdb_incr_result_t; struct kdb_fullresync_result_t { kdb_last_t lastentry; update_status_t ret; }; typedef struct kdb_fullresync_result_t kdb_fullresync_result_t; #define KRB5_IPROP_PROG 100423 #define KRB5_IPROP_VERS 1 #define IPROP_NULL 0 extern void * iprop_null_1(); #define IPROP_GET_UPDATES 1 extern kdb_incr_result_t * iprop_get_updates_1(); #define IPROP_FULL_RESYNC 2 extern kdb_fullresync_result_t * iprop_full_resync_1(); extern int krb5_iprop_prog_1_freeresult(); /* the xdr functions */ extern bool_t xdr_utf8str_t(); extern bool_t xdr_kdb_sno_t(); extern bool_t xdr_kdbe_time_t(); extern bool_t xdr_kdbe_key_t(); extern bool_t xdr_kdbe_data_t(); extern bool_t xdr_kdbe_princ_t(); extern bool_t xdr_kdbe_tl_t(); extern bool_t xdr_kdbe_pw_hist_t(); extern bool_t xdr_kdbe_attr_type_t(); extern bool_t xdr_kdbe_val_t(); extern bool_t xdr_kdbe_t(); extern bool_t xdr_kdb_incr_update_t(); extern bool_t xdr_kdb_ulog_t(); extern bool_t xdr_update_status_t(); extern bool_t xdr_kdb_last_t(); extern bool_t xdr_kdb_incr_result_t(); extern bool_t xdr_kdb_fullresync_result_t(); #endif /* !_IPROP_H_RPCGEN */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * * $Id: kadm5_create.c,v 1.6 1998/10/30 02:52:37 marc Exp $ * $Source: /cvs/krbdev/krb5/src/kadmin/dbutil/kadm5_create.c,v $ */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * 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 FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "string_table.h" #include #include #include #include #include #include #include #include #include #include "kdb5_util.h" #include int add_admin_old_princ(void *handle, krb5_context context, char *name, char *realm, int attrs, int lifetime); int add_admin_sname_princ(void *handle, krb5_context context, char *sname, int attrs, int lifetime); static int add_admin_princ(void *handle, krb5_context context, krb5_principal principal, int attrs, int lifetime); static int add_admin_princs(void *handle, krb5_context context, char *realm); #define ERR 1 #define OK 0 #define ADMIN_LIFETIME 60*60*3 /* 3 hours */ #define CHANGEPW_LIFETIME 60*5 /* 5 minutes */ extern char *progname; /* * Function: kadm5_create * * Purpose: create admin principals in KDC database * * Arguments: params (r) configuration parameters to use * * Effects: Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE * principals in the KDC database and sets their attributes * appropriately. */ int kadm5_create(kadm5_config_params *params) { int retval; krb5_context context; kadm5_config_params lparams; if ((retval = kadm5_init_krb5_context(&context))) exit(ERR); (void) memset(&lparams, 0, sizeof (kadm5_config_params)); /* * The lock file has to exist before calling kadm5_init, but * params->admin_lockfile may not be set yet... */ if ((retval = kadm5_get_config_params(context, 1, params, &lparams))) { com_err(progname, retval, gettext("while looking up the Kerberos configuration")); return 1; } retval = kadm5_create_magic_princs(&lparams, context); kadm5_free_config_params(context, &lparams); krb5_free_context(context); return retval; } int kadm5_create_magic_princs(kadm5_config_params *params, krb5_context context) { int retval; void *handle; retval = krb5_klog_init(context, "admin_server", progname, 0); if (retval) return retval; if ((retval = kadm5_init(progname, NULL, NULL, params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, db5util_db_args, &handle))) { com_err(progname, retval, gettext("while initializing the Kerberos admin interface")); return retval; } retval = add_admin_princs(handle, context, params->realm); kadm5_destroy(handle); krb5_klog_close(context); return retval; } /* * Function: build_name_with_realm * * Purpose: concatenate a name and a realm to form a krb5 name * * Arguments: * * name (input) the name * realm (input) the realm * * Returns: * * pointer to name@realm, in allocated memory, or NULL if it * cannot be allocated * * Requires: both strings are null-terminated */ static char *build_name_with_realm(char *name, char *realm) { char *n; n = (char *) malloc(strlen(name) + strlen(realm) + 2); sprintf(n, "%s@%s", name, realm); return n; } /* * Function: add_admin_princs * * Purpose: create admin principals * * Arguments: * * rseed (input) random seed * realm (input) realm, or NULL for default realm * (output) status, 0 for success, 1 for serious error * * Requires: * * Effects: * * add_admin_princs creates KADM5_ADMIN_SERVICE, * KADM5_CHANGEPW_SERVICE. If any of these exist a message is * printed. If any of these existing principal do not have the proper * attributes, a warning message is printed. */ static int add_admin_princs(void *handle, krb5_context context, char *realm) { krb5_error_code ret = 0; /* * Solaris Kerberos: * The kadmin/admin principal is unused on Solaris. This principal is used * in AUTH_GSSAPI but Solaris doesn't support AUTH_GSSAPI. RPCSEC_GSS can only * be used with host-based principals. * */ #if 0 if ((ret = add_admin_old_princ(handle, context, KADM5_ADMIN_SERVICE, realm, KRB5_KDB_DISALLOW_TGT_BASED, ADMIN_LIFETIME))) goto clean_and_exit; #endif if ((ret = add_admin_old_princ(handle, context, KADM5_CHANGEPW_SERVICE, realm, KRB5_KDB_DISALLOW_TGT_BASED | KRB5_KDB_PWCHANGE_SERVICE, CHANGEPW_LIFETIME))) goto clean_and_exit; if ((ret = add_admin_sname_princ(handle, context, KADM5_ADMIN_HOST_SERVICE, KRB5_KDB_DISALLOW_TGT_BASED, ADMIN_LIFETIME))) goto clean_and_exit; if ((ret = add_admin_sname_princ(handle, context, KADM5_CHANGEPW_HOST_SERVICE, KRB5_KDB_DISALLOW_TGT_BASED | KRB5_KDB_PWCHANGE_SERVICE, ADMIN_LIFETIME))) goto clean_and_exit; if ((ret = add_admin_sname_princ(handle, context, KADM5_KIPROP_HOST_SERVICE, KRB5_KDB_DISALLOW_TGT_BASED, ADMIN_LIFETIME))) goto clean_and_exit; clean_and_exit: return ret; } /* * Function: add_admin_princ * * Arguments: * * creator (r) principal to use as "mod_by" * rseed (r) seed for random key generator * principal (r) kerberos principal to add * attrs (r) principal's attributes * lifetime (r) principal's max life, or 0 * not_unique (r) error message for multiple entries, never used * exists (r) warning message for principal exists * wrong_attrs (r) warning message for wrong attributes * * Returns: * * OK on success * ERR on serious errors * * Effects: * * If the principal is not unique, not_unique is printed (but this * never happens). If the principal exists, then exists is printed * and if the principals attributes != attrs, wrong_attrs is printed. * Otherwise, the principal is created with mod_by creator and * attributes attrs and max life of lifetime (if not zero). */ static int add_admin_princ(void *handle, krb5_context context, krb5_principal principal, int attrs, int lifetime) { char *fullname; krb5_error_code ret; kadm5_principal_ent_rec ent; memset(&ent, 0, sizeof(ent)); if (krb5_unparse_name(context, principal, &fullname)) return ERR; ent.principal = principal; ent.max_life = lifetime; ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX; ret = kadm5_create_principal(handle, &ent, (KADM5_PRINCIPAL | KADM5_MAX_LIFE | KADM5_ATTRIBUTES), "to-be-random"); if (ret) { if (ret != KADM5_DUP) { com_err(progname, ret, gettext(str_PUT_PRINC), fullname); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } } else { /* only randomize key if we created the principal */ /* * Solaris Kerberos: * Create kadmind principals with keys for all supported encryption types. * Follows a similar pattern to add_principal() in keytab.c. */ krb5_enctype *tmpenc, *enctype = NULL; krb5_key_salt_tuple *keysalt; int num_ks, i; krb5_int32 normalsalttype; ret = krb5_get_permitted_enctypes(context, &enctype); if (ret || *enctype == 0) { com_err(progname, ret, gettext("while getting list of permitted encryption types")); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } /* Count the number of enc types */ for (tmpenc = enctype, num_ks = 0; *tmpenc; tmpenc++) num_ks++; keysalt = malloc (sizeof (krb5_key_salt_tuple) * num_ks); if (keysalt == NULL) { com_err(progname, ENOMEM, gettext("while generating list of key salt tuples")); krb5_free_ktypes(context, enctype); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } ret = krb5_string_to_salttype("normal", &normalsalttype); if (ret) { com_err(progname, ret, gettext("while converting \"normal\" to a salttype")); free(keysalt); krb5_free_ktypes(context, enctype); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } /* Only create keys with "normal" salttype */ for (i = 0; i < num_ks; i++) { keysalt[i].ks_enctype = enctype[i]; keysalt[i].ks_salttype = normalsalttype; } ret = kadm5_randkey_principal_3(handle, ent.principal, FALSE, num_ks, keysalt, NULL, NULL); free(keysalt); krb5_free_ktypes (context, enctype); if (ret) { com_err(progname, ret, gettext(str_RANDOM_KEY), fullname); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } ent.attributes = attrs; ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES); if (ret) { com_err(progname, ret, gettext(str_PUT_PRINC), fullname); krb5_free_principal(context, ent.principal); free(fullname); return ERR; } } krb5_free_principal(context, ent.principal); free(fullname); return OK; } int add_admin_old_princ(void *handle, krb5_context context, char *name, char *realm, int attrs, int lifetime) { char *fullname; krb5_error_code ret; krb5_principal principal; fullname = build_name_with_realm(name, realm); if (ret = krb5_parse_name(context, fullname, &principal)) { com_err(progname, ret, gettext(str_PARSE_NAME)); return (ERR); } return (add_admin_princ(handle, context, principal, attrs, lifetime)); } int add_admin_sname_princ(void *handle, krb5_context context, char *sname, int attrs, int lifetime) { krb5_error_code ret; krb5_principal principal; if (ret = krb5_sname_to_principal(context, NULL, sname, KRB5_NT_SRV_HST, &principal)) { com_err(progname, ret, gettext("Could not get host based " "service name for %s principal\n"), sname); return (ERR); } return (add_admin_princ(handle, context, principal, attrs, lifetime)); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * admin/create/kdb5_create.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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * Generate (from scratch) a Kerberos KDC database. */ /* * Yes, I know this is a hack, but we need admin.h without including the * rpc.h header. Additionally, our rpc.h header brings in * a des.h header which causes other problems. */ #define _RPC_RPC_H #include #include #include #include #include #include #include #include #include "kdb5_util.h" enum ap_op { NULL_KEY, /* setup null keys */ MASTER_KEY, /* use master key as new key */ TGT_KEY /* special handling for tgt key */ }; krb5_key_salt_tuple def_kslist = { ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL }; struct realm_info { krb5_deltat max_life; krb5_deltat max_rlife; krb5_timestamp expiration; krb5_flags flags; krb5_keyblock *key; krb5_int32 nkslist; krb5_key_salt_tuple *kslist; } rblock = { /* XXX */ KRB5_KDB_MAX_LIFE, KRB5_KDB_MAX_RLIFE, KRB5_KDB_EXPIRATION, KRB5_KDB_DEF_FLAGS, (krb5_keyblock *) NULL, 1, &def_kslist }; struct iterate_args { krb5_context ctx; struct realm_info *rblock; krb5_db_entry *dbentp; }; static krb5_error_code add_principal (krb5_context, krb5_principal, enum ap_op, struct realm_info *, krb5_keyblock *); /* * Steps in creating a database: * * 1) use the db calls to open/create a new database * * 2) get a realm name for the new db * * 3) get a master password for the new db; convert to an encryption key. * * 4) create various required entries in the database * * 5) close & exit */ extern krb5_principal master_princ; krb5_data tgt_princ_entries[] = { {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME}, {0, 0, 0} }; krb5_data db_creator_entries[] = { {0, sizeof("db_creation")-1, "db_creation"} }; /* XXX knows about contents of krb5_principal, and that tgt names are of form TGT/REALM@REALM */ krb5_principal_data tgt_princ = { 0, /* magic number */ {0, 0, 0}, /* krb5_data realm */ tgt_princ_entries, /* krb5_data *data */ 2, /* int length */ KRB5_NT_SRV_INST /* int type */ }; krb5_principal_data db_create_princ = { 0, /* magic number */ {0, 0, 0}, /* krb5_data realm */ db_creator_entries, /* krb5_data *data */ 1, /* int length */ KRB5_NT_SRV_INST /* int type */ }; extern char *mkey_password; extern char *progname; extern int exit_status; extern kadm5_config_params global_params; extern krb5_context util_context; void kdb5_create(argc, argv) int argc; char *argv[]; { int optchar; krb5_error_code retval; char *mkey_fullname; char *pw_str = 0; unsigned int pw_size = 0; int do_stash = 0; krb5_data pwd, seed; kdb_log_context *log_ctx; krb5_keyblock mkey; krb5_data master_salt = { 0 }; /* Solaris Kerberos */ (void) memset(&mkey, 0, sizeof (mkey)); /* Solaris Kerberos */ #if 0 if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; #endif while ((optchar = getopt(argc, argv, "s")) != -1) { switch(optchar) { case 's': do_stash++; break; case 'h': if (!add_db_arg("hash=true")) { com_err(progname, ENOMEM, "while parsing command arguments\n"); exit(1); } break; case '?': default: usage(); return; } } rblock.max_life = global_params.max_life; rblock.max_rlife = global_params.max_rlife; rblock.expiration = global_params.expiration; rblock.flags = global_params.flags; rblock.nkslist = global_params.num_keysalts; rblock.kslist = global_params.keysalts; log_ctx = util_context->kdblog_context; /* SUNW14resync XXX */ #if 0 printf ("Loading random data\n"); retval = krb5_c_random_os_entropy (util_context, 1, NULL); if (retval) { /* Solaris Kerberos */ com_err (progname, retval, "Loading random data"); exit_status++; return; } #endif /* assemble & parse the master key name */ if ((retval = krb5_db_setup_mkey_name(util_context, global_params.mkey_name, global_params.realm, &mkey_fullname, &master_princ))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while setting up master key name")); exit_status++; return; } krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm); krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm)); krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm); krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm)); krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm; krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm); printf(gettext("Initializing database '%s' for realm '%s',\n" "master key name '%s'\n"), global_params.dbname, global_params.realm, mkey_fullname); if (!mkey_password) { printf(gettext("You will be prompted for the " "database Master Password.\n")); printf(gettext("It is important that you NOT FORGET this password.\n")); fflush(stdout); pw_size = 1024; pw_str = malloc(pw_size); retval = krb5_read_password(util_context, gettext("Enter KDC database master key"), gettext("Re-enter KDC database " "master key to verify"), pw_str, &pw_size); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while reading master key from keyboard")); exit_status++; return; } mkey_password = pw_str; } pwd.data = mkey_password; pwd.length = strlen(mkey_password); retval = krb5_principal2salt(util_context, master_princ, &master_salt); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while calculated master key salt")); exit_status++; goto cleanup; } retval = krb5_c_string_to_key(util_context, global_params.enctype, &pwd, &master_salt, &mkey); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while transforming master key from password")); exit_status++; goto cleanup; } retval = krb5_copy_keyblock(util_context, &mkey, &rblock.key); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while copying master key")); exit_status++; goto cleanup; } seed.length = mkey.length; seed.data = (char *)mkey.contents; if ((retval = krb5_c_random_seed(util_context, &seed))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while initializing random key generator")); exit_status++; goto cleanup; } if ((retval = krb5_db_create(util_context, db5util_db_args))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while creating database '%s'"), global_params.dbname); exit_status++; goto cleanup; } #if 0 /************** Begin IFDEF'ed OUT *******************************/ if (retval = krb5_db_fini(util_context)) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while closing current database")); exit_status++; goto cleanup; } if ((retval = krb5_db_set_name(util_context, global_params.dbname))) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while setting active database to '%s'"), global_params.dbname); exit_status++; goto cleanup; } if ((retval = krb5_db_init(util_context))) { com_err(progname, retval, gettext("while initializing the database '%s'"), global_params.dbname); exit_status++; goto cleanup; } #endif /**************** END IFDEF'ed OUT *******************************/ /* Solaris Kerberos: for iprop */ if (log_ctx && log_ctx->iproprole) { if (retval = ulog_map(util_context, &global_params, FKCOMMAND)) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while creating update log")); exit_status++; goto cleanup; } /* * We're reinitializing the update log in case one already * existed, but this should never happen. */ (void) memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t)); log_ctx->ulog->kdb_hmagic = KDB_HMAGIC; log_ctx->ulog->db_version_num = KDB_VERSION; log_ctx->ulog->kdb_state = KDB_STABLE; log_ctx->ulog->kdb_block = ULOG_BLOCK; /* * Since we're creating a new db we shouldn't worry about * adding the initial principals since any slave might as well * do full resyncs from this newly created db. */ log_ctx->iproprole = IPROP_NULL; } if ((retval = add_principal(util_context, master_princ, MASTER_KEY, &rblock, &mkey)) || (retval = add_principal(util_context, &tgt_princ, TGT_KEY, &rblock, &mkey))) { (void) krb5_db_fini(util_context); /* Solaris Kerberos */ com_err(progname, retval, gettext("while adding entries to the database")); exit_status++; goto cleanup; } /* * Always stash the master key so kadm5_create does not prompt for * it; delete the file below if it was not requested. DO NOT EXIT * BEFORE DELETING THE KEYFILE if do_stash is not set. */ retval = krb5_db_store_master_key(util_context, global_params.stash_file, master_princ, &mkey, mkey_password); if (retval) { /* Solaris Kerberos */ com_err(progname, errno, gettext("while storing key")); printf(gettext("Warning: couldn't stash master key.\n")); } if (pw_str) memset(pw_str, 0, pw_size); if (kadm5_create(&global_params)) { if (!do_stash) unlink(global_params.stash_file); exit_status++; goto cleanup; } if (!do_stash) unlink(global_params.stash_file); /* Solaris Kerberos: deal with master_keyblock in better way */ cleanup: if (pw_str) { if (mkey_password == pw_str) mkey_password = NULL; free(pw_str); } if (master_salt.data) free(master_salt.data); krb5_free_keyblock(util_context, rblock.key); krb5_free_keyblock_contents(util_context, &mkey); (void) krb5_db_fini(util_context); return; } static krb5_error_code tgt_keysalt_iterate(ksent, ptr) krb5_key_salt_tuple *ksent; krb5_pointer ptr; { krb5_context context; krb5_error_code kret; struct iterate_args *iargs; krb5_keyblock key; krb5_int32 ind; krb5_data pwd; iargs = (struct iterate_args *) ptr; kret = 0; context = iargs->ctx; /* * Convert the master key password into a key for this particular * encryption system. */ pwd.data = mkey_password; pwd.length = strlen(mkey_password); kret = krb5_c_random_seed(context, &pwd); if (kret) return kret; if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) { ind = iargs->dbentp->n_key_data-1; if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype, &key))) { kret = krb5_dbekd_encrypt_key_data(context, iargs->rblock->key, &key, NULL, 1, &iargs->dbentp->key_data[ind]); krb5_free_keyblock_contents(context, &key); } } return(kret); } static krb5_error_code add_principal(context, princ, op, pblock, mkey) krb5_context context; krb5_principal princ; enum ap_op op; struct realm_info *pblock; krb5_keyblock *mkey; { krb5_error_code retval; krb5_db_entry entry; krb5_timestamp now; struct iterate_args iargs; int nentries = 1; memset((char *) &entry, 0, sizeof(entry)); entry.len = KRB5_KDB_V1_BASE_LENGTH; entry.attributes = pblock->flags; entry.max_life = pblock->max_life; entry.max_renewable_life = pblock->max_rlife; entry.expiration = pblock->expiration; if ((retval = krb5_copy_principal(context, princ, &entry.princ))) goto error_out; if ((retval = krb5_timeofday(context, &now))) goto error_out; if ((retval = krb5_dbe_update_mod_princ_data(context, &entry, now, &db_create_princ))) goto error_out; switch (op) { case MASTER_KEY: if ((entry.key_data=(krb5_key_data*)malloc(sizeof(krb5_key_data))) == NULL) goto error_out; memset((char *) entry.key_data, 0, sizeof(krb5_key_data)); entry.n_key_data = 1; entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; if ((retval = krb5_dbekd_encrypt_key_data(context, pblock->key, mkey, NULL, 1, entry.key_data))) goto error_out; break; case TGT_KEY: iargs.ctx = context; iargs.rblock = pblock; iargs.dbentp = &entry; /* * Iterate through the key/salt list, ignoring salt types. */ if ((retval = krb5_keysalt_iterate(pblock->kslist, pblock->nkslist, 1, tgt_keysalt_iterate, (krb5_pointer) &iargs))) return retval; break; case NULL_KEY: return EOPNOTSUPP; default: break; } entry.mask = (KADM5_KEY_DATA | KADM5_PRINCIPAL | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_TL_DATA | KADM5_PRINC_EXPIRE_TIME); retval = krb5_db_put_principal(context, &entry, &nentries); error_out:; krb5_db_free_principal(context, &entry, 1); return retval; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * admin/destroy/kdb5_destroy.c * * Copyright 1990 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * kdb_dest(roy): destroy the named database. * * This version knows about DBM format databases. */ #include "k5-int.h" #include #include "com_err.h" #include #include #include #include "kdb5_util.h" extern int exit_status; extern krb5_boolean dbactive; extern kadm5_config_params global_params; void kdb5_destroy(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; int optchar; char *dbname; char buf[5]; krb5_error_code retval1; krb5_context context; int force = 0; char ufilename[MAX_FILENAME]; retval1 = kadm5_init_krb5_context(&context); if( retval1 ) { /* Solaris Kerberos */ com_err(progname, retval1, "while initializing krb5_context"); exit(1); } if ((retval1 = krb5_set_default_realm(context, util_context->default_realm))) { /* Solaris Kerberos */ com_err(progname, retval1, "while setting default realm name"); exit(1); } /* Solaris Kerberos */ #if 0 if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; #endif dbname = global_params.dbname; optind = 1; while ((optchar = getopt(argc, argv, "f")) != -1) { switch(optchar) { case 'f': force++; break; case '?': default: usage(); return; /*NOTREACHED*/ } } if (!force) { printf(gettext("Deleting KDC database stored in '%s', " "are you sure?\n"), dbname); printf(gettext("(type 'yes' or 'y' to confirm)? ")); if (fgets(buf, sizeof(buf), stdin) == NULL) { exit_status++; return; } if ((strncmp(buf, gettext("yes\n"), strlen(gettext("yes\n"))) != 0) && (strncmp(buf, gettext("y\n"), strlen(gettext("y\n"))) != 0)) { printf(gettext("database not deleted !! '%s'...\n"), dbname); exit_status++; return; } printf(gettext("OK, deleting database '%s'...\n"), dbname); } retval1 = krb5_db_destroy(context, db5util_db_args); /* check for a stash file and delete it if necessary */ if (global_params.stash_file == NULL) { char stash[MAXPATHLEN+1]; extern krb5_principal master_princ; krb5_data *realm = krb5_princ_realm(context, master_princ); (void) strlcpy(stash, DEFAULT_KEYFILE_STUB, sizeof (stash)); /* * realm->data is not necessarily NULL terminated so be * careful how much data is copied here. Don't overrun * the "stash" buffer and dont overrun the realm->data buffer, * copy the smaller of the 2 lengths. */ (void) strncat(stash, realm->data, (realm->length < (MAXPATHLEN-strlen(stash)) ? realm->length : MAXPATHLEN-strlen(stash))); global_params.stash_file = (char *)strdup(stash); } if (!access(global_params.stash_file, F_OK)) (void)unlink(global_params.stash_file); if (retval1) { /* Solaris Kerberos */ com_err(progname, retval1, gettext("deleting database '%s'"), dbname); exit_status++; return; } if (global_params.iprop_enabled) { if (strlcpy(ufilename, dbname, MAX_FILENAME) >= MAX_FILENAME) { exit_status++; return; } if (strlcat(ufilename, ".ulog", MAX_FILENAME) >= MAX_FILENAME) { exit_status++; return; } (void) unlink(ufilename); } dbactive = FALSE; printf(gettext("** Database '%s' destroyed.\n"), dbname); return; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * admin/stash/kdb5_stash.c * * Copyright 1990 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * Store the master database key in a file. */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * 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 FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include "k5-int.h" #include #include "com_err.h" #include #include #include #include "kdb5_util.h" extern krb5_principal master_princ; extern kadm5_config_params global_params; extern int exit_status; void kdb5_stash(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; int optchar; krb5_error_code retval; char *dbname = (char *) NULL; char *realm = 0; char *mkey_name = 0; char *mkey_fullname; char *keyfile = 0; krb5_context context; krb5_keyblock mkey; /* Solaris Kerberos */ #if 0 if (strrchr(argv[0], '/')) argv[0] = strrchr(argv[0], '/')+1; #endif retval = kadm5_init_krb5_context(&context); if( retval ) { /* Solaris Kerberos */ com_err(progname, retval, "while initializing krb5_context"); exit(1); } if ((retval = krb5_set_default_realm(context, util_context->default_realm))) { /* Solaris Kerberos */ com_err(progname, retval, "while setting default realm name"); exit(1); } dbname = global_params.dbname; realm = global_params.realm; mkey_name = global_params.mkey_name; keyfile = global_params.stash_file; optind = 1; while ((optchar = getopt(argc, argv, "f:")) != -1) { switch(optchar) { case 'f': keyfile = optarg; break; case '?': default: usage(); return; } } if (!krb5_c_valid_enctype(global_params.enctype)) { char tmp[32]; if (krb5_enctype_to_string(global_params.enctype, tmp, sizeof (tmp))) /* Solaris Kerberos */ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, gettext("while setting up enctype %d"), global_params.enctype); else { /* Solaris Kerberos */ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, tmp); } exit_status++; return; } /* assemble & parse the master key name */ retval = krb5_db_setup_mkey_name(context, mkey_name, realm, &mkey_fullname, &master_princ); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while setting up master key name")); exit_status++; return; } retval = krb5_db_open(context, db5util_db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_OTHER); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while initializing the database '%s'"), dbname); exit_status++; return; } /* TRUE here means read the keyboard, but only once */ retval = krb5_db_fetch_mkey(context, master_princ, global_params.enctype, TRUE, FALSE, (char *) NULL, 0, &mkey); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while reading master key")); (void) krb5_db_fini(context); exit_status++; return; } retval = krb5_db_verify_master_key(context, master_princ, &mkey); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while verifying master key")); krb5_free_keyblock_contents(context, &mkey); (void) krb5_db_fini(context); exit_status++; return; } retval = krb5_db_store_master_key(context, keyfile, master_princ, &mkey, NULL); if (retval) { /* Solaris Kerberos */ com_err(progname, errno, gettext("while storing key")); krb5_free_keyblock_contents(context, &mkey); (void) krb5_db_fini(context); exit_status++; return; } krb5_free_keyblock_contents(context, &mkey); retval = krb5_db_fini(context); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("closing database '%s'"), dbname); exit_status++; return; } krb5_free_context(context); exit_status = 0; return; } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * admin/edit/kdb5_edit.c * * (C) Copyright 1990,1991, 1996 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * Edit a KDC database. */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * 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 FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Yes, I know this is a hack, but we need admin.h without including the * rpc.h header. Additionally, our rpc.h header brings in * a des.h header which causes other problems. */ #define _RPC_RPC_H #include #include #include #include #include #include #include #include #include #include "kdb5_util.h" char *Err_no_master_msg = "Master key not entered!\n"; char *Err_no_database = "Database not currently opened!\n"; /* * XXX Ick, ick, ick. These global variables shouldn't be global.... */ char *mkey_password = 0; /* * I can't figure out any way for this not to be global, given how ss * works. */ int exit_status = 0; krb5_context util_context; kadm5_config_params global_params; void usage() { fprintf(stderr, "%s: " "kdb5_util [-x db_args]* [-r realm] [-d dbname] [-k mkeytype] [-M mkeyname]\n" "\t [-sf stashfilename] [-P password] [-m] cmd [cmd_options]\n" "\tcreate [-s]\n" "\tdestroy [-f]\n" "\tstash [-f keyfile]\n" "\tdump [-old] [-ov] [-b6] [-verbose] [filename [princs...]]\n" "\t [-mkey_convert] [-new_mkey_file mkey_file]\n" "\t [-rev] [-recurse] [filename [princs...]]\n" "\tload [-old] [-ov] [-b6] [-verbose] [-update] filename\n" "\tark [-e etype_list] principal\n" "\nwhere,\n\t[-x db_args]* - any number of database specific arguments.\n" "\t\t\tLook at each database documentation for supported arguments\n", gettext("Usage")); exit(1); } krb5_keyblock master_key; extern krb5_principal master_princ; krb5_db_entry master_entry; int valid_master_key = 0; char *progname; krb5_boolean manual_mkey = FALSE; krb5_boolean dbactive = FALSE; static int open_db_and_mkey(void); static void add_random_key(int, char **); typedef void (*cmd_func)(int, char **); struct _cmd_table { char *name; cmd_func func; int opendb; } cmd_table[] = { {"create", kdb5_create, 0}, {"destroy", kdb5_destroy, 1}, {"stash", kdb5_stash, 1}, {"dump", dump_db, 1}, {"load", load_db, 0}, {"ark", add_random_key, 1}, {NULL, NULL, 0}, }; static struct _cmd_table *cmd_lookup(name) char *name; { struct _cmd_table *cmd = cmd_table; while (cmd->name) { if (strcmp(cmd->name, name) == 0) return cmd; else cmd++; } return NULL; } #define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL)) char **db5util_db_args = NULL; int db5util_db_args_size = 0; static void extended_com_err_fn (const char *myprog, errcode_t code, const char *fmt, va_list args) { const char *emsg; if (code) { emsg = krb5_get_error_message (util_context, code); fprintf (stderr, "%s: %s ", myprog, emsg); krb5_free_error_message (util_context, emsg); } else { fprintf (stderr, "%s: ", myprog); } vfprintf (stderr, fmt, args); fprintf (stderr, "\n"); } int add_db_arg(char *arg) { char **temp; db5util_db_args_size++; temp = realloc(db5util_db_args, sizeof(char *) * (db5util_db_args_size + 1)); if (temp == NULL) return 0; db5util_db_args = temp; db5util_db_args[db5util_db_args_size-1] = arg; db5util_db_args[db5util_db_args_size] = NULL; return 1; } int main(argc, argv) int argc; char *argv[]; { struct _cmd_table *cmd = NULL; char *koptarg, **cmd_argv; char *db_name_tmp = NULL; int cmd_argc; krb5_error_code retval; (void) setlocale(LC_ALL, ""); set_com_err_hook(extended_com_err_fn); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); Err_no_master_msg = gettext("Master key not entered!\n"); Err_no_database = gettext("Database not currently opened!\n"); /* * Solaris Kerberos: * Ensure that "progname" is set before calling com_err. */ progname = (strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0]); retval = kadm5_init_krb5_context(&util_context); if (retval) { com_err (progname, retval, gettext("while initializing Kerberos code")); exit(1); } cmd_argv = (char **) malloc(sizeof(char *)*argc); if (cmd_argv == NULL) { com_err(progname, ENOMEM, gettext("while creating sub-command arguments")); exit(1); } memset(cmd_argv, 0, sizeof(char *)*argc); cmd_argc = 1; argv++; argc--; while (*argv) { if (strcmp(*argv, "-P") == 0 && ARG_VAL) { mkey_password = koptarg; manual_mkey = TRUE; } else if (strcmp(*argv, "-d") == 0 && ARG_VAL) { global_params.dbname = koptarg; global_params.mask |= KADM5_CONFIG_DBNAME; db_name_tmp = malloc( strlen(global_params.dbname) + sizeof("dbname=")); if( db_name_tmp == NULL ) { com_err(progname, ENOMEM, "while parsing command arguments"); exit(1); } strcpy( db_name_tmp, "dbname="); strcat( db_name_tmp, global_params.dbname ); if (!add_db_arg(db_name_tmp)) { com_err(progname, ENOMEM, "while parsing command arguments\n"); exit(1); } } else if (strcmp(*argv, "-x") == 0 && ARG_VAL) { if (!add_db_arg(koptarg)) { com_err(progname, ENOMEM, "while parsing command arguments\n"); exit(1); } } else if (strcmp(*argv, "-r") == 0 && ARG_VAL) { global_params.realm = koptarg; global_params.mask |= KADM5_CONFIG_REALM; /* not sure this is really necessary */ if ((retval = krb5_set_default_realm(util_context, global_params.realm))) { com_err(progname, retval, gettext("while setting default " "realm name")); exit(1); } } else if (strcmp(*argv, "-k") == 0 && ARG_VAL) { if (krb5_string_to_enctype(koptarg, &global_params.enctype)) { /* Solaris Kerberos */ com_err(progname, 0, gettext("%s is an invalid enctype"), koptarg); } else global_params.mask |= KADM5_CONFIG_ENCTYPE; } else if (strcmp(*argv, "-M") == 0 && ARG_VAL) { global_params.mkey_name = koptarg; global_params.mask |= KADM5_CONFIG_MKEY_NAME; } else if (((strcmp(*argv, "-sf") == 0) /* SUNWresync121 - carry the old -f forward too */ || (strcmp(*argv, "-f") == 0)) && ARG_VAL) { global_params.stash_file = koptarg; global_params.mask |= KADM5_CONFIG_STASH_FILE; } else if (strcmp(*argv, "-m") == 0) { manual_mkey = TRUE; global_params.mkey_from_kbd = 1; global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; } else if (cmd_lookup(*argv) != NULL) { if (cmd_argv[0] == NULL) cmd_argv[0] = *argv; else usage(); } else { cmd_argv[cmd_argc++] = *argv; } argv++; argc--; } if (cmd_argv[0] == NULL) usage(); if( !util_context->default_realm ) { char *temp = NULL; retval = krb5_get_default_realm(util_context, &temp); if( retval ) { com_err (progname, retval, "while getting default realm"); exit(1); } util_context->default_realm = temp; } retval = kadm5_get_config_params(util_context, 1, &global_params, &global_params); if (retval) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while retreiving configuration parameters")); exit(1); } /* * Dump creates files which should not be world-readable. It is * easiest to do a single umask call here. */ (void) umask(077); (void) memset(&master_key, 0, sizeof (krb5_keyblock)); if ((global_params.enctype != ENCTYPE_UNKNOWN) && (!krb5_c_valid_enctype(global_params.enctype))) { /* Solaris Kerberos */ com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, gettext("while setting up enctype %d"), global_params.enctype); exit(1); } cmd = cmd_lookup(cmd_argv[0]); if (cmd->opendb && open_db_and_mkey()) return exit_status; if (global_params.iprop_enabled == TRUE) ulog_set_role(util_context, IPROP_MASTER); else ulog_set_role(util_context, IPROP_NULL); (*cmd->func)(cmd_argc, cmd_argv); if( db_name_tmp ) free( db_name_tmp ); if( db5util_db_args ) free(db5util_db_args); kadm5_free_config_params(util_context, &global_params); krb5_free_context(util_context); return exit_status; } #if 0 /* * This function is no longer used in kdb5_util (and it would no * longer work, anyway). */ void set_dbname(argc, argv) int argc; char *argv[]; { krb5_error_code retval; if (argc < 3) { /* Solaris Kerberos */ com_err(progname, 0, gettext("Too few arguments")); com_err(progname, 0, gettext("Usage: %s dbpathname realmname"), progname); exit_status++; return; } if (dbactive) { if ((retval = krb5_db_fini(util_context)) && retval!= KRB5_KDB_DBNOTINITED) { /* Solaris Kerberos */ com_err(progname, retval, gettext("while closing previous database")); exit_status++; return; } if (valid_master_key) { krb5_free_keyblock_contents(util_context, &master_key); master_key.contents = NULL; valid_master_key = 0; } krb5_free_principal(util_context, master_princ); dbactive = FALSE; } /* Solaris Kerberos */ (void) set_dbname_help(progname, argv[1]); return; } #endif /* * open_db_and_mkey: Opens the KDC and policy database, and sets the * global master_* variables. Sets dbactive to TRUE if the databases * are opened, and valid_master_key to 1 if the global master * variables are set properly. Returns 0 on success, and 1 on * failure, but it is not considered a failure if the master key * cannot be fetched (the master key stash file may not exist when the * program is run). */ static int open_db_and_mkey() { krb5_error_code retval; int nentries; krb5_boolean more; krb5_data scratch, pwd, seed; dbactive = FALSE; valid_master_key = 0; if ((retval = krb5_db_open(util_context, db5util_db_args, KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) { com_err(progname, retval, "while initializing database"); exit_status++; return(1); } /* assemble & parse the master key name */ if ((retval = krb5_db_setup_mkey_name(util_context, global_params.mkey_name, global_params.realm, 0, &master_princ))) { com_err(progname, retval, gettext("while setting up master key name")); exit_status++; return(1); } nentries = 1; if ((retval = krb5_db_get_principal(util_context, master_princ, &master_entry, &nentries, &more))) { com_err(progname, retval, gettext("while retrieving master entry")); exit_status++; (void) krb5_db_fini(util_context); return(1); } else if (more) { com_err(progname, KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE, gettext("while retrieving master entry")); exit_status++; (void) krb5_db_fini(util_context); return(1); } else if (!nentries) { com_err(progname, KRB5_KDB_NOENTRY, gettext("while retrieving master entry")); exit_status++; (void) krb5_db_fini(util_context); return(1); } krb5_db_free_principal(util_context, &master_entry, nentries); /* the databases are now open, and the master principal exists */ dbactive = TRUE; if (mkey_password) { pwd.data = mkey_password; pwd.length = strlen(mkey_password); retval = krb5_principal2salt(util_context, master_princ, &scratch); if (retval) { com_err(progname, retval, gettext("while calculated master key salt")); /* Solaris Kerberos */ exit_status++; return(1); } /* If no encryption type is set, use the default */ if (global_params.enctype == ENCTYPE_UNKNOWN) { global_params.enctype = DEFAULT_KDC_ENCTYPE; if (!krb5_c_valid_enctype(global_params.enctype)) com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP, gettext("while setting up enctype %d"), global_params.enctype); } retval = krb5_c_string_to_key(util_context, global_params.enctype, &pwd, &scratch, &master_key); if (retval) { com_err(progname, retval, gettext("while transforming master key from password")); /* Solaris Kerberos */ exit_status++; return(1); } free(scratch.data); mkey_password = 0; } else if ((retval = krb5_db_fetch_mkey(util_context, master_princ, global_params.enctype, manual_mkey, FALSE, global_params.stash_file, 0, &master_key))) { com_err(progname, retval, gettext("while reading master key")); com_err(progname, 0, gettext("Warning: proceeding without master key")); /* * Solaris Kerberos: We don't want to count as an error if for instance * the stash file is not present and we are trying to automate * propagation, which really doesn't need a master key to do so. */ if (retval != KRB5_KDB_CANTREAD_STORED) exit_status++; return(0); } if ((retval = krb5_db_verify_master_key(util_context, master_princ, &master_key))) { com_err(progname, retval, gettext("while verifying master key")); exit_status++; krb5_free_keyblock_contents(util_context, &master_key); return(1); } seed.length = master_key.length; seed.data = (char *)master_key.contents; if ((retval = krb5_c_random_seed(util_context, &seed))) { com_err(progname, retval, gettext("while initializing random key generator")); exit_status++; krb5_free_keyblock_contents(util_context, &master_key); return(1); } valid_master_key = 1; dbactive = TRUE; return 0; } #ifdef HAVE_GETCWD #undef getwd #endif int quit() { krb5_error_code retval; static krb5_boolean finished = 0; if (finished) return 0; retval = krb5_db_fini(util_context); krb5_free_keyblock_contents(util_context, &master_key); finished = TRUE; krb5_free_context(util_context); if (retval && retval != KRB5_KDB_DBNOTINITED) { com_err(progname, retval, gettext("while closing database")); exit_status++; return 1; } return 0; } static void add_random_key(argc, argv) int argc; char **argv; { krb5_error_code ret; krb5_principal princ; krb5_db_entry dbent; int n; krb5_boolean more; krb5_timestamp now; krb5_key_salt_tuple *keysalts = NULL; krb5_int32 num_keysalts = 0; int free_keysalts; /* Solaris Kerberos */ char *me = progname; char *ks_str = NULL; char *pr_str; if (argc < 2) usage(); for (argv++, argc--; *argv; argv++, argc--) { if (!strcmp(*argv, "-e")) { argv++; argc--; ks_str = *argv; continue; } else break; } if (argc < 1) usage(); pr_str = *argv; ret = krb5_parse_name(util_context, pr_str, &princ); if (ret) { com_err(me, ret, gettext("while parsing principal name %s"), pr_str); exit_status++; return; } n = 1; ret = krb5_db_get_principal(util_context, princ, &dbent, &n, &more); if (ret) { com_err(me, ret, gettext("while fetching principal %s"), pr_str); exit_status++; return; } if (n != 1) { fprintf(stderr, gettext("principal %s not found\n"), pr_str); exit_status++; return; } if (more) { fprintf(stderr, gettext("principal %s not unique\n"), pr_str); krb5_db_free_principal(util_context, &dbent, 1); exit_status++; return; } ret = krb5_string_to_keysalts(ks_str, ", \t", ":.-", 0, &keysalts, &num_keysalts); if (ret) { com_err(me, ret, gettext("while parsing keysalts %s"), ks_str); exit_status++; return; } if (!num_keysalts || keysalts == NULL) { num_keysalts = global_params.num_keysalts; keysalts = global_params.keysalts; free_keysalts = 0; } else free_keysalts = 1; ret = krb5_dbe_ark(util_context, &master_key, keysalts, num_keysalts, &dbent); if (free_keysalts) free(keysalts); if (ret) { com_err(me, ret, gettext("while randomizing principal %s"), pr_str); krb5_db_free_principal(util_context, &dbent, 1); exit_status++; return; } dbent.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; ret = krb5_timeofday(util_context, &now); if (ret) { com_err(me, ret, gettext("while getting time")); krb5_db_free_principal(util_context, &dbent, 1); exit_status++; return; } ret = krb5_dbe_update_last_pwd_change(util_context, &dbent, now); if (ret) { com_err(me, ret, gettext("while setting changetime")); krb5_db_free_principal(util_context, &dbent, 1); exit_status++; return; } ret = krb5_db_put_principal(util_context, &dbent, &n); krb5_db_free_principal(util_context, &dbent, 1); if (ret) { com_err(me, ret, gettext("while saving principal %s"), pr_str); exit_status++; return; } printf("%s changed\n", pr_str); } /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _KDB5_UTIL_H #define _KDB5_UTIL_H /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #ifdef __cplusplus extern "C" { #endif /* * admin/edit/kdb5_edit.h * * Copyright 1992 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * */ #include #define MAX_HEADER 1024 #define REALM_SEP '@' #define REALM_SEP_STR "@" extern char *progname; extern char *Err_no_database; #ifndef V4_DECLARES_STATIC extern krb5_keyblock master_keyblock; extern krb5_principal master_princ; #endif extern krb5_boolean dbactive; extern int exit_status; extern krb5_context util_context; extern kadm5_config_params global_params; extern int valid_master_key; extern krb5_db_entry master_db; extern char **db5util_db_args; extern int db5util_db_args_size; extern int add_db_arg(char *arg); extern void usage(void); extern void add_key (char const *, char const *, krb5_const_principal, const krb5_keyblock *, krb5_kvno, krb5_keysalt *); extern int set_dbname_help (char *, char *); extern char *kdb5_util_Init (int, char **); extern int quit (void); extern int check_for_match (char *, int, krb5_db_entry *, int, int); extern void parse_token (char *, int *, int *, char *); extern int create_db_entry (krb5_principal, krb5_db_entry *); extern int kadm5_create_magic_princs (kadm5_config_params *params, krb5_context context); extern int process_ov_principal (char *fname, krb5_context kcontext, FILE *filep, int verbose, int *linenop); extern void load_db (int argc, char **argv); extern void dump_db (int argc, char **argv); extern void kdb5_create (int argc, char **argv); extern void kdb5_destroy (int argc, char **argv); extern void kdb5_stash (int argc, char **argv); extern void update_ok_file (char *file_name); extern int kadm5_create (kadm5_config_params *params); void usage (void); #ifdef __cplusplus } #endif #endif /* !_KDB5_UTIL_H */ /* Prototype for nstrtok */ char *nstrtok(char *, const char *delim); /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include #include #include #include "autoconf.h" #ifdef HAVE_MEMORY_H #include #endif #include #include #include #include #include "import_err.h" #include "kdb5_util.h" #include "nstrtok.h" #define LINESIZE 32768 /* XXX */ #define PLURAL(count) (((count) == 1) ? error_message(IMPORT_SINGLE_RECORD) : error_message(IMPORT_PLURAL_RECORDS)) static int parse_pw_hist_ent(current, hist) char *current; osa_pw_hist_ent *hist; { int tmp, i, j, ret; char *cp; ret = 0; hist->n_key_data = 1; hist->key_data = (krb5_key_data *) malloc(hist->n_key_data * sizeof(krb5_key_data)); if (hist->key_data == NULL) return ENOMEM; memset(hist->key_data, 0, sizeof(krb5_key_data)*hist->n_key_data); for (i = 0; i < hist->n_key_data; i++) { krb5_key_data *key_data = &hist->key_data[i]; key_data->key_data_ver = 1; if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } key_data->key_data_type[0] = atoi(cp); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } key_data->key_data_length[0] = atoi(cp); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } if(!(key_data->key_data_contents[0] = (krb5_octet *) malloc(key_data->key_data_length[0]+1))) { ret = ENOMEM; goto done; } for(j = 0; j < key_data->key_data_length[0]; j++) { if(sscanf(cp, "%02x", &tmp) != 1) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } key_data->key_data_contents[0][j] = tmp; cp = strchr(cp, ' ') + 1; } } done: return ret; } /* * Function: parse_principal * * Purpose: parse principal line in db dump file * * Arguments: * 0 on success, error code on failure * * Requires: * principal database to be opened. * nstrtok(3) to have a valid buffer in memory. * * Effects: * [effects] * * Modifies: * [modifies] * */ int process_ov_principal(fname, kcontext, filep, verbose, linenop) char *fname; krb5_context kcontext; FILE *filep; int verbose; int *linenop; { XDR xdrs; osa_princ_ent_t rec; krb5_error_code ret; krb5_tl_data tl_data; krb5_principal princ; krb5_db_entry kdb; char *current; char *cp; int x, one; krb5_boolean more; char line[LINESIZE]; if (fgets(line, LINESIZE, filep) == (char *) NULL) { return IMPORT_BAD_FILE; } if((cp = nstrtok(line, "\t")) == NULL) return IMPORT_BAD_FILE; if((rec = (osa_princ_ent_t) malloc(sizeof(osa_princ_ent_rec))) == NULL) return ENOMEM; memset(rec, 0, sizeof(osa_princ_ent_rec)); if((ret = krb5_parse_name(kcontext, cp, &princ))) goto done; krb5_unparse_name(kcontext, princ, ¤t); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } else { if(strcmp(cp, "")) { if((rec->policy = (char *) malloc(strlen(cp)+1)) == NULL) { ret = ENOMEM; goto done; } strcpy(rec->policy, cp); } else rec->policy = NULL; } if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } rec->aux_attributes = strtol(cp, (char **)NULL, 16); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } rec->old_key_len = atoi(cp); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } rec->old_key_next = atoi(cp); if((cp = nstrtok((char *) NULL, "\t")) == NULL) { com_err(NULL, IMPORT_BAD_RECORD, "%s", current); ret = IMPORT_FAILED; goto done; } rec->admin_history_kvno = atoi(cp); if (! rec->old_key_len) { rec->old_keys = NULL; } else { if(!(rec->old_keys = (osa_pw_hist_ent *) malloc(sizeof(osa_pw_hist_ent) * rec->old_key_len))) { ret = ENOMEM; goto done; } memset(rec->old_keys,0, sizeof(osa_pw_hist_ent) * rec->old_key_len); for(x = 0; x < rec->old_key_len; x++) parse_pw_hist_ent(current, &rec->old_keys[x]); } xdralloc_create(&xdrs, XDR_ENCODE); if (! xdr_osa_princ_ent_rec(&xdrs, rec)) { xdr_destroy(&xdrs); ret = KADM5_XDR_FAILURE; goto done; } tl_data.tl_data_type = KRB5_TL_KADM_DATA; tl_data.tl_data_length = xdr_getpos(&xdrs); tl_data.tl_data_contents = (krb5_octet *) xdralloc_getdata(&xdrs); one = 1; ret = krb5_db_get_principal(kcontext, princ, &kdb, &one, &more); if (ret) goto done; ret = krb5_dbe_update_tl_data(kcontext, &kdb, &tl_data); if (ret) goto done; ret = krb5_db_put_principal(kcontext, &kdb, &one); if (ret) goto done; xdr_destroy(&xdrs); (*linenop)++; done: free(current); krb5_free_principal(kcontext, princ); osa_free_princ_ent(rec); return ret; } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * */ /* String table of messages for kadm5_create */ /* * I18n HACK. We define gettext(s) to be s so that we can extract the * strings here to the .po file. At the end of this file we will undef * gettext. */ #define gettext(s) s char *str_PARSE_NAME = gettext("while parsing admin principal name."); char *str_HISTORY_PARSE_NAME = gettext("while parsing admin history principal name."); char *str_ADMIN_PRINC_EXISTS = gettext("Warning! Admin principal already exists."); char *str_CHANGEPW_PRINC_EXISTS = gettext("Warning! Changepw principal already exists."); char *str_HISTORY_PRINC_EXISTS = gettext("Warning! Admin history principal already exists."); char *str_ADMIN_PRINC_WRONG_ATTRS = gettext("Warning! Admin principal has incorrect attributes.\n" "\tDISALLOW_TGT should be set, and max_life should be three hours.\n" "\tThis program will leave them as-is, but beware!."); char *str_CHANGEPW_PRINC_WRONG_ATTRS = gettext("Warning! Changepw principal has incorrect attributes.\n" "\tDISALLOW_TGT and PW_CHANGE_SERVICE should both be set, and " "max_life should be five minutes.\n" "\tThis program will leave them as-is, but beware!."); char *str_HISTORY_PRINC_WRONG_ATTRS = gettext("Warning! Admin history principal has incorrect attributes.\n" "\tDISALLOW_ALL_TIX should be set.\n" "\tThis program will leave it as-is, but beware!."); char *str_CREATED_PRINC_DB = gettext("%s: Admin principal database created " "(or it already existed).\n"); /* whoami */ char *str_CREATED_POLICY_DB = gettext("%s: Admin policy database created " "(or it already existed).\n"); /* whoami */ char *str_RANDOM_KEY = gettext("while calling random key for %s."); /* principal name */ char *str_ENCRYPT_KEY = gettext("while calling encrypt key for %s."); /* principal name */ char *str_PUT_PRINC = gettext("while storing %s in Kerberos database."); /* principal name */ char *str_CREATING_POLICY_DB = gettext("while creating/opening admin policy database."); char *str_CLOSING_POLICY_DB = gettext("while closing admin policy database."); char *str_CREATING_PRINC_DB = gettext("while creating/opening admin principal database."); char *str_CLOSING_PRINC_DB = gettext("while closing admin principal database."); char *str_CREATING_PRINC_ENTRY = gettext("while creating admin principal " "database entry for %s."); /* princ_name */ char *str_A_PRINC = gettext("a principal"); char *str_UNPARSE_PRINC = gettext("while unparsing principal."); char *str_CREATED_PRINC = gettext("%s: Created %s principal.\n"); /* whoami, princ_name */ char *str_INIT_KDB = gettext("while initializing kdb."); char *str_NO_KDB = gettext("while initializing kdb.\nThe Kerberos KDC database " "needs to exist in /krb5.\nIf you haven't run " "kdb5_create you need to do so before running this command."); char *str_INIT_RANDOM_KEY = gettext("while initializing random key generator."); char *str_TOO_MANY_ADMIN_PRINC = gettext("while fetching admin princ. Can only have one admin principal."); char *str_TOO_MANY_CHANGEPW_PRINC = gettext("while fetching changepw princ. " "Can only have one changepw principal."); char *str_TOO_MANY_HIST_PRINC = gettext("while fetching history princ. " "Can only have one history principal."); char *str_WHILE_DESTROYING_ADMIN_SESSION = gettext("while closing session with admin server and destroying tickets."); #undef gettext /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _STRING_TABLE_H #define _STRING_TABLE_H /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #ifdef __cplusplus extern "C" { #endif /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * * $Header: /afs/athena.mit.edu/astaff/project/krbdev/.cvsroot/src/kadmin/\ * dbutil/string_table.h,v 1.2 1996/07/22 20:25:25 marc Exp $ * */ #ifndef _OVSEC_ADM_STRINGS_ extern char *str_PARSE_NAME; extern char *str_HISTORY_PARSE_NAME; extern char *str_ADMIN_PRINC_EXISTS; extern char *str_CHANGEPW_PRINC_EXISTS; extern char *str_HISTORY_PRINC_EXISTS; extern char *str_ADMIN_PRINC_WRONG_ATTRS; extern char *str_CHANGEPW_PRINC_WRONG_ATTRS; extern char *str_HISTORY_PRINC_WRONG_ATTRS; extern char *str_CREATED_PRINC_DB; extern char *str_CREATED_POLICY_DB; extern char *str_RANDOM_KEY; extern char *str_ENCRYPT_KEY; extern char *str_PUT_PRINC; extern char *str_CREATING_POLICY_DB; extern char *str_CLOSING_POLICY_DB; extern char *str_CREATING_PRINC_DB; extern char *str_CLOSING_PRINC_DB; extern char *str_CREATING_PRINC_ENTRY; extern char *str_A_PRINC; extern char *str_UNPARSE_PRINC; extern char *str_CREATED_PRINC; extern char *str_INIT_KDB; extern char *str_NO_KDB; extern char *str_INIT_RANDOM_KEY; extern char *str_TOO_MANY_ADMIN_PRINC; extern char *str_TOO_MANY_CHANGEPW_PRINC; extern char *str_TOO_MANY_HIST_PRINC; extern char *str_WHILE_DESTROYING_ADMIN_SESSION; #endif /* _OVSEC_ADM_STRINGS_ */ #ifdef __cplusplus } #endif #endif /* !_STRING_TABLE_H */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * */ /* * Copyright (c) 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that: (1) source distributions retain this entire copyright * notice and comment, and (2) distributions including binaries display * the following acknowledgement: ``This product includes software * developed by the University of California, Berkeley and its contributors'' * in the documentation or other materials provided with the distribution * and in all advertising materials mentioning features or use of this * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include "nstrtok.h" /* * Function: nstrtok * * Purpose: the same as strtok ... just different. does not deal with * multiple tokens in row. * * Arguments: * s (input) string to scan * delim (input) list of delimiters * string or null on error. * * Requires: * nuttin * * Effects: * sets last to string * * Modifies: * last * */ char * nstrtok(s, delim) register char *s; register const char *delim; { register const char *spanp; register int c, sc; char *tok; static char *last; if (s == NULL && (s = last) == NULL) return (NULL); /* * Skip (span) leading delimiters (s += strspn(s, delim), sort of). */ #ifdef OLD cont: c = *s++; for (spanp = delim; (sc = *spanp++) != 0;) { if (c == sc) goto cont; } if (c == 0) { /* no non-delimiter characters */ last = NULL; return (NULL); } tok = s - 1; #else tok = s; #endif /* * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for (;;) { c = *s++; spanp = delim; do { if ((sc = *spanp++) == c) { if (c == 0) s = NULL; else s[-1] = 0; last = s; return (tok); } } while (sc != 0); } /* NOTREACHED */ } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * admin/edit/util.c * * Copyright 1992 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * Utilities for kdb5_edit. * * Some routines derived from code contributed by the Sandia National * Laboratories. Sandia National Laboratories also makes no * representations about the suitability of the modifications, or * additions to this software for any purpose. It is provided "as is" * without express or implied warranty. * */ #include #include "./kdb5_edit.h" #ifndef HAVE_STRSTR char * strstr(s1, s2) char *s1; char *s2; { int s2len; int i; char *temp_ptr; temp_ptr = s1; for ( i = 0; i < strlen(s1); i++) { if (memcmp(temp_ptr, s2, strlen(s2)) == 0) return(temp_ptr); temp_ptr += 1; } return ((char *) 0); } #endif /* HAVE_STRSTR */ void parse_token(token_in, must_be_first_char, num_tokens, tokens_out) char *token_in; int *must_be_first_char; int *num_tokens; char *tokens_out; { int i, j; int token_count = 0; i = 0; j = 0; /* Eliminate Up Front Asterisks */ *must_be_first_char = 1; for (i = 0; token_in[i] == '*'; i++) { *must_be_first_char = 0; } if (i == strlen(token_in)) { *num_tokens = 0; return; } /* Fill first token_out */ token_count++; while ((token_in[i] != '*') && (token_in[i] != '\0')) { tokens_out[j] = token_in[i]; j++; i++; } if (i == strlen(token_in)) { tokens_out[j] = '\0'; *num_tokens = token_count; return; } /* Then All Subsequent Tokens */ while (i < strlen(token_in)) { if (token_in[i] == '*') { token_count++; tokens_out[j] = '\t'; } else { tokens_out[j] = token_in[i]; } i++; j++; } tokens_out[j] = '\0'; if (tokens_out[j - 1] == '\t') { token_count--; tokens_out[j - 1] = '\0'; } *num_tokens = token_count; return; } int check_for_match(search_field, must_be_first_character, chk_entry, num_tokens, type) int must_be_first_character; char *search_field; krb5_db_entry *chk_entry; int num_tokens; int type; { char token1[256]; char *found1; char token2[256]; char *found2; char token3[256]; char *found3; char *local_entry; local_entry = chk_entry->princ->data[type].data; token1[0] = token2[0] = token3[0] = '\0'; (void) sscanf(search_field, "%s\t%s\t%s", token1, token2, token3); found1 = strstr(local_entry, token1); if (must_be_first_character && (found1 != local_entry)) return(0); if (found1 && (num_tokens == 1)) return(1); if (found1 && (num_tokens > 1)) { found2 = strstr(local_entry, token2); if (found2 && (found2 > found1) && (num_tokens == 2)) return(1); } if ((found2 > found1) && (num_tokens == 3)) { found3 = strstr(local_entry, token3); if (found3 && (found3 > found2) && (found2 > found1)) return(1); } return(0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # # Makefile for Kerberos client-install utility. # # Copyright (c) 2018, Joyent, Inc. PROG= ksetpw \ kdyndns \ ksmb \ kconf SHFILES= kclient SECFILES= pam_krb5_first \ pam_krb5_only \ pam_krb5_optional CLOBBERFILES += $(SHFILES) KRB5SBINSHFILES=$(SHFILES:%=$(KRB5SBIN)/%) USRLIBSEC= $(ROOT)/usr/lib/security SEC= $(SECFILES:%=$(USRLIBSEC)/%) $(SEC): FILEMODE = $(LIBFILEMODE) KS_OBJS= ksetpw.o KD_OBJS= kdyndns.o KSMB_OBJS= ksmb.o KC_OBJS= kconf.o OBJS= $(KS_OBJS) $(KD_OBJS) $(KSMB_OBJS) $(KC_OBJS) SSRCS= kclient.sh SRCS= $(OBJS:%.o=%.c) include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE= $(SSRCS:%.sh=%.po) CPPFLAGS += -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/lib/krb5 -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-function # not linted SMATCH=off ksetpw: LDFLAGS += $(KRUNPATH) kdyndns: LDFLAGS += -R/usr/lib/smbsrv ksmb: LDFLAGS += -R/usr/lib/smbsrv # Hammerhead: GNU ld needs rpath-link for transitive deps (libsmb, mech_krb5) via libsmbns kdyndns ksmb: LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/smbsrv -Wl,-rpath-link,$(ROOT)/usr/lib/gss kconf: LDFLAGS += $(KRUNPATH) KS_LDLIBS = $(LDLIBS) $(KMECHLIB) KD_LDLIBS = $(LDLIBS) -L$(ROOT)/usr/lib/smbsrv -lsmbns KSMB_LDLIBS = $(LDLIBS) -L$(ROOT)/usr/lib/smbsrv -lsmb KC_LDLIBS = $(LDLIBS) $(KMECHLIB) .KEEP_STATE: all: $(PROG) $(SHFILES) $(SEC) install: all $(KRB5SBIN) $(KRB5SBINSHFILES) $(KRB5LIBSHFILES) $(KRB5LIBPROG) kdyndns: $(KD_OBJS) $(LINK.c) $(KD_OBJS) -o $@ $(KD_LDLIBS) $(POST_PROCESS) ksmb: $(KSMB_OBJS) $(LINK.c) $(KSMB_OBJS) -o $@ $(KSMB_LDLIBS) $(POST_PROCESS) ksetpw: $(KS_OBJS) $(LINK.c) $(KS_OBJS) -o $@ $(KS_LDLIBS) $(POST_PROCESS) kconf: $(KC_OBJS) $(LINK.c) $(KC_OBJS) -o $@ $(KC_LDLIBS) $(POST_PROCESS) $(KRB5SBIN): $(INS.dir) $(USRLIBSEC)/%: % $(INS.file) clean: $(RM) $(OBJS) include ../../../Makefile.targ #!/bin/ksh93 -p # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2014 Nexenta Systems, Inc. All rights reserved. # Copyright 2016 Toomas Soome # # This script is used to setup the Kerberos client by # supplying information about the Kerberos realm and kdc. # # The kerberos configuration file (/etc/krb5/krb5.conf) would # be generated and local host's keytab file setup. The script # can also optionally setup the system to do kerberized nfs and # bringover a master krb5.conf copy from a specified location. # function cleanup { kdestroy -q > $TMP_FILE 2>&1 rm -r $TMPDIR > /dev/null 2>&1 exit $1 } function exiting { printf "\n$(gettext "Exiting setup, nothing changed").\n\n" cleanup $1 } function error_message { printf -- "---------------------------------------------------\n" >&2 printf "$(gettext "Setup FAILED").\n\n" >&2 cleanup 1 } function check_bin { typeset bin=$1 if [[ ! -x $bin ]]; then printf "$(gettext "Could not access/execute %s").\n" $bin >&2 error_message fi } function cannot_create { typeset filename="$1" typeset stat="$2" if [[ $stat -ne 0 ]]; then printf "\n$(gettext "Can not create/edit %s, exiting").\n" $filename >&2 error_message fi } function update_pam_conf { typeset PAM TPAM service PAM=/etc/pam.conf TPAM=$(mktemp -q -t kclient-pamconf.XXXXXX) if [[ -z $TPAM ]]; then printf "\n$(gettext "Can not create temporary file, exiting").\n" >&2 error_message fi cp $PAM $TPAM >/dev/null 2>&1 printf "$(gettext "Configuring %s").\n\n" $PAM for service in $SVCs; do svc=${service%:*} auth_type=${service#*:} if egrep -s "^$svc[ ][ ]*auth.*pam_krb5*" $TPAM; then printf "$(gettext "The %s service is already configured for pam_krb5, please merge this service in %s").\n\n" $svc $PAM >&2 continue else exec 3>>$TPAM printf "\n$svc\tauth include\t\tpam_krb5_$auth_type\n" 1>&3 fi done cp $TPAM $PAM > /dev/null 2>&1 rm $TPAM > /dev/null 2>&1 } function modify_nfssec_conf { typeset NFSSEC_FILE="/etc/nfssec.conf" if [[ -r $NFSSEC_FILE ]]; then cat $NFSSEC_FILE > $NFSSEC_FILE.sav cannot_create $NFSSEC_FILE.sav $? fi cat $NFSSEC_FILE > $TMP_FILE cannot_create $TMP_FILE $? if grep -s "#krb5" $NFSSEC_FILE > /dev/null 2>&1; then sed "s%^#krb5%krb5%" $TMP_FILE >$NFSSEC_FILE cannot_create $NFSSEC_FILE $? fi } function call_kadmin { typeset svc="$1" typeset bool1 bool2 bool3 bool4 typeset service_princ getprincsubcommand anksubcommand ktaddsubcommand typeset ktremsubcommand for listentry in $fqdnlist; do # Reset conditional vars to 1 bool1=1; bool2=1; bool3=1; bool4=1 service_princ=$(echo "${svc}/${listentry}") getprincsubcommand="getprinc $service_princ" anksubcommand="addprinc -randkey $service_princ" ktaddsubcommand="ktadd $service_princ" ktremsubcommand="ktrem $service_princ all" kadmin -c $KRB5CCNAME -q "$getprincsubcommand" 1>$TMP_FILE 2>&1 egrep -s "$(gettext "get_principal: Principal does not exist")" $TMP_FILE bool1=$? egrep -s "$(gettext "get_principal: Operation requires ``get")" $TMP_FILE bool2=$? if [[ $bool1 -eq 0 || $bool2 -eq 0 ]]; then kadmin -c $KRB5CCNAME -q "$anksubcommand" 1>$TMP_FILE 2>&1 egrep -s "$(gettext "add_principal: Principal or policy already exists while creating \"$service_princ@$realm\".")" $TMP_FILE bool3=$? egrep -s "$(gettext "Principal \"$service_princ@$realm\" created.")" $TMP_FILE bool4=$? if [[ $bool3 -eq 0 || $bool4 -eq 0 ]]; then printf "$(gettext "%s entry ADDED to KDC database").\n" $service_princ else cat $TMP_FILE; printf "\n$(gettext "kadmin: add_principal of %s failed, exiting").\n" $service_princ >&2 error_message fi else printf "$(gettext "%s entry already exists in KDC database").\n" $service_princ >&2 fi klist -k 1>$TMP_FILE 2>&1 egrep -s "$service_princ@$realm" $TMP_FILE if [[ $? -eq 0 ]]; then printf "$(gettext "%s entry already present in keytab").\n" $service_princ >&2 # Don't care is this succeeds or not, just need to replace old # entries as it is assummed that the client is reinitialized kadmin -c $KRB5CCNAME -q "$ktremsubcommand" 1>$TMP_FILE 2>&1 fi kadmin -c $KRB5CCNAME -q "$ktaddsubcommand" 1>$TMP_FILE 2>&1 egrep -s "$(gettext "added to keytab WRFILE:$KRB5_KEYTAB_FILE.")" $TMP_FILE if [[ $? -ne 0 ]]; then cat $TMP_FILE; printf "\n$(gettext "kadmin: ktadd of %s failed, exiting").\n" $service_princ >&2 error_message else printf "$(gettext "%s entry ADDED to keytab").\n" $service_princ fi done } function writeup_krb5_conf { typeset dh printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE exec 3>$KRB5_CONFIG if [[ $? -ne 0 ]]; then printf "\n$(gettext "Can not write to %s, exiting").\n" $KRB5_CONFIG >&2 error_message fi printf "[libdefaults]\n" 1>&3 if [[ $no_keytab == yes ]]; then printf "\tverify_ap_req_nofail = false\n" 1>&3 fi if [[ $dns_lookup == yes ]]; then printf "\t$dnsarg = on\n" 1>&3 if [[ $dnsarg == dns_lookup_kdc ]]; then printf "\tdefault_realm = $realm\n" 1>&3 printf "\n[domain_realm]\n" 1>&3 if [[ -n $fkdc_list ]]; then for kdc in $fkdc_list; do printf "\t$kdc = $realm\n" 1>&3 done fi printf "\t$FKDC = $realm\n" 1>&3 printf "\t$client_machine = $realm\n" 1>&3 if [[ -z $short_fqdn ]]; then printf "\t.$domain = $realm\n\n" 1>&3 else printf "\t.$short_fqdn = $realm\n\n" 1>&3 fi if [[ -n $domain_list ]]; then for dh in $domain_list; do printf "\t$dh = $realm\n" 1>&3 done fi else if [[ $dnsarg = dns_lookup_realm ]]; then printf "\tdefault_realm = $realm\n" 1>&3 printf "\n[realms]\n" 1>&3 printf "\t$realm = {\n" 1>&3 if [[ -n $kdc_list ]]; then for kdc in $kdc_list; do printf "\t\tkdc = $kdc\n" 1>&3 done else printf "\t\tkdc = $KDC\n" 1>&3 fi printf "\t\tadmin_server = $KDC\n" 1>&3 if [[ $non_solaris == yes ]]; then printf "\n\t\tkpasswd_protocol = SET_CHANGE\n" 1>&3 fi printf "\t}\n\n" 1>&3 else printf "\tdefault_realm = $realm\n\n" 1>&3 fi fi else printf "\tdefault_realm = $realm\n\n" 1>&3 printf "[realms]\n" 1>&3 printf "\t$realm = {\n" 1>&3 if [[ -n $kdc_list ]]; then for kdc in $kdc_list; do printf "\t\tkdc = $kdc\n" 1>&3 done else printf "\t\tkdc = $KDC\n" 1>&3 fi printf "\t\tadmin_server = $KDC\n" 1>&3 if [[ $non_solaris == yes ]]; then printf "\n\t\tkpasswd_protocol = SET_CHANGE\n" 1>&3 fi printf "\t}\n\n" 1>&3 printf "[domain_realm]\n" 1>&3 if [[ -n $fkdc_list ]]; then for kdc in $fkdc_list; do printf "\t$kdc = $realm\n" 1>&3 done fi printf "\t$FKDC = $realm\n" 1>&3 printf "\t$client_machine = $realm\n" 1>&3 if [[ -z $short_fqdn ]]; then printf "\t.$domain = $realm\n\n" 1>&3 else printf "\t.$short_fqdn = $realm\n\n" 1>&3 fi if [[ -n $domain_list ]]; then for dh in $domain_list; do printf "\t$dh = $realm\n" 1>&3 done fi fi printf "[logging]\n" 1>&3 printf "\tdefault = FILE:/var/krb5/kdc.log\n" 1>&3 printf "\tkdc = FILE:/var/krb5/kdc.log\n" 1>&3 printf "\tkdc_rotate = {\n\t\tperiod = 1d\n\t\tversions = 10\n\t}\n\n" 1>&3 printf "[appdefaults]\n" 1>&3 printf "\tkinit = {\n\t\trenewable = true\n\t\tforwardable = true\n" 1>&3 if [[ $no_keytab == yes ]]; then printf "\t\tno_addresses = true\n" 1>&3 fi printf "\t}\n" 1>&3 } function ask { typeset question=$1 typeset default_answer=$2 if [[ -z $default_answer ]]; then printf "$question :" else printf "$question [$default_answer]: " fi read answer test -z "$answer" && answer="$default_answer" } function yesno { typeset question="$1" answer= yn=`printf "$(gettext "y/n")"` y=`printf "$(gettext "y")"` n=`printf "$(gettext "n")"` yes=`printf "$(gettext "yes")"` no=`printf "$(gettext "no")"` while [[ -z $answer ]]; do ask "$question" $yn case $answer in $y|$yes) answer=yes;; $n|$no) answer=no;; *) answer=;; esac done } function query { yesno "$*" if [[ $answer == no ]]; then printf "\t$(gettext "No action performed").\n" fi } function read_profile { typeset param value typeset file="$1" if [[ ! -d $file && -r $file ]]; then while read param value do case $param in REALM) if [[ -z $realm ]]; then realm="$value" checkval="REALM"; check_value $realm fi ;; KDC) if [[ -z $KDC ]]; then KDC="$value" checkval="KDC"; check_value $KDC fi ;; ADMIN) if [[ -z $ADMIN_PRINC ]]; then ADMIN_PRINC="$value" checkval="ADMIN_PRINC" check_value $ADMIN_PRINC fi ;; FILEPATH) if [[ -z $filepath ]]; then filepath="$value" fi ;; NFS) if [[ -z $add_nfs ]]; then if [[ $value == 1 ]]; then add_nfs=yes else add_nfs=no fi fi ;; NOKEY) if [[ -z $no_keytab ]]; then if [[ $value == 1 ]]; then no_keytab=yes else no_keytab=no fi fi ;; NOSOL) if [[ -z $non_solaris ]]; then if [[ $value == 1 ]]; then non_solaris=yes no_keytab=yes else non_solaris=no fi fi ;; LHN) if [[ -z $logical_hn ]]; then logical_hn="$value" checkval="LOGICAL_HOSTNAME" check_value $logical_hn fi ;; DNSLOOKUP) if [[ -z $dnsarg ]]; then dnsarg="$value" checkval="DNS_OPTIONS" check_value $dnsarg fi ;; FQDN) if [[ -z $fqdnlist ]]; then fqdnlist="$value" checkval="FQDN" check_value $fqdnlist verify_fqdnlist "$fqdnlist" fi ;; MSAD) if [[ -z $msad ]]; then if [[ $value == 1 ]]; then msad=yes non_solaris=yes else msad=no fi fi ;; esac done <$file else printf "\n$(gettext "The kclient profile \`%s' is not valid, exiting").\n" $file >&2 error_message fi } function ping_check { typeset machine="$1" typeset string="$2" if ping $machine 2 > /dev/null 2>&1; then : else printf "\n$(gettext "%s %s is unreachable, exiting").\n" $string $machine >&2 error_message fi # Output timesync warning if not using a profile, i.e. in # interactive mode. if [[ -z $profile && $string == KDC ]]; then # It's difficult to sync up time with KDC esp. if in a # zone so just print a warning about KDC time sync. printf "\n$(gettext "Note, this system and the KDC's time must be within 5 minutes of each other for Kerberos to function").\n" >&2 printf "$(gettext "Both systems should run some form of time synchronization system like Network Time Protocol (NTP)").\n" >&2 break fi } function check_value { typeset arg="$1" if [[ -z $arg ]]; then printf "\n$(gettext "No input obtained for %s, exiting").\n" $checkval >&2 error_message else echo "$arg" > $TMP_FILE if egrep -s '[*$^#!]+' $TMP_FILE; then printf "\n$(gettext "Invalid input obtained for %s, exiting").\n" $checkval >&2 error_message fi fi } function set_dns_value { typeset -l arg="$1" if [[ $arg == dns_lookup_kdc || $arg == dns_lookup_realm || $arg == dns_fallback ]]; then dns_lookup=yes else if [[ $arg == none ]]; then dns_lookup=no else printf "\n$(gettext "Invalid DNS lookup option, exiting").\n" >&2 error_message fi fi } function verify_kdcs { typeset k_list="$1" typeset -l kdc typeset list fqhn f_list kdc_list=$(echo "$k_list" | sed 's/,/ /g') if [[ -z $k_list ]]; then printf "\n$(gettext "At least one KDC should be listed").\n\n" >&2 usage fi for kdc in $k_list; do if [[ $kdc != $KDC ]]; then list="$list $kdc" fkdc=`$KLOOKUP $kdc` if ping $fkdc 2 > /dev/null; then : else printf "\n$(gettext "%s %s is unreachable, no action performed").\n" "KDC" $fkdc >&2 fi f_list="$f_list $fkdc" fi done fkdc_list="$f_list" kdc_list="$list" } function parse_service { typeset service_list=$1 service_list=${service_list//,/ } for service in $service_list; do svc=${service%:} auth_type=${service#:} [[ -z $svc || -z $auth_type ]] && return print -- $svc $auth_type done } function verify_fqdnlist { typeset list="$1" typeset -l hostname typeset -i count=1 typeset fqdnlist eachfqdn tmpvar fullhost list=$(echo "$list" | tr -d " " | tr -d "\t") hostname=$(uname -n | cut -d"." -f1) fqdnlist=$client_machine eachfqdn=$(echo "$list" | cut -d"," -f$count) if [[ -z $eachfqdn ]]; then printf "\n$(gettext "If the -f option is used, at least one FQDN should be listed").\n\n" >&2 usage else while [[ ! -z $eachfqdn ]]; do tmpvar=$(echo "$eachfqdn" | cut -d"." -f1) if [[ -z $tmpvar ]]; then fullhost="$hostname$eachfqdn" else fullhost="$hostname.$eachfqdn" fi ping_check $fullhost $(gettext "System") if [[ $fullhost == $client_machine ]]; then : else fqdnlist="$fqdnlist $fullhost" fi if [[ $list == *,* ]]; then ((count = count + 1)) eachfqdn=$(echo "$list" | cut -d"," -f$count) else break fi done fi } function setup_keytab { typeset cname ask_fqdns current_release # # 1. kinit with ADMIN_PRINC # if [[ -z $ADMIN_PRINC ]]; then printf "\n$(gettext "Enter the krb5 administrative principal to be used"): " read ADMIN_PRINC checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC fi echo "$ADMIN_PRINC">$TMP_FILE [[ -n $msad ]] && return if egrep -s '\/admin' $TMP_FILE; then # Already in "/admin" format, do nothing : else if egrep -s '\/' $TMP_FILE; then printf "\n$(gettext "Improper entry for krb5 admin principal, exiting").\n" >&2 error_message else ADMIN_PRINC=$(echo "$ADMIN_PRINC/admin") fi fi printf "$(gettext "Obtaining TGT for %s") ...\n" $ADMIN_PRINC cname=$(canon_resolve $KDC) if [[ -n $cname ]]; then kinit -S kadmin/$cname $ADMIN_PRINC else kinit -S kadmin/$FKDC $ADMIN_PRINC fi klist 1>$TMP_FILE 2>&1 if egrep -s "$(gettext "Valid starting")" $TMP_FILE && egrep -s "kadmin/$FKDC@$realm" $TMP_FILE; then : else printf "\n$(gettext "kinit of %s failed, exiting").\n" $ADMIN_PRINC >&2 error_message fi # # 2. Do we want to create and/or add service principal(s) for fqdn's # other than the one listed in resolv.conf(5) ? # if [[ -z $options ]]; then query "$(gettext "Do you have multiple DNS domains spanning the Kerberos realm") $realm ?" ask_fqdns=$answer if [[ $ask_fqdns == yes ]]; then printf "$(gettext "Enter a comma-separated list of DNS domain names"): " read fqdnlist verify_fqdnlist "$fqdnlist" else fqdnlist=$client_machine fi else if [[ -z $fqdnlist ]]; then fqdnlist=$client_machine fi fi if [[ $add_nfs == yes ]]; then echo; call_kadmin nfs fi # Add the host entry to the keytab echo; call_kadmin host } function setup_lhn { typeset -l logical_hn echo "$logical_hn" > $TMP_FILE if egrep -s '[^.]\.[^.]+$' $TMP_FILE; then # do nothing, logical_hn is in fqdn format : else if egrep -s '\.+' $TMP_FILE; then printf "\n$(gettext "Improper format of logical hostname, exiting").\n" >&2 error_message else # Attach fqdn to logical_hn, to get the Fully Qualified # Host Name of the client requested logical_hn=$(echo "$logical_hn.$fqdn") fi fi client_machine=$logical_hn ping_check $client_machine $(gettext "System") } function usage { printf "\n$(gettext "Usage: kclient [ options ]")\n" >&2 printf "\t$(gettext "where options are any of the following")\n\n" >&2 printf "\t$(gettext "[ -D domain_list ] configure a client that has mul tiple mappings of doamin and/or hosts to the default realm")\n" >&2 printf "\t$(gettext "[ -K ] configure a client that does not have host/service keys")\n" >&2 printf "\t$(gettext "[ -R realm ] specifies the realm to use")\n" >&2 printf "\t$(gettext "[ -T kdc_vendor ] specifies which KDC vendor is the server")\n" >&2 printf "\t$(gettext "[ -a adminuser ] specifies the Kerberos administrator")\n" >&2 printf "\t$(gettext "[ -c filepath ] specifies the krb5.conf path used to configure this client")\n" >&2 printf "\t$(gettext "[ -d dnsarg ] specifies which information should be looked up in DNS (dns_lookup_kdc, dns_lookup_realm, and dns_fallback)")\n" >&2 printf "\t$(gettext "[ -f fqdn_list ] specifies which domains to configure host keys for this client")\n" >&2 printf "\t$(gettext "[ -h logicalhostname ] configure the logical host name for a client that is in a cluster")\n" >&2 printf "\t$(gettext "[ -k kdc_list ] specify multiple KDCs, if -m is not used the first KDC in the list is assumed to be the master. KDC host names are used verbatim.")\n" >&2 printf "\t$(gettext "[ -m master ] master KDC server host name")\n" >&2 printf "\t$(gettext "[ -n ] configure client to be an NFS client")\n" >&2 printf "\t$(gettext "[ -p profile ] specifies which profile file to use to configure this client")\n" >&2 printf "\t$(gettext "[ -s pam_list ] update the service for Kerberos authentication")\n" >&2 error_message } function discover_domain { typeset dom DOMs if [[ -z $realm ]]; then set -A DOMs -- `$KLOOKUP _ldap._tcp.dc._msdcs S` else set -A DOMs -- `$KLOOKUP _ldap._tcp.dc._msdcs.$realm S` fi [[ -z ${DOMs[0]} ]] && return 1 dom=${DOMs[0]} dom=${dom#*.} dom=${dom% *} domain=$dom return 0 } function check_nss_hosts_or_ipnodes_config { typeset backend for backend in $1 do [[ $backend == dns ]] && return 0 done return 1 } function check_nss_conf { typeset i j hosts_config for i in hosts ipnodes do grep "^${i}:" /etc/nsswitch.conf|read j hosts_config check_nss_hosts_or_ipnodes_config "$hosts_config" || return 1 done return 0 } function canon_resolve { typeset name ip name=`$KLOOKUP $1 C` [[ -z $name ]] && name=`$KLOOKUP $1 A` [[ -z $name ]] && return ip=`$KLOOKUP $name I` [[ -z $ip ]] && return for i in $ip do if ping $i 2 > /dev/null 2>&1; then break else i= fi done cname=`$KLOOKUP $ip P` [[ -z $cname ]] && return print -- "$cname" } function rev_resolve { typeset name ip ip=`$KLOOKUP $1 I` [[ -z $ip ]] && return name=`$KLOOKUP $ip P` [[ -z $name ]] && return print -- $name } # Convert an AD-style domain DN to a DNS domainname function dn2dns { typeset OIFS dname dn comp components dn=$1 dname= OIFS="$IFS" IFS=, set -A components -- $1 IFS="$OIFS" for comp in "${components[@]}" do [[ "$comp" == [dD][cC]=* ]] || continue dname="$dname.${comp#??=}" done print ${dname#.} } # Form a base DN from a DNS domainname and container function getBaseDN { if [[ -n "$2" ]] then baseDN="CN=$1,$(dns2dn $2)" else baseDN="$(dns2dn $2)" fi } # Convert a DNS domainname to an AD-style DN for that domain function dns2dn { typeset OIFS dn labels OIFS="$IFS" IFS=. set -A labels -- $1 IFS="$OIFS" dn= for label in "${labels[@]}" do dn="${dn},DC=$label" done print -- "${dn#,}" } function getSRVs { typeset srv port $KLOOKUP $1 S | while read srv port do if ping $srv 2 > /dev/null 2>&1; then print -- $srv $port fi done } function getKDC { typeset j set -A KPWs -- $(getSRVs _kpasswd._tcp.$dom.) kpasswd=${KPWs[0]} if [[ -n $siteName ]] then set -A KDCs -- $(getSRVs _kerberos._tcp.$siteName._sites.$dom.) kdc=${KDCs[0]} [[ -n $kdc ]] && return fi # No site name set -A KDCs -- $(getSRVs _kerberos._tcp.$dom.) kdc=${KDCs[0]} [[ -n $kdc ]] && return # Default set -A KDCs -- $DomainDnsZones 88 kdc=$ForestDnsZones } function getDC { typeset j if [[ -n $siteName ]] then set -A DCs -- $(getSRVs _ldap._tcp.$siteName._sites.dc._msdcs.$dom.) dc=${DCs[0]} [[ -n $dc ]] && return fi # No site name set -A DCs -- $(getSRVs _ldap._tcp.dc._msdcs.$dom.) dc=${DCs[0]} [[ -n $dc ]] && return # Default set -A DCs -- $DomainDnsZones 389 dc=$DomainDnsZones } function write_ads_krb5conf { typeset kdcs printf "\n$(gettext "Setting up %s").\n\n" $KRB5_CONFIG_FILE for i in ${KDCs[@]} do [[ $i == +([0-9]) ]] && continue if [[ -n $kdcs ]] then kdcs="$kdcs,$i" else kdcs=$i fi done $KCONF -f $KRB5_CONFIG -r $realm -k $kdcs -m $KDC -p SET_CHANGE -d .$dom if [[ $? -ne 0 ]]; then printf "\n$(gettext "Can not update %s, exiting").\n" $KRB5_CONFIG >&2 error_message fi } function getForestName { ldapsearch -R -T -h $dc $ldap_args \ -b "" -s base "" schemaNamingContext| \ grep ^schemaNamingContext|read j schemaNamingContext if [[ $? -ne 0 ]]; then printf "$(gettext "Can't find forest").\n" >&2 error_message fi schemaNamingContext=${schemaNamingContext#CN=Schema,CN=Configuration,} [[ -z $schemaNamingContext ]] && return 1 forest= while [[ -n $schemaNamingContext ]] do schemaNamingContext=${schemaNamingContext#DC=} forest=${forest}.${schemaNamingContext%%,*} [[ "$schemaNamingContext" = *,* ]] || break schemaNamingContext=${schemaNamingContext#*,} done forest=${forest#.} } function getGC { typeset j [[ -n $gc ]] && return 0 if [[ -n $siteName ]] then set -A GCs -- $(getSRVs _ldap._tcp.$siteName._sites.gc._msdcs.$forest.) gc=${GCs[0]} [[ -n $gc ]] && return fi # No site name set -A GCs -- $(getSRVs _ldap._tcp.gc._msdcs.$forest.) gc=${GCs[0]} [[ -n $gc ]] && return # Default set -A GCs -- $ForestDnsZones 3268 gc=$ForestDnsZones } # # The local variables used to calculate the IP address are of type unsigned # integer (-ui), as this is required to restrict the integer to 32b. # Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b. # function ipAddr2num { typeset OIFS typeset -ui16 num if [[ "$1" != +([0-9]).+([0-9]).+([0-9]).+([0-9]) ]] then print 0 return 0 fi OIFS="$IFS" IFS=. set -- $1 IFS="$OIFS" num=$((${1}<<24 | ${2}<<16 | ${3}<<8 | ${4})) print -- $num } # # The local variables used to calculate the IP address are of type unsigned # integer (-ui), as this is required to restrict the integer to 32b. # Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b. # function num2ipAddr { typeset -ui16 num typeset -ui10 a b c d num=$1 a=$((num>>24 )) b=$((num>>16 & 16#ff)) c=$((num>>8 & 16#ff)) d=$((num & 16#ff)) print -- $a.$b.$c.$d } # # The local variables used to calculate the IP address are of type unsigned # integer (-ui), as this is required to restrict the integer to 32b. # Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b. # function netmask2length { typeset -ui16 netmask typeset -i len netmask=$1 len=32 while [[ $((netmask % 2)) -eq 0 ]] do netmask=$((netmask>>1)) len=$((len - 1)) done print $len } # # The local variables used to calculate the IP address are of type unsigned # integer (-ui), as this is required to restrict the integer to 32b. # Starting in ksh88, Solaris has incorrectly assummed that -i represents 64b. # function getSubnets { typeset -ui16 addr netmask typeset -ui16 classa=16\#ff000000 typeset -ui16 classb=16\#ffff0000 typeset -ui16 classc=16\#ffffff00 ifconfig -a|while read line do addr=0 netmask=0 set -- $line [[ $1 == inet ]] || continue while [[ $# -gt 0 ]] do case "$1" in inet) addr=$(ipAddr2num $2); shift;; netmask) eval netmask=16\#$2; shift;; *) :; esac shift done [[ $addr -eq 0 || $netmask -eq 0 ]] && continue [[ $((addr & classa)) -eq 16\#7f000000 ]] && continue print $(num2ipAddr $((addr & netmask)))/$(netmask2length $netmask) if [ $netmask -gt $classc ] then print $(num2ipAddr $((addr & classc)))/$(netmask2length $classc) fi if [ $netmask -gt $classb ] then print $(num2ipAddr $((addr & classb)))/$(netmask2length $classb) fi if [ $netmask -gt $classa ] then print $(num2ipAddr $((addr & classa)))/$(netmask2length $classa) fi done } function getSite { typeset subnet siteDN j ldapsrv subnet_dom eval "[[ -n \"\$siteName\" ]]" && return for subnet in $(getSubnets) do ldapsearch -R -T -h $dc $ldap_args \ -p 3268 -b "" -s sub cn=$subnet dn |grep ^dn|read j subnetDN [[ -z $subnetDN ]] && continue subnet_dom=$(dn2dns $subnetDN) ldapsrv=$(canon_resolve DomainDnsZones.$subnet_dom) [[ -z $ldapsrv ]] && continue ldapsearch -R -T -h $ldapsrv $ldap_args \ -b "$subnetDN" -s base "" siteObject \ |grep ^siteObject|read j siteDN [[ -z $siteDN ]] && continue eval siteName=${siteDN%%,*} eval siteName=\${siteName#CN=} return done } function doKRB5config { [[ -f $KRB5_CONFIG_FILE ]] && \ cp $KRB5_CONFIG_FILE ${KRB5_CONFIG_FILE}-pre-kclient [[ -f $KRB5_KEYTAB_FILE ]] && \ cp $KRB5_KEYTAB_FILE ${KRB5_KEYTAB_FILE}-pre-kclient [[ -s $KRB5_CONFIG ]] && cp $KRB5_CONFIG $KRB5_CONFIG_FILE [[ -s $KRB5_CONFIG_FILE ]] && chmod 0644 $KRB5_CONFIG_FILE [[ -s $new_keytab ]] && cp $new_keytab $KRB5_KEYTAB_FILE [[ -s $KRB5_KEYTAB_FILE ]] && chmod 0600 $KRB5_KEYTAB_FILE } function addDNSRR { smbFMRI=svc:/network/smb/server:default ddnsProp=smbd/ddns_enable enProp=general/enabled enabled=`svcprop -p $enProp $smbFMRI` ddns_enable=`svcprop -p $ddnsProp $smbFMRI` if [[ $enabled == true && $ddns_enable != true ]]; then printf "$(gettext "Warning: won't create DNS records for client").\n" printf "$(gettext "%s property not set to 'true' for the %s FMRI").\n" $ddnsProp $smbFMRI return fi # Destroy any existing ccache as GSS_C_NO_CREDENTIAL will pick up any # residual default credential in the cache. kdestroy > /dev/null 2>&1 $KDYNDNS -d $1 > /dev/null 2>&1 if [[ $? -ne 0 ]]; then # # Non-fatal, we should carry-on as clients may resolve to # different servers and the client could already exist there. # printf "$(gettext "Warning: unable to create DNS records for client").\n" printf "$(gettext "This could mean that '%s' is not included as a 'nameserver' in the /etc/resolv.conf file or some other type of error").\n" $dc fi } function setSMB { typeset domain=$1 typeset server=$2 smbFMRI=svc:/network/smb/server printf "%s" "$newpw" | $KSMB -d $domain -s $server if [[ $? -ne 0 ]]; then printf "$(gettext "Warning: unable to set %s domain, server and password information").\n" $smbFMRI return fi svcadm restart $smbFMRI > /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Warning: unable to restart %s").\n" $smbFMRI fi } function compareDomains { typeset oldDom hspn newDom=$1 # If the client has been previously configured in a different # realm/domain then we need to prompt the user to see if they wish to # switch domains. klist -k 2>&1 | grep @ | read j hspn [[ -z $hspn ]] && return oldDom=${hspn#*@} if [[ $oldDom != $newDom ]]; then printf "$(gettext "The client is currently configured in a different domain").\n" printf "$(gettext "Currently in the '%s' domain, trying to join the '%s' domain").\n" $oldDom $newDom query "$(gettext "Do you want the client to join a new domain") ?" printf "\n" if [[ $answer != yes ]]; then printf "$(gettext "Client will not be joined to the new domain").\n" >&2 error_message fi fi } function getKDCDC { getKDC if [[ -n $kdc ]]; then KDC=$kdc dc=$kdc else getDC if [[ -n $dc ]]; then KDC=$dc else printf "$(gettext "Could not find domain controller server for '%s'. Exiting").\n" $realm >&2 error_message fi fi } function gen_rand { typeset -u hex dd if=/dev/random bs=1 count=1 2>/dev/null | od -A n -tx1 | read hex printf %s $((16#$hex)) } function join_domain { typeset -u upcase_nodename typeset -l locase_nodename typeset -L15 string15 typeset netbios_nodename fqdn container=Computers ldap_args="-o authzid= -o mech=gssapi" userAccountControlBASE=4096 if [[ -z $ADMIN_PRINC ]]; then cprinc=Administrator else cprinc=$ADMIN_PRINC fi if ! discover_domain; then printf "$(gettext "Can not find realm") '%s'.\n" $realm >&2 error_message fi dom=$domain realm=$domain if [[ ${#hostname} -gt 15 ]]; then string15=$hostname upcase_nodename=$string15 locase_nodename=$string15 else upcase_nodename=$hostname locase_nodename=$hostname fi netbios_nodename="${upcase_nodename}\$" fqdn=$hostname.$domain upn=host/${fqdn}@${realm} object=$(mktemp -q -t kclient-computer-object.XXXXXX) if [[ -z $object ]]; then printf "\n$(gettext "Can not create temporary file, exiting").\n " >&2 error_message fi modify_existing=false recreate=false DomainDnsZones=$(rev_resolve DomainDnsZones.$dom.) ForestDnsZones=$(rev_resolve ForestDnsZones.$dom.) getBaseDN "$container" "$dom" if [[ -n $KDC ]]; then dc=$KDC else getKDCDC fi write_ads_krb5conf printf "$(gettext "Attempting to join '%s' to the '%s' domain").\n\n" $upcase_nodename $realm kinit $cprinc@$realm if [[ $? -ne 0 ]]; then printf "$(gettext "Could not authenticate %s. Exiting").\n" $cprinc@$realm >&2 error_message fi if getForestName then printf "\n$(gettext "Forest name found: %s")\n\n" $forest else printf "\n$(gettext "Forest name not found, assuming forest is the domain name").\n" fi getGC getSite if [[ -z $siteName ]] then printf "$(gettext "Site name not found. Local DCs/GCs will not be discovered").\n\n" else printf "$(gettext "Looking for _local_ KDCs, DCs and global catalog servers (SRV RRs)").\n" getKDCDC getGC write_ads_krb5conf fi if [[ ${#GCs} -eq 0 ]]; then printf "$(gettext "Could not find global catalogs. Exiting").\n" >&2 error_message fi # Check to see if the client is transitioning between domains. compareDomains $realm # Here we check domainFunctionality to see which release: # 0, 1, 2: Windows 2000, 2003 Interim, 2003 respecitively # 3: Windows 2008 level=0 ldapsearch -R -T -h "$dc" $ldap_args -b "" -s base "" \ domainControllerFunctionality| grep ^domainControllerFunctionality| \ read j level if [[ $? -ne 0 ]]; then printf "$(gettext "Search for domain functionality failed, exiting").\n" >&2 error_message fi if ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \ -s sub sAMAccountName="$netbios_nodename" dn > /dev/null 2>&1 then : else printf "$(gettext "Search for node failed, exiting").\n" >&2 error_message fi ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" -s sub \ sAMAccountName="$netbios_nodename" dn|grep "^dn:"|read j dn if [[ -z $dn ]]; then : # modify_existing is already false, which is what we want. else printf "$(gettext "Computer account '%s' already exists in the '%s' domain").\n" $upcase_nodename $realm query "$(gettext "Do you wish to recreate this computer account") ?" printf "\n" if [[ $answer == yes ]]; then recreate=true else modify_existing=true fi fi if [[ $modify_existing == false && -n $dn ]]; then query "$(gettext "Would you like to delete any sub-object found for this computer account") ?" if [[ $answer == yes ]]; then printf "$(gettext "Looking to see if the machine account contains other objects")...\n" ldapsearch -R -T -h "$dc" $ldap_args -b "$dn" -s sub "" dn | while read j sub_dn do [[ $j != dn: || -z $sub_dn || $dn == $sub_dn ]] && continue if $recreate; then printf "$(gettext "Deleting the following object: %s")\n" ${sub_dn#$dn} ldapdelete -h "$dc" $ldap_args "$sub_dn" > /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn} fi else printf "$(gettext "The following object will not be deleted"): %s\n" ${sub_dn#$dn} fi done fi if $recreate; then ldapdelete -h "$dc" $ldap_args "$dn" > /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Error in deleting object: %s").\n" ${sub_dn#$dn} >&2 error_message fi elif $modify_existing; then : # Nothing to delete else printf "$(gettext "A machine account already exists").\n" >&2 error_message fi fi [[ -z $dn ]] && dn="CN=${upcase_nodename},${baseDN}" if $modify_existing; then cat > "$object" < /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Failed to modify the AD object via LDAP").\n" >&2 error_message fi else dn="CN=${upcase_nodename},${baseDN}" cat > "$object" < /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Failed to create the AD object via LDAP").\n" >&2 error_message fi fi # Generate a new password for the new account MAX_PASS=120 i=0 # first check to see if /dev/random exists to generate a new password if [[ ! -e /dev/random ]]; then printf "$(gettext "/dev/random does not exist").\n" >&2 error_message fi while ((MAX_PASS > i)) do # [MS-DISO] A machine password is an ASCII string of randomly # chosen characters. Each character's ASCII code is between 32 # and 122 inclusive. c=$(printf "\\$(printf %o $(($(gen_rand) % 91 + 32)))\n") p="$p$c" ((i+=1)) done newpw=$p if [[ ${#newpw} -ne MAX_PASS ]]; then printf "$(gettext "Password created was of incorrect length").\n" >&2 error_message fi # Set the new password printf "%s" "$newpw" | $KSETPW ${netbios_nodename}@${realm} > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set account password").\n" >&2 error_message fi # Lookup the new principal's kvno: ldapsearch -R -T -h "$dc" $ldap_args -b "$baseDN" \ -s sub cn=$upcase_nodename msDS-KeyVersionNumber| \ grep "^msDS-KeyVersionNumber"|read j kvno [[ -z $kvno ]] && kvno=1 # Set supported enctypes. This only works for Longhorn/Vista, so we # ignore errors here. userAccountControl=$((userAccountControlBASE + 524288 + 65536)) set -A enctypes -- # Do we have local support for AES? encrypt -l|grep ^aes|read j minkeysize maxkeysize val= if [[ $maxkeysize -eq 256 ]]; then val=16 enctypes[${#enctypes[@]}]=aes256-cts-hmac-sha1-96 fi if [[ $minkeysize -eq 128 ]]; then ((val=val+8)) enctypes[${#enctypes[@]}]=aes128-cts-hmac-sha1-96 fi # RC4 comes next (whether it's better than 1DES or not -- AD prefers it) if encrypt -l|grep -q ^arcfour then ((val=val+4)) enctypes[${#enctypes[@]}]=arcfour-hmac-md5 else # Use 1DES ONLY if we don't have arcfour userAccountControl=$((userAccountControl + 2097152)) fi if encrypt -l | grep -q ^des then ((val=val+2)) enctypes[${#enctypes[@]}]=des-cbc-md5 fi if [[ ${#enctypes[@]} -eq 0 ]] then printf "$(gettext "No enctypes are supported").\n" printf "$(gettext "Please enable arcfour or 1DES, then re-join; see cryptoadm(8)").\n" >&2 error_message fi # If domain crontroller is Longhorn or above then set new supported # encryption type attributes. if [[ $level -gt 2 ]]; then cat > "$object" </dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "Warning: Could not set the supported encryption type for computer account").\n" fi fi # We should probably check whether arcfour is available, and if not, # then set the 1DES only flag, but whatever, it's not likely NOT to be # available on S10/Nevada! # Reset userAccountControl # # NORMAL_ACCOUNT (512) | DONT_EXPIRE_PASSWORD (65536) | # TRUSTED_FOR_DELEGATION (524288) # # and possibly UseDesOnly (2097152) (see above) # cat > "$object" </dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "ldapmodify failed to modify account attribute").\n" >&2 error_message fi # Setup a keytab file set -A args -- for enctype in "${enctypes[@]}" do args[${#args[@]}]=-e args[${#args[@]}]=$enctype done rm $new_keytab > /dev/null 2>&1 cat > "$object" </dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "$(gettext "ldapmodify failed to modify account attribute").\n" >&2 error_message fi # # In Windows, unlike MIT based implementations we salt the keys with # the UPN, which is based on the host/string15@realm elements, not # with the individual SPN strings. # salt=host/${locase_nodename}.${domain}@${realm} skeys=(host/${fqdn}@${realm} nfs/${fqdn}@${realm} HTTP/${fqdn}@${realm}) skeys+=(root/${fqdn}@${realm} cifs/${fqdn}@${realm}) skeys+=(${netbios_nodename}@${realm} host/${upcase_nodename}@${realm}) skeys+=(cifs/${upcase_nodename}@${realm}) ks_args="-n -s $salt -v $kvno -k $new_keytab ${args[@]}" for skey in ${skeys[@]} do printf "%s" "$newpw" | $KSETPW $ks_args $skey > /dev/null 2>&1 if [[ $? -ne 0 ]] then printf "$(gettext "Failed to set password").\n" >&2 error_message fi done doKRB5config addDNSRR $dom setSMB $dom $dc printf -- "---------------------------------------------------\n" printf "$(gettext "Setup COMPLETE").\n\n" kdestroy -q 1>$TMP_FILE 2>&1 rm -f $TMP_FILE rm -rf $TMPDIR > /dev/null 2>&1 exit 0 } ########################### # Main section # ########################### # # Set the Kerberos config file and some default strings/files # KRB5_CONFIG_FILE=/etc/krb5/krb5.conf KRB5_KEYTAB_FILE=/etc/krb5/krb5.keytab RESOLV_CONF_FILE=/etc/resolv.conf KLOOKUP=/usr/lib/krb5/klookup; check_bin $KLOOKUP KSETPW=/usr/lib/krb5/ksetpw; check_bin $KSETPW KSMB=/usr/lib/krb5/ksmb; check_bin $KSMB KDYNDNS=/usr/lib/krb5/kdyndns; check_bin $KDYNDNS KCONF=/usr/lib/krb5/kconf; check_bin $KCONF dns_lookup=no ask_fqdns=no adddns=no no_keytab=no checkval="" profile="" typeset -u realm typeset -l hostname KDC export TMPDIR="/var/run/kclient" mkdir $TMPDIR > /dev/null 2>&1 if [[ $? -ne 0 ]]; then printf "\n$(gettext "Can not create directory: %s")\n\n" $TMPDIR >&2 exit 1 fi TMP_FILE=$(mktemp -q -t kclient-tmpfile.XXXXXX) export KRB5_CONFIG=$(mktemp -q -t kclient-krb5conf.XXXXXX) export KRB5CCNAME=$(mktemp -q -t kclient-krb5ccache.XXXXXX) new_keytab=$(mktemp -q -t kclient-krb5keytab.XXXXXX) if [[ -z $TMP_FILE || -z $KRB5_CONFIG || -z $KRB5CCNAME || -z $new_keytab ]] then printf "\n$(gettext "Can not create temporary files, exiting").\n\n" >&2 exit 1 fi # # If we are interrupted, cleanup after ourselves # trap "exiting 1" HUP INT QUIT TERM if [[ -d /usr/bin ]]; then if [[ -d /usr/sbin ]]; then PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:$PATH export PATH else printf "\n$(gettext "Directory /usr/sbin not found, exiting").\n" >&2 exit 1 fi else printf "\n$(gettext "Directory /usr/bin not found, exiting").\n" >&2 exit 1 fi printf "\n$(gettext "Starting client setup")\n\n" printf -- "---------------------------------------------------\n" # # Check for uid 0, disallow otherwise # id 1>$TMP_FILE 2>&1 if [[ $? -eq 0 ]]; then if egrep -s "uid=0\(root\)" $TMP_FILE; then # uid is 0, go ahead ... : else printf "\n$(gettext "Administrative privileges are required to run this script, exiting").\n" >&2 error_message fi else cat $TMP_FILE; printf "\n$(gettext "uid check failed, exiting").\n" >&2 error_message fi uname=$(uname -n) hostname=${uname%%.*} # # Process the command-line arguments (if any) # OPTIND=1 while getopts nD:Kp:R:k:a:c:d:f:h:m:s:T: OPTIONS do case $OPTIONS in D) options="$options -D" domain_list="$OPTARG" ;; K) options="$options -K" no_keytab=yes ;; R) options="$options -R" realm="$OPTARG" checkval="REALM"; check_value $realm ;; T) options="$options -T" type="$OPTARG" if [[ $type == ms_ad ]]; then msad=yes adddns=yes else non_solaris=yes no_keytab=yes fi ;; a) options="$options -a" ADMIN_PRINC="$OPTARG" checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC ;; c) options="$options -c" filepath="$OPTARG" ;; d) options="$options -d" dnsarg="$OPTARG" checkval="DNS_OPTIONS"; check_value $dnsarg ;; f) options="$options -f" fqdnlist="$OPTARG" ;; h) options="$options -h" logical_hn="$OPTARG" checkval="LOGICAL_HOSTNAME"; check_value $logical_hn ;; k) options="$options -k" kdc_list="$OPTARG" ;; m) options="$options -m" KDC="$OPTARG" checkval="KDC"; check_value $KDC ;; n) options="$options -n" add_nfs=yes ;; p) options="$options -p" profile="$OPTARG" read_profile $profile ;; s) options="$options -s" svc_list="$OPTARG" SVCs=${svc_list//,/ } ;; \?) usage ;; *) usage ;; esac done #correct argument count after options shift `expr $OPTIND - 1` if [[ -z $options ]]; then : else if [[ $# -ne 0 ]]; then usage fi fi # # Check to see if we will be a client of a MIT, Heimdal, Shishi, etc. # if [[ -z $options ]]; then query "$(gettext "Is this a client of a non-Solaris KDC") ?" non_solaris=$answer if [[ $non_solaris == yes ]]; then printf "$(gettext "Which type of KDC is the server"):\n" printf "\t$(gettext "ms_ad: Microsoft Active Directory")\n" printf "\t$(gettext "mit: MIT KDC server")\n" printf "\t$(gettext "heimdal: Heimdal KDC server")\n" printf "\t$(gettext "shishi: Shishi KDC server")\n" printf "$(gettext "Enter required KDC type"): " read kdctype if [[ $kdctype == ms_ad ]]; then msad=yes elif [[ $kdctype == mit || $kdctype == heimdal || \ $kdctype == shishi ]]; then no_keytab=yes else printf "\n$(gettext "Invalid KDC type option, valid types are ms_ad, mit, heimdal, or shishi, exiting").\n" >&2 error_message fi fi fi [[ $msad == yes ]] && join_domain # # Check for /etc/resolv.conf # if [[ -r $RESOLV_CONF_FILE ]]; then client_machine=`$KLOOKUP` if [[ $? -ne 0 ]]; then if [[ $adddns == no ]]; then printf "\n$(gettext "%s does not have a DNS record and is required for Kerberos setup")\n" $hostname >&2 error_message fi else # # If client entry already exists then do not recreate it # adddns=no hostname=${client_machine%%.*} domain=${client_machine#*.} fi short_fqdn=${domain#*.*} short_fqdn=$(echo $short_fqdn | grep "\.") else # # /etc/resolv.conf not present, exit ... # printf "\n$(gettext "%s does not exist and is required for Kerberos setup")\n" $RESOLV_CONF_FILE >&2 printf "$(gettext "Refer to resolv.conf(5), exiting").\n" >&2 error_message fi check_nss_conf || printf "$(gettext "/etc/nsswitch.conf does not make use of DNS for hosts and/or ipnodes").\n" [[ -n $fqdnlist ]] && verify_fqdnlist "$fqdnlist" if [[ -z $dnsarg && (-z $options || -z $filepath) ]]; then query "$(gettext "Do you want to use DNS for kerberos lookups") ?" if [[ $answer == yes ]]; then printf "\n$(gettext "Valid DNS lookup options are dns_lookup_kdc, dns_lookup_realm,\nand dns_fallback. Refer krb5.conf(5) for further details").\n" printf "\n$(gettext "Enter required DNS option"): " read dnsarg checkval="DNS_OPTIONS"; check_value $dnsarg set_dns_value $dnsarg fi else [[ -z $dnsarg ]] && dnsarg=none set_dns_value $dnsarg fi if [[ -n $kdc_list ]]; then if [[ -z $KDC ]]; then for kdc in $kdc_list; do break done KDC="$kdc" fi fi if [[ -z $realm ]]; then printf "$(gettext "Enter the Kerberos realm"): " read realm checkval="REALM"; check_value $realm fi if [[ -z $KDC ]]; then printf "$(gettext "Specify the master KDC hostname for the above realm"): " read KDC checkval="KDC"; check_value $KDC fi FKDC=`$KLOOKUP $KDC` # # Ping to see if the kdc is alive ! # ping_check $FKDC "KDC" if [[ -z $kdc_list && (-z $options || -z $filepath) ]]; then query "$(gettext "Do you have any slave KDC(s)") ?" if [[ $answer == yes ]]; then printf "$(gettext "Enter a comma-separated list of slave KDC host names"): " read kdc_list fi fi [[ -n $kdc_list ]] && verify_kdcs "$kdc_list" # # Check to see if we will have a dynamic presence in the realm # if [[ -z $options ]]; then query "$(gettext "Will this client need service keys") ?" if [[ $answer == no ]]; then no_keytab=yes fi fi # # Check to see if we are configuring the client to use a logical host name # of a cluster environment # if [[ -z $options ]]; then query "$(gettext "Is this client a member of a cluster that uses a logical host name") ?" if [[ $answer == yes ]]; then printf "$(gettext "Specify the logical hostname of the cluster"): " read logical_hn checkval="LOGICAL_HOSTNAME"; check_value $logical_hn setup_lhn fi fi if [[ -n $domain_list && (-z $options || -z $filepath) ]]; then query "$(gettext "Do you have multiple domains/hosts to map to realm %s" ) ?" $realm if [[ $answer == yes ]]; then printf "$(gettext "Enter a comma-separated list of domain/hosts to map to the default realm"): " read domain_list fi fi [[ -n domain_list ]] && domain_list=${domain_list//,/ } # # Start writing up the krb5.conf file, save the existing one # if already present # writeup_krb5_conf # # Is this client going to use krb-nfs? If so then we need to at least # uncomment the krb5* sec flavors in nfssec.conf. # if [[ -z $options ]]; then query "$(gettext "Do you plan on doing Kerberized nfs") ?" add_nfs=$answer fi if [[ $add_nfs == yes ]]; then modify_nfssec_conf # # We also want to enable gss as we now live in a SBD world # svcadm enable svc:/network/rpc/gss:default [[ $? -ne 0 ]] && printf "$(gettext "Warning: could not enable gss service").\n" fi if [[ -z $options ]]; then query "$(gettext "Do you want to update /etc/pam.conf") ?" if [[ $answer == yes ]]; then printf "$(gettext "Enter a list of PAM service names in the following format: service:{first|only|optional}[,..]"): " read svc_list SVCs=${svc_list//,/ } fi fi [[ -n $svc_list ]] && update_pam_conf # # Copy over krb5.conf master copy from filepath # if [[ -z $options || -z $filepath ]]; then query "$(gettext "Do you want to copy over the master krb5.conf file") ?" if [[ $answer == yes ]]; then printf "$(gettext "Enter the pathname of the file to be copied"): " read filepath fi fi if [[ -n $filepath && -r $filepath ]]; then cp $filepath $KRB5_CONFIG if [[ $? -eq 0 ]]; then printf "$(gettext "Copied %s to %s").\n" $filepath $KRB5_CONFIG else printf "$(gettext "Copy of %s failed, exiting").\n" $filepath >&2 error_message fi elif [[ -n $filepath ]]; then printf "\n$(gettext "%s not found, exiting").\n" $filepath >&2 error_message fi doKRB5config # # Populate any service keys needed for the client in the keytab file # if [[ $no_keytab != yes ]]; then setup_keytab else printf "\n$(gettext "Note: %s file not created, please refer to verify_ap_req_nofail in krb5.conf(5) for the implications").\n" $KRB5_KEYTAB_FILE printf "$(gettext "Client will also not be able to host services that use Kerberos").\n" fi printf -- "\n---------------------------------------------------\n" printf "$(gettext "Setup COMPLETE").\n\n" # # If we have configured the client in a cluster we need to remind the user # to propagate the keytab and configuration files to the other members. # if [[ -n $logical_hn ]]; then printf "\n$(gettext "Note, you will need to securely transfer the /etc/krb5/krb5.keytab and /etc/krb5/krb5.conf files to all the other members of your cluster").\n" fi # # Cleanup. # kdestroy -q 1>$TMP_FILE 2>&1 rm -f $TMP_FILE rm -rf $TMPDIR > /dev/null 2>&1 exit 0 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include struct profile_string_list { char **list; int num; int max; }; /* * From prof_get.c as the following four functions are private in mech_krb5. */ /* * Initialize the string list abstraction. */ static errcode_t init_list(struct profile_string_list *list) { list->num = 0; list->max = 10; list->list = malloc(list->max * sizeof (char *)); if (list->list == NULL) return (ENOMEM); list->list[0] = NULL; return (0); } /* * If re_list is non-NULL then pass the list header to the caller else free * the previously allocated list. */ static void end_list(struct profile_string_list *list, char ***ret_list) { if (list == NULL) return; if (ret_list) { *ret_list = list->list; return; } else profile_free_list(list->list); list->num = list->max = 0; list->list = NULL; } /* * Add a string to the list. */ static errcode_t add_to_list(struct profile_string_list *list, const char *str) { char *newstr, **newlist; int newmax; if (list->num + 1 >= list->max) { newmax = list->max + 10; newlist = realloc(list->list, newmax * sizeof (char *)); if (newlist == NULL) return (ENOMEM); list->max = newmax; list->list = newlist; } newstr = strdup(str); if (newstr == NULL) return (ENOMEM); list->list[list->num++] = newstr; list->list[list->num] = NULL; return (0); } static void usage() { (void) fprintf(stderr, gettext("kconf -f -r " "-k -m \n -p " "-d \n")); exit(1); } int main(int argc, char **argv) { profile_t profile; errcode_t code; int c; char *realm, *kdcs, *master, *domain, *token, *lasts; char *file, **ret_values = NULL; boolean_t set_change = FALSE; struct profile_string_list values; file = NULL; domain = NULL; master = NULL; kdcs = NULL; realm = NULL; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* TEXT_DOMAIN */ (void) textdomain(TEXT_DOMAIN); /* * kconf -f -r -k -m * -p -d */ while ((c = getopt(argc, argv, "f:r:k:a:s:p:d:m:")) != -1) { switch (c) { case 'f': file = optarg; break; case 'r': realm = optarg; break; case 'k': kdcs = optarg; break; case 'm': master = optarg; break; case 'p': if (strcmp(optarg, "SET_CHANGE") == 0) set_change = TRUE; break; case 'd': domain = optarg; break; default: usage(); break; } } code = __profile_init(file, &profile); if (code != 0) { fprintf(stderr, gettext("Wasn't able to initialize profile\n")); exit(code); } if (code = init_list(&values)) { fprintf(stderr, gettext("Can not initialize list %d\n"), code); goto error; } token = strtok_r(kdcs, ",", &lasts); do { if (token != NULL) { code = add_to_list(&values, token); if (code != 0) { fprintf(stderr, gettext("Can not add to list " "%d\n"), code); goto error; } } else { fprintf(stderr, gettext("Couldn't parse kdc list %d\n"), code); goto error; } } while ((token = strtok_r(NULL, ",", &lasts)) != NULL); end_list(&values, &ret_values); code = __profile_add_realm(profile, realm, master, ret_values, set_change, TRUE); if (code != 0) { fprintf(stderr, gettext("Wasn't able to add realm " "information\n")); goto error; } code = __profile_add_domain_mapping(profile, domain, realm); if (code != 0) { fprintf(stderr, gettext("Wasn't able to add domain mapping\n")); goto error; } error: if (ret_values != NULL) profile_free_list(ret_values); /* * Release profile, which will subsequently flush new profile to file. * If this fails then at least free profile memory. */ if ((code = __profile_release(profile)) != 0) __profile_abandon(profile); return (code); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include char *whoami = NULL; static void usage(); static void usage() { fprintf(stderr, gettext("Usage: %s -d fqdn\n"), whoami); fprintf(stderr, gettext("\t-d\tThe fully qualified domain of the client\n")); exit(1); } int main(int argc, char **argv) { char fqdn[MAXHOSTNAMELEN]; int c, ret = 0; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* TEXT_DOMAIN */ (void) textdomain(TEXT_DOMAIN); whoami = argv[0]; while ((c = getopt(argc, argv, "d:")) != -1) { switch (c) { case 'd': (void) strncpy(fqdn, optarg, sizeof (fqdn)); break; default: usage(); break; } } if (argc != optind) usage(); /* * Update DNS RR for the client using DynDNS. First it tries the * unauthed version then it tries the GSS version. */ ret = dyndns_update(fqdn); return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Portions Copyright 2021, Chris Fraire . */ #include #include #include #include #include #include "k5-int.h" #define QUOTE(x) #x #define VAL2STR(x) QUOTE(x) static char *whoami = NULL; static void kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ, const krb5_principal sprinc, krb5_enctype enctype, krb5_kvno kvno, const char *pw); static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ); static void usage(); int main(int argc, char **argv) { krb5_context ctx = NULL; krb5_error_code code = 0; krb5_enctype *enctypes = NULL; int enctype_count = 0; krb5_ccache cc = NULL; krb5_keytab kt = NULL; krb5_kvno kvno = 1; krb5_principal victim, salt = NULL; char *vprincstr, *ktname, *token, *lasts, *newpw; int c, result_code, i, len, nflag = 0; krb5_data result_code_string, result_string; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* TEXT_DOMAIN */ (void) textdomain(TEXT_DOMAIN); /* Misc init stuff */ (void) memset(&result_code_string, 0, sizeof (result_code_string)); (void) memset(&result_string, 0, sizeof (result_string)); whoami = argv[0]; code = krb5_init_context(&ctx); if (code != 0) { com_err(whoami, code, gettext("krb5_init_context() failed")); exit(1); } while ((c = getopt(argc, argv, "v:c:k:e:ns:")) != -1) { switch (c) { case 'n': nflag++; break; case 'k': if (kt != NULL) usage(); len = snprintf(NULL, 0, "WRFILE:%s", optarg) + 1; if ((ktname = malloc(len)) == NULL) { (void) fprintf(stderr, gettext("Couldn't allocate memory\n")); exit(1); } (void) snprintf(ktname, len, "WRFILE:%s", optarg); if ((code = krb5_kt_resolve(ctx, ktname, &kt)) != 0) { com_err(whoami, code, gettext("Couldn't open/create " "keytab %s"), optarg); exit(1); } break; case 'c': if (cc != NULL) usage(); if ((code = krb5_cc_resolve(ctx, optarg, &cc)) != 0) { com_err(whoami, code, gettext("Couldn't open ccache %s"), optarg); exit(1); } break; case 'e': len = strlen(optarg); token = strtok_r(optarg, ",\t ", &lasts); if (token == NULL) usage(); do { if (enctype_count++ == 0) { enctypes = malloc(sizeof (*enctypes)); } else { enctypes = realloc(enctypes, sizeof (*enctypes) * enctype_count); } if (enctypes == NULL) { (void) fprintf(stderr, gettext ("Couldn't allocate memory")); exit(1); } code = krb5_string_to_enctype(token, &enctypes[enctype_count - 1]); if (code != 0) { com_err(whoami, code, gettext("Unknown " "or unsupported enctype %s"), optarg); exit(1); } } while ((token = strtok_r(NULL, ",\t ", &lasts)) != NULL); break; case 'v': kvno = (krb5_kvno) atoi(optarg); break; case 's': vprincstr = optarg; code = krb5_parse_name(ctx, vprincstr, &salt); if (code != 0) { com_err(whoami, code, gettext("krb5_parse_name(%s) failed"), vprincstr); exit(1); } break; default: usage(); break; } } if (nflag && enctype_count == 0) usage(); if (nflag == 0 && cc == NULL && (code = krb5_cc_default(ctx, &cc)) != 0) { com_err(whoami, code, gettext("Could not find a ccache")); exit(1); } if (enctype_count > 0 && kt == NULL && (code = krb5_kt_default(ctx, &kt)) != 0) { com_err(whoami, code, gettext("No keytab specified")); exit(1); } if (argc != (optind + 1)) usage(); vprincstr = argv[optind]; code = krb5_parse_name(ctx, vprincstr, &victim); if (code != 0) { com_err(whoami, code, gettext("krb5_parse_name(%s) failed"), vprincstr); exit(1); } if (!isatty(fileno(stdin))) { char buf[PASS_MAX + 1]; if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) { (void) fprintf(stderr, gettext("Couldn't read new password\n")); exit(1); } newpw = strdup(buf); if (newpw == NULL) { (void) fprintf(stderr, gettext("Couldn't allocate memory\n")); exit(1); } } else { newpw = getpassphrase(gettext("Enter new password: ")); if (newpw == NULL) { (void) fprintf(stderr, gettext("Couldn't read new password\n")); exit(1); } newpw = strdup(newpw); if (newpw == NULL) { (void) fprintf(stderr, gettext("Couldn't allocate memory\n")); exit(1); } } if (nflag == 0) { code = krb5_set_password_using_ccache(ctx, cc, newpw, victim, &result_code, &result_code_string, &result_string); if (code != 0) { com_err(whoami, code, gettext("krb5_set_password() failed")); exit(1); } krb5_cc_close(ctx, cc); (void) printf("Result: %.*s (%d) %.*s\n", result_code == 0 ? strlen("success") : result_code_string.length, result_code == 0 ? "success" : result_code_string.data, result_code, result_string.length, result_string.data); if (result_code != 0) { (void) fprintf(stderr, gettext("Exiting...\n")); exit(result_code); } } if (enctype_count && (code = kt_remove_entries(ctx, kt, victim))) goto error; if (salt == NULL) salt = victim; for (i = 0; i < enctype_count; i++) kt_add_entry(ctx, kt, victim, salt, enctypes[i], kvno, newpw); error: if (kt != NULL) krb5_kt_close(ctx, kt); return (code ? 1 : 0); } static krb5_error_code kt_remove_entries(krb5_context ctx, krb5_keytab kt, const krb5_principal princ) { krb5_error_code code; krb5_kt_cursor cursor; krb5_keytab_entry entry; /* * This is not a fatal error, we expect this to fail in the majority * of cases (when clients are first initialized). */ code = krb5_kt_get_entry(ctx, kt, princ, 0, 0, &entry); if (code != 0) { com_err(whoami, code, gettext("Could not retrieve entry in keytab")); return (0); } krb5_kt_free_entry(ctx, &entry); code = krb5_kt_start_seq_get(ctx, kt, &cursor); if (code != 0) { com_err(whoami, code, gettext("While starting keytab scan")); return (code); } while ((code = krb5_kt_next_entry(ctx, kt, &entry, &cursor)) == 0) { if (krb5_principal_compare(ctx, princ, entry.principal)) { code = krb5_kt_end_seq_get(ctx, kt, &cursor); if (code != 0) { com_err(whoami, code, gettext("While temporarily " "ending keytab scan")); return (code); } code = krb5_kt_remove_entry(ctx, kt, &entry); if (code != 0) { com_err(whoami, code, gettext("While deleting entry " "from keytab")); return (code); } code = krb5_kt_start_seq_get(ctx, kt, &cursor); if (code != 0) { com_err(whoami, code, gettext("While restarting keytab scan")); return (code); } } krb5_kt_free_entry(ctx, &entry); } if (code && code != KRB5_KT_END) { com_err(whoami, code, gettext("While scanning keytab")); return (code); } if ((code = krb5_kt_end_seq_get(ctx, kt, &cursor))) { com_err(whoami, code, gettext("While ending keytab scan")); return (code); } return (0); } static void kt_add_entry(krb5_context ctx, krb5_keytab kt, const krb5_principal princ, const krb5_principal sprinc, krb5_enctype enctype, krb5_kvno kvno, const char *pw) { krb5_keytab_entry *entry; krb5_data password, salt; krb5_keyblock key; krb5_error_code code; char enctype_name[100]; if ((code = krb5_enctype_to_string(enctype, enctype_name, sizeof (enctype_name)))) { com_err(whoami, code, gettext("Enctype %d has no name!"), enctype); return; } if ((entry = (krb5_keytab_entry *) malloc(sizeof (*entry))) == NULL) { (void) fprintf(stderr, gettext("Couldn't allocate memory")); return; } (void) memset((char *)entry, 0, sizeof (*entry)); password.length = strlen(pw); password.data = (char *)pw; if ((code = krb5_principal2salt(ctx, sprinc, &salt)) != 0) { com_err(whoami, code, gettext("Could not compute salt for %s"), enctype_name); return; } code = krb5_c_string_to_key(ctx, enctype, &password, &salt, &key); if (code != 0) { com_err(whoami, code, gettext("Could not convert to key for %s"), enctype_name); krb5_xfree(salt.data); return; } (void) memcpy(&entry->key, &key, sizeof (krb5_keyblock)); entry->vno = kvno; entry->principal = princ; if ((code = krb5_kt_add_entry(ctx, kt, entry)) != 0) { com_err(whoami, code, gettext("Could not add entry to keytab")); } } static void usage() { (void) fprintf(stderr, gettext("Usage: %s [-c ccache] [-k keytab] " "[-e enctype_list] [-s salt_name] [-n] princ\n"), whoami); (void) fprintf(stderr, gettext("\t-n\tDon't set the principal's password\n")); (void) fprintf(stderr, gettext("\tenctype_list is a comma or whitespace" " separated list\n")); (void) fprintf(stderr, gettext("\tIf -n is used then -k and -e must be " "used\n")); exit(1); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #define QUOTE(x) #x #define VAL2STR(x) QUOTE(x) char *whoami = NULL; static void usage(); static void usage() { fprintf(stderr, gettext("Usage: %s [ -d fqdn ] [ -s server ]\n"), whoami); fprintf(stderr, gettext("\t-d\tThe fully qualified domain of the client\n")); fprintf(stderr, gettext("\t-s\tThe domain controller to join\n")); fprintf(stderr, gettext("\tstdin is used to read in the password or \n")); fprintf(stderr, gettext("\tthe password is prompted for.\n")); exit(1); } int main(int argc, char **argv) { char fqdn[MAXHOSTNAMELEN], server[MAXHOSTNAMELEN]; char *newpw; int c, ret = 0; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* TEXT_DOMAIN */ (void) textdomain(TEXT_DOMAIN); whoami = argv[0]; while ((c = getopt(argc, argv, "d:s:")) != -1) { switch (c) { case 'd': (void) strncpy(fqdn, optarg, sizeof (fqdn)); break; case 's': (void) strncpy(server, optarg, sizeof (server)); break; default: usage(); break; } } if (argc != optind) usage(); if (!isatty(fileno(stdin))) { char buf[PASS_MAX + 1]; if (scanf("%" VAL2STR(PASS_MAX) "s", &buf) != 1) { fprintf(stderr, gettext("Couldn't read new password\n")); exit(1); } newpw = strdup(buf); if (newpw == NULL) { fprintf(stderr, gettext("Couldn't allocate memory\n")); exit(1); } } else { newpw = getpassphrase(gettext("Enter new password: ")); if (newpw == NULL) { fprintf(stderr, gettext("Couldn't read new password\n")); exit(1); } newpw = strdup(newpw); if (newpw == NULL) { fprintf(stderr, gettext("Couldn't allocate memory\n")); exit(1); } } /* * Set the SMF properties for smb for later use. */ ret = smb_setdomainprops(fqdn, server, newpw); free(newpw); return (ret); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # PAM include module for Kerberos authentication foremost and then fall-back # to crypt authentication. # # Hammerhead: pam_dhkeys.so.1 line removed (NIS/SUN-DES key support gone). OTHER auth requisite pam_authtok_get.so.1 OTHER auth required pam_unix_cred.so.1 OTHER auth sufficient pam_krb5.so.1 OTHER auth required pam_unix_auth.so.1 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # PAM include module for Kerberos authentication foremost and then fall-back # to crypt authentication. # # Hammerhead: pam_dhkeys.so.1 line removed (NIS/SUN-DES key support gone). OTHER auth requisite pam_authtok_get.so.1 OTHER auth required pam_unix_cred.so.1 OTHER auth binding pam_krb5.so.1 OTHER auth required pam_unix_auth.so.1 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # # PAM include module for Kerberos authentication foremost and then fall-back # to crypt authentication. # # Hammerhead: pam_dhkeys.so.1 line removed (NIS/SUN-DES key support gone). OTHER auth requisite pam_authtok_get.so.1 OTHER auth required pam_unix_cred.so.1 OTHER auth required pam_unix_auth.so.1 OTHER auth optional pam_krb5.so.1 # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= kdcmgr KLPROG= klookup OBJS= klookup.o SSRCS= kdcmgr.sh CSRCS= $(OBJS:.o=.c) include ../../../Makefile.cmd POFILE= $(SSRCS:%.sh=%.po) CERRWARN += -Wno-implicit-function-declaration # not linted SMATCH=off LDLIBS += -lresolv -lnsl CLOBBERFILES += $(KLPROG) .KEEP_STATE: all: $(PROG) $(KLPROG) KRB5LIBKLPROG= $(KLPROG:%=$(KRB5LIB)/%) install: $(PROG) $(KRB5SBINPROG) $(KRB5LIBKLPROG) $(KLPROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) clean: $(RM) $(OBJS) include ../../../Makefile.targ #!/usr/bin/ksh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # This command provides an simple interface to configure, destroy, and to obtain # the status of a master or slave Kerberos KDC server. # function usage { app=`basename $0` printf "\n$(gettext "Usage: %s [ -a admprincipal ] [ -e enctype ] [ -h ]")\n" $app printf "\t$(gettext "[ -p pwfile ] [ -r realm ] subcommand")\n\n" printf "\t$(gettext "-a: Create non-default admin principal.")\n" printf "\t$(gettext "-e: Encryption type used to encrypt the master key")\n" printf "\t$(gettext "-h: This help message.")\n" printf "\t$(gettext "-p: File that contains the admin principal and master key password.")\n" printf "\t$(gettext "-r: Set the default realm for this server.")\n\n" printf "\t$(gettext "where 'subcommand' is one of the following:")\n\n" printf "\t$(gettext "create [ master ]")\n" printf "\t$(gettext "create [ -m masterkdc ] slave")\n" printf "\t$(gettext "destroy")\n" printf "\t$(gettext "status")\n\n" cleanup 1 } function ask { # ask question, set global answer typeset question=$1 default_answer=$2 if [[ -z $default_answer ]]; then print "$question \c" else print "$question [$default_answer]: \c" fi read answer [ -z "$answer" ] && answer="$default_answer" } function yesno { typeset question="$1" # answer is a global set by ask answer= yn=`printf "$(gettext "y/n")"` y=`printf "$(gettext "y")"` n=`printf "$(gettext "n")"` yes=`printf "$(gettext "yes")"` no=`printf "$(gettext "no")"` while [[ -z $answer ]]; do ask "$question" $yn case $answer in $y|$yes) answer=yes;; $n|$no) answer=no;; *) answer=;; esac done } function query { yesno "$*" if [[ $answer = no ]]; then printf "\t$(gettext "No action performed").\n" fi } function cleanup { integer ret=$1 kdestroy -q -c $TMP_CCACHE 1>$TMP_FILE 2>&1 rm -f $TMP_FILE exit $ret } function error_message { printf "---------------------------------------------------\n" printf "$(gettext "Setup FAILED").\n\n" cleanup 1 } function check_bin { bin=$1 if [[ ! -x $bin ]]; then printf "$(gettext "Could not access/execute %s").\n" $bin error_message fi } function check_ret { integer ret=$1 prog=$2 if [[ $ret -ne 0 ]]; then printf "\n$(gettext "%s failed with return value %d, exiting").\n\n" $prog $ret error_message fi } function ok_to_proceed { yesno "$@" if [[ $answer = no ]]; then printf "\n$(gettext "Exiting, no action performed")\n\n" cleanup 0 fi } function check_value { typeset arg="$1" if [[ -z $arg ]]; then printf "\n$(gettext "No input obtained for %s, exiting").\n" $checkval error_message else echo "$arg">$TMP_FILE if egrep -s '[*$^#!]+' $TMP_FILE; then printf "\n$(gettext "Invalid input obtained for %s, exiting").\n" $checkval error_message fi fi } function setup_kdc_conf { printf "\n$(gettext "Setting up %s").\n" $KRB5_KDC_CONF if [[ -r $KRB5_KDC_CONF ]]; then cat $KRB5_KDC_CONF > $KRB5_KDC_CONF.sav cannot_create $KRB5_KDC_CONF.sav $? fi exec 3>$KRB5_KDC_CONF if [[ $? -ne 0 ]]; then printf "\n$(gettext "Cannot write to %s, exiting").\n" $KRB5_KDC_CONF error_message fi printf "\n[kdcdefaults]\n\tkdc_ports = 88,750\n\n" 1>&3 printf "[realms]\n\t$REALM = {\n" 1>&3 printf "\t\tprofile = $KRB5_KRB_CONF\n" 1>&3 printf "\t\tdatabase_name = $PRINCDB\n" 1>&3 printf "\t\tmaster_key_type = $ENCTYPE\n" 1>&3 printf "\t\tacl_file = $KADM5ACL\n" 1>&3 printf "\t\tkadmind_port = 749\n" 1>&3 printf "\t\tmax_life = 8h 0m 0s\n" 1>&3 printf "\t\tmax_renewable_life = 7d 0h 0m 0s\n" 1>&3 printf "\t\tdefault_principal_flags = +preauth\n" 1>&3 printf "\t\tsunw_dbprop_enable = true\n" 1>&3 if [[ $master = yes ]]; then printf "\t\tsunw_dbprop_master_ulogsize = 1000\n" 1>&3 fi if [[ $slave = yes ]]; then printf "\t\tsunw_dbprop_slave_poll = 2m\n" 1>&3 fi printf "\t}\n" 1>&3 } function setup_krb_conf { printf "\n$(gettext "Setting up %s").\n" $KRB5_KRB_CONF if [[ -r $KRB5_KRB_CONF ]]; then cat $KRB5_KRB_CONF > $KRB5_KRB_CONF.sav cannot_create $KRB5_KRB_CONF.sav $? fi exec 3>$KRB5_KRB_CONF if [[ $? -ne 0 ]]; then printf "\n$(gettext "Cannot write to %s, exiting").\n" $KRB5_KRB_CONF error_message fi printf "[libdefaults]\n" 1>&3 printf "\tdefault_realm = $REALM\n\n" 1>&3 printf "[realms]\n" 1>&3 printf "\t$REALM = {\n" 1>&3 if [[ $slave = yes ]]; then printf "\t\tkdc = $master_hn\n" 1>&3 fi printf "\t\tkdc = $fqhn\n" 1>&3 if [[ $master = yes ]]; then printf "\t\tadmin_server = $fqhn\n" 1>&3 else printf "\t\tadmin_server = $master_hn\n" 1>&3 fi printf "\t}\n\n" 1>&3 printf "[domain_realm]\n" 1>&3 printf "\t.$domain = $REALM\n\n" 1>&3 printf "[logging]\n" 1>&3 printf "\tdefault = FILE:/var/krb5/kdc.log\n" 1>&3 printf "\tkdc = FILE:/var/krb5/kdc.log\n" 1>&3 printf "\tkdc_rotate = {\n\t\tperiod = 1d\n\t\tversions = 10\n\t}\n\n" 1>&3 printf "[appdefaults]\n" 1>&3 printf "\tkinit = {\n\t\trenewable = true\n\t\tforwardable = true\n" 1>&3 printf "\t}\n" 1>&3 } function cannot_create { typeset filename="$1" typeset stat="$2" if [[ $stat -ne 0 ]]; then printf "\n$(gettext "Cannot create/edit %s, exiting").\n" $filename error_message fi } function check_admin { message=$1 if [[ -z $ADMIN_PRINC ]]; then printf "$message" read ADMIN_PRINC checkval="ADMIN_PRINC"; check_value $ADMIN_PRINC fi echo "$ADMIN_PRINC">$TMP_FILE if egrep -s '\/admin' $TMP_FILE; then # Already in "/admin" format, do nothing : else if egrep -s '\/' $TMP_FILE; then printf "\n$(gettext "Improper entry for krb5 admin principal, exiting").\n" error_message else ADMIN_PRINC=$(echo "$ADMIN_PRINC/admin") fi fi } function ping_check { typeset machine="$1" if $PING $machine > /dev/null 2>&1; then : else printf "\n$(gettext "%s %s is unreachable, exiting").\n" $string $machine error_message fi } function check_host { echo "$host">$TMP_FILE if egrep -s '[^.]\.[^.]+$' $TMP_FILE; then # do nothing, host is in fqhn format : else if egrep -s '\.+' $TMP_FILE; then printf "\n$(gettext "Improper format of host name: '%s'").\n" printf "$(gettext "Expecting the following format: 'somehost.example.com' or 'somehost', exiting").\n" error_message else # Attach fqdn to host, to get the Fully Qualified Domain # Name of the host requested host=$(echo "$host.$domain") fi fi # # Ping to see if the host is alive! # ping_check $host } function kill_daemons { # Kill daemons so they won't go into maintenance mode $SVCADM disable -s krb5kdc if [[ $? -ne 0 ]]; then printf "\n$(gettext "Error in disabling krb5kdc, exiting").\n" error_message fi $SVCADM disable -s kadmin if [[ $? -ne 0 ]]; then printf "\n$(gettext "Error in disabling kadmind, exiting").\n" error_message fi $SVCADM disable -s krb5_prop if [[ $? -ne 0 ]]; then printf "\n$(gettext "Error in disabling kpropd, exiting").\n" error_message fi # Make sure that none of the daemons outside of SMF are running either pkill kadmind if [[ $? -gt 1 ]]; then printf "\n$(gettext "Error in killing kadmind, exiting").\n" error_message fi pkill krb5kdc if [[ $? -gt 1 ]]; then printf "\n$(gettext "Error in killing krb5kdc, exiting").\n" error_message fi pkill kpropd if [[ $? -gt 1 ]]; then printf "\n$(gettext "Error in killing kpropd, exiting").\n" error_message fi } function setup_mkeytab { check_admin "\n$(gettext "Enter the krb5 administrative principal to be created"): \c" if [[ -z $PWFILE ]]; then echo $KADMINL -q "ank $ADMIN_PRINC" check_ret $? $KADMINL else cat $PWFILE $PWFILE | $KADMINL -q "ank $ADMIN_PRINC" > /dev/null 2>&1 check_ret $? $KADMINL fi $KADMINL -q "ank -randkey host/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMINL $KADMINL -q "ktadd host/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMINL } function setup_skeytab { check_admin "\n$(gettext "Enter the krb5 administrative principal to be used"): \c" printf "$(gettext "Obtaining TGT for %s") ...\n" $ADMIN_PRINC if [[ -z $PWFILE ]]; then kinit -c $TMP_CCACHE -S kadmin/$master_hn $ADMIN_PRINC check_ret $? kinit else cat $PWFILE | kinit -c $TMP_CCACHE -S kadmin/$master_hn \ $ADMIN_PRINC > /dev/null 2>&1 fi klist -c $TMP_CCACHE 1>$TMP_FILE 2>&1 if egrep -s "$(gettext "Valid starting")" $TMP_FILE && \ egrep -s "kadmin/$master_hn@$REALM" $TMP_FILE; then : else printf "\n$(gettext "kinit of %s failed, exiting").\n" $ADMIN_PRINC error_message fi $KADMIN -c $TMP_CCACHE -q "ank -randkey kiprop/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMIN $KADMIN -c $TMP_CCACHE -q "ktadd kiprop/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMIN $KADMIN -c $TMP_CCACHE -q "ank -randkey host/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMIN $KADMIN -c $TMP_CCACHE -q "ktadd host/$fqhn" 1>$TMP_FILE 2>&1 check_ret $? $KADMIN kdestroy -q -c $TMP_CCACHE 1>$TMP_FILE 2>&1 check_ret $? $kdestroy } function setup_kadm5acl { printf "\n$(gettext "Setting up %s").\n" $KADM5ACL if [[ -r $KADM5ACL ]]; then cat $KADM5ACL > $KADM5ACL.sav cannot_create $KADM5ACL.sav $? fi exec 3>$KADM5ACL if [[ $? -ne 0 ]]; then printf "\n$(gettext "Cannot write to %s, exiting").\n" $KADM5ACL error_message fi if [[ $master = yes ]]; then printf "\n$ADMIN_PRINC@$REALM\t\tacmil\n" 1>&3 printf "\nkiprop/*@$REALM\t\tp\n" 1>&3 else printf "\n*/admin@___default_realm___\t\t*\n" 1>&3 fi } function setup_kpropdacl { printf "\n$(gettext "Setting up %s").\n\n" $KPROPACL if [[ -r $KPROPACL ]]; then cat $KPROPACL > $KPROPACL.sav cannot_create $KPROPACL.sav $? fi exec 3>$KPROPACL if [[ $? -ne 0 ]]; then printf "\n$(gettext "Cannot write to %s, exiting").\n" $KPROPACL error_message fi printf "\nhost/$master_hn@$REALM\n" 1>&3 } function setup_master { # create principal DB (KDB) if [[ -z $PWFILE ]]; then echo kdb5_util create check_ret $? kdb5_util else cat $PWFILE $PWFILE | kdb5_util create > /dev/null check_ret $? kdb5_util fi setup_mkeytab setup_kadm5acl $SVCADM enable -r -s krb5kdc $SVCADM enable -r -s kadmin } function setup_slave { integer count=1 setup_skeytab # Clear the kadm5acl, since the start methods look at this file # to see if the server has been configured as a master server setup_kadm5acl setup_kpropdacl $SVCADM enable -r -s krb5_prop # Wait for full propagation of the database, in some environments # this could take a few seconds while [[ ! -f /var/krb5/principal ]]; do if [[ count -gt $LOOPCNT ]]; then printf "\n$(gettext "Could not receive updates from the master").\n" error_message ((count = count + 1)) fi printf "$(gettext "Waiting for database from master")...\n" sleep $SLEEPTIME done # The database is propagated now we need to create the stash file if [[ -z $PWFILE ]]; then kdb5_util stash check_ret $? kdb5_util else cat $PWFILE | kdb5_util stash > /dev/null 2>&1 check_ret $? kdb5_util fi $SVCADM enable -r -s krb5kdc } function kdb5_destroy { typeset status=0 typeset arg= [[ -n $REALM ]] && arg="-r $REALM" printf "$(gettext "yes")\n" | kdb5_util $arg destroy > /dev/null 2>&1 status=$? [[ $status -eq 0 ]] && return $status # Could mean that the admin could have already removed part of the # configuration. Better to check to see if anything else should be # destroyed. We check by looking at any other stash files in /var/krb5 stashfiles=`ls $STASH` for stash in $stashfiles do realm=${stash#*.k5.} [[ -z $realm ]] && continue printf "$(gettext "Found non-default realm: %s")\n" $realm query "$(gettext "Do you wish to destroy realm"): $realm ?" if [[ $answer == yes ]]; then printf "$(gettext "yes")\n" | kdb5_util -r $realm destroy > /dev/null 2>&1 status=$? if [[ $status -ne 0 ]]; then printf "$(gettext "Could not destroy realm: %s")\n" $realm return $status fi else printf "$(gettext "%s will not be destroyed").\n" $realm status=0 fi done return $status } function destroy_kdc { typeset status # Check first to see if this is an existing KDC or server if [[ -f $KRB5KT || -f $PRINCDB || -f $OLDPRINCDB ]] then if [[ -z $PWFILE ]]; then printf "\n$(gettext "Some of the following files are present on this system"):\n" echo "\t$KRB5KT\n\t$PRINCDB\n\t$OLDPRINCDB\n\t$STASH\n" if [[ -z $d_option ]]; then printf "$(gettext "You must first run 'kdcmgr destroy' to remove all of these files before creating a KDC server").\n\n" cleanup 1 else ok_to_proceed "$(gettext "All of these files will be removed, okay to proceed?")" fi fi else if [[ -n $d_option ]]; then printf "\n$(gettext "No KDC related files exist, exiting").\n\n" cleanup 0 fi return fi kdb5_destroy status=$? rm -f $KRB5KT [[ $status -ne 0 ]] && cleanup 1 } function kadm5_acl_configed { if [[ -s $KADM5ACL ]]; then grep -v '^[ ]*#' $KADM5ACL | \ egrep '_default_realm_' > /dev/null 2>&1 if [[ $? -gt 0 ]]; then return 0 fi fi return 1 } function status_kdc { integer is_master=0 printf "\n$(gettext "KDC Status Information")\n" echo "--------------------------------------------" svcs -xv svc:/network/security/krb5kdc:default if kadm5_acl_configed; then is_master=1 printf "\n$(gettext "KDC Master Status Information")\n" echo "--------------------------------------------" svcs -xv svc:/network/security/kadmin:default else printf "\n$(gettext "KDC Slave Status Information")\n" echo "--------------------------------------------" svcs -xv svc:/network/security/krb5_prop:default fi printf "\n$(gettext "Transaction Log Information")\n" echo "--------------------------------------------" /usr/sbin/kproplog -h printf "$(gettext "Kerberos Related File Information")\n" echo "--------------------------------------------" printf "$(gettext "(will display any missing files below)")\n" FILELIST="$KRB5_KDC_CONF $KRB5_KRB_CONF $KADM5ACL $KRB5KT $PRINCDB " for file in $FILELIST; do if [[ ! -s $file ]]; then printf "$(gettext "%s not found").\n" $file fi done if [[ $is_master -eq 0 && ! -s $KPROPACL ]]; then printf "$(gettext "%s not found").\n" $KPROPACL fi test ! -s $STASH && printf "$(gettext "Stash file not found") (/var/krb5/.k5.*).\n" echo cleanup 0 } # Start of Main script typeset -u REALM typeset -l host typeset -l fqhn # Defaults KRB5_KDC_CONF=/etc/krb5/kdc.conf KRB5_KRB_CONF=/etc/krb5/krb5.conf KADM5ACL=/etc/krb5/kadm5.acl KPROPACL=/etc/krb5/kpropd.acl KRB5KT=/etc/krb5/krb5.keytab PRINCDB=/var/krb5/principal OLDPRINCDB=/var/krb5/principal.old STASH=/var/krb5/.k5.* KADMINL=/usr/sbin/kadmin.local; check_bin $KADMINL KADMIN=/usr/sbin/kadmin; check_bin $KADMIN KDCRES=/usr/lib/krb5/klookup; check_bin $KDCRES SVCADM=/sbin/svcadm; check_bin $SVCADM PING=/sbin/ping; check_bin $PING ENCTYPE=aes128-cts-hmac-sha1-96 LOOPCNT=10 SLEEPTIME=5 if [[ -x /usr/bin/mktemp ]]; then TMP_FILE=$(/usr/bin/mktemp /etc/krb5/krb5tmpfile.XXXXXX) TMP_CCACHE=$(/usr/bin/mktemp /etc/krb5/krb5tmpccache.XXXXXX) else TMP_FILE="/etc/krb5/krb5tmpfile.$$" TMP_CCACHE="/etc/krb5/krb5tmpccache.$$" fi if [[ ! -f /etc/resolv.conf ]]; then printf "$(gettext "Error: need to configure /etc/resolv.conf").\n" cleanup 1 fi fqhn=`$KDCRES` if [[ -n "$fqhn" ]]; then : elif [[ -n $(hostname) && -n $(domainname) ]]; then fqhn=$(hostname|cut -f1 -d'.').$(domainname|cut -f2- -d'.') else printf "$(gettext "Error: can not determine full hostname (FQHN). Aborting")\n" printf "$(gettext "Note, trying to use hostname and domainname to get FQHN").\n" cleanup 1 fi ping_check $fqhn domain=${fqhn#*.} # remove host part exitmsg=`printf "$(gettext "Exiting...")"` trap "echo $exitmsg; rm -f $TMP_FILE $TMP_CCACHE; exit 1" HUP INT QUIT TERM while getopts :a:e:hp:r:s flag do case "$flag" in a) ADMIN_PRINC=$OPTARG;; e) ENCTYPE=$OPTARG;; h) usage;; p) PWFILE=$OPTARG if [[ ! -r $PWFILE ]]; then printf "\n$(gettext "Password file %s does not exist, exiting").\n\n" $PWFILE cleanup 1 fi ;; r) REALM=$OPTARG;; *) usage;; esac done shift $(($OPTIND - 1)) case "$*" in create) master=yes;; "create master") master=yes;; "create -m "*) host=$3 checkval="MASTER"; check_value $host check_host master_hn=$host if [[ $4 != slave ]]; then usage fi;& "create slave") slave=yes;; destroy) d_option=yes kill_daemons destroy_kdc cleanup 0;; status) status_kdc;; *) usage;; esac kill_daemons printf "\n$(gettext "Starting server setup")\n" printf "---------------------------------------------------\n" # Checks for existing kdb and destroys if desired destroy_kdc if [[ -z $REALM ]]; then printf "$(gettext "Enter the Kerberos realm"): \c" read REALM checkval="REALM"; check_value $REALM fi if [[ -z $master && -z $slave ]]; then query "$(gettext "Is this machine to be configured as a master?"): \c" master=$answer if [[ $answer = no ]]; then query "$(gettext "Is this machine to be configured as a slave?"): \c" slave=$answer if [[ $answer = no ]]; then printf "\n$(gettext "Machine must either be a master or a slave KDC server").\n" error_message fi fi fi if [[ $slave = yes && -z $master_hn ]]; then printf "$(gettext "What is the master KDC's host name?"): \c" read host checkval="MASTER"; check_value $host check_host master_hn=$host fi setup_kdc_conf setup_krb_conf if [[ $master = yes ]]; then setup_master else setup_slave fi printf "\n---------------------------------------------------\n" printf "$(gettext "Setup COMPLETE").\n\n" cleanup 0 /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright 2014 Nexenta Systems, Inc. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include /* * Private resolver of target and type with arguments: * klooukp [ target [ RR_type ] ] * * Utitilizes DNS lookups to discover domain and realm information. This CLI * is used primarily by kdcmgr(8) and kclient(8). */ int /* ARGSUSED */ main(int argc, char **argv) { unsigned char answer[NS_MAXMSG], *ansp = NULL, *end, a, b, c, d; int len = 0, anslen, hostlen, nq, na, type, class; int ttl __unused, priority __unused, weight __unused, port, size; char name[NS_MAXDNAME], *cp, *typestr = NULL; char nbuf[INET6_ADDRSTRLEN]; struct __res_state stat; int found = 0; int rr_type = T_A; HEADER *h; type = T_A; if (argc > 3) exit(1); if (argc == 1) { if (gethostname(name, MAXHOSTNAMELEN) != 0) exit(1); } else { (void) strncpy(name, (char *)argv[1], NS_MAXDNAME); if (argc == 3) { typestr = argv[2]; switch (*typestr) { case 'A': rr_type = T_A; break; case 'C': rr_type = T_CNAME; break; case 'I': rr_type = T_A; break; case 'P': rr_type = T_PTR; (void) sscanf(name, "%hhd.%hhd.%hhd.%hhd", &a, &b, &c, &d); (void) sprintf(name, "%d.%d.%d.%d.in-addr.arpa", d, c, b, a); break; case 'S': rr_type = T_SRV; break; default: exit(1); } } } (void) memset(&stat, 0, sizeof (stat)); if (res_ninit(&stat) == -1) exit(1); anslen = sizeof (answer); len = res_nsearch(&stat, name, C_IN, rr_type, answer, anslen); if (len < sizeof (HEADER)) { res_ndestroy(&stat); exit(1); } ansp = answer; end = ansp + anslen; /* LINTED */ h = (HEADER *)answer; nq = ntohs(h->qdcount); na = ntohs(h->ancount); ansp += HFIXEDSZ; if (nq != 1 || na < 1) { res_ndestroy(&stat); exit(1); } hostlen = sizeof (name); len = dn_expand(answer, end, ansp, name, hostlen); if (len < 0) { res_ndestroy(&stat); exit(1); } ansp += len + QFIXEDSZ; if (ansp > end) { res_ndestroy(&stat); exit(1); } while (na-- > 0 && ansp < end) { len = dn_expand(answer, end, ansp, name, hostlen); if (len < 0) continue; ansp += len; /* name */ NS_GET16(type, ansp); /* type */ NS_GET16(class, ansp); /* class */ NS_GET32(ttl, ansp); /* ttl */ NS_GET16(size, ansp); /* size */ if ((ansp + size) > end) { res_ndestroy(&stat); exit(1); } if (type == T_SRV) { NS_GET16(priority, ansp); NS_GET16(weight, ansp); NS_GET16(port, ansp); len = dn_expand(answer, end, ansp, name, hostlen); if (len < 0) { res_ndestroy(&stat); exit(1); } for (cp = name; *cp; cp++) { *cp = tolower(*cp); } (void) printf("%s %d\n", name, port); } else if (typestr && *typestr == 'I') { (void) inet_ntop(AF_INET, (void *)ansp, nbuf, INET6_ADDRSTRLEN); len = size; (void) printf("%s\n", nbuf); } else if (type == T_PTR) { len = dn_expand(answer, end, ansp, name, hostlen); if (len < 0) { res_ndestroy(&stat); exit(1); } } ansp += len; if (type == rr_type && class == C_IN) { found = 1; if (type != T_SRV && !(typestr && *typestr == 'I')) break; } } if (found != 1) { res_ndestroy(&stat); exit(1); } for (cp = name; *cp; cp++) { *cp = tolower(*cp); } if (type != T_SRV && !(typestr && *typestr == 'I')) (void) printf("%s\n", name); res_ndestroy(&stat); return (0); } # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= kpasswd OBJS = tty_kpasswd.o kpasswd.o SRCS = $(OBJS:.o=.c) CLOBBERFILES += $(TESTPROG) include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(PROG).po POFILES = generic.po # # Override $ROOTLIB # KRB5LIBDIR= $(ROOT)$(KERBLIBDIR) CPPFLAGS += -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/uts/common/gssapi/include/ \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(SRC)/lib/krb5 \ -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_UNISTD_H=1 \ -DHAVE_SYS_TIMEB_H=1 -DHAVE_ALLOCA_H=1 -DHAVE_FTIME=1 \ -DHAVE_TIMEZONE -DUSE_KADM5_API_VERSION=2 CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-variable CERRWARN += -Wno-unused-function # not linted SMATCH=off LDFLAGS += $(KRUNPATH) $(KERBRUNPATH) LDLIBS += -L $(KRB5LIBDIR) LDLIBS += $(KMECHLIB) $(KCLNTLIB) .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) install: $(KRB5PROG) clean: $(RM) $(OBJS) include ../../../Makefile.targ $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ $(RM) generic.po generic.po: $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved. * * $Header$ * * */ static char rcsid[] = "$Id: kpasswd.c 17258 2005-06-21 01:36:03Z raeburn $"; #include #include #include "kpasswd_strings.h" #define string_text error_message #include "kpasswd.h" #include #include #include #include extern char *whoami; extern void display_intro_message(); extern long read_old_password(); extern long read_new_password(); #define MISC_EXIT_STATUS 6 /* * Function: kpasswd * * Purpose: Initialize and call lower level routines to change a password * * Arguments: * * context (r) krb5_context to use * argc/argv (r) principal name to use, optional * read_old_password (f) function to read old password * read_new_password (f) function to read new and change password * display_intro_message (f) function to display intro message * whoami (extern) argv[0] * * Returns: * exit status of 0 for success * 1 principal unknown * 2 old password wrong * 3 cannot initialize admin server session * 4 new passwd mismatch or error trying to change pw * 5 password not typed * 6 misc error * 7 incorrect usage * * Requires: * Passwords cannot be more than 255 characters long. * * Effects: * * If argc is 2, the password for the principal specified in argv[1] * is changed; otherwise, the principal of the default credential * cache or username is used. display_intro_message is called with * the arguments KPW_STR_CHANGING_PW_FOR and the principal name. * read_old_password is then called to prompt for the old password. * The admin system is then initialized, the principal's policy * retrieved and explained, if appropriate, and finally * read_new_password is called to read the new password and change the * principal's password (presumably ovsec_kadm_chpass_principal). * admin system is de-initialized before the function returns. * * Modifies: * * Changes the principal's password. * */ int kpasswd(context, argc, argv) krb5_context context; int argc; char *argv[]; { kadm5_ret_t code; krb5_ccache ccache = NULL; krb5_principal princ = 0; char *princ_str; struct passwd *pw = 0; unsigned int pwsize; char password[255]; /* I don't really like 255 but that's what kinit uses */ char msg_ret[1024], admin_realm[1024]; kadm5_principal_ent_rec principal_entry; kadm5_policy_ent_rec policy_entry; void *server_handle; kadm5_config_params params; char *cpw_service; memset((char *)¶ms, 0, sizeof (params)); memset(&principal_entry, 0, sizeof (principal_entry)); memset(&policy_entry, 0, sizeof (policy_entry)); if (argc > 2) { com_err(whoami, KPW_STR_USAGE, 0); return(7); /*NOTREACHED*/ } /************************************ * Get principal name to change * ************************************/ /* Look on the command line first, followed by the default credential cache, followed by defaulting to the Unix user name */ if (argc == 2) princ_str = strdup(argv[1]); else { code = krb5_cc_default(context, &ccache); /* If we succeed, find who is in the credential cache */ if (code == 0) { /* Get default principal from cache if one exists */ code = krb5_cc_get_principal(context, ccache, &princ); /* if we got a principal, unparse it, otherwise get out of the if with an error code */ (void) krb5_cc_close(context, ccache); if (code == 0) { code = krb5_unparse_name(context, princ, &princ_str); if (code != 0) { com_err(whoami, code, string_text(KPW_STR_UNPARSE_NAME)); return(MISC_EXIT_STATUS); } } } /* this is a crock.. we want to compare against */ /* "KRB5_CC_DOESNOTEXIST" but there is no such error code, and */ /* both the file and stdio types return FCC_NOFILE. If there is */ /* ever another ccache type (or if the error codes are ever */ /* fixed), this code will have to be updated. */ if (code && code != KRB5_FCC_NOFILE) { com_err(whoami, code, string_text(KPW_STR_WHILE_LOOKING_AT_CC)); return(MISC_EXIT_STATUS); } /* if either krb5_cc failed check the passwd file */ if (code != 0) { pw = getpwuid( getuid()); if (pw == NULL) { com_err(whoami, 0, string_text(KPW_STR_NOT_IN_PASSWD_FILE)); return(MISC_EXIT_STATUS); } princ_str = strdup(pw->pw_name); } } display_intro_message(string_text(KPW_STR_CHANGING_PW_FOR), princ_str); /* Need to get a krb5_principal, unless we started from with one from the credential cache */ if (! princ) { code = krb5_parse_name (context, princ_str, &princ); if (code != 0) { com_err(whoami, code, string_text(KPW_STR_PARSE_NAME), princ_str); free(princ_str); return(MISC_EXIT_STATUS); } } pwsize = sizeof(password); code = read_old_password(context, password, &pwsize); if (code != 0) { memset(password, 0, sizeof(password)); com_err(whoami, code, string_text(KPW_STR_WHILE_READING_PASSWORD)); krb5_free_principal(context, princ); free(princ_str); return(MISC_EXIT_STATUS); } if (pwsize == 0) { memset(password, 0, sizeof(password)); com_err(whoami, 0, string_text(KPW_STR_NO_PASSWORD_READ)); krb5_free_principal(context, princ); free(princ_str); return(5); } snprintf(admin_realm, sizeof (admin_realm), krb5_princ_realm(context, princ)->data); params.mask |= KADM5_CONFIG_REALM; params.realm = admin_realm; if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) { fprintf(stderr, gettext("%s: unable to get host based " "service name for realm %s\n"), whoami, admin_realm); exit(1); } code = kadm5_init_with_password(princ_str, password, cpw_service, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, NULL, &server_handle); free(cpw_service); if (code != 0) { if (code == KADM5_BAD_PASSWORD) com_err(whoami, 0, string_text(KPW_STR_OLD_PASSWORD_INCORRECT)); else com_err(whoami, 0, string_text(KPW_STR_CANT_OPEN_ADMIN_SERVER), admin_realm, error_message(code)); krb5_free_principal(context, princ); free(princ_str); return ((code == KADM5_BAD_PASSWORD) ? 2 : 3); } /* * we can only check the policy if the server speaks * RPCSEC_GSS */ if (_kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) { /* Explain policy restrictions on new password if any. */ /* * Note: copy of this exists in login * (kverify.c/get_verified_in_tkt). */ code = kadm5_get_principal(server_handle, princ, &principal_entry, KADM5_PRINCIPAL_NORMAL_MASK); if (code != 0) { com_err(whoami, 0, string_text((code == KADM5_UNK_PRINC) ? KPW_STR_PRIN_UNKNOWN : KPW_STR_CANT_GET_POLICY_INFO), princ_str); krb5_free_principal(context, princ); free(princ_str); (void) kadm5_destroy(server_handle); return ((code == KADM5_UNK_PRINC) ? 1 : MISC_EXIT_STATUS); } if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) { code = kadm5_get_policy(server_handle, principal_entry.policy, &policy_entry); if (code != 0) { /* * doesn't matter which error comes back, * there's no nice recovery or need to * differentiate to the user */ com_err(whoami, 0, string_text(KPW_STR_CANT_GET_POLICY_INFO), princ_str); (void) kadm5_free_principal_ent(server_handle, &principal_entry); krb5_free_principal(context, princ); free(princ_str); free(princ_str); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } com_err(whoami, 0, string_text(KPW_STR_POLICY_EXPLANATION), princ_str, principal_entry.policy, policy_entry.pw_min_length, policy_entry.pw_min_classes); if (code = kadm5_free_principal_ent(server_handle, &principal_entry)) { (void) kadm5_free_policy_ent(server_handle, &policy_entry); krb5_free_principal(context, princ); free(princ_str); com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } if (code = kadm5_free_policy_ent(server_handle, &policy_entry)) { krb5_free_principal(context, princ); free(princ_str); com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_POLICY)); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } } else { /* * kpasswd *COULD* output something here to * encourage the choice of good passwords, * in the absence of an enforced policy. */ if (code = kadm5_free_principal_ent(server_handle, &principal_entry)) { krb5_free_principal(context, princ); free(princ_str); com_err(whoami, code, string_text(KPW_STR_WHILE_FREEING_PRINCIPAL)); (void) kadm5_destroy(server_handle); return (MISC_EXIT_STATUS); } } } /* if protocol == KRB5_CHGPWD_RPCSEC */ pwsize = sizeof(password); code = read_new_password(server_handle, password, &pwsize, msg_ret, sizeof (msg_ret), princ); memset(password, 0, sizeof(password)); if (code) com_err(whoami, 0, msg_ret); krb5_free_principal(context, princ); free(princ_str); (void) kadm5_destroy(server_handle); if (code == KRB5_LIBOS_CANTREADPWD) return(5); else if (code) return(4); else return(0); } /* * kadmin/passwd/kpasswd.h * * Copyright 2001 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * * Prototypes for the kpasswd program callback functions. */ #ifndef __KPASSWD_H__ #define __KPASSWD_H__ int kpasswd(krb5_context context, int argc, char *argv[]); long read_old_password(krb5_context context, char *password, unsigned int *pwsize); long read_new_password(void *server_handle, char *password, unsigned int *pwsize, char *msg_ret, int msg_len, krb5_principal princ); void display_intro_message(const char *fmt_string, const char *arg_string); #endif /* __KPASSWD_H__ */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include /* * kpasswd_strings.h: * This file is automatically generated; please do not edit it. */ #define KPW_STR_USAGE (-1767084800L) #define KPW_STR_PRIN_UNKNOWN (-1767084799L) #define KPW_STR_WHILE_LOOKING_AT_CC (-1767084798L) #define KPW_STR_OLD_PASSWORD_INCORRECT (-1767084797L) #define KPW_STR_CANT_OPEN_ADMIN_SERVER (-1767084796L) #define KPW_STR_NEW_PASSWORD_MISMATCH (-1767084795L) #define KPW_STR_PASSWORD_CHANGED (-1767084794L) #define KPW_STR_PASSWORD_NOT_CHANGED (-1767084793L) #define KPW_STR_PARSE_NAME (-1767084792L) #define KPW_STR_UNPARSE_NAME (-1767084791L) #define KPW_STR_NOT_IN_PASSWD_FILE (-1767084790L) #define KPW_STR_CHANGING_PW_FOR (-1767084789L) #define KPW_STR_OLD_PASSWORD_PROMPT (-1767084788L) #define KPW_STR_WHILE_READING_PASSWORD (-1767084787L) #define KPW_STR_NO_PASSWORD_READ (-1767084786L) #define KPW_STR_WHILE_TRYING_TO_CHANGE (-1767084785L) #define KPW_STR_WHILE_DESTROYING_ADMIN_SESSION (-1767084784L) #define KPW_STR_WHILE_FREEING_PRINCIPAL (-1767084783L) #define KPW_STR_WHILE_FREEING_POLICY (-1767084782L) #define KPW_STR_CANT_GET_POLICY_INFO (-1767084781L) #define KPW_STR_POLICY_EXPLANATION (-1767084780L) #define ERROR_TABLE_BASE_kpws (-1767084800L) extern const struct error_table et_kpws_error_table; #if !defined(_WIN32) /* for compatibility with older versions... */ extern void initialize_kpws_error_table (void) /*@modifies internalState@*/; #else #define initialize_kpws_error_table() #endif #if !defined(_WIN32) #define init_kpws_err_tbl initialize_kpws_error_table #define kpws_err_base ERROR_TABLE_BASE_kpws #endif /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993-1994 OpenVision Technologies, Inc., All Rights Reserved. * * $Header: /cvs/krbdev/krb5/src/kadmin/passwd/tty_kpasswd.c,v 1.9 2001/02/26 18:22:08 epeisach Exp $ * * */ static char rcsid[] = "$Id: tty_kpasswd.c,v 1.9 2001/02/26 18:22:08 epeisach Exp $"; #include #include #include "kpasswd_strings.h" #define string_text error_message #include "kpasswd.h" #include #include #include #include #include char *whoami; void display_intro_message(fmt_string, arg_string) const char *fmt_string; const char *arg_string; { com_err(whoami, 0, fmt_string, arg_string); } long read_old_password(context, password, pwsize) krb5_context context; char *password; unsigned int *pwsize; { long code = krb5_read_password(context, (char *) string_text(KPW_STR_OLD_PASSWORD_PROMPT), 0, password, pwsize); return code; } long read_new_password(server_handle, password, pwsize, msg_ret, msg_len, princ) void *server_handle; char *password; unsigned int *pwsize; char *msg_ret; int msg_len; krb5_principal princ; { return (kadm5_chpass_principal_util(server_handle, princ, NULL, NULL /* don't need new pw back */, msg_ret, msg_len)); } /* * main() for tty version of kpasswd.c */ int main(argc, argv) int argc; char *argv[]; { krb5_context context; int retval; whoami = (whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0]; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); retval = krb5_init_context(&context); if (retval) { com_err(whoami, retval, gettext("initializing krb5 context")); exit(retval); } /* initialize_kpws_error_table(); SUNWresync121 */ retval = kpasswd(context, argc, argv); if (!retval) printf(string_text(KPW_STR_PASSWORD_CHANGED)); exit(retval); } # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= ktutil OBJS = ktutil.o ktutil_ct.o ktutil_funcs.o SRCS = $(OBJS:.o=.c) CLOBBERFILES += $(TESTPROG) include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(PROG).po POFILES = generic.po CPPFLAGS += -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/lib/krb5 -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(SRC)/uts/common/gssapi/include \ -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_UNISTD_H=1 \ -DHAVE_SYS_TIMEB_H=1 -DHAVE_ALLOCA_H=1 -DHAVE_FTIME=1 \ -DHAVE_TIMEZONE CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-unused-function # not linted SMATCH=off LDFLAGS += $(KRUNPATH) $(KERBRUNPATH) LDLIBS += $(KMECHLIB) $(ROOT)$(KERBLIBDIR)/libss.so .KEEP_STATE: all: $(PROG) ktutil: $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) install: $(KRB5PROG) clean: $(RM) $(OBJS) include ../../../Makefile.targ $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ $(RM) generic.po generic.po: $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * kadmin/ktutil/ktutil.c * * Copyright 1995, 1996 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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 user interface for ktutil. */ #include "k5-int.h" #include "ktutil.h" #include #include #include #ifdef HAVE_STDLIB_H #include #endif #include #include extern ss_request_table ktutil_cmds; krb5_context kcontext; krb5_kt_list ktlist = NULL; int main(argc, argv) int argc; char *argv[]; { krb5_error_code retval; int sci_idx; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); retval = krb5_init_context(&kcontext); if (retval) { com_err(argv[0], retval, gettext("while initializing krb5")); exit(1); } retval = ktutil_initialize_cmds_table (&ktutil_cmds); if (retval) { com_err(argv[0], retval, gettext("while localizing command description messages")); exit(1); } sci_idx = ss_create_invocation("ktutil", "5.0", (char *) NULL, &ktutil_cmds, &retval); if (retval) { ss_perror(sci_idx, retval, gettext("creating invocation")); exit(1); } retval = ss_listen(sci_idx); ktutil_free_kt_list(kcontext, ktlist); exit(0); } void ktutil_clear_list(argc, argv) int argc; char *argv[]; { krb5_error_code retval; if (argc != 1) { fprintf(stderr, gettext("%s: invalid arguments\n"), argv[0]); return; } retval = ktutil_free_kt_list(kcontext, ktlist); if (retval) com_err(argv[0], retval, gettext("while freeing ktlist")); ktlist = NULL; } void ktutil_read_v5(argc, argv) int argc; char *argv[]; { krb5_error_code retval; if (argc != 2) { fprintf(stderr, gettext("%s: must specify keytab to read\n"), argv[0]); return; } retval = ktutil_read_keytab(kcontext, argv[1], &ktlist); if (retval) com_err(argv[0], retval, gettext("while reading keytab \"%s\""), argv[1]); } void ktutil_read_v4(argc, argv) int argc; char *argv[]; { #ifdef KRB5_KRB4_COMPAT krb5_error_code retval; if (argc != 2) { fprintf(stderr, gettext("%s: must specify the srvtab to read\n"), argv[0]); return; } retval = ktutil_read_srvtab(kcontext, argv[1], &ktlist); if (retval) com_err(argv[0], retval, gettext("while reading srvtab \"%s\""), argv[1]); #else fprintf(stderr, gettext("%s: krb4 support not configured\n"), argv[0]); #endif } void ktutil_write_v5(argc, argv) int argc; char *argv[]; { krb5_error_code retval; if (argc != 2) { fprintf(stderr, gettext("%s: must specify keytab to write\n"), argv[0]); return; } retval = ktutil_write_keytab(kcontext, ktlist, argv[1]); if (retval) com_err(argv[0], retval, gettext("while writing keytab \"%s\""), argv[1]); } void ktutil_write_v4(argc, argv) int argc; char *argv[]; { #ifdef KRB5_KRB4_COMPAT krb5_error_code retval; if (argc != 2) { fprintf(stderr, gettext("%s: must specify srvtab to write\n"), argv[0]); return; } retval = ktutil_write_srvtab(kcontext, ktlist, argv[1]); if (retval) com_err(argv[0], retval, gettext("while writing srvtab \"%s\""), argv[1]); #else fprintf(stderr, gettext("%s: krb4 support not configured\n"), argv[0]); #endif } void ktutil_add_entry(argc, argv) int argc; char *argv[]; { krb5_error_code retval; char *princ = NULL; char *enctype = NULL; krb5_kvno kvno = 0; int use_pass = 0, use_key = 0, i; for (i = 1; i < argc; i++) { if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-p", 2)) { princ = argv[++i]; continue; } if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) { kvno = (krb5_kvno) atoi(argv[++i]); continue; } if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-e", 2)) { enctype = argv[++i]; continue; } if ((strlen(argv[i]) == 9) && !strncmp(argv[i], "-password", 9)) { use_pass++; continue; } if ((strlen(argv[i]) == 4) && !strncmp(argv[i], "-key", 4)) { use_key++; continue; } } if (argc != 8 || !(princ && kvno && enctype) || (use_pass+use_key != 1)) { fprintf(stderr, "%s: %s (-key | -password) -p principal " "-k kvno -e enctype\n", gettext("usage"), argv[0]); return; } retval = ktutil_add(kcontext, &ktlist, princ, kvno, enctype, use_pass); if (retval) com_err(argv[0], retval, gettext("while adding new entry")); } void ktutil_delete_entry(argc, argv) int argc; char *argv[]; { krb5_error_code retval; if (argc != 2) { fprintf(stderr, gettext("%s: must specify entry to delete\n"), argv[0]); return; } retval = ktutil_delete(kcontext, &ktlist, atoi(argv[1])); if (retval) com_err(argv[0], retval, gettext("while deleting entry %d"), atoi(argv[1])); } void ktutil_list(argc, argv) int argc; char *argv[]; { krb5_error_code retval; krb5_kt_list lp; int show_time = 0, show_keys = 0, show_enctype = 0; int i, j; char *pname; for (i = 1; i < argc; i++) { if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-t", 2)) { show_time++; continue; } if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-k", 2)) { show_keys++; continue; } if ((strlen(argv[i]) == 2) && !strncmp(argv[i], "-e", 2)) { show_enctype++; continue; } fprintf(stderr, "%s: %s [-t] [-k] [-e]\n", gettext("usage"), argv[0]); return; } if (show_time) { printf(gettext("slot KVNO Timestamp Principal\n")); printf("---- ---- ----------------- ---------------------------------------------------\n"); } else { printf(gettext("slot KVNO Principal\n")); printf("---- ---- ---------------------------------------------------------------------\n"); } for (i = 1, lp = ktlist; lp; i++, lp = lp->next) { retval = krb5_unparse_name(kcontext, lp->entry->principal, &pname); if (retval) { com_err(argv[0], retval, gettext("while unparsing principal name")); return; } printf("%4d %4d ", i, lp->entry->vno); if (show_time) { char fmtbuf[18]; char fill; time_t tstamp; (void) localtime(&tstamp); lp->entry->timestamp = tstamp; fill = ' '; if (!krb5_timestamp_to_sfstring((krb5_timestamp)lp->entry-> timestamp, fmtbuf, sizeof(fmtbuf), &fill)) printf("%s ", fmtbuf); } printf("%40s", pname); if (show_enctype) { static char buf[256]; if ((retval = krb5_enctype_to_string( lp->entry->key.enctype, buf, 256))) { if (retval == EINVAL) snprintf(buf, sizeof(buf), gettext("unsupported encryption type %d"), lp->entry->key.enctype); else { com_err(argv[0], retval, gettext("While converting " "enctype to string")); return; } } printf(" (%s) ", buf); } if (show_keys) { printf(" (0x"); for (j = 0; j < lp->entry->key.length; j++) printf("%02x", lp->entry->key.contents[j]); printf(")"); } printf("\n"); krb5_xfree(pname); } } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * kadmin/ktutil/ktutil.h * * Copyright 1995 by the Massachusetts Institute of Technology. * All Rights Reserved. * * Export of this software from the United States of America may * require a specific license from the United States Government. * It is the responsibility of any person or organization contemplating * export to obtain such a license before exporting. * * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and * distribute this software and its documentation for any purpose and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of M.I.T. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * */ typedef struct _krb5_kt_list { struct _krb5_kt_list *next; krb5_keytab_entry *entry; } *krb5_kt_list; krb5_error_code ktutil_free_kt_list (krb5_context, krb5_kt_list); krb5_error_code ktutil_delete (krb5_context, krb5_kt_list *, int); krb5_error_code ktutil_add (krb5_context, krb5_kt_list *, char *, krb5_kvno, char *, int); krb5_error_code ktutil_read_keytab (krb5_context, char *, krb5_kt_list *); krb5_error_code ktutil_write_keytab (krb5_context, krb5_kt_list, char *); #ifdef KRB5_KRB4_COMPAT krb5_error_code ktutil_read_srvtab (krb5_context, char *, krb5_kt_list *); krb5_error_code ktutil_write_srvtab (krb5_context, krb5_kt_list, char *); #endif void ktutil_add_entry (int, char *[]); void ktutil_clear_list (int, char *[]); void ktutil_read_v5 (int, char *[]); void ktutil_read_v4 (int, char *[]); void ktutil_write_v5 (int, char *[]); void ktutil_write_v4 (int, char *[]); void ktutil_delete_entry (int, char *[]); void ktutil_list (int, char *[]); /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* ktutil_ct.c - automatically generated from ktutil_ct.ct */ /* Above no longer appears to be true */ #include #include #include "k5-int.h" /* * I18n hack. We sill define gettext(s) to be s here. That way the info_strings * will be extracted to the .po file. */ #define gettext(s) s #ifndef __STDC__ #define const #endif static char const * const ssu00001[] = { "clear_list", "clear", (char const *)0 }; extern void ktutil_clear_list __SS_PROTO; static char const * const ssu00002[] = { "read_kt", "rkt", (char const *)0 }; extern void ktutil_read_v5 __SS_PROTO; static char const * const ssu00003[] = { "read_st", "rst", (char const *)0 }; extern void ktutil_read_v4 __SS_PROTO; static char const * const ssu00004[] = { "write_kt", "wkt", (char const *)0 }; extern void ktutil_write_v5 __SS_PROTO; static char const * const ssu00005[] = { "write_st", "wst", (char const *)0 }; extern void ktutil_write_v4 __SS_PROTO; static char const * const ssu00006[] = { "add_entry", "addent", (char const *)0 }; extern void ktutil_add_entry __SS_PROTO; static char const * const ssu00007[] = { "delete_entry", "delent", (char const *)0 }; extern void ktutil_delete_entry __SS_PROTO; static char const * const ssu00008[] = { "list", "l", (char const *)0 }; extern void ktutil_list __SS_PROTO; static char const * const ssu00009[] = { "list_requests", "lr", "?", (char const *)0 }; extern void ss_list_requests __SS_PROTO; static char const * const ssu00010[] = { "quit", "exit", "q", (char const *)0 }; extern void ss_quit __SS_PROTO; static ss_request_entry ssu00011[] = { { ssu00001, ktutil_clear_list, gettext("Clear the current keylist."), 0 }, { ssu00002, ktutil_read_v5, gettext("Read a krb5 keytab into the current keylist."), 0 }, { ssu00003, ktutil_read_v4, gettext("Read a krb4 srvtab into the current keylist."), 0 }, { ssu00004, ktutil_write_v5, gettext("Write the current keylist to a krb5 keytab."), 0 }, { ssu00005, ktutil_write_v4, gettext("Write the current keylist to a krb4 srvtab."), 0 }, { ssu00006, ktutil_add_entry, gettext("Add an entry to the current keylist."), 0 }, { ssu00007, ktutil_delete_entry, gettext("Delete an entry from the current keylist."), 0 }, { ssu00008, ktutil_list, gettext("List the current keylist."), 0 }, { ssu00009, ss_list_requests, gettext("List available requests."), 0 }, { ssu00010, ss_quit, gettext("Exit program."), 0 }, { 0, 0, 0, 0 } }; ss_request_table ktutil_cmds = { 2, ssu00011 }; #undef gettext /* * This routine is responsible for localizing all the displayable * messages in the table. This was necessary since ktutil will be * invoking library calls that need to be able to display the messages * in the correct text domain (which only ktutil knows). * * This function assumes that the US version of the messages are * pre-loaded in the table and will be used should gettext not be * successful. This routine does NOT free the replaced strings as * its expected they may be in the heap (as above) and not malloc'ed. * If the caller malloc'ed the strings, they should retain pointers * and free them if not matching the contents of the table. */ krb5_error_code ktutil_initialize_cmds_table(ss_request_table *ktutil_cmds) { char *localized_text; ss_request_entry *ss_cmd; krb5_error_code retval = 0; if (ktutil_cmds) { for (ss_cmd = ktutil_cmds->requests; ss_cmd->info_string && *(ss_cmd->info_string) != '\0'; ++ss_cmd) { localized_text = gettext(ss_cmd->info_string); if ((strcmp(localized_text, ss_cmd->info_string)) != 0) { ss_cmd->info_string = strdup(localized_text); } } } else retval = EINVAL; return (retval); } /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * kadmin/ktutil/ktutil_funcs.c * *(C) Copyright 1995, 1996 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. Furthermore if you modify this software you must label * your software as modified software and not distribute it in such a * fashion that it might be confused with the original M.I.T. software. * 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. * * Utility functions for ktutil. */ #include "k5-int.h" #include "ktutil.h" #ifdef KRB5_KRB4_COMPAT #include "kerberosIV/krb.h" #include #endif #include #include #include /* * Free a kt_list */ krb5_error_code ktutil_free_kt_list(context, list) krb5_context context; krb5_kt_list list; { krb5_kt_list lp, prev; krb5_error_code retval = 0; for (lp = list; lp;) { retval = krb5_kt_free_entry(context, lp->entry); free((char *)lp->entry); if (retval) break; prev = lp; lp = lp->next; free((char *)prev); } return retval; } /* * Delete a numbered entry in a kt_list. Takes a pointer to a kt_list * in case head gets deleted. */ krb5_error_code ktutil_delete(context, list, idx) krb5_context context; krb5_kt_list *list; int idx; { krb5_kt_list lp, prev; int i; for (lp = *list, i = 1; lp; prev = lp, lp = lp->next, i++) { if (i == idx) { if (i == 1) *list = lp->next; else prev->next = lp->next; lp->next = NULL; return ktutil_free_kt_list(context, lp); } } return EINVAL; } /* * Create a new keytab entry and add it to the keytab list. * Based on the value of use_pass, either prompt the user for a * password or key. If the keytab list is NULL, allocate a new * one first. */ krb5_error_code ktutil_add(context, list, princ_str, kvno, enctype_str, use_pass) krb5_context context; krb5_kt_list *list; char *princ_str; krb5_kvno kvno; char *enctype_str; int use_pass; { krb5_keytab_entry *entry; krb5_kt_list lp = NULL, prev = NULL; krb5_principal princ; krb5_enctype enctype; krb5_timestamp now; krb5_error_code retval; krb5_data password, salt; krb5_keyblock key; char buf[BUFSIZ]; char promptstr[1024]; char *cp; int i, tmp; unsigned int pwsize = BUFSIZ; retval = krb5_parse_name(context, princ_str, &princ); if (retval) return retval; /* now unparse in order to get the default realm appended to princ_str, if no realm was specified */ retval = krb5_unparse_name(context, princ, &princ_str); if (retval) return retval; retval = krb5_string_to_enctype(enctype_str, &enctype); if (retval) return KRB5_BAD_ENCTYPE; retval = krb5_timeofday(context, &now); if (retval) return retval; if (*list) { /* point lp at the tail of the list */ for (lp = *list; lp->next; lp = lp->next); } entry = (krb5_keytab_entry *) malloc(sizeof(krb5_keytab_entry)); if (!entry) { return ENOMEM; } memset((char *) entry, 0, sizeof(*entry)); if (!lp) { /* if list is empty, start one */ lp = (krb5_kt_list) malloc(sizeof(*lp)); if (!lp) { return ENOMEM; } } else { lp->next = (krb5_kt_list) malloc(sizeof(*lp)); if (!lp->next) { return ENOMEM; } prev = lp; lp = lp->next; } lp->next = NULL; lp->entry = entry; if (use_pass) { password.length = pwsize; password.data = (char *) malloc(pwsize); if (!password.data) { retval = ENOMEM; goto cleanup; } (void) snprintf(promptstr, sizeof(promptstr), gettext("Password for %.1000s"), princ_str); retval = krb5_read_password(context, promptstr, NULL, password.data, &password.length); if (retval) goto cleanup; retval = krb5_principal2salt(context, princ, &salt); if (retval) goto cleanup; retval = krb5_c_string_to_key(context, enctype, &password, &salt, &key); if (retval) goto cleanup; memset(password.data, 0, password.length); password.length = 0; memcpy(&lp->entry->key, &key, sizeof(krb5_keyblock)); } else { printf(gettext("Key for %s (hex): "), princ_str); fgets(buf, BUFSIZ, stdin); /* * We need to get rid of the trailing '\n' from fgets. * If we have an even number of hex digits (as we should), * write a '\0' over the '\n'. If for some reason we have * an odd number of hex digits, force an even number of hex * digits by writing a '0' into the last position (the string * will still be null-terminated). */ buf[strlen(buf) - 1] = strlen(buf) % 2 ? '\0' : '0'; if (strlen(buf) == 0) { fprintf(stderr, "addent: %s", gettext("Error reading key.\n")); retval = 0; goto cleanup; } lp->entry->key.enctype = enctype; lp->entry->key.contents = (krb5_octet *) malloc((strlen(buf) + 1) / 2); if (!lp->entry->key.contents) { retval = ENOMEM; goto cleanup; } i = 0; for (cp = buf; *cp; cp += 2) { if (!isxdigit((int) cp[0]) || !isxdigit((int) cp[1])) { fprintf(stderr, "addent: %s", gettext("Illegal character in key.\n")); retval = 0; goto cleanup; } sscanf(cp, "%02x", &tmp); lp->entry->key.contents[i++] = (krb5_octet) tmp; } lp->entry->key.length = i; } lp->entry->principal = princ; lp->entry->vno = kvno; lp->entry->timestamp = now; if (!*list) *list = lp; return 0; cleanup: if (prev) prev->next = NULL; ktutil_free_kt_list(context, lp); return retval; } /* * Read in a keytab and append it to list. If list starts as NULL, * allocate a new one if necessary. */ krb5_error_code ktutil_read_keytab(context, name, list) krb5_context context; char *name; krb5_kt_list *list; { krb5_kt_list lp = NULL, tail = NULL, back = NULL; krb5_keytab kt; krb5_keytab_entry *entry; krb5_kt_cursor cursor; krb5_error_code retval = 0; if (*list) { /* point lp at the tail of the list */ for (lp = *list; lp->next; lp = lp->next); back = lp; } retval = krb5_kt_resolve(context, name, &kt); if (retval) return retval; retval = krb5_kt_start_seq_get(context, kt, &cursor); if (retval) goto close_kt; for (;;) { entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); if (!entry) { retval = ENOMEM; break; } memset((char *)entry, 0, sizeof (*entry)); retval = krb5_kt_next_entry(context, kt, entry, &cursor); if (retval) break; if (!lp) { /* if list is empty, start one */ lp = (krb5_kt_list)malloc(sizeof (*lp)); if (!lp) { retval = ENOMEM; break; } } else { lp->next = (krb5_kt_list)malloc(sizeof (*lp)); if (!lp->next) { retval = ENOMEM; break; } lp = lp->next; } if (!tail) tail = lp; lp->next = NULL; lp->entry = entry; } if (entry) free((char *)entry); if (retval) { if (retval == KRB5_KT_END) retval = 0; else { ktutil_free_kt_list(context, tail); tail = NULL; if (back) back->next = NULL; } } if (!*list) *list = tail; krb5_kt_end_seq_get(context, kt, &cursor); close_kt: krb5_kt_close(context, kt); return retval; } /* * Takes a kt_list and writes it to the named keytab. */ krb5_error_code ktutil_write_keytab(context, list, name) krb5_context context; krb5_kt_list list; char *name; { krb5_kt_list lp; krb5_keytab kt; char ktname[MAXPATHLEN+sizeof("WRFILE:")+1]; krb5_error_code retval = 0; strcpy(ktname, "WRFILE:"); if (strlen (name) >= MAXPATHLEN) return ENAMETOOLONG; strncat (ktname, name, MAXPATHLEN); retval = krb5_kt_resolve(context, ktname, &kt); if (retval) return retval; for (lp = list; lp; lp = lp->next) { retval = krb5_kt_add_entry(context, kt, lp->entry); if (retval) break; } krb5_kt_close(context, kt); return retval; } #ifdef KRB5_KRB4_COMPAT /* * getstr() takes a file pointer, a string and a count. It reads from * the file until either it has read "count" characters, or until it * reads a null byte. When finished, what has been read exists in the * given string "s". If "count" characters were actually read, the * last is changed to a null, so the returned string is always null- * terminated. getstr() returns the number of characters read, * including the null terminator. */ static int getstr(fp, s, n) FILE *fp; register char *s; int n; { register int count = n; while (fread(s, 1, 1, fp) > 0 && --count) if (*s++ == '\0') return (n - count); *s = '\0'; return (n - count); } /* * Read in a named krb4 srvtab and append to list. Allocate new list * if needed. */ krb5_error_code ktutil_read_srvtab(context, name, list) krb5_context context; char *name; krb5_kt_list *list; { krb5_kt_list lp = NULL, tail = NULL, back = NULL; krb5_keytab_entry *entry; krb5_error_code retval = 0; char sname[SNAME_SZ]; /* name of service */ char sinst[INST_SZ]; /* instance of service */ char srealm[REALM_SZ]; /* realm of service */ unsigned char kvno; /* key version number */ des_cblock key; FILE *fp; if (*list) { /* point lp at the tail of the list */ for (lp = *list; lp->next; lp = lp->next); back = lp; } fp = fopen(name, "r"); if (!fp) return EIO; for (;;) { entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry)); if (!entry) { retval = ENOMEM; break; } memset((char *)entry, 0, sizeof (*entry)); memset(sname, 0, sizeof (sname)); memset(sinst, 0, sizeof (sinst)); memset(srealm, 0, sizeof (srealm)); if (!(getstr(fp, sname, SNAME_SZ) > 0 && getstr(fp, sinst, INST_SZ) > 0 && getstr(fp, srealm, REALM_SZ) > 0 && fread(&kvno, 1, 1, fp) > 0 && fread((char *)key, sizeof (key), 1, fp) > 0)) break; entry->magic = KV5M_KEYTAB_ENTRY; entry->timestamp = 0; /* XXX */ entry->vno = kvno; retval = krb5_425_conv_principal(context, sname, sinst, srealm, &entry->principal); if (retval) break; entry->key.magic = KV5M_KEYBLOCK; entry->key.enctype = ENCTYPE_DES_CBC_CRC; entry->key.length = sizeof (key); entry->key.contents = (krb5_octet *)malloc(sizeof (key)); if (!entry->key.contents) { retval = ENOMEM; break; } memcpy((char *)entry->key.contents, (char *)key, sizeof (key)); if (!lp) { /* if list is empty, start one */ lp = (krb5_kt_list)malloc(sizeof (*lp)); if (!lp) { retval = ENOMEM; break; } } else { lp->next = (krb5_kt_list)malloc(sizeof (*lp)); if (!lp->next) { retval = ENOMEM; break; } lp = lp->next; } lp->next = NULL; lp->entry = entry; if (!tail) tail = lp; } if (entry) { if (entry->magic == KV5M_KEYTAB_ENTRY) krb5_kt_free_entry(context, entry); free((char *)entry); } if (retval) { ktutil_free_kt_list(context, tail); tail = NULL; if (back) back->next = NULL; } if (!*list) *list = tail; fclose(fp); return retval; } /* * Writes a kt_list out to a krb4 srvtab file. Note that it first * prunes the kt_list so that it won't contain any keys that are not * the most recent, and ignores keys that are not ENCTYPE_DES. */ krb5_error_code ktutil_write_srvtab(context, list, name) krb5_context context; krb5_kt_list list; char *name; { krb5_kt_list lp, lp1, prev, pruned = NULL; krb5_error_code retval = 0; FILE *fp; char sname[SNAME_SZ]; char sinst[INST_SZ]; char srealm[REALM_SZ]; /* First do heinous stuff to prune the list. */ for (lp = list; lp; lp = lp->next) { if ((lp->entry->key.enctype != ENCTYPE_DES_CBC_CRC) && (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD5) && (lp->entry->key.enctype != ENCTYPE_DES_CBC_MD4) && (lp->entry->key.enctype != ENCTYPE_DES_CBC_RAW)) continue; for (lp1 = pruned; lp1; prev = lp1, lp1 = lp1->next) { /* Hunt for the current principal in the pruned list */ if (krb5_principal_compare(context, lp->entry->principal, lp1->entry->principal)) break; } if (!lp1) { /* need to add entry to tail of pruned list */ if (!pruned) { pruned = (krb5_kt_list) malloc(sizeof (*pruned)); if (!pruned) return ENOMEM; memset((char *) pruned, 0, sizeof(*pruned)); lp1 = pruned; } else { prev->next = (krb5_kt_list) malloc(sizeof (*pruned)); if (!prev->next) { retval = ENOMEM; goto free_pruned; } memset((char *) prev->next, 0, sizeof(*pruned)); lp1 = prev->next; } lp1->entry = lp->entry; } else { /* This heuristic should be roughly the same as in the keytab-reading code in libkrb5. */ int offset = 0; if (lp1->entry->vno > 240 || lp->entry->vno > 240) { offset = 128; } #define M(X) (((X) + offset) % 256) if (M(lp1->entry->vno) < M(lp->entry->vno)) /* Check if lp->entry is newer kvno; if so, update */ lp1->entry = lp->entry; } } umask(0077); /*Changing umask for all of ktutil is OK * We don't ever write out anything that should use * default umask.*/ fp = fopen(name, "w"); if (!fp) { retval = EIO; goto free_pruned; } for (lp = pruned; lp; lp = lp->next) { unsigned char kvno; kvno = (unsigned char) lp->entry->vno; retval = krb5_524_conv_principal(context, lp->entry->principal, sname, sinst, srealm); if (retval) break; fwrite(sname, strlen(sname) + 1, 1, fp); fwrite(sinst, strlen(sinst) + 1, 1, fp); fwrite(srealm, strlen(srealm) + 1, 1, fp); fwrite((char *)&kvno, 1, 1, fp); fwrite((char *)lp->entry->key.contents, sizeof (des_cblock), 1, fp); } fclose(fp); free_pruned: /* * Loop over and free the pruned list; don't use free_kt_list * because that kills the entries. */ for (lp = pruned; lp;) { prev = lp; lp = lp->next; free((char *)prev); } return retval; } #endif /* KRB5_KRB4_COMPAT */ # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= kadmind MANIFEST= kadmin.xml OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.o \ ipropd_svc.o DERIVED_OBJS= iprop_xdr.o SRCS= $(OBJS:.o=.c) SRCS+= $(DERIVED_OBJS:.o=.c) # Definitions needed to rpcgen iprop-related files ISRC= iprop.h iprop_xdr.c KRB5IPROPDIR= $(SRC)/cmd/krb5/iprop CMD= grep -v "usr/src/cmd/krb5/iprop" > $@ CLOBBERFILES += $(TESTPROG) include ../../../Makefile.cmd include $(SRC)/lib/gss_mechs/mech_krb5/Makefile.mech_krb5 POFILE = $(PROG).po POFILES = generic.po ROOTMANIFESTDIR= $(ROOTSVCNETWORKSECURITY) DEFS = -DHAVE_LIBSOCKET=1 -DHAVE_LIBNSL=1 -DHAVE_COMPILE=1 -DHAVE_STEP=1 -DKRB5_KRB4_COMPAT CPPFLAGS += -I. -I$(SRC)/uts/common/gssapi/mechs/krb5/include \ -I$(SRC)/uts/common/gssapi \ -I$(SRC)/lib/krb5 \ -I$(SRC)/lib/krb5/kadm5 \ -I$(SRC)/lib/krb5/kadm5/srv \ -I$(SRC)/lib/gss_mechs/mech_krb5/include \ -I$(KRB5IPROPDIR) \ -I$(SRC)/uts/common/gssapi/include/ $(DEFS) CERRWARN += -Wno-implicit-function-declaration CERRWARN += -Wno-unused-variable CERRWARN += -Wno-parentheses CERRWARN += -Wno-unused-function # Hammerhead: Suppress xdr_longlong_t type mismatch warnings (iprop_xdr.c) CERRWARN += -Wno-incompatible-pointer-types # not linted SMATCH=off LDFLAGS += $(KRUNPATH) $(KERBRUNPATH) # Hammerhead: GNU ld needs rpath-link for transitive deps (libdyn, libkdb) via libkadm5srv LDFLAGS += -Wl,-rpath-link,$(ROOT)/usr/lib/krb5 LDLIBS += -lgss -L$(KRB5LIB) \ -lmech_krb5 -lkadm5srv -lkdb -lnsl -lresolv -lbsm -lpam -lsocket .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(DERIVED_OBJS) $(LINK.c) $(OBJS) $(DERIVED_OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) # Hammerhead: pre-generated (rpcgen + GNU cpp truncation bug) # iprop.h and iprop_xdr.c are now committed source files. # Explicitly state the dependancy on iprop.h $(OBJS): iprop.h $(KRB5LIBPROG): FILEMODE = 0500 install: $(KRB5LIBPROG) $(ROOTSVCMETHOD) $(ROOTMANIFEST) check: $(CHKMANIFEST) clean: $(RM) $(OBJS) $(DERIVED_OBJS) @# Hammerhead: do not delete pre-generated $(ISRC) include ../../../Makefile.targ $(POFILE): $(DERIVED_FILES) .WAIT $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ generic.po: FRC $(RM) messages.po $(XGETTEXT) $(XGETFLAGS) `$(GREP) -l gettext *.[ch]` $(SED) "/^domain/d" messages.po > $@ $(RM) messages.po FRC: /* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _IPROP_H_RPCGEN #define _IPROP_H_RPCGEN #include typedef struct { u_int utf8str_t_len; char *utf8str_t_val; } utf8str_t; typedef uint32_t kdb_sno_t; struct kdbe_time_t { uint32_t seconds; uint32_t useconds; }; typedef struct kdbe_time_t kdbe_time_t; struct kdbe_key_t { int32_t k_ver; int32_t k_kvno; struct { u_int k_enctype_len; int32_t *k_enctype_val; } k_enctype; struct { u_int k_contents_len; utf8str_t *k_contents_val; } k_contents; }; typedef struct kdbe_key_t kdbe_key_t; struct kdbe_data_t { int32_t k_magic; utf8str_t k_data; }; typedef struct kdbe_data_t kdbe_data_t; struct kdbe_princ_t { utf8str_t k_realm; struct { u_int k_components_len; kdbe_data_t *k_components_val; } k_components; int32_t k_nametype; }; typedef struct kdbe_princ_t kdbe_princ_t; struct kdbe_tl_t { int16_t tl_type; struct { u_int tl_data_len; char *tl_data_val; } tl_data; }; typedef struct kdbe_tl_t kdbe_tl_t; typedef struct { u_int kdbe_pw_hist_t_len; kdbe_key_t *kdbe_pw_hist_t_val; } kdbe_pw_hist_t; enum kdbe_attr_type_t { AT_ATTRFLAGS = 0, AT_MAX_LIFE = 1, AT_MAX_RENEW_LIFE = 2, AT_EXP = 3, AT_PW_EXP = 4, AT_LAST_SUCCESS = 5, AT_LAST_FAILED = 6, AT_FAIL_AUTH_COUNT = 7, AT_PRINC = 8, AT_KEYDATA = 9, AT_TL_DATA = 10, AT_LEN = 11, AT_MOD_PRINC = 12, AT_MOD_TIME = 13, AT_MOD_WHERE = 14, AT_PW_LAST_CHANGE = 15, AT_PW_POLICY = 16, AT_PW_POLICY_SWITCH = 17, AT_PW_HIST_KVNO = 18, AT_PW_HIST = 19 }; typedef enum kdbe_attr_type_t kdbe_attr_type_t; struct kdbe_val_t { kdbe_attr_type_t av_type; union { uint32_t av_attrflags; uint32_t av_max_life; uint32_t av_max_renew_life; uint32_t av_exp; uint32_t av_pw_exp; uint32_t av_last_success; uint32_t av_last_failed; uint32_t av_fail_auth_count; kdbe_princ_t av_princ; struct { u_int av_keydata_len; kdbe_key_t *av_keydata_val; } av_keydata; struct { u_int av_tldata_len; kdbe_tl_t *av_tldata_val; } av_tldata; int16_t av_len; uint32_t av_pw_last_change; kdbe_princ_t av_mod_princ; uint32_t av_mod_time; utf8str_t av_mod_where; utf8str_t av_pw_policy; bool_t av_pw_policy_switch; uint32_t av_pw_hist_kvno; struct { u_int av_pw_hist_len; kdbe_pw_hist_t *av_pw_hist_val; } av_pw_hist; struct { u_int av_extension_len; char *av_extension_val; } av_extension; } kdbe_val_t_u; }; typedef struct kdbe_val_t kdbe_val_t; typedef struct { u_int kdbe_t_len; kdbe_val_t *kdbe_t_val; } kdbe_t; struct kdb_incr_update_t { utf8str_t kdb_princ_name; kdb_sno_t kdb_entry_sno; kdbe_time_t kdb_time; kdbe_t kdb_update; bool_t kdb_deleted; bool_t kdb_commit; struct { u_int kdb_kdcs_seen_by_len; utf8str_t *kdb_kdcs_seen_by_val; } kdb_kdcs_seen_by; struct { u_int kdb_futures_len; char *kdb_futures_val; } kdb_futures; }; typedef struct kdb_incr_update_t kdb_incr_update_t; typedef struct { u_int kdb_ulog_t_len; kdb_incr_update_t *kdb_ulog_t_val; } kdb_ulog_t; enum update_status_t { UPDATE_OK = 0, UPDATE_ERROR = 1, UPDATE_FULL_RESYNC_NEEDED = 2, UPDATE_BUSY = 3, UPDATE_NIL = 4, UPDATE_PERM_DENIED = 5 }; typedef enum update_status_t update_status_t; struct kdb_last_t { kdb_sno_t last_sno; kdbe_time_t last_time; }; typedef struct kdb_last_t kdb_last_t; struct kdb_incr_result_t { kdb_last_t lastentry; kdb_ulog_t updates; update_status_t ret; }; typedef struct kdb_incr_result_t kdb_incr_result_t; struct kdb_fullresync_result_t { kdb_last_t lastentry; update_status_t ret; }; typedef struct kdb_fullresync_result_t kdb_fullresync_result_t; #define KRB5_IPROP_PROG 100423 #define KRB5_IPROP_VERS 1 #define IPROP_NULL 0 extern void * iprop_null_1(); #define IPROP_GET_UPDATES 1 extern kdb_incr_result_t * iprop_get_updates_1(); #define IPROP_FULL_RESYNC 2 extern kdb_fullresync_result_t * iprop_full_resync_1(); extern int krb5_iprop_prog_1_freeresult(); /* the xdr functions */ extern bool_t xdr_utf8str_t(); extern bool_t xdr_kdb_sno_t(); extern bool_t xdr_kdbe_time_t(); extern bool_t xdr_kdbe_key_t(); extern bool_t xdr_kdbe_data_t(); extern bool_t xdr_kdbe_princ_t(); extern bool_t xdr_kdbe_tl_t(); extern bool_t xdr_kdbe_pw_hist_t(); extern bool_t xdr_kdbe_attr_type_t(); extern bool_t xdr_kdbe_val_t(); extern bool_t xdr_kdbe_t(); extern bool_t xdr_kdb_incr_update_t(); extern bool_t xdr_kdb_ulog_t(); extern bool_t xdr_update_status_t(); extern bool_t xdr_kdb_last_t(); extern bool_t xdr_kdb_incr_result_t(); extern bool_t xdr_kdb_fullresync_result_t(); #endif /* !_IPROP_H_RPCGEN */ /* * Please do not edit this file. * It was generated using rpcgen. */ #include "iprop.h" #ifndef _KERNEL #include #endif /* !_KERNEL */ #include "iprop.h" bool_t xdr_int16_t(xdrs, objp) XDR *xdrs; int16_t *objp; { rpc_inline_t *buf __unused; if (!xdr_short(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_uint16_t(xdrs, objp) XDR *xdrs; uint16_t *objp; { rpc_inline_t *buf __unused; if (!xdr_u_short(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_int32_t(xdrs, objp) XDR *xdrs; int32_t *objp; { rpc_inline_t *buf __unused; if (!xdr_int(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_uint32_t(xdrs, objp) XDR *xdrs; uint32_t *objp; { rpc_inline_t *buf __unused; if (!xdr_u_int(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_int64_t(xdrs, objp) XDR *xdrs; int64_t *objp; { rpc_inline_t *buf __unused; if (!xdr_longlong_t(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_uint64_t(xdrs, objp) XDR *xdrs; uint64_t *objp; { rpc_inline_t *buf __unused; if (!xdr_u_longlong_t(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_utf8str_t(xdrs, objp) XDR *xdrs; utf8str_t *objp; { rpc_inline_t *buf __unused; if (!xdr_bytes(xdrs, (char **)&objp->utf8str_t_val, (u_int *) &objp->utf8str_t_len, ~0)) return (FALSE); return (TRUE); } bool_t xdr_kdb_sno_t(xdrs, objp) XDR *xdrs; kdb_sno_t *objp; { rpc_inline_t *buf __unused; if (!xdr_uint32_t(xdrs, objp)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_time_t(xdrs, objp) XDR *xdrs; kdbe_time_t *objp; { rpc_inline_t *buf __unused; if (!xdr_uint32_t(xdrs, &objp->seconds)) return (FALSE); if (!xdr_uint32_t(xdrs, &objp->useconds)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_key_t(xdrs, objp) XDR *xdrs; kdbe_key_t *objp; { rpc_inline_t *buf __unused; if (!xdr_int32_t(xdrs, &objp->k_ver)) return (FALSE); if (!xdr_int32_t(xdrs, &objp->k_kvno)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->k_enctype.k_enctype_val, (u_int *) &objp->k_enctype.k_enctype_len, ~0, sizeof (int32_t), (xdrproc_t)xdr_int32_t)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->k_contents.k_contents_val, (u_int *) &objp->k_contents.k_contents_len, ~0, sizeof (utf8str_t), (xdrproc_t)xdr_utf8str_t)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_data_t(xdrs, objp) XDR *xdrs; kdbe_data_t *objp; { rpc_inline_t *buf __unused; if (!xdr_int32_t(xdrs, &objp->k_magic)) return (FALSE); if (!xdr_utf8str_t(xdrs, &objp->k_data)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_princ_t(xdrs, objp) XDR *xdrs; kdbe_princ_t *objp; { rpc_inline_t *buf __unused; if (!xdr_utf8str_t(xdrs, &objp->k_realm)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->k_components.k_components_val, (u_int *) &objp->k_components.k_components_len, ~0, sizeof (kdbe_data_t), (xdrproc_t)xdr_kdbe_data_t)) return (FALSE); if (!xdr_int32_t(xdrs, &objp->k_nametype)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_tl_t(xdrs, objp) XDR *xdrs; kdbe_tl_t *objp; { rpc_inline_t *buf __unused; if (!xdr_int16_t(xdrs, &objp->tl_type)) return (FALSE); if (!xdr_bytes(xdrs, (char **)&objp->tl_data.tl_data_val, (u_int *) &objp->tl_data.tl_data_len, ~0)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_pw_hist_t(xdrs, objp) XDR *xdrs; kdbe_pw_hist_t *objp; { rpc_inline_t *buf __unused; if (!xdr_array(xdrs, (char **)&objp->kdbe_pw_hist_t_val, (u_int *) &objp->kdbe_pw_hist_t_len, ~0, sizeof (kdbe_key_t), (xdrproc_t)xdr_kdbe_key_t)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_attr_type_t(xdrs, objp) XDR *xdrs; kdbe_attr_type_t *objp; { rpc_inline_t *buf __unused; if (!xdr_enum(xdrs, (enum_t *)objp)) return (FALSE); return (TRUE); } bool_t xdr_kdbe_val_t(xdrs, objp) XDR *xdrs; kdbe_val_t *objp; { rpc_inline_t *buf __unused; if (!xdr_kdbe_attr_type_t(xdrs, &objp->av_type)) return (FALSE); switch (objp->av_type) { case AT_ATTRFLAGS: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_attrflags)) return (FALSE); break; case AT_MAX_LIFE: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_max_life)) return (FALSE); break; case AT_MAX_RENEW_LIFE: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_max_renew_life)) return (FALSE); break; case AT_EXP: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_exp)) return (FALSE); break; case AT_PW_EXP: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_pw_exp)) return (FALSE); break; case AT_LAST_SUCCESS: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_last_success)) return (FALSE); break; case AT_LAST_FAILED: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_last_failed)) return (FALSE); break; case AT_FAIL_AUTH_COUNT: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_fail_auth_count)) return (FALSE); break; case AT_PRINC: if (!xdr_kdbe_princ_t(xdrs, &objp->kdbe_val_t_u.av_princ)) return (FALSE); break; case AT_KEYDATA: if (!xdr_array(xdrs, (char **)&objp->kdbe_val_t_u.av_keydata.av_keydata_val, (u_int *) &objp->kdbe_val_t_u.av_keydata.av_keydata_len, ~0, sizeof (kdbe_key_t), (xdrproc_t)xdr_kdbe_key_t)) return (FALSE); break; case AT_TL_DATA: if (!xdr_array(xdrs, (char **)&objp->kdbe_val_t_u.av_tldata.av_tldata_val, (u_int *) &objp->kdbe_val_t_u.av_tldata.av_tldata_len, ~0, sizeof (kdbe_tl_t), (xdrproc_t)xdr_kdbe_tl_t)) return (FALSE); break; case AT_LEN: if (!xdr_int16_t(xdrs, &objp->kdbe_val_t_u.av_len)) return (FALSE); break; case AT_PW_LAST_CHANGE: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_pw_last_change)) return (FALSE); break; case AT_MOD_PRINC: if (!xdr_kdbe_princ_t(xdrs, &objp->kdbe_val_t_u.av_mod_princ)) return (FALSE); break; case AT_MOD_TIME: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_mod_time)) return (FALSE); break; case AT_MOD_WHERE: if (!xdr_utf8str_t(xdrs, &objp->kdbe_val_t_u.av_mod_where)) return (FALSE); break; case AT_PW_POLICY: if (!xdr_utf8str_t(xdrs, &objp->kdbe_val_t_u.av_pw_policy)) return (FALSE); break; case AT_PW_POLICY_SWITCH: if (!xdr_bool(xdrs, &objp->kdbe_val_t_u.av_pw_policy_switch)) return (FALSE); break; case AT_PW_HIST_KVNO: if (!xdr_uint32_t(xdrs, &objp->kdbe_val_t_u.av_pw_hist_kvno)) return (FALSE); break; case AT_PW_HIST: if (!xdr_array(xdrs, (char **)&objp->kdbe_val_t_u.av_pw_hist.av_pw_hist_val, (u_int *) &objp->kdbe_val_t_u.av_pw_hist.av_pw_hist_len, ~0, sizeof (kdbe_pw_hist_t), (xdrproc_t)xdr_kdbe_pw_hist_t)) return (FALSE); break; default: if (!xdr_bytes(xdrs, (char **)&objp->kdbe_val_t_u.av_extension.av_extension_val, (u_int *) &objp->kdbe_val_t_u.av_extension.av_extension_len, ~0)) return (FALSE); break; } return (TRUE); } bool_t xdr_kdbe_t(xdrs, objp) XDR *xdrs; kdbe_t *objp; { rpc_inline_t *buf __unused; if (!xdr_array(xdrs, (char **)&objp->kdbe_t_val, (u_int *) &objp->kdbe_t_len, ~0, sizeof (kdbe_val_t), (xdrproc_t)xdr_kdbe_val_t)) return (FALSE); return (TRUE); } bool_t xdr_kdb_incr_update_t(xdrs, objp) XDR *xdrs; kdb_incr_update_t *objp; { rpc_inline_t *buf __unused; if (!xdr_utf8str_t(xdrs, &objp->kdb_princ_name)) return (FALSE); if (!xdr_kdb_sno_t(xdrs, &objp->kdb_entry_sno)) return (FALSE); if (!xdr_kdbe_time_t(xdrs, &objp->kdb_time)) return (FALSE); if (!xdr_kdbe_t(xdrs, &objp->kdb_update)) return (FALSE); if (!xdr_bool(xdrs, &objp->kdb_deleted)) return (FALSE); if (!xdr_bool(xdrs, &objp->kdb_commit)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->kdb_kdcs_seen_by.kdb_kdcs_seen_by_val, (u_int *) &objp->kdb_kdcs_seen_by.kdb_kdcs_seen_by_len, ~0, sizeof (utf8str_t), (xdrproc_t)xdr_utf8str_t)) return (FALSE); if (!xdr_bytes(xdrs, (char **)&objp->kdb_futures.kdb_futures_val, (u_int *) &objp->kdb_futures.kdb_futures_len, ~0)) return (FALSE); return (TRUE); } bool_t xdr_kdb_ulog_t(xdrs, objp) XDR *xdrs; kdb_ulog_t *objp; { rpc_inline_t *buf __unused; if (!xdr_array(xdrs, (char **)&objp->kdb_ulog_t_val, (u_int *) &objp->kdb_ulog_t_len, ~0, sizeof (kdb_incr_update_t), (xdrproc_t)xdr_kdb_incr_update_t)) return (FALSE); return (TRUE); } bool_t xdr_update_status_t(xdrs, objp) XDR *xdrs; update_status_t *objp; { rpc_inline_t *buf __unused; if (!xdr_enum(xdrs, (enum_t *)objp)) return (FALSE); return (TRUE); } bool_t xdr_kdb_last_t(xdrs, objp) XDR *xdrs; kdb_last_t *objp; { rpc_inline_t *buf __unused; if (!xdr_kdb_sno_t(xdrs, &objp->last_sno)) return (FALSE); if (!xdr_kdbe_time_t(xdrs, &objp->last_time)) return (FALSE); return (TRUE); } bool_t xdr_kdb_incr_result_t(xdrs, objp) XDR *xdrs; kdb_incr_result_t *objp; { rpc_inline_t *buf __unused; if (!xdr_kdb_last_t(xdrs, &objp->lastentry)) return (FALSE); if (!xdr_kdb_ulog_t(xdrs, &objp->updates)) return (FALSE); if (!xdr_update_status_t(xdrs, &objp->ret)) return (FALSE); return (TRUE); } bool_t xdr_kdb_fullresync_result_t(xdrs, objp) XDR *xdrs; kdb_fullresync_result_t *objp; { rpc_inline_t *buf __unused; if (!xdr_kdb_last_t(xdrs, &objp->lastentry)) return (FALSE); if (!xdr_update_status_t(xdrs, &objp->ret)) return (FALSE); return (TRUE); } /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include /* getenv, exit */ #include #include #include #include #include #include /* rlimit */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "misc.h" extern int setup_gss_names(struct svc_req *, char **, char **); extern gss_name_t get_clnt_name(struct svc_req *); extern char *client_addr(struct svc_req *, char *); extern void *global_server_handle; extern int nofork; extern short l_port; static char abuf[33]; static char *reply_ok_str = "UPDATE_OK"; static char *reply_err_str = "UPDATE_ERROR"; static char *reply_fr_str = "UPDATE_FULL_RESYNC_NEEDED"; static char *reply_busy_str = "UPDATE_BUSY"; static char *reply_nil_str = "UPDATE_NIL"; static char *reply_perm_str = "UPDATE_PERM_DENIED"; static char *reply_unknown_str = ""; #define LOG_UNAUTH gettext("Unauthorized request: %s, %s, " \ "client=%s, service=%s, addr=%s") #define LOG_DONE gettext("Request: %s, %s, %s, client=%s, " \ "service=%s, addr=%s") #define KDB5_UTIL_DUMP_STR "/usr/sbin/kdb5_util dump -i " #ifdef DPRINT #undef DPRINT #endif #define DPRINT(i) if (nofork) printf i #ifdef POSIX_SIGNALS static struct sigaction s_action; #endif /* POSIX_SIGNALS */ static void debprret(char *w, update_status_t ret, kdb_sno_t sno) { switch (ret) { case UPDATE_OK: printf("%s: end (OK, sno=%u)\n", w, sno); break; case UPDATE_ERROR: printf("%s: end (ERROR)\n", w); break; case UPDATE_FULL_RESYNC_NEEDED: printf("%s: end (FR NEEDED)\n", w); break; case UPDATE_BUSY: printf("%s: end (BUSY)\n", w); break; case UPDATE_NIL: printf("%s: end (NIL)\n", w); break; case UPDATE_PERM_DENIED: printf("%s: end (PERM)\n", w); break; default: printf("%s: end (UNKNOWN return code (%d))\n", w, ret); } } static char * replystr(update_status_t ret) { switch (ret) { case UPDATE_OK: return (reply_ok_str); case UPDATE_ERROR: return (reply_err_str); case UPDATE_FULL_RESYNC_NEEDED: return (reply_fr_str); case UPDATE_BUSY: return (reply_busy_str); case UPDATE_NIL: return (reply_nil_str); case UPDATE_PERM_DENIED: return (reply_perm_str); default: return (reply_unknown_str); } } kdb_incr_result_t * iprop_get_updates_1(kdb_last_t *arg, struct svc_req *rqstp) { static kdb_incr_result_t ret; char *whoami = "iprop_get_updates_1"; int kret; kadm5_server_handle_t handle = global_server_handle; char *client_name = NULL, *service_name = NULL; gss_name_t name = NULL; OM_uint32 min_stat; char obuf[256] = {0}; /* default return code */ ret.ret = UPDATE_ERROR; DPRINT(("%s: start, last_sno=%u\n", whoami, (ulong_t)arg->last_sno)); if (!handle) { krb5_klog_syslog(LOG_ERR, gettext("%s: server handle is NULL"), whoami); goto out; } if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { krb5_klog_syslog(LOG_ERR, gettext("%s: setup_gss_names failed"), whoami); goto out; } DPRINT(("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n", whoami, client_name, service_name)); if (!(name = get_clnt_name(rqstp))) { krb5_klog_syslog(LOG_ERR, gettext("%s: Couldn't obtain client's name"), whoami); goto out; } if (!kadm5int_acl_check(handle->context, name, ACL_IPROP, NULL, NULL)) { ret.ret = UPDATE_PERM_DENIED; audit_kadmind_unauth(rqstp->rq_xprt, l_port, whoami, "", client_name); krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, whoami, "", client_name, service_name, client_addr(rqstp, abuf)); goto out; } kret = ulog_get_entries(handle->context, *arg, &ret); if (ret.ret == UPDATE_OK) { (void) snprintf(obuf, sizeof (obuf), gettext("%s; Incoming SerialNo=%u; Outgoing SerialNo=%u"), replystr(ret.ret), (ulong_t)arg->last_sno, (ulong_t)ret.lastentry.last_sno); } else { (void) snprintf(obuf, sizeof (obuf), gettext("%s; Incoming SerialNo=%u; Outgoing SerialNo=N/A"), replystr(ret.ret), (ulong_t)arg->last_sno); } audit_kadmind_auth(rqstp->rq_xprt, l_port, whoami, obuf, client_name, kret); krb5_klog_syslog(LOG_NOTICE, LOG_DONE, whoami, obuf, ((kret == 0) ? "success" : error_message(kret)), client_name, service_name, client_addr(rqstp, abuf)); out: if (nofork) debprret(whoami, ret.ret, ret.lastentry.last_sno); if (client_name) free(client_name); if (service_name) free(service_name); if (name) gss_release_name(&min_stat, &name); return (&ret); } /* * Given a client princ (foo/fqdn@R), copy (in arg cl) the fqdn substring. * Return arg cl str ptr on success, else NULL. */ static char * getclhoststr(char *clprinc, char *cl, int len) { char *s; if (s = strchr(clprinc, '/')) { if (!++s || strlcpy(cl, s, len) >= len) { return (NULL); } if (s = strchr(cl, '@')) { *s = '\0'; return (cl); /* success */ } } return (NULL); } kdb_fullresync_result_t * iprop_full_resync_1( /* LINTED */ void *argp, struct svc_req *rqstp) { static kdb_fullresync_result_t ret; char tmpf[MAX_FILENAME] = {0}; char ubuf[MAX_FILENAME + sizeof (KDB5_UTIL_DUMP_STR)] = {0}; char clhost[MAXHOSTNAMELEN] = {0}; int pret, fret; kadm5_server_handle_t handle = global_server_handle; OM_uint32 min_stat; gss_name_t name = NULL; char *client_name = NULL, *service_name = NULL; char *whoami = "iprop_full_resync_1"; /* default return code */ ret.ret = UPDATE_ERROR; if (!handle) { krb5_klog_syslog(LOG_ERR, gettext("%s: server handle is NULL"), whoami); goto out; } DPRINT(("%s: start\n", whoami)); if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { krb5_klog_syslog(LOG_ERR, gettext("%s: setup_gss_names failed"), whoami); goto out; } DPRINT(("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n", whoami, client_name, service_name)); if (!(name = get_clnt_name(rqstp))) { krb5_klog_syslog(LOG_ERR, gettext("%s: Couldn't obtain client's name"), whoami); goto out; } if (!kadm5int_acl_check(handle->context, name, ACL_IPROP, NULL, NULL)) { ret.ret = UPDATE_PERM_DENIED; audit_kadmind_unauth(rqstp->rq_xprt, l_port, whoami, "", client_name); krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, whoami, "", client_name, service_name, client_addr(rqstp, abuf)); goto out; } if (!getclhoststr(client_name, clhost, sizeof (clhost))) { krb5_klog_syslog(LOG_ERR, gettext("%s: getclhoststr failed"), whoami); goto out; } /* * construct db dump file name; kprop style name + clnt fqdn */ (void) strcpy(tmpf, "/var/krb5/slave_datatrans_"); if (strlcat(tmpf, clhost, sizeof (tmpf)) >= sizeof (tmpf)) { krb5_klog_syslog(LOG_ERR, gettext("%s: db dump file name too long; max length=%d"), whoami, (sizeof (tmpf) - 1)); goto out; } /* * note the -i; modified version of kdb5_util dump format * to include sno (serial number) */ if (strlcpy(ubuf, KDB5_UTIL_DUMP_STR, sizeof (ubuf)) >= sizeof (ubuf)) { goto out; } if (strlcat(ubuf, tmpf, sizeof (ubuf)) >= sizeof (ubuf)) { krb5_klog_syslog(LOG_ERR, gettext("%s: kdb5 util dump string too long; max length=%d"), whoami, (sizeof (ubuf) - 1)); goto out; } /* * Fork to dump the db and xfer it to the slave. * (the fork allows parent to return quickly and the child * acts like a callback to the slave). */ fret = fork(); DPRINT(("%s: fork=%d (%d)\n", whoami, fret, getpid())); switch (fret) { case -1: /* error */ if (nofork) { perror(whoami); } krb5_klog_syslog(LOG_ERR, gettext("%s: fork failed: %s"), whoami, error_message(errno)); goto out; case 0: /* child */ DPRINT(("%s: run `%s' ...\n", whoami, ubuf)); #ifdef POSIX_SIGNALS (void) sigemptyset(&s_action.sa_mask); s_action.sa_handler = SIG_DFL; (void) sigaction(SIGCHLD, &s_action, (struct sigaction *) NULL); #else (void) signal(SIGCHLD, SIG_DFL); #endif /* POSIX_SIGNALS */ /* run kdb5_util(8) dump for IProp */ pret = pclose(popen(ubuf, "w")); DPRINT(("%s: pclose=%d\n", whoami, pret)); if (pret == -1) { if (nofork) { perror(whoami); } krb5_klog_syslog(LOG_ERR, gettext("%s: pclose(popen) failed: %s"), whoami, error_message(errno)); goto out; } DPRINT(("%s: exec `kprop -f %s %s' ...\n", whoami, tmpf, clhost)); pret = execl("/usr/lib/krb5/kprop", "kprop", "-f", tmpf, clhost, NULL); if (pret == -1) { if (nofork) { perror(whoami); } krb5_klog_syslog(LOG_ERR, gettext("%s: exec failed: %s"), whoami, error_message(errno)); goto out; } /* NOTREACHED */ break; default: /* parent */ ret.ret = UPDATE_OK; /* not used by slave (sno is retrieved from kdb5_util dump) */ ret.lastentry.last_sno = 0; ret.lastentry.last_time.seconds = 0; ret.lastentry.last_time.useconds = 0; audit_kadmind_auth(rqstp->rq_xprt, l_port, whoami, "", client_name, 0); krb5_klog_syslog(LOG_NOTICE, LOG_DONE, whoami, "", "success", client_name, service_name, client_addr(rqstp, abuf)); goto out; } out: if (nofork) debprret(whoami, ret.ret, 0); if (client_name) free(client_name); if (service_name) free(service_name); if (name) gss_release_name(&min_stat, &name); return (&ret); } void krb5_iprop_prog_1( struct svc_req *rqstp, register SVCXPRT *transp) { union { kdb_last_t iprop_get_updates_1_arg; } argument; char *result; bool_t (*_xdr_argument)(), (*_xdr_result)(); char *(*local)(); char *whoami = "krb5_iprop_prog_1"; switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply(transp, xdr_void, (char *)NULL); return; case IPROP_GET_UPDATES: _xdr_argument = xdr_kdb_last_t; _xdr_result = xdr_kdb_incr_result_t; local = (char *(*)()) iprop_get_updates_1; break; case IPROP_FULL_RESYNC: _xdr_argument = xdr_void; _xdr_result = xdr_kdb_fullresync_result_t; local = (char *(*)()) iprop_full_resync_1; break; default: krb5_klog_syslog(LOG_ERR, gettext("RPC unknown request: %d (%s)"), rqstp->rq_proc, whoami); svcerr_noproc(transp); return; } (void) memset((char *)&argument, 0, sizeof (argument)); if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) { krb5_klog_syslog(LOG_ERR, gettext("RPC svc_getargs failed (%s)"), whoami); svcerr_decode(transp); return; } result = (*local)(&argument, rqstp); if (_xdr_result && result != NULL && !svc_sendreply(transp, _xdr_result, result)) { krb5_klog_syslog(LOG_ERR, gettext("RPC svc_sendreply failed (%s)"), whoami); svcerr_systemerr(transp); } if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) { krb5_klog_syslog(LOG_ERR, gettext("RPC svc_freeargs failed (%s)"), whoami); exit(1); } if (rqstp->rq_proc == IPROP_GET_UPDATES) { /* LINTED */ kdb_incr_result_t *r = (kdb_incr_result_t *)result; if (r->ret == UPDATE_OK) { ulog_free_entries(r->updates.kdb_ulog_t_val, r->updates.kdb_ulog_t_len); r->updates.kdb_ulog_t_val = NULL; r->updates.kdb_ulog_t_len = 0; } } } /* * Get the host base service name for the kiprop principal. Returns * KADM5_OK on success. Caller must free the storage allocated for * host_service_name. */ kadm5_ret_t kiprop_get_adm_host_srv_name( krb5_context context, const char *realm, char **host_service_name) { kadm5_ret_t ret; char *name; char *host; if (ret = kadm5_get_master(context, realm, &host)) return (ret); name = malloc(strlen(KIPROP_SVC_NAME)+ strlen(host) + 2); if (name == NULL) { free(host); return (ENOMEM); } (void) sprintf(name, "%s@%s", KIPROP_SVC_NAME, host); free(host); *host_service_name = name; return (KADM5_OK); } /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. * */ #include #include #include /* SUNWresync 121 XXX */ #include /* for gss_nt_krb5_name */ #include #ifdef HAVE_MEMORY_H #include #endif #include #include #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif #include "misc.h" #include "kadm5/server_internal.h" extern void *global_server_handle; void log_badauth(OM_uint32 major, OM_uint32 minor, struct sockaddr_in *addr, char *data); /* * Function: kadm_1 * * Purpose: RPC proccessing procedure. * originally generated from rpcgen * * Arguments: * rqstp (input) rpc request structure * transp (input) rpc transport structure * (input/output) * * * Requires: * Effects: * Modifies: */ void kadm_1(rqstp, transp) struct svc_req *rqstp; register SVCXPRT *transp; { union { cprinc_arg create_principal_2_arg; dprinc_arg delete_principal_2_arg; mprinc_arg modify_principal_2_arg; rprinc_arg rename_principal_2_arg; gprinc_arg get_principal_2_arg; chpass_arg chpass_principal_2_arg; chrand_arg chrand_principal_2_arg; cpol_arg create_policy_2_arg; dpol_arg delete_policy_2_arg; mpol_arg modify_policy_2_arg; gpol_arg get_policy_2_arg; setkey_arg setkey_principal_2_arg; setv4key_arg setv4key_principal_2_arg; cprinc3_arg create_principal3_2_arg; chpass3_arg chpass_principal3_2_arg; chrand3_arg chrand_principal3_2_arg; setkey3_arg setkey_principal3_2_arg; } argument; char *result; bool_t (*xdr_argument)(), (*xdr_result)(); char *(*local)(); if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS) { krb5_klog_syslog(LOG_ERR, gettext("Authentication attempt failed: invalid " "RPC authentication flavor %d"), rqstp->rq_cred.oa_flavor); svcerr_weakauth(transp); return; } switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply(transp, xdr_void, (char *)NULL); return; case CREATE_PRINCIPAL: xdr_argument = xdr_cprinc_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) create_principal_2_svc; break; case DELETE_PRINCIPAL: xdr_argument = xdr_dprinc_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) delete_principal_2_svc; break; case MODIFY_PRINCIPAL: xdr_argument = xdr_mprinc_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) modify_principal_2_svc; break; case RENAME_PRINCIPAL: xdr_argument = xdr_rprinc_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) rename_principal_2_svc; break; case GET_PRINCIPAL: xdr_argument = xdr_gprinc_arg; xdr_result = xdr_gprinc_ret; local = (char *(*)()) get_principal_2_svc; break; case GET_PRINCS: xdr_argument = xdr_gprincs_arg; xdr_result = xdr_gprincs_ret; local = (char *(*)()) get_princs_2_svc; break; case CHPASS_PRINCIPAL: xdr_argument = xdr_chpass_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) chpass_principal_2_svc; break; #ifdef SUNWOFF case SETV4KEY_PRINCIPAL: xdr_argument = xdr_setv4key_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) setv4key_principal_2_svc; break; #endif case SETKEY_PRINCIPAL: xdr_argument = xdr_setkey_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) setkey_principal_2_svc; break; case CHRAND_PRINCIPAL: xdr_argument = xdr_chrand_arg; xdr_result = xdr_chrand_ret; local = (char *(*)()) chrand_principal_2_svc; break; case CREATE_POLICY: xdr_argument = xdr_cpol_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) create_policy_2_svc; break; case DELETE_POLICY: xdr_argument = xdr_dpol_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) delete_policy_2_svc; break; case MODIFY_POLICY: xdr_argument = xdr_mpol_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) modify_policy_2_svc; break; case GET_POLICY: xdr_argument = xdr_gpol_arg; xdr_result = xdr_gpol_ret; local = (char *(*)()) get_policy_2_svc; break; case GET_POLS: xdr_argument = xdr_gpols_arg; xdr_result = xdr_gpols_ret; local = (char *(*)()) get_pols_2_svc; break; case GET_PRIVS: xdr_argument = xdr_u_int; xdr_result = xdr_getprivs_ret; local = (char *(*)()) get_privs_2_svc; break; case INIT: xdr_argument = xdr_u_int; xdr_result = xdr_generic_ret; local = (char *(*)()) init_2_svc; break; case CREATE_PRINCIPAL3: xdr_argument = xdr_cprinc3_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) create_principal3_2_svc; break; case CHPASS_PRINCIPAL3: xdr_argument = xdr_chpass3_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) chpass_principal3_2_svc; break; case CHRAND_PRINCIPAL3: xdr_argument = xdr_chrand3_arg; xdr_result = xdr_chrand_ret; local = (char *(*)()) chrand_principal3_2_svc; break; case SETKEY_PRINCIPAL3: xdr_argument = xdr_setkey3_arg; xdr_result = xdr_generic_ret; local = (char *(*)()) setkey_principal3_2_svc; break; default: krb5_klog_syslog(LOG_ERR, gettext("Invalid KADM5 procedure number: %d"), rqstp->rq_proc); svcerr_noproc(transp); return; } memset((char *)&argument, 0, sizeof(argument)); if (!svc_getargs(transp, xdr_argument, (char *) &argument)) { svcerr_decode(transp); return; } result = (*local)(&argument, rqstp); if (result != NULL && !svc_sendreply(transp, xdr_result, (char *) result)) { krb5_klog_syslog(LOG_ERR, gettext("WARNING! Unable to send function results, " "continuing.")); svcerr_systemerr(transp); } if (!svc_freeargs(transp, xdr_argument, (char *) &argument)) { krb5_klog_syslog(LOG_ERR, gettext("WARNING! Unable to free arguments, " "continuing.")); } return; } /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * */ #include #include #include #include #include "misc.h" /* * Function: chpass_principal_wrapper_3 * * Purpose: wrapper to kadm5_chpass_principal that checks to see if * pw_min_life has been reached. if not it returns an error. * otherwise it calls kadm5_chpass_principal * * Arguments: * principal (input) krb5_principals whose password we are * changing * keepold (input) whether to preserve old keys * n_ks_tuple (input) the number of key-salt tuples in ks_tuple * ks_tuple (input) array of tuples indicating the caller's * requested enctypes/salttypes * password (input) password we are going to change to. * 0 on success error code on failure. * * Requires: * kadm5_init to have been run. * * Effects: * calls kadm5_chpass_principal which changes the kdb and the * the admin db. * */ kadm5_ret_t chpass_principal_wrapper_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password) { kadm5_ret_t ret; /* Solaris Kerberos */ ret = kadm5_check_min_life(server_handle, principal, NULL, 0); if (ret) return ret; return kadm5_chpass_principal_3(server_handle, principal, keepold, n_ks_tuple, ks_tuple, password); } /* * Function: randkey_principal_wrapper_3 * * Purpose: wrapper to kadm5_randkey_principal which checks the * password's min. life. * * Arguments: * principal (input) krb5_principal whose password we are * changing * keepold (input) whether to preserve old keys * n_ks_tuple (input) the number of key-salt tuples in ks_tuple * ks_tuple (input) array of tuples indicating the caller's * requested enctypes/salttypes * key (output) new random key * 0, error code on error. * * Requires: * kadm5_init needs to be run * * Effects: * calls kadm5_randkey_principal * */ kadm5_ret_t randkey_principal_wrapper_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **keys, int *n_keys) { kadm5_ret_t ret; /* Solaris Kerberos */ ret = kadm5_check_min_life(server_handle, principal, NULL, 0); if (ret) return ret; return kadm5_randkey_principal_3(server_handle, principal, keepold, n_ks_tuple, ks_tuple, keys, n_keys); } kadm5_ret_t schpw_util_wrapper(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len) { kadm5_ret_t ret; /* Solaris Kerberos */ ret = kadm5_check_min_life(server_handle, princ, msg_ret, msg_len); if (ret) return ret; return kadm5_chpass_principal_util(server_handle, princ, new_pw, ret_pw, msg_ret, msg_len); } kadm5_ret_t randkey_principal_wrapper(void *server_handle, krb5_principal princ, krb5_keyblock ** keys, int *n_keys) { kadm5_ret_t ret; /* Solaris Kerberos */ ret = kadm5_check_min_life(server_handle, princ, NULL, 0); if (ret) return ret; return kadm5_randkey_principal(server_handle, princ, keys, n_keys); } /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ #ifndef _MISC_H #define _MISC_H #ifdef __cplusplus extern "C" { #endif /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1994 OpenVision Technologies, Inc., All Rights Reserved * */ kadm5_ret_t chpass_principal_wrapper_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, char *password); kadm5_ret_t randkey_principal_wrapper_3(void *server_handle, krb5_principal principal, krb5_boolean keepold, int n_ks_tuple, krb5_key_salt_tuple *ks_tuple, krb5_keyblock **keys, int *n_keys); kadm5_ret_t schpw_util_wrapper(void *server_handle, krb5_principal princ, char *new_pw, char **ret_pw, char *msg_ret, unsigned int msg_len); kadm5_ret_t kadm5_get_principal_v1(void *server_handle, krb5_principal principal, kadm5_principal_ent_t_v1 *ent); kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name, kadm5_policy_ent_t *ent); krb5_error_code process_chpw_request(krb5_context context, void *server_handle, char *realm, int s, krb5_keytab keytab, struct sockaddr_in *sockin, krb5_data *req, krb5_data *rep); #ifdef SVC_GETARGS void kadm_1(struct svc_req *, SVCXPRT *); #endif void trunc_name(size_t *len, char **dots); #ifdef __cplusplus } #endif #endif /* !_MISC_H */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * */ /* * Copyright (C) 1998 by the FundsXpress, INC. * * 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 FundsXpress. not be used in advertising or publicity pertaining * to distribution of the software without specific, written prior * permission. FundsXpress makes no representations about the suitability of * this software for any purpose. It is provided "as is" without express * or implied warranty. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * SUNWresync121 XXX * Beware future resyncers, this file is much diff from MIT (1.0...) */ #include #include #include #include #include #ifdef _AIX #include #endif #include #include #include #include #include /* inet_ntoa */ #include #include "gssapiP_krb5.h" /* for kg_get_context */ #include #include #include #include #include #include "kdb_kt.h" /* for krb5_ktkdb_set_context */ #include #include #include #include #include #include #include #include #include #include "misc.h" #ifdef PURIFY #include "purify.h" int signal_pure_report = 0; int signal_pure_clear = 0; void request_pure_report(int); void request_pure_clear(int); #endif /* PURIFY */ #ifndef FD_SETSIZE #define FD_SETSIZE 256 #endif #ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif #if defined(NEED_DAEMON_PROTO) extern int daemon(int, int); #endif static int signal_request_exit = 0; kadm5_config_params chgpw_params; void setup_signal_handlers(iprop_role iproprole); void request_exit(int); void sig_pipe(int); void kadm_svc_run(void); #ifdef POSIX_SIGNALS static struct sigaction s_action; #endif /* POSIX_SIGNALS */ #define TIMEOUT 15 typedef struct _auth_gssapi_name { char *name; gss_OID type; } auth_gssapi_name; gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL; void *global_server_handle; /* * This is a kludge, but the server needs these constants to be * compatible with old clients. They are defined in , * but only if USE_KADM5_API_VERSION == 1. */ #define OVSEC_KADM_ADMIN_SERVICE_P "ovsec_adm@admin" #define OVSEC_KADM_CHANGEPW_SERVICE_P "ovsec_adm@changepw" extern void krb5_iprop_prog_1(); extern kadm5_ret_t kiprop_get_adm_host_srv_name( krb5_context, const char *, char **); static int schpw; in_port_t l_port = 0; /* global local port num, for BSM audits */ int nofork = 0; /* global; don't fork (debug mode) */ /* * Function: usage * * Purpose: print out the server usage message * * Arguments: * Requires: * Effects: * Modifies: */ static void usage() { fprintf(stderr, gettext("Usage: kadmind [-x db_args]* [-r realm] [-m] [-d] " "[-p port-number]\n")); exit(1); } /* * Function: display_status * * Purpose: displays GSS-API messages * * Arguments: * * msg a string to be displayed with the message * maj_stat the GSS-API major status code * min_stat the GSS-API minor status code * * Effects: * * The GSS-API messages associated with maj_stat and min_stat are * displayed on stderr, each preceeded by "GSS-API error : " and * followed by a newline. */ static void display_status_1(char *, OM_uint32, int); static void display_status(msg, maj_stat, min_stat) char *msg; OM_uint32 maj_stat; OM_uint32 min_stat; { display_status_1(msg, maj_stat, GSS_C_GSS_CODE); display_status_1(msg, min_stat, GSS_C_MECH_CODE); } static void display_status_1(m, code, type) char *m; OM_uint32 code; int type; { OM_uint32 min_stat; gss_buffer_desc msg; OM_uint32 msg_ctx; msg_ctx = 0; while (1) { (void) gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, &msg_ctx, &msg); fprintf(stderr, "GSS-API error %s: %s\n", m, (char *)msg.value); (void) gss_release_buffer(&min_stat, &msg); if (!msg_ctx) break; } } /* * Solaris Kerberos: the following prototypes are needed because these are * private interfaces that do not have prototypes in any .h */ extern struct hostent *res_getipnodebyaddr(const void *, size_t, int, int *); extern void res_freehostent(struct hostent *); static void freedomnames(char **npp) { char **tpp; if (npp) { tpp = npp; while (*tpp++) { free(*(tpp-1)); } free(npp); } } /* * Construct a list of uniq FQDNs of all the net interfaces (except * krb5.conf master dups) and return it in arg 'dnames'. * * On successful return (0), caller must call freedomnames() * to free memory. */ static int getdomnames(krb5_context ctx, char *realm, char ***dnames) { krb5_address **addresses = NULL; krb5_address *a = NULL; struct hostent *hp = NULL; int ret, i, result=0, error; char **npp = NULL, **tpp=NULL; int dup=0, n = 0; char *cfhost = NULL; /* krb5 conf file master hostname */ if (ret = kadm5_get_master(ctx, realm, &cfhost)) { return (ret); } ret = krb5_os_localaddr(ctx, &addresses); if (ret != 0) { if (nofork) (void) fprintf(stderr, "kadmind: get localaddrs failed: %s", error_message(ret)); result = ret; goto err; } for (i=0; addresses[i]; i++) { a = addresses[i]; hp = res_getipnodebyaddr(a->contents, a->length, a->addrtype == ADDRTYPE_INET ? AF_INET : AF_INET6, &error); if (hp != NULL) { /* skip master host in krb5.conf */ if (strcasecmp(cfhost, hp->h_name) == 0) { res_freehostent(hp); hp = NULL; continue; } dup = 0; tpp = npp; /* skip if hostname already exists in list */ while (tpp && *tpp++) { if (strcasecmp(*(tpp-1), hp->h_name) == 0) { dup++; break; } } if (dup) { res_freehostent(hp); hp = NULL; continue; } npp = realloc(npp, sizeof(char *) * (n + 2)); if (!npp) { result = ENOMEM; goto err; } npp[n] = strdup(hp->h_name); if (!npp[n]) { result = ENOMEM; goto err; } npp[n+1] = NULL; n++; res_freehostent(hp); hp = NULL; result = 0; } } #ifdef DEBUG printf("getdomnames: n=%d, i=%d, npp=%p\n", n, i, npp); tpp = npp; while (tpp && *tpp++) { printf("tpp=%s\n", *(tpp-1)); } #endif goto out; err: if (npp) { freedomnames(npp); npp = NULL; } if (hp) { res_freehostent(hp); hp = NULL; } out: if (cfhost) { free (cfhost); cfhost = NULL; } if (addresses) { krb5_free_addresses(ctx, addresses); addresses = NULL; } if (result == 0) *dnames = npp; return (result); } /* * Set the rpcsec_gss svc names for all net interfaces. */ static void set_svc_domnames(char *svcname, char **dnames, u_int program, u_int version) { bool_t ret; char **tpp = dnames; if (!tpp) return; while (*tpp++) { /* MAX_NAME_LEN from rpc/rpcsec_gss.h */ char name[MAXHOSTNAMELEN+MAX_NAME_LEN+2] = {0}; (void) snprintf(name, sizeof(name), "%s@%s", svcname, *(tpp-1)); ret = rpc_gss_set_svc_name(name, "kerberos_v5", 0, program, version); if (nofork && ret) (void) fprintf(stderr, "rpc_gss_set_svc_name success: %s\n", name); } } /* XXX yuck. the signal handlers need this */ static krb5_context context; static krb5_context hctx; int main(int argc, char *argv[]) { register SVCXPRT *transp; extern char *optarg; extern int optind, opterr; int ret, rlen, oldnames = 0; OM_uint32 OMret, major_status, minor_status; char *whoami; FILE *acl_file; gss_buffer_desc in_buf; struct servent *srv; struct sockaddr_in addr; struct sockaddr_in *sin; int s; auth_gssapi_name names[6]; gss_buffer_desc gssbuf; gss_OID nt_krb5_name_oid; int optchar; struct netconfig *nconf; void *handlep; int fd; struct t_info tinfo; struct t_bind tbindstr, *tres; struct t_optmgmt req, resp; struct opthdr *opt; char reqbuf[128]; struct rlimit rl; char *kiprop_name = NULL; /* IProp svc name */ kdb_log_context *log_ctx; kadm5_server_handle_t handle; krb5_context ctx; kadm5_config_params params; char **db_args = NULL; int db_args_size = 0; const char *errmsg; char **dnames = NULL; int retdn; int iprop_supported; /* Solaris Kerberos: Stores additional error messages */ char *emsg = NULL; /* Solaris Kerberos: Indicates whether loalhost is master or not */ krb5_boolean is_master; /* Solaris Kerberos: Used for checking acl file */ gss_name_t name; /* This is OID value the Krb5_Name NameType */ gssbuf.value = "{1 2 840 113554 1 2 2 1}"; gssbuf.length = strlen(gssbuf.value); major_status = gss_str_to_oid(&minor_status, &gssbuf, &nt_krb5_name_oid); if (major_status != GSS_S_COMPLETE) { fprintf(stderr, gettext("Couldn't create KRB5 Name NameType OID\n")); display_status("str_to_oid", major_status, minor_status); exit(1); } names[0].name = names[1].name = names[2].name = names[3].name = NULL; names[4].name = names[5].name =NULL; names[0].type = names[1].type = names[2].type = names[3].type = (gss_OID) nt_krb5_name_oid; names[4].type = names[5].type = (gss_OID) nt_krb5_name_oid; #ifdef PURIFY purify_start_batch(); #endif /* PURIFY */ whoami = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]); (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); nofork = 0; memset((char *) ¶ms, 0, sizeof(params)); while ((optchar = getopt(argc, argv, "r:mdp:x:")) != EOF) { switch (optchar) { case 'r': if (!optarg) usage(); params.realm = optarg; params.mask |= KADM5_CONFIG_REALM; break; case 'm': params.mkey_from_kbd = 1; params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; break; case 'd': nofork = 1; break; case 'p': if (!optarg) usage(); params.kadmind_port = atoi(optarg); params.mask |= KADM5_CONFIG_KADMIND_PORT; break; case 'x': if (!optarg) usage(); db_args_size++; { char **temp = realloc( db_args, sizeof(char*) * (db_args_size+1)); /* one for NULL */ if( temp == NULL ) { fprintf(stderr, gettext("%s: cannot initialize. Not enough memory\n"), whoami); exit(1); } db_args = temp; } db_args[db_args_size-1] = optarg; db_args[db_args_size] = NULL; break; case '?': default: usage(); } } if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { rl.rlim_cur = rl.rlim_max = MAX(rl.rlim_max, FD_SETSIZE); (void) setrlimit(RLIMIT_NOFILE, &rl); (void) enable_extended_FILE_stdio(-1, -1); } if ((ret = kadm5_init_krb5_context(&context))) { fprintf(stderr, gettext("%s: %s while initializing context, aborting\n"), whoami, error_message(ret)); exit(1); } krb5_klog_init(context, "admin_server", whoami, 1); /* Solaris Kerberos */ if((ret = kadm5_init2("kadmind", NULL, NULL, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, db_args, &global_server_handle, &emsg)) != KADM5_OK) { krb5_klog_syslog(LOG_ERR, gettext("%s while initializing, aborting"), (emsg ? emsg : error_message(ret))); fprintf(stderr, gettext("%s: %s while initializing, aborting\n"), whoami, (emsg ? emsg : error_message(ret))); if (emsg) free(emsg); krb5_klog_close(context); exit(1); } if( db_args ) { free(db_args), db_args=NULL; } if ((ret = kadm5_get_config_params(context, 1, ¶ms, ¶ms))) { const char *e_txt = krb5_get_error_message (context, ret); /* Solaris Kerberos: Remove double "whoami" */ krb5_klog_syslog(LOG_ERR, gettext("%s while initializing, aborting"), e_txt); fprintf(stderr, gettext("%s: %s while initializing, aborting\n"), whoami, e_txt); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE) if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { /* Solaris Kerberos: Keep error messages consistent */ krb5_klog_syslog(LOG_ERR, gettext("Missing required configuration values (%lx)" "while initializing, aborting"), (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); fprintf(stderr, gettext("%s: Missing required configuration values " "(%lx) while initializing, aborting\n"), whoami, (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); krb5_klog_close(context); kadm5_destroy(global_server_handle); exit(1); } /* * When using the Horowitz/IETF protocol for * password changing, the default port is 464 * (officially recognized by IANA) * * DEFAULT_KPASSWD_PORT -> 464 */ chgpw_params.kpasswd_port = DEFAULT_KPASSWD_PORT; chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PORT; chgpw_params.kpasswd_protocol = KRB5_CHGPWD_CHANGEPW_V2; chgpw_params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL; if (ret = kadm5_get_config_params(context, 1, &chgpw_params, &chgpw_params)) { /* Solaris Kerberos: Remove double "whoami" */ krb5_klog_syslog(LOG_ERR, gettext("%s while initializing," " aborting"), error_message(ret)); fprintf(stderr, gettext("%s: %s while initializing, aborting\n"), whoami, error_message(ret)); krb5_klog_close(context); exit(1); } /* * We now setup the socket and bind() to port 464, so that * kadmind can now listen to and process change-pwd requests * from non-Solaris Kerberos V5 clients such as Microsoft, * MIT, AIX, HP etc */ if ((schpw = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { const char *e_txt = krb5_get_error_message (context, ret); krb5_klog_syslog(LOG_ERR, gettext( "Cannot create simple " "chpw socket: %s"), e_txt); fprintf(stderr, gettext("Cannot create simple chpw socket: %s"), e_txt); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } /* Solaris Kerberos: Ensure that kadmind is only run on a master kdc */ if (ret = kadm5_is_master(context, params.realm, &is_master)){ krb5_klog_syslog(LOG_ERR, gettext("Failed to determine whether host is master " "KDC for realm %s: %s"), params.realm, error_message(ret)); fprintf(stderr, gettext("%s: Failed to determine whether host is master " "KDC for realm %s: %s\n"), whoami, params.realm, error_message(ret)); krb5_klog_close(context); exit(1); } if (is_master == FALSE) { char *master = NULL; kadm5_get_master(context, params.realm, &master); krb5_klog_syslog(LOG_ERR, gettext("%s can only be run on the master KDC, %s, for " "realm %s"), whoami, master ? master : "unknown", params.realm); fprintf(stderr, gettext("%s: %s can only be run on the master KDC, %s, for " "realm %s\n"), whoami, whoami, master ? master: "unknown", params.realm); krb5_klog_close(context); exit(1); } memset((char *) &addr, 0, sizeof (struct sockaddr_in)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; l_port = addr.sin_port = htons(params.kadmind_port); sin = &addr; if ((handlep = setnetconfig()) == (void *) NULL) { (void) krb5_klog_syslog(LOG_ERR, gettext("cannot get any transport information")); krb5_klog_close(context); exit(1); } while (nconf = getnetconfig(handlep)) { if ((nconf->nc_semantics == NC_TPI_COTS_ORD) && (strcmp(nconf->nc_protofmly, NC_INET) == 0) && (strcmp(nconf->nc_proto, NC_TCP) == 0)) break; } if (nconf == (struct netconfig *) NULL) { (void) endnetconfig(handlep); krb5_klog_close(context); exit(1); } fd = t_open(nconf->nc_device, O_RDWR, &tinfo); if (fd == -1) { krb5_klog_syslog(LOG_ERR, gettext("unable to open connection for ADMIN server")); krb5_klog_close(context); exit(1); } /* LINTED */ opt = (struct opthdr *) reqbuf; opt->level = SOL_SOCKET; opt->name = SO_REUSEADDR; opt->len = sizeof (int); /* * The option value is "1". This will allow the server to restart * whilst the previous process is cleaning up after itself in a * FIN_WAIT_2 or TIME_WAIT state. If another process is started * outside of smf(7) then bind will fail anyway, which is what we want. */ reqbuf[sizeof (struct opthdr)] = 1; req.flags = T_NEGOTIATE; req.opt.len = sizeof (struct opthdr) + opt->len; req.opt.buf = (char *) opt; resp.flags = 0; resp.opt.buf = reqbuf; resp.opt.maxlen = sizeof (reqbuf); if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) { t_error("t_optmgmt"); exit(1); } /* Transform addr to netbuf */ tres = (struct t_bind *) t_alloc(fd, T_BIND, T_ADDR); if (tres == NULL) { (void) t_close(fd); (void) krb5_klog_syslog(LOG_ERR, gettext("cannot allocate netbuf")); krb5_klog_close(context); exit(1); } tbindstr.qlen = 8; tbindstr.addr.buf = (char *) sin; tbindstr.addr.len = tbindstr.addr.maxlen = __rpc_get_a_size(tinfo.addr); sin = (struct sockaddr_in *) tbindstr.addr.buf; /* SUNWresync121 XXX (void) memset(&addr, 0, sizeof(addr)); */ if (t_bind(fd, &tbindstr, tres) < 0) { int oerrno = errno; const char *e_txt = krb5_get_error_message (context, errno); fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami); fprintf(stderr, gettext("bind: %s\n"), e_txt); errno = oerrno; krb5_klog_syslog(LOG_ERR, gettext("Cannot bind socket: %s"), e_txt); if(oerrno == EADDRINUSE) { char *w = strrchr(whoami, '/'); if (w) { w++; } else { w = whoami; } fprintf(stderr, gettext( "This probably means that another %s process is already\n" "running, or that another program is using the server port (number %d)\n" "after being assigned it by the RPC portmap daemon. If another\n" "%s is already running, you should kill it before\n" "restarting the server. If, on the other hand, another program is\n" "using the server port, you should kill it before running\n" "%s, and ensure that the conflict does not occur in the\n" "future by making sure that %s is started on reboot\n" "before portmap.\n"), w, ntohs(addr.sin_port), w, w, w); krb5_klog_syslog(LOG_ERR, gettext("Check for already-running %s or for " "another process using port %d"), w, htons(addr.sin_port)); } kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(chgpw_params.kpasswd_port); if (bind(schpw, (struct sockaddr *)&addr, sizeof(addr)) < 0) { char portbuf[32]; int oerrno = errno; const char *e_txt = krb5_get_error_message (context, errno); fprintf(stderr, gettext("%s: Cannot bind socket.\n"), whoami); fprintf(stderr, gettext("bind: %s\n"), e_txt); errno = oerrno; (void) snprintf(portbuf, sizeof (portbuf), "%d", ntohs(addr.sin_port)); krb5_klog_syslog(LOG_ERR, gettext("cannot bind simple chpw socket: %s"), e_txt); if(oerrno == EADDRINUSE) { char *w = strrchr(whoami, '/'); if (w) { w++; } else { w = whoami; } fprintf(stderr, gettext( "This probably means that another %s process is already\n" "running, or that another program is using the server port (number %d).\n" "If another %s is already running, you should kill it before\n" "restarting the server.\n"), w, ntohs(addr.sin_port), w); } krb5_klog_close(context); exit(1); } transp = svc_tli_create(fd, nconf, NULL, 0, 0); (void) t_free((char *) tres, T_BIND); (void) endnetconfig(handlep); if(transp == NULL) { fprintf(stderr, gettext("%s: Cannot create RPC service.\n"), whoami); krb5_klog_syslog(LOG_ERR, gettext("Cannot create RPC service: %m")); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) { fprintf(stderr, gettext("%s: Cannot register RPC service.\n"), whoami); krb5_klog_syslog(LOG_ERR, gettext("Cannot register RPC service, failing.")); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } /* Solaris Kerberos: * The only service principals which matter here are * -> names[0].name (kadmin/) * -> names[1].name (changepw/) * KADM5_ADMIN_SERVICE_P, KADM5_CHANGEPW_SERVICE_P, * OVSEC_KADM_ADMIN_SERVICE_P, OVSEC_KADM_CHANGEPW_SERVICE_P * are all legacy service princs and calls to rpc_gss_set_svc_name() * using these principals will always fail as they are not host * based principals. */ if (ret = kadm5_get_adm_host_srv_name(context, params.realm, &names[0].name)) { krb5_klog_syslog(LOG_ERR, gettext("Cannot get host based service name for admin " "principal in realm %s: %s"), params.realm, error_message(ret)); fprintf(stderr, gettext("%s: Cannot get host based service name for admin " "principal in realm %s: %s\n"), whoami, params.realm, error_message(ret)); krb5_klog_close(context); exit(1); } if (ret = kadm5_get_cpw_host_srv_name(context, params.realm, &names[1].name)) { krb5_klog_syslog(LOG_ERR, gettext("Cannot get host based service name for changepw " "principal in realm %s: %s"), params.realm, error_message(ret)); fprintf(stderr, gettext("%s: Cannot get host based service name for " "changepw principal in realm %s: %s\n"), whoami, params.realm, error_message(ret)); krb5_klog_close(context); exit(1); } names[2].name = KADM5_ADMIN_SERVICE_P; names[3].name = KADM5_CHANGEPW_SERVICE_P; names[4].name = OVSEC_KADM_ADMIN_SERVICE_P; names[5].name = OVSEC_KADM_CHANGEPW_SERVICE_P; if (names[0].name == NULL || names[1].name == NULL || names[2].name == NULL || names[3].name == NULL || names[4].name == NULL || names[5].name == NULL) { krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize GSS-API authentication, " "failing.")); fprintf(stderr, gettext("%s: Cannot initialize " "GSS-API authentication.\n"), whoami); krb5_klog_close(context); exit(1); } /* * Go through some contortions to point gssapi at a kdb keytab. * This prevents kadmind from needing to use an actual file-based * keytab. */ /* XXX extract kadm5's krb5_context */ hctx = ((kadm5_server_handle_t)global_server_handle)->context; /* Set ktkdb's internal krb5_context. */ ret = krb5_ktkdb_set_context(hctx); if (ret) { krb5_klog_syslog(LOG_ERR, "Can't set kdb keytab's internal context."); goto kterr; } /* Solaris Kerberos */ ret = krb5_db_set_mkey(hctx, &((kadm5_server_handle_t)global_server_handle)->master_keyblock); if (ret) { krb5_klog_syslog(LOG_ERR, "Can't set master key for kdb keytab."); goto kterr; } ret = krb5_kt_register(context, &krb5_kt_kdb_ops); if (ret) { krb5_klog_syslog(LOG_ERR, "Can't register kdb keytab."); goto kterr; } /* Tell gssapi about the kdb keytab. */ ret = krb5_gss_register_acceptor_identity("KDB:"); if (ret) { krb5_klog_syslog(LOG_ERR, "Can't register acceptor keytab."); goto kterr; } kterr: if (ret) { krb5_klog_syslog(LOG_ERR, "%s", krb5_get_error_message (context, ret)); fprintf(stderr, "%s: Can't set up keytab for RPC.\n", whoami); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } /* * Try to acquire creds for the old OV services as well as the * new names, but if that fails just fall back on the new names. */ if (rpc_gss_set_svc_name(names[5].name, "kerberos_v5", 0, KADM, KADMVERS) && rpc_gss_set_svc_name(names[4].name, "kerberos_v5", 0, KADM, KADMVERS)) oldnames++; if (rpc_gss_set_svc_name(names[3].name, "kerberos_v5", 0, KADM, KADMVERS)) oldnames++; if (rpc_gss_set_svc_name(names[2].name, "kerberos_v5", 0, KADM, KADMVERS)) oldnames++; /* If rpc_gss_set_svc_name() fails for either kadmin/ or * for changepw/ then try to determine if this is caused * by a missing keytab file or entry. If so, log it and continue. */ if (rpc_gss_set_svc_name(names[0].name, "kerberos_v5", 0, KADM, KADMVERS)) oldnames++; if (rpc_gss_set_svc_name(names[1].name, "kerberos_v5", 0, KADM, KADMVERS)) oldnames++; retdn = getdomnames(context, params.realm, &dnames); if (retdn == 0 && dnames) { /* * Multi-homed KDCs sometimes may need to set svc names * for multiple net interfaces so we set them for * all interfaces just in case. */ set_svc_domnames(KADM5_ADMIN_HOST_SERVICE, dnames, KADM, KADMVERS); set_svc_domnames(KADM5_CHANGEPW_HOST_SERVICE, dnames, KADM, KADMVERS); } /* if set_names succeeded, this will too */ in_buf.value = names[1].name; in_buf.length = strlen(names[1].name) + 1; (void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid, &gss_changepw_name); if (oldnames) { in_buf.value = names[3].name; in_buf.length = strlen(names[3].name) + 1; (void) gss_import_name(&OMret, &in_buf, (gss_OID) nt_krb5_name_oid, &gss_oldchangepw_name); } if ((ret = kadm5int_acl_init(context, 0, params.acl_file))) { errmsg = krb5_get_error_message (context, ret); krb5_klog_syslog(LOG_ERR, gettext("Cannot initialize acl file: %s"), errmsg); fprintf(stderr, gettext("%s: Cannot initialize acl file: %s\n"), whoami, errmsg); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } /* * Solaris Kerberos: * Warn if the acl file contains an entry for a principal matching the * default (unconfigured) acl rule. */ gssbuf.length = strlen("x/admin@___default_realm___"); gssbuf.value = "x/admin@___default_realm___"; /* Use any value as the first component - 'x' in this case */ if (gss_import_name(&minor_status, &gssbuf, GSS_C_NT_USER_NAME, &name) == GSS_S_COMPLETE) { if (kadm5int_acl_check(context, name, ACL_MODIFY, NULL, NULL)) { krb5_klog_syslog(LOG_WARNING, gettext("acls may not be properly configured: " "found an acl matching \"___default_realm___\" in " " %s"), params.acl_file); (void) fprintf(stderr, gettext("%s: Warning: " "acls may not be properly configured: found an acl " "matching \"___default_realm___\" in %s\n"), whoami, params.acl_file); } (void) gss_release_name(&minor_status, &name); } gssbuf.value = NULL; gssbuf.length = 0; /* * Solaris Kerberos: * List the logs (FILE, STDERR, etc) which are currently being * logged to and print to stderr. Useful when trying to * track down a failure via SMF. */ if (ret = krb5_klog_list_logs(whoami)) { fprintf(stderr, gettext("%s: %s while listing logs\n"), whoami, error_message(ret)); krb5_klog_syslog(LOG_ERR, gettext("%s while listing logs"), error_message(ret)); } if (!nofork && (ret = daemon(0, 0))) { ret = errno; errmsg = krb5_get_error_message (context, ret); krb5_klog_syslog(LOG_ERR, gettext("Cannot detach from tty: %s"), errmsg); fprintf(stderr, gettext("%s: Cannot detach from tty: %s\n"), whoami, errmsg); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } /* SUNW14resync */ #if 0 krb5_klog_syslog(LOG_INFO, "Seeding random number generator"); ret = krb5_c_random_os_entropy(context, 1, NULL); if (ret) { krb5_klog_syslog(LOG_ERR, "Error getting random seed: %s, aborting", krb5_get_error_message(context, ret)); kadm5_destroy(global_server_handle); krb5_klog_close(context); exit(1); } #endif handle = global_server_handle; ctx = handle->context; if (params.iprop_enabled == TRUE) { if (ret = krb5_db_supports_iprop(ctx, &iprop_supported)) { fprintf(stderr, gettext("%s: %s while trying to determine if KDB " "plugin supports iprop\n"), whoami, error_message(ret)); krb5_klog_syslog(LOG_ERR, gettext("%s while trying to determine if KDB " "plugin supports iprop"), error_message(ret)); krb5_klog_close(ctx); exit(1); } if (!iprop_supported) { fprintf(stderr, gettext("%s: Warning, current KDB " "plugin does not support iprop, continuing " "with iprop disabled\n"), whoami); krb5_klog_syslog(LOG_WARNING, gettext("Warning, current KDB " "plugin does not support iprop, continuing " "with iprop disabled")); ulog_set_role(ctx, IPROP_NULL); } else ulog_set_role(ctx, IPROP_MASTER); } else ulog_set_role(ctx, IPROP_NULL); log_ctx = ctx->kdblog_context; if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) { /* * IProp is enabled, so let's map in the update log * and setup the service. */ if (ret = ulog_map(ctx, ¶ms, FKADMIND)) { fprintf(stderr, gettext("%s: %s while mapping update log " "(`%s.ulog')\n"), whoami, error_message(ret), params.dbname); krb5_klog_syslog(LOG_ERR, gettext("%s while mapping update log " "(`%s.ulog')"), error_message(ret), params.dbname); krb5_klog_close(ctx); exit(1); } if (nofork) fprintf(stderr, "%s: create IPROP svc (PROG=%d, VERS=%d)\n", whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS); if (!svc_create(krb5_iprop_prog_1, KRB5_IPROP_PROG, KRB5_IPROP_VERS, "circuit_v")) { fprintf(stderr, gettext("%s: Cannot create IProp RPC service (PROG=%d, VERS=%d)\n"), whoami, KRB5_IPROP_PROG, KRB5_IPROP_VERS); krb5_klog_syslog(LOG_ERR, gettext("Cannot create IProp RPC service (PROG=%d, VERS=%d), failing."), KRB5_IPROP_PROG, KRB5_IPROP_VERS); krb5_klog_close(ctx); exit(1); } if (ret = kiprop_get_adm_host_srv_name(ctx, params.realm, &kiprop_name)) { krb5_klog_syslog(LOG_ERR, gettext("%s while getting IProp svc name, failing"), error_message(ret)); fprintf(stderr, gettext("%s: %s while getting IProp svc name, failing\n"), whoami, error_message(ret)); krb5_klog_close(ctx); exit(1); } if (!rpc_gss_set_svc_name(kiprop_name, "kerberos_v5", 0, KRB5_IPROP_PROG, KRB5_IPROP_VERS)) { rpc_gss_error_t err; (void) rpc_gss_get_error(&err); krb5_klog_syslog(LOG_ERR, gettext("Unable to set RPCSEC_GSS service name (`%s'), failing."), kiprop_name ? kiprop_name : ""); fprintf(stderr, gettext("%s: Unable to set RPCSEC_GSS service name (`%s'), failing.\n"), whoami, kiprop_name ? kiprop_name : ""); if (nofork) { fprintf(stderr, "%s: set svc name (rpcsec err=%d, sys err=%d)\n", whoami, err.rpc_gss_error, err.system_error); } exit(1); } free(kiprop_name); if (retdn == 0 && dnames) { set_svc_domnames(KADM5_KIPROP_HOST_SERVICE, dnames, KRB5_IPROP_PROG, KRB5_IPROP_VERS); } } else { if (!oldnames) { /* rpc_gss_set_svc_name failed for both kadmin/ and * changepw/. */ krb5_klog_syslog(LOG_ERR, gettext("Unable to set RPCSEC_GSS service names " "('%s, %s')"), names[0].name, names[1].name); fprintf(stderr, gettext("%s: Unable to set RPCSEC_GSS service names " "('%s, %s')\n"), whoami, names[0].name, names[1].name); krb5_klog_close(context); exit(1); } } if (dnames) freedomnames(dnames); setup_signal_handlers(log_ctx->iproprole); krb5_klog_syslog(LOG_INFO, gettext("starting")); if (nofork) fprintf(stderr, "%s: starting...\n", whoami); /* * We now call our own customized async event processing * function kadm_svc_run(), as opposed to svc_run() earlier, * since this enables kadmind to also listen-to/process * non-RPCSEC_GSS based change-pwd requests apart from the * regular, RPCSEC_GSS kpasswd requests from Solaris Krb5 clients. */ kadm_svc_run(); krb5_klog_syslog(LOG_INFO, gettext("finished, exiting")); kadm5_destroy(global_server_handle); t_close(fd); krb5_klog_close(context); exit(0); } /* * Function: kadm_svc_run * * Purpose: modified version of sunrpc svc_run. * which closes the database every TIMEOUT seconds. * * Arguments: * Requires: * Effects: * Modifies: */ void kadm_svc_run(void) { struct pollfd *rfd = 0; struct timeval timeout; int pollret; int nfds = 0; int i; while(signal_request_exit == 0) { timeout.tv_sec = TIMEOUT; timeout.tv_usec = 0; if (nfds != svc_max_pollfd) { rfd = realloc(rfd, sizeof (pollfd_t) * svc_max_pollfd); nfds = svc_max_pollfd; } (void) memcpy(rfd, svc_pollfd, sizeof (pollfd_t) * svc_max_pollfd); for (i = 0; i < nfds; i++) { if (rfd[i].fd == -1) { rfd[i].fd = schpw; rfd[i].events = POLLIN; break; } } switch(pollret = poll(rfd, nfds, __rpc_timeval_to_msec(&timeout))) { case -1: if(errno == EINTR) continue; perror("poll"); return; case 0: continue; default: for (i = 0; i < nfds; i++) { if (rfd[i].revents & POLLIN) { if (rfd[i].fd == schpw) handle_chpw(context, schpw, global_server_handle, &chgpw_params); else svc_getreq_poll(rfd, pollret); break; } else { if (i == (nfds - 1)) perror("poll"); } } break; } } } /* * Function: setup_signal_handlers * * Purpose: Setup signal handling functions with either * System V's signal() or POSIX_SIGNALS. */ void setup_signal_handlers(iprop_role iproprole) { #ifdef POSIX_SIGNALS (void) sigemptyset(&s_action.sa_mask); s_action.sa_handler = request_exit; (void) sigaction(SIGINT, &s_action, (struct sigaction *) NULL); (void) sigaction(SIGTERM, &s_action, (struct sigaction *) NULL); (void) sigaction(SIGQUIT, &s_action, (struct sigaction *) NULL); s_action.sa_handler = sig_pipe; (void) sigaction(SIGPIPE, &s_action, (struct sigaction *) NULL); /* * IProp will fork for a full-resync, we don't want to * wait on it and we don't want the living dead procs either. */ if (iproprole == IPROP_MASTER) { s_action.sa_handler = SIG_IGN; (void) sigaction(SIGCHLD, &s_action, (struct sigaction *) NULL); } #else signal(SIGINT, request_exit); signal(SIGTERM, request_exit); signal(SIGQUIT, request_exit); signal(SIGPIPE, sig_pipe); /* * IProp will fork for a full-resync, we don't want to * wait on it and we don't want the living dead procs either. */ if (iproprole == IPROP_MASTER) (void) signal(SIGCHLD, SIG_IGN); #endif /* POSIX_SIGNALS */ return; } /* * Function: request_exit * * Purpose: sets flags saying the server got a signal and that it * should exit when convient. * * Arguments: * Requires: * Effects: * modifies signal_request_exit which ideally makes the server exit * at some point. * * Modifies: * signal_request_exit */ void request_exit(int signum) { krb5_klog_syslog(LOG_NOTICE, gettext("Got signal to request exit")); signal_request_exit = 1; return; } /* * Function: sig_pipe * * Purpose: SIGPIPE handler * * Effects: krb5_klog_syslogs a message that a SIGPIPE occurred and returns, * thus causing the read() or write() to fail and, presumable, the RPC * to recover. Otherwise, the process aborts. */ void sig_pipe(int unused) { #ifndef POSIX_SIGNALS signal(SIGPIPE, sig_pipe); #endif /* POSIX_SIGNALS */ krb5_klog_syslog(LOG_NOTICE, gettext("Warning: Received a SIGPIPE; " "probably a client aborted. Continuing.")); return; } /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ #include #include "misc.h" /* * In server_stubs.c, kadmind has to be able to call kadm5 functions * with the arguments appropriate for any api version. Because of the * prototypes in admin.h, however, the compiler will only allow one * set of arguments to be passed. This file exports the old api * definitions with a different name, so they can be called from * server_stubs.c, and just passes on the call to the real api * function; it uses the old api version, however, so it can actually * call the real api functions whereas server_stubs.c cannot. * * This is most useful for functions like kadm5_get_principal that * take a different number of arguments based on API version. For * kadm5_get_policy, the same thing could be accomplished with * typecasts instead. */ kadm5_ret_t kadm5_get_principal_v1(void *server_handle, krb5_principal principal, kadm5_principal_ent_t_v1 *ent) { return kadm5_get_principal(server_handle, principal,(kadm5_principal_ent_t) ent, 0); } kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name, kadm5_policy_ent_t *ent) { return kadm5_get_policy(server_handle, name,(kadm5_policy_ent_t) ent); } /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * Openvision retains the copyright to derivative works of * this source code. Do *NOT* create a derivative of this * source code before consulting with your legal department. * Do *NOT* integrate *ANY* of this source code into another * product before consulting with your legal department. * * For further information, read the top-level Openvision * copyright which is contained in the top-level MIT Kerberos * copyright. * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING * */ /* * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved * */ #include #include #include /* for gss_nt_krb5_name */ #include #include #include #include #include #include /* inet_ntoa */ #include /* krb5_klog_syslog */ #include #include #include "misc.h" #define LOG_UNAUTH gettext("Unauthorized request: %s, %s, " \ "client=%s, service=%s, addr=%s") #define LOG_DONE gettext("Request: %s, %s, %s, client=%s, " \ "service=%s, addr=%s") extern gss_name_t gss_changepw_name; extern gss_name_t gss_oldchangepw_name; extern void * global_server_handle; extern short l_port; char buf[33]; #define CHANGEPW_SERVICE(rqstp) \ (cmp_gss_names_rel_1(acceptor_name(rqstp), gss_changepw_name) |\ (gss_oldchangepw_name && \ cmp_gss_names_rel_1(acceptor_name(rqstp), \ gss_oldchangepw_name))) static int gss_to_krb5_name(kadm5_server_handle_t handle, gss_name_t gss_name, krb5_principal *princ); static int gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str); static gss_name_t acceptor_name(struct svc_req * rqstp); kadm5_ret_t kadm5_get_priv(void *server_handle, long *privs, gss_name_t clnt); gss_name_t get_clnt_name(struct svc_req * rqstp) { OM_uint32 maj_stat, min_stat; gss_name_t name; rpc_gss_rawcred_t *raw_cred; void *cookie; gss_buffer_desc name_buff; rpc_gss_getcred(rqstp, &raw_cred, NULL, &cookie); name_buff.value = raw_cred->client_principal->name; name_buff.length = raw_cred->client_principal->len; maj_stat = gss_import_name(&min_stat, &name_buff, (gss_OID) GSS_C_NT_EXPORT_NAME, &name); if (maj_stat != GSS_S_COMPLETE) { return (NULL); } return (name); } char * client_addr(struct svc_req * req, char *buf) { struct sockaddr *ca; u_char *b; char *frontspace = " "; /* * Convert the caller's IP address to a dotted string */ ca = (struct sockaddr *) svc_getrpccaller(req->rq_xprt)->buf; if (ca->sa_family == AF_INET) { b = (u_char *) & ((struct sockaddr_in *) ca)->sin_addr; (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace, b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF); } else { /* * No IP address to print. If there was a host name * printed, then we print a space. */ (void) sprintf(buf, frontspace); } return (buf); } static int cmp_gss_names(gss_name_t n1, gss_name_t n2) { OM_uint32 emaj, emin; int equal; if (GSS_ERROR(emaj = gss_compare_name(&emin, n1, n2, &equal))) return(0); return(equal); } /* Does a comparison of the names and then releases the first entity */ /* For use above in CHANGEPW_SERVICE */ static int cmp_gss_names_rel_1(gss_name_t n1, gss_name_t n2) { OM_uint32 min_stat; int ret; ret = cmp_gss_names(n1, n2); if (n1) (void) gss_release_name(&min_stat, &n1); return ret; } /* * Function check_handle * * Purpose: Check a server handle and return a com_err code if it is * invalid or 0 if it is valid. * * Arguments: * * handle The server handle. */ static int check_handle(void *handle) { CHECK_HANDLE(handle); return 0; } /* * Function: new_server_handle * * Purpose: Constructs a server handle suitable for passing into the * server library API functions, by folding the client's API version * and calling principal into the server handle returned by * kadm5_init. * * Arguments: * api_version (input) The API version specified by the client * rqstp (input) The RPC request * handle (output) The returned handle * (output) An error code, or 0 if no error occurred * * Effects: * Returns a pointer to allocated storage containing the server * handle. If an error occurs, then no allocated storage is * returned, and the return value of the function will be a * non-zero com_err code. * * The allocated storage for the handle should be freed with * free_server_handle (see below) when it is no longer needed. */ static kadm5_ret_t new_server_handle(krb5_ui_4 api_version, struct svc_req *rqstp, kadm5_server_handle_t *out_handle) { kadm5_server_handle_t handle; gss_name_t name; OM_uint32 min_stat; if (! (handle = (kadm5_server_handle_t) malloc(sizeof(*handle)))) return ENOMEM; *handle = *(kadm5_server_handle_t)global_server_handle; handle->api_version = api_version; if (!(name = get_clnt_name(rqstp))) { free(handle); return KADM5_FAILURE; } if (! gss_to_krb5_name(handle, name, &handle->current_caller)) { free(handle); gss_release_name(&min_stat, &name); return KADM5_FAILURE; } gss_release_name(&min_stat, &name); *out_handle = handle; return 0; } /* * Function: free_server_handle * * Purpose: Free handle memory allocated by new_server_handle * * Arguments: * handle (input/output) The handle to free */ static void free_server_handle(kadm5_server_handle_t handle) { krb5_free_principal(handle->context, handle->current_caller); free(handle); } /* * Function: setup_gss_names * * Purpose: Create printable representations of the client and server * names. * * Arguments: * rqstp (r) the RPC request * client_name (w) pointer to client_name string * server_name (w) pointer to server_name string * * Effects: * * Unparses the client and server names into client_name and * server_name, both of which must be freed by the caller. Returns 0 * on success and -1 on failure. On failure client_name and server_name * will point to null. */ /* SUNW14resync */ int setup_gss_names(struct svc_req *rqstp, char **client_name, char **server_name) { OM_uint32 maj_stat, min_stat; rpc_gss_rawcred_t *raw_cred; gss_buffer_desc name_buf; char *tmp, *val; size_t len; gss_name_t name; *client_name = NULL; rpc_gss_getcred(rqstp, &raw_cred, NULL, NULL); /* Return a copy of the service principal from the raw_cred */ *server_name = strdup(raw_cred->svc_principal); if (*server_name == NULL) return (-1); if (!(name = get_clnt_name(rqstp))) { free(*server_name); *server_name = NULL; return (-1); } maj_stat = gss_display_name(&min_stat, name, &name_buf, NULL); if (maj_stat != GSS_S_COMPLETE) { free(*server_name); gss_release_name(&min_stat, &name); *server_name = NULL; return (-1); } gss_release_name(&min_stat, &name); /* * Allocate space to copy the client principal. We allocate an * extra byte to make the string null terminated if we need to. */ val = name_buf.value; len = name_buf.length + (val[name_buf.length - 1] != '\0'); /* len is the length including the null terminating byte. */ tmp = malloc(len); if (tmp) { memcpy(tmp, val, len - 1); tmp[len - 1] = '\0'; } else { free(*server_name); *server_name = NULL; } /* Were done with the GSS buffer */ (void) gss_release_buffer(&min_stat, &name_buf); *client_name = tmp; return (tmp ? 0 : -1); } static gss_name_t acceptor_name(struct svc_req * rqstp) { OM_uint32 maj_stat, min_stat; gss_name_t name; rpc_gss_rawcred_t *raw_cred; void *cookie; gss_buffer_desc name_buff; rpc_gss_getcred(rqstp, &raw_cred, NULL, &cookie); name_buff.value = raw_cred->svc_principal; name_buff.length = strlen(raw_cred->svc_principal); maj_stat = gss_import_name(&min_stat, &name_buff, (gss_OID) gss_nt_krb5_name, &name); if (maj_stat != GSS_S_COMPLETE) { gss_release_buffer(&min_stat, &name_buff); return (NULL); } maj_stat = gss_display_name(&min_stat, name, &name_buff, NULL); if (maj_stat != GSS_S_COMPLETE) { gss_release_buffer(&min_stat, &name_buff); return (NULL); } gss_release_buffer(&min_stat, &name_buff); return name; } static int cmp_gss_krb5_name(kadm5_server_handle_t handle, gss_name_t gss_name, krb5_principal princ) { krb5_principal princ2; int status; if (! gss_to_krb5_name(handle, gss_name, &princ2)) return 0; status = krb5_principal_compare(handle->context, princ, princ2); krb5_free_principal(handle->context, princ2); return status; } /* * This routine primarily validates the username and password * of the principal to be created, if a prior acl check for * the 'u' privilege succeeds. Validation is done using * the PAM `k5migrate' service. k5migrate normally stacks * pam_unix_auth.so and pam_unix_account.so in its auth and * account stacks respectively. * * Returns 1 (true), if validation is successful, * else returns 0 (false). */ int verify_pam_pw(char *userdata, char *pwd) { pam_handle_t *pamh; int err = 0; int result = 1; char *user = NULL; char *ptr = NULL; ptr = strchr(userdata, '@'); if (ptr != NULL) { user = (char *)malloc(ptr - userdata + 1); (void) strlcpy(user, userdata, (ptr - userdata) + 1); } else { user = (char *)strdup(userdata); } err = pam_start("k5migrate", user, NULL, &pamh); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "verify_pam_pw: pam_start() failed, %s\n", pam_strerror(pamh, err)); if (user) free(user); return (0); } if (user) free(user); err = pam_set_item(pamh, PAM_AUTHTOK, (void *)pwd); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "verify_pam_pw: pam_set_item() failed, %s\n", pam_strerror(pamh, err)); (void) pam_end(pamh, err); return (0); } err = pam_authenticate(pamh, PAM_SILENT); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "verify_pam_pw: pam_authenticate() " "failed, %s\n", pam_strerror(pamh, err)); (void) pam_end(pamh, err); return (0); } err = pam_acct_mgmt(pamh, PAM_SILENT); if (err != PAM_SUCCESS) { syslog(LOG_ERR, "verify_pam_pw: pam_acct_mgmt() failed, %s\n", pam_strerror(pamh, err)); (void) pam_end(pamh, err); return (0); } (void) pam_end(pamh, PAM_SUCCESS); return (result); } static int gss_to_krb5_name(kadm5_server_handle_t handle, gss_name_t gss_name, krb5_principal *princ) { OM_uint32 status, minor_stat; gss_buffer_desc gss_str; gss_OID gss_type; int success; status = gss_display_name(&minor_stat, gss_name, &gss_str, &gss_type); if ((status != GSS_S_COMPLETE) || (!g_OID_equal(gss_type, gss_nt_krb5_name))) return 0; success = (krb5_parse_name(handle->context, gss_str.value, princ) == 0); gss_release_buffer(&minor_stat, &gss_str); return success; } static int gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str) { OM_uint32 status, minor_stat; gss_OID gss_type; status = gss_display_name(&minor_stat, gss_name, str, &gss_type); if ((status != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name)) return 1; return 0; } static int log_unauth( char *op, char *target, char *client, char *server, char *addr) { size_t tlen, clen, slen; char *tdots, *cdots, *sdots; tlen = strlen(target); trunc_name(&tlen, &tdots); clen = strlen(client); trunc_name(&clen, &cdots); slen = strlen(server); trunc_name(&slen, &sdots); return krb5_klog_syslog(LOG_NOTICE, "Unauthorized request: %s, %.*s%s, " "client=%.*s%s, service=%.*s%s, addr=%s", op, tlen, target, tdots, clen, client, cdots, slen, server, sdots, addr); } static int log_done( char *op, char *target, const char *errmsg, char *client, char *server, char *addr) { size_t tlen, clen, slen; char *tdots, *cdots, *sdots; tlen = strlen(target); trunc_name(&tlen, &tdots); clen = strlen(client); trunc_name(&clen, &cdots); slen = strlen(server); trunc_name(&slen, &sdots); return krb5_klog_syslog(LOG_NOTICE, "Request: %s, %.*s%s, %s, " "client=%.*s%s, service=%.*s%s, addr=%s", op, tlen, target, tdots, errmsg, clen, client, cdots, slen, server, sdots, addr); } generic_ret * create_principal_2_svc(cprinc_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; int policy_migrate = 0; OM_uint32 minor_stat; kadm5_server_handle_t handle; kadm5_ret_t retval; restriction_t *rp; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (kadm5int_acl_check(handle->context, name, ACL_MIGRATE, arg->rec.principal, &rp) && verify_pam_pw(prime_arg, arg->passwd)) { policy_migrate = 1; } if (CHANGEPW_SERVICE(rqstp) || (!kadm5int_acl_check(handle->context, name, ACL_ADD, arg->rec.principal, &rp) && !(policy_migrate)) || kadm5int_acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret.code = KADM5_AUTH_ADD; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_create_principal", prime_arg, client_name); log_unauth("kadm5_create_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_create_principal((void *)handle, &arg->rec, arg->mask, arg->passwd); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_create_principal", prime_arg, client_name, ret.code); log_done("kadm5_create_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); if (policy_migrate && (ret.code == 0)) { arg->rec.policy = strdup("default"); if ((arg->mask & KADM5_PW_EXPIRATION)) { arg->mask = 0; arg->mask |= KADM5_POLICY; arg->mask |= KADM5_PW_EXPIRATION; } else { arg->mask = 0; arg->mask |= KADM5_POLICY; } retval = kadm5_modify_principal((void *)handle, &arg->rec, arg->mask); log_done("kadm5_modify_principal", prime_arg, ((retval == 0) ? "success" : error_message(retval)), client_name, service_name, client_addr(rqstp, buf)); } } error: if (name) gss_release_name(&minor_stat, &name); free_server_handle(handle); if (prime_arg) free(prime_arg); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } generic_ret * create_principal3_2_svc(cprinc3_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; int policy_migrate = 0; OM_uint32 minor_stat; kadm5_server_handle_t handle; kadm5_ret_t retval; restriction_t *rp; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (kadm5int_acl_check(handle->context, name, ACL_MIGRATE, arg->rec.principal, &rp) && verify_pam_pw(prime_arg, arg->passwd)) { policy_migrate = 1; } if (CHANGEPW_SERVICE(rqstp) || (!kadm5int_acl_check(handle->context, name, ACL_ADD, arg->rec.principal, &rp) && !(policy_migrate)) || kadm5int_acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret.code = KADM5_AUTH_ADD; log_unauth("kadm5_create_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_create_principal_3((void *)handle, &arg->rec, arg->mask, arg->n_ks_tuple, arg->ks_tuple, arg->passwd); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done("kadm5_create_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); if (policy_migrate && (ret.code == 0)) { arg->rec.policy = strdup("default"); if ((arg->mask & KADM5_PW_EXPIRATION)) { arg->mask = 0; arg->mask |= KADM5_POLICY; arg->mask |= KADM5_PW_EXPIRATION; } else { arg->mask = 0; arg->mask |= KADM5_POLICY; } retval = kadm5_modify_principal((void *)handle, &arg->rec, arg->mask); log_done("kadm5_modify_principal", prime_arg, ((retval == 0) ? "success" : error_message(retval)), client_name, service_name, client_addr(rqstp, buf)); } } error: if (name) gss_release_name(&minor_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return &ret; } generic_ret * delete_principal_2_svc(dprinc_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_DELETE, arg->princ, NULL)) { ret.code = KADM5_AUTH_DELETE; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_delete_principal", prime_arg, client_name); log_unauth("kadm5_delete_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_delete_principal((void *)handle, arg->princ); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_delete_principal", prime_arg, client_name, ret.code); log_done("kadm5_delete_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); if (prime_arg) free(prime_arg); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } generic_ret * modify_principal_2_svc(mprinc_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; restriction_t *rp; gss_name_t name = NULL; const char *errmsg = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_MODIFY, arg->rec.principal, &rp) || kadm5int_acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret.code = KADM5_AUTH_MODIFY; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_modify_principal", prime_arg, client_name); log_unauth("kadm5_modify_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_modify_principal((void *)handle, &arg->rec, arg->mask); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_modify_principal", prime_arg, client_name, ret.code); log_done("kadm5_modify_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (prime_arg) free(prime_arg); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } generic_ret * rename_principal_2_svc(rprinc_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg1 = NULL, *prime_arg2 = NULL; char prime_arg[BUFSIZ]; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; restriction_t *rp; const char *errmsg = NULL; gss_name_t name = NULL; size_t tlen1, tlen2, clen, slen; char *tdots1, *tdots2, *cdots, *sdots; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->src, &prime_arg1) || krb5_unparse_name(handle->context, arg->dest, &prime_arg2)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } tlen1 = strlen(prime_arg1); trunc_name(&tlen1, &tdots1); tlen2 = strlen(prime_arg2); trunc_name(&tlen2, &tdots2); clen = strlen(client_name); trunc_name(&clen, &cdots); slen = strlen(service_name); trunc_name(&slen, &sdots); (void) snprintf(prime_arg, sizeof (prime_arg), "%.*s%s to %.*s*s", tlen1, prime_arg1, tdots1, tlen2, prime_arg2, tdots2); ret.code = KADM5_OK; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (! CHANGEPW_SERVICE(rqstp)) { if (!kadm5int_acl_check(handle->context, name, ACL_DELETE, arg->src, NULL)) ret.code = KADM5_AUTH_DELETE; /* any restrictions at all on the ADD kills the RENAME */ if (!kadm5int_acl_check(handle->context, name, ACL_ADD, arg->dest, &rp)) { if (ret.code == KADM5_AUTH_DELETE) ret.code = KADM5_AUTH_INSUFFICIENT; else ret.code = KADM5_AUTH_ADD; } } else ret.code = KADM5_AUTH_INSUFFICIENT; if (ret.code != KADM5_OK) { audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_rename_principal", prime_arg, client_name); krb5_klog_syslog(LOG_NOTICE, "Unauthorized request: kadm5_rename_principal, " "%.*s%s to %.*s%s, " "client=%.*s%s, service=%.*s%s, addr=%s", tlen1, prime_arg1, tdots1, tlen2, prime_arg2, tdots2, clen, client_name, cdots, slen, service_name, sdots, client_addr(rqstp, buf)); } else { ret.code = kadm5_rename_principal((void *)handle, arg->src, arg->dest); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_rename_principal", prime_arg, client_name, ret.code); krb5_klog_syslog(LOG_NOTICE, "Request: kadm5_rename_principal, " "%.*s%s to %.*s%s, %s, " "client=%.*s%s, service=%.*s%s, addr=%s", tlen1, prime_arg1, tdots1, tlen2, prime_arg2, tdots2, errmsg ? errmsg : "success", clen, client_name, cdots, slen, service_name, sdots, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (prime_arg1) free(prime_arg1); if (prime_arg2) free(prime_arg2); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } gprinc_ret * get_principal_2_svc(gprinc_arg *arg, struct svc_req *rqstp) { static gprinc_ret ret; kadm5_principal_ent_t_v1 e; char *prime_arg = NULL, *funcname; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_gprinc_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; funcname = handle->api_version == KADM5_API_VERSION_1 ? "kadm5_get_principal (V1)" : "kadm5_get_principal"; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (! cmp_gss_krb5_name(handle, name, arg->princ) && (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_INQUIRE, arg->princ, NULL))) { ret.code = KADM5_AUTH_GET; audit_kadmind_unauth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name); log_unauth(funcname, prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { if (handle->api_version == KADM5_API_VERSION_1) { ret.code = kadm5_get_principal_v1((void *)handle, arg->princ, &e); if(ret.code == KADM5_OK) { memcpy(&ret.rec, e, sizeof(kadm5_principal_ent_rec_v1)); free(e); } } else { ret.code = kadm5_get_principal((void *)handle, arg->princ, &ret.rec, arg->mask); } /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name, ret.code); log_done(funcname, prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (prime_arg) free(prime_arg); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } gprincs_ret * get_princs_2_svc(gprincs_arg *arg, struct svc_req *rqstp) { static gprincs_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; gss_name_t name = NULL; const char *errmsg = NULL; xdr_free(xdr_gprincs_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->exp; if (prime_arg == NULL) prime_arg = "*"; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_LIST, NULL, NULL)) { ret.code = KADM5_AUTH_LIST; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_get_principals", prime_arg, client_name); log_unauth("kadm5_get_principals", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_get_principals((void *)handle, arg->exp, &ret.princs, &ret.count); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_get_principals", prime_arg, client_name, ret.code); log_done("kadm5_get_principals", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } generic_ret * chpass_principal_2_svc(chpass_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (cmp_gss_krb5_name(handle, name, arg->princ)) { ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ, FALSE, 0, NULL, arg->pass); } else if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_CHANGEPW, arg->princ, NULL)) { ret.code = kadm5_chpass_principal((void *)handle, arg->princ, arg->pass); } else { audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_chpass_principal", prime_arg, client_name); log_unauth("kadm5_chpass_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_CHANGEPW; } if(ret.code != KADM5_AUTH_CHANGEPW) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_chpass_principal", prime_arg, client_name, ret.code); log_done("kadm5_chpass_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (prime_arg) free(prime_arg); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } generic_ret * chpass_principal3_2_svc(chpass3_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (cmp_gss_krb5_name(handle, name, arg->princ)) { ret.code = chpass_principal_wrapper_3((void *)handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, arg->pass); } else if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_CHANGEPW, arg->princ, NULL)) { ret.code = kadm5_chpass_principal_3((void *)handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, arg->pass); } else { log_unauth("kadm5_chpass_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_CHANGEPW; } if(ret.code != KADM5_AUTH_CHANGEPW) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done("kadm5_chpass_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return (&ret); } #ifdef SUNWOFF generic_ret * setv4key_principal_2_svc(setv4key_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_SETKEY, arg->princ, NULL)) { ret.code = kadm5_setv4key_principal((void *)handle, arg->princ, arg->keyblock); } else { log_unauth("kadm5_setv4key_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_SETKEY; } if(ret.code != KADM5_AUTH_SETKEY) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done("kadm5_setv4key_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return (&ret); } #endif generic_ret * setkey_principal_2_svc(setkey_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg; char *client_name, *service_name; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_SETKEY, arg->princ, NULL)) { ret.code = kadm5_setkey_principal((void *)handle, arg->princ, arg->keyblocks, arg->n_keys); } else { log_unauth("kadm5_setkey_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_SETKEY; } if(ret.code != KADM5_AUTH_SETKEY) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done("kadm5_setkey_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return (&ret); } generic_ret * setkey_principal3_2_svc(setkey3_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_SETKEY, arg->princ, NULL)) { ret.code = kadm5_setkey_principal_3((void *)handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, arg->keyblocks, arg->n_keys); } else { log_unauth("kadm5_setkey_principal", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_SETKEY; } if(ret.code != KADM5_AUTH_SETKEY) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done("kadm5_setkey_principal", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return &ret; } chrand_ret * chrand_principal_2_svc(chrand_arg *arg, struct svc_req *rqstp) { static chrand_ret ret; krb5_keyblock *k; int nkeys; char *prime_arg = NULL, *funcname; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_chrand_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; funcname = handle->api_version == KADM5_API_VERSION_1 ? "kadm5_randkey_principal (V1)" : "kadm5_randkey_principal"; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (cmp_gss_krb5_name(handle, name, arg->princ)) { ret.code = randkey_principal_wrapper((void *)handle, arg->princ, &k, &nkeys); } else if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_CHANGEPW, arg->princ, NULL)) { ret.code = kadm5_randkey_principal((void *)handle, arg->princ, &k, &nkeys); } else { audit_kadmind_unauth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name); log_unauth(funcname, prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_CHANGEPW; } if(ret.code == KADM5_OK) { if (handle->api_version == KADM5_API_VERSION_1) { krb5_copy_keyblock_contents(handle->context, k, &ret.key); krb5_free_keyblock(handle->context, k); } else { ret.keys = k; ret.n_keys = nkeys; } } if(ret.code != KADM5_AUTH_CHANGEPW) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name, ret.code); log_done(funcname, prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (prime_arg) free(prime_arg); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } chrand_ret * chrand_principal3_2_svc(chrand3_arg *arg, struct svc_req *rqstp) { static chrand_ret ret; krb5_keyblock *k; int nkeys; char *prime_arg = NULL, *funcname; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_chrand_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; funcname = handle->api_version == KADM5_API_VERSION_1 ? "kadm5_randkey_principal (V1)" : "kadm5_randkey_principal"; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { ret.code = KADM5_BAD_PRINCIPAL; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (cmp_gss_krb5_name(handle, name, arg->princ)) { ret.code = randkey_principal_wrapper_3((void *)handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, &k, &nkeys); } else if (!(CHANGEPW_SERVICE(rqstp)) && kadm5int_acl_check(handle->context, name, ACL_CHANGEPW, arg->princ, NULL)) { ret.code = kadm5_randkey_principal_3((void *)handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, &k, &nkeys); } else { log_unauth(funcname, prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_CHANGEPW; } if(ret.code == KADM5_OK) { if (handle->api_version == KADM5_API_VERSION_1) { krb5_copy_keyblock_contents(handle->context, k, &ret.key); krb5_free_keyblock(handle->context, k); } else { ret.keys = k; ret.n_keys = nkeys; } } if(ret.code != KADM5_AUTH_CHANGEPW) { /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); log_done(funcname, prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); if (prime_arg) free(prime_arg); return (&ret); } generic_ret * create_policy_2_svc(cpol_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->rec.policy; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_ADD, NULL, NULL)) { ret.code = KADM5_AUTH_ADD; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_create_policy", prime_arg, client_name); log_unauth("kadm5_create_policy", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_create_policy((void *)handle, &arg->rec, arg->mask); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_create_policy", prime_arg, client_name, ret.code); log_done("kadm5_create_policy", ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } generic_ret * delete_policy_2_svc(dpol_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->name; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_DELETE, NULL, NULL)) { audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_delete_policy", prime_arg, client_name); log_unauth("kadm5_delete_policy", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_DELETE; } else { ret.code = kadm5_delete_policy((void *)handle, arg->name); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_delete_policy", prime_arg, client_name, ret.code); log_done("kadm5_delete_policy", ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return &ret; } generic_ret * modify_policy_2_svc(mpol_arg *arg, struct svc_req *rqstp) { static generic_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->rec.policy; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_MODIFY, NULL, NULL)) { audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_modify_policy", prime_arg, client_name); log_unauth("kadm5_modify_policy", prime_arg, client_name, service_name, client_addr(rqstp, buf)); ret.code = KADM5_AUTH_MODIFY; } else { ret.code = kadm5_modify_policy((void *)handle, &arg->rec, arg->mask); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_modify_policy", prime_arg, client_name, ret.code); log_done("kadm5_modify_policy", ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } gpol_ret * get_policy_2_svc(gpol_arg *arg, struct svc_req *rqstp) { static gpol_ret ret; kadm5_ret_t ret2; char *prime_arg = NULL, *funcname; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_policy_ent_t e; kadm5_principal_ent_rec caller_ent; krb5_principal caller; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_gpol_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *) handle))) goto error; ret.api_version = handle->api_version; funcname = handle->api_version == KADM5_API_VERSION_1 ? "kadm5_get_policy (V1)" : "kadm5_get_policy"; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->name; ret.code = KADM5_AUTH_GET; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (!CHANGEPW_SERVICE(rqstp) && kadm5int_acl_check(handle->context, name, ACL_INQUIRE, NULL, NULL)) ret.code = KADM5_OK; else { ret.code = kadm5_get_principal(handle->lhandle, handle->current_caller, &caller_ent, KADM5_PRINCIPAL_NORMAL_MASK); if (ret.code == KADM5_OK) { if (caller_ent.aux_attributes & KADM5_POLICY && strcmp(caller_ent.policy, arg->name) == 0) { ret.code = KADM5_OK; } else ret.code = KADM5_AUTH_GET; ret2 = kadm5_free_principal_ent(handle->lhandle, &caller_ent); ret.code = ret.code ? ret.code : ret2; } } if (ret.code == KADM5_OK) { if (handle->api_version == KADM5_API_VERSION_1) { ret.code = kadm5_get_policy_v1((void *)handle, arg->name, &e); if(ret.code == KADM5_OK) { memcpy(&ret.rec, e, sizeof(kadm5_policy_ent_rec)); free(e); } } else { ret.code = kadm5_get_policy((void *)handle, arg->name, &ret.rec); } /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name, ret.code); log_done(funcname, ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } else { audit_kadmind_unauth(rqstp->rq_xprt, l_port, funcname, prime_arg, client_name); log_unauth(funcname, prime_arg, client_name, service_name, client_addr(rqstp, buf)); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } gpols_ret * get_pols_2_svc(gpols_arg *arg, struct svc_req *rqstp) { static gpols_ret ret; char *prime_arg = NULL; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_gpols_ret, (char *) &ret); if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } prime_arg = arg->exp; if (prime_arg == NULL) prime_arg = "*"; if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, name, ACL_LIST, NULL, NULL)) { ret.code = KADM5_AUTH_LIST; audit_kadmind_unauth(rqstp->rq_xprt, l_port, "kadm5_get_policies", prime_arg, client_name); log_unauth("kadm5_get_policies", prime_arg, client_name, service_name, client_addr(rqstp, buf)); } else { ret.code = kadm5_get_policies((void *)handle, arg->exp, &ret.pols, &ret.count); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_get_policies", prime_arg, client_name, ret.code); log_done("kadm5_get_policies", prime_arg, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); } error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } getprivs_ret * get_privs_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) { static getprivs_ret ret; char *client_name = NULL, *service_name = NULL; OM_uint32 min_stat; kadm5_server_handle_t handle; const char *errmsg = NULL; gss_name_t name = NULL; xdr_free(xdr_getprivs_ret, (char *) &ret); if ((ret.code = new_server_handle(*arg, rqstp, &handle))) return &ret; if ((ret.code = check_handle((void *)handle))) goto error; ret.api_version = handle->api_version; if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; goto error; } if (!(name = get_clnt_name(rqstp))) { ret.code = KADM5_FAILURE; goto error; } ret.code = __kadm5_get_priv((void *) handle, &ret.privs, name); /* Solaris Kerberos */ if( ret.code != 0 ) errmsg = krb5_get_error_message(handle ? handle->context : NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, "kadm5_get_privs", NULL, client_name, ret.code); log_done("kadm5_get_privs", client_name, errmsg ? errmsg : "success", client_name, service_name, client_addr(rqstp, buf)); if (errmsg != NULL) krb5_free_error_message(handle ? handle->context : NULL, errmsg); error: if (name) gss_release_name(&min_stat, &name); free_server_handle(handle); if (client_name) free(client_name); if (service_name) free(service_name); return (&ret); } generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) { static generic_ret ret; char *client_name, *service_name; kadm5_server_handle_t handle; const char *errmsg = NULL; size_t clen, slen; char *cdots, *sdots; xdr_free(xdr_generic_ret, (char *) &ret); if ((ret.code = new_server_handle(*arg, rqstp, &handle))) return &ret; if (! (ret.code = check_handle((void *)handle))) { ret.api_version = handle->api_version; } free_server_handle(handle); if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { ret.code = KADM5_FAILURE; return &ret; } /* Solaris Kerberos */ if (ret.code != 0) errmsg = krb5_get_error_message(NULL, ret.code); audit_kadmind_auth(rqstp->rq_xprt, l_port, (ret.api_version == KADM5_API_VERSION_1 ? "kadm5_init (V1)" : "kadm5_init"), NULL, client_name, ret.code); clen = strlen(client_name); trunc_name(&clen, &cdots); slen = strlen(service_name); trunc_name(&slen, &sdots); krb5_klog_syslog(LOG_NOTICE, "Request: %s, %.*s%s, %s, " "client=%.*s%s, service=%.*s%s, addr=%s, flavor=%d", (ret.api_version == KADM5_API_VERSION_1 ? "kadm5_init (V1)" : "kadm5_init"), clen, client_name, cdots, errmsg ? errmsg : "success", clen, client_name, cdots, slen, service_name, sdots, client_addr(rqstp, buf), rqstp->rq_cred.oa_flavor); if (errmsg != NULL) krb5_free_error_message(NULL, errmsg); free(client_name); free(service_name); return (&ret); }