diff options
Diffstat (limited to 'src/lib')
242 files changed, 47582 insertions, 1309 deletions
diff --git a/src/lib/ChangeLog b/src/lib/ChangeLog index 210d8cf51..c7e7fb6b1 100644 --- a/src/lib/ChangeLog +++ b/src/lib/ChangeLog @@ -12,6 +12,10 @@ Wed Jul 10 20:32:22 1996 Theodore Y. Ts'o <tytso@mit.edu> timebomb and version server code was moved to krb5_win_do_init(), which is called by krb5_init_context(). +Tue Jul 9 17:31:57 1996 Marc Horowitz <marc@mit.edu> + + * configure.in (CONFIG_DIRS): add rpc subdir + Tue Jul 9 16:44:22 1996 Theodore Ts'o <tytso@rsts-11.mit.edu> * win_glue.c: Add a quick hack so we can time-bomb the libkrb5.dll diff --git a/src/lib/configure.in b/src/lib/configure.in index aebd96c6a..80c359eb3 100644 --- a/src/lib/configure.in +++ b/src/lib/configure.in @@ -7,7 +7,7 @@ else AC_MSG_RESULT(skipping Kerberos 4 libraries) krb4= fi -CONFIG_DIRS(crypto krb5 des425 $krb4 krb5util kdb gssapi kadm) +CONFIG_DIRS(crypto krb5 des425 $krb4 krb5util kdb gssapi rpc kadm5) AC_PROG_ARCHIVE AC_PROG_RANLIB DO_SUBDIRS diff --git a/src/lib/crypto/des/ChangeLog b/src/lib/crypto/des/ChangeLog index f8637a6e7..c6f707290 100644 --- a/src/lib/crypto/des/ChangeLog +++ b/src/lib/crypto/des/ChangeLog @@ -1,3 +1,4 @@ +<<<<<<< ChangeLog Sat Jun 15 03:51:19 1996 Ezra Peisach <epeisach@kangaroo.mit.edu> * Makefile.in (clean): Add space before \ @@ -66,6 +67,11 @@ Thu May 2 18:29:01 1996 Richard Basch <basch@lehman.com> [3-DES uses DES3-CBC-CRC to increment a 192 bit sequence number, instead of being only as secure as DES.] +Wed Apr 17 19:25:01 1996 Marc Horowitz <marc@mit.edu> + + * cbc_cksum.c (mit_des_cbc_checksum): don't allocate the checksum + contents. The caller is supposed to do this. + Wed Apr 10 17:46:40 1996 Theodore Y. Ts'o <tytso@dcl> * Makefile.in (SRCS,OBJS): Added afsstring2key.c to the list of diff --git a/src/lib/crypto/des/cbc_cksum.c b/src/lib/crypto/des/cbc_cksum.c index 9c98263a2..c4fb8c086 100644 --- a/src/lib/crypto/des/cbc_cksum.c +++ b/src/lib/crypto/des/cbc_cksum.c @@ -86,7 +86,6 @@ mit_des_cbc_checksum(in, in_length, key, key_size, cksum) cksum->checksum_type = CKSUMTYPE_DESCBC; cksum->length = sizeof(mit_des_cblock); - mit_des_cbc_cksum(in, cksum->contents, in_length, schedule, key); cleanup(); diff --git a/src/lib/gssapi/ChangeLog b/src/lib/gssapi/ChangeLog index 0ad7c89bd..036bd4693 100644 --- a/src/lib/gssapi/ChangeLog +++ b/src/lib/gssapi/ChangeLog @@ -12,6 +12,11 @@ Mon May 6 21:33:25 1996 Ezra Peisach <epeisach@kangaroo.mit.edu> * Makefile.in (clean-unix): Remove libgssapi_krb5.stamp. +Wed Apr 17 21:48:15 1996 Marc Horowitz <marc@mit.edu> + + * Makefile.in, configure.in: Nothing in mechglue is used anymore, + for now. + Tue Feb 27 22:10:48 1996 Theodore Y. Ts'o <tytso@dcl> * Makefile.in (all-windows, clean-windows): Add mechglue to the diff --git a/src/lib/gssapi/Makefile.in b/src/lib/gssapi/Makefile.in index c27788dc2..b874a951c 100644 --- a/src/lib/gssapi/Makefile.in +++ b/src/lib/gssapi/Makefile.in @@ -10,8 +10,8 @@ KRB5_VER=@KRB5_SH_VERS@ DEPLIBS=$(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \ $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \ $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) -LIB_SUBDIRS= generic krb5 mechglue -LIBDONE= generic/DONE krb5/DONE mechglue/DONE +LIB_SUBDIRS= generic krb5 +LIBDONE= generic/DONE krb5/DONE # mechglue/DONE LIBUPDATE= $(BUILDTOP)/util/libupdate SHLIB_LIBS=-lkrb5 -lcrypto -lcom_err @@ -51,9 +51,9 @@ all-windows:: cd ..\krb5 @echo Making in gssapi\krb5 -$(MAKE) -$(MFLAGS) - cd ..\mechglue - @echo Making in gssapi\mechglue - -$(MAKE) -$(MFLAGS) +# cd ..\mechglue +# @echo Making in gssapi\mechglue +# -$(MAKE) -$(MFLAGS) cd .. clean-windows:: @@ -63,9 +63,9 @@ clean-windows:: cd ..\krb5 @echo Making clean in gssapi\krb5 -$(MAKE) -$(MFLAGS) clean - cd ..\mechglue - @echo Making clean in gssapi\mechglue - -$(MAKE) -$(MFLAGS) clean +# cd ..\mechglue +# @echo Making clean in gssapi\mechglue +# -$(MAKE) -$(MFLAGS) clean cd .. @echo Making clean in gssapi diff --git a/src/lib/gssapi/configure.in b/src/lib/gssapi/configure.in index ee150e11f..164582c64 100644 --- a/src/lib/gssapi/configure.in +++ b/src/lib/gssapi/configure.in @@ -1,6 +1,7 @@ AC_INIT(configure.in) CONFIG_RULES -CONFIG_DIRS(generic krb5 mechglue) +CONFIG_DIRS(generic krb5) +dnl CONFIG_DIRS(generic krb5 mechglue) AC_PROG_ARCHIVE AC_PROG_ARCHIVE_ADD AC_PROG_RANLIB diff --git a/src/lib/gssapi/generic/ChangeLog b/src/lib/gssapi/generic/ChangeLog index d43459914..a3b2a1411 100644 --- a/src/lib/gssapi/generic/ChangeLog +++ b/src/lib/gssapi/generic/ChangeLog @@ -28,6 +28,26 @@ Wed Jun 12 00:46:41 1996 Theodore Ts'o <tytso@rsts-11.mit.edu> all uses of INTERFACE in favor of KRB5_CALLCONV and KRB5_DLLIMP. +Sun Apr 21 03:07:02 1996 Marc Horowitz <marc@mit.edu> + + * gssapi_generic.c, release_buffer.c, release_oid_set.c: added + files which should have been added before, but either I or commit + was confused. + +Wed Apr 17 20:59:23 1996 Marc Horowitz <marc@mit.edu> + + * oid_ops.c: moved from mechglue + + * util_canonhost.c (g_canonicalize_host): cast the return value of + malloc() + + * gssapiP_generic.h: Added prototypes for oid_ops.c + + * gssapi.h: Make the types of OM_uint32 constants portable, + fix some minor compile-time nits + + * Makefile.in: change the list of files which need to be built + Tue Apr 2 15:31:25 1996 Theodore Y. Ts'o <tytso@dcl> * Makefile.in (SRCS): Inlined list of source files for SRCS and diff --git a/src/lib/gssapi/generic/Makefile.in b/src/lib/gssapi/generic/Makefile.in index 9c90244f2..c9e940962 100644 --- a/src/lib/gssapi/generic/Makefile.in +++ b/src/lib/gssapi/generic/Makefile.in @@ -39,28 +39,40 @@ gssapi_err_generic.c: gssapi_err_generic.et #endif SRCS = \ - $(srcdir)/disp_major_status.c \ $(srcdir)/disp_com_err_status.c \ + $(srcdir)/disp_major_status.c \ + $(srcdir)/gssapi_generic.c \ + $(srcdir)/oid_ops.c \ + $(srcdir)/release_buffer.c \ + $(srcdir)/release_oid_set.c \ $(srcdir)/util_buffer.c \ $(srcdir)/util_canonhost.c \ $(srcdir)/util_dup.c \ $(srcdir)/util_oid.c \ + $(srcdir)/util_ordering.c \ + $(srcdir)/util_set.c \ $(srcdir)/util_token.c \ - $(srcdir)/utl_nohash_validate.c \ + $(srcdir)/util_validate.c \ gssapi_err_generic.c OBJS = \ - disp_major_status.$(OBJEXT) \ disp_com_err_status.$(OBJEXT) \ + disp_major_status.$(OBJEXT) \ + gssapi_generic.$(OBJEXT) \ + oid_ops.$(OBJEXT) \ + release_buffer.$(OBJEXT) \ + release_oid_set.$(OBJEXT) \ util_buffer.$(OBJEXT) \ util_canonhost.$(OBJEXT) \ util_dup.$(OBJEXT) \ util_oid.$(OBJEXT) \ + util_ordering.$(OBJEXT) \ + util_set.$(OBJEXT) \ util_token.$(OBJEXT) \ - utl_nohash_validate.$(OBJEXT) \ + util_validate.$(OBJEXT) \ gssapi_err_generic.$(OBJEXT) -EHDRDIR= $(BUILDTOP)$(S)include$(S)gssapi +EHDRDIR= $(BUILDTOP)/include/gssapi EXPORTED_HEADERS= gssapi.h gssapi_generic.h HDRS= $(ETHDRS) @@ -89,8 +101,8 @@ clean-windows:: # Krb5InstallHeaders($(EXPORTED_HEADERS), $(KRB5_INCDIR)/krb5) install:: @set -x; for f in $(EXPORTED_HEADERS) ; \ - do $(INSTALL_DATA) $(srcdir)$(S)$$f \ - $(DESTDIR)$(KRB5_INCDIR)$(S)gssapi$(S)$$f ; \ + do $(INSTALL_DATA) $(srcdir)/$$f \ + $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \ done depend:: $(ETSRCS) diff --git a/src/lib/gssapi/generic/disp_com_err_status.c b/src/lib/gssapi/generic/disp_com_err_status.c index 79b5fbbe2..c4db91375 100644 --- a/src/lib/gssapi/generic/disp_com_err_status.c +++ b/src/lib/gssapi/generic/disp_com_err_status.c @@ -20,6 +20,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_generic.h" #include "com_err.h" diff --git a/src/lib/gssapi/generic/disp_major_status.c b/src/lib/gssapi/generic/disp_major_status.c index ad0b17f20..4dd91d25f 100644 --- a/src/lib/gssapi/generic/disp_major_status.c +++ b/src/lib/gssapi/generic/disp_major_status.c @@ -23,6 +23,10 @@ #include "gssapiP_generic.h" #include <string.h> +/* + * $Id$ + */ + /* This code has knowledge of the min and max errors of each type within the gssapi major status */ diff --git a/src/lib/gssapi/generic/gssapi.h b/src/lib/gssapi/generic/gssapi.h index 2b2e6002b..28cc4ca41 100644 --- a/src/lib/gssapi/generic/gssapi.h +++ b/src/lib/gssapi/generic/gssapi.h @@ -131,14 +131,6 @@ typedef unsigned int uid_t; #endif #endif -#ifndef NPROTOTYPE -#if defined(__ultrix) && !defined (__GNUC__) -#define NPROTOTYPE(x) () -#else -#define NPROTOTYPE(x) PROTOTYPE(x) -#endif -#endif - /* * First, include stddef.h to get size_t defined. */ @@ -161,8 +153,13 @@ typedef unsigned int uid_t; #endif /* HAVE_XOM_H */ /* + * $Id$ + */ + +/* * First, define the three platform-dependent pointer types. */ + typedef void FAR * gss_name_t; typedef void FAR * gss_cred_id_t; typedef void FAR * gss_ctx_id_t; @@ -305,7 +302,7 @@ typedef int gss_cred_usage_t; * Expiration time of 2^32-1 seconds means infinite lifetime for a * credential or security context */ -#define GSS_C_INDEFINITE 0xffffffffl +#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful) /* Major status codes */ @@ -318,9 +315,9 @@ typedef int gss_cred_usage_t; #define GSS_C_CALLING_ERROR_OFFSET 24 #define GSS_C_ROUTINE_ERROR_OFFSET 16 #define GSS_C_SUPPLEMENTARY_OFFSET 0 -#define GSS_C_CALLING_ERROR_MASK 0377l -#define GSS_C_ROUTINE_ERROR_MASK 0377l -#define GSS_C_SUPPLEMENTARY_MASK 0177777l +#define GSS_C_CALLING_ERROR_MASK ((OM_uint32) 0377ul) +#define GSS_C_ROUTINE_ERROR_MASK ((OM_uint32) 0377ul) +#define GSS_C_SUPPLEMENTARY_MASK ((OM_uint32) 0177777ul) /* * The macros that test status codes for error conditions. Note that the @@ -345,43 +342,51 @@ typedef int gss_cred_usage_t; * Calling errors: */ #define GSS_S_CALL_INACCESSIBLE_READ \ - (1l << GSS_C_CALLING_ERROR_OFFSET) + (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET) #define GSS_S_CALL_INACCESSIBLE_WRITE \ - (2l << GSS_C_CALLING_ERROR_OFFSET) + (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET) #define GSS_S_CALL_BAD_STRUCTURE \ - (3l << GSS_C_CALLING_ERROR_OFFSET) + (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET) /* * Routine errors: */ -#define GSS_S_BAD_MECH (1l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_NAME (2l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_NAMETYPE (3l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_BINDINGS (4l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_STATUS (5l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_SIG (6l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_NO_CRED (7l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_NO_CONTEXT (8l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_DEFECTIVE_TOKEN (9l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_DEFECTIVE_CREDENTIAL (10l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_CREDENTIALS_EXPIRED (11l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_CONTEXT_EXPIRED (12l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_FAILURE (13l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_BAD_QOP (14l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_UNAUTHORIZED (15l << GSS_C_ROUTINE_ERROR_OFFSET) -#define GSS_S_UNAVAILABLE (16l << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_MECH (((OM_uint32) 1ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAME (((OM_uint32) 2ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_NAMETYPE (((OM_uint32) 3ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_BINDINGS (((OM_uint32) 4ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_STATUS (((OM_uint32) 5ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_SIG (((OM_uint32) 6ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CRED (((OM_uint32) 7ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NO_CONTEXT (((OM_uint32) 8ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_TOKEN (((OM_uint32) 9ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DEFECTIVE_CREDENTIAL \ + (((OM_uint32) 10ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CREDENTIALS_EXPIRED \ + (((OM_uint32) 11ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_CONTEXT_EXPIRED \ + (((OM_uint32) 12ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_FAILURE (((OM_uint32) 13ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_BAD_QOP (((OM_uint32) 14ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAUTHORIZED (((OM_uint32) 15ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_UNAVAILABLE (((OM_uint32) 16ul) << GSS_C_ROUTINE_ERROR_OFFSET) /* * XXX new functions. Check to get official error number assigments? */ -#define GSS_S_DUPLICATE_ELEMENT (17l << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_DUPLICATE_ELEMENT \ + (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET) /* * Supplementary info bits: */ -#define GSS_S_CONTINUE_NEEDED (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) -#define GSS_S_DUPLICATE_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) -#define GSS_S_OLD_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) -#define GSS_S_UNSEQ_TOKEN (1l << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +#define GSS_S_CONTINUE_NEEDED (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 0)) +#define GSS_S_DUPLICATE_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 1)) +#define GSS_S_OLD_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 2)) +#define GSS_S_UNSEQ_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 3)) +/* + * XXX not in the cbindings yet. remove this comment when it is + */ +#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) /* diff --git a/src/lib/gssapi/generic/gssapiP_generic.h b/src/lib/gssapi/generic/gssapiP_generic.h index a882f6139..e0bb28d44 100644 --- a/src/lib/gssapi/generic/gssapiP_generic.h +++ b/src/lib/gssapi/generic/gssapiP_generic.h @@ -23,7 +23,10 @@ #ifndef _GSSAPIP_GENERIC_H_ #define _GSSAPIP_GENERIC_H_ -#include "k5-int.h" +/* + * $Id$ + */ + #include "gssapi.h" #include "gssapi_err_generic.h" @@ -86,6 +89,14 @@ /** helper functions **/ +typedef struct _g_set *g_set; + +int g_set_init PROTOTYPE((g_set *s)); +int g_set_destroy PROTOTYPE((g_set *s)); +int g_set_entry_add PROTOTYPE((g_set *s, void *key, void *value)); +int g_set_entry_delete PROTOTYPE((g_set *s, void *key)); +int g_set_entry_get PROTOTYPE((g_set *s, void *key, void **value)); + int g_save_name PROTOTYPE((void **vdb, gss_name_t *name)); int g_save_cred_id PROTOTYPE((void **vdb, gss_cred_id_t *cred)); int g_save_ctx_id PROTOTYPE((void **vdb, gss_ctx_id_t *ctx)); @@ -119,8 +130,64 @@ OM_uint32 g_display_com_err_status PROTOTYPE((OM_uint32 *minor_status, OM_uint32 status_value, gss_buffer_t status_string)); -char * g_canonicalize_host PROTOTYPE((char *hostname)); - -char * g_strdup PROTOTYPE((char *str)); +OM_uint32 g_order_init PROTOTYPE((void **queue, unsigned int seqnum, + int do_replay, int do_sequence)); + +OM_uint32 g_order_check PROTOTYPE((void **queue, unsigned int seqnum)); + +void g_order_free PROTOTYPE((void **queue)); + +char *g_canonicalize_host PROTOTYPE((char *hostname)); +char *g_local_host_name PROTOTYPE((void)); + +char *g_strdup PROTOTYPE((char *str)); + +/** declarations of internal name mechanism functions **/ + +OM_uint32 generic_gss_release_buffer +PROTOTYPE((OM_uint32*, /* minor_status */ + gss_buffer_t /* buffer */ + )); + +OM_uint32 generic_gss_release_oid_set +PROTOTYPE((OM_uint32*, /* minor_status */ + gss_OID_set* /* set */ + )); + +OM_uint32 generic_gss_copy_oid +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_OID, /* oid */ + gss_OID * /* new_oid */ + )); + +OM_uint32 generic_gss_create_empty_oid_set +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_OID_set * /* oid_set */ + )); + +OM_uint32 generic_gss_add_oid_set_member +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_OID, /* member_oid */ + gss_OID_set * /* oid_set */ + )); + +OM_uint32 generic_gss_test_oid_set_member +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_OID, /* member */ + gss_OID_set, /* set */ + int * /* present */ + )); + +OM_uint32 generic_gss_oid_to_str +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_OID, /* oid */ + gss_buffer_t /* oid_str */ + )); + +OM_uint32 generic_gss_str_to_oid +PROTOTYPE( (OM_uint32 *, /* minor_status */ + gss_buffer_t, /* oid_str */ + gss_OID * /* oid */ + )); #endif /* _GSSAPIP_GENERIC_H_ */ diff --git a/src/lib/gssapi/generic/gssapi_err_generic.et b/src/lib/gssapi/generic/gssapi_err_generic.et index 91d958d12..ddeed4227 100644 --- a/src/lib/gssapi/generic/gssapi_err_generic.et +++ b/src/lib/gssapi/generic/gssapi_err_generic.et @@ -20,6 +20,10 @@ # PERFORMANCE OF THIS SOFTWARE. # +# +# $Id$ +# + error_table ggss error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string" @@ -31,5 +35,9 @@ error_code G_BAD_MSG_CTX, "Message context invalid" error_code G_WRONG_SIZE, "Buffer is the wrong size" error_code G_BAD_USAGE, "Credential usage type is unknown" error_code G_UNKNOWN_QOP, "Unknown quality of protection specified" +error_code G_NO_HOSTNAME, "Local host name could not be determined" error_code G_BAD_HOSTNAME, "Hostname in SERVICE-NAME string could not be canonicalized" +error_code G_WRONG_MECH, "Mechanism is incorrect" +error_code G_BAD_TOK_HEADER, "Token header is malformed or corrupt" +error_code G_BAD_DIRECTION, "Packet was replayed in wrong direction" end diff --git a/src/lib/gssapi/generic/gssapi_generic.c b/src/lib/gssapi/generic/gssapi_generic.c new file mode 100644 index 000000000..7072329b7 --- /dev/null +++ b/src/lib/gssapi/generic/gssapi_generic.c @@ -0,0 +1,59 @@ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * $Id$ + */ + +#include "gssapiP_generic.h" + +/* + * See krb5/gssapi_krb5.c for a description of the algorithm for + * encoding an object identifier. + */ + +/* + * The OID of user_name is: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * generic(1) user_name(1) = 1.2.840.113554.1.2.1.1 + * machine_uid_name: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * generic(1) machine_uid_name(2) = 1.2.840.113554.1.2.1.2 + * string_uid_name: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * generic(1) string_uid_name(3) = 1.2.840.113554.1.2.1.3 + * service_name: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4) = 1.2.840.113554.1.2.1.4 + */ + +static gss_OID_desc oids[] = { + {10, "\052\206\110\206\367\022\001\002\001\001"}, + {10, "\052\206\110\206\367\022\001\002\001\002"}, + {10, "\052\206\110\206\367\022\001\002\001\003"}, + {10, "\052\206\110\206\367\022\001\002\001\004"}, +}; + +gss_OID gss_nt_user_name = oids+0; +gss_OID gss_nt_machine_uid_name = oids+1; +gss_OID gss_nt_string_uid_name = oids+2; +gss_OID gss_nt_service_name = oids+3; diff --git a/src/lib/gssapi/generic/gssapi_generic.h b/src/lib/gssapi/generic/gssapi_generic.h index fe2282796..88c054788 100644 --- a/src/lib/gssapi/generic/gssapi_generic.h +++ b/src/lib/gssapi/generic/gssapi_generic.h @@ -23,6 +23,10 @@ #ifndef _GSSAPI_GENERIC_H_ #define _GSSAPI_GENERIC_H_ +/* + * $Id$ + */ + #if defined(__MWERKS__) || defined(applec) || defined(THINK_C) #include <gssapi.h> #else diff --git a/src/lib/gssapi/generic/oid_ops.c b/src/lib/gssapi/generic/oid_ops.c new file mode 100644 index 000000000..38d73f429 --- /dev/null +++ b/src/lib/gssapi/generic/oid_ops.c @@ -0,0 +1,385 @@ +/* + * lib/gssapi/generic/oid_ops.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs + */ + +#include "gssapiP_generic.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <ctype.h> + +#if 0 +OM_uint32 +generic_gss_release_oid(minor_status, oid) + OM_uint32 *minor_status; + gss_OID *oid; +{ + *minor_status = 0; + + if (*oid == GSS_C_NO_OID) + return(GSS_S_COMPLETE); + + /* + * The V2 API says the following! + * + * gss_release_oid[()] will recognize any of the GSSAPI's own OID values, + * and will silently ignore attempts to free these OIDs; for other OIDs + * it will call the C free() routine for both the OID data and the + * descriptor. This allows applications to freely mix their own heap- + * allocated OID values with OIDs returned by GSS-API. + */ + if ((*oid != gss_nt_user_name) && + (*oid != gss_nt_machine_uid_name) && + (*oid != gss_nt_string_uid_name) && + (*oid != gss_nt_service_name)) { + free((*oid)->elements); + free(*oid); + } + *oid = GSS_C_NO_OID; + return(GSS_S_COMPLETE); +} +#endif + +OM_uint32 +generic_gss_copy_oid(minor_status, oid, new_oid) + OM_uint32 *minor_status; + gss_OID oid, *new_oid; +{ + gss_OID p; + + p = (gss_OID) malloc(sizeof(gss_OID_desc)); + if (!p) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + p->length = oid->length; + p->elements = malloc(p->length); + if (!p->elements) { + free(p); + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + memcpy(p->elements, oid->elements, p->length); + *new_oid = p; + return(GSS_S_COMPLETE); +} + + +OM_uint32 +generic_gss_create_empty_oid_set(minor_status, oid_set) + OM_uint32 *minor_status; + gss_OID_set *oid_set; +{ + if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) { + memset(*oid_set, 0, sizeof(gss_OID_set_desc)); + *minor_status = 0; + return(GSS_S_COMPLETE); + } + else { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } +} + +OM_uint32 +generic_gss_add_oid_set_member(minor_status, member_oid, oid_set) + OM_uint32 *minor_status; + gss_OID member_oid; + gss_OID_set *oid_set; +{ + gss_OID elist; + gss_OID lastel; + + elist = (*oid_set)->elements; + /* Get an enlarged copy of the array */ + if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) * + sizeof(gss_OID_desc)))) { + /* Copy in the old junk */ + if (elist) + memcpy((*oid_set)->elements, + elist, + ((*oid_set)->count * sizeof(gss_OID_desc))); + + /* Duplicate the input element */ + lastel = &(*oid_set)->elements[(*oid_set)->count]; + if ((lastel->elements = + (void *) malloc((size_t) member_oid->length))) { + /* Success - copy elements */ + memcpy(lastel->elements, member_oid->elements, + (size_t) member_oid->length); + /* Set length */ + lastel->length = member_oid->length; + + /* Update count */ + (*oid_set)->count++; + if (elist) + free(elist); + *minor_status = 0; + return(GSS_S_COMPLETE); + } + else + free((*oid_set)->elements); + } + /* Failure - restore old contents of list */ + (*oid_set)->elements = elist; + *minor_status = ENOMEM; + return(GSS_S_FAILURE); +} + +OM_uint32 +generic_gss_test_oid_set_member(minor_status, member, set, present) + OM_uint32 *minor_status; + gss_OID member; + gss_OID_set set; + int *present; +{ + size_t i; + int result; + + result = 0; + for (i=0; i<set->count; i++) { + if ((set->elements[i].length == member->length) && + !memcmp(set->elements[i].elements, + member->elements, + (size_t) member->length)) { + result = 1; + break; + } + } + *present = result; + *minor_status = 0; + return(GSS_S_COMPLETE); +} + +/* + * OID<->string routines. These are uuuuugly. + */ +OM_uint32 +generic_gss_oid_to_str(minor_status, oid, oid_str) + OM_uint32 *minor_status; + gss_OID oid; + gss_buffer_t oid_str; +{ + char numstr[128]; + unsigned long number; + int numshift; + size_t string_length; + size_t i; + unsigned char *cp; + char *bp; + + /* Decoded according to krb5/gssapi_krb5.c */ + + /* First determine the size of the string */ + string_length = 0; + number = 0; + numshift = 0; + cp = (unsigned char *) oid->elements; + number = (unsigned long) cp[0]; + sprintf(numstr, "%ld ", number/40); + string_length += strlen(numstr); + sprintf(numstr, "%ld ", number%40); + string_length += strlen(numstr); + for (i=1; i<oid->length; i++) { + if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { + number = (number << 7) | (cp[i] & 0x7f); + numshift += 7; + } + else { + *minor_status = EINVAL; + return(GSS_S_FAILURE); + } + if ((cp[i] & 0x80) == 0) { + sprintf(numstr, "%ld ", number); + string_length += strlen(numstr); + number = 0; + numshift = 0; + } + } + /* + * If we get here, we've calculated the length of "n n n ... n ". Add 4 + * here for "{ " and "}\0". + */ + string_length += 4; + if ((bp = (char *) malloc(string_length))) { + strcpy(bp, "{ "); + number = (unsigned long) cp[0]; + sprintf(numstr, "%ld ", number/40); + strcat(bp, numstr); + sprintf(numstr, "%ld ", number%40); + strcat(bp, numstr); + number = 0; + cp = (unsigned char *) oid->elements; + for (i=1; i<oid->length; i++) { + number = (number << 7) | (cp[i] & 0x7f); + if ((cp[i] & 0x80) == 0) { + sprintf(numstr, "%ld ", number); + strcat(bp, numstr); + number = 0; + } + } + strcat(bp, "}"); + oid_str->length = strlen(bp)+1; + oid_str->value = (void *) bp; + *minor_status = 0; + return(GSS_S_COMPLETE); + } + *minor_status = ENOMEM; + return(GSS_S_FAILURE); +} + +OM_uint32 +generic_gss_str_to_oid(minor_status, oid_str, oid) + OM_uint32 *minor_status; + gss_buffer_t oid_str; + gss_OID *oid; +{ + char *cp, *bp, *startp; + int brace; + long numbuf; + long onumbuf; + OM_uint32 nbytes; + int index; + unsigned char *op; + + brace = 0; + bp = (char *) oid_str->value; + cp = bp; + /* Skip over leading space */ + while ((bp < &cp[oid_str->length]) && isspace(*bp)) + bp++; + if (*bp == '{') { + brace = 1; + bp++; + } + while ((bp < &cp[oid_str->length]) && isspace(*bp)) + bp++; + startp = bp; + nbytes = 0; + + /* + * The first two numbers are chewed up by the first octet. + */ + if (sscanf(bp, "%ld", &numbuf) != 1) { + *minor_status = EINVAL; + return(GSS_S_FAILURE); + } + while ((bp < &cp[oid_str->length]) && isdigit(*bp)) + bp++; + while ((bp < &cp[oid_str->length]) && isspace(*bp)) + bp++; + if (sscanf(bp, "%ld", &numbuf) != 1) { + *minor_status = EINVAL; + return(GSS_S_FAILURE); + } + while ((bp < &cp[oid_str->length]) && isdigit(*bp)) + bp++; + while ((bp < &cp[oid_str->length]) && isspace(*bp)) + bp++; + nbytes++; + while (isdigit(*bp)) { + if (sscanf(bp, "%ld", &numbuf) != 1) { + *minor_status = EINVAL; + return(GSS_S_FAILURE); + } + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + while ((bp < &cp[oid_str->length]) && isdigit(*bp)) + bp++; + while ((bp < &cp[oid_str->length]) && isspace(*bp)) + bp++; + } + if (brace && (*bp != '}')) { + *minor_status = EINVAL; + return(GSS_S_FAILURE); + } + + /* + * Phew! We've come this far, so the syntax is good. + */ + if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) { + if (((*oid)->elements = (void *) malloc((size_t) nbytes))) { + (*oid)->length = nbytes; + op = (unsigned char *) (*oid)->elements; + bp = startp; + sscanf(bp, "%ld", &numbuf); + while (isdigit(*bp)) + bp++; + while (isspace(*bp)) + bp++; + onumbuf = 40*numbuf; + sscanf(bp, "%ld", &numbuf); + onumbuf += numbuf; + *op = (unsigned char) onumbuf; + op++; + while (isdigit(*bp)) + bp++; + while (isspace(*bp)) + bp++; + while (isdigit(*bp)) { + sscanf(bp, "%ld", &numbuf); + nbytes = 0; + /* Have to fill in the bytes msb-first */ + onumbuf = numbuf; + while (numbuf) { + nbytes++; + numbuf >>= 7; + } + numbuf = onumbuf; + op += nbytes; + index = -1; + while (numbuf) { + op[index] = (unsigned char) numbuf & 0x7f; + if (index != -1) + op[index] |= 0x80; + index--; + numbuf >>= 7; + } + while (isdigit(*bp)) + bp++; + while (isspace(*bp)) + bp++; + } + *minor_status = 0; + return(GSS_S_COMPLETE); + } + else { + free(*oid); + *oid = GSS_C_NO_OID; + } + } + *minor_status = ENOMEM; + return(GSS_S_FAILURE); +} + diff --git a/src/lib/gssapi/generic/release_buffer.c b/src/lib/gssapi/generic/release_buffer.c new file mode 100644 index 000000000..d367ef31e --- /dev/null +++ b/src/lib/gssapi/generic/release_buffer.c @@ -0,0 +1,58 @@ +/* #ident "@(#)g_rel_buffer.c 1.2 96/02/06 SMI" */ + +/* + * Copyright 1996 by Sun Microsystems, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Sun Microsystems not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Sun Microsystems makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * glue routine for gss_release_buffer + */ + +#include "gssapiP_generic.h" + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +OM_uint32 INTERFACE +generic_gss_release_buffer (minor_status, + buffer) + OM_uint32 * minor_status; + gss_buffer_t buffer; +{ + if (minor_status) + *minor_status = 0; + + /* if buffer is NULL, return */ + + if (buffer == GSS_C_NO_BUFFER) + return(GSS_S_COMPLETE); + + if ((buffer->length) && + (buffer->value)) { + free(buffer->value); + buffer->length = 0; + buffer->value = NULL; + } + + return (GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/generic/release_oid_set.c b/src/lib/gssapi/generic/release_oid_set.c new file mode 100644 index 000000000..01e814bcb --- /dev/null +++ b/src/lib/gssapi/generic/release_oid_set.c @@ -0,0 +1,62 @@ +/* #ident "@(#)gss_release_oid_set.c 1.12 95/08/23 SMI" */ + +/* + * Copyright 1996 by Sun Microsystems, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Sun Microsystems not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. Sun Microsystems makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * glue routine for gss_release_oid_set + */ + +#include "gssapiP_generic.h" + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +OM_uint32 INTERFACE +generic_gss_release_oid_set (minor_status, + set) + OM_uint32 * minor_status; + gss_OID_set * set; +{ + size_t i; + gss_OID oid; + if (minor_status) + *minor_status = 0; + + if (set == NULL) + return(GSS_S_COMPLETE); + + if (*set == GSS_C_NULL_OID_SET) + return(GSS_S_COMPLETE); + + for (i=0; i<(*set)->count; i++) + free((*set)->elements[i].elements); + + free((*set)->elements); + free(*set); + + *set = GSS_C_NULL_OID_SET; + + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/generic/util_buffer.c b/src/lib/gssapi/generic/util_buffer.c index cf144495f..e715834d9 100644 --- a/src/lib/gssapi/generic/util_buffer.c +++ b/src/lib/gssapi/generic/util_buffer.c @@ -20,6 +20,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_generic.h" #include <string.h> diff --git a/src/lib/gssapi/generic/util_canonhost.c b/src/lib/gssapi/generic/util_canonhost.c index 896b950b1..900834f40 100644 --- a/src/lib/gssapi/generic/util_canonhost.c +++ b/src/lib/gssapi/generic/util_canonhost.c @@ -20,10 +20,16 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + /* This file could be OS specific */ -#define NEED_SOCKETS + #include "gssapiP_generic.h" +#include "port-sockets.h" + #ifndef _MACINTOSH #include <sys/types.h> #endif @@ -41,7 +47,7 @@ g_canonicalize_host(hostname) if ((hent = gethostbyname(hostname)) == NULL) return(NULL); - if (! (haddr = xmalloc(hent->h_length))) { + if (! (haddr = (char *) xmalloc(hent->h_length))) { return(NULL); } @@ -53,7 +59,7 @@ g_canonicalize_host(hostname) xfree(haddr); - if ((canon = xmalloc(strlen(hent->h_name)+1)) == NULL) + if ((canon = (char *) xmalloc(strlen(hent->h_name)+1)) == NULL) return(NULL); strcpy(canon, hent->h_name); diff --git a/src/lib/gssapi/generic/util_dup.c b/src/lib/gssapi/generic/util_dup.c index 6b19092db..d601ceef2 100644 --- a/src/lib/gssapi/generic/util_dup.c +++ b/src/lib/gssapi/generic/util_dup.c @@ -20,6 +20,10 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_generic.h" #include <string.h> diff --git a/src/lib/gssapi/generic/util_oid.c b/src/lib/gssapi/generic/util_oid.c index 91bb544ed..8843a7ff6 100644 --- a/src/lib/gssapi/generic/util_oid.c +++ b/src/lib/gssapi/generic/util_oid.c @@ -22,6 +22,10 @@ #include "gssapiP_generic.h" +/* + * $Id$ + */ + int g_copy_OID_set(in, out) const gss_OID_set_desc * const in; diff --git a/src/lib/gssapi/generic/util_token.c b/src/lib/gssapi/generic/util_token.c index e440d907a..027d2a765 100644 --- a/src/lib/gssapi/generic/util_token.c +++ b/src/lib/gssapi/generic/util_token.c @@ -23,11 +23,9 @@ #include "gssapiP_generic.h" #include <memory.h> -#if (SIZEOF_INT == 2) -#define VALID_INT_BITS 0x7fff -#elif (SIZEOF_INT == 4) -#define VALID_INT_BITS 0x7fffffff -#endif +/* + * $Id$ + */ /* XXXX this code currently makes the assumption that a mech oid will never be longer than 127 bytes. This assumption is not inherent in @@ -153,58 +151,68 @@ void g_make_token_header(mech, body_size, buf, tok_type) *(*buf)++ = (unsigned char) (tok_type&0xff); } -/* given a buffer containing a token, reads and verifies the token, - leaving buf advanced past the token header, and setting body_size - to the number of remaining bytes */ - -int g_verify_token_header(mech, body_size, buf, tok_type, toksize) +/* + * Given a buffer containing a token, reads and verifies the token, + * leaving buf advanced past the token header, and setting body_size + * to the number of remaining bytes. Returns 0 on success, + * G_BAD_TOK_HEADER for a variety of errors, and G_WRONG_MECH if the + * mechanism in the token does not match the mech argument. buf and + * *body_size are left unmodified on error. + */ +int g_verify_token_header(mech, body_size, buf_in, tok_type, toksize) gss_OID mech; int *body_size; - unsigned char **buf; + unsigned char **buf_in; int tok_type; int toksize; { + char *buf = *buf_in; int seqsize; gss_OID_desc toid; + int ret = 0; if ((toksize-=1) < 0) - return(0); - if (*(*buf)++ != 0x60) - return(0); + return(G_BAD_TOK_HEADER); + if (*buf++ != 0x60) + return(G_BAD_TOK_HEADER); - if ((seqsize = der_read_length(buf, &toksize)) < 0) - return(0); + if ((seqsize = der_read_length(&buf, &toksize)) < 0) + return(G_BAD_TOK_HEADER); if (seqsize != toksize) - return(0); + return(G_BAD_TOK_HEADER); if ((toksize-=1) < 0) - return(0); - if (*(*buf)++ != 0x06) - return(0); + return(G_BAD_TOK_HEADER); + if (*buf++ != 0x06) + return(G_BAD_TOK_HEADER); if ((toksize-=1) < 0) - return(0); - toid.length = *(*buf)++; - - if ((toid.length & VALID_INT_BITS) != toid.length) /* Overflow??? */ - return(0); - if ((toksize-= (int) toid.length) < 0) - return(0); - toid.elements = *buf; - (*buf)+=toid.length; - - if (! g_OID_equal(&toid, mech)) - return(0); + return(G_BAD_TOK_HEADER); + toid.length = *buf++; + + if ((toksize-=toid.length) < 0) + return(G_BAD_TOK_HEADER); + toid.elements = buf; + buf+=toid.length; + + if (! g_OID_equal(&toid, mech)) + ret = G_WRONG_MECH; + /* G_WRONG_MECH is not returned immediately because it's more important + to return G_BAD_TOK_HEADER if the token header is in fact bad */ + if ((toksize-=2) < 0) - return(0); + return(G_BAD_TOK_HEADER); - if ((*(*buf)++ != ((tok_type>>8)&0xff)) || - (*(*buf)++ != (tok_type&0xff))) - return(0); + if ((*buf++ != ((tok_type>>8)&0xff)) || + (*buf++ != (tok_type&0xff))) + return(G_BAD_TOK_HEADER); - *body_size = toksize; + if (!ret) { + *buf_in = buf; + *body_size = toksize; + } - return(1); + return(ret); } diff --git a/src/lib/gssapi/generic/util_validate.c b/src/lib/gssapi/generic/util_validate.c index 72631341b..63f552859 100644 --- a/src/lib/gssapi/generic/util_validate.c +++ b/src/lib/gssapi/generic/util_validate.c @@ -21,6 +21,10 @@ */ /* + * $Id$ + */ + +/* * functions to validate name, credential, and context handles */ @@ -30,24 +34,31 @@ #include <sys/file.h> #include <fcntl.h> #include <limits.h> +#ifdef HAVE_BSD_DB #include <db.h> -#define V_NAME 1 -#define V_CRED_ID 2 -#define V_CTX_ID 3 +static const int one = 1; +static const DBT dbtone = { (void *) &one, sizeof(one) }; typedef struct _vkey { int type; void *ptr; } vkey; +#endif -static const int one = 1; -static const DBT dbtone = { (void *) &one, sizeof(one) }; +#define V_NAME 1 +#define V_CRED_ID 2 +#define V_CTX_ID 3 /* All these functions return 0 on failure, and non-zero on success */ -static int g_save(DB **vdb, int type, void *ptr) +static int g_save(db, type, ptr) + void **db; + int type; + void *ptr; { +#ifdef HAVE_BSD_DB + DB **vdb = (DB **) db; vkey vk; DBT key; @@ -61,10 +72,24 @@ static int g_save(DB **vdb, int type, void *ptr) key.size = sizeof(vk); return((*((*vdb)->put))(*vdb, &key, &dbtone, 0) == 0); +#else + g_set *gs = (g_set *) db; + + if (!*gs) + if (g_set_init(gs)) + return(0); + + return(g_set_entry_add(gs, ptr, (void *) type) == 0); +#endif } -static int g_validate(DB **vdb, int type, void *ptr) +static int g_validate(db, type, ptr) + void **db; + int type; + void *ptr; { +#ifdef HAVE_BSD_DB + DB **vdb = (DB **) db; vkey vk; DBT key, value; @@ -82,10 +107,27 @@ static int g_validate(DB **vdb, int type, void *ptr) return((value.size == sizeof(one)) && (*((int *) value.data) == one)); +#else + g_set *gs = (g_set *) db; + void *value; + + if (!*gs) + return(0); + + if (g_set_entry_get(gs, ptr, (void **) &value)) + return(0); + + return(((int) value) == type); +#endif } -static int g_delete(DB **vdb, int type, void *ptr) +static int g_delete(db, type, ptr) + void **db; + int type; + void *ptr; { +#ifdef HAVE_BSD_DB + DB **vdb = (DB **) db; vkey vk; DBT key; @@ -99,52 +141,81 @@ static int g_delete(DB **vdb, int type, void *ptr) key.size = sizeof(vk); return((*((*vdb)->del))(*vdb, &key, 0) == 0); +#else + g_set *gs = (g_set *) db; + + if (!*gs) + return(0); + + if (g_set_entry_delete(gs, ptr)) + return(0); + + return(1); +#endif } /* functions for each type */ /* save */ -int g_save_name(void **vdb, gss_name_t *name) +int g_save_name(vdb, name) + void **vdb; + gss_name_t *name; { - return(g_save((DB **) vdb, V_NAME, (void *) name)); + return(g_save(vdb, V_NAME, (void *) name)); } -int g_save_cred_id(void **vdb, gss_cred_id_t *cred) +int g_save_cred_id(vdb, cred) + void **vdb; + gss_cred_id_t *cred; { - return(g_save((DB **) vdb, V_CRED_ID, (void *) cred)); + return(g_save(vdb, V_CRED_ID, (void *) cred)); } -int g_save_ctx_id(void **vdb, gss_ctx_id_t *ctx) +int g_save_ctx_id(vdb, ctx) + void **vdb; + gss_ctx_id_t *ctx; { - return(g_save((DB **) vdb, V_CTX_ID, (void *) ctx)); + return(g_save(vdb, V_CTX_ID, (void *) ctx)); } /* validate */ -int g_validate_name(void **vdb, gss_name_t *name) +int g_validate_name(vdb, name) + void **vdb; + gss_name_t *name; { - return(g_validate((DB **) vdb, V_NAME, (void *) name)); + return(g_validate(vdb, V_NAME, (void *) name)); } -int g_validate_cred_id(void **vdb, gss_cred_id_t *cred) +int g_validate_cred_id(vdb, cred) + void **vdb; + gss_cred_id_t *cred; { - return(g_validate((DB **) vdb, V_CRED_ID, (void *) cred)); + return(g_validate(vdb, V_CRED_ID, (void *) cred)); } -int g_validate_ctx_id(void **vdb, gss_ctx_id_t *ctx) +int g_validate_ctx_id(vdb, ctx) + void **vdb; + gss_ctx_id_t *ctx; { - return(g_validate((DB **) vdb, V_CTX_ID, (void *) ctx)); + return(g_validate(vdb, V_CTX_ID, (void *) ctx)); } /* delete */ -int g_delete_name(void **vdb, gss_name_t *name) +int g_delete_name(vdb, name) + void **vdb; + gss_name_t *name; { - return(g_delete((DB **) vdb, V_NAME, (void *) name)); + return(g_delete(vdb, V_NAME, (void *) name)); } -int g_delete_cred_id(void **vdb, gss_cred_id_t *cred) +int g_delete_cred_id(vdb, cred) + void **vdb; + gss_cred_id_t *cred; { - return(g_delete((DB **) vdb, V_CRED_ID, (void *) cred)); + return(g_delete(vdb, V_CRED_ID, (void *) cred)); } -int g_delete_ctx_id(void **vdb, gss_ctx_id_t *ctx) +int g_delete_ctx_id(vdb, ctx) + void **vdb; + gss_ctx_id_t *ctx; { - return(g_delete((DB **) vdb, V_CTX_ID, (void *) ctx)); + return(g_delete(vdb, V_CTX_ID, (void *) ctx)); } diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index 73a09c111..a996733e6 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -1,3 +1,43 @@ +Thu Jul 18 19:48:48 1996 Marc Horowitz <marc@mit.edu> + + * init_sec_context.c (krb5_gss_init_sec_context), + accept_sec_context.c (krb5_gss_accept_sec_context): ifdef'd out + reference to 3des. + +Fri Jul 5 15:27:29 1996 Marc Horowitz <marc@mit.edu> + + * gssapi_krb5.h: Add declarations for _old mech set, and _both + mech set + +Thu Jun 20 23:15:57 1996 Marc Horowitz <marc@mit.edu> + + * ser_sctx.c (kg_oid_size, kg_ctx_size): pull the oid-related code + out of kg_ctx_size into kg_oid_size. + + * k5unseal.c (kg_unseal), k5seal.c (make_seal_token): == cannot be + used to compare oid's. The g_OID_equal macro must be used. + + * init_sec_context.c (make_ap_req, krb5_gss_init_sec_context): - + gss_init_sec_context should use the mech set in the credential. + If the default mech is requested, but the old mech oid was + explicitly passed to gss_acquire_cred, then the context should be + the old mech, otherwise, the new mech. If a mech was requested + explicitly, then the code should insure that the credential is + compatible. + + * acquire_cred.c (krb5_gss_acquire_cred), gssapiP_krb5.h (struct + _krb5_gss_cred_it_rec), gssapi_krb5.c (gss_mech_set_krb5*), + inq_cred.c (krb5_gss_inquire_cred): gss_acquire_cred needs to be + able to deal with both mech oid's. It should return in + actual_mechs the intersection of the set passed in and the + {old,new} mechs, or if the default was requested, it should return + both mech oid's. This state should be stored in the credential + handle, and regurgitated by gss_inquire_cred. + + * accept_sec_context.c (krb5_gss_accept_sec_context): make sure + that the oid in the token is compatible with the mechanisms + specified by the credential. + Thu Jun 13 22:11:30 1996 Tom Yu <tlyu@voltage-multiplier.mit.edu> * configure.in: remove ref to ET_RULES @@ -29,6 +69,63 @@ Tue May 14 04:42:11 1996 Theodore Y. Ts'o <tytso@mit.edu> krb5_auth_con_setcksumtype to use krb5_auth_con_set_req_cksumtype by default instead. +Sun May 12 00:54:35 1996 Marc Horowitz <marc@mit.edu> + + * util_crypt.c (kg_encrypt): It used to be that krb5_encrypt could + be used to encrypt in place. That's broken now. This would need + to be fixed in several places in the crypto layer, and it's not + clear what the right thing is, so it's worked around here in the + interests of portability and reliablility, at the expense of a + malloc/memcpy/free. + + * Makefile.in, configure.in: gssapi_krb5.h should be installed + inside the tree. This is really only half the work, as it should + be installed outside of the tree, too. + +Sat Apr 20 00:02:51 1996 Marc Horowitz <marc@mit.edu> + + * accept_sec_context.c, export_sec_context.c, gssapiP_krb5.h, + import_sec_context.c, init_sec_context.c, k5seal.c, k5unseal.c, + ser_sctx.c, wrap_size_limit.c: Implemented triple-des changes + based on Richard's patches. + +Wed Apr 17 21:08:59 1996 Marc Horowitz <marc@mit.edu> + + * accept_sec_context.c (krb5_gss_set_backward_mode): removed + + * krb5_gss_glue.c, wrap_size_limit.c: added + + * import_sec_context.c: intern the newly created context id so + that the validation functions will accept it. + + * Makefile.in (CFLAGS): Don't need md5 header files anymore. + (OBJS, SRCS): Change the list of files to build. + + * export_sec_context.c, import_sec_context.c, gssapiP_krb5.h, + ser_sctx.c: don't use the serialization abstraction, since it + doesn't add anything, and is internal to kerberos. Instead, make + the {de,}serialization functions internal gssapi functions, and + call those directly. + + * accept_sec_context.c, acquire_cred.c, context_time.c, + delete_sec_context.c, disp_name.c, disp_status.c, + export_sec_context.c, gssapi_krb5.c (kg_get_context), + import_name.c, import_sec_context.c, indicate_mechs.c, + init_sec_context.c, inq_context.c, inq_cred.c, inq_names.c, + process_context_token.c, rel_cred.c, rel_name.c, seal.c, sign.c, + unseal.c, verify.c: + Don't pass in the context from the caller. Instead, call + kg_get_context() to find out the kerberos library context. Also, + random minor compile-time fixes. + + * accept_sec_context.c, gssapi_krb5.c (kg_get_defcred), + gssapiP_krb5.h, init_sec_context.c, k5seal.c, k5unseal.c, + util_cksum.c (kg_checksum_channel_bindings), util_seqnum.c + (kg_make_seq_num, kg_get_seq_num), util_seed.c (kg_make_seed), + util_crypt.c (kg_encrypt, kg_decrypt): + pass the context to the kg_* functions which need it instead of + determining it directly. + Fri Apr 12 21:47:46 1996 Richard Basch <basch@lehman.com> * k5seal.c k5unseal.c: diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in index d5061fa14..4a18efeea 100644 --- a/src/lib/gssapi/krb5/Makefile.in +++ b/src/lib/gssapi/krb5/Makefile.in @@ -1,4 +1,4 @@ -CFLAGS = $(CCOPTS) $(DEFS) -I. -I$(srcdir) -I../generic -I$(srcdir)/../generic -I$(srcdir)/../../crypto/md5 -DUSE_AUTOCONF_H +CFLAGS = $(CCOPTS) $(DEFS) -I. -I$(srcdir) -I../generic -I$(srcdir)/../generic -DUSE_AUTOCONF_H ##DOSBUILDTOP = ..\..\.. ##DOSLIBNAME=..\gssapi.$(LIBEXT) @@ -50,12 +50,10 @@ SRCS = \ $(srcdir)/inq_names.c \ $(srcdir)/k5seal.c \ $(srcdir)/k5unseal.c \ - $(srcdir)/k5mech.c \ - $(srcdir)/pname_to_uid.c \ + $(srcdir)/krb5_gss_glue.c \ $(srcdir)/process_context_token.c \ $(srcdir)/rel_cred.c \ $(srcdir)/rel_name.c \ - $(srcdir)/rel_oid.c \ $(srcdir)/seal.c \ $(srcdir)/ser_sctx.c \ $(srcdir)/sign.c \ @@ -65,8 +63,13 @@ SRCS = \ $(srcdir)/util_seed.c \ $(srcdir)/util_seqnum.c \ $(srcdir)/verify.c \ + $(srcdir)/wrap_size_limit.c \ gssapi_err_krb5.c +# $(srcdir)/pname_to_uid.c \ +# $(srcdir)/k5mech.c \ +# $(srcdir)/rel_oid.c + OBJS = \ accept_sec_context.$(OBJEXT) \ acquire_cred.$(OBJEXT) \ @@ -87,12 +90,10 @@ OBJS = \ inq_names.$(OBJEXT) \ k5seal.$(OBJEXT) \ k5unseal.$(OBJEXT) \ - k5mech.$(OBJEXT) \ - pname_to_uid.$(OBJEXT) \ + krb5_gss_glue.$(OBJEXT) \ process_context_token.$(OBJEXT) \ rel_cred.$(OBJEXT) \ rel_name.$(OBJEXT) \ - rel_oid.$(OBJEXT) \ seal.$(OBJEXT) \ ser_sctx.$(OBJEXT) \ sign.$(OBJEXT) \ @@ -102,15 +103,23 @@ OBJS = \ util_seed.$(OBJEXT) \ util_seqnum.$(OBJEXT) \ verify.$(OBJEXT) \ + wrap_size_limit.$(OBJEXT) \ gssapi_err_krb5.$(OBJEXT) +# k5mech.$(OBJEXT) \ +# pname_to_uid.$(OBJEXT) \ +# rel_oid.$(OBJEXT) + HDRS= $(ETHDRS) EHDRDIR=$(TOP)/include/gssapi +EXPORTED_HEADERS= gssapi_krb5.h all-unix:: $(SRCS) $(HDRS) includes $(OBJS) all-mac:: $(SRCS) $(HDRS) includes $(OBJS) all-windows:: $(SRCS) $(HDRS) includes $(OBJS) + if not exist $(EHDRDIR)\nul mkdir $(EHDRDIR) + copy gssapi_krb5.h $(EHDRDIR) clean-unix:: $(RM) $(ETHDRS) $(ETSRCS) shared/* @@ -119,6 +128,14 @@ clean-mac:: $(RM) $(ETHDRS) $(ETSRCS) shared/* clean-windows:: + $(RM) $(EHDRDIR)\gssapi_krb5.h + if exist $(EHDRDIR)\nul rmdir $(EHDRDIR) + +install:: + @set -x; for f in $(EXPORTED_HEADERS) ; \ + do $(INSTALL_DATA) $(srcdir)/$$f \ + $(DESTDIR)$(KRB5_INCDIR)/gssapi/$$f ; \ + done depend:: $(ETSRCS) diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index 79d41b71d..09ed41247 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -21,9 +21,40 @@ */ #include "gssapiP_krb5.h" -#include "rsa-md5.h" #include <memory.h> +/* + * $Id$ + */ + +#if 0 + +/* XXXX This widen/narrow stuff is bletcherous, but it seems to be + necessary. Perhaps there is a "better" way, but I don't know what it + is */ + +#include <krb5/widen.h> +static krb5_error_code +rd_req_keyproc(krb5_pointer keyprocarg, krb5_principal server, + krb5_kvno kvno, krb5_keyblock **keyblock) +#include <krb5/narrow.h> +{ + krb5_error_code code; + krb5_keytab_entry ktentry; + + if (code = krb5_kt_get_entry((krb5_keytab) keyprocarg, server, kvno, + &ktentry)) + return(code); + + code = krb5_copy_keyblock(&ktentry.key, keyblock); + + (void) krb5_kt_free_entry(&ktentry); + + return(code); +} + +#endif + /* Decode, decrypt and store the forwarded creds in the local ccache. */ static krb5_error_code rd_and_store_for_creds(context, auth_context, inbuf) @@ -56,12 +87,11 @@ cleanup: } OM_uint32 -krb5_gss_accept_sec_context(ct, minor_status, context_handle, +krb5_gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle, input_token, input_chan_bindings, src_name, mech_type, output_token, ret_flags, time_rec, delegated_cred_handle) - void *ct; OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_cred_id_t verifier_cred_handle; @@ -74,7 +104,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, OM_uint32 *time_rec; gss_cred_id_t *delegated_cred_handle; { - krb5_context context = ct; + krb5_context context; unsigned char *ptr, *ptr2; char *sptr; long tmp; @@ -89,14 +119,20 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, krb5_principal name; int gss_flags; krb5_gss_ctx_id_rec *ctx; + krb5_enctype enctype; krb5_timestamp now; gss_buffer_desc token; + int err; krb5_auth_context auth_context = NULL; krb5_ticket * ticket = NULL; int option_id; krb5_data option; krb5_auth_context auth_context_cred = NULL; + const gss_OID_desc *mech_used = NULL; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); /* set up returns to be freeable */ @@ -141,14 +177,43 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, return(GSS_S_NO_CRED); } - /* verify the token's integrity, and leave the token in ap_req */ + /* verify the token's integrity, and leave the token in ap_req. + figure out which mech oid was used, and save it */ ptr = (unsigned char *) input_token->value; - if (! g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length), - &ptr, KG_TOK_CTX_AP_REQ, input_token->length)) { - *minor_status = 0; - return(GSS_S_DEFECTIVE_TOKEN); + if (err = g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length)) { + /* + * Previous versions of this library used the old mech_id + * and some broken behavior (wrong IV on checksum + * encryption). We support the old mech_id for + * compatibility, and use it to decide when to use the + * old behavior. + */ + if (err != G_WRONG_MECH || + (err = g_verify_token_header((gss_OID) gss_mech_krb5_old, + &(ap_req.length), + &ptr, KG_TOK_CTX_AP_REQ, + input_token->length))) { + *minor_status = err; + return(GSS_S_DEFECTIVE_TOKEN); + } else { + if (! cred->prerfc_mech) { + *minor_status = G_WRONG_MECH; + return(GSS_S_DEFECTIVE_TOKEN); + } + + mech_used = gss_mech_krb5_old; + } + } else { + if (! cred->rfc_mech) { + *minor_status = G_WRONG_MECH; + return(GSS_S_DEFECTIVE_TOKEN); + } + + mech_used = gss_mech_krb5; } sptr = (char *) ptr; @@ -180,6 +245,17 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, krb5_auth_con_getauthenticator(context, auth_context, &authdat); +#if 0 + /* make sure the necessary parts of the authdat are present */ + + if ((authdat->authenticator->subkey == NULL) || + (authdat->ticket->enc_part2 == NULL)) { + krb5_free_tkt_authent(authdat); + *minor_status = KG_NO_SUBKEY; + return(GSS_S_FAILURE); + } +#endif + /* verify that the checksum is correct */ /* @@ -210,13 +286,13 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, TREAD_INT(ptr, tmp, bigend); - if (tmp != RSA_MD5_CKSUM_LENGTH) { + if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) { ptr = (unsigned char *) authdat->checksum->contents; bigend = 1; TREAD_INT(ptr, tmp, bigend); - if (tmp != RSA_MD5_CKSUM_LENGTH) { + if (tmp != krb5_checksum_size(context, CKSUMTYPE_RSA_MD5)) { xfree(md5.contents); krb5_free_authenticator(context, authdat); *minor_status = KG_BAD_LENGTH; @@ -226,7 +302,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, /* at this point, bigend is set according to the initiator's byte order */ - if ((code = kg_checksum_channel_bindings(input_chan_bindings, &md5, + if ((code = kg_checksum_channel_bindings(context, input_chan_bindings, &md5, bigend))) { krb5_free_authenticator(context, authdat); *minor_status = code; @@ -289,21 +365,13 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, break; - default : + /* default: */ + /* unknown options aren't an error */ - /* any other options are unrecognized. return - generic GSS_C_FAILURE error with a minor status - of KRB5_PARSE_MALFORMED (XXX this is probably - not the right error, since it is used for - string parsing errors not token parsing errors.) */ - - *minor_status = KRB5_PARSE_MALFORMED; - return(GSS_S_FAILURE); } /* switch */ } /* while */ } /* if */ - /* create the ctx struct and start filling it in */ if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec))) @@ -313,6 +381,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, } memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); + ctx->mech_used = mech_used; ctx->auth_context = auth_context; ctx->initiate = 0; ctx->gss_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | @@ -345,20 +414,42 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, return(GSS_S_FAILURE); } + switch(ctx->subkey->enctype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_CRC: + enctype = ENCTYPE_DES_CBC_RAW; + ctx->signalg = 0; + ctx->cksum_size = 8; + ctx->sealalg = 0; + break; +#if 0 + case ENCTYPE_DES3_CBC_MD5: + enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = 3; + ctx->cksum_size = 16; + ctx->sealalg = 1; + break; +#endif + default: + return GSS_S_FAILURE; + } + /* fill in the encryption descriptors */ - krb5_use_enctype(context, &ctx->enc.eblock, ENCTYPE_DES_CBC_RAW); + krb5_use_enctype(context, &ctx->enc.eblock, enctype); ctx->enc.processed = 0; - if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))) + + if (code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key)) return(code); for (i=0; i<ctx->enc.key->length; i++) /*SUPPRESS 113*/ ctx->enc.key->contents[i] ^= 0xf0; - krb5_use_enctype(context, &ctx->seq.eblock, ENCTYPE_DES_CBC_RAW); + krb5_use_enctype(context, &ctx->seq.eblock, enctype); ctx->seq.processed = 0; if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) return(code); + ctx->endtime = ticket->enc_part2->times.endtime; ctx->flags = ticket->enc_part2->flags; @@ -366,6 +457,10 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, krb5_auth_con_getremoteseqnumber(context, auth_context, &ctx->seq_recv); + g_order_init(&(ctx->seqstate), ctx->seq_recv, + gss_flags & GSS_C_REPLAY_FLAG, + gss_flags & GSS_C_SEQUENCE_FLAG); + /* at this point, the entire context structure is filled in, so it can be released. */ @@ -375,23 +470,23 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, krb5_data ap_rep; unsigned char * ptr; if ((code = krb5_mk_rep(context, auth_context, &ap_rep))) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); *minor_status = code; return(GSS_S_FAILURE); } krb5_auth_con_getlocalseqnumber(context, auth_context, &ctx->seq_send); - token.length = g_token_size((gss_OID) gss_mech_krb5, ap_rep.length); + token.length = g_token_size((gss_OID) mech_used, ap_rep.length); if ((token.value = (unsigned char *) xmalloc(token.length)) == NULL) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); - *minor_status = code; + *minor_status = ENOMEM; return(GSS_S_FAILURE); } ptr = token.value; - g_make_token_header((gss_OID) gss_mech_krb5, ap_rep.length, - &ptr, KG_TOK_CTX_AP_REP); + g_make_token_header((gss_OID) mech_used, ap_rep.length, + &ptr, KG_TOK_CTX_AP_REP); TWRITE_STR(ptr, ap_rep.data, ap_rep.length); xfree(ap_rep.data); @@ -410,7 +505,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, if ((code = krb5_copy_principal(context, ctx->there, &name))) { if (token.value) xfree(token.value); - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); *minor_status = code; return(GSS_S_FAILURE); @@ -418,14 +513,14 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, } if (mech_type) - *mech_type = (gss_OID) gss_mech_krb5; + *mech_type = (gss_OID) mech_used; if (time_rec) { if ((code = krb5_timeofday(context, &now))) { if (src_name) krb5_free_principal(context, name); xfree(token.value); - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); *minor_status = code; return(GSS_S_FAILURE); @@ -434,7 +529,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, } if (ret_flags) - *ret_flags = ctx->gss_flags; + *ret_flags = KG_IMPLFLAGS(gss_flags); ctx->established = 1; @@ -445,7 +540,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, krb5_free_principal(context, name); if (token.value) xfree(token.value); - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); *minor_status = (OM_uint32) G_VALIDATE_FAILED; return(GSS_S_FAILURE); @@ -460,7 +555,7 @@ krb5_gss_accept_sec_context(ct, minor_status, context_handle, } if (token.value) xfree(token.value); - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t *) &ctx, NULL); *minor_status = (OM_uint32) G_VALIDATE_FAILED; return(GSS_S_FAILURE); diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c index 526e6dddb..b2d6ce111 100644 --- a/src/lib/gssapi/krb5/acquire_cred.c +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -27,6 +27,10 @@ #include <strings.h> #endif +/* + * $Id$ + */ + /* get credentials corresponding to a key in the krb5 keytab. If the default name is requested, return the name in output_princ. If output_princ is non-NULL, the caller will use or free it, regardless @@ -35,14 +39,13 @@ */ static OM_uint32 -acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred) - void *ctx; +acquire_accept_cred(context, minor_status, desired_name, output_princ, cred) + krb5_context context; OM_uint32 *minor_status; gss_name_t desired_name; krb5_principal *output_princ; krb5_gss_cred_id_rec *cred; { - krb5_context context = ctx; krb5_error_code code; krb5_principal princ; krb5_keytab kt; @@ -65,6 +68,7 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred) if (desired_name == (gss_name_t) NULL) { if (code = krb5_sname_to_principal(context, NULL, NULL, KRB5_NT_SRV_HST, &princ)) { + (void) krb5_kt_close(context, kt); *minor_status = code; return(GSS_S_FAILURE); } @@ -76,6 +80,7 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred) /* iterate over the keytab searching for the principal */ if (code = krb5_kt_start_seq_get(context, kt, &cur)) { + (void) krb5_kt_close(context, kt); *minor_status = code; return(GSS_S_FAILURE); } @@ -92,16 +97,19 @@ acquire_accept_cred(ctx, minor_status, desired_name, output_princ, cred) if (code == KRB5_KT_END) { /* this means that the principal wasn't in the keytab */ (void)krb5_kt_end_seq_get(context, kt, &cur); + (void) krb5_kt_close(context, kt); *minor_status = KG_KEYTAB_NOMATCH; return(GSS_S_CRED_UNAVAIL); } else if (code) { /* this means some error occurred reading the keytab */ (void)krb5_kt_end_seq_get(context, kt, &cur); + (void) krb5_kt_close(context, kt); *minor_status = code; return(GSS_S_FAILURE); } else { /* this means that we found a matching entry */ if (code = krb5_kt_end_seq_get(context, kt, &cur)) { + (void) krb5_kt_close(context, kt); *minor_status = code; return(GSS_S_FAILURE); } @@ -204,7 +212,6 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) if (got_endtime == 0) { cred->tgt_expire = creds.times.endtime; got_endtime = 1; - *minor_status = KG_TGT_MISSING; } krb5_free_cred_contents(context, &creds); } @@ -215,6 +222,12 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) (void)krb5_cc_close(context, ccache); *minor_status = code; return(GSS_S_FAILURE); + } else if (! got_endtime) { + /* this means the ccache was entirely empty */ + (void)krb5_cc_end_seq_get(context, ccache, &cur); + (void)krb5_cc_close(context, ccache); + *minor_status = KG_EMPTY_CCACHE; + return(GSS_S_FAILURE); } else { /* this means that we found an endtime to use. */ if (code = krb5_cc_end_seq_get(context, ccache, &cur)) { @@ -239,10 +252,9 @@ acquire_init_cred(context, minor_status, desired_name, output_princ, cred) /*ARGSUSED*/ OM_uint32 -krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, +krb5_gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec) - void *ctx; OM_uint32 *minor_status; gss_name_t desired_name; OM_uint32 time_req; @@ -252,13 +264,17 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, gss_OID_set *actual_mechs; OM_uint32 *time_rec; { - krb5_context context = ctx; + krb5_context context; size_t i; krb5_gss_cred_id_t cred; - gss_OID_set mechs; + gss_OID_set valid_mechs, ret_mechs; + int req_old, req_new; OM_uint32 ret; krb5_error_code code; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* make sure all outputs are valid */ *output_cred_handle = NULL; @@ -279,11 +295,26 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, /* verify that the requested mechanism set is the default, or contains krb5 */ - if (desired_mechs != GSS_C_NULL_OID_SET) { - for (i=0; i<desired_mechs->count; i++) + if (desired_mechs == GSS_C_NULL_OID_SET) { + valid_mechs = gss_mech_set_krb5_both; + } else { + req_old = 0; + req_new = 0; + + for (i=0; i<desired_mechs->count; i++) { + if (g_OID_equal(gss_mech_krb5_old, &(desired_mechs->elements[i]))) + req_old++; if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i]))) - break; - if (i == desired_mechs->count) { + req_new++; + } + + if (req_old && req_new) { + valid_mechs = gss_mech_set_krb5_both; + } else if (req_old) { + valid_mechs = gss_mech_set_krb5_old; + } else if (req_new) { + valid_mechs = gss_mech_set_krb5; + } else { *minor_status = 0; return(GSS_S_BAD_MECH); } @@ -300,6 +331,9 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, cred->usage = cred_usage; cred->princ = NULL; + cred->actual_mechs = valid_mechs; + cred->prerfc_mech = req_old; + cred->rfc_mech = req_new; cred->keytab = NULL; cred->ccache = NULL; @@ -390,7 +424,7 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, /* create mechs */ if (actual_mechs) { - if (! g_copy_OID_set(gss_mech_set_krb5, &mechs)) { + if (! g_copy_OID_set(cred->actual_mechs, &ret_mechs)) { if (cred->ccache) (void)krb5_cc_close(context, cred->ccache); if (cred->keytab) @@ -406,8 +440,8 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, /* intern the credential handle */ if (! kg_save_cred_id((gss_cred_id_t) cred)) { - free(mechs->elements); - free(mechs); + free(ret_mechs->elements); + free(ret_mechs); if (cred->ccache) (void)krb5_cc_close(context, cred->ccache); if (cred->keytab) @@ -424,19 +458,18 @@ krb5_gss_acquire_cred(ctx, minor_status, desired_name, time_req, *minor_status = 0; *output_cred_handle = (gss_cred_id_t) cred; if (actual_mechs) - *actual_mechs = mechs; + *actual_mechs = ret_mechs; return(GSS_S_COMPLETE); } /* V2 interface */ OM_uint32 -krb5_gss_add_cred(ctx, minor_status, input_cred_handle, +krb5_gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech, cred_usage, initiator_time_req, acceptor_time_req, output_cred_handle, actual_mechs, initiator_time_rec, acceptor_time_rec) - void *ctx; OM_uint32 *minor_status; gss_cred_id_t input_cred_handle; gss_name_t desired_name; @@ -449,12 +482,19 @@ krb5_gss_add_cred(ctx, minor_status, input_cred_handle, OM_uint32 *initiator_time_rec; OM_uint32 *acceptor_time_rec; { - krb5_context context = ctx; /* - * This does not apply to our single-mechanism implementation. Until we - * come up with a better error code, return failure. + * This does not apply to our single-mechanism implementation. Decide + * if the correct error is BAD_MECH or DUPLICATE_ELEMENT. */ + + /* verify that the requested mechanism is the default, or + is krb5 */ + + if ((desired_mech != GSS_C_NULL_OID) && + (g_OID_equal(desired_mech, gss_mech_krb5))) + return(GSS_S_BAD_MECH); + *minor_status = 0; - return(GSS_S_FAILURE); + return(GSS_S_DUPLICATE_ELEMENT); } diff --git a/src/lib/gssapi/krb5/compare_name.c b/src/lib/gssapi/krb5/compare_name.c index 19b94f452..75a534220 100644 --- a/src/lib/gssapi/krb5/compare_name.c +++ b/src/lib/gssapi/krb5/compare_name.c @@ -20,17 +20,24 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_compare_name(ctx, minor_status, name1, name2, name_equal) - void *ctx; +krb5_gss_compare_name(minor_status, name1, name2, name_equal) OM_uint32 *minor_status; gss_name_t name1; gss_name_t name2; int *name_equal; { - krb5_context context = ctx; + krb5_context context; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (! kg_validate_name(name1)) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); diff --git a/src/lib/gssapi/krb5/configure.in b/src/lib/gssapi/krb5/configure.in index d5fc0695f..a05531893 100644 --- a/src/lib/gssapi/krb5/configure.in +++ b/src/lib/gssapi/krb5/configure.in @@ -4,4 +4,5 @@ AC_PROG_AWK AC_CHECK_HEADERS(stdlib.h) V5_SHARED_LIB_OBJS SubdirLibraryRule([${OBJS}]) +CopySrcHeader(gssapi_krb5.h,[$](BUILDTOP)/include/gssapi) V5_AC_OUTPUT_MAKEFILE diff --git a/src/lib/gssapi/krb5/context_time.c b/src/lib/gssapi/krb5/context_time.c index 3bc42e603..76f1489b7 100644 --- a/src/lib/gssapi/krb5/context_time.c +++ b/src/lib/gssapi/krb5/context_time.c @@ -22,19 +22,25 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_context_time(ct, minor_status, context_handle, time_rec) - void *ct; +krb5_gss_context_time(minor_status, context_handle, time_rec) OM_uint32 *minor_status; gss_ctx_id_t context_handle; OM_uint32 *time_rec; { - krb5_context context = ct; + krb5_context context; krb5_error_code code; krb5_gss_ctx_id_rec *ctx; krb5_timestamp now; krb5_deltat lifetime; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* validate the context handle */ if (! kg_validate_ctx_id(context_handle)) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; diff --git a/src/lib/gssapi/krb5/delete_sec_context.c b/src/lib/gssapi/krb5/delete_sec_context.c index fded9afa8..5b5ff74fa 100644 --- a/src/lib/gssapi/krb5/delete_sec_context.c +++ b/src/lib/gssapi/krb5/delete_sec_context.c @@ -22,16 +22,22 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token) - void *ct; +krb5_gss_delete_sec_context(minor_status, context_handle, output_token) OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_buffer_t output_token; { - krb5_context context = ct; + krb5_context context; krb5_gss_ctx_id_rec *ctx; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (output_token) { output_token->length = 0; output_token->value = NULL; @@ -71,6 +77,9 @@ krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token) ctx = (gss_ctx_id_t) *context_handle; + if (ctx->seqstate) + g_order_free(&(ctx->seqstate)); + if (ctx->enc.processed) krb5_finish_key(context, &ctx->enc.eblock); krb5_free_keyblock(context, ctx->enc.key); @@ -86,6 +95,8 @@ krb5_gss_delete_sec_context(ct, minor_status, context_handle, output_token) if (ctx->auth_context) krb5_auth_con_free(context, ctx->auth_context); + /* Zero out context */ + memset(ctx, 0, sizeof(*ctx)); xfree(ctx); /* zero the handle itself */ diff --git a/src/lib/gssapi/krb5/disp_name.c b/src/lib/gssapi/krb5/disp_name.c index a9cbcae06..77f520035 100644 --- a/src/lib/gssapi/krb5/disp_name.c +++ b/src/lib/gssapi/krb5/disp_name.c @@ -23,18 +23,20 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_display_name(ctx, minor_status, input_name, output_name_buffer, +krb5_gss_display_name(minor_status, input_name, output_name_buffer, output_name_type) - void *ctx; OM_uint32 *minor_status; gss_name_t input_name; gss_buffer_t output_name_buffer; gss_OID *output_name_type; { - krb5_context context = ctx; + krb5_context context; krb5_error_code code; char *str; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + output_name_buffer->length = 0; output_name_buffer->value = NULL; diff --git a/src/lib/gssapi/krb5/disp_status.c b/src/lib/gssapi/krb5/disp_status.c index 326d3fc7c..143f7a624 100644 --- a/src/lib/gssapi/krb5/disp_status.c +++ b/src/lib/gssapi/krb5/disp_status.c @@ -32,9 +32,8 @@ static int init_et = 0; /**/ OM_uint32 -krb5_gss_display_status(ctx, minor_status, status_value, status_type, +krb5_gss_display_status(minor_status, status_value, status_type, mech_type, message_context, status_string) - void *ctx; OM_uint32 *minor_status; OM_uint32 status_value; int status_type; @@ -42,10 +41,13 @@ krb5_gss_display_status(ctx, minor_status, status_value, status_type, OM_uint32 *message_context; gss_buffer_t status_string; { - krb5_context context = ctx; + krb5_context context; status_string->length = 0; status_string->value = NULL; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if ((mech_type != GSS_C_NULL_OID) && (! g_OID_equal(gss_mech_krb5, mech_type))) { *minor_status = 0; diff --git a/src/lib/gssapi/krb5/export_sec_context.c b/src/lib/gssapi/krb5/export_sec_context.c index 180cc2ef5..fba8a684b 100644 --- a/src/lib/gssapi/krb5/export_sec_context.c +++ b/src/lib/gssapi/krb5/export_sec_context.c @@ -28,20 +28,21 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_export_sec_context(ct, - minor_status, context_handle, interprocess_token) - void *ct; +krb5_gss_export_sec_context(minor_status, context_handle, interprocess_token) OM_uint32 *minor_status; gss_ctx_id_t *context_handle; gss_buffer_t interprocess_token; { - krb5_context ser_ctx = ct; + krb5_context context; krb5_error_code kret; OM_uint32 retval; size_t bufsize, blen; - krb5_gss_ctx_id_t *ctx; + krb5_gss_ctx_id_t ctx; krb5_octet *obuffer, *obp; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* Assume a tragic failure */ obuffer = (krb5_octet *) NULL; retval = GSS_S_FAILURE; @@ -53,12 +54,12 @@ krb5_gss_export_sec_context(ct, goto error_out; } - ctx = (krb5_gss_ctx_id_t *) *context_handle; + ctx = (krb5_gss_ctx_id_t) *context_handle; /* Determine size needed for externalization of context */ bufsize = 0; - if ((kret = krb5_size_opaque(ser_ctx, KG_CONTEXT, (krb5_pointer) ctx, - &bufsize))) + if ((kret = kg_ctx_size(context, (krb5_pointer) ctx, + &bufsize))) goto error_out; /* Allocate the buffer */ @@ -70,8 +71,8 @@ krb5_gss_export_sec_context(ct, obp = obuffer; blen = bufsize; /* Externalize the context */ - if ((kret = krb5_externalize_opaque(ser_ctx, KG_CONTEXT, - (krb5_pointer)ctx, &obp, &blen))) + if ((kret = kg_ctx_externalize(context, + (krb5_pointer) ctx, &obp, &blen))) goto error_out; /* Success! Return the buffer */ @@ -81,23 +82,7 @@ krb5_gss_export_sec_context(ct, retval = GSS_S_COMPLETE; /* Now, clean up the context state */ - (void) kg_delete_ctx_id((gss_ctx_id_t) ctx); - if (ctx->enc.processed) - krb5_finish_key(ser_ctx, &ctx->enc.eblock); - krb5_free_keyblock(ser_ctx, ctx->enc.key); - if (ctx->seq.processed) - krb5_finish_key(ser_ctx, &ctx->seq.eblock); - krb5_free_keyblock(ser_ctx, ctx->seq.key); - krb5_free_principal(ser_ctx, ctx->here); - krb5_free_principal(ser_ctx, ctx->there); - krb5_free_keyblock(ser_ctx, ctx->subkey); - - if (ctx->auth_context) - krb5_auth_con_free(ser_ctx, ctx->auth_context); - - /* Zero out context */ - memset(ctx, 0, sizeof(*ctx)); - xfree(ctx); + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); *context_handle = GSS_C_NO_CONTEXT; return (GSS_S_COMPLETE); diff --git a/src/lib/gssapi/krb5/get_tkt_flags.c b/src/lib/gssapi/krb5/get_tkt_flags.c index 2e73cacfe..5dd91064f 100644 --- a/src/lib/gssapi/krb5/get_tkt_flags.c +++ b/src/lib/gssapi/krb5/get_tkt_flags.c @@ -22,6 +22,10 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 gss_krb5_get_tkt_flags(minor_status, context_handle, ticket_flags) OM_uint32 *minor_status; diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 53c4f4691..7ccc4b828 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -23,7 +23,11 @@ #ifndef _GSSAPIP_KRB5_H_ #define _GSSAPIP_KRB5_H_ -#include "k5-int.h" +/* + * $Id$ + */ + +#include <krb5.h> #include <memory.h> /* work around sunos braindamage */ @@ -34,12 +38,15 @@ #undef minor #endif -/* this must be after "krb5.h", since krb5 #defines xfree(), too */ #ifndef _MACINTOSH #include "../generic/gssapiP_generic.h" #else #include "gssapiP_generic.h" #endif + +/* The include of gssapi_krb5.h will dtrt with the above #defines in + * effect. + */ #include "gssapi_krb5.h" #include "gssapi_err_krb5.h" @@ -56,6 +63,10 @@ #define KG_TOK_WRAP_MSG 0x0201 #define KG_TOK_DEL_CTX 0x0102 +#define KG_IMPLFLAGS(x) (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG | \ + ((x) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | \ + GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG))) + #define KRB5_GSS_FOR_CREDS_OPTION 1 /** internal types **/ @@ -66,6 +77,9 @@ typedef struct _krb5_gss_cred_id_rec { /* name/type of credential */ gss_cred_usage_t usage; krb5_principal princ; /* this is not interned as a gss_name_t */ + const gss_OID_set_desc *actual_mechs; + int prerfc_mech; /* these are a cache of the set above */ + int rfc_mech; /* keytab (accept) data */ krb5_keytab keytab; @@ -89,21 +103,24 @@ typedef struct _krb5_gss_ctx_id_rec { krb5_principal here; krb5_principal there; krb5_keyblock *subkey; + int signalg; + int cksum_size; + int sealalg; krb5_gss_enc_desc enc; krb5_gss_enc_desc seq; krb5_timestamp endtime; krb5_flags flags; krb5_int32 seq_send; krb5_int32 seq_recv; + void *seqstate; int established; int big_endian; krb5_auth_context auth_context; -} krb5_gss_ctx_id_rec, krb5_gss_ctx_id_t; + const gss_OID_desc *mech_used; +} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; extern void *kg_vdb; -extern krb5_context kg_context; - /* helper macros */ #define kg_save_name(name) g_save_name(&kg_vdb,name) @@ -127,16 +144,23 @@ OM_uint32 kg_get_defcred OM_uint32 kg_release_defcred PROTOTYPE((OM_uint32 *minor_status)); krb5_error_code kg_checksum_channel_bindings - PROTOTYPE((gss_channel_bindings_t cb, + PROTOTYPE((krb5_context context, gss_channel_bindings_t cb, krb5_checksum *cksum, int bigend)); -krb5_error_code kg_make_seq_num PROTOTYPE((krb5_gss_enc_desc *ed, +krb5_error_code kg_make_seq_num PROTOTYPE((krb5_context context, + krb5_gss_enc_desc *ed, int direction, krb5_int32 seqnum, unsigned char *cksum, unsigned char *buf)); -krb5_error_code kg_make_seed PROTOTYPE((krb5_keyblock *key, - unsigned char *seed)); +krb5_error_code kg_get_seq_num PROTOTYPE((krb5_context context, + krb5_gss_enc_desc *ed, + unsigned char *cksum, unsigned char *buf, int *direction, + krb5_int32 *seqnum)); + +krb5_error_code kg_make_seed PROTOTYPE((krb5_context context, + krb5_keyblock *key, + unsigned char *seed)); int kg_confounder_size PROTOTYPE((krb5_gss_enc_desc *ed)); @@ -145,10 +169,12 @@ krb5_error_code kg_make_confounder PROTOTYPE((krb5_gss_enc_desc *ed, int kg_encrypt_size PROTOTYPE((krb5_gss_enc_desc *ed, int n)); -krb5_error_code kg_encrypt PROTOTYPE((krb5_gss_enc_desc *ed, +krb5_error_code kg_encrypt PROTOTYPE((krb5_context context, + krb5_gss_enc_desc *ed, krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length)); -krb5_error_code kg_decrypt PROTOTYPE((krb5_gss_enc_desc *ed, +krb5_error_code kg_decrypt PROTOTYPE((krb5_context context, + krb5_gss_enc_desc *ed, krb5_pointer iv, krb5_pointer in, krb5_pointer out, int length)); OM_uint32 kg_seal PROTOTYPE((krb5_context context, @@ -178,14 +204,27 @@ OM_uint32 kg_seal_size PROTOTYPE((krb5_context context, OM_uint32 output_size, OM_uint32 *input_size)); -krb5_error_code -kg_ser_context_init PROTOTYPE((krb5_context)); +krb5_error_code kg_ctx_size PROTOTYPE((krb5_context kcontext, + krb5_pointer arg, + size_t *sizep)); + +krb5_error_code kg_ctx_externalize PROTOTYPE((krb5_context kcontext, + krb5_pointer arg, + krb5_octet **buffer, + size_t *lenremain)); + +krb5_error_code kg_ctx_internalize PROTOTYPE((krb5_context kcontext, + krb5_pointer *argp, + krb5_octet **buffer, + size_t *lenremain)); +OM_uint32 kg_get_context PROTOTYPE((OM_uint32 *minor_status, + krb5_context *context)); + /** declarations of internal name mechanism functions **/ OM_uint32 krb5_gss_acquire_cred -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_name_t, /* desired_name */ OM_uint32, /* time_req */ gss_OID_set, /* desired_mechs */ @@ -196,14 +235,12 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_release_cred -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_cred_id_t* /* cred_handle */ )); OM_uint32 krb5_gss_init_sec_context -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_cred_id_t, /* claimant_cred_handle */ gss_ctx_id_t*, /* context_handle */ gss_name_t, /* target_name */ @@ -220,8 +257,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_accept_sec_context -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t*, /* context_handle */ gss_cred_id_t, /* verifier_cred_handle */ gss_buffer_t, /* input_token_buffer */ @@ -236,29 +272,25 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_process_context_token -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_buffer_t /* token_buffer */ )); OM_uint32 krb5_gss_delete_sec_context -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t*, /* context_handle */ gss_buffer_t /* output_token */ )); OM_uint32 krb5_gss_context_time -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ OM_uint32* /* time_rec */ )); OM_uint32 krb5_gss_sign -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ int, /* qop_req */ gss_buffer_t, /* message_buffer */ @@ -266,8 +298,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_verify -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_buffer_t, /* message_buffer */ gss_buffer_t, /* token_buffer */ @@ -275,8 +306,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_seal -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ int, /* conf_req_flag */ int, /* qop_req */ @@ -286,8 +316,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_unseal -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_buffer_t, /* input_message_buffer */ gss_buffer_t, /* output_message_buffer */ @@ -296,8 +325,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_display_status -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ OM_uint32, /* status_value */ int, /* status_type */ gss_OID, /* mech_type */ @@ -306,44 +334,38 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_indicate_mechs -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_OID_set* /* mech_set */ )); OM_uint32 krb5_gss_compare_name -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_name_t, /* name1 */ gss_name_t, /* name2 */ int* /* name_equal */ )); OM_uint32 krb5_gss_display_name -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_name_t, /* input_name */ gss_buffer_t, /* output_name_buffer */ gss_OID* /* output_name_type */ )); OM_uint32 krb5_gss_import_name -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_buffer_t, /* input_name_buffer */ gss_OID, /* input_name_type */ gss_name_t* /* output_name */ )); OM_uint32 krb5_gss_release_name -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_name_t* /* input_name */ )); OM_uint32 krb5_gss_inquire_cred -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_cred_id_t, /* cred_handle */ gss_name_t *, /* name */ OM_uint32 *, /* lifetime */ @@ -352,8 +374,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_inquire_context -PROTOTYPE( (void *, - OM_uint32*, /* minor_status */ +PROTOTYPE( (OM_uint32*, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_name_t*, /* initiator_name */ gss_name_t*, /* acceptor_name */ @@ -366,8 +387,7 @@ PROTOTYPE( (void *, /* New V2 entry points */ OM_uint32 krb5_gss_get_mic -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_qop_t, /* qop_req */ gss_buffer_t, /* message_buffer */ @@ -375,8 +395,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_verify_mic -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_buffer_t, /* message_buffer */ gss_buffer_t, /* message_token */ @@ -384,8 +403,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_wrap -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t, /* context_handle */ int, /* conf_req_flag */ gss_qop_t, /* qop_req */ @@ -395,8 +413,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_unwrap -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t, /* context_handle */ gss_buffer_t, /* input_message_buffer */ gss_buffer_t, /* output_message_buffer */ @@ -405,8 +422,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_wrap_size_limit -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t, /* context_handle */ int, /* conf_req_flag */ gss_qop_t, /* qop_req */ @@ -415,24 +431,21 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_import_name_object -PROTOTYPE( (krb5_context, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ void *, /* input_name */ gss_OID, /* input_name_type */ gss_name_t * /* output_name */ )); OM_uint32 krb5_gss_export_name_object -PROTOTYPE( (krb5_context, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_name_t, /* input_name */ gss_OID, /* desired_name_type */ void * * /* output_name */ )); OM_uint32 krb5_gss_add_cred -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_cred_id_t, /* input_cred_handle */ gss_name_t, /* desired_name */ gss_OID, /* desired_mech */ @@ -446,8 +459,7 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_inquire_cred_by_mech -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_cred_id_t, /* cred_handle */ gss_OID, /* mech_type */ gss_name_t *, /* name */ @@ -457,38 +469,33 @@ PROTOTYPE( (void *, )); OM_uint32 krb5_gss_export_sec_context -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_ctx_id_t *, /* context_handle */ gss_buffer_t /* interprocess_token */ )); OM_uint32 krb5_gss_import_sec_context -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_buffer_t, /* interprocess_token */ gss_ctx_id_t * /* context_handle */ )); +#if 0 OM_uint32 krb5_gss_release_oid PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_OID * /* oid */ )); - +#endif OM_uint32 krb5_gss_internal_release_oid -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_OID * /* oid */ )); OM_uint32 krb5_gss_inquire_names_for_mech -PROTOTYPE( (void *, - OM_uint32 *, /* minor_status */ +PROTOTYPE( (OM_uint32 *, /* minor_status */ gss_OID, /* mechanism */ gss_OID_set * /* name_types */ )); -OM_uint32 kg_get_context(); - #endif /* _GSSAPIP_KRB5_H_ */ diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et index 0f26773b1..54a126518 100644 --- a/src/lib/gssapi/krb5/gssapi_err_krb5.et +++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et @@ -33,4 +33,6 @@ error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context" error_code KG_CONTEXT, "Bad magic number for krb5_gss_ctx_id_t" error_code KG_CRED, "Bad magic number for krb5_gss_cred_id_t" error_code KG_ENC_DESC, "Bad magic number for krb5_gss_enc_desc" +error_code KG_BAD_SEQ, "Sequence number in token is corrupt" +error_code KG_EMPTY_CCACHE, "Credential cache is empty" end diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c index e18455755..feec0bc71 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.c +++ b/src/lib/gssapi/krb5/gssapi_krb5.c @@ -20,50 +20,62 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_krb5.h" -/** exported constants defined in gssapi_krb5.h **/ +/** exported constants defined in gssapi_krb5{,_nx}.h **/ /* these are bogus, but will compile */ /* - * The OID of the krb5 mechanism, assigned by IETF, is: - * 1.3.5.1.5.2 + * The OID of the draft krb5 mechanism, assigned by IETF, is: + * iso(1) org(3) dod(5) internet(1) security(5) + * kerberosv5(2) = 1.3.5.1.5.2 * The OID of the krb5_name type is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) - * krb5(2) krb5_name(1) = 1.2.840.113554.2.1.2.1 + * krb5(2) krb5_name(1) = 1.2.840.113554.1.2.2.1 * The OID of the krb5_principal type is: * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) - * krb5(2) krb5_principal(2) = 1.2.840.113554.2.1.2.2 + * krb5(2) krb5_principal(2) = 1.2.840.113554.1.2.2.2 + * The OID of the proposed standard krb5 mechanism is: + * iso(1) member-body(2) US(840) mit(113554) infosys(1) gssapi(2) + * krb5(2) = 1.2.840.113554.1.2.2 + * */ /* * Encoding rules: The first two values are encoded in one byte as 40 * * value1 + value2. Subsequent values are encoded base 128, most - * significant digit first, with the high bit set on all octets except - * the last in each value's encoding. + * significant digit first, with the high bit (\200) set on all octets + * except the last in each value's encoding. */ static const gss_OID_desc oids[] = { - /* this OID is from Ted. It's not official yet, but it's close. */ + /* this is the unofficial, wrong OID */ {5, "\053\005\001\005\002"}, + /* this is the official, rfc-specified OID */ + {9, "\052\206\110\206\367\022\001\002\002"}, {10, "\052\206\110\206\367\022\001\002\002\001"}, {10, "\052\206\110\206\367\022\001\002\002\002"}, - {9, "\052\206\110\206\367\022\001\002\002"}, }; -const gss_OID_desc * const gss_mech_krb5 = oids+0; +const gss_OID_desc * const gss_mech_krb5_old = oids+0; +const gss_OID_desc * const gss_mech_krb5 = oids+1; const gss_OID_desc * const gss_nt_krb5_name = oids+1; -const gss_OID_desc * const gss_nt_krb5_principal = oids+2; -const gss_OID_desc * const gss_new_mech_krb5 = oids+3; +const gss_OID_desc * const gss_nt_krb5_principal = oids+3; static const gss_OID_set_desc oidsets[] = { - {1, (gss_OID) oids}, + {1, (gss_OID) oids+0}, + {1, (gss_OID) oids+1}, + {2, (gss_OID) oids+0}, }; -const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+0; - -krb5_context kg_context; +const gss_OID_set_desc * const gss_mech_set_krb5_old = oidsets+0; +const gss_OID_set_desc * const gss_mech_set_krb5 = oidsets+1; +const gss_OID_set_desc * const gss_mech_set_krb5_both = oidsets+2; void *kg_vdb = NULL; @@ -83,10 +95,7 @@ kg_get_defcred(minor_status, cred) if (defcred == GSS_C_NO_CREDENTIAL) { OM_uint32 major; - if (!kg_context && kg_get_context()) - return GSS_S_FAILURE; - - if ((major = krb5_gss_acquire_cred(kg_context, minor_status, + if ((major = krb5_gss_acquire_cred(minor_status, (gss_name_t) NULL, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, GSS_C_INITIATE, &defcred, NULL, NULL)) && @@ -110,19 +119,24 @@ kg_release_defcred(minor_status) return(GSS_S_COMPLETE); } - if (!kg_context && kg_get_context()) - return GSS_S_FAILURE; - - return(krb5_gss_release_cred(kg_context, minor_status, &defcred)); + return(krb5_gss_release_cred(minor_status, &defcred)); } OM_uint32 -kg_get_context() +kg_get_context(minor_status, context) + OM_uint32 *minor_status; + krb5_context *context; { - if (kg_context) - return GSS_S_COMPLETE; - if (krb5_init_context(&kg_context)) - return GSS_S_FAILURE; - krb5_init_ets(kg_context); - return GSS_S_COMPLETE; + static krb5_context kg_context = NULL; + krb5_error_code code; + + if ((! kg_context) && + (code = krb5_init_context(&kg_context))) { + *minor_status = (OM_uint32) code; + return GSS_S_FAILURE; + } + + *context = kg_context; + *minor_status = 0; + return GSS_S_COMPLETE; } diff --git a/src/lib/gssapi/krb5/gssapi_krb5.h b/src/lib/gssapi/krb5/gssapi_krb5.h index 450081d97..71182f22b 100644 --- a/src/lib/gssapi/krb5/gssapi_krb5.h +++ b/src/lib/gssapi/krb5/gssapi_krb5.h @@ -28,10 +28,13 @@ #else #include <gssapi_generic.h> #endif -#include "krb5.h" +#include <krb5.h> extern const gss_OID_desc * const gss_mech_krb5; +extern const gss_OID_desc * const gss_mech_krb5_old; extern const gss_OID_set_desc * const gss_mech_set_krb5; +extern const gss_OID_set_desc * const gss_mech_set_krb5_old; +extern const gss_OID_set_desc * const gss_mech_set_krb5_both; extern const gss_OID_desc * const gss_nt_krb5_name; extern const gss_OID_desc * const gss_nt_krb5_principal; @@ -49,4 +52,11 @@ OM_uint32 gss_krb5_get_tkt_flags krb5_flags *ticket_flags)); +/* this is for backward compatibility only. It is declared here for + completeness, but should not be used */ + +OM_uint32 krb5_gss_set_backward_mode + PROTOTYPE((OM_uint32 *minor_status, + int mode)); + #endif /* _GSSAPI_KRB5_H_ */ diff --git a/src/lib/gssapi/krb5/import_name.c b/src/lib/gssapi/krb5/import_name.c index ee44132ae..5c2c6f43a 100644 --- a/src/lib/gssapi/krb5/import_name.c +++ b/src/lib/gssapi/krb5/import_name.c @@ -20,7 +20,12 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_krb5.h" + #ifndef NO_PASSWORD #include <pwd.h> #endif @@ -39,21 +44,24 @@ */ OM_uint32 -krb5_gss_import_name(ctx, minor_status, input_name_buffer, +krb5_gss_import_name(minor_status, input_name_buffer, input_name_type, output_name) - void *ctx; OM_uint32 *minor_status; gss_buffer_t input_name_buffer; gss_OID input_name_type; gss_name_t *output_name; { - krb5_context context = ctx; + krb5_context context; krb5_principal princ; krb5_error_code code; char *stringrep, *tmp; #ifndef NO_PASSWORD struct passwd *pw; #endif + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* set up default returns */ *output_name = NULL; @@ -75,13 +83,10 @@ krb5_gss_import_name(ctx, minor_status, input_name_buffer, tmp[input_name_buffer->length] = 0; service = tmp; - if ((host = strchr(tmp, '@')) == NULL) { - xfree(tmp); - *minor_status = (OM_uint32) G_BAD_SERVICE_NAME; - return(GSS_S_BAD_NAME); + if (host = strchr(tmp, '@')) { + *host = '\0'; + host++; } - *host = '\0'; - host++; code = krb5_sname_to_principal(context, host, service, KRB5_NT_SRV_HST, &princ); diff --git a/src/lib/gssapi/krb5/import_sec_context.c b/src/lib/gssapi/krb5/import_sec_context.c index d802ecdd0..c1d1bfa72 100644 --- a/src/lib/gssapi/krb5/import_sec_context.c +++ b/src/lib/gssapi/krb5/import_sec_context.c @@ -28,59 +28,46 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_import_sec_context(ct, - minor_status, interprocess_token, context_handle) - void *ct; +krb5_gss_import_sec_context(minor_status, interprocess_token, context_handle) OM_uint32 *minor_status; gss_buffer_t interprocess_token; gss_ctx_id_t *context_handle; { - krb5_context ser_ctx = ct; + krb5_context context; krb5_error_code kret = 0; OM_uint32 retval; size_t blen; - krb5_gss_ctx_id_t *ctx; + krb5_gss_ctx_id_t ctx; krb5_octet *ibp; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* Assume a tragic failure */ - ctx = (krb5_gss_ctx_id_t *) NULL; + ctx = (krb5_gss_ctx_id_t) NULL; retval = GSS_S_FAILURE; *minor_status = 0; /* Internalize the context */ ibp = (krb5_octet *) interprocess_token->value; blen = (size_t) interprocess_token->length; - if ((kret = krb5_internalize_opaque(ser_ctx, KG_CONTEXT, - (krb5_pointer *) &ctx, - &ibp, &blen))) - goto error_out; - + if ((kret = kg_ctx_internalize(context, + (krb5_pointer *) &ctx, + &ibp, &blen))) { + *minor_status = (OM_uint32) kret; + return(GSS_S_FAILURE); + } - /* Make sure that everything is cool. */ - if (!kg_validate_ctx_id((gss_ctx_id_t) ctx)) - goto error_out; + /* intern the context handle */ + if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) { + (void)krb5_gss_delete_sec_context(minor_status, + (gss_ctx_id_t *) &ctx, NULL); + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_FAILURE); + } *context_handle = (gss_ctx_id_t) ctx; + *minor_status = 0; return (GSS_S_COMPLETE); - -error_out: - if (ctx) { - (void) kg_delete_ctx_id((gss_ctx_id_t) ctx); - if (ctx->enc.processed) - krb5_finish_key(ser_ctx, &ctx->enc.eblock); - krb5_free_keyblock(ser_ctx, ctx->enc.key); - if (ctx->seq.processed) - krb5_finish_key(ser_ctx, &ctx->seq.eblock); - krb5_free_principal(ser_ctx, ctx->here); - krb5_free_principal(ser_ctx, ctx->there); - krb5_free_keyblock(ser_ctx, ctx->subkey); - - /* Zero out context */ - memset(ctx, 0, sizeof(*ctx)); - xfree(ctx); - } - if (*minor_status == 0) - *minor_status = (OM_uint32) kret; - return(retval); } diff --git a/src/lib/gssapi/krb5/indicate_mechs.c b/src/lib/gssapi/krb5/indicate_mechs.c index 0f78de219..bc53b4434 100644 --- a/src/lib/gssapi/krb5/indicate_mechs.c +++ b/src/lib/gssapi/krb5/indicate_mechs.c @@ -20,11 +20,14 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_indicate_mechs(ctx, minor_status, mech_set) - void *ctx; +krb5_gss_indicate_mechs(minor_status, mech_set) OM_uint32 *minor_status; gss_OID_set *mech_set; { diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index 2b671680a..686384216 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -22,22 +22,25 @@ #include "gssapiP_krb5.h" #include <memory.h> -#include "k5-int.h" + +/* + * $Id$ + */ static krb5_error_code -make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, - do_mutual, flags, token) - void *ctx; +make_ap_req(context, auth_context, cred, server, endtime, chan_bindings, + req_flags, flags, mech_type, token) + krb5_context context; krb5_auth_context * auth_context; krb5_gss_cred_id_t cred; krb5_principal server; krb5_timestamp *endtime; gss_channel_bindings_t chan_bindings; - OM_uint32 do_mutual; + OM_uint32 req_flags; krb5_flags *flags; + gss_OID mech_type; gss_buffer_t token; { - krb5_context context = ctx; krb5_flags mk_req_flags = 0; krb5_error_code code; krb5_data checksum_data; @@ -46,19 +49,19 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, krb5_data ap_req; unsigned char *ptr; krb5_data credmsg; - unsigned char ckbuf[24]; /* see the token formats doc */ unsigned char *t; int tlen; krb5_int32 con_flags; ap_req.data = 0; checksum_data.data = 0; + credmsg.data = 0; /* build the checksum buffer */ /* compute the hash of the channel bindings */ - if ((code = kg_checksum_channel_bindings(chan_bindings, &md5, 0))) + if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0))) return(code); /* get an auth_context structure and fill in checksum type */ @@ -92,25 +95,31 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, return(KRB5KRB_ERR_FIELD_TOOLONG); } - /* now allocate a buffer to hold the checksum data and KRB_CRED msg - and write it */ + checksum_data.length = 28+credmsg.length; + } else { + checksum_data.length = 24; + } + + /* now allocate a buffer to hold the checksum data and + (maybe) KRB_CRED msg */ - if ((ptr = (unsigned char *) xmalloc(credmsg.length+28)) == NULL) { + if ((checksum_data.data = + (char *) xmalloc(checksum_data.length)) == NULL) { + if (credmsg.data) krb5_xfree(credmsg.data); - return(ENOMEM); - } + return(ENOMEM); + } - checksum_data.data = (char *) ptr; - checksum_data.length = credmsg.length+28; + ptr = checksum_data.data; - TWRITE_INT(ptr, md5.length, 0); - TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length); - TWRITE_INT(ptr, do_mutual?GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG - :GSS_C_DELEG_FLAG, 0); + TWRITE_INT(ptr, md5.length, 0); + TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length); + TWRITE_INT(ptr, KG_IMPLFLAGS(req_flags), 0); - /* done with this, free it */ - xfree(md5.contents); + /* done with this, free it */ + xfree(md5.contents); + if (credmsg.data) { TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0); TWRITE_INT16(ptr, credmsg.length, 0); TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length); @@ -118,20 +127,6 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, /* free credmsg data */ krb5_xfree(credmsg.data); - - } else { - - ptr = ckbuf; - - TWRITE_INT(ptr, md5.length, 0); - TWRITE_STR(ptr, (unsigned char *) md5.contents, md5.length); - TWRITE_INT(ptr, do_mutual?GSS_C_MUTUAL_FLAG:0, 0); - - /* done with this, free it */ - xfree(md5.contents); - - checksum_data.data = (char *) ckbuf; - checksum_data.length = sizeof(ckbuf); } /* fill in the necessary fields in creds */ @@ -142,7 +137,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, goto cleanup; in_creds.times.endtime = *endtime; - in_creds.keyblock.enctype = ENCTYPE_DES_CBC_CRC; + /* * Get the credential..., I don't know in 0 is a good value for the * kdcoptions @@ -155,7 +150,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, mk_req_flags = AP_OPTS_USE_SUBKEY; - if (do_mutual) + if (req_flags & GSS_C_MUTUAL_FLAG) mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED; if ((code = krb5_mk_req_extended(context, auth_context, mk_req_flags, @@ -169,7 +164,7 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, /* build up the token */ /* allocate space for the token */ - tlen = g_token_size((gss_OID) gss_mech_krb5, ap_req.length); + tlen = g_token_size((gss_OID) mech_type, ap_req.length); if ((t = (unsigned char *) xmalloc(tlen)) == NULL) { code = ENOMEM; @@ -180,38 +175,38 @@ make_ap_req(ctx, auth_context, cred, server, endtime, chan_bindings, ptr = t; - g_make_token_header((gss_OID) gss_mech_krb5, ap_req.length, + g_make_token_header((gss_OID) mech_type, ap_req.length, &ptr, KG_TOK_CTX_AP_REQ); TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length); /* pass it back */ + token->length = tlen; token->value = (void *) t; code = 0; cleanup: - if (checksum_data.data && checksum_data.data != (char *) ckbuf) - free(checksum_data.data); - krb5_free_cred_contents(context, &in_creds); - if (out_creds) - krb5_free_creds(context, out_creds); - if (ap_req.data) - xfree(ap_req.data); - if (code) - krb5_auth_con_free(context, *auth_context); - - return (code); + if (checksum_data.data) + free(checksum_data.data); + krb5_free_cred_contents(context, &in_creds); + if (out_creds) + krb5_free_creds(context, out_creds); + if (ap_req.data) + xfree(ap_req.data); + if (code) + krb5_auth_con_free(context, *auth_context); + + return (code); } OM_uint32 -krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, - context_handle, target_name, mech_type, - req_flags, time_req, input_chan_bindings, - input_token, actual_mech_type, output_token, - ret_flags, time_rec) - void *ct; +krb5_gss_init_sec_context(minor_status, claimant_cred_handle, + context_handle, target_name, mech_type, + req_flags, time_req, input_chan_bindings, + input_token, actual_mech_type, output_token, + ret_flags, time_rec) OM_uint32 *minor_status; gss_cred_id_t claimant_cred_handle; gss_ctx_id_t *context_handle; @@ -226,28 +221,25 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, OM_uint32 *ret_flags; OM_uint32 *time_rec; { - krb5_context context = ct; - krb5_gss_cred_id_t cred; - krb5_error_code code; - krb5_gss_ctx_id_rec *ctx; - krb5_timestamp now; - gss_buffer_desc token; - int i; + krb5_context context; + krb5_gss_cred_id_t cred; + krb5_error_code code; + krb5_gss_ctx_id_rec *ctx; + krb5_timestamp now; + krb5_enctype enctype; + gss_buffer_desc token; + int i; + int err; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); /* set up return values so they can be "freed" successfully */ output_token->length = 0; output_token->value = NULL; if (actual_mech_type) - *actual_mech_type = (gss_OID) gss_mech_krb5; - - /* verify the mech_type */ - - if ((mech_type != GSS_C_NULL_OID) && - (! g_OID_equal(mech_type, gss_mech_krb5))) { - *minor_status = 0; - return(GSS_S_BAD_MECH); - } + *actual_mech_type = NULL; /* verify the credential, or use the default */ /*SUPPRESS 29*/ @@ -267,6 +259,17 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, cred = (krb5_gss_cred_id_t) claimant_cred_handle; + /* verify the mech_type */ + + if (mech_type == GSS_C_NULL_OID) { + mech_type = cred->rfc_mech?gss_mech_krb5:gss_mech_krb5_old; + } else if ((g_OID_equal(mech_type, gss_mech_krb5) && !cred->rfc_mech) || + (g_OID_equal(mech_type, gss_mech_krb5_old) && + !cred->prerfc_mech)) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } + /* verify that the target_name is valid and usable */ if (! kg_validate_name(target_name)) { @@ -303,6 +306,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, /* fill in the ctx */ memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); + ctx->mech_used = mech_type; ctx->auth_context = NULL; ctx->initiate = 1; ctx->gss_flags = ((req_flags & (GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG)) | @@ -310,6 +314,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, ctx->flags = req_flags & GSS_C_DELEG_FLAG; ctx->seed_init = 0; ctx->big_endian = 0; /* all initiators do little-endian, as per spec */ + ctx->seqstate = 0; if (time_req == 0 || time_req == GSS_C_INDEFINITE) { ctx->endtime = 0; @@ -338,8 +343,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, if ((code = make_ap_req(context, &(ctx->auth_context), cred, ctx->there, &ctx->endtime, input_chan_bindings, - ctx->gss_flags & GSS_C_MUTUAL_FLAG, &ctx->flags, - &token))) { + req_flags, &ctx->flags, mech_type, &token))) { krb5_free_principal(context, ctx->here); krb5_free_principal(context, ctx->there); xfree(ctx); @@ -354,9 +358,29 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, /* fill in the encryption descriptors */ + switch(ctx->subkey->enctype) { + case ENCTYPE_DES_CBC_MD5: + case ENCTYPE_DES_CBC_CRC: + enctype = ENCTYPE_DES_CBC_RAW; + ctx->signalg = 0; + ctx->cksum_size = 8; + ctx->sealalg = 0; + break; +#if 0 + case ENCTYPE_DES3_CBC_MD5: + enctype = ENCTYPE_DES3_CBC_RAW; + ctx->signalg = 3; + ctx->cksum_size = 16; + ctx->sealalg = 1; + break; +#endif + default: + return GSS_S_FAILURE; + } + /* the encryption key is the session key XOR 0xf0f0f0f0f0f0f0f0 */ - krb5_use_enctype(context, &ctx->enc.eblock, ENCTYPE_DES_CBC_RAW); + krb5_use_enctype(context, &ctx->enc.eblock, enctype); ctx->enc.processed = 0; if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc.key))) return(code); @@ -364,7 +388,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, /*SUPPRESS 113*/ ctx->enc.key->contents[i] ^= 0xf0; - krb5_use_enctype(context, &ctx->seq.eblock, ENCTYPE_DES_CBC_RAW); + krb5_use_enctype(context, &ctx->seq.eblock, enctype); ctx->seq.processed = 0; if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->seq.key))) return(code); @@ -390,7 +414,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, if (time_rec) { if ((code = krb5_timeofday(context, &now))) { xfree(token.value); - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t) ctx, NULL); *minor_status = code; return(GSS_S_FAILURE); @@ -405,7 +429,10 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, *output_token = token; if (ret_flags) - *ret_flags = ctx->gss_flags; + *ret_flags = KG_IMPLFLAGS(req_flags); + + if (actual_mech_type) + *actual_mech_type = mech_type; /* return successfully */ @@ -415,8 +442,11 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, return(GSS_S_CONTINUE_NEEDED); } else { ctx->seq_recv = ctx->seq_send; + g_order_init(&(ctx->seqstate), ctx->seq_recv, + req_flags & GSS_C_REPLAY_FLAG, + req_flags & GSS_C_SEQUENCE_FLAG); ctx->established = 1; - return(GSS_S_COMPLETE); + /* fall through to GSS_S_COMPLETE */ } } else { unsigned char *ptr; @@ -439,15 +469,16 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, if ((ctx->established) || (((gss_cred_id_t) cred) != claimant_cred_handle) || ((req_flags & GSS_C_MUTUAL_FLAG) == 0)) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); + /* XXX this minor status is wrong if an arg was changed */ *minor_status = KG_CONTEXT_ESTABLISHED; return(GSS_S_FAILURE); } if (! krb5_principal_compare(context, ctx->there, (krb5_principal) target_name)) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); *minor_status = 0; return(GSS_S_BAD_NAME); @@ -456,7 +487,7 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, /* verify the token and leave the AP_REP message in ap_rep */ if (input_token == GSS_C_NO_BUFFER) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); *minor_status = 0; return(GSS_S_DEFECTIVE_TOKEN); @@ -464,10 +495,10 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, ptr = (unsigned char *) input_token->value; - if (! g_verify_token_header((gss_OID) gss_mech_krb5, &(ap_rep.length), - &ptr, KG_TOK_CTX_AP_REP, - input_token->length)) { - *minor_status = 0; + if (err = g_verify_token_header((gss_OID) mech_type, &(ap_rep.length), + &ptr, KG_TOK_CTX_AP_REP, + input_token->length)) { + *minor_status = err; return(GSS_S_DEFECTIVE_TOKEN); } @@ -482,9 +513,9 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, * To be removed in 1999 -- proven */ krb5_auth_con_setuseruserkey(context,ctx->auth_context,ctx->subkey); - if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep, - &ap_rep_data))) { - (void)krb5_gss_delete_sec_context(context, minor_status, + if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep, + &ap_rep_data))) { + (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL); *minor_status = code; return(GSS_S_FAILURE); @@ -493,6 +524,9 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, /* store away the sequence number */ ctx->seq_recv = ap_rep_data->seq_number; + g_order_init(&(ctx->seqstate), ctx->seq_recv, + req_flags & GSS_C_REPLAY_FLAG, + req_flags & GSS_C_SEQUENCE_FLAG); /* free the ap_rep_data */ krb5_free_ap_rep_enc_part(context, ap_rep_data); @@ -504,20 +538,25 @@ krb5_gss_init_sec_context(ct, minor_status, claimant_cred_handle, if (time_rec) { if ((code = krb5_timeofday(context, &now))) { - (void)krb5_gss_delete_sec_context(context, minor_status, + (void)krb5_gss_delete_sec_context(minor_status, (gss_ctx_id_t) ctx, NULL); *minor_status = code; return(GSS_S_FAILURE); - } + *time_rec = ctx->endtime - now; } if (ret_flags) - *ret_flags = GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_MUTUAL_FLAG; + *ret_flags = KG_IMPLFLAGS(req_flags); + + if (actual_mech_type) + *actual_mech_type = mech_type; /* success */ *minor_status = 0; - return(GSS_S_COMPLETE); + /* fall through to GSS_S_COMPLETE */ } + + return(GSS_S_COMPLETE); } diff --git a/src/lib/gssapi/krb5/inq_context.c b/src/lib/gssapi/krb5/inq_context.c index c8499212f..5e5746344 100644 --- a/src/lib/gssapi/krb5/inq_context.c +++ b/src/lib/gssapi/krb5/inq_context.c @@ -23,10 +23,9 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name, +krb5_gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name, lifetime_rec, mech_type, ret_flags, locally_initiated, open) - void *ct; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_name_t *initiator_name; @@ -37,13 +36,16 @@ krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name, int *locally_initiated; int *open; { - krb5_context context = ct; + krb5_context context; krb5_error_code code; krb5_gss_ctx_id_rec *ctx; krb5_principal init, accept; krb5_timestamp now; krb5_deltat lifetime; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (initiator_name) *initiator_name = (gss_name_t) NULL; if (acceptor_name) @@ -116,7 +118,7 @@ krb5_gss_inquire_context(ct, minor_status, context_handle, initiator_name, *lifetime_rec = lifetime; if (mech_type) - *mech_type = (gss_OID) gss_mech_krb5; + *mech_type = (gss_OID) ctx->mech_used; if (ret_flags) *ret_flags = ctx->gss_flags; diff --git a/src/lib/gssapi/krb5/inq_cred.c b/src/lib/gssapi/krb5/inq_cred.c index e3e01bf4e..f9811c347 100644 --- a/src/lib/gssapi/krb5/inq_cred.c +++ b/src/lib/gssapi/krb5/inq_cred.c @@ -23,9 +23,8 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, +krb5_gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, cred_usage, mechanisms) - void *ctx; OM_uint32 *minor_status; gss_cred_id_t cred_handle; gss_name_t *name; @@ -33,7 +32,7 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, gss_cred_usage_t *cred_usage; gss_OID_set *mechanisms; { - krb5_context context = ctx; + krb5_context context; krb5_gss_cred_id_t cred; krb5_error_code code; krb5_timestamp now; @@ -41,6 +40,9 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, krb5_principal ret_name; gss_OID_set mechs; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (name) *name = NULL; if (mechanisms) *mechanisms = NULL; @@ -82,7 +84,7 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, } if (mechanisms) - if (! g_copy_OID_set(gss_mech_set_krb5, &mechs)) { + if (! g_copy_OID_set(cred->actual_mechs, &mechs)) { krb5_free_principal(context, ret_name); *minor_status = ENOMEM; return(GSS_S_FAILURE); @@ -113,10 +115,9 @@ krb5_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret, /* V2 interface */ OM_uint32 -krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle, +krb5_gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, initiator_lifetime, acceptor_lifetime, cred_usage) - void *ctx; OM_uint32 *minor_status; gss_cred_id_t cred_handle; gss_OID mech_type; @@ -125,11 +126,14 @@ krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle, OM_uint32 *acceptor_lifetime; gss_cred_usage_t *cred_usage; { - krb5_context context = ctx; + krb5_context context; krb5_gss_cred_id_t cred; OM_uint32 lifetime; OM_uint32 mstat; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* * We only know how to handle our own creds. */ @@ -140,8 +144,7 @@ krb5_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle, } cred = (krb5_gss_cred_id_t) cred_handle; - mstat = krb5_gss_inquire_cred(context, - minor_status, + mstat = krb5_gss_inquire_cred(minor_status, cred_handle, name, &lifetime, diff --git a/src/lib/gssapi/krb5/inq_names.c b/src/lib/gssapi/krb5/inq_names.c index fe61eb01a..948346dc6 100644 --- a/src/lib/gssapi/krb5/inq_names.c +++ b/src/lib/gssapi/krb5/inq_names.c @@ -28,19 +28,23 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_inquire_names_for_mech(context, minor_status, mechanism, name_types) - void *context; +krb5_gss_inquire_names_for_mech(minor_status, mechanism, name_types) OM_uint32 *minor_status; gss_OID mechanism; gss_OID_set *name_types; { + krb5_context context; OM_uint32 major, minor; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* * We only know how to handle our own mechanism. */ if ((mechanism != GSS_C_NULL_OID) && - !g_OID_equal(gss_mech_krb5, mechanism)) { + !g_OID_equal(gss_mech_krb5, mechanism) && + !g_OID_equal(gss_mech_krb5_old, mechanism)) { *minor_status = 0; return(GSS_S_FAILURE); } diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c index 4e5c78bd1..254d51680 100644 --- a/src/lib/gssapi/krb5/k5seal.c +++ b/src/lib/gssapi/krb5/k5seal.c @@ -21,11 +21,11 @@ */ #include "gssapiP_krb5.h" -#include "rsa-md5.h" static krb5_error_code make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, - encrypt, toktype, bigend) + signalg, cksum_size, sealalg, encrypt, toktype, + bigend, oid) krb5_context context; krb5_gss_enc_desc *enc_ed; krb5_gss_enc_desc *seq_ed; @@ -33,29 +33,36 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, int direction; gss_buffer_t text; gss_buffer_t token; + int signalg; + int cksum_size; + int sealalg; int encrypt; int toktype; int bigend; + gss_OID oid; { krb5_error_code code; - krb5_MD5_CTX md5; - krb5_checksum desmac; - krb5_octet cbc_checksum[KRB5_MIT_DES_KEYSIZE]; - int tmsglen, tlen; + char *data_ptr; + krb5_checksum md5cksum; + krb5_checksum cksum; + int conflen, tmsglen, tlen; unsigned char *t, *ptr; /* create the token buffer */ - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) { - if (bigend && !encrypt) + if (toktype == KG_TOK_SEAL_MSG) { + if (bigend && !encrypt) { tmsglen = text->length; - else - tmsglen = (kg_confounder_size(enc_ed)+text->length+8)&(~7); + } else { + conflen = kg_confounder_size(enc_ed); + /* XXX knows that des block size is 8 */ + tmsglen = (conflen+text->length+8)&(~7); + } } else { tmsglen = 0; } - tlen = g_token_size((gss_OID) gss_mech_krb5, 22+tmsglen); + tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen); if ((t = (unsigned char *) xmalloc(tlen)) == NULL) return(ENOMEM); @@ -64,104 +71,192 @@ make_seal_token(context, enc_ed, seq_ed, seqnum, direction, text, token, ptr = t; - g_make_token_header((gss_OID) gss_mech_krb5, 22+tmsglen, &ptr, toktype); + g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype); - /* for now, only generate DES integrity */ + /* 0..1 SIGN_ALG */ - ptr[0] = 0; + ptr[0] = signalg; ptr[1] = 0; + + /* 2..3 SEAL_ALG or Filler */ - /* SEAL_ALG, or filler */ - - if (((toktype == KG_TOK_SEAL_MSG) || - (toktype == KG_TOK_WRAP_MSG)) && encrypt) { - ptr[2] = 0; + if ((toktype == KG_TOK_SEAL_MSG) && encrypt) { + ptr[2] = sealalg; ptr[3] = 0; } else { + /* No seal */ ptr[2] = 0xff; ptr[3] = 0xff; } - /* filler */ + /* 4..5 Filler */ ptr[4] = 0xff; ptr[5] = 0xff; /* pad the plaintext, encrypt if needed, and stick it in the token */ - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) { + /* initialize the the cksum and allocate the contents buffer */ + md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; + md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); + if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) { + return(ENOMEM); + } + + if (toktype == KG_TOK_SEAL_MSG) { unsigned char *plain; unsigned char pad; - if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) { - xfree(t); - return(ENOMEM); - } + if (!bigend || encrypt) { + if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) { + xfree(md5cksum.contents); + xfree(t); + return(ENOMEM); + } - if (code = kg_make_confounder(enc_ed, plain)) { - xfree(plain); - xfree(t); - return(code); - } + if (code = kg_make_confounder(enc_ed, plain)) { + xfree(plain); + xfree(md5cksum.contents); + xfree(t); + return(code); + } - memcpy(plain+8, text->value, text->length); + memcpy(plain+conflen, text->value, text->length); - pad = 8-(text->length%8); + /* XXX 8 is DES cblock size */ + pad = 8-(text->length%8); - memset(plain+8+text->length, pad, pad); + memset(plain+conflen+text->length, pad, pad); + } else { + /* plain is never used in the bigend && !encrypt case */ + plain = NULL; + } if (encrypt) { - if (code = kg_encrypt(enc_ed, NULL, (krb5_pointer) plain, - (krb5_pointer) (ptr+22), tmsglen)) { - xfree(plain); + if (code = kg_encrypt(context, enc_ed, NULL, (krb5_pointer) plain, + (krb5_pointer) (ptr+cksum_size+14), tmsglen)) { + if (plain) + xfree(plain); + xfree(md5cksum.contents); xfree(t); return(code); } } else { if (bigend) - memcpy(ptr+22, text->value, text->length); + memcpy(ptr+14+cksum_size, text->value, text->length); else - memcpy(ptr+22, plain, tmsglen); + memcpy(ptr+14+cksum_size, plain, tmsglen); } /* compute the checksum */ - krb5_MD5Init(&md5); - krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8); + /* 8 = head of token body as specified by mech spec */ + if (! (data_ptr = + (char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) { + if (plain) + xfree(plain); + xfree(md5cksum.contents); + xfree(t); + return(ENOMEM); + } + (void) memcpy(data_ptr, ptr-2, 8); if (bigend) - krb5_MD5Update(&md5, text->value, text->length); + (void) memcpy(data_ptr+8, text->value, text->length); else - krb5_MD5Update(&md5, plain, tmsglen); - krb5_MD5Final(&md5); + (void) memcpy(data_ptr+8, plain, tmsglen); + code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr, + 8 + (bigend ? text->length : tmsglen), + 0, 0, &md5cksum); + xfree(data_ptr); + + if (code) { + if (plain) + xfree(plain); + xfree(md5cksum.contents); + xfree(t); + return(code); + memcpy(ptr+14+cksum_size, plain, tmsglen); + } - xfree(plain); + if (plain) + xfree(plain); } else { /* compute the checksum */ - krb5_MD5Init(&md5); - krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8); - krb5_MD5Update(&md5, text->value, text->length); - krb5_MD5Final(&md5); + if (! (data_ptr = (char *) xmalloc(8 + text->length))) { + xfree(md5cksum.contents); + xfree(t); + return(ENOMEM); + } + (void) memcpy(data_ptr, ptr-2, 8); + (void) memcpy(data_ptr+8, text->value, text->length); + code = krb5_calculate_checksum(context, md5cksum.checksum_type, data_ptr, + 8 + text->length, + 0, 0, &md5cksum); + xfree(data_ptr); + if (code) { + xfree(md5cksum.contents); + xfree(t); + return(code); + } } - /* XXX this depends on the key being a single-des key, but that's - all that kerberos supports right now */ - - desmac.length = sizeof(cbc_checksum); - desmac.contents = cbc_checksum; - if (code = krb5_calculate_checksum(context, CKSUMTYPE_DESCBC, md5.digest, 16, - seq_ed->key->contents, - seq_ed->key->length, - &desmac)) { - xfree(t); - return(code); + switch(signalg) { + case 0: + case 3: + +#if 0 + /* XXX this depends on the key being a single-des key */ + + /* DES CBC doesn't use a zero IV like it should in some + krb5 implementations (beta5+). So we just do the + DES encryption the long way, and keep the last block + as the MAC */ + + /* initialize the the cksum and allocate the contents buffer */ + cksum.checksum_type = CKSUMTYPE_DESCBC; + cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC); + if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL) + return(ENOMEM); + + if (code = krb5_calculate_checksum(context, cksum.checksum_type, + md5cksum.contents, 16, + seq_ed->key->contents, + seq_ed->key->length, + &cksum)) { + xfree(cksum.contents); + xfree(md5cksum.contents); + xfree(t); + return(code); + } + + memcpy(ptr+14, cksum.contents, 8); + + xfree(cksum.contents); +#else + if (code = kg_encrypt(context, seq_ed, + (g_OID_equal(oid, gss_mech_krb5_old) ? + seq_ed->key->contents : NULL), + md5cksum.contents, md5cksum.contents, 16)) { + xfree(md5cksum.contents); + xfree(t); + return code; + } + + cksum.length = cksum_size; + cksum.contents = md5cksum.contents + 16 - cksum.length; + + memcpy(ptr+14, cksum.contents, cksum.length); +#endif + + break; } - memcpy(ptr+14, desmac.contents, 8); + xfree(md5cksum.contents); /* create the seq_num */ - if (code = kg_make_seq_num(seq_ed, direction?0:0xff, *seqnum, + if (code = kg_make_seq_num(context, seq_ed, direction?0:0xff, *seqnum, ptr+14, ptr+6)) { xfree(t); return(code); @@ -227,60 +322,16 @@ kg_seal(context, minor_status, context_handle, conf_req_flag, qop_req, if (code = make_seal_token(context, &ctx->enc, &ctx->seq, &ctx->seq_send, ctx->initiate, input_message_buffer, output_message_buffer, - conf_req_flag, toktype, ctx->big_endian)) { + ctx->signalg, ctx->cksum_size, ctx->sealalg, + conf_req_flag, toktype, ctx->big_endian, + ctx->mech_used)) { *minor_status = code; return(GSS_S_FAILURE); } - if (((toktype == KG_TOK_SEAL_MSG) || - (toktype == KG_TOK_WRAP_MSG)) && conf_state) { + if ((toktype == KG_TOK_SEAL_MSG) && conf_state) *conf_state = conf_req_flag; - } *minor_status = 0; return((ctx->endtime < now)?GSS_S_CONTEXT_EXPIRED:GSS_S_COMPLETE); } - -OM_uint32 -kg_seal_size(context, minor_status, context_handle, conf_req_flag, qop_req, - output_size, input_size) - krb5_context context; - OM_uint32 *minor_status; - gss_ctx_id_t context_handle; - int conf_req_flag; - gss_qop_t qop_req; - OM_uint32 output_size; - OM_uint32 *input_size; -{ - krb5_gss_ctx_id_rec *ctx; - OM_uint32 cfsize; - OM_uint32 ohlen; - - /* only default qop is allowed */ - if (qop_req != GSS_C_QOP_DEFAULT) { - *minor_status = (OM_uint32) G_UNKNOWN_QOP; - return(GSS_S_FAILURE); - } - - /* validate the context handle */ - if (! kg_validate_ctx_id(context_handle)) { - *minor_status = (OM_uint32) G_VALIDATE_FAILED; - return(GSS_S_NO_CONTEXT); - } - - ctx = (krb5_gss_ctx_id_rec *) context_handle; - if (! ctx->established) { - *minor_status = KG_CTX_INCOMPLETE; - return(GSS_S_NO_CONTEXT); - } - - /* Calculate the token size and subtract that from the output size */ - cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0; - ohlen = g_token_size((gss_OID) gss_mech_krb5, (unsigned int) cfsize + 22); - - /* Cannot have trailer length that will cause us to pad over our length */ - *input_size = (output_size - ohlen) & (~7); - *minor_status = 0; - return(GSS_S_COMPLETE); -} - diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c index 1b4288c0c..70d2d4d7b 100644 --- a/src/lib/gssapi/krb5/k5unseal.c +++ b/src/lib/gssapi/krb5/k5unseal.c @@ -22,7 +22,10 @@ #include "gssapiP_krb5.h" #include <memory.h> -#include "rsa-md5.h" + +/* + * $Id$ + */ /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX conf_state is only valid if SEAL. @@ -44,19 +47,25 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, krb5_error_code code; int bodysize; int tmsglen; + int conflen; int signalg; int sealalg; gss_buffer_desc token; unsigned char *ptr; + krb5_checksum cksum; krb5_checksum desmac; - krb5_octet cbc_checksum[KRB5_MIT_DES_KEYSIZE]; - krb5_MD5_CTX md5; - unsigned char *cksum; + krb5_checksum md5cksum; + char *data_ptr; krb5_timestamp now; unsigned char *plain; + int cksum_len; int plainlen; + int err; + int direction; + krb5_int32 seqnum; + OM_uint32 retval; - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) { + if (toktype == KG_TOK_SEAL_MSG) { message_buffer->length = 0; message_buffer->value = NULL; } @@ -80,73 +89,109 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, ptr = (unsigned char *) input_token_buffer->value; - if (! g_verify_token_header((gss_OID) gss_mech_krb5, &bodysize, - &ptr, toktype, input_token_buffer->length)) { - *minor_status = 0; + if (err = g_verify_token_header((gss_OID) ctx->mech_used, &bodysize, + &ptr, toktype, + input_token_buffer->length)) { + *minor_status = err; return(GSS_S_DEFECTIVE_TOKEN); } - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) - tmsglen = bodysize-22; - /* get the sign and seal algorithms */ signalg = ptr[0] + (ptr[1]<<8); sealalg = ptr[2] + (ptr[3]<<8); - if (((signalg != 0) && (signalg != 1)) || - (((toktype != KG_TOK_SEAL_MSG) && - (toktype != KG_TOK_WRAP_MSG)) && (sealalg != 0xffff)) || - (((toktype == KG_TOK_SEAL_MSG) || - (toktype == KG_TOK_WRAP_MSG)) && - ((sealalg != 0xffff) && (sealalg != 0))) || - (ptr[4] != 0xff) || - (ptr[5] != 0xff)) { - *minor_status = 0; - return(GSS_S_DEFECTIVE_TOKEN); + /* Sanity checks */ + + if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; } + if ((toktype != KG_TOK_SEAL_MSG) && + (sealalg != 0xffff)) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* in the current spec, there is only one valid seal algorithm per + key type, so a simple comparison is ok */ + + if ((toktype == KG_TOK_SEAL_MSG) && + !((sealalg == 0xffff) || + (sealalg == ctx->sealalg))) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + + /* there are several mappings of seal algorithms to sign algorithms, + but few enough that we can try them all. */ + + if (((ctx->sealalg == 0) && + (signalg > 1)) || + ((ctx->sealalg == 1) && + (signalg != 3))) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + + switch (signalg) { + case 0: + case 1: + cksum_len = 8; + break; + case 3: + cksum_len = 16; + break; + } + + if (toktype == KG_TOK_SEAL_MSG) + tmsglen = bodysize-(14+cksum_len); + /* get the token parameters */ /* decode the message, if SEAL */ - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) { - if (sealalg == 0) { + if (toktype == KG_TOK_SEAL_MSG) { + if (sealalg != 0xffff) { if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) { *minor_status = ENOMEM; return(GSS_S_FAILURE); } - if (code = kg_decrypt(&ctx->enc, NULL, ptr+22, plain, tmsglen)) { + if (code = kg_decrypt(context, &ctx->enc, NULL, + ptr+14+cksum_len, plain, tmsglen)) { xfree(plain); *minor_status = code; return(GSS_S_FAILURE); } } else { - plain = ptr+22; + plain = ptr+14+cksum_len; } plainlen = tmsglen; - if (sealalg && ctx->big_endian) + if ((sealalg == 0xffff) && ctx->big_endian) { token.length = tmsglen; - else - token.length = tmsglen - 8 - plain[tmsglen-1]; + } else { + conflen = kg_confounder_size(&ctx->enc); + token.length = tmsglen - conflen - plain[tmsglen-1]; + } if (token.length) { - if ((token.value = xmalloc(token.length)) == NULL) { - if (sealalg == 0) + if ((token.value = (void *) xmalloc(token.length)) == NULL) { + if (sealalg != 0xffff) xfree(plain); *minor_status = ENOMEM; return(GSS_S_FAILURE); } - if (sealalg && ctx->big_endian) + if ((sealalg == 0xffff) && ctx->big_endian) memcpy(token.value, plain, token.length); else - memcpy(token.value, plain+8, token.length); + memcpy(token.value, plain+conflen, token.length); } - } else if ((toktype == KG_TOK_SIGN_MSG) || (toktype == KG_TOK_MIC_MSG)) { + } else if (toktype == KG_TOK_SIGN_MSG) { token = *message_buffer; plain = token.value; plainlen = token.length; @@ -159,81 +204,184 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, /* compute the checksum of the message */ - if (signalg == 0) { + /* initialize the the cksum and allocate the contents buffer */ + md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; + md5cksum.length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); + if ((md5cksum.contents = (krb5_octet *) xmalloc(md5cksum.length)) == NULL) { + if (sealalg != 0xffff) + xfree(plain); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + switch (signalg) { + case 0: + case 3: /* compute the checksum of the message */ - krb5_MD5Init(&md5); - krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8); + /* 8 = bytes of token body to be checksummed according to spec */ + + if (! (data_ptr = (void *) + xmalloc(8 + (ctx->big_endian ? token.length : plainlen)))) { + xfree(md5cksum.contents); + if (sealalg != 0xffff) + xfree(plain); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + (void) memcpy(data_ptr, ptr-2, 8); + if (ctx->big_endian) - krb5_MD5Update(&md5, token.value, token.length); + (void) memcpy(data_ptr+8, token.value, token.length); else - krb5_MD5Update(&md5, plain, plainlen); - krb5_MD5Final(&md5); - - if (sealalg == 0) - xfree(plain); + (void) memcpy(data_ptr+8, plain, plainlen); + + code = krb5_calculate_checksum(context, md5cksum.checksum_type, + data_ptr, 8 + + (ctx->big_endian ? token.length : + plainlen), 0, 0, &md5cksum); + xfree(data_ptr); + + if (code) { + xfree(md5cksum.contents); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = code; + return(GSS_S_FAILURE); + } +#if 0 /* XXX this depends on the key being a single-des key, but that's all that kerberos supports right now */ - desmac.length = sizeof(cbc_checksum); - desmac.contents = cbc_checksum; - if (code = krb5_calculate_checksum(context, CKSUMTYPE_DESCBC, md5.digest, - 16, ctx->seq.key->contents, + + /* initialize the the cksum and allocate the contents buffer */ + cksum.checksum_type = CKSUMTYPE_DESCBC; + cksum.length = krb5_checksum_size(context, CKSUMTYPE_DESCBC); + if ((cksum.contents = (krb5_octet *) xmalloc(cksum.length)) == NULL) { + xfree(md5cksum.contents); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + if (code = krb5_calculate_checksum(context, cksum.checksum_type, + md5cksum.contents, 16, + ctx->seq.key->contents, ctx->seq.key->length, - &desmac)) { - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) + &cksum)) { + xfree(cksum.contents); + xfree(md5cksum.contents); + if (toktype == KG_TOK_SEAL_MSG) xfree(token.value); *minor_status = code; return(GSS_S_FAILURE); } - cksum = desmac.contents; - } else { - if (! ctx->seed_init) { - if (code = kg_make_seed(ctx->subkey, ctx->seed)) { - if (sealalg == 0) + code = memcmp(cksum.contents, ptr+14, cksum.length); + + xfree(cksum.contents); +#else + if (code = kg_encrypt(context, &ctx->seq, + (g_OID_equal(ctx->mech_used, gss_mech_krb5_old) ? + ctx->seq.key->contents : NULL), + md5cksum.contents, md5cksum.contents, 16)) { + xfree(md5cksum.contents); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = code; + return GSS_S_FAILURE; + } + + if (signalg == 0) + cksum.length = 8; + else + cksum.length = 16; + cksum.contents = md5cksum.contents + 16 - cksum.length; + + code = memcmp(cksum.contents, ptr+14, cksum.length); +#endif + break; + + case 1: + if (!ctx->seed_init && + (code = kg_make_seed(context, ctx->subkey, ctx->seed))) { + xfree(md5cksum.contents); + if (sealalg != 0xffff) xfree(plain); - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) + if (toktype == KG_TOK_SEAL_MSG) xfree(token.value); - *minor_status = code; - return(GSS_S_FAILURE); - } - ctx->seed_init = 1; + *minor_status = code; + return GSS_S_FAILURE; + } + + if (! (data_ptr = (void *) + xmalloc(sizeof(ctx->seed) + 8 + + (ctx->big_endian ? token.length : plainlen)))) { + xfree(md5cksum.contents); + if (sealalg == 0) + xfree(plain); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); } - - krb5_MD5Init(&md5); - krb5_MD5Update(&md5, ctx->seed, sizeof(ctx->seed)); - krb5_MD5Update(&md5, (unsigned char *) ptr-2, 8); + (void) memcpy(data_ptr, ptr-2, 8); + (void) memcpy(data_ptr+8, ctx->seed, sizeof(ctx->seed)); if (ctx->big_endian) - krb5_MD5Update(&md5, token.value, token.length); + (void) memcpy(data_ptr+8+sizeof(ctx->seed), + token.value, token.length); else - krb5_MD5Update(&md5, plain, plainlen); - krb5_MD5Final(&md5); + (void) memcpy(data_ptr+8+sizeof(ctx->seed), + plain, plainlen); + code = krb5_calculate_checksum(context, md5cksum.checksum_type, + data_ptr, 8 + sizeof(ctx->seed) + + (ctx->big_endian ? token.length : + plainlen), 0, 0, &md5cksum); + + xfree(data_ptr); + + if (code) { + xfree(md5cksum.contents); + if (sealalg == 0) + xfree(plain); + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = code; + return(GSS_S_FAILURE); + } - if (sealalg == 0) - xfree(plain); + code = memcmp(md5cksum.contents, ptr+14, 8); - cksum = md5.digest; + default: + *minor_status = 0; + return(GSS_S_DEFECTIVE_TOKEN); } - + + xfree(md5cksum.contents); + if (sealalg != 0xffff) + xfree(plain); + /* compare the computed checksum against the transmitted checksum */ - if (memcmp(cksum, ptr+14, 8) != 0) { - if ((toktype == KG_TOK_SEAL_MSG) || (toktype == KG_TOK_WRAP_MSG)) + if (code) { + if (toktype == KG_TOK_SEAL_MSG) xfree(token.value); *minor_status = 0; return(GSS_S_BAD_SIG); } + - /* XXX this is where the seq_num check would go */ - /* it got through unscathed. Make sure the context is unexpired */ - if ((toktype == KG_TOK_SEAL_MSG) || (toktype = KG_TOK_WRAP_MSG)) + if (toktype == KG_TOK_SEAL_MSG) *message_buffer = token; if (conf_state) - *conf_state = (sealalg == 0); + *conf_state = (sealalg != 0xffff); if (qop_state) *qop_state = GSS_C_QOP_DEFAULT; @@ -248,8 +396,28 @@ kg_unseal(context, minor_status, context_handle, input_token_buffer, return(GSS_S_CONTEXT_EXPIRED); } - /* success */ + /* do sequencing checks */ + + if (code = kg_get_seq_num(context, &(ctx->seq), ptr+14, ptr+6, &direction, + &seqnum)) { + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = code; + return(GSS_S_BAD_SIG); + } + + if ((ctx->initiate && direction != 0xff) || + (!ctx->initiate && direction != 0)) { + if (toktype == KG_TOK_SEAL_MSG) + xfree(token.value); + *minor_status = G_BAD_DIRECTION; + return(GSS_S_BAD_SIG); + } + + retval = g_order_check(&(ctx->seqstate), seqnum); + + /* success or ordering violation */ *minor_status = 0; - return(GSS_S_COMPLETE); + return(retval); } diff --git a/src/lib/gssapi/krb5/krb5_gss_glue.c b/src/lib/gssapi/krb5/krb5_gss_glue.c new file mode 100644 index 000000000..f22e9d633 --- /dev/null +++ b/src/lib/gssapi/krb5/krb5_gss_glue.c @@ -0,0 +1,538 @@ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * $Id$ + */ + +#include "gssapiP_krb5.h" + +OM_uint32 INTERFACE +gss_accept_sec_context(minor_status, context_handle, verifier_cred_handle, + input_token, input_chan_bindings, src_name, mech_type, + output_token, ret_flags, time_rec, delegated_cred_handle) + OM_uint32 *minor_status; + gss_ctx_id_t *context_handle; + gss_cred_id_t verifier_cred_handle; + gss_buffer_t input_token; + gss_channel_bindings_t input_chan_bindings; + gss_name_t *src_name; + gss_OID *mech_type; + gss_buffer_t output_token; + OM_uint32 *ret_flags; + OM_uint32 *time_rec; + gss_cred_id_t *delegated_cred_handle; +{ + return(krb5_gss_accept_sec_context(minor_status, + context_handle, + verifier_cred_handle, + input_token, + input_chan_bindings, + src_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle)); +} + +OM_uint32 INTERFACE +gss_acquire_cred(minor_status, desired_name, time_req, desired_mechs, + cred_usage, output_cred_handle, actual_mechs, time_rec) + OM_uint32 *minor_status; + gss_name_t desired_name; + OM_uint32 time_req; + gss_OID_set desired_mechs; + gss_cred_usage_t cred_usage; + gss_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *time_rec; +{ + return(krb5_gss_acquire_cred(minor_status, + desired_name, + time_req, + desired_mechs, + cred_usage, + output_cred_handle, + actual_mechs, + time_rec)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech, + cred_usage, initiator_time_req, acceptor_time_req, + output_cred_handle, actual_mechs, initiator_time_rec, + acceptor_time_rec) + OM_uint32 *minor_status; + gss_cred_id_t input_cred_handle; + gss_name_t desired_name; + gss_OID desired_mech; + gss_cred_usage_t cred_usage; + OM_uint32 initiator_time_req; + OM_uint32 acceptor_time_req; + gss_cred_id_t *output_cred_handle; + gss_OID_set *actual_mechs; + OM_uint32 *initiator_time_rec; + OM_uint32 *acceptor_time_rec; +{ + return(krb5_gss_add_cred(minor_status, input_cred_handle, desired_name, + desired_mech, cred_usage, initiator_time_req, + acceptor_time_req, output_cred_handle, + actual_mechs, initiator_time_rec, + acceptor_time_rec)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_add_oid_set_member(minor_status, member_oid, oid_set) + OM_uint32 *minor_status; + gss_OID member_oid; + gss_OID_set *oid_set; +{ + return(generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)); +} + +OM_uint32 INTERFACE +gss_compare_name(minor_status, name1, name2, name_equal) + OM_uint32 *minor_status; + gss_name_t name1; + gss_name_t name2; + int *name_equal; +{ + return(krb5_gss_compare_name(minor_status, name1, + name2, name_equal)); +} + +OM_uint32 INTERFACE +gss_context_time(minor_status, context_handle, time_rec) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + OM_uint32 *time_rec; +{ + return(krb5_gss_context_time(minor_status, context_handle, + time_rec)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_create_empty_oid_set(minor_status, oid_set) + OM_uint32 *minor_status; + gss_OID_set *oid_set; +{ + return(generic_gss_create_empty_oid_set(minor_status, oid_set)); +} + +OM_uint32 INTERFACE +gss_delete_sec_context(minor_status, context_handle, output_token) + OM_uint32 *minor_status; + gss_ctx_id_t *context_handle; + gss_buffer_t output_token; +{ + return(krb5_gss_delete_sec_context(minor_status, + context_handle, output_token)); +} + +OM_uint32 INTERFACE +gss_display_name(minor_status, input_name, output_name_buffer, output_name_type) + OM_uint32 *minor_status; + gss_name_t input_name; + gss_buffer_t output_name_buffer; + gss_OID *output_name_type; +{ + return(krb5_gss_display_name(minor_status, input_name, + output_name_buffer, output_name_type)); +} + +OM_uint32 INTERFACE +gss_display_status(minor_status, status_value, status_type, + mech_type, message_context, status_string) + OM_uint32 *minor_status; + OM_uint32 status_value; + int status_type; + gss_OID mech_type; + OM_uint32 *message_context; + gss_buffer_t status_string; +{ + return(krb5_gss_display_status(minor_status, status_value, + status_type, mech_type, message_context, + status_string)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_export_sec_context(minor_status, context_handle, interprocess_token) + OM_uint32 *minor_status; + gss_ctx_id_t *context_handle; + gss_buffer_t interprocess_token; +{ + return(krb5_gss_export_sec_context(minor_status, + context_handle, + interprocess_token)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_get_mic(minor_status, context_handle, qop_req, + message_buffer, message_token) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_qop_t qop_req; + gss_buffer_t message_buffer; + gss_buffer_t message_token; +{ + return(krb5_gss_get_mic(minor_status, context_handle, + qop_req, message_buffer, message_token)); +} + +OM_uint32 INTERFACE +gss_import_name(minor_status, input_name_buffer, input_name_type, output_name) + OM_uint32 *minor_status; + gss_buffer_t input_name_buffer; + gss_OID input_name_type; + gss_name_t *output_name; +{ + return(krb5_gss_import_name(minor_status, input_name_buffer, + input_name_type, output_name)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_import_sec_context(minor_status, interprocess_token, context_handle) + OM_uint32 *minor_status; + gss_buffer_t interprocess_token; + gss_ctx_id_t *context_handle; +{ + return(krb5_gss_import_sec_context(minor_status, + interprocess_token, + context_handle)); +} + +OM_uint32 INTERFACE +gss_indicate_mechs(minor_status, mech_set) + OM_uint32 *minor_status; + gss_OID_set *mech_set; +{ + return(krb5_gss_indicate_mechs(minor_status, mech_set)); +} + +OM_uint32 INTERFACE +gss_init_sec_context(minor_status, claimant_cred_handle, context_handle, + target_name, mech_type, req_flags, time_req, + input_chan_bindings, input_token, actual_mech_type, + output_token, ret_flags, time_rec) + OM_uint32 *minor_status; + gss_cred_id_t claimant_cred_handle; + gss_ctx_id_t *context_handle; + gss_name_t target_name; + gss_OID mech_type; + OM_uint32 req_flags; + OM_uint32 time_req; + gss_channel_bindings_t input_chan_bindings; + gss_buffer_t input_token; + gss_OID *actual_mech_type; + gss_buffer_t output_token; + OM_uint32 *ret_flags; + OM_uint32 *time_rec; +{ + return(krb5_gss_init_sec_context(minor_status, + claimant_cred_handle, context_handle, + target_name, mech_type, req_flags, + time_req, input_chan_bindings, input_token, + actual_mech_type, output_token, ret_flags, + time_rec)); +} + +OM_uint32 INTERFACE +gss_inquire_context(minor_status, context_handle, initiator_name, acceptor_name, + lifetime_rec, mech_type, ret_flags, + locally_initiated, open) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_name_t *initiator_name; + gss_name_t *acceptor_name; + OM_uint32 *lifetime_rec; + gss_OID *mech_type; + OM_uint32 *ret_flags; + int *locally_initiated; + int *open; +{ + return(krb5_gss_inquire_context(minor_status, context_handle, + initiator_name, acceptor_name, lifetime_rec, + mech_type, ret_flags, locally_initiated, + open)); +} + +OM_uint32 INTERFACE +gss_inquire_cred(minor_status, cred_handle, name, lifetime_ret, + cred_usage, mechanisms) + OM_uint32 *minor_status; + gss_cred_id_t cred_handle; + gss_name_t *name; + OM_uint32 *lifetime_ret; + gss_cred_usage_t *cred_usage; + gss_OID_set *mechanisms; +{ + return(krb5_gss_inquire_cred(minor_status, cred_handle, + name, lifetime_ret, cred_usage, mechanisms)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, name, + initiator_lifetime, acceptor_lifetime, cred_usage) + OM_uint32 *minor_status; + gss_cred_id_t cred_handle; + gss_OID mech_type; + gss_name_t *name; + OM_uint32 *initiator_lifetime; + OM_uint32 *acceptor_lifetime; + gss_cred_usage_t *cred_usage; +{ + return(krb5_gss_inquire_cred_by_mech(minor_status, cred_handle, + mech_type, name, initiator_lifetime, + acceptor_lifetime, cred_usage)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_inquire_names_for_mech(minor_status, mechanism, name_types) + OM_uint32 *minor_status; + gss_OID mechanism; + gss_OID_set *name_types; +{ + return(krb5_gss_inquire_names_for_mech(minor_status, + mechanism, + name_types)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_oid_to_str(minor_status, oid, oid_str) + OM_uint32 *minor_status; + gss_OID oid; + gss_buffer_t oid_str; +{ + return(generic_gss_oid_to_str(minor_status, oid, oid_str)); +} + +OM_uint32 INTERFACE +gss_process_context_token(minor_status, context_handle, token_buffer) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t token_buffer; +{ + return(krb5_gss_process_context_token(minor_status, + context_handle, token_buffer)); +} + +OM_uint32 INTERFACE +gss_release_cred(minor_status, cred_handle) + OM_uint32 *minor_status; + gss_cred_id_t *cred_handle; +{ + return(krb5_gss_release_cred(minor_status, cred_handle)); +} + +OM_uint32 INTERFACE +gss_release_name(minor_status, input_name) + OM_uint32 *minor_status; + gss_name_t *input_name; +{ + return(krb5_gss_release_name(minor_status, input_name)); +} + +OM_uint32 INTERFACE +gss_release_buffer(minor_status, buffer) + OM_uint32 *minor_status; + gss_buffer_t buffer; +{ + return(generic_gss_release_buffer(minor_status, + buffer)); +} + +#if 0 +/* V2 */ +OM_uint32 INTERFACE +gss_release_oid(minor_status, oid) + OM_uint32 *minor_status; + gss_OID *oid; +{ + return(krb5_gss_release_oid(minor_status, oid)); +} +#endif + +OM_uint32 INTERFACE +gss_release_oid_set(minor_status, set) + OM_uint32* minor_status; + gss_OID_set *set; +{ + return(generic_gss_release_oid_set(minor_status, set)); +} + +/* V1 only */ +OM_uint32 INTERFACE +gss_seal(minor_status, context_handle, conf_req_flag, qop_req, + input_message_buffer, conf_state, output_message_buffer) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + int conf_req_flag; + int qop_req; + gss_buffer_t input_message_buffer; + int *conf_state; + gss_buffer_t output_message_buffer; +{ + return(krb5_gss_seal(minor_status, context_handle, + conf_req_flag, qop_req, input_message_buffer, + conf_state, output_message_buffer)); +} + +OM_uint32 INTERFACE +gss_sign(minor_status, context_handle, + qop_req, message_buffer, + message_token) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + int qop_req; + gss_buffer_t message_buffer; + gss_buffer_t message_token; +{ + return(krb5_gss_sign(minor_status, context_handle, + qop_req, message_buffer, message_token)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_verify_mic(minor_status, context_handle, + message_buffer, token_buffer, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t message_buffer; + gss_buffer_t token_buffer; + gss_qop_t *qop_state; +{ + return(krb5_gss_verify_mic(minor_status, context_handle, + message_buffer, token_buffer, qop_state)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, + input_message_buffer, conf_state, output_message_buffer) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + int conf_req_flag; + gss_qop_t qop_req; + gss_buffer_t input_message_buffer; + int *conf_state; + gss_buffer_t output_message_buffer; +{ + return(krb5_gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, + input_message_buffer, conf_state, + output_message_buffer)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_str_to_oid(minor_status, oid_str, oid) + OM_uint32 *minor_status; + gss_buffer_t oid_str; + gss_OID *oid; +{ + return(generic_gss_str_to_oid(minor_status, oid_str, oid)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_test_oid_set_member(minor_status, member, set, present) + OM_uint32 *minor_status; + gss_OID member; + gss_OID_set set; + int *present; +{ + return(generic_gss_test_oid_set_member(minor_status, member, set, + present)); +} + +/* V1 only */ +OM_uint32 INTERFACE +gss_unseal(minor_status, context_handle, input_message_buffer, + output_message_buffer, conf_state, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t input_message_buffer; + gss_buffer_t output_message_buffer; + int *conf_state; + int *qop_state; +{ + return(krb5_gss_unseal(minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state)); +} + +/* V2 */ +OM_uint32 INTERFACE +gss_unwrap(minor_status, context_handle, input_message_buffer, + output_message_buffer, conf_state, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t input_message_buffer; + gss_buffer_t output_message_buffer; + int *conf_state; + gss_qop_t *qop_state; +{ + return(krb5_gss_unwrap(minor_status, context_handle, input_message_buffer, + output_message_buffer, conf_state, qop_state)); +} + +/* V1 only */ +OM_uint32 INTERFACE +gss_verify(minor_status, context_handle, message_buffer, + token_buffer, qop_state) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + gss_buffer_t message_buffer; + gss_buffer_t token_buffer; + int *qop_state; +{ + return(krb5_gss_verify(minor_status, + context_handle, + message_buffer, + token_buffer, + qop_state)); +} + +/* V2 interface */ +OM_uint32 INTERFACE +gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, + qop_req, req_output_size, max_input_size) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + int conf_req_flag; + gss_qop_t qop_req; + OM_uint32 req_output_size; + OM_uint32 *max_input_size; +{ + return(krb5_gss_wrap_size_limit(minor_status, context_handle, + conf_req_flag, qop_req, + req_output_size, max_input_size)); +} diff --git a/src/lib/gssapi/krb5/process_context_token.c b/src/lib/gssapi/krb5/process_context_token.c index 80affbd27..4639108d5 100644 --- a/src/lib/gssapi/krb5/process_context_token.c +++ b/src/lib/gssapi/krb5/process_context_token.c @@ -22,18 +22,24 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_process_context_token(ct, minor_status, context_handle, +krb5_gss_process_context_token(minor_status, context_handle, token_buffer) - void *ct; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t token_buffer; { - krb5_context context = ct; + krb5_context context; krb5_gss_ctx_id_rec *ctx; OM_uint32 majerr; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + /* validate the context handle */ if (! kg_validate_ctx_id(context_handle)) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; @@ -56,6 +62,6 @@ krb5_gss_process_context_token(ct, minor_status, context_handle, /* that's it. delete the context */ - return(krb5_gss_delete_sec_context(context, minor_status, &context_handle, + return(krb5_gss_delete_sec_context(minor_status, &context_handle, GSS_C_NO_BUFFER)); } diff --git a/src/lib/gssapi/krb5/rel_cred.c b/src/lib/gssapi/krb5/rel_cred.c index 297699fe1..df301987b 100644 --- a/src/lib/gssapi/krb5/rel_cred.c +++ b/src/lib/gssapi/krb5/rel_cred.c @@ -23,15 +23,17 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_release_cred(ctx, minor_status, cred_handle) - void *ctx; +krb5_gss_release_cred(minor_status, cred_handle) OM_uint32 *minor_status; gss_cred_id_t *cred_handle; { - krb5_context context = ctx; + krb5_context context; krb5_gss_cred_id_t cred; krb5_error_code code1, code2; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (*cred_handle == GSS_C_NO_CREDENTIAL) return(kg_release_defcred(minor_status)); diff --git a/src/lib/gssapi/krb5/rel_name.c b/src/lib/gssapi/krb5/rel_name.c index 40ff0d2d3..56f56d060 100644 --- a/src/lib/gssapi/krb5/rel_name.c +++ b/src/lib/gssapi/krb5/rel_name.c @@ -23,13 +23,15 @@ #include "gssapiP_krb5.h" OM_uint32 -krb5_gss_release_name(ctx, minor_status, input_name) - void *ctx; +krb5_gss_release_name(minor_status, input_name) OM_uint32 *minor_status; gss_name_t *input_name; { - krb5_context context = ctx; + krb5_context context; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + if (! kg_validate_name(*input_name)) { *minor_status = (OM_uint32) G_VALIDATE_FAILED; return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); diff --git a/src/lib/gssapi/krb5/rel_oid.c b/src/lib/gssapi/krb5/rel_oid.c index 32e697ace..d5ec7bcc7 100644 --- a/src/lib/gssapi/krb5/rel_oid.c +++ b/src/lib/gssapi/krb5/rel_oid.c @@ -73,6 +73,7 @@ krb5_gss_internal_release_oid(ct, minor_status, oid) */ if ((*oid != gss_mech_krb5) && + (*oid != gss_mech_krb5_old) && (*oid != gss_nt_krb5_name) && (*oid != gss_nt_krb5_principal)) { /* We don't know about this OID */ diff --git a/src/lib/gssapi/krb5/seal.c b/src/lib/gssapi/krb5/seal.c index ca52a60af..818de191f 100644 --- a/src/lib/gssapi/krb5/seal.c +++ b/src/lib/gssapi/krb5/seal.c @@ -22,11 +22,14 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag, +krb5_gss_seal(minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int conf_req_flag; @@ -35,7 +38,11 @@ krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag, int *conf_state; gss_buffer_t output_message_buffer; { - krb5_context context = ctx; + krb5_context context; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + return(kg_seal(context, minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer, KG_TOK_SEAL_MSG)); @@ -43,10 +50,9 @@ krb5_gss_seal(ctx, minor_status, context_handle, conf_req_flag, /* V2 interface */ OM_uint32 -krb5_gss_wrap(ctx, minor_status, context_handle, conf_req_flag, +krb5_gss_wrap(minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int conf_req_flag; @@ -55,28 +61,13 @@ krb5_gss_wrap(ctx, minor_status, context_handle, conf_req_flag, int *conf_state; gss_buffer_t output_message_buffer; { - krb5_context context = ctx; + krb5_context context; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + return(kg_seal(context, minor_status, context_handle, conf_req_flag, (int) qop_req, input_message_buffer, conf_state, output_message_buffer, KG_TOK_WRAP_MSG)); } -/* V2 interface */ -OM_uint32 -krb5_gss_wrap_size_limit(ctx, minor_status, context_handle, conf_req_flag, - qop_req, req_output_size, max_input_size) - void *ctx; - OM_uint32 *minor_status; - gss_ctx_id_t context_handle; - int conf_req_flag; - gss_qop_t qop_req; - OM_uint32 req_output_size; - OM_uint32 *max_input_size; -{ - krb5_context context = ctx; - - /* XXX - should just put this in k5seal.c */ - return(kg_seal_size(context, minor_status, context_handle, conf_req_flag, - qop_req, req_output_size, max_input_size)); -} diff --git a/src/lib/gssapi/krb5/ser_sctx.c b/src/lib/gssapi/krb5/ser_sctx.c index 5acfd5c67..2a8cd0dd0 100644 --- a/src/lib/gssapi/krb5/ser_sctx.c +++ b/src/lib/gssapi/krb5/ser_sctx.c @@ -28,264 +28,17 @@ #include "gssapiP_krb5.h" /* - * This module contains routines to [de]serialize krb5_gss_cred_id_t, + * This module contains routines to [de]serialize * krb5_gss_enc_desc and krb5_gss_ctx_id_t. + * XXX This whole serialization abstraction is unnecessary in a + * non-messaging environment, which krb5 is. Someday, this should + * all get redone without the extra level of indirection. I've done + * some of this work here, since adding new serializers is an internal + * krb5 interface, and I won't use those. There is some more + * deobfuscation (no longer anonymizing pointers, mostly) which could + * still be done. --marc */ - -/* Windows needs these prototypes since the structure they're assigned - * into is prototyped. - */ -static krb5_error_code kg_cred_size - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - size_t *sizep)); - -static krb5_error_code kg_cred_externalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - krb5_octet **buffer, - size_t *lenremain)); - -static krb5_error_code kg_cred_internalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer *argp, - krb5_octet **buffer, - size_t *lenremain)); - -static krb5_error_code kg_enc_desc_size - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - size_t *sizep)); - -static krb5_error_code kg_enc_desc_externalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - krb5_octet **buffer, - size_t *lenremain)); - -static krb5_error_code kg_enc_desc_internalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer *argp, - krb5_octet **buffer, - size_t *lenremain)); - -static krb5_error_code kg_ctx_size - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - size_t *sizep)); - -static krb5_error_code kg_ctx_externalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer arg, - krb5_octet **buffer, - size_t *lenremain)); - -static krb5_error_code kg_ctx_internalize - PROTOTYPE((krb5_context kcontext, - krb5_pointer *argp, - krb5_octet **buffer, - size_t *lenremain)); - -/* - * Determine the size required for this krb5_gss_cred_id_t. - */ -static krb5_error_code -kg_cred_size(kcontext, arg, sizep) - krb5_context kcontext; - krb5_pointer arg; - size_t *sizep; -{ - krb5_error_code kret; - krb5_gss_cred_id_t cred; - size_t required; - - /* - * krb5_gss_cred_id_t requires: - * krb5_int32 for KG_CRED - * krb5_int32 for usage. - * krb5_int32 for tgt_expire. - * krb5_int32 for trailer. - */ - kret = EINVAL; - if ((cred = (krb5_gss_cred_id_t) arg)) { - required = 4*sizeof(krb5_int32); - kret = 0; - if (cred->princ) - kret = krb5_size_opaque(kcontext, - KV5M_PRINCIPAL, - (krb5_pointer) cred->princ, - &required); - if (!kret && cred->keytab) - kret = krb5_size_opaque(kcontext, - KV5M_KEYTAB, - (krb5_pointer) cred->keytab, - &required); - - if (!kret && cred->ccache) - kret = krb5_size_opaque(kcontext, - KV5M_CCACHE, - (krb5_pointer) cred->ccache, - &required); - if (!kret) - *sizep += required; - } - return(kret); -} - -/* - * Externalize this krb5_gss_cred_id_t. - */ -static krb5_error_code -kg_cred_externalize(kcontext, arg, buffer, lenremain) - krb5_context kcontext; - krb5_pointer arg; - krb5_octet **buffer; - size_t *lenremain; -{ - krb5_error_code kret; - krb5_gss_cred_id_t cred; - size_t required; - krb5_octet *bp; - size_t remain; - - required = 0; - bp = *buffer; - remain = *lenremain; - kret = EINVAL; - if ((cred = (krb5_gss_cred_id_t) arg)) { - kret = ENOMEM; - if (!kg_cred_size(kcontext, arg, &required) && - (required <= remain)) { - /* Our identifier */ - (void) krb5_ser_pack_int32(KG_CRED, &bp, &remain); - - /* Now static data */ - (void) krb5_ser_pack_int32((krb5_int32) cred->usage, &bp, &remain); - (void) krb5_ser_pack_int32((krb5_int32) cred->tgt_expire, - &bp, &remain); - - /* Now pack up dynamic data */ - if (cred->princ) - kret = krb5_externalize_opaque(kcontext, - KV5M_PRINCIPAL, - (krb5_pointer) cred->princ, - &bp, &remain); - else - kret = 0; - - if (!kret && cred->keytab) - kret = krb5_externalize_opaque(kcontext, - KV5M_KEYTAB, - (krb5_pointer) cred->keytab, - &bp, &remain); - - if (!kret && cred->ccache) - kret = krb5_externalize_opaque(kcontext, - KV5M_CCACHE, - (krb5_pointer) cred->ccache, - &bp, &remain); - - if (!kret) { - (void) krb5_ser_pack_int32(KG_CRED, &bp, &remain); - *buffer = bp; - *lenremain = remain; - } - } - } - return(kret); -} - -/* - * Internalize this krb5_gss_cred_id_t. - */ -static krb5_error_code -kg_cred_internalize(kcontext, argp, buffer, lenremain) - krb5_context kcontext; - krb5_pointer *argp; - krb5_octet **buffer; - size_t *lenremain; -{ - krb5_error_code kret; - krb5_gss_cred_id_t cred; - krb5_int32 ibuf; - krb5_octet *bp; - size_t remain; - - bp = *buffer; - remain = *lenremain; - kret = EINVAL; - /* Read our magic number */ - if (krb5_ser_unpack_int32(&ibuf, &bp, &remain)) - ibuf = 0; - if (ibuf == KG_CRED) { - kret = ENOMEM; - - /* Get a cred */ - if ((remain >= (2*sizeof(krb5_int32))) && - (cred = (krb5_gss_cred_id_t) - xmalloc(sizeof(krb5_gss_cred_id_rec)))) { - memset(cred, 0, sizeof(krb5_gss_cred_id_rec)); - - /* Get the static data */ - (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); - cred->usage = (int) ibuf; - (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); - cred->tgt_expire = (krb5_timestamp) ibuf; - - /* cred->princ */ - if ((kret = krb5_internalize_opaque(kcontext, - KV5M_PRINCIPAL, - (krb5_pointer *) &cred->princ, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - - /* cred->keytab */ - if (!kret && - (kret = krb5_internalize_opaque(kcontext, - KV5M_KEYTAB, - (krb5_pointer *) &cred->keytab, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - - /* cred->ccache */ - if (!kret && - (kret = krb5_internalize_opaque(kcontext, - KV5M_CCACHE, - (krb5_pointer *) &cred->ccache, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } - - /* trailer */ - if (!kret && - !(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain)) && - (ibuf == KG_CRED)) { - *buffer = bp; - *lenremain = remain; - *argp = (krb5_pointer) cred; - } - else { - if (!kret && (ibuf != KG_CRED)) - kret = EINVAL; - if (cred->ccache) - krb5_cc_close(kcontext, cred->ccache); - if (cred->keytab) - krb5_kt_close(kcontext, cred->keytab); - if (cred->princ) - krb5_free_principal(kcontext, cred->princ); - xfree(cred); - } - } - } - return(kret); -} - /* * Determine the size required for this krb5_gss_enc_desc. */ @@ -332,7 +85,7 @@ kg_enc_desc_size(kcontext, arg, sizep) } return(kret); } - + /* * Externalize this krb5_gss_enc_desc. */ @@ -387,7 +140,7 @@ kg_enc_desc_externalize(kcontext, arg, buffer, lenremain) } return(kret); } - + /* * Internalize this krb5_gss_enc_desc. */ @@ -471,27 +224,88 @@ kg_enc_desc_internalize(kcontext, argp, buffer, lenremain) } return(kret); } - + +static krb5_error_code +kg_oid_externalize(kcontext, arg, buffer, lenremain) + krb5_context kcontext; + krb5_pointer arg; + krb5_octet **buffer; + size_t *lenremain; +{ + gss_OID oid = (gss_OID) arg; + + (void) krb5_ser_pack_int32((krb5_int32) oid->length, + buffer, lenremain); + (void) krb5_ser_pack_bytes((krb5_octet *) oid->elements, + oid->length, buffer, lenremain); +} + +static krb5_error_code +kg_oid_internalize(kcontext, argp, buffer, lenremain) + krb5_context kcontext; + krb5_pointer *argp; + krb5_octet **buffer; + size_t *lenremain; +{ + gss_OID oid; + krb5_int32 ibuf; + + oid = (gss_OID) malloc(sizeof(gss_OID_desc)); + if (oid == NULL) + return ENOMEM; + (void) krb5_ser_unpack_int32(&ibuf, buffer, lenremain); + oid->length = ibuf; + (void) krb5_ser_unpack_bytes((krb5_octet *) oid->elements, + oid->length, buffer, lenremain); + return 0; +} + +krb5_error_code +kg_oid_size(kcontext, arg, sizep) + krb5_context kcontext; + krb5_pointer arg; + size_t *sizep; +{ + krb5_error_code kret; + gss_OID oid; + size_t required; + + kret = EINVAL; + if ((oid = (gss_OID) arg)) { + required = sizeof(krb5_int32); + required += oid->length; + + kret = 0; + + *sizep += required; + } + + return(kret); +} + /* - * Determine the size required for this krb5_gss_ctx_id_t. + * Determine the size required for this krb5_gss_ctx_id_rec. */ -static krb5_error_code +krb5_error_code kg_ctx_size(kcontext, arg, sizep) krb5_context kcontext; krb5_pointer arg; size_t *sizep; { krb5_error_code kret; - krb5_gss_ctx_id_t *ctx; + krb5_gss_ctx_id_rec *ctx; size_t required; /* - * krb5_gss_ctx_id_t requires: + * krb5_gss_ctx_id_rec requires: * krb5_int32 for KG_CONTEXT * krb5_int32 for initiate. * krb5_int32 for mutual. * krb5_int32 for seed_init. * sizeof(seed) for seed + * krb5_int32 for signalg. + * krb5_int32 for cksum_size. + * krb5_int32 for sealalg. * krb5_int32 for endtime. * krb5_int32 for flags. * krb5_int32 for seq_send. @@ -501,8 +315,8 @@ kg_ctx_size(kcontext, arg, sizep) * krb5_int32 for trailer. */ kret = EINVAL; - if ((ctx = (krb5_gss_ctx_id_t *) arg)) { - required = 11*sizeof(krb5_int32); + if ((ctx = (krb5_gss_ctx_id_rec *) arg)) { + required = 14*sizeof(krb5_int32); required += sizeof(ctx->seed); kret = 0; @@ -525,33 +339,30 @@ kg_ctx_size(kcontext, arg, sizep) &required); if (!kret) - kret = krb5_size_opaque(kcontext, - KG_ENC_DESC, + kret = kg_enc_desc_size(kcontext, (krb5_pointer) &ctx->enc, &required); if (!kret) - kret = krb5_size_opaque(kcontext, - KG_ENC_DESC, + kret = kg_enc_desc_size(kcontext, (krb5_pointer) &ctx->seq, &required); - if (!kret && ctx->auth_context) - kret = krb5_size_opaque(kcontext, - KV5M_AUTH_CONTEXT, - (krb5_pointer) ctx->auth_context, - &required); + if (!kret) + kret = kg_oid_size(kcontext, + (krb5_pointer) ctx->mech_used, + &required); if (!kret) *sizep += required; } return(kret); } - + /* - * Externalize this krb5_gss_ctx_id_t. + * Externalize this krb5_gss_ctx_id_ret. */ -static krb5_error_code +krb5_error_code kg_ctx_externalize(kcontext, arg, buffer, lenremain) krb5_context kcontext; krb5_pointer arg; @@ -559,7 +370,7 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) size_t *lenremain; { krb5_error_code kret; - krb5_gss_ctx_id_t *ctx; + krb5_gss_ctx_id_rec *ctx; size_t required; krb5_octet *bp; size_t remain; @@ -568,7 +379,7 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) bp = *buffer; remain = *lenremain; kret = EINVAL; - if ((ctx = (krb5_gss_ctx_id_t *) arg)) { + if ((ctx = (krb5_gss_ctx_id_rec *) arg)) { kret = ENOMEM; if (!kg_ctx_size(kcontext, arg, &required) && (required <= remain)) { @@ -585,6 +396,12 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) (void) krb5_ser_pack_bytes((krb5_octet *) ctx->seed, sizeof(ctx->seed), &bp, &remain); + (void) krb5_ser_pack_int32((krb5_int32) ctx->signalg, + &bp, &remain); + (void) krb5_ser_pack_int32((krb5_int32) ctx->cksum_size, + &bp, &remain); + (void) krb5_ser_pack_int32((krb5_int32) ctx->sealalg, + &bp, &remain); (void) krb5_ser_pack_int32((krb5_int32) ctx->endtime, &bp, &remain); (void) krb5_ser_pack_int32((krb5_int32) ctx->flags, @@ -601,6 +418,10 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) /* Now dynamic data */ kret = 0; + if (!kret && ctx->mech_used) + kret = kg_oid_externalize(kcontext, ctx->mech_used, + &bp, &remain); + if (!kret && ctx->here) kret = krb5_externalize_opaque(kcontext, KV5M_PRINCIPAL, @@ -620,23 +441,15 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) &bp, &remain); if (!kret) - kret = krb5_externalize_opaque(kcontext, - KG_ENC_DESC, + kret = kg_enc_desc_externalize(kcontext, (krb5_pointer) &ctx->enc, &bp, &remain); if (!kret) - kret = krb5_externalize_opaque(kcontext, - KG_ENC_DESC, + kret = kg_enc_desc_externalize(kcontext, (krb5_pointer) &ctx->seq, &bp, &remain); - if (!kret && ctx->auth_context) - kret = krb5_externalize_opaque(kcontext, - KV5M_AUTH_CONTEXT, - (krb5_pointer)ctx->auth_context, - &bp, &remain); - if (!kret) { (void) krb5_ser_pack_int32(KG_CONTEXT, &bp, &remain); *buffer = bp; @@ -646,11 +459,11 @@ kg_ctx_externalize(kcontext, arg, buffer, lenremain) } return(kret); } - + /* * Internalize this krb5_gss_ctx_id_t. */ -static krb5_error_code +krb5_error_code kg_ctx_internalize(kcontext, argp, buffer, lenremain) krb5_context kcontext; krb5_pointer *argp; @@ -658,7 +471,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) size_t *lenremain; { krb5_error_code kret; - krb5_gss_ctx_id_t *ctx; + krb5_gss_ctx_id_rec *ctx; krb5_int32 ibuf; krb5_octet *bp; size_t remain; @@ -675,9 +488,9 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) /* Get a context */ if ((remain >= ((10*sizeof(krb5_int32))+sizeof(ctx->seed))) && - (ctx = (krb5_gss_ctx_id_t *) - xmalloc(sizeof(krb5_gss_ctx_id_t)))) { - memset(ctx, 0, sizeof(krb5_gss_ctx_id_t)); + (ctx = (krb5_gss_ctx_id_rec *) + xmalloc(sizeof(krb5_gss_ctx_id_rec)))) { + memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec)); /* Get static data */ (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); @@ -690,9 +503,15 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) sizeof(ctx->seed), &bp, &remain); (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->signalg = (int) ibuf; + (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->cksum_size = (int) ibuf; + (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); + ctx->sealalg = (int) ibuf; + (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); ctx->endtime = (krb5_timestamp) ibuf; (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); - ctx->flags = (krb5_timestamp) ibuf; + ctx->flags = (krb5_flags) ibuf; (void) krb5_ser_unpack_int32(&ctx->seq_send, &bp, &remain); (void) krb5_ser_unpack_int32(&ctx->seq_recv, &bp, &remain); (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); @@ -700,6 +519,11 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain); ctx->big_endian = (int) ibuf; + if ((kret = kg_oid_internalize(kcontext, &ctx->mech_used, &bp, + &remain))) { + if (kret == EINVAL) + kret = 0; + } /* Now get substructure data */ if ((kret = krb5_internalize_opaque(kcontext, KV5M_PRINCIPAL, @@ -725,8 +549,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) kret = 0; } if (!kret) { - if ((kret = krb5_internalize_opaque(kcontext, - KG_ENC_DESC, + if ((kret = kg_enc_desc_internalize(kcontext, (krb5_pointer *) &edp, &bp, &remain))) { if (kret == EINVAL) @@ -738,8 +561,7 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) } } if (!kret) { - if ((kret = krb5_internalize_opaque(kcontext, - KG_ENC_DESC, + if ((kret = kg_enc_desc_internalize(kcontext, (krb5_pointer *) &edp, &bp, &remain))) { if (kret == EINVAL) @@ -750,15 +572,6 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) xfree(edp); } } - if (!kret && - (kret = krb5_internalize_opaque(kcontext, - KV5M_AUTH_CONTEXT, - (krb5_pointer *) - &ctx->auth_context, - &bp, &remain))) { - if (kret == EINVAL) - kret = 0; - } /* Get trailer */ if (!kret && @@ -771,8 +584,6 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) else { if (!kret && (ibuf != KG_CONTEXT)) kret = EINVAL; - if (ctx->auth_context) - krb5_auth_con_free(kcontext, ctx->auth_context); if (ctx->seq.eblock.key) krb5_free_keyblock(kcontext, ctx->seq.eblock.key); if (ctx->seq.eblock.priv && ctx->seq.eblock.priv_size) @@ -797,36 +608,3 @@ kg_ctx_internalize(kcontext, argp, buffer, lenremain) } return(kret); } - -static const krb5_ser_entry kg_cred_ser_entry = { - KG_CRED, /* Type */ - kg_cred_size, /* Sizer routine */ - kg_cred_externalize, /* Externalize routine */ - kg_cred_internalize /* Internalize routine */ -}; -static const krb5_ser_entry kg_enc_desc_ser_entry = { - KG_ENC_DESC, /* Type */ - kg_enc_desc_size, /* Sizer routine */ - kg_enc_desc_externalize, /* Externalize routine */ - kg_enc_desc_internalize /* Internalize routine */ -}; -static const krb5_ser_entry kg_ctx_ser_entry = { - KG_CONTEXT, /* Type */ - kg_ctx_size, /* Sizer routine */ - kg_ctx_externalize, /* Externalize routine */ - kg_ctx_internalize /* Internalize routine */ -}; - -krb5_error_code -kg_ser_context_init(kcontext) - krb5_context kcontext; -{ - krb5_error_code kret; - - kret = krb5_register_serializer(kcontext, &kg_cred_ser_entry); - if (!kret) - kret = krb5_register_serializer(kcontext, &kg_enc_desc_ser_entry); - if (!kret) - kret = krb5_register_serializer(kcontext, &kg_ctx_ser_entry); - return(kret); -} diff --git a/src/lib/gssapi/krb5/sign.c b/src/lib/gssapi/krb5/sign.c index c3b6ebf4b..0177f40d4 100644 --- a/src/lib/gssapi/krb5/sign.c +++ b/src/lib/gssapi/krb5/sign.c @@ -22,19 +22,25 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_sign(ctx, minor_status, context_handle, +krb5_gss_sign(minor_status, context_handle, qop_req, message_buffer, message_token) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; int qop_req; gss_buffer_t message_buffer; gss_buffer_t message_token; { - krb5_context context = ctx; + krb5_context context; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + return(kg_seal(context, minor_status, context_handle, 0, qop_req, message_buffer, NULL, message_token, KG_TOK_SIGN_MSG)); @@ -42,17 +48,19 @@ krb5_gss_sign(ctx, minor_status, context_handle, /* V2 interface */ OM_uint32 -krb5_gss_get_mic(ctx, minor_status, context_handle, qop_req, +krb5_gss_get_mic(minor_status, context_handle, qop_req, message_buffer, message_token) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_qop_t qop_req; gss_buffer_t message_buffer; gss_buffer_t message_token; { - krb5_context context = ctx; + krb5_context context; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + return(kg_seal(context, minor_status, context_handle, 0, (int) qop_req, message_buffer, NULL, message_token, KG_TOK_MIC_MSG)); diff --git a/src/lib/gssapi/krb5/unseal.c b/src/lib/gssapi/krb5/unseal.c index da71fa4f4..546521e1b 100644 --- a/src/lib/gssapi/krb5/unseal.c +++ b/src/lib/gssapi/krb5/unseal.c @@ -22,11 +22,14 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_unseal(ctx, minor_status, context_handle, +krb5_gss_unseal(minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t input_message_buffer; @@ -34,7 +37,11 @@ krb5_gss_unseal(ctx, minor_status, context_handle, int *conf_state; int *qop_state; { - krb5_context context = ctx; + krb5_context context; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + return(kg_unseal(context, minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state, KG_TOK_SEAL_MSG)); @@ -42,10 +49,9 @@ krb5_gss_unseal(ctx, minor_status, context_handle, /* V2 interface */ OM_uint32 -krb5_gss_unwrap(ctx, minor_status, context_handle, +krb5_gss_unwrap(minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t input_message_buffer; @@ -53,10 +59,13 @@ krb5_gss_unwrap(ctx, minor_status, context_handle, int *conf_state; gss_qop_t *qop_state; { - krb5_context context = ctx; + krb5_context context; OM_uint32 rstat; int qstate; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + rstat = kg_unseal(context, minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, &qstate, KG_TOK_WRAP_MSG); diff --git a/src/lib/gssapi/krb5/util_cksum.c b/src/lib/gssapi/krb5/util_cksum.c index 0b46d0e5e..ee3e1aafa 100644 --- a/src/lib/gssapi/krb5/util_cksum.c +++ b/src/lib/gssapi/krb5/util_cksum.c @@ -20,11 +20,16 @@ * PERFORMANCE OF THIS SOFTWARE. */ +/* + * $Id$ + */ + #include "gssapiP_krb5.h" #include <memory.h> krb5_error_code -kg_checksum_channel_bindings(cb, cksum, bigend) +kg_checksum_channel_bindings(context, cb, cksum, bigend) + krb5_context context; gss_channel_bindings_t cb; krb5_checksum *cksum; int bigend; @@ -33,20 +38,18 @@ kg_checksum_channel_bindings(cb, cksum, bigend) char *buf, *ptr; krb5_error_code code; - if (!kg_context && (code=kg_get_context())) - return code; - + /* initialize the the cksum and allocate the contents buffer */ + cksum->checksum_type = CKSUMTYPE_RSA_MD5; + cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); + if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { + free(buf); + return(ENOMEM); + } + /* generate a buffer full of zeros if no cb specified */ if (cb == GSS_C_NO_CHANNEL_BINDINGS) { - /* allocate the cksum contents buffer */ - if ((cksum->contents = (krb5_octet *) - xmalloc(krb5_checksum_size(context, CKSUMTYPE_RSA_MD5))) == NULL) - return(ENOMEM); - - cksum->checksum_type = CKSUMTYPE_RSA_MD5; - memset(cksum->contents, '\0', - (cksum->length = krb5_checksum_size(kg_context, CKSUMTYPE_RSA_MD5))); + memset(cksum->contents, '\0', cksum->length); return(0); } @@ -60,13 +63,6 @@ kg_checksum_channel_bindings(cb, cksum, bigend) if ((buf = (char *) xmalloc(len)) == NULL) return(ENOMEM); - /* allocate the cksum contents buffer */ - cksum->length = krb5_checksum_size(context, CKSUMTYPE_RSA_MD5); - if ((cksum->contents = (krb5_octet *) xmalloc(cksum->length)) == NULL) { - free(buf); - return(ENOMEM); - } - /* helper macros. This code currently depends on a long being 32 bits, and htonl dtrt. */ @@ -80,7 +76,7 @@ kg_checksum_channel_bindings(cb, cksum, bigend) /* checksum the data */ - if (code = krb5_calculate_checksum(kg_context, CKSUMTYPE_RSA_MD5, + if (code = krb5_calculate_checksum(context, CKSUMTYPE_RSA_MD5, buf, len, NULL, 0, cksum)) { xfree(cksum->contents); xfree(buf); diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c index 89028270e..bf49de41d 100644 --- a/src/lib/gssapi/krb5/util_crypt.c +++ b/src/lib/gssapi/krb5/util_crypt.c @@ -23,6 +23,10 @@ #include "gssapiP_krb5.h" #include <memory.h> +/* + * $Id$ + */ + static unsigned char zeros[8] = {0,0,0,0,0,0,0,0}; int @@ -39,7 +43,7 @@ kg_make_confounder(ed, buf) krb5_gss_enc_desc *ed; unsigned char *buf; { - return(krb5_random_confounder( ed->eblock.crypto_entry->block_length, buf)); + return(krb5_random_confounder(ed->eblock.crypto_entry->block_length, buf)); } int @@ -51,7 +55,8 @@ kg_encrypt_size(ed, n) } krb5_error_code -kg_encrypt(ed, iv, in, out, length) +kg_encrypt(context, ed, iv, in, out, length) + krb5_context context; krb5_gss_enc_desc *ed; krb5_pointer iv; krb5_pointer in; @@ -59,18 +64,29 @@ kg_encrypt(ed, iv, in, out, length) int length; { krb5_error_code code; + krb5_pointer tmp; - if (!kg_context && (code=kg_get_context())) - return code; - if (! ed->processed) { - if (code = krb5_process_key(kg_context, &ed->eblock, ed->key)) + if (code = krb5_process_key(context, &ed->eblock, ed->key)) return(code); ed->processed = 1; } - if (code = krb5_encrypt(kg_context, in, out, length, &ed->eblock, - iv?iv:(krb5_pointer)zeros)) + /* this is lame. the krb5 encryption interfaces no longer allow + you to encrypt in place. perhaps this should be fixed, but + dealing here is easier for now --marc */ + + if ((tmp = (krb5_pointer) xmalloc(length)) == NULL) + return(ENOMEM); + + memcpy(tmp, in, length); + + code = krb5_encrypt(context, tmp, out, length, &ed->eblock, + iv?iv:(krb5_pointer)zeros); + + xfree(tmp); + + if (code) return(code); return(0); @@ -79,7 +95,8 @@ kg_encrypt(ed, iv, in, out, length) /* length is the length of the cleartext. */ krb5_error_code -kg_decrypt(ed, iv, in, out, length) +kg_decrypt(context, ed, iv, in, out, length) + krb5_context context; krb5_gss_enc_desc *ed; krb5_pointer iv; krb5_pointer in; @@ -90,11 +107,8 @@ kg_decrypt(ed, iv, in, out, length) int elen; char *buf; - if (!kg_context && (code=kg_get_context())) - return code; - if (! ed->processed) { - if (code = krb5_process_key(kg_context, &ed->eblock, ed->key)) + if (code = krb5_process_key(context, &ed->eblock, ed->key)) return(code); ed->processed = 1; } @@ -103,7 +117,7 @@ kg_decrypt(ed, iv, in, out, length) if ((buf = (char *) xmalloc(elen)) == NULL) return(ENOMEM); - if (code = krb5_decrypt(kg_context, in, buf, elen, &ed->eblock, + if (code = krb5_decrypt(context, in, buf, elen, &ed->eblock, iv?iv:(krb5_pointer)zeros)) { xfree(buf); return(code); diff --git a/src/lib/gssapi/krb5/util_seed.c b/src/lib/gssapi/krb5/util_seed.c index ed60922d5..14f365245 100644 --- a/src/lib/gssapi/krb5/util_seed.c +++ b/src/lib/gssapi/krb5/util_seed.c @@ -23,10 +23,15 @@ #include "gssapiP_krb5.h" #include <memory.h> +/* + * $Id$ + */ + static unsigned char zeros[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; krb5_error_code -kg_make_seed(key, seed) +kg_make_seed(context, key, seed) + krb5_context context; krb5_keyblock *key; unsigned char *seed; { @@ -34,10 +39,7 @@ kg_make_seed(key, seed) krb5_gss_enc_desc ed; int i; - if (!kg_context && (code=kg_get_context())) - return code; - - if (code = krb5_copy_keyblock(kg_context, key, &ed.key)) + if (code = krb5_copy_keyblock(context, key, &ed.key)) return(code); /* reverse the key bytes, as per spec */ @@ -45,13 +47,13 @@ kg_make_seed(key, seed) for (i=0; i<ed.key->length; i++) ed.key->contents[i] = key->contents[key->length - 1 - i]; - krb5_use_enctype(kg_context, &ed.eblock, ENCTYPE_DES_CBC_RAW); + krb5_use_enctype(context, &ed.eblock, ENCTYPE_DES_CBC_RAW); ed.processed = 0; - code = kg_encrypt(&ed, NULL, zeros, seed, 16); + code = kg_encrypt(context, &ed, NULL, zeros, seed, 16); - krb5_finish_key(kg_context, &ed.eblock); - krb5_free_keyblock(kg_context, ed.key); + krb5_finish_key(context, &ed.eblock); + krb5_free_keyblock(context, ed.key); return(code); } diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c index 67bcda6db..ed9293f77 100644 --- a/src/lib/gssapi/krb5/util_seqnum.c +++ b/src/lib/gssapi/krb5/util_seqnum.c @@ -22,8 +22,13 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + krb5_error_code -kg_make_seq_num(ed, direction, seqnum, cksum, buf) +kg_make_seq_num(context, ed, direction, seqnum, cksum, buf) + krb5_context context; krb5_gss_enc_desc *ed; int direction; krb5_int32 seqnum; @@ -42,5 +47,34 @@ kg_make_seq_num(ed, direction, seqnum, cksum, buf) plain[6] = direction; plain[7] = direction; - return(kg_encrypt(ed, cksum, plain, buf, 8)); + return(kg_encrypt(context, ed, cksum, plain, buf, 8)); +} + +krb5_error_code kg_get_seq_num(context, ed, cksum, buf, direction, seqnum) + krb5_context context; + krb5_gss_enc_desc *ed; + unsigned char *cksum; + unsigned char *buf; + int *direction; + krb5_int32 *seqnum; +{ + krb5_error_code code; + unsigned char plain[8]; + + if (code = kg_decrypt(context, ed, cksum, buf, plain, 8)) + return(code); + + if ((plain[4] != plain[5]) || + (plain[4] != plain[6]) || + (plain[4] != plain[7])) + return((krb5_error_code) KG_BAD_SEQ); + + *direction = plain[4]; + + *seqnum = ((plain[0]) | + (plain[1]<<8) | + (plain[2]<<16) | + (plain[3]<<24)); + + return(0); } diff --git a/src/lib/gssapi/krb5/verify.c b/src/lib/gssapi/krb5/verify.c index 33ee8fb8c..0e7305640 100644 --- a/src/lib/gssapi/krb5/verify.c +++ b/src/lib/gssapi/krb5/verify.c @@ -22,39 +22,50 @@ #include "gssapiP_krb5.h" +/* + * $Id$ + */ + OM_uint32 -krb5_gss_verify(ctx, minor_status, context_handle, +krb5_gss_verify(minor_status, context_handle, message_buffer, token_buffer, qop_state) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t message_buffer; gss_buffer_t token_buffer; int *qop_state; { - krb5_context context = ctx; - return(kg_unseal(context, minor_status, context_handle, - token_buffer, message_buffer, - NULL, qop_state, KG_TOK_SIGN_MSG)); + krb5_context context; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + + + return(kg_unseal(context, minor_status, context_handle, + token_buffer, message_buffer, + NULL, qop_state, KG_TOK_SIGN_MSG)); } /* V2 interface */ OM_uint32 -krb5_gss_verify_mic(ctx, minor_status, context_handle, +krb5_gss_verify_mic(minor_status, context_handle, message_buffer, token_buffer, qop_state) - void *ctx; OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t message_buffer; gss_buffer_t token_buffer; gss_qop_t *qop_state; { - krb5_context context = ctx; + krb5_context context; OM_uint32 rstat; int qstate; + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + + rstat = kg_unseal(context, minor_status, context_handle, token_buffer, message_buffer, NULL, &qstate, KG_TOK_MIC_MSG); diff --git a/src/lib/gssapi/krb5/wrap_size_limit.c b/src/lib/gssapi/krb5/wrap_size_limit.c new file mode 100644 index 000000000..8c47d0fa6 --- /dev/null +++ b/src/lib/gssapi/krb5/wrap_size_limit.c @@ -0,0 +1,75 @@ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "gssapiP_krb5.h" + +/* + * $Id$ + */ + +/* V2 interface */ +OM_uint32 +krb5_gss_wrap_size_limit(minor_status, context_handle, conf_req_flag, + qop_req, req_output_size, max_input_size) + OM_uint32 *minor_status; + gss_ctx_id_t context_handle; + int conf_req_flag; + gss_qop_t qop_req; + OM_uint32 req_output_size; + OM_uint32 *max_input_size; +{ + krb5_context context; + krb5_gss_ctx_id_rec *ctx; + OM_uint32 cfsize; + OM_uint32 ohlen; + + if (GSS_ERROR(kg_get_context(minor_status, &context))) + return(GSS_S_FAILURE); + + /* only default qop is allowed */ + if (qop_req != GSS_C_QOP_DEFAULT) { + *minor_status = (OM_uint32) G_UNKNOWN_QOP; + return(GSS_S_FAILURE); + } + + /* validate the context handle */ + if (! kg_validate_ctx_id(context_handle)) { + *minor_status = (OM_uint32) G_VALIDATE_FAILED; + return(GSS_S_NO_CONTEXT); + } + + ctx = (krb5_gss_ctx_id_rec *) context_handle; + if (! ctx->established) { + *minor_status = KG_CTX_INCOMPLETE; + return(GSS_S_NO_CONTEXT); + } + + /* Calculate the token size and subtract that from the output size */ + cfsize = (conf_req_flag) ? kg_confounder_size(&ctx->enc) : 0; + ohlen = g_token_size((gss_OID) ctx->mech_used, + (unsigned int) cfsize + ctx->cksum_size + 14); + + /* Cannot have trailer length that will cause us to pad over our length */ + *max_input_size = (req_output_size - ohlen) & (~7); + *minor_status = 0; + return(GSS_S_COMPLETE); +} diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index e82cfbba0..22b8c5bdb 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -74,6 +74,17 @@ typedef struct gss_union_cred_t { /* define one of these and provide a function to return */ /* it to initialize the GSSAPI library */ +/* ultrix cc doesn't understand prototypes in structures. + we could autoconf test for this --marc */ + +#ifndef NPROTOTYPE +#if defined(__ultrix) && !defined (__GNUC__) +#define NPROTOTYPE(x) () +#else +#define NPROTOTYPE(x) PROTOTYPE(x) +#endif +#endif + /* * This is the definition of the mechs_array struct, which is used to * define the mechs array table. This table is used to indirectly diff --git a/src/lib/kadm/ChangeLog b/src/lib/kadm/ChangeLog index 6e9e4d64e..ac07e1981 100644 --- a/src/lib/kadm/ChangeLog +++ b/src/lib/kadm/ChangeLog @@ -13,6 +13,11 @@ Tue May 21 20:51:06 1996 Sam Hartman <hartmans@mit.edu> * Makefile.in (check-unix): Use KRB5_RUN_FLAGS +Sun May 12 00:46:57 1996 Marc Horowitz <marc@mit.edu> + + * alt_prof.c (krb5_read_realm_params): added "acl_file" variable + for the admin server. + Wed Mar 13 17:37:00 1996 Ken Raeburn <raeburn@cygnus.com> * configure.in: Use AC_HEADER_STDARG. diff --git a/src/lib/kadm/alt_prof.c b/src/lib/kadm/alt_prof.c index d4512c41c..9556ac450 100644 --- a/src/lib/kadm/alt_prof.c +++ b/src/lib/kadm/alt_prof.c @@ -305,6 +305,11 @@ krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp) if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) rparams->realm_kdc_ports = svalue; + /* Get the name of the acl file */ + hierarchy[2] = "acl_file"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_acl_file = svalue; + /* Get the value for the kadmind port */ hierarchy[2] = "kadmind_port"; if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { diff --git a/src/lib/kadm5/ChangeLog b/src/lib/kadm5/ChangeLog new file mode 100644 index 000000000..a10d351d1 --- /dev/null +++ b/src/lib/kadm5/ChangeLog @@ -0,0 +1,81 @@ +Mon Jul 22 04:17:23 1996 Marc Horowitz <marc@mit.edu> + + * configure.in (LIBS): add -lgen to LIBS whenever compile is + found. Solaris requires it. + + * chpass_util.c (_kadm5_chpass_principal_util): the calls to + kadm5_free_{princicpal,policy}_ent used server_handle instead of + lhandle, which caused problems in the api versioning code. + +Thu Jul 18 19:50:39 1996 Marc Horowitz <marc@mit.edu> + + * configure.in: removed ET_RULES, replaced with AC_PROG_AWK + +Mon Jul 15 16:52:44 1996 Barry Jaspan <bjaspan@mit.edu> + + * client_init.c (_kadm5_init_any): use krb5_get_in_tkt_keytab + instead of changing krb5_defkeyname + +Mon Jul 15 16:36:02 1996 Marc Horowitz <marc@mit.edu> + + * Makefile.in (CLNTOBJS), AC_REPLACE_FUNCS: check for setenv, and + link against setenv.o if it's needed. + +Fri Jul 12 15:06:48 1996 Marc Horowitz <marc@mit.edu> + + * svr_iters.c (glob_to_regexp:append_realm): the semantics and + code were somewhat confused. they are now fixed. + + * logger.c (HAVE_*): turn all the "#if HAVE_*" into + "#ifdef HAVE_*" + + * configure.in (AC_CHECK_FUNCS): check for the functions which + logger.c checks for. + + * svr_principal.c (kadm5_get_principal): due to the the api + versioning, it is possible for this function to be called with a + three argument prototype. in this case, do not modify mask, + because this will clobber the stack on some platforms. + + * client_principal.c (kadm5_create_principal): be more careful + about what sorts of things are referenced, passed down, and passed + back if the caller is api v1. + +Wed Jul 10 01:29:34 1996 Marc Horowitz <marc@mit.edu> + + * configure.in: added autoconf support + +Tue Jul 9 17:38:43 1996 Marc Horowitz <marc@mit.edu> + + * svr_iters.c (*_REGEXPS): rework the conditionals to operate + as functions of function symbols tested by configure. + * client_init.c (setenv, unsetenv declarations): make them the + same as the stdlib declarations, if they're going to be here at + all. + * Makefile.in: reworked to support building both libraries. this + required a bunch of changes, including some coordinating ones in + aclocal.m4 + +Tue Jul 9 16:26:26 1996 Barry Jaspan <bjaspan@mit.edu> + + * svr_principal.c (kadm5_decrypt_key): add kadm5_decrypt_key + +Mon Jul 8 16:55:22 1996 Barry Jaspan <bjaspan@mit.edu> + + * svr_iters.c (kadm5_get_either): append local ream to globs with + no realm + + * alt_prof.c: fix dbname, admin_dbname, and admin_lockfile to + derive from each other as in spec + + * adb_policy.c: add create_db/destroy_db + + * adb_openclose.c: add create_db/destroy_db, fix handling of + permanent locks, handle multiple lock files via static linked list + + * adb.h: update create_db/destroy_db to make params instead of + explicit values + + * Makefile.ov (TOP): Use ../../kadmin, not kadmin.ov + + diff --git a/src/lib/kadm5/Makefile.in b/src/lib/kadm5/Makefile.in new file mode 100644 index 000000000..ef500d3f2 --- /dev/null +++ b/src/lib/kadm5/Makefile.in @@ -0,0 +1,165 @@ +CFLAGS = $(CCOPTS) $(DEFS) + +##DOSBUILDTOP = ..\.. +##DOSLIBNAME=libkadm5srv.lib + +.c.o: + $(CC) $(CFLAGS) -c $(srcdir)/$*.c +@SHARED_RULE@ + +kadm_err.$(OBJEXT): kadm_err.c + $(CC) $(CFLAGS) -c $*.c +@SHARED_RULE_LOCAL@ + +adb_err.$(OBJEXT): adb_err.c + $(CC) $(CFLAGS) -c $*.c +@SHARED_RULE_LOCAL@ + +chpass_util_strings.$(OBJEXT): chpass_util_strings.c + $(CC) $(CFLAGS) -c $*.c +@SHARED_RULE_LOCAL@ + +kadm_err.c kadm_err.h: $(srcdir)/kadm_err.et +adb_err.c adb_err.h: $(srcdir)/adb_err.et +chpass_util_strings.c chpass_util_strings.h: $(srcdir)/chpass_util_strings.et + +clean:: + $(RM) kadm_err.c kadm_err.h kadm_err.o + $(RM) adb_err.c adb_err.h adb_err.o + $(RM) chpass_util_strings.c chpass_util_strings.h chpass_util_strings.o + +GENSRCS = kadm_err.c \ + adb_err.c \ + chpass_util_strings.c \ + $(srcdir)/ovsec_glue.c \ + $(srcdir)/misc_free.c \ + $(srcdir)/kadm_rpc_xdr.c \ + $(srcdir)/chpass_util.c \ + $(srcdir)/alt_prof.c \ + $(srcdir)/str_conv.c \ + $(srcdir)/logger.c \ + +SRVSRCS = $(GENSRCS) \ + $(srcdir)/svr_policy.c \ + $(srcdir)/svr_principal.c \ + $(srcdir)/server_acl.c \ + $(srcdir)/server_kdb.c \ + $(srcdir)/server_misc.c \ + $(srcdir)/server_init.c \ + $(srcdir)/server_dict.c \ + $(srcdir)/svr_iters.c \ + $(srcdir)/svr_chpass_util.c \ + $(srcdir)/adb_xdr.c \ + $(srcdir)/adb_policy.c \ + $(srcdir)/adb_free.c \ + $(srcdir)/adb_openclose.c + +CLNTSRCS = $(GENSRCS) \ + $(srcdir)/clnt_policy.c \ + $(srcdir)/client_rpc.c \ + $(srcdir)/client_principal.c \ + $(srcdir)/client_init.c \ + $(srcdir)/clnt_privs.c \ + $(srcdir)/clnt_chpass_util.c + +GENOBJS = kadm_err.$(OBJEXT) \ + adb_err.$(OBJEXT) \ + chpass_util_strings.$(OBJEXT) \ + ovsec_glue.$(OBJEXT) \ + misc_free.$(OBJEXT) \ + kadm_rpc_xdr.$(OBJEXT) \ + chpass_util.$(OBJEXT) \ + alt_prof.$(OBJEXT) \ + str_conv.$(OBJEXT) \ + logger.$(OBJEXT) \ + +SRVOBJS = $(GENOBJS) \ + svr_policy.$(OBJEXT) \ + svr_principal.$(OBJEXT) \ + server_acl.$(OBJEXT) \ + server_kdb.$(OBJEXT) \ + server_misc.$(OBJEXT) \ + server_init.$(OBJEXT) \ + server_dict.$(OBJEXT) \ + svr_iters.$(OBJEXT) \ + svr_chpass_util.$(OBJEXT) \ + adb_xdr.$(OBJEXT) \ + adb_policy.$(OBJEXT) \ + adb_free.$(OBJEXT) \ + adb_openclose.$(OBJEXT) + +CLNTOBJS = $(GENOBJS) @LIBOBJS@ \ + clnt_policy.$(OBJEXT) \ + client_rpc.$(OBJEXT) \ + client_principal.$(OBJEXT) \ + client_init.$(OBJEXT) \ + clnt_privs.$(OBJEXT) \ + clnt_chpass_util.$(OBJEXT) + +# +# Depends on libkdb5, libkrb5, libcrypto, libcom_err, libdyn +# +KDB5_VER=@KDB5_SH_VERS@ +KRB5_VER=@KRB5_SH_VERS@ +CRYPTO_VER=@CRYPTO_SH_VERS@ +COMERR_VER=@COMERR_SH_VERS@ +DYN_VER=@DYN_SH_VERS@ +DEPLIBS=$(TOPLIBD)/libkdb5.$(SHEXT).$(KDB5_VER) \ + $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) \ + $(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \ + $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) \ + $(TOPLIBD)/libdyn.$(SHEXT).$(DYN_VER) + +SHLIB_LIBS=-lkdb5 -lkrb5 -lcrypto -lcom_err -ldyn +SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@ +SHLIB_LIBDIRS= @SHLIB_LIBDIRS@ + +all-unix:: shared includes $(OBJS) +all-mac:: $(OBJS) +all-windows:: $(OBJS) + +# don't think about this very hard. when the build system goes away, +# so will this. +LIBDONE = srv/DONE clnt/DONE +LIB_SUBDIRS= +shared: + -mkdir shared srv clnt + ln -s ../shared srv/shared + ln -s ../shared clnt/shared + +srv/DONE: $(SRVOBJS) + $(RM) srv/DONE + echo $(SRVOBJS) > srv/DONE + +clnt/DONE: $(CLNTOBJS) + $(RM) clnt/DONE + echo $(CLNTOBJS) > clnt/DONE + +check-windows:: + +clean-unix:: + $(RM) shared/* srv/* clnt/* + -rmdir shared srv clnt + +clean-mac:: +clean-windows:: + +libkadm5srv.a: $(SRVOBJS) + $(RM) $@ + $(ARADD) $@ $(SRVOBJS) + $(RANLIB) $@ + +libkadm5clnt.a: $(CLNTOBJS) + $(RM) $@ + $(ARADD) $@ $(CLNTOBJS) + $(RANLIB) $@ + +install:: libkadm5srv.a libkadm5clnt.a + $(INSTALL_DATA) libkadm5srv.a $(DESTDIR)$(KRB5_LIBDIR)/libkadm5srv.a + $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkadm5srv.a + $(INSTALL_DATA) libkadm5clnt.a $(DESTDIR)$(KRB5_LIBDIR)/libkadm5clnt.a + $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkadm5clnt.a + +clean:: + $(RM) libkadm5srv.a libkadm5srv.bak DONESRV + $(RM) libkadm5clnt.a libkadm5clnt.bak DONECLNT diff --git a/src/lib/kadm5/Makefile.ov b/src/lib/kadm5/Makefile.ov new file mode 100644 index 000000000..6b078f777 --- /dev/null +++ b/src/lib/kadm5/Makefile.ov @@ -0,0 +1,61 @@ +TOP = ../../kadmin +include $(TOP)/config.mk/template + +# All but D_REGEXP_TYPE are needed only for logger.c +CFLAGS += $(D_REGEXP_TYPE) $(D_HAVE_SYSLOG_H) $(D_HAVE_STDARG_H) \ + $(D_HAVE_SYSLOG) $(D_HAVE_VSPRINTF) $(D_HAVE_OPENLOG) \ + $(D_HAVE_CLOSELOG) $(D_HAVE_STRFTIME) + +ifdef D_NO_SETENV +SETENVC = setenv.c +SETENVO = setenv.o +endif + +SUBDIRS = unit-test + +COMMON_SRCS := kadm_err.c adb_err.c chpass_util_strings.c ovsec_glue.c \ + misc_free.c kadm_rpc_xdr.c chpass_util.c alt_prof.c str_conv.c \ + logger.c $(SETENVC) +COMMON_OBJS := kadm_err.o adb_err.o chpass_util_strings.o ovsec_glue.o \ + misc_free.o kadm_rpc_xdr.o chpass_util.o alt_prof.o str_conv.o \ + logger.o $(SETENVO) + +SERVER_SRCS := svr_policy.c svr_principal.c server_kdb.c server_misc.c \ + server_init.c server_dict.c server_acl.c svr_iters.c \ + svr_chpass_util.c +SERVER_OBJS := svr_policy.o svr_principal.o server_kdb.o server_misc.o \ + server_init.o server_dict.o server_acl.o svr_iters.o \ + svr_chpass_util.o +DB_SRCS := adb_xdr.c adb_policy.c adb_free.c adb_openclose.c +DB_OBJS := adb_xdr.o adb_policy.o adb_free.o adb_openclose.o + +CLIENT_SRCS := clnt_policy.c client_rpc.c client_principal.c \ + client_init.c clnt_privs.c clnt_chpass_util.c +CLIENT_OBJS := clnt_policy.o client_rpc.o client_principal.o \ + client_init.o clnt_privs.o clnt_chpass_util.o + +HDRS := kadm_rpc.h admin.h admin_xdr.h adb.h admin_internal.h \ + server_internal.h server_acl.h +HDRS_DIR := kadm5 +ETABLES := chpass_util_strings.et kadm_err.et adb_err.et + +SRCS := $(COMMON_SRCS) $(SERVER_SRCS) $(DB_SRCS) +OBJS := $(COMMON_OBJS) $(SERVER_OBJS) $(DB_OBJS) +LIB := libkadm5srv.a + +expand StageLibrary +expand Depend + +SRCS = $(COMMON_SRCS) $(CLIENT_SRCS) +OBJS = $(COMMON_OBJS) $(CLIENT_OBJS) +LIB = libkadm5clnt.a + +expand StageLibrary +expand Depend + +expand SubdirTarget +expand StageIncludes +expand StageErrorTables + +# Not sure if/why this is needed... +chpass_util.c: chpass_util_strings.h diff --git a/src/lib/kadm5/adb.h b/src/lib/kadm5/adb.h new file mode 100644 index 000000000..b73553575 --- /dev/null +++ b/src/lib/kadm5/adb.h @@ -0,0 +1,141 @@ +/* + * Data Types for policys, and principal information that + * exist in the respective databases. + * + * $Header$ + * + * This file was originally created with rpcgen. + * It has been hacked up since then. + */ + +#ifndef __ADB_H__ +#define __ADB_H__ +#include <sys/types.h> +#include <rpc/types.h> +#include "k5-int.h" +#include <krb5/kdb.h> +#include <db.h> +#include <kadm5/admin.h> +#include <kadm5/adb_err.h> +#include <com_err.h> + +typedef long osa_adb_ret_t; + +#define OSA_ADB_POLICY_DB_MAGIC 0x12345A00 +#define OSA_ADB_PRINC_DB_MAGIC 0x12345B00 + +#define OSA_ADB_SHARED 0x7001 +#define OSA_ADB_EXCLUSIVE 0x7002 +#define OSA_ADB_PERMANENT 0x7003 + +#define OSA_ADB_PRINC_VERSION_MASK 0x12345C00 +#define OSA_ADB_PRINC_VERSION_1 0x12345C01 +#define OSA_ADB_POLICY_VERSION_MASK 0x12345D00 +#define OSA_ADB_POLICY_VERSION_1 0x12345D01 + +typedef struct _osa_adb_db_lock_ent_t { + FILE *lockfile; + char *filename; + int refcnt, lockmode, lockcnt; + krb5_context context; +} osa_adb_lock_ent, *osa_adb_lock_t; + +typedef struct _osa_adb_db_ent_t { + int magic; + DB *db; + HASHINFO info; + char *filename; + osa_adb_lock_t lock; +} osa_adb_db_ent, *osa_adb_db_t, *osa_adb_princ_t, *osa_adb_policy_t; + +/* an osa_pw_hist_ent stores all the key_datas for a single password */ +typedef struct _osa_pw_hist_t { + int n_key_data; + krb5_key_data *key_data; +} osa_pw_hist_ent, *osa_pw_hist_t; + +typedef struct _osa_princ_ent_t { + int version; + char *policy; + long aux_attributes; + unsigned int old_key_len; + unsigned int old_key_next; + krb5_kvno admin_history_kvno; + osa_pw_hist_ent *old_keys; +} osa_princ_ent_rec, *osa_princ_ent_t; + +typedef struct _osa_policy_ent_t { + int version; + char *name; + rpc_u_int32 pw_min_life; + rpc_u_int32 pw_max_life; + rpc_u_int32 pw_min_length; + rpc_u_int32 pw_min_classes; + rpc_u_int32 pw_history_num; + rpc_u_int32 policy_refcnt; +} osa_policy_ent_rec, *osa_policy_ent_t; + +typedef void (*osa_adb_iter_princ_func) (void *, osa_princ_ent_t); +typedef void (*osa_adb_iter_policy_func) (void *, osa_policy_ent_t); + + +/* + * Return Code (the rest are in adb_err.h) + */ + +#define OSA_ADB_OK 0 + +/* + * xdr functions + */ +bool_t xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp); +bool_t xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp); + +/* + * Functions + */ + +osa_adb_ret_t osa_adb_create_db(char *filename, char *lockfile, int magic); +osa_adb_ret_t osa_adb_destroy_db(char *filename, char *lockfile, int magic); +osa_adb_ret_t osa_adb_init_db(osa_adb_db_t *dbp, char *filename, + char *lockfile, int magic); +osa_adb_ret_t osa_adb_fini_db(osa_adb_db_t db, int magic); +osa_adb_ret_t osa_adb_get_lock(osa_adb_db_t db, int mode); +osa_adb_ret_t osa_adb_release_lock(osa_adb_db_t db); +osa_adb_ret_t osa_adb_open_and_lock(osa_adb_princ_t db, int locktype); +osa_adb_ret_t osa_adb_close_and_unlock(osa_adb_princ_t db); + +osa_adb_ret_t osa_adb_create_policy_db(kadm5_config_params *params); +osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params); +osa_adb_ret_t osa_adb_open_princ(osa_adb_princ_t *db, char *filename); +osa_adb_ret_t osa_adb_open_policy(osa_adb_policy_t *db, + kadm5_config_params *rparams); +osa_adb_ret_t osa_adb_close_princ(osa_adb_princ_t db); +osa_adb_ret_t osa_adb_close_policy(osa_adb_policy_t db); +osa_adb_ret_t osa_adb_create_princ(osa_adb_princ_t db, + osa_princ_ent_t entry); +osa_adb_ret_t osa_adb_create_policy(osa_adb_policy_t db, + osa_policy_ent_t entry); +osa_adb_ret_t osa_adb_destroy_princ(osa_adb_princ_t db, + kadm5_princ_t name); +osa_adb_ret_t osa_adb_destroy_policy(osa_adb_policy_t db, + kadm5_policy_t name); +osa_adb_ret_t osa_adb_get_princ(osa_adb_princ_t db, + kadm5_princ_t name, + osa_princ_ent_t *entry); +osa_adb_ret_t osa_adb_get_policy(osa_adb_policy_t db, + kadm5_policy_t name, + osa_policy_ent_t *entry); +osa_adb_ret_t osa_adb_put_princ(osa_adb_princ_t db, + osa_princ_ent_t entry); +osa_adb_ret_t osa_adb_put_policy(osa_adb_policy_t db, + osa_policy_ent_t entry); +osa_adb_ret_t osa_adb_iter_policy(osa_adb_policy_t db, + osa_adb_iter_policy_func func, + void * data); +osa_adb_ret_t osa_adb_iter_princ(osa_adb_princ_t db, + osa_adb_iter_princ_func func, + void *data); +void osa_free_policy_ent(osa_policy_ent_t val); +void osa_free_princ_ent(osa_princ_ent_t val); +#endif /* __ADB_H__ */ diff --git a/src/lib/kadm5/adb_err.et b/src/lib/kadm5/adb_err.et new file mode 100644 index 000000000..394802571 --- /dev/null +++ b/src/lib/kadm5/adb_err.et @@ -0,0 +1,16 @@ +error_table adb +error_code OSA_ADB_NOERR, "No Error" +error_code OSA_ADB_DUP, "Principal or policy already exists" +error_code OSA_ADB_NOENT, "Principal or policy does not exist" +error_code OSA_ADB_DBINIT, "Database not initialized" +error_code OSA_ADB_BAD_POLICY, "Invalid policy name" +error_code OSA_ADB_BAD_PRINC, "Invalid principal name" +error_code OSA_ADB_BAD_DB, "Database inconsistency detected" +error_code OSA_ADB_XDR_FAILURE, "XDR encoding error" +error_code OSA_ADB_FAILURE, "Failure!" +error_code OSA_ADB_BADLOCKMODE, "Bad lock mode" +error_code OSA_ADB_CANTLOCK_DB, "Cannot lock database" +error_code OSA_ADB_NOTLOCKED, "Database not locked" +error_code OSA_ADB_NOLOCKFILE, "KADM5 administration database lock file missing" +error_code OSA_ADB_NOEXCL_PERM, "Insufficient permission to lock file" +end diff --git a/src/lib/kadm5/adb_free.c b/src/lib/kadm5/adb_free.c new file mode 100644 index 000000000..4c6f8a66d --- /dev/null +++ b/src/lib/kadm5/adb_free.c @@ -0,0 +1,71 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + * $Log$ + * Revision 1.8 1996/07/22 20:35:16 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.7.4.1 1996/07/18 03:08:07 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.7.2.1 1996/06/20 02:16:25 marc + * File added to the repository on a branch + * + * Revision 1.7 1996/05/12 06:21:57 marc + * don't use <absolute paths> for "internal header files" + * + * Revision 1.6 1993/12/13 21:15:56 shanzer + * fixed memory leak + * ., + * + * Revision 1.5 1993/12/06 22:20:37 marc + * fixup free functions to use xdr to free the underlying struct + * + * Revision 1.4 1993/11/15 00:29:46 shanzer + * check to make sure pointers are somewhat vaid before freeing. + * + * Revision 1.3 1993/11/09 04:02:24 shanzer + * added some includefiles + * changed bzero to memset + * + * Revision 1.2 1993/11/04 01:54:24 shanzer + * added rcs header .. + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include "adb.h" +#include <memory.h> +#include <malloc.h> + +void +osa_free_princ_ent(osa_princ_ent_t val) +{ + XDR xdrs; + + xdrmem_create(&xdrs, NULL, 0, XDR_FREE); + + xdr_osa_princ_ent_rec(&xdrs, val); + free(val); +} + +void +osa_free_policy_ent(osa_policy_ent_t val) +{ + XDR xdrs; + + xdrmem_create(&xdrs, NULL, 0, XDR_FREE); + + xdr_osa_policy_ent_rec(&xdrs, val); + free(val); +} + diff --git a/src/lib/kadm5/adb_openclose.c b/src/lib/kadm5/adb_openclose.c new file mode 100644 index 000000000..627a6b410 --- /dev/null +++ b/src/lib/kadm5/adb_openclose.c @@ -0,0 +1,338 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/file.h> +#include <fcntl.h> +#include <unistd.h> +#include "adb.h" +#include <stdlib.h> + +#define MAX_LOCK_TRIES 5 + +struct _locklist { + osa_adb_lock_ent lockinfo; + struct _locklist *next; +}; + +osa_adb_ret_t osa_adb_create_db(char *filename, char *lockfilename, + int magic) +{ + FILE *lf; + DB *db; + HASHINFO info; + + lf = fopen(lockfilename, "w+"); + if (lf == NULL) + return errno; + (void) fclose(lf); + + memset(&info, 0, sizeof(info)); + info.hash = NULL; + info.bsize = 256; + info.ffactor = 8; + info.nelem = 25000; + info.lorder = 0; + db = dbopen(filename, O_RDWR | O_CREAT | O_EXCL, 0600, DB_HASH, &info); + if (db == NULL) + return errno; + if (db->close(db) < 0) + return errno; + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_destroy_db(char *filename, char *lockfilename, + int magic) +{ + /* the admin databases do not contain security-critical data */ + if (unlink(filename) < 0 || + unlink(lockfilename) < 0) + return errno; + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_init_db(osa_adb_db_t *dbp, char *filename, + char *lockfilename, int magic) +{ + osa_adb_db_t db; + static struct _locklist *locklist = NULL; + struct _locklist *lockp; + krb5_error_code code; + + if (dbp == NULL || filename == NULL) + return EINVAL; + + db = (osa_adb_princ_t) malloc(sizeof(osa_adb_db_ent)); + if (db == NULL) + return ENOMEM; + + memset(db, 0, sizeof(*db)); + db->info.hash = NULL; + db->info.bsize = 256; + db->info.ffactor = 8; + db->info.nelem = 25000; + db->info.lorder = 0; + + /* + * A process is allowed to open the same database multiple times + * and access it via different handles. If the handles use + * distinct lockinfo structures, things get confused: lock(A), + * lock(B), release(B) will result in the kernel unlocking the + * lock file but handle A will still think the file is locked. + * Therefore, all handles using the same lock file must share a + * single lockinfo structure. + * + * It is not sufficient to have a single lockinfo structure, + * however, because a single process may also wish to open + * multiple different databases simultaneously, with different + * lock files. This code used to use a single static lockinfo + * structure, which means that the second database opened used + * the first database's lock file. This was Bad. + * + * We now maintain a linked list of lockinfo structures, keyed by + * lockfilename. An entry is added when this function is called + * with a new lockfilename, and all subsequent calls with that + * lockfilename use the existing entry, updating the refcnt. + * When the database is closed with fini_db(), the refcnt is + * decremented, and when it is zero the lockinfo structure is + * freed and reset. The entry in the linked list, however, is + * never removed; it will just be reinitialized the next time + * init_db is called with the right lockfilename. + */ + + /* find or create the lockinfo structure for lockfilename */ + lockp = locklist; + while (lockp) { + if (strcmp(lockp->lockinfo.filename, lockfilename) == 0) + break; + else + lockp = lockp->next; + } + if (lockp == NULL) { + /* doesn't exist, create it, add to list */ + lockp = (struct _locklist *) malloc(sizeof(*lockp)); + if (lockp == NULL) { + free(db); + return ENOMEM; + } + memset(lockp, 0, sizeof(*lockp)); + lockp->next = locklist; + locklist = lockp; + } + + /* now initialize lockp->lockinfo if necessary */ + if (lockp->lockinfo.lockfile == NULL) { + if (code = krb5_init_context(&lockp->lockinfo.context)) { + free(db); + return((osa_adb_ret_t) code); + } + + /* + * needs be open read/write so that write locking can work with + * POSIX systems + */ + lockp->lockinfo.filename = strdup(lockfilename); + if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r+")) == NULL) { + /* + * maybe someone took away write permission so we could only + * get shared locks? + */ + if ((lockp->lockinfo.lockfile = fopen(lockfilename, "r")) + == NULL) { + free(db); + return OSA_ADB_NOLOCKFILE; + } + } + lockp->lockinfo.lockmode = lockp->lockinfo.lockcnt = 0; + } + + /* lockp is set, lockinfo is initialized, update the reference count */ + db->lock = &lockp->lockinfo; + db->lock->refcnt++; + + db->filename = strdup(filename); + db->magic = magic; + + *dbp = db; + + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_fini_db(osa_adb_db_t db, int magic) +{ + if (db->magic != magic) + return EINVAL; + if (db->lock->refcnt == 0) { + /* barry says this can't happen */ + return OSA_ADB_FAILURE; + } else { + db->lock->refcnt--; + } + + if (db->lock->refcnt == 0) { + /* + * Don't free db->lock->filename, it is used as a key to + * find the lockinfo entry in the linked list. If the + * lockfile doesn't exist, we must be closing the database + * after trashing it. This has to be allowed, so don't + * generate an error. + */ + (void) fclose(db->lock->lockfile); + db->lock->lockfile = NULL; + krb5_free_context(db->lock->context); + } + + db->magic = 0; + free(db->filename); + free(db); + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_get_lock(osa_adb_db_t db, int mode) +{ + int tries, gotlock, perm, krb5_mode, ret; + + if (db->lock->lockmode >= mode) { + /* No need to upgrade lock, just incr refcnt and return */ + db->lock->lockcnt++; + return(OSA_ADB_OK); + } + + perm = 0; + switch (mode) { + case OSA_ADB_PERMANENT: + perm = 1; + case OSA_ADB_EXCLUSIVE: + krb5_mode = KRB5_LOCKMODE_EXCLUSIVE; + break; + case OSA_ADB_SHARED: + krb5_mode = KRB5_LOCKMODE_SHARED; + break; + default: + return(EINVAL); + } + + for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) { + if ((ret = krb5_lock_file(db->lock->context, + fileno(db->lock->lockfile), + krb5_mode|KRB5_LOCKMODE_DONTBLOCK)) == 0) { + gotlock++; + break; + } else if (ret == EBADF && mode == OSA_ADB_EXCLUSIVE) + /* tried to exclusive-lock something we don't have */ + /* write access to */ + return OSA_ADB_NOEXCL_PERM; + + sleep(1); + } + + /* test for all the likely "can't get lock" error codes */ + if (ret == EACCES || ret == EAGAIN || ret == EWOULDBLOCK) + return OSA_ADB_CANTLOCK_DB; + else if (ret != 0) + return ret; + + /* + * If the file no longer exists, someone acquired a permanent + * lock. If that process terminates its exclusive lock is lost, + * but if we already had the file open we can (probably) lock it + * even though it has been unlinked. So we need to insist that + * it exist. + */ + if (access(db->lock->filename, F_OK) < 0) { + (void) krb5_lock_file(db->lock->context, + fileno(db->lock->lockfile), + KRB5_LOCKMODE_UNLOCK); + return OSA_ADB_NOLOCKFILE; + } + + /* we have the shared/exclusive lock */ + + if (perm) { + if (unlink(db->lock->filename) < 0) { + int ret; + + /* somehow we can't delete the file, but we already */ + /* have the lock, so release it and return */ + + ret = errno; + (void) krb5_lock_file(db->lock->context, + fileno(db->lock->lockfile), + KRB5_LOCKMODE_UNLOCK); + + /* maybe we should return CANTLOCK_DB.. but that would */ + /* look just like the db was already locked */ + return ret; + } + + /* this releases our exclusive lock.. which is okay because */ + /* now no one else can get one either */ + (void) fclose(db->lock->lockfile); + } + + db->lock->lockmode = mode; + db->lock->lockcnt++; + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_release_lock(osa_adb_db_t db) +{ + int ret; + + if (!db->lock->lockcnt) /* lock already unlocked */ + return OSA_ADB_NOTLOCKED; + + if (--db->lock->lockcnt == 0) { + if (db->lock->lockmode == OSA_ADB_PERMANENT) { + /* now we need to create the file since it does not exist */ + if ((db->lock->lockfile = fopen(db->lock->filename, + "w+")) == NULL) + return OSA_ADB_NOLOCKFILE; + } else if (ret = krb5_lock_file(db->lock->context, + fileno(db->lock->lockfile), + KRB5_LOCKMODE_UNLOCK)) + return ret; + + db->lock->lockmode = 0; + } + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_open_and_lock(osa_adb_princ_t db, int locktype) +{ + int ret; + + ret = osa_adb_get_lock(db, locktype); + if (ret != OSA_ADB_OK) + return ret; + + db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info); + if (db->db == NULL) { + (void) osa_adb_release_lock(db); + if(errno == EINVAL) + return OSA_ADB_BAD_DB; + return errno; + } + return OSA_ADB_OK; +} + +osa_adb_ret_t osa_adb_close_and_unlock(osa_adb_princ_t db) +{ + int ret; + + if(db->db->close(db->db) == -1) { + (void) osa_adb_release_lock(db); + return OSA_ADB_FAILURE; + } + + db->db = NULL; + + return(osa_adb_release_lock(db)); +} + diff --git a/src/lib/kadm5/adb_policy.c b/src/lib/kadm5/adb_policy.c new file mode 100644 index 000000000..ff0117bac --- /dev/null +++ b/src/lib/kadm5/adb_policy.c @@ -0,0 +1,401 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/file.h> +#include <fcntl.h> +#include "adb.h" +#include <stdlib.h> +#include <malloc.h> +#include <string.h> + +extern int errno; + +#define OPENLOCK(db, mode) \ +{ \ + int ret; \ + if (db == NULL) \ + return EINVAL; \ + else if (db->magic != OSA_ADB_POLICY_DB_MAGIC) \ + return OSA_ADB_DBINIT; \ + else if ((ret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \ + return ret; \ + } + +#define CLOSELOCK(db) \ +{ \ + int ret; \ + if ((ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \ + return ret; \ +} + +osa_adb_ret_t osa_adb_create_policy_db(kadm5_config_params *params) +{ + return osa_adb_create_db(params->admin_dbname, + params->admin_lockfile, + OSA_ADB_POLICY_DB_MAGIC); +} + +osa_adb_ret_t osa_adb_destroy_policy_db(kadm5_config_params *params) +{ + return osa_adb_destroy_db(params->admin_dbname, + params->admin_lockfile, + OSA_ADB_POLICY_DB_MAGIC); +} + +osa_adb_ret_t osa_adb_open_policy(osa_adb_princ_t *dbp, + kadm5_config_params *rparams) +{ + return osa_adb_init_db(dbp, rparams->admin_dbname, + rparams->admin_lockfile, + OSA_ADB_POLICY_DB_MAGIC); +} + +osa_adb_ret_t osa_adb_close_policy(osa_adb_princ_t db) +{ + return osa_adb_fini_db(db, OSA_ADB_POLICY_DB_MAGIC); +} + +/* + * Function: osa_adb_create_policy + * + * Purpose: create a policy entry in the policy db. + * + * Arguments: + * entry (input) pointer to the entry to be added + * <return value> OSA_ADB_OK on sucsess, else error code. + * + * Requires: + * entry have a valid name. + * + * Effects: + * creates the entry in the db + * + * Modifies: + * the policy db. + * + */ +osa_adb_ret_t +osa_adb_create_policy(osa_adb_policy_t db, osa_policy_ent_t entry) +{ + DBT dbkey; + DBT dbdata; + XDR xdrs; + int ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(entry->name == NULL) { + ret = EINVAL; + goto error; + } + dbkey.data = entry->name; + dbkey.size = (strlen(entry->name) + 1); + + switch(db->db->get(db->db, &dbkey, &dbdata, 0)) { + case 0: + ret = OSA_ADB_DUP; + goto error; + case 1: + break; + default: + ret = errno; + goto error; + } + xdralloc_create(&xdrs, XDR_ENCODE); + if(!xdr_osa_policy_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + ret = OSA_ADB_XDR_FAILURE; + goto error; + } + dbdata.data = xdralloc_getdata(&xdrs); + dbdata.size = xdr_getpos(&xdrs); + switch(db->db->put(db->db, &dbkey, &dbdata, R_NOOVERWRITE)) { + case 0: + if((db->db->sync(db->db, 0)) == -1) + ret = OSA_ADB_FAILURE; + ret = OSA_ADB_OK; + break; + case 1: + ret = OSA_ADB_DUP; + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + xdr_destroy(&xdrs); + +error: + CLOSELOCK(db); + return ret; +} + +/* + * Function: osa_adb_destroy_policy + * + * Purpose: destroy a policy entry + * + * Arguments: + * db (input) database handle + * name (input) name of policy + * <return value> OSA_ADB_OK on sucsess, or error code. + * + * Requires: + * db being valid. + * name being non-null. + * Effects: + * deletes policy from db. + * + * Modifies: + * policy db. + * + */ +osa_adb_ret_t +osa_adb_destroy_policy(osa_adb_policy_t db, kadm5_policy_t name) +{ + DBT dbkey; + int status, ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(name == NULL) { + ret = EINVAL; + goto error; + } + dbkey.data = name; + dbkey.size = (strlen(name) + 1); + + status = db->db->del(db->db, &dbkey, 0); + switch(status) { + case 1: + ret = OSA_ADB_NOENT; + goto error; + case 0: + if ((db->db->sync(db->db, 0)) == -1) { + ret = OSA_ADB_FAILURE; + goto error; + } + ret = OSA_ADB_OK; + break; + default: + ret = OSA_ADB_FAILURE; + goto error; + } + +error: + CLOSELOCK(db); + return ret; +} + +/* + * Function: osa_adb_get_policy + * + * Purpose: retrieve policy + * + * Arguments: + * db (input) db handle + * name (input) name of policy + * entry (output) policy entry + * <return value> 0 on sucsess, error code on failure. + * + * Requires: + * Effects: + * Modifies: + */ +osa_adb_ret_t +osa_adb_get_policy(osa_adb_policy_t db, kadm5_policy_t name, + osa_policy_ent_t *entry) +{ + DBT dbkey; + DBT dbdata; + XDR xdrs; + int ret; + char *aligned_data; + + OPENLOCK(db, OSA_ADB_SHARED); + + if(name == NULL) { + ret = EINVAL; + goto error; + } + dbkey.data = name; + dbkey.size = (strlen(dbkey.data) + 1); + dbdata.data = NULL; + dbdata.size = 0; + switch((db->db->get(db->db, &dbkey, &dbdata, 0))) { + case 1: + ret = OSA_ADB_NOENT; + goto error; + case 0: + break; + default: + ret = OSA_ADB_FAILURE; + goto error; + } + if (!(*(entry) = (osa_policy_ent_t)malloc(sizeof(osa_policy_ent_rec)))) { + ret = ENOMEM; + goto error; + } + if (!(aligned_data = (char *) malloc(dbdata.size))) { + ret = ENOMEM; + goto error; + } + memcpy(aligned_data, dbdata.data, dbdata.size); + memset(*entry, 0, sizeof(osa_policy_ent_rec)); + xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE); + if (!xdr_osa_policy_ent_rec(&xdrs, *entry)) + ret = OSA_ADB_FAILURE; + else ret = OSA_ADB_OK; + xdr_destroy(&xdrs); + free(aligned_data); + +error: + CLOSELOCK(db); + return ret; +} + +/* + * Function: osa_adb_put_policy + * + * Purpose: update a policy in the dababase + * + * Arguments: + * db (input) db handle + * entry (input) policy entry + * <return value> 0 on sucsess error code on failure. + * + * Requires: + * [requires] + * + * Effects: + * [effects] + * + * Modifies: + * [modifies] + * + */ +osa_adb_ret_t +osa_adb_put_policy(osa_adb_policy_t db, osa_policy_ent_t entry) +{ + DBT dbkey; + DBT dbdata; + DBT tmpdb; + XDR xdrs; + int ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(entry->name == NULL) { + ret = EINVAL; + goto error; + } + dbkey.data = entry->name; + dbkey.size = (strlen(entry->name) + 1); + switch(db->db->get(db->db, &dbkey, &tmpdb, 0)) { + case 0: + break; + case 1: + ret = OSA_ADB_NOENT; + goto error; + default: + ret = OSA_ADB_FAILURE; + goto error; + } + xdralloc_create(&xdrs, XDR_ENCODE); + if(!xdr_osa_policy_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + ret = OSA_ADB_XDR_FAILURE; + goto error; + } + dbdata.data = xdralloc_getdata(&xdrs); + dbdata.size = xdr_getpos(&xdrs); + switch(db->db->put(db->db, &dbkey, &dbdata, 0)) { + case 0: + if((db->db->sync(db->db, 0)) == -1) + ret = OSA_ADB_FAILURE; + ret = OSA_ADB_OK; + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + xdr_destroy(&xdrs); + +error: + CLOSELOCK(db); + return ret; +} + +/* + * Function: osa_adb_iter_policy + * + * Purpose: iterate over the policy database. + * + * Arguments: + * db (input) db handle + * func (input) fucntion pointer to call + * data opaque data type + * <return value> 0 on sucsess error code on failure + * + * Requires: + * Effects: + * Modifies: + */ +osa_adb_ret_t +osa_adb_iter_policy(osa_adb_policy_t db, osa_adb_iter_policy_func func, + void *data) +{ + DBT dbkey, + dbdata; + XDR xdrs; + int ret; + osa_policy_ent_t entry; + char *aligned_data; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); /* hmmm */ + + if((ret = db->db->seq(db->db, &dbkey, &dbdata, R_FIRST)) == -1) { + ret = errno; + goto error; + } + + while (ret == 0) { + if (!(entry = (osa_policy_ent_t) malloc(sizeof(osa_policy_ent_rec)))) { + ret = ENOMEM; + goto error; + } + + if(!(aligned_data = (char *) malloc(dbdata.size))) { + ret = ENOMEM; + goto error; + } + memcpy(aligned_data, dbdata.data, dbdata.size); + + memset(entry, 0, sizeof(osa_policy_ent_rec)); + xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE); + if(!xdr_osa_policy_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + free(aligned_data); + ret = OSA_ADB_FAILURE; + goto error; + } + (*func)(data, entry); + xdr_destroy(&xdrs); + free(aligned_data); + osa_free_policy_ent(entry); + ret = db->db->seq(db->db, &dbkey, &dbdata, R_NEXT); + } + if(ret == -1) + ret = errno; + else ret = OSA_ADB_OK; + +error: + CLOSELOCK(db); + return ret; +} diff --git a/src/lib/kadm5/adb_principal.c b/src/lib/kadm5/adb_principal.c new file mode 100644 index 000000000..8ee9aab30 --- /dev/null +++ b/src/lib/kadm5/adb_principal.c @@ -0,0 +1,408 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + * $Log$ + * Revision 1.24 1996/07/22 20:35:23 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.23.4.1 1996/07/18 03:08:17 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.23.2.1 1996/06/20 02:16:30 marc + * File added to the repository on a branch + * + * Revision 1.23 1996/05/16 21:44:35 bjaspan + * this file is no longer used, #if the whole thing out + * + * Revision 1.22 1996/05/08 20:51:44 bjaspan + * marc's changes + * + * Revision 1.21 1995/08/24 20:23:43 bjaspan + * marc is a bonehead + * + * Revision 1.20 1995/08/23 19:16:02 marc + * check for db == NULL in OPENLOCK() + * + * Revision 1.19 1995/08/08 18:31:30 bjaspan + * [secure/3394] first cut at admin db locking support + * + * Revision 1.18 1995/08/02 15:26:57 bjaspan + * check db==NULL in iter + * + * Revision 1.17 1994/05/09 17:52:36 shanzer + * fixed some include files + * + * Revision 1.16 1994/03/17 01:25:58 shanzer + * include fcntl.h + * + * Revision 1.15 1993/12/17 18:54:06 jik + * [secure-admin/1040] + * + * open_princ should return errno, rather than BAD_DB, if errno is + * something other than BAD_DB. + * + * Revision 1.14 1993/12/13 18:55:58 marc + * remove bogus free()'s + * + * Revision 1.13 1993/12/08 22:29:27 marc + * fixed another xdrmem alignment thing] + * + * Revision 1.12 1993/12/06 22:22:22 bjaspan + * fix alignment and free-memory-read bugs + * + * Revision 1.11 1993/12/05 04:15:16 shanzer + * removed data size hack. + * + * Revision 1.10 1993/11/15 00:29:24 shanzer + * added filenme to open + * + * Revision 1.9 1993/11/10 20:10:06 shanzer + * now uses xdralloc instead of xdrmem + * + * Revision 1.8 1993/11/09 21:43:24 shanzer + * added check to see if we overflowed our xdr buffer. + * + * Revision 1.7 1993/11/09 04:00:19 shanzer + * changed bzero to memset + * + * Revision 1.6 1993/11/05 23:16:21 shanzer + * return ENOMEM instead of ovsec_kadm_mem + * + * Revision 1.5 1993/11/05 22:17:03 shanzer + * added principal db interative function + * + * Revision 1.4 1993/11/04 23:20:24 shanzer + * made HASHINFO static. + * + * Revision 1.3 1993/11/04 01:52:30 shanzer + * Restructred some code .. fixed some bugs/leaks + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#if 0 +/* XXX THIS FILE IS NO LONGER USED, and should be deleted when we're done */ + +#include <sys/file.h> +#include <fcntl.h> +#include "adb.h" +#include <stdlib.h> +#include <memory.h> + +#define OPENLOCK(db, mode) \ +{ \ + int ret; \ + if (db == NULL) \ + return EINVAL; \ + else if (db->magic != OSA_ADB_PRINC_DB_MAGIC) \ + return OSA_ADB_DBINIT; \ + else if ((ret = osa_adb_open_and_lock(db, mode)) != OSA_ADB_OK) \ + return ret; \ + } + +#define CLOSELOCK(db) \ +{ \ + int ret; \ + if ((ret = osa_adb_close_and_unlock(db)) != OSA_ADB_OK) \ + return ret; \ +} + +osa_adb_ret_t osa_adb_open_princ(osa_adb_princ_t *dbp, char *filename) +{ + return osa_adb_init_db(dbp, filename, OSA_ADB_PRINC_DB_MAGIC); +} + +osa_adb_ret_t osa_adb_close_princ(osa_adb_princ_t db) +{ + return osa_adb_fini_db(db, OSA_ADB_PRINC_DB_MAGIC); +} + +osa_adb_ret_t +osa_adb_create_princ(osa_adb_princ_t db, osa_princ_ent_t entry) +{ + + DBT dbkey; + DBT dbdata; + XDR xdrs; + int ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(krb5_unparse_name(db->lock->context, + entry->name, (char **) &dbkey.data)) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + if((dbkey.size = strlen(dbkey.data)) == 0) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + + switch(db->db->get(db->db, &dbkey, &dbdata, 0)) { + case 0: + ret = OSA_ADB_DUP; + goto error; + case 1: + break; + default: + ret = OSA_ADB_FAILURE; + goto error; + } + xdralloc_create(&xdrs, XDR_ENCODE); + if(!xdr_osa_princ_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + ret = OSA_ADB_XDR_FAILURE; + goto error; + } + dbdata.data = xdralloc_getdata(&xdrs); + dbdata.size = xdr_getpos(&xdrs); + switch(db->db->put(db->db, &dbkey, &dbdata, R_NOOVERWRITE)) { + case 0: + if((db->db->sync(db->db, 0)) == -1) + ret = OSA_ADB_FAILURE; + else + ret = OSA_ADB_OK; + break; + case 1: + ret = OSA_ADB_DUP; + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + xdralloc_release(&xdrs); + free(dbkey.data); + +error: + CLOSELOCK(db); + + return ret; +} + +osa_adb_ret_t +osa_adb_destroy_princ(osa_adb_princ_t db, ovsec_kadm_princ_t name) +{ + DBT dbkey; + int status; + int ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(krb5_unparse_name(db->lock->context, name, (char **) &dbkey.data)) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + if ((dbkey.size = strlen(dbkey.data)) == 0) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + status = db->db->del(db->db, &dbkey, 0); + switch(status) { + case 1: + ret = OSA_ADB_NOENT; + break; + case 0: + if ((db->db->sync(db->db, 0)) == -1) + ret = OSA_ADB_FAILURE; + else + ret = OSA_ADB_OK; + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + free(dbkey.data); + +error: + CLOSELOCK(db); + + return ret; +} + +osa_adb_ret_t +osa_adb_get_princ(osa_adb_princ_t db, ovsec_kadm_princ_t name, + osa_princ_ent_t *entry) +{ + DBT dbkey; + DBT dbdata; + XDR xdrs; + int ret = 0; + char *aligned_data; + + OPENLOCK(db, OSA_ADB_SHARED); + + if(krb5_unparse_name(db->lock->context, name, (char **) &dbkey.data)) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + if((dbkey.size = strlen(dbkey.data)) == 0) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + dbdata.size = 0; + dbdata.data = NULL; + switch(db->db->get(db->db, &dbkey, &dbdata, 0)) { + case 1: + ret = OSA_ADB_NOENT; + break; + case 0: + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + free(dbkey.data); + if (ret) + goto error; + + if (!(*(entry) = (osa_princ_ent_t)malloc(sizeof(osa_princ_ent_rec)))) { + ret = ENOMEM; + goto error; + } + + aligned_data = (char *) malloc(dbdata.size); + if (aligned_data == NULL) { + ret = ENOMEM; + goto error; + } + memcpy(aligned_data, dbdata.data, dbdata.size); + + memset(*entry, 0, sizeof(osa_princ_ent_rec)); + xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE); + if (!xdr_osa_princ_ent_rec(&xdrs, *entry)) { + xdr_destroy(&xdrs); + free(aligned_data); + ret = OSA_ADB_FAILURE; + goto error; + } + xdr_destroy(&xdrs); + free(aligned_data); + ret = OSA_ADB_OK; + +error: + CLOSELOCK(db); + return ret; +} + +osa_adb_ret_t +osa_adb_put_princ(osa_adb_princ_t db, osa_princ_ent_t entry) +{ + DBT dbkey; + DBT dbdata; + DBT tmpdb; + XDR xdrs; + int ret; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); + + if(krb5_unparse_name(db->lock->context, + entry->name, (char **) &dbkey.data)) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + if((dbkey.size = strlen(dbkey.data)) == 0) { + ret = OSA_ADB_BAD_PRINC; + goto error; + } + + switch(db->db->get(db->db, &dbkey, &tmpdb, 0)) { + case 0: + break; + case 1: + ret = OSA_ADB_NOENT; + goto error; + default: + ret = OSA_ADB_FAILURE; + goto error; + } + xdralloc_create(&xdrs, XDR_ENCODE); + if(!xdr_osa_princ_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + ret = OSA_ADB_XDR_FAILURE; + goto error; + } + dbdata.data = xdralloc_getdata(&xdrs); + dbdata.size = xdr_getpos(&xdrs); + switch(db->db->put(db->db, &dbkey, &dbdata, 0)) { + case 0: + if((db->db->sync(db->db, 0)) == -1) + ret = OSA_ADB_FAILURE; + else + ret = OSA_ADB_OK; + break; + default: + ret = OSA_ADB_FAILURE; + break; + } + xdralloc_release(&xdrs); + free(dbkey.data); + +error: + CLOSELOCK(db); + return ret; +} + +osa_adb_ret_t +osa_adb_iter_princ(osa_adb_princ_t db, osa_adb_iter_princ_func func, + void *data) +{ + DBT dbkey, + dbdata; + XDR xdrs; + int ret; + osa_princ_ent_t entry; + char *aligned_data; + + OPENLOCK(db, OSA_ADB_EXCLUSIVE); /* hmmmm */ + + if((ret = db->db->seq(db->db, &dbkey, &dbdata, R_FIRST)) == -1) { + ret = errno; + goto error; + } + while (ret == 0) { + if (!(entry = (osa_princ_ent_t) malloc(sizeof(osa_princ_ent_rec)))) { + ret = ENOMEM; + goto error; + } + + aligned_data = (char *) malloc(dbdata.size); + if (aligned_data == NULL) { + ret = ENOMEM; + goto error; + } + memcpy(aligned_data, dbdata.data, dbdata.size); + + memset(entry, 0, sizeof(osa_princ_ent_rec)); + xdrmem_create(&xdrs, aligned_data, dbdata.size, XDR_DECODE); + if(!xdr_osa_princ_ent_rec(&xdrs, entry)) { + xdr_destroy(&xdrs); + free(aligned_data); + ret = OSA_ADB_FAILURE; + goto error; + } + (*func)(data, entry); + xdr_destroy(&xdrs); + free(aligned_data); + osa_free_princ_ent(entry); + ret = db->db->seq(db->db, &dbkey, &dbdata, R_NEXT); + } + if(ret == -1) + ret = errno; + else + ret = OSA_ADB_OK; + +error: + CLOSELOCK(db); + return ret; +} + +#endif /* 0 */ diff --git a/src/lib/kadm5/adb_xdr.c b/src/lib/kadm5/adb_xdr.c new file mode 100644 index 000000000..944fb04b3 --- /dev/null +++ b/src/lib/kadm5/adb_xdr.c @@ -0,0 +1,132 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/types.h> +#include <krb5.h> +#include <rpc/rpc.h> +#include "adb.h" +#include "admin_xdr.h" +#include <memory.h> + +bool_t +xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp) +{ + unsigned int tmp; + + if (!xdr_krb5_int16(xdrs, &objp->key_data_ver)) + return(FALSE); + if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno)) + return(FALSE); + if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) + return(FALSE); + if (!xdr_krb5_int16(xdrs, &objp->key_data_type[1])) + return(FALSE); + if (!xdr_krb5_int16(xdrs, &objp->key_data_length[0])) + return(FALSE); + if (!xdr_krb5_int16(xdrs, &objp->key_data_length[1])) + return(FALSE); + + tmp = (unsigned int) objp->key_data_length[0]; + if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[0], + &tmp, ~0)) + return FALSE; + + tmp = (unsigned int) objp->key_data_length[1]; + if (!xdr_bytes(xdrs, (char **) &objp->key_data_contents[1], + &tmp, ~0)) + return FALSE; + + /* don't need to copy tmp out, since key_data_length will be set + by the above encoding. */ + + return(TRUE); +} + +bool_t +xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp) +{ + if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, + (u_int *) &objp->n_key_data, ~0, + sizeof(krb5_key_data), + xdr_krb5_key_data)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_osa_princ_ent_rec(XDR *xdrs, osa_princ_ent_t objp) +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + objp->version = OSA_ADB_PRINC_VERSION_1; + /* fall through */ + case XDR_FREE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + break; + case XDR_DECODE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + if (objp->version != OSA_ADB_PRINC_VERSION_1) + return FALSE; + break; + } + + if (!xdr_nullstring(xdrs, &objp->policy)) + return (FALSE); + if (!xdr_long(xdrs, &objp->aux_attributes)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->old_key_next)) + return (FALSE); + if (!xdr_krb5_kvno(xdrs, &objp->admin_history_kvno)) + return (FALSE); + if (!xdr_array(xdrs, (caddr_t *) &objp->old_keys, + (unsigned int *) &objp->old_key_len, ~0, + sizeof(osa_pw_hist_ent), + xdr_osa_pw_hist_ent)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_osa_policy_ent_rec(XDR *xdrs, osa_policy_ent_t objp) +{ + switch (xdrs->x_op) { + case XDR_ENCODE: + objp->version = OSA_ADB_POLICY_VERSION_1; + /* fall through */ + case XDR_FREE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + break; + case XDR_DECODE: + if (!xdr_int(xdrs, &objp->version)) + return FALSE; + if (objp->version != OSA_ADB_POLICY_VERSION_1) + return FALSE; + break; + } + + if(!xdr_nullstring(xdrs, &objp->name)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->pw_min_life)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->pw_max_life)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->pw_min_length)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->pw_min_classes)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->pw_history_num)) + return (FALSE); + if (!xdr_u_int32(xdrs, &objp->policy_refcnt)) + return (FALSE); + return (TRUE); +} diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h new file mode 100644 index 000000000..1e98430db --- /dev/null +++ b/src/lib/kadm5/admin.h @@ -0,0 +1,649 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#ifndef __KADM5_ADMIN_H__ +#define __KADM5_ADMIN_H__ + +#if !defined(USE_KADM5_API_VERSION) +#define USE_KADM5_API_VERSION 2 +#endif + +#include <sys/types.h> +#include <rpc/rpc.h> +#include <krb5.h> +#include <k5-int.h> +#include <com_err.h> +#include <kadm5/kadm_err.h> +#include <kadm5/adb_err.h> +#include <kadm5/chpass_util_strings.h> + +#define KADM5_ADMIN_SERVICE "kadmin/admin" +#define KADM5_CHANGEPW_SERVICE "kadmin/changepw" +#define KADM5_HIST_PRINCIPAL "kadmin/history" + +typedef krb5_principal kadm5_princ_t; +typedef char *kadm5_policy_t; +typedef long kadm5_ret_t; + +#define KADM5_PW_FIRST_PROMPT \ + ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT)) +#define KADM5_PW_SECOND_PROMPT \ + ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT)) + +/* + * Succsessfull return code + */ +#define KADM5_OK 0 + +/* + * XXX This should be in kdb.h; it is here so that I do not have to + * change that file yet, but this should be *very* temporary. + * --- bjaspan, 5/23/96 + */ +#define KRB5_TL_KADM5_E_DATA 0x0004 + +/* + * Field masks + */ + +/* kadm5_principal_ent_t */ +#define KADM5_PRINCIPAL 0x000001 +#define KADM5_PRINC_EXPIRE_TIME 0x000002 +#define KADM5_PW_EXPIRATION 0x000004 +#define KADM5_LAST_PWD_CHANGE 0x000008 +#define KADM5_ATTRIBUTES 0x000010 +#define KADM5_MAX_LIFE 0x000020 +#define KADM5_MOD_TIME 0x000040 +#define KADM5_MOD_NAME 0x000080 +#define KADM5_KVNO 0x000100 +#define KADM5_MKVNO 0x000200 +#define KADM5_AUX_ATTRIBUTES 0x000400 +#define KADM5_POLICY 0x000800 +#define KADM5_POLICY_CLR 0x001000 +/* version 2 masks */ +#define KADM5_MAX_RLIFE 0x002000 +#define KADM5_LAST_SUCCESS 0x004000 +#define KADM5_LAST_FAILED 0x008000 +#define KADM5_FAIL_AUTH_COUNT 0x010000 +#define KADM5_KEY_DATA 0x020000 +#define KADM5_TL_DATA 0x040000 +/* all but KEY_DATA and TL_DATA */ +#define KADM5_PRINCIPAL_NORMAL_MASK 0x01ffff + +/* kadm5_policy_ent_t */ +#define KADM5_PW_MAX_LIFE 0x004000 +#define KADM5_PW_MIN_LIFE 0x008000 +#define KADM5_PW_MIN_LENGTH 0x010000 +#define KADM5_PW_MIN_CLASSES 0x020000 +#define KADM5_PW_HISTORY_NUM 0x040000 +#define KADM5_REF_COUNT 0x080000 + +/* kadm5_config_params */ +#define KADM5_CONFIG_REALM 0x000001 +#define KADM5_CONFIG_DBNAME 0x000002 +#define KADM5_CONFIG_MKEY_NAME 0x000004 +#define KADM5_CONFIG_MAX_LIFE 0x000008 +#define KADM5_CONFIG_MAX_RLIFE 0x000010 +#define KADM5_CONFIG_EXPIRATION 0x000020 +#define KADM5_CONFIG_FLAGS 0x000040 +#define KADM5_CONFIG_ADMIN_KEYTAB 0x000080 +#define KADM5_CONFIG_STASH_FILE 0x000100 +#define KADM5_CONFIG_ENCTYPE 0x000200 +#define KADM5_CONFIG_ADBNAME 0x000400 +#define KADM5_CONFIG_ADB_LOCKFILE 0x000800 +#define KADM5_CONFIG_PROFILE 0x001000 +#define KADM5_CONFIG_ACL_FILE 0x002000 +#define KADM5_CONFIG_KADMIND_PORT 0x004000 +#define KADM5_CONFIG_ENCTYPES 0x008000 +#define KADM5_CONFIG_ADMIN_SERVER 0x010000 +#define KADM5_CONFIG_DICT_FILE 0x020000 +#define KADM5_CONFIG_MKEY_FROM_KBD 0x040000 + +/* + * permission bits + */ +#define KADM5_PRIV_GET 0x01 +#define KADM5_PRIV_ADD 0x02 +#define KADM5_PRIV_MODIFY 0x04 +#define KADM5_PRIV_DELETE 0x08 + +/* + * API versioning constants + */ +#define KADM5_MASK_BITS 0xffffff00 + +#define KADM5_STRUCT_VERSION_MASK 0x12345600 +#define KADM5_STRUCT_VERSION_1 (KADM5_STRUCT_VERSION_MASK|0x01) +#define KADM5_STRUCT_VERSION KADM5_STRUCT_VERSION_1 + +#define KADM5_API_VERSION_MASK 0x12345700 +#define KADM5_API_VERSION_1 (KADM5_API_VERSION_MASK|0x01) +#define KADM5_API_VERSION_2 (KADM5_API_VERSION_MASK|0x02) + +typedef struct _kadm5_principal_ent_t_v2 { + krb5_principal principal; + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + krb5_kvno mkvno; + char *policy; + long aux_attributes; + + /* version 2 fields */ + krb5_deltat max_renewable_life; + krb5_timestamp last_success; + krb5_timestamp last_failed; + krb5_kvno fail_auth_count; + krb5_int16 n_key_data; + krb5_int16 n_tl_data; + krb5_tl_data *tl_data; + krb5_key_data *key_data; +} kadm5_principal_ent_rec_v2, *kadm5_principal_ent_t_v2; + +typedef struct _kadm5_principal_ent_t_v1 { + krb5_principal principal; + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + krb5_kvno mkvno; + char *policy; + long aux_attributes; +} kadm5_principal_ent_rec_v1, *kadm5_principal_ent_t_v1; + +#if USE_KADM5_API_VERSION == 1 +typedef struct _kadm5_principal_ent_t_v1 + kadm5_principal_ent_rec, *kadm5_principal_ent_t; +#else +typedef struct _kadm5_principal_ent_t_v2 + kadm5_principal_ent_rec, *kadm5_principal_ent_t; +#endif + +typedef struct _kadm5_policy_ent_t { + char *policy; + long pw_min_life; + long pw_max_life; + long pw_min_length; + long pw_min_classes; + long pw_history_num; + long policy_refcnt; +} kadm5_policy_ent_rec, *kadm5_policy_ent_t; + +typedef struct __krb5_key_salt_tuple { + krb5_enctype ks_enctype; + krb5_int32 ks_salttype; +} krb5_key_salt_tuple; + +/* + * Data structure returned by kadm5_get_config_params() + */ +typedef struct _kadm5_config_params { + long mask; + char * realm; + char * profile; + int kadmind_port; + + char * admin_server; + + char * dbname; + char * admin_dbname; + char * admin_lockfile; + char * admin_keytab; + char * acl_file; + char * dict_file; + + int mkey_from_kbd; + char * stash_file; + char * mkey_name; + krb5_enctype enctype; + krb5_deltat max_life; + krb5_deltat max_rlife; + krb5_timestamp expiration; + krb5_flags flags; + krb5_key_salt_tuple *keysalts; + krb5_int32 num_keysalts; +} kadm5_config_params; + +/*********************************************************************** + * This is the old krb5_realm_read_params, which I mutated into + * kadm5_get_config_params but which old code (kdb5_* and krb5kdc) + * still uses. + ***********************************************************************/ + +/* + * Data structure returned by krb5_read_realm_params() + */ +typedef struct __krb5_realm_params { + char * realm_profile; + char * realm_dbname; + char * realm_mkey_name; + char * realm_stash_file; + char * realm_kdc_ports; + char * realm_acl_file; + krb5_int32 realm_kadmind_port; + krb5_enctype realm_enctype; + krb5_deltat realm_max_life; + krb5_deltat realm_max_rlife; + krb5_timestamp realm_expiration; + krb5_flags realm_flags; + krb5_key_salt_tuple *realm_keysalts; + unsigned int realm_kadmind_port_valid:1; + unsigned int realm_enctype_valid:1; + unsigned int realm_max_life_valid:1; + unsigned int realm_max_rlife_valid:1; + unsigned int realm_expiration_valid:1; + unsigned int realm_flags_valid:1; + unsigned int realm_filler:7; + krb5_int32 realm_num_keysalts; +} krb5_realm_params; + +/* + * functions + */ + +#if USE_KADM5_API_VERSION > 1 +krb5_error_code kadm5_get_config_params(krb5_context context, + char *kdcprofile, char *kdcenv, + kadm5_config_params *params_in, + kadm5_config_params *params_out); +krb5_error_code kadm5_free_realm_params(krb5_context kcontext, + kadm5_config_params *params); +#endif + +kadm5_ret_t kadm5_init(char *client_name, char *pass, + char *service_name, +#if USE_KADM5_API_VERSION == 1 + char *realm, +#else + kadm5_config_params *params, +#endif + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +kadm5_ret_t kadm5_init_with_password(char *client_name, + char *pass, + char *service_name, +#if USE_KADM5_API_VERSION == 1 + char *realm, +#else + kadm5_config_params *params, +#endif + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +kadm5_ret_t kadm5_init_with_skey(char *client_name, + char *keytab, + char *service_name, +#if USE_KADM5_API_VERSION == 1 + char *realm, +#else + kadm5_config_params *params, +#endif + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +#if USE_KADM5_API_VERSION > 1 +kadm5_ret_t kadm5_init_with_creds(char *client_name, + krb5_ccache cc, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +#endif +kadm5_ret_t kadm5_flush(void *server_handle); +kadm5_ret_t kadm5_destroy(void *server_handle); +kadm5_ret_t kadm5_create_principal(void *server_handle, + kadm5_principal_ent_t ent, + long mask, char *pass); +kadm5_ret_t kadm5_delete_principal(void *server_handle, + krb5_principal principal); +kadm5_ret_t kadm5_modify_principal(void *server_handle, + kadm5_principal_ent_t ent, + long mask); +kadm5_ret_t kadm5_rename_principal(void *server_handle, + krb5_principal,krb5_principal); +#if USE_KADM5_API_VERSION == 1 +kadm5_ret_t kadm5_get_principal(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t *ent); +#else +kadm5_ret_t kadm5_get_principal(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t ent, + long mask); +#endif +kadm5_ret_t kadm5_chpass_principal(void *server_handle, + krb5_principal principal, + char *pass); +#if USE_KADM5_API_VERSION == 1 +kadm5_ret_t kadm5_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_keyblock **keyblock); +#else +kadm5_ret_t kadm5_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_keyblock **keyblocks, + int *n_keys); +#endif +kadm5_ret_t kadm5_create_policy(void *server_handle, + kadm5_policy_ent_t ent, + long mask); +/* + * kadm5_create_policy_internal is not part of the supported, + * exposed API. It is available only in the server library, and you + * shouldn't use it unless you know why it's there and how it's + * different from kadm5_create_policy. + */ +kadm5_ret_t kadm5_create_policy_internal(void *server_handle, + kadm5_policy_ent_t + entry, long mask); +kadm5_ret_t kadm5_delete_policy(void *server_handle, + kadm5_policy_t policy); +kadm5_ret_t kadm5_modify_policy(void *server_handle, + kadm5_policy_ent_t ent, + long mask); +/* + * kadm5_modify_policy_internal is not part of the supported, + * exposed API. It is available only in the server library, and you + * shouldn't use it unless you know why it's there and how it's + * different from kadm5_modify_policy. + */ +kadm5_ret_t kadm5_modify_policy_internal(void *server_handle, + kadm5_policy_ent_t + entry, long mask); +#if USE_KADM5_API_VERSION == 1 +kadm5_ret_t kadm5_get_policy(void *server_handle, + kadm5_policy_t policy, + kadm5_policy_ent_t *ent); +#else +kadm5_ret_t kadm5_get_policy(void *server_handle, + kadm5_policy_t policy, + kadm5_policy_ent_t ent); +#endif +kadm5_ret_t kadm5_get_privs(void *server_handle, + long *privs); + +kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret); + +kadm5_ret_t kadm5_free_principal_ent(void *server_handle, + kadm5_principal_ent_t + ent); +kadm5_ret_t kadm5_free_policy_ent(void *server_handle, + kadm5_policy_ent_t ent); + +kadm5_ret_t kadm5_get_principals(void *server_handle, + char *exp, char ***princs, + int *count); + +kadm5_ret_t kadm5_get_policies(void *server_handle, + char *exp, char ***pols, + int *count); + +#if USE_KADM5_API_VERSION > 1 +kadm5_ret_t kadm5_free_key_data(void *server_handle, + krb5_int16 *n_key_data, + krb5_key_data *key_data); +#endif + +#if USE_KADM5_API_VERSION == 1 +/* + * OVSEC_KADM_API_VERSION_1 should be, if possible, compile-time + * compatible with KADM5_API_VERSION_2. Basically, this means we have + * to continue to provide all the old ovsec_kadm function and symbol + * names. + */ + +#define OVSEC_KADM_ACLFILE "/krb5/ovsec_adm.acl" +#define OVSEC_KADM_WORDFILE "/krb5/ovsec_adm.dict" + +#define OVSEC_KADM_ADMIN_SERVICE "ovsec_adm/admin" +#define OVSEC_KADM_CHANGEPW_SERVICE "ovsec_adm/changepw" +#define OVSEC_KADM_HIST_PRINCIPAL "ovsec_adm/history" + +typedef krb5_principal ovsec_kadm_princ_t; +typedef krb5_keyblock ovsec_kadm_keyblock; +typedef char *ovsec_kadm_policy_t; +typedef long ovsec_kadm_ret_t; + +enum ovsec_kadm_salttype { OVSEC_KADM_SALT_V4, OVSEC_KADM_SALT_NORMAL }; +enum ovsec_kadm_saltmod { OVSEC_KADM_MOD_KEEP, OVSEC_KADM_MOD_V4, OVSEC_KADM_MOD_NORMAL }; + +#define OVSEC_KADM_PW_FIRST_PROMPT \ + ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_PROMPT)) +#define OVSEC_KADM_PW_SECOND_PROMPT \ + ((char *) error_message(CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT)) + +/* + * Succsessfull return code + */ +#define OVSEC_KADM_OK 0 + +/* + * Create/Modify masks + */ +/* principal */ +#define OVSEC_KADM_PRINCIPAL 0x000001 +#define OVSEC_KADM_PRINC_EXPIRE_TIME 0x000002 +#define OVSEC_KADM_PW_EXPIRATION 0x000004 +#define OVSEC_KADM_LAST_PWD_CHANGE 0x000008 +#define OVSEC_KADM_ATTRIBUTES 0x000010 +#define OVSEC_KADM_MAX_LIFE 0x000020 +#define OVSEC_KADM_MOD_TIME 0x000040 +#define OVSEC_KADM_MOD_NAME 0x000080 +#define OVSEC_KADM_KVNO 0x000100 +#define OVSEC_KADM_MKVNO 0x000200 +#define OVSEC_KADM_AUX_ATTRIBUTES 0x000400 +#define OVSEC_KADM_POLICY 0x000800 +#define OVSEC_KADM_POLICY_CLR 0x001000 +/* policy */ +#define OVSEC_KADM_PW_MAX_LIFE 0x004000 +#define OVSEC_KADM_PW_MIN_LIFE 0x008000 +#define OVSEC_KADM_PW_MIN_LENGTH 0x010000 +#define OVSEC_KADM_PW_MIN_CLASSES 0x020000 +#define OVSEC_KADM_PW_HISTORY_NUM 0x040000 +#define OVSEC_KADM_REF_COUNT 0x080000 + +/* + * permission bits + */ +#define OVSEC_KADM_PRIV_GET 0x01 +#define OVSEC_KADM_PRIV_ADD 0x02 +#define OVSEC_KADM_PRIV_MODIFY 0x04 +#define OVSEC_KADM_PRIV_DELETE 0x08 + +/* + * API versioning constants + */ +#define OVSEC_KADM_MASK_BITS 0xffffff00 + +#define OVSEC_KADM_STRUCT_VERSION_MASK 0x12345600 +#define OVSEC_KADM_STRUCT_VERSION_1 (OVSEC_KADM_STRUCT_VERSION_MASK|0x01) +#define OVSEC_KADM_STRUCT_VERSION OVSEC_KADM_STRUCT_VERSION_1 + +#define OVSEC_KADM_API_VERSION_MASK 0x12345700 +#define OVSEC_KADM_API_VERSION_1 (OVSEC_KADM_API_VERSION_MASK|0x01) + + +typedef struct _ovsec_kadm_principal_ent_t { + krb5_principal principal; + krb5_timestamp princ_expire_time; + krb5_timestamp last_pwd_change; + krb5_timestamp pw_expiration; + krb5_deltat max_life; + krb5_principal mod_name; + krb5_timestamp mod_date; + krb5_flags attributes; + krb5_kvno kvno; + krb5_kvno mkvno; + char *policy; + long aux_attributes; +} ovsec_kadm_principal_ent_rec, *ovsec_kadm_principal_ent_t; + +typedef struct _ovsec_kadm_policy_ent_t { + char *policy; + long pw_min_life; + long pw_max_life; + long pw_min_length; + long pw_min_classes; + long pw_history_num; + long policy_refcnt; +} ovsec_kadm_policy_ent_rec, *ovsec_kadm_policy_ent_t; + +/* + * functions + */ +ovsec_kadm_ret_t ovsec_kadm_init(char *client_name, char *pass, + char *service_name, char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +ovsec_kadm_ret_t ovsec_kadm_init_with_password(char *client_name, + char *pass, + char *service_name, + char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +ovsec_kadm_ret_t ovsec_kadm_init_with_skey(char *client_name, + char *keytab, + char *service_name, + char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); +ovsec_kadm_ret_t ovsec_kadm_flush(void *server_handle); +ovsec_kadm_ret_t ovsec_kadm_destroy(void *server_handle); +ovsec_kadm_ret_t ovsec_kadm_create_principal(void *server_handle, + ovsec_kadm_principal_ent_t ent, + long mask, char *pass); +ovsec_kadm_ret_t ovsec_kadm_delete_principal(void *server_handle, + krb5_principal principal); +ovsec_kadm_ret_t ovsec_kadm_modify_principal(void *server_handle, + ovsec_kadm_principal_ent_t ent, + long mask); +ovsec_kadm_ret_t ovsec_kadm_rename_principal(void *server_handle, + krb5_principal,krb5_principal); +ovsec_kadm_ret_t ovsec_kadm_get_principal(void *server_handle, + krb5_principal principal, + ovsec_kadm_principal_ent_t *ent); +ovsec_kadm_ret_t ovsec_kadm_chpass_principal(void *server_handle, + krb5_principal principal, + char *pass); +ovsec_kadm_ret_t ovsec_kadm_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_keyblock **keyblock); +ovsec_kadm_ret_t ovsec_kadm_create_policy(void *server_handle, + ovsec_kadm_policy_ent_t ent, + long mask); +/* + * ovsec_kadm_create_policy_internal is not part of the supported, + * exposed API. It is available only in the server library, and you + * shouldn't use it unless you know why it's there and how it's + * different from ovsec_kadm_create_policy. + */ +ovsec_kadm_ret_t ovsec_kadm_create_policy_internal(void *server_handle, + ovsec_kadm_policy_ent_t + entry, long mask); +ovsec_kadm_ret_t ovsec_kadm_delete_policy(void *server_handle, + ovsec_kadm_policy_t policy); +ovsec_kadm_ret_t ovsec_kadm_modify_policy(void *server_handle, + ovsec_kadm_policy_ent_t ent, + long mask); +/* + * ovsec_kadm_modify_policy_internal is not part of the supported, + * exposed API. It is available only in the server library, and you + * shouldn't use it unless you know why it's there and how it's + * different from ovsec_kadm_modify_policy. + */ +ovsec_kadm_ret_t ovsec_kadm_modify_policy_internal(void *server_handle, + ovsec_kadm_policy_ent_t + entry, long mask); +ovsec_kadm_ret_t ovsec_kadm_get_policy(void *server_handle, + ovsec_kadm_policy_t policy, + ovsec_kadm_policy_ent_t *ent); +ovsec_kadm_ret_t ovsec_kadm_get_privs(void *server_handle, + long *privs); + +ovsec_kadm_ret_t ovsec_kadm_chpass_principal_util(void *server_handle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret); + +ovsec_kadm_ret_t ovsec_kadm_free_principal_ent(void *server_handle, + ovsec_kadm_principal_ent_t + ent); +ovsec_kadm_ret_t ovsec_kadm_free_policy_ent(void *server_handle, + ovsec_kadm_policy_ent_t ent); + +ovsec_kadm_ret_t ovsec_kadm_get_principals(void *server_handle, + char *exp, char ***princs, + int *count); + +ovsec_kadm_ret_t ovsec_kadm_get_policies(void *server_handle, + char *exp, char ***pols, + int *count); + +#define OVSEC_KADM_FAILURE KADM5_FAILURE +#define OVSEC_KADM_AUTH_GET KADM5_AUTH_GET +#define OVSEC_KADM_AUTH_ADD KADM5_AUTH_ADD +#define OVSEC_KADM_AUTH_MODIFY KADM5_AUTH_MODIFY +#define OVSEC_KADM_AUTH_DELETE KADM5_AUTH_DELETE +#define OVSEC_KADM_AUTH_INSUFFICIENT KADM5_AUTH_INSUFFICIENT +#define OVSEC_KADM_BAD_DB KADM5_BAD_DB +#define OVSEC_KADM_DUP KADM5_DUP +#define OVSEC_KADM_RPC_ERROR KADM5_RPC_ERROR +#define OVSEC_KADM_NO_SRV KADM5_NO_SRV +#define OVSEC_KADM_BAD_HIST_KEY KADM5_BAD_HIST_KEY +#define OVSEC_KADM_NOT_INIT KADM5_NOT_INIT +#define OVSEC_KADM_UNK_PRINC KADM5_UNK_PRINC +#define OVSEC_KADM_UNK_POLICY KADM5_UNK_POLICY +#define OVSEC_KADM_BAD_MASK KADM5_BAD_MASK +#define OVSEC_KADM_BAD_CLASS KADM5_BAD_CLASS +#define OVSEC_KADM_BAD_LENGTH KADM5_BAD_LENGTH +#define OVSEC_KADM_BAD_POLICY KADM5_BAD_POLICY +#define OVSEC_KADM_BAD_PRINCIPAL KADM5_BAD_PRINCIPAL +#define OVSEC_KADM_BAD_AUX_ATTR KADM5_BAD_AUX_ATTR +#define OVSEC_KADM_BAD_HISTORY KADM5_BAD_HISTORY +#define OVSEC_KADM_BAD_MIN_PASS_LIFE KADM5_BAD_MIN_PASS_LIFE +#define OVSEC_KADM_PASS_Q_TOOSHORT KADM5_PASS_Q_TOOSHORT +#define OVSEC_KADM_PASS_Q_CLASS KADM5_PASS_Q_CLASS +#define OVSEC_KADM_PASS_Q_DICT KADM5_PASS_Q_DICT +#define OVSEC_KADM_PASS_REUSE KADM5_PASS_REUSE +#define OVSEC_KADM_PASS_TOOSOON KADM5_PASS_TOOSOON +#define OVSEC_KADM_POLICY_REF KADM5_POLICY_REF +#define OVSEC_KADM_INIT KADM5_INIT +#define OVSEC_KADM_BAD_PASSWORD KADM5_BAD_PASSWORD +#define OVSEC_KADM_PROTECT_PRINCIPAL KADM5_PROTECT_PRINCIPAL +#define OVSEC_KADM_BAD_SERVER_HANDLE KADM5_BAD_SERVER_HANDLE +#define OVSEC_KADM_BAD_STRUCT_VERSION KADM5_BAD_STRUCT_VERSION +#define OVSEC_KADM_OLD_STRUCT_VERSION KADM5_OLD_STRUCT_VERSION +#define OVSEC_KADM_NEW_STRUCT_VERSION KADM5_NEW_STRUCT_VERSION +#define OVSEC_KADM_BAD_API_VERSION KADM5_BAD_API_VERSION +#define OVSEC_KADM_OLD_LIB_API_VERSION KADM5_OLD_LIB_API_VERSION +#define OVSEC_KADM_OLD_SERVER_API_VERSION KADM5_OLD_SERVER_API_VERSION +#define OVSEC_KADM_NEW_LIB_API_VERSION KADM5_NEW_LIB_API_VERSION +#define OVSEC_KADM_NEW_SERVER_API_VERSION KADM5_NEW_SERVER_API_VERSION +#define OVSEC_KADM_SECURE_PRINC_MISSING KADM5_SECURE_PRINC_MISSING +#define OVSEC_KADM_NO_RENAME_SALT KADM5_NO_RENAME_SALT + +#endif /* USE_KADM5_API_VERSION == 1 */ + +#endif /* __KADM5_ADMIN_H__ */ diff --git a/src/lib/kadm5/admin_internal.h b/src/lib/kadm5/admin_internal.h new file mode 100644 index 000000000..d73837e67 --- /dev/null +++ b/src/lib/kadm5/admin_internal.h @@ -0,0 +1,79 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#ifndef __KADM5_ADMIN_INTERNAL_H__ +#define __KADM5_ADMIN_INTERNAL_H__ + +#include <kadm5/admin.h> + +#define KADM5_SERVER_HANDLE_MAGIC 0x12345800 + +#define GENERIC_CHECK_HANDLE(handle, old_api_version, new_api_version) \ +{ \ + kadm5_server_handle_t srvr = \ + (kadm5_server_handle_t) handle; \ + \ + if (! srvr) \ + return KADM5_BAD_SERVER_HANDLE; \ + if (srvr->magic_number != KADM5_SERVER_HANDLE_MAGIC) \ + return KADM5_BAD_SERVER_HANDLE; \ + if ((srvr->struct_version & KADM5_MASK_BITS) != \ + KADM5_STRUCT_VERSION_MASK) \ + return KADM5_BAD_STRUCT_VERSION; \ + if (srvr->struct_version < KADM5_STRUCT_VERSION_1) \ + return KADM5_OLD_STRUCT_VERSION; \ + if (srvr->struct_version > KADM5_STRUCT_VERSION_1) \ + return KADM5_NEW_STRUCT_VERSION; \ + if ((srvr->api_version & KADM5_MASK_BITS) != \ + KADM5_API_VERSION_MASK) \ + return KADM5_BAD_API_VERSION; \ + if (srvr->api_version < KADM5_API_VERSION_1) \ + return old_api_version; \ + if (srvr->api_version > KADM5_API_VERSION_2) \ + return new_api_version; \ +} + +/* + * _KADM5_CHECK_HANDLE calls the function _kadm5_check_handle and + * returns any non-zero error code that function returns. + * _kadm5_check_handle, in client_handle.c and server_handle.c, exists + * in both the server- and client- side libraries. In each library, + * it calls CHECK_HANDLE, which is defined by the appropriate + * _internal.h header file to call GENERIC_CHECK_HANDLE as well as + * CLIENT_CHECK_HANDLE and SERVER_CHECK_HANDLE. + * + * _KADM5_CHECK_HANDLE should be used by a function that needs to + * check the handle but wants to be the same code in both the client + * and server library; it makes a function call to the right handle + * checker. Code that only exists in one library can call the + * CHECK_HANDLE macro, which inlines the test instead of making + * another function call. + * + * Got that? + */ +#define _KADM5_CHECK_HANDLE(handle) \ +{ int code; if (code = _kadm5_check_handle((void *)handle)) return code; } + +kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, + void *lhandle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret); + +/* this is needed by the alt_prof code I stole. The functions + maybe shouldn't be named krb5_*, but they are. */ + +krb5_error_code +krb5_string_to_keysalts(char *string, const char *tupleseps, + const char *ksaltseps, krb5_boolean dups, + krb5_key_salt_tuple **ksaltp, krb5_int32 *nksaltp); + +krb5_error_code +krb5_string_to_flags(char* string, const char* positive, const char* negative, + krb5_flags *flagsp); + +#endif /* __KADM5_ADMIN_INTERNAL_H__ */ diff --git a/src/lib/kadm5/admin_xdr.h b/src/lib/kadm5/admin_xdr.h new file mode 100644 index 000000000..3e4f48f7a --- /dev/null +++ b/src/lib/kadm5/admin_xdr.h @@ -0,0 +1,65 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + * $Log$ + * Revision 1.5 1996/07/22 20:35:33 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.4.4.1 1996/07/18 03:08:25 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.4.2.1 1996/06/20 02:16:37 marc + * File added to the repository on a branch + * + * Revision 1.4 1996/05/30 16:36:34 bjaspan + * finish updating to kadm5 naming (oops) + * + * Revision 1.3 1996/05/22 00:28:19 bjaspan + * rename to kadm5 + * + * Revision 1.2 1996/05/12 06:30:10 marc + * - fixup includes and data types to match beta6 + * + * Revision 1.1 1993/11/09 04:06:01 shanzer + * Initial revision + * + */ + +#include <kadm5/admin.h> +#include "kadm_rpc.h" + +bool_t xdr_nullstring(XDR *xdrs, char **objp); +bool_t xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp); +bool_t xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp); +bool_t xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp); +bool_t xdr_krb5_flags(XDR *xdrs, krb5_flags *objp); +bool_t xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp); +bool_t xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp); +bool_t xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp); +bool_t xdr_kadm5_policy_ent_t(XDR *xdrs, kadm5_policy_ent_t *objp); +bool_t xdr_kadm5_principal_ent_t(XDR *xdrs, kadm5_principal_ent_t *objp); +bool_t xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp); +bool_t xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp); +bool_t xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp); +bool_t xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp); +bool_t xdr_chpass_arg(XDR *xdrs, chpass_arg *objp); +bool_t xdr_chrand_arg(XDR *xdrs, chrand_arg *objp); +bool_t xdr_chrand_ret(XDR *xdrs, chrand_ret *objp); +bool_t xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp); +bool_t xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp); +bool_t xdr_cpol_arg(XDR *xdrs, cpol_arg *objp); +bool_t xdr_dpol_arg(XDR *xdrs, dpol_arg *objp); +bool_t xdr_mpol_arg(XDR *xdrs, mpol_arg *objp); +bool_t xdr_gpol_arg(XDR *xdrs, gpol_arg *objp); +bool_t xdr_gpol_ret(XDR *xdrs, gpol_ret *objp); +bool_t xdr_krb5_principal(XDR *xdrs, krb5_principal *objp); +bool_t xdr_krb5_octet(XDR *xdrs, krb5_octet *objp); +bool_t xdr_krb5_int32(XDR *xdrs, krb5_int32 *objp); +bool_t xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp); +bool_t xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp); diff --git a/src/lib/kadm5/alt_prof.c b/src/lib/kadm5/alt_prof.c new file mode 100644 index 000000000..2f36f76fa --- /dev/null +++ b/src/lib/kadm5/alt_prof.c @@ -0,0 +1,861 @@ +/* + * lib/kadm/alt_prof.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * alt_prof.c - Implement alternate profile file handling. + */ +#include "k5-int.h" +#include <kadm5/admin.h> +#include <stdio.h> +#include <ctype.h> + +/* + * krb5_aprof_init() - Initialize alternate profile context. + * + * Parameters: + * fname - default file name of the profile. + * envname - environment variable name which can override fname. + * acontextp - Pointer to opaque context for alternate profile. + * + * Returns: + * error codes from profile_init() + */ +krb5_error_code +krb5_aprof_init(fname, envname, acontextp) + char *fname; + char *envname; + krb5_pointer *acontextp; +{ + krb5_error_code kret; + const char *namelist[2]; + profile_t profile; + + namelist[1] = (char *) NULL; + profile = (profile_t) NULL; + if (envname) { + if ((namelist[0] = getenv(envname))) { + if (!(kret = profile_init(namelist, &profile))) { + *acontextp = (krb5_pointer) profile; + return(0); + } + } + } + namelist[0] = fname; + profile = (profile_t) NULL; + if (!(kret = profile_init(namelist, &profile))) { + *acontextp = (krb5_pointer) profile; + return(0); + } + return(kret); +} + +/* + * krb5_aprof_getvals() - Get values from alternate profile. + * + * Parameters: + * acontext - opaque context for alternate profile. + * hierarchy - hierarchy of value to retrieve. + * retdata - Returned data values. + * + * Returns: + * error codes from profile_get_values() + */ +krb5_error_code +krb5_aprof_getvals(acontext, hierarchy, retdata) + krb5_pointer acontext; + const char **hierarchy; + char ***retdata; +{ + return(profile_get_values((profile_t) acontext, + hierarchy, + retdata)); +} + +/* + * krb5_aprof_get_deltat() - Get a delta time value from the alternate + * profile. + * + * Parameters: + * acontext - opaque context for alternate profile. + * hierarchy - hierarchy of value to retrieve. + * uselast - if true, use last value, otherwise use + * first value found. + * deltatp - returned delta time value. + * + * Returns: + * error codes from profile_get_values() + * error codes from krb5_string_to_deltat() + */ +krb5_error_code +krb5_aprof_get_deltat(acontext, hierarchy, uselast, deltatp) + krb5_pointer acontext; + const char **hierarchy; + krb5_boolean uselast; + krb5_deltat *deltatp; +{ + krb5_error_code kret; + char **values; + char *valp; + int index; + + if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { + index = 0; + if (uselast) { + for (index=0; values[index]; index++); + index--; + } + valp = values[index]; + kret = krb5_string_to_deltat(valp, deltatp); + + /* Free the string storage */ + for (index=0; values[index]; index++) + krb5_xfree(values[index]); + krb5_xfree(values); + } + return(kret); +} + +/* + * krb5_aprof_get_string() - Get a string value from the alternate + * profile. + * + * Parameters: + * acontext - opaque context for alternate profile. + * hierarchy - hierarchy of value to retrieve. + * uselast - if true, use last value, otherwise use + * first value found. + * stringp - returned string value. + * + * Returns: + * error codes from profile_get_values() + */ +krb5_error_code +krb5_aprof_get_string(acontext, hierarchy, uselast, stringp) + krb5_pointer acontext; + const char **hierarchy; + krb5_boolean uselast; + char **stringp; +{ + krb5_error_code kret; + char **values; + int index, i; + + if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { + index = 0; + if (uselast) { + for (index=0; values[index]; index++); + index--; + } + + *stringp = values[index]; + + /* Free the string storage */ + for (i=0; values[i]; i++) + if (i != index) + krb5_xfree(values[i]); + krb5_xfree(values); + } + return(kret); +} + +/* + * krb5_aprof_get_int32() - Get a 32-bit integer value from the alternate + * profile. + * + * Parameters: + * acontext - opaque context for alternate profile. + * hierarchy - hierarchy of value to retrieve. + * uselast - if true, use last value, otherwise use + * first value found. + * intp - returned 32-bit integer value. + * + * Returns: + * error codes from profile_get_values() + * EINVAL - value is not an integer + */ +krb5_error_code +krb5_aprof_get_int32(acontext, hierarchy, uselast, intp) + krb5_pointer acontext; + const char **hierarchy; + krb5_boolean uselast; + krb5_int32 *intp; +{ + krb5_error_code kret; + char **values; + int index; + + if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) { + index = 0; + if (uselast) { + for (index=0; values[index]; index++); + index--; + } + + if (sscanf(values[index], "%d", intp) != 1) + kret = EINVAL; + + /* Free the string storage */ + for (index=0; values[index]; index++) + krb5_xfree(values[index]); + krb5_xfree(values); + } + return(kret); +} + +/* + * krb5_aprof_finish() - Finish alternate profile context. + * + * Parameter: + * acontext - opaque context for alternate profile. + * + * Returns: + * 0 on success, something else on failure. + */ +krb5_error_code +krb5_aprof_finish(acontext) + krb5_pointer acontext; +{ + profile_release(acontext); + return(0); +} + +/* + * Function: kadm5_get_config_params + * + * Purpose: Merge configuration parameters provided by the caller with + * values specified in configuration files and with default values. + * + * Arguments: + * + * context (r) krb5_context to use + * profile (r) profile file to use + * envname (r) envname that contains a profile name to + * override profile + * params_in (r) params structure containing user-supplied + * values, or NULL + * params_out (w) params structure to be filled in + * + * Effects: + * + * The fields and mask of params_out are filled in with values + * obtained from params_in, the specified profile, and default + * values. Only and all fields specified in params_out->mask are + * set. The context of params_out must be freed with + * kadm5_free_config_params. + * + * params_in and params_out may be the same pointer. However, all pointers + * in params_in for which the mask is set will be re-assigned to newly copied + * versions, overwriting the old pointer value. + */ +krb5_error_code kadm5_get_config_params(context, kdcprofile, kdcenv, + params_in, params_out) + krb5_context context; + char *kdcprofile; + char *kdcenv; + kadm5_config_params *params_in, *params_out; +{ + char *filename; + char *envname; + char *lrealm; + krb5_pointer aprofile = 0; + const char *hierarchy[4]; + char *svalue; + krb5_int32 ivalue; + krb5_deltat dtvalue; + kadm5_config_params params, empty_params; + + krb5_error_code kret; + + memset((char *) ¶ms, 0, sizeof(params)); + memset((char *) &empty_params, 0, sizeof(empty_params)); + + if (params_in == NULL) params_in = &empty_params; + + if (params_in->mask & KADM5_CONFIG_REALM) { + lrealm = params.realm = strdup(params_in->realm); + params.mask |= KADM5_CONFIG_REALM; + } else { + kret = krb5_get_default_realm(context, &lrealm); + if (kret) + goto cleanup; + params.realm = lrealm; + params.mask |= KADM5_CONFIG_REALM; + } + if (params_in->mask & KADM5_CONFIG_PROFILE) { + filename = params.profile = strdup(params_in->profile); + params.mask |= KADM5_CONFIG_PROFILE; + envname = NULL; + } else { + /* XXX ummm... these defaults should to work on both sides */ + filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE; + envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV; + if (context->profile_secure == TRUE) envname = 0; + } + + kret = krb5_aprof_init(filename, envname, &aprofile); + if (kret) + goto cleanup; + + /* Initialize realm parameters */ + hierarchy[0] = "realms"; + hierarchy[1] = lrealm; + hierarchy[3] = (char *) NULL; + + /* Get the value for the admin server */ + hierarchy[2] = "admin_server"; + if (params_in->mask & KADM5_CONFIG_ADMIN_SERVER) { + params.mask |= KADM5_CONFIG_ADMIN_SERVER; + params.admin_server = strdup(params_in->admin_server); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.admin_server = svalue; + params.mask |= KADM5_CONFIG_ADMIN_SERVER; + } + if (params.mask & KADM5_CONFIG_ADMIN_SERVER) { + char *p; + if (p = strchr(params.admin_server, ':')) { + params.kadmind_port = atoi(p+1); + params.mask |= KADM5_CONFIG_KADMIND_PORT; + *p = '\0'; + } + } + + /* Get the value for the database */ + hierarchy[2] = "database_name"; + if (params_in->mask & KADM5_CONFIG_DBNAME) { + params.mask |= KADM5_CONFIG_DBNAME; + params.dbname = strdup(params_in->dbname); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.dbname = svalue; + params.mask |= KADM5_CONFIG_DBNAME; + } + + /* + * Get the value for the admin (policy) database and lockfile. + * The logic here is slightly tricky. DBNAME, ADBNAME, and + * ADB_LOCKFILE are dependent on the earlier items in the + * sequence. If an earlier item was specified via the input + * parameters, that value overrides the variables in the config + * file and causes the later item to be set to ".kadm5" or + * ".lock", respectively. However, if no earlier item was + * specified, the variables in the config file are used, and the + * ".kadm5" and ".lock" suffixes are only added as a no-variable + * default. + * + * Read the spec. + */ + hierarchy[2] = "admin_database_name"; + if (params_in->mask & KADM5_CONFIG_ADBNAME) { + params.mask |= KADM5_CONFIG_ADBNAME; + params.admin_dbname = strdup(params_in->admin_dbname); + } else if (params_in->mask & KADM5_CONFIG_DBNAME) { + params.admin_dbname = (char *) malloc(strlen(params.dbname) + 6); + if (params.admin_dbname) { + sprintf(params.admin_dbname, "%s.kadm5", params.dbname); + params.mask |= KADM5_CONFIG_ADBNAME; + } + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.admin_dbname = svalue; + params.mask |= KADM5_CONFIG_ADBNAME; + } else if (params.mask & KADM5_CONFIG_DBNAME) { + params.admin_dbname = (char *) malloc(strlen(params.dbname) + 6); + if (params.admin_dbname) { + sprintf(params.admin_dbname, "%s.kadm5", params.dbname); + params.mask |= KADM5_CONFIG_ADBNAME; + } + } + + /* Get the value for the admin (policy) database lock file*/ + hierarchy[2] = "admin_database_lockfile"; + if (params_in->mask & KADM5_CONFIG_ADB_LOCKFILE) { + params.mask |= KADM5_CONFIG_ADB_LOCKFILE; + params.admin_lockfile = strdup(params_in->admin_lockfile); + } else if ((params_in->mask & KADM5_CONFIG_ADBNAME) || + (params_in->mask & KADM5_CONFIG_DBNAME)) { + /* if DBNAME is set but ADBNAME is not, then admin_database + * will already have been set above */ + params.admin_lockfile = (char *) malloc(strlen(params.admin_dbname) + + 6); + if (params.admin_lockfile) { + sprintf(params.admin_lockfile, "%s.lock", params.admin_dbname); + params.mask |= KADM5_CONFIG_ADB_LOCKFILE; + } + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_ADB_LOCKFILE; + params.admin_lockfile = svalue; + } else if (params.mask & KADM5_CONFIG_ADBNAME) { + params.admin_lockfile = (char *) malloc(strlen(params.admin_dbname) + + 6); + if (params.admin_lockfile) { + sprintf(params.admin_lockfile, "%s.lock", params.admin_dbname); + params.mask |= KADM5_CONFIG_ADB_LOCKFILE; + } + } + + /* Get the value for the admin (policy) database lock file*/ + hierarchy[2] = "admin_keytab"; + if (params_in->mask & KADM5_CONFIG_ADMIN_KEYTAB) { + params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; + params.admin_keytab = strdup(params_in->admin_keytab); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; + params.admin_keytab = svalue; + } else { + params.admin_keytab = (char *) getenv("KRB5_KTNAME"); + if (params.admin_keytab) { + params.admin_keytab = strdup(params.admin_keytab); + if (params.admin_keytab) + params.mask |= KADM5_CONFIG_ADMIN_KEYTAB; + } + } + + /* Get the name of the acl file */ + hierarchy[2] = "acl_file"; + if (params_in->mask & KADM5_CONFIG_ACL_FILE) { + params.mask |= KADM5_CONFIG_ACL_FILE; + params.acl_file = strdup(params_in->acl_file); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_ACL_FILE; + params.acl_file = svalue; + } + + /* Get the name of the dict file */ + hierarchy[2] = "dict_file"; + if (params_in->mask & KADM5_CONFIG_DICT_FILE) { + params.mask |= KADM5_CONFIG_DICT_FILE; + params.dict_file = strdup(params_in->dict_file); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_DICT_FILE; + params.dict_file = svalue; + } + + /* Get the value for the kadmind port */ + if (! (params.mask & KADM5_CONFIG_KADMIND_PORT)) { + hierarchy[2] = "kadmind_port"; + if (params_in->mask & KADM5_CONFIG_KADMIND_PORT) { + params.mask |= KADM5_CONFIG_KADMIND_PORT; + params.kadmind_port = params_in->kadmind_port; + } else if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, + &ivalue)) { + params.kadmind_port = ivalue; + params.mask |= KADM5_CONFIG_KADMIND_PORT; + } else { + params.kadmind_port = 749; /* assigned by IANA */ + params.mask |= KADM5_CONFIG_KADMIND_PORT; + } + } + + /* Get the value for the master key name */ + hierarchy[2] = "master_key_name"; + if (params_in->mask & KADM5_CONFIG_MKEY_NAME) { + params.mask |= KADM5_CONFIG_MKEY_NAME; + params.mkey_name = strdup(params_in->mkey_name); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_MKEY_NAME; + params.mkey_name = svalue; + } + + /* Get the value for the master key type */ + hierarchy[2] = "master_key_type"; + if (params_in->mask & KADM5_CONFIG_ENCTYPE) { + params.mask |= KADM5_CONFIG_ENCTYPE; + params.enctype = params_in->enctype; + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + if (!krb5_string_to_enctype(svalue, ¶ms.enctype)) { + params.mask |= KADM5_CONFIG_ENCTYPE; + krb5_xfree(svalue); + } + } + + /* Get the value for mkey_from_kbd */ + if (params_in->mask & KADM5_CONFIG_MKEY_FROM_KBD) { + params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; + params.mkey_from_kbd = params_in->mkey_from_kbd; + } + + /* Get the value for the stashfile */ + hierarchy[2] = "key_stash_file"; + if (params_in->mask & KADM5_CONFIG_STASH_FILE) { + params.mask |= KADM5_CONFIG_STASH_FILE; + params.stash_file = strdup(params_in->stash_file); + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.mask |= KADM5_CONFIG_STASH_FILE; + params.stash_file = svalue; + } + + /* Get the value for maximum ticket lifetime. */ + hierarchy[2] = "max_life"; + if (params_in->mask & KADM5_CONFIG_MAX_LIFE) { + params.mask |= KADM5_CONFIG_MAX_LIFE; + params.max_life = params_in->max_life; + } else if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { + params.max_life = dtvalue; + params.mask |= KADM5_CONFIG_MAX_LIFE; + } else { + params.max_life = 0; + params.mask |= KADM5_CONFIG_MAX_LIFE; + } + + /* Get the value for maximum renewable ticket lifetime. */ + hierarchy[2] = "max_renewable_life"; + if (params_in->mask & KADM5_CONFIG_MAX_RLIFE) { + params.mask |= KADM5_CONFIG_MAX_RLIFE; + params.max_rlife = params_in->max_rlife; + } else if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { + params.max_rlife = dtvalue; + params.mask |= KADM5_CONFIG_MAX_RLIFE; + } else { + params.max_rlife = 0; + params.mask |= KADM5_CONFIG_MAX_RLIFE; + } + + /* Get the value for the default principal expiration */ + hierarchy[2] = "default_principal_expiration"; + if (params_in->mask & KADM5_CONFIG_EXPIRATION) { + params.mask |= KADM5_CONFIG_EXPIRATION; + params.expiration = params_in->expiration; + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + if (!krb5_string_to_timestamp(svalue, ¶ms.expiration)) { + params.mask |= KADM5_CONFIG_EXPIRATION; + krb5_xfree(svalue); + } + } else { + params.mask |= KADM5_CONFIG_EXPIRATION; + params.expiration = 0; + } + + /* Get the value for the default principal flags */ + hierarchy[2] = "default_principal_flags"; + if (params_in->mask & KADM5_CONFIG_FLAGS) { + params.mask |= KADM5_CONFIG_FLAGS; + params.flags = params_in->flags; + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + char *sp, *ep, *tp; + + sp = svalue; + params.flags = 0; + while (sp) { + if ((ep = strchr(sp, (int) ',')) || + (ep = strchr(sp, (int) ' ')) || + (ep = strchr(sp, (int) '\t'))) { + /* Fill in trailing whitespace of sp */ + tp = ep - 1; + while (isspace(*tp) && (tp < sp)) { + *tp = '\0'; + tp--; + } + *ep = '\0'; + ep++; + /* Skip over trailing whitespace of ep */ + while (isspace(*ep) && (*ep)) ep++; + } + /* Convert this flag */ + if (krb5_string_to_flags(sp, + "+", + "-", + ¶ms.flags)) + break; + sp = ep; + } + if (!sp) + params.mask |= KADM5_CONFIG_FLAGS; + krb5_xfree(svalue); + } else { + params.mask |= KADM5_CONFIG_FLAGS; + params.flags = KRB5_KDB_DEF_FLAGS; + } + + /* Get the value for the supported enctype/salttype matrix */ + hierarchy[2] = "supported_enctypes"; + if (params_in->mask & KADM5_CONFIG_ENCTYPES) { + params.mask |= KADM5_CONFIG_ENCTYPES; + params.keysalts = params_in->keysalts; + params.num_keysalts = params_in->num_keysalts; + } else if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + params.keysalts = NULL; + params.num_keysalts = 0; + krb5_string_to_keysalts(svalue, + ", \t", /* Tuple separators */ + ":.-", /* Key/salt separators */ + 0, /* No duplicates */ + ¶ms.keysalts, + ¶ms.num_keysalts); + if (params.num_keysalts) + params.mask |= KADM5_CONFIG_ENCTYPES; + krb5_xfree(svalue); + } + + *params_out = params; + +cleanup: + if (aprofile) + krb5_aprof_finish(aprofile); + if (kret) { + kadm5_free_config_params(context, ¶ms); + params_out->mask = 0; + } + return(kret); +} +/* + * kadm5_free_config_params() - Free data allocated by above. + */ +krb5_error_code +kadm5_free_config_params(context, params) + krb5_context context; + kadm5_config_params *params; +{ + if (params) { + if (params->profile) + krb5_xfree(params->profile); + if (params->dbname) + krb5_xfree(params->dbname); + if (params->mkey_name) + krb5_xfree(params->mkey_name); + if (params->stash_file) + krb5_xfree(params->stash_file); + if (params->keysalts) + krb5_xfree(params->keysalts); + if (params->admin_keytab) + free(params->admin_keytab); + if (params->dict_file) + free(params->dict_file); + if (params->acl_file) + free(params->acl_file); + if (params->realm) + free(params->realm); + if (params->admin_dbname) + free(params->admin_dbname); + } + return(0); +} + +/*********************************************************************** + * This is the old krb5_realm_read_params, which I mutated into + * kadm5_get_config_params but which old code (kdb5_* and krb5kdc) + * still uses. + ***********************************************************************/ + +/* + * krb5_read_realm_params() - Read per-realm parameters from KDC + * alternate profile. + */ +krb5_error_code +krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp) + krb5_context kcontext; + char *realm; + char *kdcprofile; + char *kdcenv; + krb5_realm_params **rparamp; +{ + char *filename; + char *envname; + char *lrealm; + krb5_pointer aprofile = 0; + krb5_realm_params *rparams; + const char *hierarchy[4]; + char *svalue; + krb5_int32 ivalue; + krb5_deltat dtvalue; + + krb5_error_code kret; + + filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE; + envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV; + + if (kcontext->profile_secure == TRUE) envname = 0; + + rparams = (krb5_realm_params *) NULL; + if (realm) + lrealm = strdup(realm); + else { + kret = krb5_get_default_realm(kcontext, &lrealm); + if (kret) + goto cleanup; + } + + kret = krb5_aprof_init(filename, envname, &aprofile); + if (kret) + goto cleanup; + + rparams = (krb5_realm_params *) malloc(sizeof(krb5_realm_params)); + if (rparams == 0) { + kret = ENOMEM; + goto cleanup; + } + + /* Initialize realm parameters */ + memset((char *) rparams, 0, sizeof(krb5_realm_params)); + + /* Get the value for the database */ + hierarchy[0] = "realms"; + hierarchy[1] = lrealm; + hierarchy[2] = "database_name"; + hierarchy[3] = (char *) NULL; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_dbname = svalue; + + /* Get the value for the KDC port list */ + hierarchy[2] = "kdc_ports"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_kdc_ports = svalue; + + /* Get the name of the acl file */ + hierarchy[2] = "acl_file"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_acl_file = svalue; + + /* Get the value for the kadmind port */ + hierarchy[2] = "kadmind_port"; + if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) { + rparams->realm_kadmind_port = ivalue; + rparams->realm_kadmind_port_valid = 1; + } + + /* Get the value for the master key name */ + hierarchy[2] = "master_key_name"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_mkey_name = svalue; + + /* Get the value for the master key type */ + hierarchy[2] = "master_key_type"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + if (!krb5_string_to_enctype(svalue, &rparams->realm_enctype)) + rparams->realm_enctype_valid = 1; + krb5_xfree(svalue); + } + + /* Get the value for the stashfile */ + hierarchy[2] = "key_stash_file"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) + rparams->realm_stash_file = svalue; + + /* Get the value for maximum ticket lifetime. */ + hierarchy[2] = "max_life"; + if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { + rparams->realm_max_life = dtvalue; + rparams->realm_max_life_valid = 1; + } + + /* Get the value for maximum renewable ticket lifetime. */ + hierarchy[2] = "max_renewable_life"; + if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) { + rparams->realm_max_rlife = dtvalue; + rparams->realm_max_rlife_valid = 1; + } + + /* Get the value for the default principal expiration */ + hierarchy[2] = "default_principal_expiration"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + if (!krb5_string_to_timestamp(svalue, + &rparams->realm_expiration)) + rparams->realm_expiration_valid = 1; + krb5_xfree(svalue); + } + + /* Get the value for the default principal flags */ + hierarchy[2] = "default_principal_flags"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + char *sp, *ep, *tp; + + sp = svalue; + rparams->realm_flags = 0; + while (sp) { + if ((ep = strchr(sp, (int) ',')) || + (ep = strchr(sp, (int) ' ')) || + (ep = strchr(sp, (int) '\t'))) { + /* Fill in trailing whitespace of sp */ + tp = ep - 1; + while (isspace(*tp) && (tp < sp)) { + *tp = '\0'; + tp--; + } + *ep = '\0'; + ep++; + /* Skip over trailing whitespace of ep */ + while (isspace(*ep) && (*ep)) ep++; + } + /* Convert this flag */ + if (krb5_string_to_flags(sp, + "+", + "-", + &rparams->realm_flags)) + break; + sp = ep; + } + if (!sp) + rparams->realm_flags_valid = 1; + krb5_xfree(svalue); + } + + /* Get the value for the supported enctype/salttype matrix */ + hierarchy[2] = "supported_enctypes"; + if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) { + krb5_string_to_keysalts(svalue, + ", \t", /* Tuple separators */ + ":.-", /* Key/salt separators */ + 0, /* No duplicates */ + &rparams->realm_keysalts, + &rparams->realm_num_keysalts); + krb5_xfree(svalue); + } + +cleanup: + if (aprofile) + krb5_aprof_finish(aprofile); + if (lrealm) + free(lrealm); + if (kret) { + if (rparams) + krb5_free_realm_params(kcontext, rparams); + rparams = 0; + } + *rparamp = rparams; + return(kret); +} + +/* + * krb5_free_realm_params() - Free data allocated by above. + */ +krb5_error_code +krb5_free_realm_params(kcontext, rparams) + krb5_context kcontext; + krb5_realm_params *rparams; +{ + if (rparams) { + if (rparams->realm_profile) + krb5_xfree(rparams->realm_profile); + if (rparams->realm_dbname) + krb5_xfree(rparams->realm_dbname); + if (rparams->realm_mkey_name) + krb5_xfree(rparams->realm_mkey_name); + if (rparams->realm_stash_file) + krb5_xfree(rparams->realm_stash_file); + if (rparams->realm_keysalts) + krb5_xfree(rparams->realm_keysalts); + if (rparams->realm_kdc_ports) + krb5_xfree(rparams->realm_kdc_ports); + krb5_xfree(rparams); + } + return(0); +} + diff --git a/src/lib/kadm5/chpass_util.c b/src/lib/kadm5/chpass_util.c new file mode 100644 index 000000000..dbf610ce3 --- /dev/null +++ b/src/lib/kadm5/chpass_util.c @@ -0,0 +1,229 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * + */ + + +#include <stdio.h> +#include <memory.h> +#include <time.h> + +#include <kadm5/admin.h> +#include "admin_internal.h" + +#include <krb5.h> + +#define string_text error_message + +/* + * Function: kadm5_chpass_principal_util + * + * Purpose: Wrapper around chpass_principal. We can read new pw, change pw and return useful messages + * + * Arguments: + * + * princ (input) a krb5b_principal structure for the + * principal whose password we should change. + * + * new_password (input) NULL or a null terminated string with the + * the principal's desired new password. If new_password + * is NULL then this routine will read a new password. + * + * pw_ret (output) if non-NULL, points to a static buffer + * containing the new password (if password is prompted + * internally), or to the new_password argument (if + * that is non-NULL). If the former, then the buffer + * is only valid until the next call to the function, + * and the caller should be sure to zero it when + * it is no longer needed. + * + * msg_ret (output) a useful message is copied here. + * + * <return value> exit status of 0 for success, else the com err code + * for the last significant routine called. + * + * Requires: + * + * A msg_ret should point to a buffer large enough for the messasge. + * + * Effects: + * + * Modifies: + * + * + */ + +kadm5_ret_t _kadm5_chpass_principal_util(void *server_handle, + void *lhandle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret) +{ + int code, code2, pwsize; + static char buffer[255]; + char *new_password; + kadm5_principal_ent_rec princ_ent; + kadm5_policy_ent_rec policy_ent; + + _KADM5_CHECK_HANDLE(server_handle); + + if (ret_pw) + *ret_pw = NULL; + + if (new_pw != NULL) { + new_password = new_pw; + } else { /* read the password */ + krb5_context context; + + if ((code = (int) krb5_init_context(&context)) == 0) { + pwsize = sizeof(buffer); + code = krb5_read_password(context, KADM5_PW_FIRST_PROMPT, + KADM5_PW_SECOND_PROMPT, + buffer, &pwsize); + krb5_free_context(context); + } + + if (code == 0) + new_password = buffer; + else { +#ifdef ZEROPASSWD + memset(buffer, 0, sizeof(buffer)); +#endif + if (code == KRB5_LIBOS_BADPWDMATCH) { + strcpy(msg_ret, string_text(CHPASS_UTIL_NEW_PASSWORD_MISMATCH)); + return(code); + } else { + sprintf(msg_ret, "%s %s\n%s\n", error_message(code), + string_text(CHPASS_UTIL_WHILE_READING_PASSWORD), + string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); + return(code); + } + } + if (pwsize == 0) { +#ifdef ZEROPASSWD + memset(buffer, 0, sizeof(buffer)); +#endif + strcpy(msg_ret, string_text(CHPASS_UTIL_NO_PASSWORD_READ)); + return(KRB5_LIBOS_CANTREADPWD); /* could do better */ + } + } + + if (ret_pw) + *ret_pw = new_password; + + code = kadm5_chpass_principal(server_handle, princ, new_password); + +#ifdef ZEROPASSWD + if (!ret_pw) + memset(buffer, 0, sizeof(buffer)); /* in case we read a new password */ +#endif + + if (code == KADM5_OK) { + strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_CHANGED)); + return(0); + } + + if ((code != KADM5_PASS_Q_TOOSHORT) && + (code != KADM5_PASS_REUSE) &&(code != KADM5_PASS_Q_CLASS) && + (code != KADM5_PASS_Q_DICT) && (code != KADM5_PASS_TOOSOON)) { + /* Can't get more info for other errors */ + sprintf(buffer, "%s %s", error_message(code), + string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); + sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), + buffer); + return(code); + } + + /* Ok, we have a password quality error. Return a good message */ + + if (code == KADM5_PASS_REUSE) { + strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_REUSE)); + return(code); + } + + if (code == KADM5_PASS_Q_DICT) { + strcpy(msg_ret, string_text(CHPASS_UTIL_PASSWORD_IN_DICTIONARY)); + return(code); + } + + /* Look up policy for the remaining messages */ + + code2 = kadm5_get_principal (lhandle, princ, &princ_ent, + KADM5_PRINCIPAL_NORMAL_MASK); + if (code2 != 0) { + sprintf(msg_ret, "%s %s\n%s %s\n\n%s\n ", error_message(code2), + string_text(CHPASS_UTIL_GET_PRINC_INFO), + error_message(code), + string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), + string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); + return(code); + } + + if ((princ_ent.aux_attributes & KADM5_POLICY) == 0) { + sprintf(msg_ret, "%s %s\n\n%s", error_message(code), + string_text(CHPASS_UTIL_NO_POLICY_YET_Q_ERROR), + string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + return(code); + } + + code2 = kadm5_get_policy(lhandle, princ_ent.policy, + &policy_ent); + if (code2 != 0) { + sprintf(msg_ret, "%s %s\n%s %s\n\n%s\n ", error_message(code2), + string_text(CHPASS_UTIL_GET_POLICY_INFO), + error_message(code), + string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE), + string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED)); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + return(code); + } + + if (code == KADM5_PASS_Q_TOOSHORT) { + sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SHORT), + policy_ent.pw_min_length); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + (void) kadm5_free_policy_ent(lhandle, &policy_ent); + return(code); + } + +/* Can't get more info for other errors */ + + if (code == KADM5_PASS_Q_CLASS) { + sprintf(msg_ret, string_text(CHPASS_UTIL_TOO_FEW_CLASSES), + policy_ent.pw_min_classes); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + (void) kadm5_free_policy_ent(lhandle, &policy_ent); + return(code); + } + + if (code == KADM5_PASS_TOOSOON) { + time_t until; + char *time_string, *ptr; + + until = princ_ent.last_pwd_change + policy_ent.pw_min_life; + + time_string = ctime(&until); + if (*(ptr = &time_string[strlen(time_string)-1]) == '\n') + *ptr = '\0'; + + sprintf(msg_ret, string_text(CHPASS_UTIL_PASSWORD_TOO_SOON), + time_string); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + (void) kadm5_free_policy_ent(lhandle, &policy_ent); + return(code); + } + + /* We should never get here, but just in case ... */ + sprintf(buffer, "%s %s", error_message(code), + string_text(CHPASS_UTIL_WHILE_TRYING_TO_CHANGE)); + sprintf(msg_ret, "%s\n%s\n", string_text(CHPASS_UTIL_PASSWORD_NOT_CHANGED), + buffer); + (void) kadm5_free_principal_ent(lhandle, &princ_ent); + (void) kadm5_free_policy_ent(lhandle, &policy_ent); + return(code); +} diff --git a/src/lib/kadm5/chpass_util_strings.et b/src/lib/kadm5/chpass_util_strings.et new file mode 100644 index 000000000..032254998 --- /dev/null +++ b/src/lib/kadm5/chpass_util_strings.et @@ -0,0 +1,58 @@ +# this is really a string table for ovsec_kadm_chpass_principal_util + +error_table ovku + +error_code CHPASS_UTIL_GET_POLICY_INFO, "while getting policy info." +error_code CHPASS_UTIL_GET_PRINC_INFO, "while getting principal info." +error_code CHPASS_UTIL_NEW_PASSWORD_MISMATCH, + "New passwords do not match - password not changed.\n" + +error_code CHPASS_UTIL_NEW_PASSWORD_PROMPT, "New password:" +error_code CHPASS_UTIL_NEW_PASSWORD_AGAIN_PROMPT, "New password (again):" +error_code CHPASS_UTIL_NO_PASSWORD_READ, "You must type a password. Passwords must be at least one character long.\n" +error_code CHPASS_UTIL_NO_POLICY_YET_Q_ERROR, +"yet no policy set! Contact your system security administrator." + +error_code CHPASS_UTIL_PASSWORD_CHANGED, "Password changed.\n" + +error_code CHPASS_UTIL_PASSWORD_IN_DICTIONARY, +"New password was found in a dictionary of possible passwords and\n\ +therefore may be easily guessed. Please choose another password.\n\ +See the ovpasswd man page for help in choosing a good password." + +error_code CHPASS_UTIL_PASSWORD_NOT_CHANGED, "Password not changed." + +error_code CHPASS_UTIL_PASSWORD_TOO_SHORT, +"New password is too short.\n\ +Please choose a password which is at least %d characters long." +# /* <pw-min-len> */ + +error_code CHPASS_UTIL_TOO_FEW_CLASSES, +"New password does not have enough character classes.\n\ +The character classes are:\n\ + - lower-case letters,\n\ + - upper-case letters,\n\ + - digits,\n\ + - punctuation, and\n\ + - all other characters (e.g., control characters).\n\ +Please choose a password with at least %d character classes." +# /* <min-classes> */ + + +error_code CHPASS_UTIL_PASSWORD_TOO_SOON, +"Password cannot be changed because it was changed too recently.\n\ +Please wait until %s before you change it.\n\ +If you need to change your password before then, contact your system\n\ +security administrator." +# /* <ctime(last-pw-change+pw-min-life)> */ + +error_code CHPASS_UTIL_PASSWORD_REUSE, +"New password was used previously. Please choose a different password." + +error_code CHPASS_UTIL_WHILE_TRYING_TO_CHANGE, +"while trying to change password." + +error_code CHPASS_UTIL_WHILE_READING_PASSWORD, "while reading new password." + +end + diff --git a/src/lib/kadm5/client_handle.c b/src/lib/kadm5/client_handle.c new file mode 100644 index 000000000..895777a6e --- /dev/null +++ b/src/lib/kadm5/client_handle.c @@ -0,0 +1,9 @@ +#include <krb5.h> +#include <kadm5/admin.h> +#include "client_internal.h" + +int _kadm5_check_handle(void *handle) +{ + CHECK_HANDLE(handle); + return 0; +} diff --git a/src/lib/kadm5/client_init.c b/src/lib/kadm5/client_init.c new file mode 100644 index 000000000..bfc1c3a3c --- /dev/null +++ b/src/lib/kadm5/client_init.c @@ -0,0 +1,554 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <netdb.h> +#include <memory.h> +#include <string.h> +#include <com_err.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <krb5.h> +#include <k5-int.h> /* for KRB5_ADM_DEFAULT_PORT */ +#ifdef __STDC__ +#include <stdlib.h> +#endif + +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include "client_internal.h" + +#include <rpc/rpc.h> +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_krb5.h> +#include <rpc/auth_gssapi.h> + +#define ADM_CCACHE "/tmp/ovsec_adm.XXXXXX" + +#ifndef _POSIX_SOURCE /* Perhaps this should actually say __STDC__ */ +int setenv(const char *var, const char *val, int flag); +void unsetenv(const char *var); +#endif + +enum init_type { INIT_PASS, INIT_SKEY, INIT_CREDS }; + +static kadm5_ret_t _kadm5_init_any(char *client_name, + enum init_type init_type, + char *pass, + krb5_ccache ccache_in, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle); + +kadm5_ret_t kadm5_init_with_creds(char *client_name, + krb5_ccache ccache, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return _kadm5_init_any(client_name, INIT_CREDS, NULL, ccache, + service_name, params, + struct_version, api_version, + server_handle); +} + + +kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, + service_name, params, struct_version, + api_version, server_handle); +} + +kadm5_ret_t kadm5_init(char *client_name, char *pass, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return _kadm5_init_any(client_name, INIT_PASS, pass, NULL, + service_name, params, struct_version, + api_version, server_handle); +} + +kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return _kadm5_init_any(client_name, INIT_SKEY, keytab, NULL, + service_name, params, struct_version, + api_version, server_handle); +} + +/* + * Try no preauthentication first; then try the encrypted timestamp + * (stolen from krb5 kinit.c) + */ +static int preauth_search_list[] = { + 0, + KRB5_PADATA_ENC_UNIX_TIME, + -1 +}; + +static kadm5_ret_t _kadm5_init_any(char *client_name, + enum init_type init_type, + char *pass, + krb5_ccache ccache_in, + char *service_name, + kadm5_config_params *params_in, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + struct sockaddr_in addr; + struct hostent *hp; + struct servent *srv; + int fd; + int i; + + char full_service_name[BUFSIZ], host[MAXHOSTNAMELEN], *ccname_orig; + char *realm; + krb5_creds creds; + krb5_ccache ccache = NULL; + krb5_timestamp now; + + OM_uint32 gssstat, minor_stat; + gss_buffer_desc input_name; + gss_name_t gss_target, gss_client; + gss_cred_id_t gss_client_creds = GSS_C_NO_CREDENTIAL; + + kadm5_server_handle_t handle; + kadm5_config_params params_local; + + int code = 0; + generic_ret *r; + + initialize_ovk_error_table(); + initialize_adb_error_table(); + initialize_ovku_error_table(); + + if (! server_handle) { + return EINVAL; + } + + if (! (handle = malloc(sizeof(*handle)))) { + return ENOMEM; + } + if (! (handle->lhandle = malloc(sizeof(*handle)))) { + free(handle); + return ENOMEM; + } + + handle->magic_number = KADM5_SERVER_HANDLE_MAGIC; + handle->struct_version = struct_version; + handle->api_version = api_version; + handle->clnt = 0; + handle->cache_name = 0; + handle->destroy_cache = 0; + *handle->lhandle = *handle; + handle->lhandle->api_version = KADM5_API_VERSION_2; + handle->lhandle->struct_version = KADM5_STRUCT_VERSION; + handle->lhandle->lhandle = handle->lhandle; + + krb5_init_context(&handle->context); + krb5_init_ets(handle->context); + + if(service_name == NULL || client_name == NULL) { + free(handle); + return EINVAL; + } + memset((char *) &creds, 0, sizeof(creds)); + + /* + * Verify the version numbers before proceeding; we can't use + * CHECK_HANDLE because not all fields are set yet. + */ + GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, + KADM5_NEW_LIB_API_VERSION); + + /* + * Acquire relevant profile entries. In version 2, merge values + * in params_in with values from profile, based on + * params_in->mask. + * + * In version 1, we've given a realm (which may be NULL) instead + * of params_in. So use that realm, make params_in contain an + * empty mask, and behave like version 2. + */ + memset((char *) ¶ms_local, 0, sizeof(params_local)); + if (api_version == KADM5_API_VERSION_1) { + realm = params_local.realm = (char *) params_in; + if (params_in) + params_local.mask = KADM5_CONFIG_REALM; + params_in = ¶ms_local; + } else { + if (params_in && (params_in->mask & KADM5_CONFIG_REALM)) + realm = params_in->realm; + else + realm = NULL; + } + +#define ILLEGAL_PARAMS (KADM5_CONFIG_DBNAME | KADM5_CONFIG_ADBNAME | \ + KADM5_CONFIG_ADB_LOCKFILE | \ + KADM5_CONFIG_ACL_FILE | KADM5_CONFIG_DICT_FILE \ + | KADM5_CONFIG_ADMIN_KEYTAB | \ + KADM5_CONFIG_STASH_FILE | \ + KADM5_CONFIG_MKEY_NAME | KADM5_CONFIG_ENCTYPE \ + | KADM5_CONFIG_MAX_LIFE | \ + KADM5_CONFIG_MAX_RLIFE | \ + KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_FLAGS | \ + KADM5_CONFIG_ENCTYPES | KADM5_CONFIG_MKEY_FROM_KBD) + + if (params_in && params_in->mask & ILLEGAL_PARAMS) { + free(handle); + return KADM5_BAD_CLIENT_PARAMS; + } + + if (code = kadm5_get_config_params(handle->context, + "/etc/krb5.conf", + "KRB5_CONFIG", + params_in, + &handle->params)) { + krb5_free_context(handle->context); + free(handle); + return(code); + } + +#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | \ + KADM5_CONFIG_ADMIN_SERVER | \ + KADM5_CONFIG_KADMIND_PORT) + + if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { + krb5_free_context(handle->context); + free(handle); + return KRB5_CONFIG_BADFORMAT; + } + + /* + * Acquire a service ticket for service_name@realm in the name of + * client_name, using password pass (which could be NULL), and + * create a ccache to store them in. If INIT_CREDS, use the + * ccache we were provided instead. + */ + + if ((code = krb5_parse_name(handle->context, client_name, &creds.client))) + goto error; + + if (realm) { + sprintf(full_service_name, "%s@%s", service_name, realm); + } else { + /* krb5_princ_realm(creds.client) is not null terminated */ + strcpy(full_service_name, service_name); + strcat(full_service_name, "@"); + strncat(full_service_name, krb5_princ_realm(handle->context, + creds.client)->data, + krb5_princ_realm(handle->context, creds.client)->length); + } + + if ((code = krb5_parse_name(handle->context, full_service_name, + &creds.server))) + goto error; + + /* XXX temporarily fix a bug in krb5_cc_get_type */ +#undef krb5_cc_get_type +#define krb5_cc_get_type(context, cache) ((cache)->ops->prefix) + + + if (init_type == INIT_CREDS) { + ccache = ccache_in; + handle->cache_name = (char *) + malloc(strlen(krb5_cc_get_type(handle->context, ccache)) + + strlen(krb5_cc_get_name(handle->context, ccache)) + 2); + if (handle->cache_name == NULL) { + code = ENOMEM; + goto error; + } + sprintf(handle->cache_name, "%s:%s", + krb5_cc_get_type(handle->context, ccache), + krb5_cc_get_name(handle->context, ccache)); + } else { + handle->cache_name = + (char *) malloc(strlen(ADM_CCACHE)+strlen("FILE:")+1); + if (handle->cache_name == NULL) { + code = ENOMEM; + goto error; + } + sprintf(handle->cache_name, "FILE:%s", ADM_CCACHE); + mktemp(handle->cache_name + strlen("FILE:")); + + if ((code = krb5_cc_resolve(handle->context, handle->cache_name, + &ccache))) + goto error; + + if ((code = krb5_cc_initialize (handle->context, ccache, + creds.client))) + goto error; + + handle->destroy_cache = 1; + } + handle->lhandle->cache_name = handle->cache_name; + + if ((code = krb5_timeofday(handle->context, &now))) + goto error; + + /* + * Get a ticket, use the method specified in init_type. + */ + + creds.times.starttime = 0; /* start timer at KDC */ + creds.times.endtime = 0; /* endtime will be limited by service */ + + if (init_type == INIT_PASS) { + for (i=0; preauth_search_list[i] >= 0; i++) { + code = krb5_get_in_tkt_with_password(handle->context, + 0, /* no options */ + 0, /* default addresses */ + NULL, + NULL, /* XXX preauth */ + pass, + ccache, + &creds, + NULL); + if (code != KRB5KDC_ERR_PREAUTH_FAILED && + code != KRB5KDC_ERR_PREAUTH_REQUIRED && + code != KRB5KRB_ERR_GENERIC) + break; + } + } else if (init_type == INIT_SKEY) { + krb5_keytab kt = NULL; + + if (pass && (code = krb5_kt_resolve(handle->context, pass, &kt))) + ; + else { + for (i=0; preauth_search_list[i] >= 0; i++) { + code = krb5_get_in_tkt_with_keytab(handle->context, + 0, /* no options */ + 0, /* default addrs */ + NULL, + NULL, /* XXX preauth */ + kt, + ccache, + &creds, + NULL); + if (code != KRB5KDC_ERR_PREAUTH_FAILED && + code != KRB5KDC_ERR_PREAUTH_REQUIRED && + code != KRB5KRB_ERR_GENERIC) + break; + } + + if (pass) krb5_kt_close(handle->context, kt); + } + } + + /* Improved error messages */ + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) code = KADM5_BAD_PASSWORD; + if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) + code = KADM5_SECURE_PRINC_MISSING; + + if (code != 0) goto error; + +#ifdef ZEROPASSWD + if (pass != NULL) + memset(pass, 0, strlen(pass)); +#endif + + /* + * We have ticket; open the RPC connection. + */ + + hp = gethostbyname(handle->params.admin_server); + if (hp == (struct hostent *) NULL) { + code = KRB5_CONFIG_BADFORMAT; + goto cleanup; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = hp->h_addrtype; + (void) memcpy((char *) &addr.sin_addr, (char *) hp->h_addr, + sizeof(addr.sin_addr)); + addr.sin_port = htons((u_short) handle->params.kadmind_port); + + fd = RPC_ANYSOCK; + + handle->clnt = clnttcp_create(&addr, KADM, KADMVERS, &fd, 0, 0); + if (handle->clnt == NULL) { + code = KADM5_RPC_ERROR; + goto error; + } + handle->lhandle->clnt = handle->clnt; + + /* now that handle->clnt is set, we can check the handle */ + if (code = _kadm5_check_handle((void *) handle)) + goto error; + + /* + * The RPC connection is open; establish the GSS-API + * authentication context. + */ + + /* use the kadm5 cache */ + ccname_orig = getenv("KRB5CCNAME"); + if (ccname_orig) + ccname_orig = strdup(ccname_orig); + + (void) setenv("KRB5CCNAME", handle->cache_name, 1); + +#ifndef INIT_TEST + input_name.value = full_service_name; + input_name.length = strlen((char *)input_name.value) + 1; + gssstat = gss_import_name(&minor_stat, &input_name, + gss_nt_krb5_name, &gss_target); + if (gssstat != GSS_S_COMPLETE) { + code = KADM5_GSS_ERROR; + goto error; + } +#endif /* ! INIT_TEST */ + + input_name.value = client_name; + input_name.length = strlen((char *)input_name.value) + 1; + gssstat = gss_import_name(&minor_stat, &input_name, + gss_nt_krb5_name, &gss_client); + if (gssstat != GSS_S_COMPLETE) { + code = KADM5_GSS_ERROR; + goto error; + } + + gssstat = gss_acquire_cred(&minor_stat, gss_client, 0, + GSS_C_NULL_OID_SET, GSS_C_INITIATE, + &gss_client_creds, NULL, NULL); + (void) gss_release_name(&minor_stat, &gss_client); + if (gssstat != GSS_S_COMPLETE) { + code = KADM5_GSS_ERROR; + goto error; + } + +#ifndef INIT_TEST + handle->clnt->cl_auth = auth_gssapi_create(handle->clnt, + &gssstat, + &minor_stat, + gss_client_creds, + gss_target, + GSS_C_NULL_OID, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, + 0, + NULL, + NULL, + NULL); + (void) gss_release_name(&minor_stat, &gss_target); +#endif /* ! INIT_TEST */ + + if (ccname_orig) { + (void) setenv("KRB5CCNAME", ccname_orig, 1); + free(ccname_orig); + } else + (void) unsetenv("KRB5CCNAME"); + + + if (handle->clnt->cl_auth == NULL) { + code = KADM5_GSS_ERROR; + goto error; + } + + r = init_1(&handle->api_version, handle->clnt); + if (r == NULL) { + code = KADM5_RPC_ERROR; + goto error; + } + if (r->code) { + code = r->code; + goto error; + } + + *server_handle = (void *) handle; + + if (init_type != INIT_CREDS) + krb5_cc_close(handle->context, ccache); + + goto cleanup; + +error: + /* + * Note that it is illegal for this code to execute if "handle" + * has not been allocated and initialized. I.e., don't use "goto + * error" before the block of code at the top of the function + * that allocates and initializes "handle". + */ + if (handle->cache_name) + free(handle->cache_name); + if (handle->destroy_cache && ccache) + krb5_cc_destroy(handle->context, ccache); + if(handle->clnt && handle->clnt->cl_auth) + AUTH_DESTROY(handle->clnt->cl_auth); + if(handle->clnt) + clnt_destroy(handle->clnt); + +cleanup: + krb5_free_cred_contents(handle->context, &creds); + if (gss_client_creds != GSS_C_NO_CREDENTIAL) + (void) gss_release_cred(&minor_stat, &gss_client_creds); + + if (code) + free(handle); + + return code; +} + +kadm5_ret_t +kadm5_destroy(void *server_handle) +{ + krb5_ccache ccache = NULL; + int code = KADM5_OK; + kadm5_server_handle_t handle = + (kadm5_server_handle_t) server_handle; + + CHECK_HANDLE(server_handle); + + if (handle->destroy_cache && handle->cache_name) { + if ((code = krb5_cc_resolve(handle->context, + handle->cache_name, &ccache)) == 0) + code = krb5_cc_destroy (handle->context, ccache); + } + if (handle->cache_name) + free(handle->cache_name); + if (handle->clnt && handle->clnt->cl_auth) + AUTH_DESTROY(handle->clnt->cl_auth); + if (handle->clnt) + clnt_destroy(handle->clnt); + + handle->magic_number = 0; + free(handle); + + return code; +} + +kadm5_ret_t kadm5_flush(void *server_handle) +{ + return KADM5_OK; +} + +int _kadm5_check_handle(void *handle) +{ + CHECK_HANDLE(handle); + return 0; +} diff --git a/src/lib/kadm5/client_internal.h b/src/lib/kadm5/client_internal.h new file mode 100644 index 000000000..5a246158e --- /dev/null +++ b/src/lib/kadm5/client_internal.h @@ -0,0 +1,93 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + * $Log$ + * Revision 1.11 1996/07/22 20:35:46 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.10.4.1 1996/07/18 03:08:37 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.10.2.1 1996/06/20 02:16:46 marc + * File added to the repository on a branch + * + * Revision 1.10 1996/06/06 20:09:16 bjaspan + * add destroy_cache, for kadm5_init_with_creds + * + * Revision 1.9 1996/05/30 21:04:42 bjaspan + * add lhandle to handle + * + * Revision 1.8 1996/05/28 20:33:49 bjaspan + * rework kadm5_config + * + * Revision 1.7 1996/05/17 21:36:59 bjaspan + * rename to kadm5, begin implementing version 2 + * + * Revision 1.6 1996/05/16 21:45:07 bjaspan + * add context + * + * Revision 1.5 1996/05/08 21:10:23 bjaspan + * marc's changes + * + * Revision 1.4 1996/01/16 20:54:30 grier + * secure/3570 use krb5_ui_4 not unsigned int + * + * Revision 1.3 1995/11/14 17:48:57 grier + * long to int + * + * Revision 1.2 1994/08/16 18:53:47 jik + * Versioning stuff. + * + * Revision 1.1 1994/08/09 21:14:38 jik + * Initial revision + * + */ + +/* + * This header file is used internally by the Admin API client + * libraries. IF YOU THINK YOU NEED TO USE THIS FILE FOR ANYTHING, + * YOU'RE ALMOST CERTAINLY WRONG. + */ + +#ifndef __KADM5_CLIENT_INTERNAL_H__ +#define __KADM5_CLIENT_INTERNAL_H__ + +#include "admin_internal.h" + +typedef struct _kadm5_server_handle_t { + krb5_ui_4 magic_number; + krb5_ui_4 struct_version; + krb5_ui_4 api_version; + char * cache_name; + int destroy_cache; + CLIENT * clnt; + krb5_context context; + kadm5_config_params params; + struct _kadm5_server_handle_t *lhandle; +} kadm5_server_handle_rec, *kadm5_server_handle_t; + +#define CLIENT_CHECK_HANDLE(handle) \ +{ \ + kadm5_server_handle_t srvr = \ + (kadm5_server_handle_t) handle; \ + \ + if (! srvr->clnt) \ + return KADM5_BAD_SERVER_HANDLE; \ + if (! srvr->cache_name) \ + return KADM5_BAD_SERVER_HANDLE; \ + if (! srvr->lhandle) \ + return KADM5_BAD_SERVER_HANDLE; \ +} + +#define CHECK_HANDLE(handle) \ + GENERIC_CHECK_HANDLE(handle, KADM5_OLD_LIB_API_VERSION, \ + KADM5_NEW_LIB_API_VERSION) \ + CLIENT_CHECK_HANDLE(handle) + +#endif /* __KADM5_CLIENT_INTERNAL_H__ */ diff --git a/src/lib/kadm5/client_principal.c b/src/lib/kadm5/client_principal.c new file mode 100644 index 000000000..c41922722 --- /dev/null +++ b/src/lib/kadm5/client_principal.c @@ -0,0 +1,307 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include <memory.h> +#include "client_internal.h" + +kadm5_ret_t +kadm5_create_principal(void *server_handle, + kadm5_principal_ent_t princ, long mask, + char *pw) +{ + generic_ret *r; + cprinc_arg arg; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.mask = mask; + arg.passwd = pw; + arg.api_version = handle->api_version; + + if(princ == NULL) + return EINVAL; + memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); + if (handle->api_version == KADM5_API_VERSION_1) { + /* + * hack hack cough cough. + * krb5_unparse name dumps core if we pass it in garbage + * or null. So, since the client is not allowed to set mod_name + * anyway, we just fill it in with a dummy principal. The server of + * course ignores this. + */ + krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); + } else + arg.rec.mod_name = NULL; + + if(!(mask & KADM5_POLICY)) + arg.rec.policy = NULL; + if (! (mask & KADM5_KEY_DATA)) { + arg.rec.n_key_data = 0; + arg.rec.key_data = NULL; + } + if (! (mask & KADM5_TL_DATA)) { + arg.rec.n_tl_data = 0; + arg.rec.tl_data = NULL; + } + + r = create_principal_1(&arg, handle->clnt); + + if (handle->api_version == KADM5_API_VERSION_1) + krb5_free_principal(handle->context, arg.rec.mod_name); + + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_delete_principal(void *server_handle, krb5_principal principal) +{ + dprinc_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if(principal == NULL) + return EINVAL; + arg.princ = principal; + arg.api_version = handle->api_version; + r = delete_principal_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_modify_principal(void *server_handle, + kadm5_principal_ent_t princ, long mask) +{ + mprinc_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.mask = mask; + arg.api_version = handle->api_version; + /* + * cough cough gag gag + * see comment in create_principal. + */ + if(princ == NULL) + return EINVAL; + memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec)); + if(!(mask & KADM5_POLICY)) + arg.rec.policy = NULL; + if (! (mask & KADM5_KEY_DATA)) { + arg.rec.n_key_data = 0; + arg.rec.key_data = NULL; + } + if (! (mask & KADM5_TL_DATA)) { + arg.rec.n_tl_data = 0; + arg.rec.tl_data = NULL; + } + + if (handle->api_version == KADM5_API_VERSION_1) { + /* + * See comment in create_principal + */ + krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); + } else + arg.rec.mod_name = NULL; + + r = modify_principal_1(&arg, handle->clnt); + + if (handle->api_version == KADM5_API_VERSION_1) + krb5_free_principal(handle->context, arg.rec.mod_name); + + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_get_principal(void *server_handle, + krb5_principal princ, kadm5_principal_ent_t ent, + long mask) +{ + gprinc_arg arg; + gprinc_ret *r; + kadm5_server_handle_t handle = server_handle; + krb5_error_code retval; + + CHECK_HANDLE(server_handle); + + if(princ == NULL) + return EINVAL; + arg.princ = princ; + if (handle->api_version == KADM5_API_VERSION_1) + arg.mask = KADM5_PRINCIPAL_NORMAL_MASK; + else + arg.mask = mask; + arg.api_version = handle->api_version; + r = get_principal_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + if (handle->api_version == KADM5_API_VERSION_1) { + kadm5_principal_ent_t_v1 *entp; + + entp = (kadm5_principal_ent_t_v1 *) ent; + if (r->code == 0) { + if (!(*entp = (kadm5_principal_ent_t_v1) + malloc(sizeof(kadm5_principal_ent_rec_v1)))) + return ENOMEM; + /* this memcpy works because the v1 structure is an initial + subset of the v2 struct. C guarantees that this will + result in the same layout in memory */ + memcpy(*entp, &r->rec, sizeof(**entp)); + } else { + *entp = NULL; + } + } else { + if (r->code == 0) + memcpy(ent, &r->rec, sizeof(r->rec)); + } + + return r->code; +} + +kadm5_ret_t +kadm5_get_principals(void *server_handle, + char *exp, char ***princs, int *count) +{ + gprincs_arg arg; + gprincs_ret *r; + kadm5_server_handle_t handle = server_handle; + krb5_error_code retval; + + CHECK_HANDLE(server_handle); + + if(princs == NULL || count == NULL) + return EINVAL; + arg.exp = exp; + arg.api_version = handle->api_version; + r = get_princs_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + if(r->code == 0) { + *count = r->count; + *princs = r->princs; + } else { + *count = 0; + *princs = NULL; + } + + return r->code; +} + +kadm5_ret_t +kadm5_rename_principal(void *server_handle, + krb5_principal source, krb5_principal dest) +{ + rprinc_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.src = source; + arg.dest = dest; + arg.api_version = handle->api_version; + if (source == NULL || dest == NULL) + return EINVAL; + r = rename_principal_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_chpass_principal(void *server_handle, + krb5_principal princ, char *password) +{ + chpass_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.princ = princ; + arg.pass = password; + arg.api_version = handle->api_version; + + if(princ == NULL) + return EINVAL; + r = chpass_principal_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_randkey_principal(void *server_handle, + krb5_principal princ, + krb5_keyblock **key, int *n_keys) +{ + chrand_arg arg; + chrand_ret *r; + krb5_keyblock new; + kadm5_server_handle_t handle = server_handle; + int i, ret; + + CHECK_HANDLE(server_handle); + + arg.princ = princ; + arg.api_version = handle->api_version; + + if(princ == NULL) + return EINVAL; + r = chrand_principal_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + if (handle->api_version == KADM5_API_VERSION_1) { + if (key) + krb5_copy_keyblock(handle->context, &r->key, key); + } else { + if (n_keys) + *n_keys = r->n_keys; + if (key) { + *key = (krb5_keyblock *) malloc(r->n_keys*sizeof(krb5_keyblock)); + if (*key == NULL) + return ENOMEM; + for (i = 0; i < r->n_keys; i++) { + ret = krb5_copy_keyblock_contents(handle->context, + &r->keys[i], + &(*key)[i]); + if (ret) { + free(*key); + return ENOMEM; + } + } + } + } + + return r->code; +} + +/* not supported on client side */ +kadm5_ret_t kadm5_decrypt_key(void *server_handle, + kadm5_principal_ent_t entry, krb5_int32 + ktype, krb5_int32 stype, krb5_int32 + kvno, krb5_keyblock *keyblock, + krb5_keysalt *keysalt, int *kvnop) +{ + return EINVAL; +} diff --git a/src/lib/kadm5/client_rpc.c b/src/lib/kadm5/client_rpc.c new file mode 100644 index 000000000..547844a2c --- /dev/null +++ b/src/lib/kadm5/client_rpc.c @@ -0,0 +1,221 @@ +#include <rpc/rpc.h> +#include <kadm5/kadm_rpc.h> +#include <krb5.h> +#include <kadm5/admin.h> +#include <memory.h> + +/* Default timeout can be changed using clnt_control() */ +static struct timeval TIMEOUT = { 25, 0 }; + +generic_ret * +create_principal_1(argp, clnt) + cprinc_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, CREATE_PRINCIPAL, xdr_cprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +delete_principal_1(argp, clnt) + dprinc_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, DELETE_PRINCIPAL, xdr_dprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +modify_principal_1(argp, clnt) + mprinc_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, MODIFY_PRINCIPAL, xdr_mprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +rename_principal_1(argp, clnt) + rprinc_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, RENAME_PRINCIPAL, xdr_rprinc_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +gprinc_ret * +get_principal_1(argp, clnt) + gprinc_arg *argp; + CLIENT *clnt; +{ + static gprinc_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, GET_PRINCIPAL, xdr_gprinc_arg, argp, xdr_gprinc_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +gprincs_ret * +get_princs_1(argp, clnt) + gprinc_arg *argp; + CLIENT *clnt; +{ + static gprincs_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, GET_PRINCS, xdr_gprincs_arg, argp, + xdr_gprincs_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +chpass_principal_1(argp, clnt) + chpass_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, CHPASS_PRINCIPAL, xdr_chpass_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +chrand_ret * +chrand_principal_1(argp, clnt) + chrand_arg *argp; + CLIENT *clnt; +{ + static chrand_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, CHRAND_PRINCIPAL, xdr_chrand_arg, argp, xdr_chrand_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +create_policy_1(argp, clnt) + cpol_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, CREATE_POLICY, xdr_cpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +delete_policy_1(argp, clnt) + dpol_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, DELETE_POLICY, xdr_dpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +modify_policy_1(argp, clnt) + mpol_arg *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, MODIFY_POLICY, xdr_mpol_arg, argp, xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +gpol_ret * +get_policy_1(argp, clnt) + gpol_arg *argp; + CLIENT *clnt; +{ + static gpol_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, GET_POLICY, xdr_gpol_arg, argp, xdr_gpol_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +gpols_ret * +get_pols_1(argp, clnt) + gprinc_arg *argp; + CLIENT *clnt; +{ + static gpols_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, GET_POLS, xdr_gpols_arg, argp, + xdr_gpols_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +getprivs_ret *get_privs_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static getprivs_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, GET_PRIVS, xdr_u_int32, argp, + xdr_getprivs_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} + +generic_ret * +init_1(argp, clnt) + void *argp; + CLIENT *clnt; +{ + static generic_ret res; + + memset((char *)&res, 0, sizeof(res)); + if (clnt_call(clnt, INIT, xdr_u_int32, argp, + xdr_generic_ret, &res, TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&res); +} diff --git a/src/lib/kadm5/clnt_chpass_util.c b/src/lib/kadm5/clnt_chpass_util.c new file mode 100644 index 000000000..d6c7f0bfb --- /dev/null +++ b/src/lib/kadm5/clnt_chpass_util.c @@ -0,0 +1,15 @@ +#include <kadm5/admin.h> +#include "client_internal.h" + +kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret) +{ + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + return _kadm5_chpass_principal_util(handle, handle->lhandle, princ, + new_pw, ret_pw, msg_ret); +} diff --git a/src/lib/kadm5/clnt_policy.c b/src/lib/kadm5/clnt_policy.c new file mode 100644 index 000000000..f81cf7471 --- /dev/null +++ b/src/lib/kadm5/clnt_policy.c @@ -0,0 +1,151 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include "client_internal.h" +#include <stdlib.h> +#include <string.h> + +kadm5_ret_t +kadm5_create_policy(void *server_handle, + kadm5_policy_ent_t policy, long mask) +{ + cpol_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if(policy == (kadm5_policy_ent_t) NULL) + return EINVAL; + + arg.mask = mask; + arg.api_version = handle->api_version; + memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec)); + r = create_policy_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_delete_policy(void *server_handle, char *name) +{ + dpol_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if(name == NULL) + return EINVAL; + + arg.name = name; + arg.api_version = handle->api_version; + + r = delete_policy_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_modify_policy(void *server_handle, + kadm5_policy_ent_t policy, long mask) + +{ + mpol_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if(policy == (kadm5_policy_ent_t) NULL) + return EINVAL; + + arg.mask = mask; + arg.api_version = handle->api_version; + + memcpy(&arg.rec, policy, sizeof(kadm5_policy_ent_rec)); + r = modify_policy_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + return r->code; +} + +kadm5_ret_t +kadm5_get_policy(void *server_handle, char *name, kadm5_policy_ent_t ent) + +{ + gpol_arg arg; + gpol_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + arg.name = name; + arg.api_version = handle->api_version; + + if(name == NULL) + return EINVAL; + + r = get_policy_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + if (handle->api_version == KADM5_API_VERSION_1) { + kadm5_policy_ent_t *entp; + + entp = (kadm5_policy_ent_t *) ent; + if(r->code == 0) { + if (!(*entp = (kadm5_policy_ent_t) + malloc(sizeof(kadm5_policy_ent_rec)))) + return ENOMEM; + memcpy(*entp, &r->rec, sizeof(**entp)); + } else { + *entp = NULL; + } + } else { + if (r->code == 0) + memcpy(ent, &r->rec, sizeof(r->rec)); + } + + return r->code; +} + +kadm5_ret_t +kadm5_get_policies(void *server_handle, + char *exp, char ***pols, int *count) +{ + gpols_arg arg; + gpols_ret *r; + kadm5_server_handle_t handle = server_handle; + krb5_error_code retval; + + CHECK_HANDLE(server_handle); + + if(pols == NULL || count == NULL) + return EINVAL; + arg.exp = exp; + arg.api_version = handle->api_version; + r = get_pols_1(&arg, handle->clnt); + if(r == NULL) + return KADM5_RPC_ERROR; + if(r->code == 0) { + *count = r->count; + *pols = r->pols; + } else { + *count = 0; + *pols = NULL; + } + + return r->code; +} diff --git a/src/lib/kadm5/clnt_privs.c b/src/lib/kadm5/clnt_privs.c new file mode 100644 index 000000000..93ea199e2 --- /dev/null +++ b/src/lib/kadm5/clnt_privs.c @@ -0,0 +1,66 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.6 1996/07/22 20:35:57 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.5.4.1 1996/07/18 03:08:45 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.5.2.1 1996/06/20 02:16:53 marc + * File added to the repository on a branch + * + * Revision 1.5 1996/05/17 21:36:50 bjaspan + * rename to kadm5, begin implementing version 2 + * + * Revision 1.4 1996/05/16 21:45:51 bjaspan + * u_int32 -> long, add krb5_context + * + * Revision 1.3 1994/09/20 16:25:05 bjaspan + * [secure-admin/2436: API versioning fixes to various admin files] + * [secure-releng/2502: audit secure-admin/2436: random API versioning fixes] + * + * Sandbox: + * + * Unnecessary variable initialization removed. + * + * Revision 1.3 1994/09/12 20:26:39 jik + * Unnecessary variable initialization removed. + * + * Revision 1.2 1994/08/16 18:52:02 jik + * Versioning changes. + * + * Revision 1.1 1993/11/10 23:10:39 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include "client_internal.h" + +kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs) +{ + getprivs_ret *r; + kadm5_server_handle_t handle = server_handle; + + r = get_privs_1(&handle->api_version, handle->clnt); + if (r == NULL) + return KADM5_RPC_ERROR; + else if (r->code == KADM5_OK) + *privs = r->privs; + return r->code; +} diff --git a/src/lib/kadm5/configure.in b/src/lib/kadm5/configure.in new file mode 100644 index 000000000..6466673a8 --- /dev/null +++ b/src/lib/kadm5/configure.in @@ -0,0 +1,49 @@ +AC_INIT(configure.in) +CONFIG_RULES +AC_PROG_ARCHIVE +AC_PROG_ARCHIVE_ADD +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PROG_LEX +AC_PROG_AWK +AC_CHECK_HEADERS(syslog.h) +AC_REPLACE_FUNCS(setenv) +save_LIBS="$LIBS" +LIBS=-lgen +AC_CHECK_FUNCS(compile step) +[if test "$krb5_cv_func_compile" = true ; then + LIBS="$save_LIBS -lgen" +else + LIBS="$save_LIBS" +fi] +AC_CHECK_FUNCS(re_comp re_exec regcomp regexec openlog syslog closelog strftime vsprintf) +V5_SHARED_LIB_OBJS +V5_MAKE_SHARED_LIB(libkadm5srv,1.0,.., ./kadm5,srv) +V5_MAKE_SHARED_LIB(libkadm5clnt,1.0,.., ./kadm5,clnt) +GSSRPC_SH_VERS=$krb5_cv_shlib_version_libgssrpc +AC_SUBST(GSSRPC_SH_VERS) +GSSAPI_KRB5_SH_VERS=$krb5_cv_shlib_version_libgssapi_krb5 +AC_SUBST(GSSAPI_KRB5_SH_VERS) +KDB5_SH_VERS=$krb5_cv_shlib_version_libkdb5 +AC_SUBST(KDB5_SH_VERS) +KRB5_SH_VERS=$krb5_cv_shlib_version_libkrb5 +AC_SUBST(KRB5_SH_VERS) +CRYPTO_SH_VERS=$krb5_cv_shlib_version_libcrypto +AC_SUBST(CRYPTO_SH_VERS) +COMERR_SH_VERS=$krb5_cv_shlib_version_libcom_err +AC_SUBST(COMERR_SH_VERS) +DYN_SH_VERS=$krb5_cv_shlib_version_libdyn +AC_SUBST(DYN_SH_VERS) +CopySrcHeader(adb.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(admin.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(admin_internal.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(admin_xdr.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(client_internal.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(kadm_rpc.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(server_acl.h,[$](BUILDTOP)/include/kadm5) +CopySrcHeader(server_internal.h,[$](BUILDTOP)/include/kadm5) +CopyHeader(adb_err.h,[$](BUILDTOP)/include/kadm5) +CopyHeader(chpass_util_strings.h,[$](BUILDTOP)/include/kadm5) +CopyHeader(kadm_err.h,[$](BUILDTOP)/include/kadm5) +AppendRule([all:: all-$(WHAT)]) +V5_AC_OUTPUT_MAKEFILE diff --git a/src/lib/kadm5/get_admhst.c b/src/lib/kadm5/get_admhst.c new file mode 100644 index 000000000..a398997d6 --- /dev/null +++ b/src/lib/kadm5/get_admhst.c @@ -0,0 +1,89 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1985, 1986, 1987, 1988 by the Massachusetts Institute + * of Technology. + * + * For copying and distribution information, please see the file + * <mit-copyright.h>. + */ + +#ifndef lint +static char *rcsid = +"$Header$"; +#endif /* lint */ + +#include <stdio.h> +#include <krb5/osconf.h> +#include <string.h> + +/* + * Given a Kerberos realm, find a host on which the Kerberos database + * administration server can be found. + * + * krb5_get_admhst takes a pointer to be filled in, a pointer to the name + * of the realm for which a server is desired, and an integer n, and + * returns (in h) the nth administrative host entry from the configuration + * file DEFAULT_CONFIG_FILENAME. + * + * If the realm is NULL, the default realm is used. + * + * On error, get_admhst returns 0. If all goes well, the routine + * returns 1. + * + * This is a temporary hack to allow us to find the nearest system running + * a Kerberos admin server. In the long run, this functionality will be + * provided by a nameserver. + */ +int +krb5_get_admhst(char *h, char *r, int n) +{ + FILE *cnffile; + char *realm = NULL; + char tr[BUFSIZ]; + char linebuf[BUFSIZ]; + char scratch[64]; + register int i; + int ret; + + if(r == NULL) { + if((ret = krb5_get_default_realm(&realm)) != 0) + return ret; + r = realm; + } + if ((cnffile = fopen(DEFAULT_CONFIG_FILENAME, "r")) == NULL) { + return(0); + } + if (fgets(linebuf, BUFSIZ, cnffile) == NULL) { + /* error reading */ + (void) fclose(cnffile); + return(0); + } + if (!strchr(linebuf, '\n')) { + /* didn't all fit into buffer, punt */ + (void) fclose(cnffile); + if(realm) + free(realm); + return(0); + } + for (i = 0; i < n; ) { + /* run through the file, looking for admin host */ + if (fgets(linebuf, BUFSIZ, cnffile) == NULL) { + (void) fclose(cnffile); + if(realm) + free(realm); + return(0); + } + /* need to scan for a token after 'admin' to make sure that + admin matched correctly */ + if (sscanf(linebuf, "%s %s admin %s", tr, h, scratch) != 3) + continue; + if (!strcmp(tr,r)) + i++; + } + (void) fclose(cnffile); + if(realm) + free(realm); + return(1); +} diff --git a/src/lib/kadm5/kadm_err.et b/src/lib/kadm5/kadm_err.et new file mode 100644 index 000000000..446a38de1 --- /dev/null +++ b/src/lib/kadm5/kadm_err.et @@ -0,0 +1,54 @@ +# This is the KADM5 error table. The order of error codes +# defined in this file MUST match that specified in the API +# functionality specification, which is the master version. +# +error_table ovk +# vv 0 +error_code KADM5_FAILURE, "Operation failed for unspecified reason" +error_code KADM5_AUTH_GET, "Operation requires ``get'' privilege" +error_code KADM5_AUTH_ADD, "Operation requires ``add'' privilege" +error_code KADM5_AUTH_MODIFY, "Operation requires ``modify'' privilege" +error_code KADM5_AUTH_DELETE, "Operation requires ``delete'' privilege" +error_code KADM5_AUTH_INSUFFICIENT, "Insufficient authorization for operation" +error_code KADM5_BAD_DB, "Database inconsistency detected" +error_code KADM5_DUP, "Principal or policy already exists" +error_code KADM5_RPC_ERROR, "Communication failure with server" +error_code KADM5_NO_SRV, "No administration server found for realm" +error_code KADM5_BAD_HIST_KEY, "Password history principal key version mismatch" +error_code KADM5_NOT_INIT, "Connection to server not initialized" +error_code KADM5_UNK_PRINC, "Principal does not exist" +error_code KADM5_UNK_POLICY, "Policy does not exist" +error_code KADM5_BAD_MASK, "Invalid field mask for operation" +error_code KADM5_BAD_CLASS, "Invalid number of character classes" +error_code KADM5_BAD_LENGTH, "Invalid password length" +error_code KADM5_BAD_POLICY, "Illegal policy name" +error_code KADM5_BAD_PRINCIPAL, "Illegal principal name" +error_code KADM5_BAD_AUX_ATTR, "Invalid auxillary attributes" +error_code KADM5_BAD_HISTORY, "Invalid password history count" +error_code KADM5_BAD_MIN_PASS_LIFE, "Password minimum life is greater than password maximum life" +error_code KADM5_PASS_Q_TOOSHORT, "Password is too short" +error_code KADM5_PASS_Q_CLASS, "Password does not contain enough character classes" +error_code KADM5_PASS_Q_DICT, "Password is in the password dictionary" +error_code KADM5_PASS_REUSE, "Cannot reuse password" +error_code KADM5_PASS_TOOSOON, "Current password's minimum life has not expired" +error_code KADM5_POLICY_REF, "Policy is in use" +error_code KADM5_INIT, "Connection to server already initialized" +error_code KADM5_BAD_PASSWORD, "Incorrect password" +error_code KADM5_PROTECT_PRINCIPAL, "Cannot change protected principal" +error_code KADM5_BAD_SERVER_HANDLE, "Programmer error! Bad Admin server handle" +error_code KADM5_BAD_STRUCT_VERSION, "Programmer error! Bad API structure version" +error_code KADM5_OLD_STRUCT_VERSION, "API structure version specified by application is no longer supported (to fix, recompile application against current KADM5 API header files and libraries)" +error_code KADM5_NEW_STRUCT_VERSION, "API structure version specified by application is unknown to libraries (to fix, obtain current KADM5 API header files and libraries and recompile application)" +error_code KADM5_BAD_API_VERSION, "Programmer error! Bad API version" +error_code KADM5_OLD_LIB_API_VERSION, "API version specified by application is no longer supported by libraries (to fix, update application to adhere to current API version and recompile)" +error_code KADM5_OLD_SERVER_API_VERSION, "API version specified by application is no longer supported by server (to fix, update application to adhere to current API version and recompile)" +error_code KADM5_NEW_LIB_API_VERSION, "API version specified by application is unknown to libraries (to fix, obtain current KADM5 API header files and libraries and recompile application)" +error_code KADM5_NEW_SERVER_API_VERSION, "API version specified by application is unknown to server (to fix, obtain and install newest KADM5 Admin Server)" +error_code KADM5_SECURE_PRINC_MISSING, "Database error! Required KADM5 principal missing" +error_code KADM5_NO_RENAME_SALT, "The salt type of the specified principal does not support renaming" +error_code KADM5_BAD_CLIENT_PARAMS, "Illegal configuration parameter for remote KADM5 client" +error_code KADM5_BAD_SERVER_PARAMS, "Illegal configuration parameter for local KADM5 client" +error_code KADM5_AUTH_LIST, "Operation requires ``list'' privilege" +error_code KADM5_AUTH_CHANGEPW, "Operation requires ``change-password'' privilege" +error_code KADM5_GSS_ERROR, "GSS-API (or Kerberos) error" +end diff --git a/src/lib/kadm5/kadm_rpc.h b/src/lib/kadm5/kadm_rpc.h new file mode 100644 index 000000000..b0f97e6cb --- /dev/null +++ b/src/lib/kadm5/kadm_rpc.h @@ -0,0 +1,205 @@ +#include <rpc/types.h> + +#include <krb5.h> +#include <kadm5/admin.h> + +struct cprinc_arg { + krb5_ui_4 api_version; + kadm5_principal_ent_rec rec; + long mask; + char *passwd; +}; +typedef struct cprinc_arg cprinc_arg; +bool_t xdr_cprinc_arg(); + +struct generic_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; +}; +typedef struct generic_ret generic_ret; +bool_t xdr_generic_ret(); + +struct dprinc_arg { + krb5_ui_4 api_version; + krb5_principal princ; +}; +typedef struct dprinc_arg dprinc_arg; +bool_t xdr_dprinc_arg(); + +struct mprinc_arg { + krb5_ui_4 api_version; + kadm5_principal_ent_rec rec; + long mask; +}; +typedef struct mprinc_arg mprinc_arg; +bool_t xdr_mprinc_arg(); + +struct rprinc_arg { + krb5_ui_4 api_version; + krb5_principal src; + krb5_principal dest; +}; +typedef struct rprinc_arg rprinc_arg; +bool_t xdr_rprinc_arg(); + +struct gprincs_arg { + krb5_ui_4 api_version; + char *exp; +}; +typedef struct gprincs_arg gprincs_arg; +bool_t xdr_gprincs_arg(); + +struct gprincs_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + char **princs; + int count; +}; +typedef struct gprincs_ret gprincs_ret; +bool_t xdr_gprincs_ret(); + +struct chpass_arg { + krb5_ui_4 api_version; + krb5_principal princ; + char *pass; +}; +typedef struct chpass_arg chpass_arg; +bool_t xdr_chpass_arg(); + +struct chrand_arg { + krb5_ui_4 api_version; + krb5_principal princ; +}; +typedef struct chrand_arg chrand_arg; +bool_t xdr_chrand_arg(); + +struct chrand_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + krb5_keyblock key; + krb5_keyblock *keys; + int n_keys; +}; +typedef struct chrand_ret chrand_ret; +bool_t xdr_chrand_ret(); + +struct gprinc_arg { + krb5_ui_4 api_version; + krb5_principal princ; + long mask; +}; +typedef struct gprinc_arg gprinc_arg; +bool_t xdr_gprinc_arg(); + +struct gprinc_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + kadm5_principal_ent_rec rec; +}; +typedef struct gprinc_ret gprinc_ret; +bool_t xdr_gprinc_ret(); +bool_t xdr_kadm5_ret_t(); +bool_t xdr_kadm5_principal_ent_rec(); +bool_t xdr_kadm5_policy_ent_rec(); +bool_t xdr_krb5_keyblock(); +bool_t xdr_krb5_principal(); +bool_t xdr_krb5_enctype(); +bool_t xdr_krb5_octet(); +bool_t xdr_krb5_int32(); +bool_t xdr_u_int32(); + +struct cpol_arg { + krb5_ui_4 api_version; + kadm5_policy_ent_rec rec; + long mask; +}; +typedef struct cpol_arg cpol_arg; +bool_t xdr_cpol_arg(); + +struct dpol_arg { + krb5_ui_4 api_version; + char *name; +}; +typedef struct dpol_arg dpol_arg; +bool_t xdr_dpol_arg(); + +struct mpol_arg { + krb5_ui_4 api_version; + kadm5_policy_ent_rec rec; + long mask; +}; +typedef struct mpol_arg mpol_arg; +bool_t xdr_mpol_arg(); + +struct gpol_arg { + krb5_ui_4 api_version; + char *name; +}; +typedef struct gpol_arg gpol_arg; +bool_t xdr_gpol_arg(); + +struct gpol_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + kadm5_policy_ent_rec rec; +}; +typedef struct gpol_ret gpol_ret; +bool_t xdr_gpol_ret(); + +struct gpols_arg { + krb5_ui_4 api_version; + char *exp; +}; +typedef struct gpols_arg gpols_arg; +bool_t xdr_gpols_arg(); + +struct gpols_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + char **pols; + int count; +}; +typedef struct gpols_ret gpols_ret; +bool_t xdr_gpols_ret(); + +struct getprivs_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + long privs; +}; +typedef struct getprivs_ret getprivs_ret; +bool_t xdr_getprivs_ret(); + +#define KADM ((krb5_ui_4)2112) +#define KADMVERS ((krb5_ui_4)2) +#define CREATE_PRINCIPAL ((krb5_ui_4)1) +extern generic_ret *create_principal_1(); +#define DELETE_PRINCIPAL ((krb5_ui_4)2) +extern generic_ret *delete_principal_1(); +#define MODIFY_PRINCIPAL ((krb5_ui_4)3) +extern generic_ret *modify_principal_1(); +#define RENAME_PRINCIPAL ((krb5_ui_4)4) +extern generic_ret *rename_principal_1(); +#define GET_PRINCIPAL ((krb5_ui_4)5) +extern gprinc_ret *get_principal_1(); +#define CHPASS_PRINCIPAL ((krb5_ui_4)6) +extern generic_ret *chpass_principal_1(); +#define CHRAND_PRINCIPAL ((krb5_ui_4)7) +extern chrand_ret *chrand_principal_1(); +#define CREATE_POLICY ((krb5_ui_4)8) +extern generic_ret *create_policy_1(); +#define DELETE_POLICY ((krb5_ui_4)9) +extern generic_ret *delete_policy_1(); +#define MODIFY_POLICY ((krb5_ui_4)10) +extern generic_ret *modify_policy_1(); +#define GET_POLICY ((krb5_ui_4)11) +extern gpol_ret *get_policy_1(); +#define GET_PRIVS ((krb5_ui_4)12) +extern getprivs_ret *get_privs_1(); +#define INIT ((krb5_ui_4)13) +extern generic_ret *init_1(); +#define GET_PRINCS ((krb5_ui_4) 14) +extern gprincs_ret *get_princs_1(); +#define GET_POLS ((krb5_ui_4) 15) +extern gpols_ret *get_pols_1(); + diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c new file mode 100644 index 000000000..6cce9391e --- /dev/null +++ b/src/lib/kadm5/kadm_rpc_xdr.c @@ -0,0 +1,830 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <krb5.h> +#include <k5-int.h> +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include <malloc.h> +#include <string.h> + +static bool_t +_xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp, + int v); + +/* + * Function: xdr_ui_4 + * + * Purpose: XDR function which serves as a wrapper for xdr_u_int32, + * to prevent compiler warnings about type clashes between u_int32 + * and krb5_ui_4. + */ +bool_t xdr_ui_4(XDR *xdrs, krb5_ui_4 *objp) +{ + /* Assumes that krb5_ui_4 and u_int32 are both four bytes long. + This should not be a harmful assumption. */ + return xdr_u_int32(xdrs, (rpc_u_int32 *) objp); +} + + +/* + * Function: xdr_nullstring + * + * Purpose: XDR function for "strings" that are either NULL-terminated + * or NULL. + */ +bool_t xdr_nullstring(XDR *xdrs, char **objp) +{ + u_int size; + + if (xdrs->x_op == XDR_ENCODE) { + if (*objp == NULL) + size = 0; + else + size = strlen(*objp) + 1; + } + if (! xdr_u_int(xdrs, &size)) { + return FALSE; + } + switch (xdrs->x_op) { + case XDR_DECODE: + if (size == 0) { + *objp = NULL; + return TRUE; + } else if (*objp == NULL) { + *objp = (char *) mem_alloc(size); + if (*objp == NULL) { + errno = ENOMEM; + return FALSE; + } + } + return (xdr_opaque(xdrs, *objp, size)); + + case XDR_ENCODE: + if (size != 0) + return (xdr_opaque(xdrs, *objp, size)); + return TRUE; + + case XDR_FREE: + if (*objp != NULL) + mem_free(*objp, size); + *objp = NULL; + return TRUE; + } + + return FALSE; +} + +/* + * Function: xdr_nulltype + * + * Purpose: XDR function for arbitrary pointer types that are either + * NULL or contain data. + */ +bool_t xdr_nulltype(XDR *xdrs, void **objp, xdrproc_t proc) +{ + bool_t null; + + switch (xdrs->x_op) { + case XDR_DECODE: + if (!xdr_bool(xdrs, &null)) + return FALSE; + if (null) { + *objp = NULL; + return TRUE; + } + return (*proc)(xdrs, objp); + + case XDR_ENCODE: + if (*objp == NULL) + null = TRUE; + else + null = FALSE; + if (!xdr_bool(xdrs, &null)) + return FALSE; + if (null == FALSE) + return (*proc)(xdrs, objp); + return TRUE; + + case XDR_FREE: + if (*objp) + return (*proc)(xdrs, objp); + return TRUE; + } + + return FALSE; +} + +bool_t +xdr_krb5_timestamp(XDR *xdrs, krb5_timestamp *objp) +{ + /* This assumes that int32 and krb5_timestamp are the same size. + This shouldn't be a problem, since we've got a unit test which + checks for this. */ + if (!xdr_int32(xdrs, (rpc_int32 *) objp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_krb5_kvno(XDR *xdrs, krb5_kvno *objp) +{ + unsigned char tmp; + + if (xdrs->x_op == XDR_ENCODE) + tmp = (unsigned char) *objp; + + if (!xdr_u_char(xdrs, &tmp)) + return (FALSE); + + if (xdrs->x_op == XDR_DECODE) + *objp = (krb5_kvno) tmp; + + return (TRUE); +} + +bool_t +xdr_krb5_deltat(XDR *xdrs, krb5_deltat *objp) +{ + /* This assumes that int32 and krb5_deltat are the same size. + This shouldn't be a problem, since we've got a unit test which + checks for this. */ + if (!xdr_int32(xdrs, (rpc_int32 *) objp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_krb5_flags(XDR *xdrs, krb5_flags *objp) +{ + /* This assumes that int32 and krb5_flags are the same size. + This shouldn't be a problem, since we've got a unit test which + checks for this. */ + if (!xdr_int32(xdrs, (rpc_int32 *) objp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_krb5_ui_4(XDR *xdrs, krb5_ui_4 *objp) +{ + if (!xdr_u_int32(xdrs, (rpc_u_int32 *) objp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_krb5_int16(XDR *xdrs, krb5_int16 *objp) +{ + int tmp; + + tmp = (int) *objp; + + if (!xdr_int(xdrs, &tmp)) + return(FALSE); + + *objp = (krb5_int16) tmp; + + return(TRUE); +} + +bool_t xdr_krb5_key_data_nocontents(XDR *xdrs, krb5_key_data *objp) +{ + /* + * Note that this function intentionally DOES NOT tranfer key + * length or contents! xdr_krb5_key_data in adb_xdr.c does. + */ + + if (xdrs->x_op == XDR_DECODE) + memset((char *) objp, 0, sizeof(krb5_key_data)); + + if (!xdr_krb5_int16(xdrs, &objp->key_data_ver)) { + return (FALSE); + } + if (!xdr_krb5_int16(xdrs, &objp->key_data_kvno)) { + return (FALSE); + } + if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) { + return (FALSE); + } + if (objp->key_data_ver > 1) { + if (!xdr_krb5_int16(xdrs, &objp->key_data_type[0])) { + return (FALSE); + } + } + return (TRUE); +} + +bool_t xdr_krb5_tl_data(XDR *xdrs, krb5_tl_data **tl_data_head) +{ + krb5_tl_data *tl, *tl2; + bool_t more; + int len; + + switch (xdrs->x_op) { + case XDR_FREE: + case XDR_ENCODE: + tl = *tl_data_head; + while (1) { + more = (tl != NULL); + if (!xdr_bool(xdrs, &more)) + return FALSE; + if (tl == NULL) + break; + if (!xdr_krb5_int16(xdrs, &tl->tl_data_type)) + return FALSE; + len = tl->tl_data_length; + if (!xdr_bytes(xdrs, (char **) &tl->tl_data_contents, &len, ~0)) + return FALSE; + tl = tl->tl_data_next; + } + break; + + case XDR_DECODE: + tl = NULL; + while (1) { + if (!xdr_bool(xdrs, &more)) + return FALSE; + if (more == FALSE) + break; + tl2 = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); + if (tl2 == NULL) + return FALSE; + memset((char *) tl2, 0, sizeof(krb5_tl_data)); + if (!xdr_krb5_int16(xdrs, &tl2->tl_data_type)) + return FALSE; + if (!xdr_bytes(xdrs, (char **)&tl2->tl_data_contents, &len, ~0)) + return FALSE; + tl2->tl_data_length = len; + + tl2->tl_data_next = tl; + tl = tl2; + } + + *tl_data_head = tl; + break; + } + + return TRUE; +} + +bool_t +xdr_kadm5_ret_t(XDR *xdrs, kadm5_ret_t *objp) +{ + rpc_u_int32 tmp; + + if (xdrs->x_op == XDR_ENCODE) + tmp = (rpc_u_int32) *objp; + + if (!xdr_u_int32(xdrs, &tmp)) + return (FALSE); + + if (xdrs->x_op == XDR_DECODE) + *objp = (kadm5_ret_t) tmp; + + return (TRUE); +} + +bool_t xdr_kadm5_principal_ent_rec_v1(XDR *xdrs, + kadm5_principal_ent_rec *objp) +{ + return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_1); +} + +bool_t xdr_kadm5_principal_ent_rec(XDR *xdrs, + kadm5_principal_ent_rec *objp) +{ + return _xdr_kadm5_principal_ent_rec(xdrs, objp, KADM5_API_VERSION_2); +} + +static bool_t +_xdr_kadm5_principal_ent_rec(XDR *xdrs, kadm5_principal_ent_rec *objp, + int v) +{ + unsigned int n; + + if (!xdr_krb5_principal(xdrs, &objp->principal)) { + return (FALSE); + } + if (!xdr_krb5_timestamp(xdrs, &objp->princ_expire_time)) { + return (FALSE); + } + if (!xdr_krb5_timestamp(xdrs, &objp->last_pwd_change)) { + return (FALSE); + } + if (!xdr_krb5_timestamp(xdrs, &objp->pw_expiration)) { + return (FALSE); + } + if (!xdr_krb5_deltat(xdrs, &objp->max_life)) { + return (FALSE); + } + if (v == KADM5_API_VERSION_1) { + if (!xdr_krb5_principal(xdrs, &objp->mod_name)) { + return (FALSE); + } + } else { + if (!xdr_nulltype(xdrs, (void **) &objp->mod_name, + xdr_krb5_principal)) { + return (FALSE); + } + } + if (!xdr_krb5_timestamp(xdrs, &objp->mod_date)) { + return (FALSE); + } + if (!xdr_krb5_flags(xdrs, &objp->attributes)) { + return (FALSE); + } + if (!xdr_krb5_kvno(xdrs, &objp->kvno)) { + return (FALSE); + } + if (!xdr_krb5_kvno(xdrs, &objp->mkvno)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->policy)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->aux_attributes)) { + return (FALSE); + } + if (v != KADM5_API_VERSION_1) { + if (!xdr_krb5_deltat(xdrs, &objp->max_renewable_life)) { + return (FALSE); + } + if (!xdr_krb5_timestamp(xdrs, &objp->last_success)) { + return (FALSE); + } + if (!xdr_krb5_timestamp(xdrs, &objp->last_failed)) { + return (FALSE); + } + if (!xdr_krb5_kvno(xdrs, &objp->fail_auth_count)) { + return (FALSE); + } + if (!xdr_krb5_int16(xdrs, &objp->n_key_data)) { + return (FALSE); + } + if (!xdr_krb5_int16(xdrs, &objp->n_tl_data)) { + return (FALSE); + } + if (!xdr_nulltype(xdrs, (void **) &objp->tl_data, + xdr_krb5_tl_data)) { + return FALSE; + } + n = objp->n_key_data; + if (!xdr_array(xdrs, (caddr_t *) &objp->key_data, + &n, ~0, sizeof(krb5_key_data), + xdr_krb5_key_data_nocontents)) { + return (FALSE); + } + } + return (TRUE); +} + +bool_t +xdr_kadm5_policy_ent_rec(XDR *xdrs, kadm5_policy_ent_rec *objp) +{ + if (!xdr_nullstring(xdrs, &objp->policy)) { + return (FALSE); + } + /* these all used to be u_int32, but it's stupid for sized types + to be exposed at the api, and they're the same as longs on the + wire. */ + if (!xdr_long(xdrs, &objp->pw_min_life)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->pw_max_life)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->pw_min_length)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->pw_min_classes)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->pw_history_num)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->policy_refcnt)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_cprinc_arg(XDR *xdrs, cprinc_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (objp->api_version == KADM5_API_VERSION_1) { + if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { + return (FALSE); + } + } else { + if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { + return (FALSE); + } + } + if (!xdr_long(xdrs, &objp->mask)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->passwd)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_generic_ret(XDR *xdrs, generic_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + return(TRUE); +} + +bool_t +xdr_dprinc_arg(XDR *xdrs, dprinc_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mprinc_arg(XDR *xdrs, mprinc_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (objp->api_version == KADM5_API_VERSION_1) { + if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { + return (FALSE); + } + } else { + if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { + return (FALSE); + } + } + if (!xdr_long(xdrs, &objp->mask)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_rprinc_arg(XDR *xdrs, rprinc_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->src)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->dest)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gprincs_arg(XDR *xdrs, gprincs_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->exp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gprincs_ret(XDR *xdrs, gprincs_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if (objp->code == KADM5_OK) { + if (!xdr_int(xdrs, &objp->count)) { + return (FALSE); + } + if (!xdr_array(xdrs, (caddr_t *) &objp->princs, + (unsigned int *) &objp->count, ~0, + sizeof(char *), xdr_nullstring)) { + return (FALSE); + } + } + return (TRUE); +} + +bool_t +xdr_chpass_arg(XDR *xdrs, chpass_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->pass)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_chrand_arg(XDR *xdrs, chrand_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_chrand_ret(XDR *xdrs, chrand_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if (objp->api_version == KADM5_API_VERSION_1) { + if(objp->code == KADM5_OK) { + if (!xdr_krb5_keyblock(xdrs, &objp->key)) { + return (FALSE); + } + } + } else { + if (objp->code == KADM5_OK) { + if (!xdr_array(xdrs, (char **)&objp->keys, &objp->n_keys, ~0, + sizeof(krb5_keyblock), + xdr_krb5_keyblock)) + return FALSE; + } + } + + return (TRUE); +} + +bool_t +xdr_gprinc_arg(XDR *xdrs, gprinc_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + if ((objp->api_version > KADM5_API_VERSION_1) && + !xdr_long(xdrs, &objp->mask)) { + return FALSE; + } + + return (TRUE); +} + +bool_t +xdr_gprinc_ret(XDR *xdrs, gprinc_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if(objp->code == KADM5_OK) { + if (objp->api_version == KADM5_API_VERSION_1) { + if (!xdr_kadm5_principal_ent_rec_v1(xdrs, &objp->rec)) { + return (FALSE); + } + } else { + if (!xdr_kadm5_principal_ent_rec(xdrs, &objp->rec)) { + return (FALSE); + } + } + } + return (TRUE); +} + +bool_t +xdr_cpol_arg(XDR *xdrs, cpol_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->mask)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_dpol_arg(XDR *xdrs, dpol_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->name)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_mpol_arg(XDR *xdrs, mpol_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) { + return (FALSE); + } + if (!xdr_long(xdrs, &objp->mask)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gpol_arg(XDR *xdrs, gpol_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->name)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gpol_ret(XDR *xdrs, gpol_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if(objp->code == KADM5_OK) { + if (!xdr_kadm5_policy_ent_rec(xdrs, &objp->rec)) + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gpols_arg(XDR *xdrs, gpols_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->exp)) { + return (FALSE); + } + return (TRUE); +} + +bool_t +xdr_gpols_ret(XDR *xdrs, gpols_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if (objp->code == KADM5_OK) { + if (!xdr_int(xdrs, &objp->count)) { + return (FALSE); + } + if (!xdr_array(xdrs, (caddr_t *) &objp->pols, + (unsigned int *) &objp->count, ~0, + sizeof(char *), xdr_nullstring)) { + return (FALSE); + } + } + return (TRUE); +} + +bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (! xdr_kadm5_ret_t(xdrs, &objp->code) || + ! xdr_long(xdrs, &objp->privs)) + return FALSE; + return TRUE; +} + +bool_t +xdr_krb5_principal(XDR *xdrs, krb5_principal *objp) +{ + int ret; + char *p = NULL; + krb5_principal pr = NULL; + static krb5_context context = NULL; + + /* using a static context here is ugly, but should work + ok, and the other solutions are even uglier */ + + if (!context && + krb5_init_context(&context)) + return(FALSE); + + switch(xdrs->x_op) { + case XDR_ENCODE: + if((ret = krb5_unparse_name(context, *objp, &p)) != 0) + return FALSE; + if(!xdr_nullstring(xdrs, &p)) + return FALSE; + free(p); + break; + case XDR_DECODE: + if(!xdr_nullstring(xdrs, &p)) + return FALSE; + ret = krb5_parse_name(context, p, &pr); + if(ret != 0) + return FALSE; + *objp = pr; + free(p); + break; + case XDR_FREE: + if(*objp != NULL) + krb5_free_principal(context, *objp); + break; + } + return TRUE; +} + +bool_t +xdr_krb5_octet(XDR *xdrs, krb5_octet *objp) +{ + if (!xdr_u_char(xdrs, objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp) +{ + /* + * This used to be xdr_krb5_keytype, but keytypes and enctypes have + * been merged into only enctypes. However, randkey_principal + * already ensures that only a key of ENCTYPE_DES_CBC_CRC will be + * returned to v1 clients, and ENCTYPE_DES_CBC_CRC has the same + * value as KEYTYPE_DES used too, which is what all v1 clients + * expect. Therefore, IMHO, just encoding whatever enctype we get + * is safe. + */ + + if (!xdr_u_int(xdrs, (unsigned int *) objp)) + return (FALSE); + return (TRUE); +} + +bool_t +xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp) +{ + /* XXX This only works because free_keyblock assumes ->contents + is allocated by malloc() */ + + if(!xdr_krb5_enctype(xdrs, &objp->enctype)) + return FALSE; + if(!xdr_bytes(xdrs, (char **) &objp->contents, (unsigned int *) + &objp->length, ~0)) + return FALSE; + return TRUE; +} + diff --git a/src/lib/kadm5/logger.c b/src/lib/kadm5/logger.c new file mode 100644 index 000000000..924fb9a23 --- /dev/null +++ b/src/lib/kadm5/logger.c @@ -0,0 +1,940 @@ +/* + * lib/kadm/logger.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#if !defined(_MSDOS) + +/* + * logger.c - Handle logging functions for those who want it. + */ +#include "k5-int.h" +#include "adm_proto.h" +#include "com_err.h" +#include <stdio.h> +#ifdef HAVE_SYSLOG_H +#include <syslog.h> +#endif /* HAVE_SYSLOG_H */ +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#else /* HAVE_STDARG_H */ +#include <varargs.h> +#endif /* HAVE_STDARG_H */ + +#define KRB5_KLOG_MAX_ERRMSG_SIZE 1024 +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 256 +#endif /* MAXHOSTNAMELEN */ + +/* This is to assure that we have at least one match in the syslog stuff */ +#ifndef LOG_AUTH +#define LOG_AUTH 0 +#endif /* LOG_AUTH */ +#ifndef LOG_ERR +#define LOG_ERR 0 +#endif /* LOG_ERR */ + +static const char lspec_parse_err_1[] = "%s: cannot parse <%s>\n"; +static const char lspec_parse_err_2[] = "%s: warning - logging entry syntax error\n"; +static const char log_file_err[] = "%s: error writing to %s\n"; +static const char log_device_err[] = "%s: error writing to %s device\n"; +static const char log_ufo_string[] = "???"; +static const char log_emerg_string[] = "EMERGENCY"; +static const char log_alert_string[] = "ALERT"; +static const char log_crit_string[] = "CRITICAL"; +static const char log_err_string[] = "Error"; +static const char log_warning_string[] = "Warning"; +static const char log_notice_string[] = "Notice"; +static const char log_info_string[] = "info"; +static const char log_debug_string[] = "debug"; + +/* + * Output logging. + * + * Output logging is now controlled by the configuration file. We can specify + * the following syntaxes under the [logging]->entity specification. + * FILE<opentype><pathname> + * SYSLOG[=<severity>[:<facility>]] + * STDERR + * CONSOLE + * DEVICE=<device-spec> + * + * Where: + * <opentype> is ":" for open/append, "=" for open/create. + * <pathname> is a valid path name. + * <severity> is one of: (default = ERR) + * EMERG + * ALERT + * CRIT + * ERR + * WARNING + * NOTICE + * INFO + * DEBUG + * <facility> is one of: (default = AUTH) + * KERN + * USER + * MAIL + * DAEMON + * AUTH + * LPR + * NEWS + * UUCP + * CRON + * LOCAL0..LOCAL7 + * <device-spec> is a valid device specification. + */ +struct log_entry { + enum log_type { K_LOG_FILE, + K_LOG_SYSLOG, + K_LOG_STDERR, + K_LOG_CONSOLE, + K_LOG_DEVICE, + K_LOG_NONE } log_type; + krb5_pointer log_2free; + union log_union { + struct log_file { + FILE *lf_filep; + char *lf_fname; + } log_file; + struct log_syslog { + int ls_facility; + int ls_severity; + } log_syslog; + struct log_device { + FILE *ld_filep; + char *ld_devname; + } log_device; + } log_union; +}; +#define lfu_filep log_union.log_file.lf_filep +#define lfu_fname log_union.log_file.lf_fname +#define lsu_facility log_union.log_syslog.ls_facility +#define lsu_severity log_union.log_syslog.ls_severity +#define ldu_filep log_union.log_device.ld_filep +#define ldu_devname log_union.log_device.ld_devname + +struct log_control { + struct log_entry *log_entries; + int log_nentries; + char *log_whoami; + char *log_hostname; + krb5_boolean log_opened; +}; + +static struct log_control log_control = { + (struct log_entry *) NULL, + 0, + (char *) NULL, + (char *) NULL, + 0 +}; +static struct log_entry def_log_entry; + +/* + * These macros define any special processing that needs to happen for + * devices. For unix, of course, this is hardly anything. + */ +#define DEVICE_OPEN(d, m) fopen(d, m) +#define CONSOLE_OPEN(m) fopen("/dev/console", m) +#define DEVICE_PRINT(f, m) ((fprintf(f, m) >= 0) ? \ + (fprintf(f, "\r\n"), fflush(f), 0) : \ + -1) +#define DEVICE_CLOSE(d) fclose(d) + + +/* + * klog_com_err_proc() - Handle com_err(3) messages as specified by the + * profile. + */ +static void +klog_com_err_proc(whoami, code, format, ap) + const char *whoami; + long code; + const char *format; + va_list ap; +{ + char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; + int lindex; + char *actual_format; +#ifdef HAVE_SYSLOG + int log_pri = -1; +#endif /* HAVE_SYSLOG */ + char *cp; + char *syslogp; + + /* Make the header */ + sprintf(outbuf, "%s: ", whoami); + /* + * Squirrel away address after header for syslog since syslog makes + * a header + */ + syslogp = &outbuf[strlen(outbuf)]; + + /* If reporting an error message, separate it. */ + if (code) { + strcat(outbuf, error_message(code)); + strcat(outbuf, " - "); + } + cp = &outbuf[strlen(outbuf)]; + + actual_format = (char *) format; +#ifdef HAVE_SYSLOG + /* + * This is an unpleasant hack. If the first character is less than + * 8, then we assume that it is a priority. + * + * Since it is not guaranteed that there is a direct mapping between + * syslog priorities (e.g. Ultrix and old BSD), we resort to this + * intermediate representation. + */ + if ((((unsigned char) *format) > 0) && (((unsigned char) *format) <= 8)) { + actual_format = (char *) (format + 1); + switch ((unsigned char) *format) { +#ifdef LOG_EMERG + case 1: + log_pri = LOG_EMERG; + break; +#endif /* LOG_EMERG */ +#ifdef LOG_ALERT + case 2: + log_pri = LOG_ALERT; + break; +#endif /* LOG_ALERT */ +#ifdef LOG_CRIT + case 3: + log_pri = LOG_CRIT; + break; +#endif /* LOG_CRIT */ + default: + case 4: + log_pri = LOG_ERR; + break; +#ifdef LOG_WARNING + case 5: + log_pri = LOG_WARNING; + break; +#endif /* LOG_WARNING */ +#ifdef LOG_NOTICE + case 6: + log_pri = LOG_NOTICE; + break; +#endif /* LOG_NOTICE */ +#ifdef LOG_INFO + case 7: + log_pri = LOG_INFO; + break; +#endif /* LOG_INFO */ +#ifdef LOG_DEBUG + case 8: + log_pri = LOG_DEBUG; + break; +#endif /* LOG_DEBUG */ + } + } +#endif /* HAVE_SYSLOG */ + + /* Now format the actual message */ +#if HAVE_VSPRINTF + vsprintf(cp, actual_format, ap); +#else /* HAVE_VSPRINTF */ + sprintf(cp, actual_format, ((int *) ap)[0], ((int *) ap)[1], + ((int *) ap)[2], ((int *) ap)[3], + ((int *) ap)[4], ((int *) ap)[5]); +#endif /* HAVE_VSPRINTF */ + + /* + * Now that we have the message formatted, perform the output to each + * logging specification. + */ + for (lindex = 0; lindex < log_control.log_nentries; lindex++) { + switch (log_control.log_entries[lindex].log_type) { + case K_LOG_FILE: + case K_LOG_STDERR: + /* + * Files/standard error. + */ + if (fprintf(log_control.log_entries[lindex].lfu_filep, + outbuf) < 0) { + /* Attempt to report error */ + fprintf(stderr, log_file_err, whoami, + log_control.log_entries[lindex].lfu_fname); + } + else { + fprintf(log_control.log_entries[lindex].lfu_filep, "\n"); + fflush(log_control.log_entries[lindex].lfu_filep); + } + break; + case K_LOG_CONSOLE: + case K_LOG_DEVICE: + /* + * Devices (may need special handling) + */ + if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, + outbuf) < 0) { + /* Attempt to report error */ + fprintf(stderr, log_device_err, whoami, + log_control.log_entries[lindex].ldu_devname); + } + break; +#ifdef HAVE_SYSLOG + case K_LOG_SYSLOG: + /* + * System log. + */ + /* + * If we have specified a priority through our hackery, then + * use it, otherwise use the default. + */ + if (log_pri >= 0) + log_pri |= log_control.log_entries[lindex].lsu_facility; + else + log_pri = log_control.log_entries[lindex].lsu_facility | + log_control.log_entries[lindex].lsu_severity; + + /* Log the message with our header trimmed off */ + syslog(log_pri, syslogp); + break; +#endif /* HAVE_SYSLOG */ + default: + break; + } + } +} + +/* + * krb5_klog_init() - Initialize logging. + * + * This routine parses the syntax described above to specify destinations for + * com_err(3) or krb5_klog_syslog() messages generated by the caller. + * + * Parameters: + * kcontext - Kerberos context. + * ename - Entity name as it is to appear in the profile. + * whoami - Entity name as it is to appear in error output. + * do_com_err - Take over com_err(3) processing. + * + * Implicit inputs: + * stderr - This is where STDERR output goes. + * + * Implicit outputs: + * log_nentries - Number of log entries, both valid and invalid. + * log_control - List of entries (log_nentries long) which contains + * data for klog_com_err_proc() to use to determine + * where/how to send output. + */ +krb5_error_code +krb5_klog_init(kcontext, ename, whoami, do_com_err) + krb5_context kcontext; + char *ename; + char *whoami; + krb5_boolean do_com_err; +{ + const char *logging_profent[3]; + const char *logging_defent[3]; + char **logging_specs; + int i, ngood; + char *cp, *cp2; + char savec; + int error; + int do_openlog, log_facility; + FILE *f; + + /* Initialize */ + do_openlog = 0; + log_facility = 0; + + /* + * Look up [logging]-><ename> in the profile. If that doesn't + * succeed, then look for [logging]->default. + */ + logging_profent[0] = "logging"; + logging_profent[1] = ename; + logging_profent[2] = (char *) NULL; + logging_defent[0] = "logging"; + logging_defent[1] = "default"; + logging_defent[2] = (char *) NULL; + logging_specs = (char **) NULL; + ngood = 0; + log_control.log_nentries = 0; + if (!profile_get_values(kcontext->profile, + logging_profent, + &logging_specs) || + !profile_get_values(kcontext->profile, + logging_defent, + &logging_specs)) { + /* + * We have a match, so we first count the number of elements + */ + for (log_control.log_nentries = 0; + logging_specs[log_control.log_nentries]; + log_control.log_nentries++); + + /* + * Now allocate our structure. + */ + log_control.log_entries = (struct log_entry *) + malloc(log_control.log_nentries * sizeof(struct log_entry)); + if (log_control.log_entries) { + /* + * Scan through the list. + */ + for (i=0; i<log_control.log_nentries; i++) { + log_control.log_entries[i].log_type = K_LOG_NONE; + log_control.log_entries[i].log_2free = logging_specs[i]; + /* + * The format is: + * <whitespace><data><whitespace> + * so, trim off the leading and trailing whitespace here. + */ + for (cp = logging_specs[i]; isspace(*cp); cp++); + for (cp2 = &logging_specs[i][strlen(logging_specs[i])-1]; + isspace(*cp2); cp2--); + cp2++; + *cp2 = '\0'; + /* + * Is this a file? + */ + if (!strncasecmp(cp, "FILE", 4)) { + /* + * Check for append/overwrite, then open the file. + */ + if (cp[4] == ':' || cp[4] == '=') { + f = fopen(&cp[5], (cp[4] == ':') ? "a+" : "w"); + if (f) { + log_control.log_entries[i].lfu_filep = f; + log_control.log_entries[i].log_type = K_LOG_FILE; + log_control.log_entries[i].lfu_fname = &cp[5]; + } else { + fprintf(stderr,"Couldn't open log file %s: %s\n", + &cp[5], error_message(errno)); + continue; + } + } + } +#ifdef HAVE_SYSLOG + /* + * Is this a syslog? + */ + else if (!strncasecmp(cp, "SYSLOG", 6)) { + error = 0; + log_control.log_entries[i].lsu_facility = LOG_AUTH; + log_control.log_entries[i].lsu_severity = LOG_ERR; + /* + * Is there a severify specified? + */ + if (cp[6] == ':') { + /* + * Find the end of the severity. + */ + if (cp2 = strchr(&cp[7], ':')) { + savec = *cp2; + *cp2 = '\0'; + cp2++; + } + + /* + * Match a severity. + */ + if (!strcasecmp(&cp[7], "ERR")) { + log_control.log_entries[i].lsu_severity = LOG_ERR; + } +#ifdef LOG_EMERG + else if (!strcasecmp(&cp[7], "EMERG")) { + log_control.log_entries[i].lsu_severity = + LOG_EMERG; + } +#endif /* LOG_EMERG */ +#ifdef LOG_ALERT + else if (!strcasecmp(&cp[7], "ALERT")) { + log_control.log_entries[i].lsu_severity = + LOG_ALERT; + } +#endif /* LOG_ALERT */ +#ifdef LOG_CRIT + else if (!strcasecmp(&cp[7], "CRIT")) { + log_control.log_entries[i].lsu_severity = LOG_CRIT; + } +#endif /* LOG_CRIT */ +#ifdef LOG_WARNING + else if (!strcasecmp(&cp[7], "WARNING")) { + log_control.log_entries[i].lsu_severity = + LOG_WARNING; + } +#endif /* LOG_WARNING */ +#ifdef LOG_NOTICE + else if (!strcasecmp(&cp[7], "NOTICE")) { + log_control.log_entries[i].lsu_severity = + LOG_NOTICE; + } +#endif /* LOG_NOTICE */ +#ifdef LOG_INFO + else if (!strcasecmp(&cp[7], "INFO")) { + log_control.log_entries[i].lsu_severity = LOG_INFO; + } +#endif /* LOG_INFO */ +#ifdef LOG_DEBUG + else if (!strcasecmp(&cp[7], "DEBUG")) { + log_control.log_entries[i].lsu_severity = + LOG_DEBUG; + } +#endif /* LOG_DEBUG */ + else + error = 1; + + /* + * If there is a facility present, then parse that. + */ + if (cp2) { + if (!strcasecmp(cp2, "AUTH")) { + log_control.log_entries[i].lsu_facility = LOG_AUTH; + } +#ifdef LOG_KERN + else if (!strcasecmp(cp2, "KERN")) { + log_control.log_entries[i].lsu_facility = LOG_KERN; + } +#endif /* LOG_KERN */ +#ifdef LOG_USER + else if (!strcasecmp(cp2, "USER")) { + log_control.log_entries[i].lsu_facility = LOG_USER; + } +#endif /* LOG_USER */ +#ifdef LOG_MAIL + else if (!strcasecmp(cp2, "MAIL")) { + log_control.log_entries[i].lsu_facility = LOG_MAIL; + } +#endif /* LOG_MAIL */ +#ifdef LOG_DAEMON + else if (!strcasecmp(cp2, "DAEMON")) { + log_control.log_entries[i].lsu_facility = LOG_DAEMON; + } +#endif /* LOG_DAEMON */ +#ifdef LOG_LPR + else if (!strcasecmp(cp2, "LPR")) { + log_control.log_entries[i].lsu_facility = LOG_LPR; + } +#endif /* LOG_LPR */ +#ifdef LOG_NEWS + else if (!strcasecmp(cp2, "NEWS")) { + log_control.log_entries[i].lsu_facility = LOG_NEWS; + } +#endif /* LOG_NEWS */ +#ifdef LOG_UUCP + else if (!strcasecmp(cp2, "UUCP")) { + log_control.log_entries[i].lsu_facility = LOG_UUCP; + } +#endif /* LOG_UUCP */ +#ifdef LOG_CRON + else if (!strcasecmp(cp2, "CRON")) { + log_control.log_entries[i].lsu_facility = LOG_CRON; + } +#endif /* LOG_CRON */ +#ifdef LOG_LOCAL0 + else if (!strcasecmp(cp2, "LOCAL0")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL0; + } +#endif /* LOG_LOCAL0 */ +#ifdef LOG_LOCAL1 + else if (!strcasecmp(cp2, "LOCAL1")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL1; + } +#endif /* LOG_LOCAL1 */ +#ifdef LOG_LOCAL2 + else if (!strcasecmp(cp2, "LOCAL2")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL2; + } +#endif /* LOG_LOCAL2 */ +#ifdef LOG_LOCAL3 + else if (!strcasecmp(cp2, "LOCAL3")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL3; + } +#endif /* LOG_LOCAL3 */ +#ifdef LOG_LOCAL4 + else if (!strcasecmp(cp2, "LOCAL4")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL4; + } +#endif /* LOG_LOCAL4 */ +#ifdef LOG_LOCAL5 + else if (!strcasecmp(cp2, "LOCAL5")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL5; + } +#endif /* LOG_LOCAL5 */ +#ifdef LOG_LOCAL6 + else if (!strcasecmp(cp2, "LOCAL6")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL6; + } +#endif /* LOG_LOCAL6 */ +#ifdef LOG_LOCAL7 + else if (!strcasecmp(cp2, "LOCAL7")) { + log_control.log_entries[i].lsu_facility = LOG_LOCAL7; + } +#endif /* LOG_LOCAL7 */ + cp2--; + *cp2 = savec; + } + } + if (!error) { + log_control.log_entries[i].log_type = K_LOG_SYSLOG; + do_openlog = 1; + log_facility = log_control.log_entries[i].lsu_facility; + } + } +#endif /* HAVE_SYSLOG */ + /* + * Is this a standard error specification? + */ + else if (!strcasecmp(cp, "STDERR")) { + if (log_control.log_entries[i].lfu_filep = + fdopen(fileno(stderr), "a+")) { + log_control.log_entries[i].log_type = K_LOG_STDERR; + log_control.log_entries[i].lfu_fname = + "standard error"; + } + } + /* + * Is this a specification of the console? + */ + else if (!strcasecmp(cp, "CONSOLE")) { + if (log_control.log_entries[i].ldu_filep = + CONSOLE_OPEN("a+")) { + log_control.log_entries[i].log_type = K_LOG_CONSOLE; + log_control.log_entries[i].ldu_devname = "console"; + } + } + /* + * Is this a specification of a device? + */ + else if (!strncasecmp(cp, "DEVICE", 6)) { + /* + * We handle devices very similarly to files. + */ + if (cp[6] == '=') { + if (log_control.log_entries[i].ldu_filep = + DEVICE_OPEN(&cp[7], "w")) { + log_control.log_entries[i].log_type = K_LOG_DEVICE; + log_control.log_entries[i].ldu_devname = &cp[7]; + } + } + } + /* + * See if we successfully parsed this specification. + */ + if (log_control.log_entries[i].log_type == K_LOG_NONE) { + fprintf(stderr, lspec_parse_err_1, whoami, cp); + fprintf(stderr, lspec_parse_err_2, whoami); + } + else + ngood++; + } + } + /* + * If we didn't find anything, then free our lists. + */ + if (ngood == 0) { + for (i=0; i<log_control.log_nentries; i++) + free(logging_specs[i]); + } + free(logging_specs); + } + /* + * If we didn't find anything, go for the default which is to log to + * the system log. + */ + if (ngood == 0) { + if (log_control.log_entries) + free(log_control.log_entries); + log_control.log_entries = &def_log_entry; + log_control.log_entries->log_type = K_LOG_SYSLOG; + log_control.log_entries->log_2free = (krb5_pointer) NULL; + log_control.log_entries->lsu_facility = LOG_AUTH; + log_control.log_entries->lsu_severity = LOG_ERR; + log_control.log_nentries = 1; + } + if (log_control.log_nentries) { + if (log_control.log_whoami = (char *) malloc(strlen(whoami)+1)) + strcpy(log_control.log_whoami, whoami); + if (log_control.log_hostname = (char *) malloc(MAXHOSTNAMELEN)) + gethostname(log_control.log_hostname, MAXHOSTNAMELEN); +#ifdef HAVE_OPENLOG + if (do_openlog) { + openlog(whoami, LOG_NDELAY|LOG_PID, log_facility); + log_control.log_opened = 1; + } +#endif /* HAVE_OPENLOG */ + if (do_com_err) + (void) set_com_err_hook(klog_com_err_proc); + } + return((log_control.log_nentries) ? 0 : ENOENT); +} + +/* + * krb5_klog_close() - Close the logging context and free all data. + */ +void +krb5_klog_close(kcontext) + krb5_context kcontext; +{ + int lindex; + (void) reset_com_err_hook(); + for (lindex = 0; lindex < log_control.log_nentries; lindex++) { + switch (log_control.log_entries[lindex].log_type) { + case K_LOG_FILE: + case K_LOG_STDERR: + /* + * Files/standard error. + */ + fclose(log_control.log_entries[lindex].lfu_filep); + break; + case K_LOG_CONSOLE: + case K_LOG_DEVICE: + /* + * Devices (may need special handling) + */ + DEVICE_CLOSE(log_control.log_entries[lindex].ldu_filep); + break; +#ifdef HAVE_SYSLOG + case K_LOG_SYSLOG: + /* + * System log. + */ + break; +#endif /* HAVE_SYSLOG */ + default: + break; + } + if (log_control.log_entries[lindex].log_2free) + free(log_control.log_entries[lindex].log_2free); + } + if (log_control.log_entries != &def_log_entry) + free(log_control.log_entries); + log_control.log_entries = (struct log_entry *) NULL; + log_control.log_nentries = 0; + if (log_control.log_whoami) + free(log_control.log_whoami); + log_control.log_whoami = (char *) NULL; + if (log_control.log_hostname) + free(log_control.log_hostname); + log_control.log_hostname = (char *) NULL; +#ifdef HAVE_CLOSELOG + if (log_control.log_opened) + closelog(); +#endif /* HAVE_CLOSELOG */ +} + +/* + * severity2string() - Convert a severity to a string. + */ +static char * +severity2string(severity) + int severity; +{ + int s; + const char *ss; + + s = severity & LOG_PRIMASK; + ss = log_ufo_string; + switch (s) { +#ifdef LOG_EMERG + case LOG_EMERG: + ss = log_emerg_string; + break; +#endif /* LOG_EMERG */ +#ifdef LOG_ALERT + case LOG_ALERT: + ss = log_alert_string; + break; +#endif /* LOG_ALERT */ +#ifdef LOG_CRIT + case LOG_CRIT: + ss = log_crit_string; + break; +#endif /* LOG_CRIT */ + case LOG_ERR: + ss = log_err_string; + break; +#ifdef LOG_WARNING + case LOG_WARNING: + ss = log_warning_string; + break; +#endif /* LOG_WARNING */ +#ifdef LOG_NOTICE + case LOG_NOTICE: + ss = log_notice_string; + break; +#endif /* LOG_NOTICE */ +#ifdef LOG_INFO + case LOG_INFO: + ss = log_info_string; + break; +#endif /* LOG_INFO */ +#ifdef LOG_DEBUG + case LOG_DEBUG: + ss = log_debug_string; + break; +#endif /* LOG_DEBUG */ + } + return((char *) ss); +} + +/* + * krb5_klog_syslog() - Simulate the calling sequence of syslog(3), while + * also performing the logging redirection as specified + * by krb5_klog_init(). + */ +static int +klog_vsyslog(priority, format, arglist) + int priority; + const char *format; + va_list arglist; +{ + char outbuf[KRB5_KLOG_MAX_ERRMSG_SIZE]; + int lindex; + char *syslogp; + char *cp; + time_t now; +#ifdef HAVE_STRFTIME + size_t soff; +#endif /* HAVE_STRFTIME */ + + /* + * Format a syslog-esque message of the format: + * + * (verbose form) + * <date> <hostname> <id>[<pid>](<priority>): <message> + * + * (short form) + * <date> <message> + */ + cp = outbuf; + (void) time(&now); +#ifdef HAVE_STRFTIME + /* + * Format the date: mon dd hh:mm:ss + */ + soff = strftime(outbuf, sizeof(outbuf), "%b %d %H:%M:%S", localtime(&now)); + if (soff > 0) + cp += soff; + else + return(-1); +#else /* HAVE_STRFTIME */ + /* + * Format the date: + * We ASSUME here that the output of ctime is of the format: + * dow mon dd hh:mm:ss tzs yyyy\n + * 012345678901234567890123456789 + */ + strncpy(outbuf, ctime(&now) + 4, 15); + cp += 15; +#endif /* HAVE_STRFTIME */ +#ifdef VERBOSE_LOGS + sprintf(cp, " %s %s[%d](%s): ", + log_control.log_hostname, log_control.log_whoami, getpid(), + severity2string(priority)); +#else + sprintf(cp, " "); +#endif + syslogp = &outbuf[strlen(outbuf)]; + + /* Now format the actual message */ +#ifdef HAVE_VSPRINTF + vsprintf(syslogp, format, arglist); +#else /* HAVE_VSPRINTF */ + sprintf(syslogp, format, ((int *) arglist)[0], ((int *) arglist)[1], + ((int *) arglist)[2], ((int *) arglist)[3], + ((int *) arglist)[4], ((int *) arglist)[5]); +#endif /* HAVE_VSPRINTF */ + + /* + * Now that we have the message formatted, perform the output to each + * logging specification. + */ + for (lindex = 0; lindex < log_control.log_nentries; lindex++) { + switch (log_control.log_entries[lindex].log_type) { + case K_LOG_FILE: + case K_LOG_STDERR: + /* + * Files/standard error. + */ + if (fprintf(log_control.log_entries[lindex].lfu_filep, + outbuf) < 0) { + /* Attempt to report error */ + fprintf(stderr, log_file_err, + log_control.log_entries[lindex].lfu_fname); + } + else { + fprintf(log_control.log_entries[lindex].lfu_filep, "\n"); + fflush(log_control.log_entries[lindex].lfu_filep); + } + break; + case K_LOG_CONSOLE: + case K_LOG_DEVICE: + /* + * Devices (may need special handling) + */ + if (DEVICE_PRINT(log_control.log_entries[lindex].ldu_filep, + outbuf) < 0) { + /* Attempt to report error */ + fprintf(stderr, log_device_err, + log_control.log_entries[lindex].ldu_devname); + } + break; +#ifdef HAVE_SYSLOG + case K_LOG_SYSLOG: + /* + * System log. + */ + + /* Log the message with our header trimmed off */ + syslog(priority, syslogp); + break; +#endif /* HAVE_SYSLOG */ + default: + break; + } + } + return(0); +} + +#ifdef HAVE_STDARG_H +int +krb5_klog_syslog(int priority, const char *format, ...) +#else /* HAVE_STDARG_H */ +int +krb5_klog_syslog(priority, format, va_alist) + int priority; + const char *format; + va_dcl +#endif /* HAVE_STDARG_H */ +{ + int retval; + va_list pvar; + +#ifdef HAVE_STDARG_H + va_start(pvar, format); +#else /* HAVE_STDARG_H */ + va_start(pvar); +#endif /* HAVE_STDARG_H */ + retval = klog_vsyslog(priority, format, pvar); + va_end(pvar); + return(retval); +} +#endif /* !defined(_MSDOS) */ diff --git a/src/lib/kadm5/misc_free.c b/src/lib/kadm5/misc_free.c new file mode 100644 index 000000000..cfe28a411 --- /dev/null +++ b/src/lib/kadm5/misc_free.c @@ -0,0 +1,96 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif +#include <kadm5/admin.h> +#include <malloc.h> +#include "server_internal.h" + +kadm5_ret_t +kadm5_free_policy_ent(void *server_handle, kadm5_policy_ent_t val) +{ + kadm5_server_handle_t handle = server_handle; + + _KADM5_CHECK_HANDLE(server_handle); + + if(val) { + if (val->policy) + free(val->policy); + if (handle->api_version == KADM5_API_VERSION_1) + free(val); + } + return KADM5_OK; +} + +kadm5_ret_t + kadm5_free_name_list(void *server_handle, char **names, int count) +{ + _KADM5_CHECK_HANDLE(server_handle); + + while (count--) + free(names[count]); + free(names); +} + + +/* XXX this ought to be in libkrb5.a, but isn't */ +kadm5_ret_t krb5_free_key_data_contents(context, key) + krb5_context context; + krb5_key_data *key; +{ + int i, idx; + + idx = (key->key_data_ver == 1 ? 1 : 2); + for (i = 0; i < idx; i++) { + if (key->key_data_contents[i]) { + memset(key->key_data_contents[i], 0, key->key_data_length[i]); + free(key->key_data_contents[i]); + } + } +} + +kadm5_ret_t +kadm5_free_principal_ent(void *server_handle, + kadm5_principal_ent_t val) +{ + kadm5_server_handle_t handle = server_handle; + int i; + + _KADM5_CHECK_HANDLE(server_handle); + + if(val) { + if(val->principal) + krb5_free_principal(handle->context, val->principal); + if(val->mod_name) + krb5_free_principal(handle->context, val->mod_name); + if(val->policy) + free(val->policy); + if (handle->api_version > KADM5_API_VERSION_1) { + if (val->n_key_data) { + for (i = 0; i < val->n_key_data; i++) + krb5_free_key_data_contents(handle->context, + &val->key_data[i]); + free(val->key_data); + } + if (val->tl_data) { + krb5_tl_data *tl; + + while (val->tl_data) { + tl = val->tl_data->tl_data_next; + free(val->tl_data->tl_data_contents); + free(val->tl_data); + val->tl_data = tl; + } + } + } + + if (handle->api_version == KADM5_API_VERSION_1) + free(val); + } + return KADM5_OK; +} diff --git a/src/lib/kadm5/ovsec_glue.c b/src/lib/kadm5/ovsec_glue.c new file mode 100644 index 000000000..6118282df --- /dev/null +++ b/src/lib/kadm5/ovsec_glue.c @@ -0,0 +1,188 @@ +#define USE_KADM5_API_VERSION 1 +#include <kadm5/admin.h> + +ovsec_kadm_ret_t ovsec_kadm_init_with_password(char *client_name, char *pass, + char *service_name, + char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return kadm5_init_with_password(client_name, pass, service_name, + realm, struct_version, api_version, + server_handle); +} + +ovsec_kadm_ret_t ovsec_kadm_init_with_skey(char *client_name, char *keytab, + char *service_name, + char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return kadm5_init_with_skey(client_name, keytab, service_name, realm, + struct_version, api_version, + server_handle); +} + +ovsec_kadm_ret_t ovsec_kadm_init(char *client_name, char *from_stash, + char *service_name, + char *realm, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return kadm5_init(client_name, from_stash, service_name, + realm, struct_version, api_version, + server_handle); +} + +ovsec_kadm_ret_t ovsec_kadm_destroy(void *server_handle) +{ + return kadm5_destroy(server_handle); +} + +ovsec_kadm_ret_t ovsec_kadm_flush(void *server_handle) +{ + return kadm5_flush(server_handle); +} + +ovsec_kadm_ret_t ovsec_kadm_create_principal(void *server_handle, + ovsec_kadm_principal_ent_t entry, + long mask, + char *password) +{ + return kadm5_create_principal(server_handle, + (kadm5_principal_ent_t) + entry, mask, password); +} + + +ovsec_kadm_ret_t ovsec_kadm_delete_principal(void *server_handle, + krb5_principal principal) +{ + return kadm5_delete_principal(server_handle, principal); +} + + +ovsec_kadm_ret_t ovsec_kadm_modify_principal(void *server_handle, + ovsec_kadm_principal_ent_t entry, + long mask) +{ + return kadm5_modify_principal(server_handle, + (kadm5_principal_ent_t) entry, mask); +} + + +ovsec_kadm_ret_t ovsec_kadm_rename_principal(void *server_handle, + krb5_principal source, + krb5_principal target) +{ + return kadm5_rename_principal(server_handle, source, target); +} + +ovsec_kadm_ret_t ovsec_kadm_get_principal(void *server_handle, + krb5_principal principal, + ovsec_kadm_principal_ent_t *entry) +{ + return kadm5_get_principal(server_handle, principal, + (kadm5_principal_ent_t *) entry); +} + +ovsec_kadm_ret_t ovsec_kadm_chpass_principal(void *server_handle, + krb5_principal principal, + char *password) +{ + return kadm5_chpass_principal(server_handle, principal, password); +} + +ovsec_kadm_ret_t ovsec_kadm_chpass_principal_util(void *server_handle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret) +{ + return kadm5_chpass_principal_util(server_handle, princ, new_pw, + ret_pw, msg_ret); +} + +ovsec_kadm_ret_t ovsec_kadm_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_keyblock **key) +{ + return kadm5_randkey_principal(server_handle, principal, key); +} + +ovsec_kadm_ret_t ovsec_kadm_create_policy(void *server_handle, + ovsec_kadm_policy_ent_t entry, + long mask) +{ + return kadm5_create_policy(server_handle, + (kadm5_policy_ent_t) entry, mask); +} + +ovsec_kadm_ret_t ovsec_kadm_delete_policy(void *server_handle, + ovsec_kadm_policy_t name) +{ + return kadm5_delete_policy(server_handle, (kadm5_policy_t) name); +} + +ovsec_kadm_ret_t ovsec_kadm_modify_policy(void *server_handle, + ovsec_kadm_policy_ent_t entry, + long mask) +{ + return kadm5_modify_policy(server_handle, + (kadm5_policy_ent_t) entry, mask); +} + + +ovsec_kadm_ret_t ovsec_kadm_get_policy(void *server_handle, + ovsec_kadm_policy_t name, + ovsec_kadm_policy_ent_t *entry) +{ + return kadm5_get_policy(server_handle, (kadm5_policy_t) name, + (kadm5_policy_ent_t *) entry); +} + + +ovsec_kadm_ret_t ovsec_kadm_free_policy_ent(void *server_handle, + ovsec_kadm_policy_ent_t val) +{ + return kadm5_free_policy_ent(server_handle, (kadm5_policy_ent_t) val); +} + +ovsec_kadm_ret_t ovsec_kadm_free_name_list(void *server_handle, + char **names, int count) +{ + return kadm5_free_name_list(server_handle, names, count); +} + +ovsec_kadm_ret_t +ovsec_kadm_free_principal_ent(void *server_handle, + ovsec_kadm_principal_ent_t val) +{ + return kadm5_free_principal_ent(server_handle, + (kadm5_principal_ent_t) val); +} + +ovsec_kadm_ret_t ovsec_kadm_get_privs(void *server_handle, long *privs) +{ + return kadm5_get_privs(server_handle, privs); +} + +ovsec_kadm_ret_t ovsec_kadm_get_principals(void *server_handle, + char *exp, + char ***princs, + int *count) +{ + return kadm5_get_principals(server_handle, exp, princs, count); +} + +ovsec_kadm_ret_t ovsec_kadm_get_policies(void *server_handle, + char *exp, + char ***pols, + int *count) +{ + return kadm5_get_policies(server_handle, exp, pols, count); +} + diff --git a/src/lib/kadm5/server_acl.c b/src/lib/kadm5/server_acl.c new file mode 100644 index 000000000..16a7f4e40 --- /dev/null +++ b/src/lib/kadm5/server_acl.c @@ -0,0 +1,511 @@ +/* + * kadmin/v5server/srv_acl.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * srv_acl.c - Handle Kerberos ACL related functions. + */ +#include <stdio.h> +#include <sys/param.h> +#include <gssapi/gssapi_generic.h> +#include "k5-int.h" +#include "server_acl.h" +#include <kadm5/server_internal.h> + +typedef struct _acl_op_table { + char ao_op; + krb5_int32 ao_mask; +} aop_t; + +typedef struct _acl_entry { + struct _acl_entry *ae_next; + char *ae_name; + krb5_boolean ae_name_bad; + krb5_principal ae_principal; + krb5_int32 ae_op_allowed; + char *ae_target; + krb5_boolean ae_target_bad; + krb5_principal ae_target_princ; +} aent_t; + +static const aop_t acl_op_table[] = { + { 'a', ACL_ADD }, + { 'd', ACL_DELETE }, + { 'm', ACL_MODIFY }, + { 'c', ACL_CHANGEPW }, + { 'i', ACL_INQUIRE }, + { 'l', ACL_LIST }, + { 'x', ACL_ALL_MASK }, + { '*', ACL_ALL_MASK }, + { '\0', 0 } +}; + +static aent_t *acl_list_head = (aent_t *) NULL; +static aent_t *acl_list_tail = (aent_t *) NULL; + +static const char *acl_acl_file = (char *) NULL; +static int acl_inited = 0; +static int acl_debug_level = 0; +/* + * This is the catchall entry. If nothing else appropriate is found, or in + * the case where the ACL file is not present, this entry controls what can + * be done. + */ +static const char *acl_catchall_entry = NULL; + +static const char *acl_line2long_msg = "%s: line %d too long, truncated\n"; +static const char *acl_op_bad_msg = "Unrecognized ACL operation '%c' in %s\n"; +static const char *acl_syn_err_msg = "%s: syntax error at line %d <%10s...>\n"; +static const char *acl_cantopen_msg = "\007cannot open ACL file"; + +/* + * acl_get_line() - Get a line from the ACL file. + */ +static char * +acl_get_line(fp, lnp) + FILE *fp; + int *lnp; +{ + int i, domore; + static char acl_buf[BUFSIZ]; + + for (domore = 1; domore && !feof(fp); ) { + /* Copy in the line */ + for (i=0; + ((i<BUFSIZ) && + (!feof(fp)) && + ((acl_buf[i] = fgetc(fp)) != '\n')); + i++); + + /* Check if we exceeded our buffer size */ + if ((i == BUFSIZ) && (!feof(fp)) && (acl_buf[i] != '\n')) { + fprintf(stderr, acl_line2long_msg, acl_acl_file, *lnp); + while (fgetc(fp) != '\n'); + } + acl_buf[i] = '\0'; + if (acl_buf[0] == (char) EOF) /* ptooey */ + acl_buf[0] = '\0'; + else + (*lnp)++; + if ((acl_buf[0] != '#') && (acl_buf[0] != '\0')) + domore = 0; + } + if (domore || (strlen(acl_buf) == 0)) + return((char *) NULL); + else + return(acl_buf); +} + +/* + * acl_parse_line() - Parse the contents of an ACL line. + */ +static aent_t * +acl_parse_line(lp) + char *lp; +{ + static char acle_principal[BUFSIZ]; + static char acle_ops[BUFSIZ]; + static char acle_object[BUFSIZ]; + aent_t *acle; + char *op; + int t, found, opok, nmatch; + + DPRINT(DEBUG_CALLS, acl_debug_level, + ("* acl_parse_line(line=%20s)\n", lp)); + /* + * Format is very simple: + * entry ::= <whitespace> <principal> <whitespace> <opstring> <whitespace> + * [<target> <whitespace>] + */ + acle = (aent_t *) NULL; + acle_object[0] = '\0'; + nmatch = sscanf(lp, "%s %s %s", acle_principal, acle_ops, acle_object); + if (nmatch >= 2) { + acle = (aent_t *) malloc(sizeof(aent_t)); + if (acle) { + acle->ae_next = (aent_t *) NULL; + acle->ae_op_allowed = (krb5_int32) 0; + acle->ae_target = + (nmatch >= 3) ? strdup(acle_object) : (char *) NULL; + acle->ae_target_bad = 0; + acle->ae_target_princ = (krb5_principal) NULL; + opok = 1; + for (op=acle_ops; *op; op++) { + char rop; + + rop = (isupper(*op)) ? tolower(*op) : *op; + found = 0; + for (t=0; acl_op_table[t].ao_op; t++) { + if (rop == acl_op_table[t].ao_op) { + found = 1; + if (rop == *op) + acle->ae_op_allowed |= acl_op_table[t].ao_mask; + else + acle->ae_op_allowed &= ~acl_op_table[t].ao_mask; + } + } + if (!found) { + fprintf(stderr, acl_op_bad_msg, *op, lp); + opok = 0; + } + } + if (opok) { + acle->ae_name = (char *) malloc(strlen(acle_principal)+1); + if (acle->ae_name) { + strcpy(acle->ae_name, acle_principal); + acle->ae_principal = (krb5_principal) NULL; + acle->ae_name_bad = 0; + DPRINT(DEBUG_ACL, acl_debug_level, + ("A ACL entry %s -> opmask %x\n", + acle->ae_name, acle->ae_op_allowed)); + } + else { + if (acle->ae_target) + free(acle->ae_target); + free(acle); + acle = (aent_t *) NULL; + } + } + else { + if (acle->ae_target) + free(acle->ae_target); + free(acle); + acle = (aent_t *) NULL; + } + } + } + DPRINT(DEBUG_CALLS, acl_debug_level, + ("X acl_parse_line() = %x\n", (long) acle)); + return(acle); +} + +/* + * acl_free_entries() - Free all ACL entries. + */ +static void +acl_free_entries() +{ + aent_t *ap; + aent_t *np; + + DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_free_entries()\n")); + for (ap=acl_list_head; ap; ap = np) { + if (ap->ae_name) + free(ap->ae_name); + if (ap->ae_principal) + krb5_free_principal((krb5_context) NULL, ap->ae_principal); + if (ap->ae_target) + free(ap->ae_target); + if (ap->ae_target_princ) + krb5_free_principal((krb5_context) NULL, ap->ae_target_princ); + np = ap->ae_next; + free(ap); + } + acl_list_head = acl_list_tail = (aent_t *) NULL; + acl_inited = 0; + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_free_entries()\n")); +} + +/* + * acl_load_acl_file() - Open and parse the ACL file. + */ +static int +acl_load_acl_file() +{ +char tmpbuf[10]; + FILE *afp; + char *alinep; + aent_t **aentpp; + int alineno; + int retval = 1; + + DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_load_acl_file()\n")); + /* Open the ACL file for read */ + if (afp = fopen(acl_acl_file, "r")) { + alineno = 1; + aentpp = &acl_list_head; + + /* Get a non-comment line */ + while (alinep = acl_get_line(afp, &alineno)) { + /* Parse it */ + *aentpp = acl_parse_line(alinep); + /* If syntax error, then fall out */ + if (!*aentpp) { + fprintf(stderr, acl_syn_err_msg, + acl_acl_file, alineno, alinep); + retval = 0; + break; + } + acl_list_tail = *aentpp; + aentpp = &(*aentpp)->ae_next; + } + + if (acl_catchall_entry) { + strcpy(tmpbuf, acl_catchall_entry); + if (*aentpp = acl_parse_line(tmpbuf)) { + acl_list_tail = *aentpp; + } + else { + retval = 0; + DPRINT(DEBUG_OPERATION, acl_debug_level, + ("> catchall acl entry (%s) load failed\n", + acl_catchall_entry)); + } + fclose(afp); + } + } + else { + com_err(acl_acl_file, errno, acl_cantopen_msg); + if (acl_list_head = acl_parse_line(acl_catchall_entry)) { + acl_list_tail = acl_list_head; + } + else { + retval = 0; + DPRINT(DEBUG_OPERATION, acl_debug_level, + ("> catchall acl entry (%s) load failed\n", + acl_catchall_entry)); + } + } + + if (!retval) { + acl_free_entries(); + } + DPRINT(DEBUG_CALLS, acl_debug_level, + ("X acl_load_acl_file() = %d\n", retval)); + return(retval); +} + +/* + * acl_match_data() - See if two data entries match. + * + * Wildcarding is only supported for a whole component. + */ +static krb5_boolean +acl_match_data(e1, e2) + krb5_data *e1, *e2; +{ + krb5_boolean retval; + + DPRINT(DEBUG_CALLS, acl_debug_level, + ("* acl_match_entry(%s, %s)\n", e1->data, e2->data)); + retval = 0; + if (!strncmp(e1->data, "*", e1->length) || + !strncmp(e2->data, "*", e2->length)) { + retval = 1; + } + else { + if ((e1->length == e2->length) && + (!strncmp(e1->data, e2->data, e1->length))) + retval = 1; + } + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval)); + return(retval); +} + +/* + * acl_find_entry() - Find a matching entry. + */ +static aent_t * +acl_find_entry(kcontext, principal, dest_princ) + krb5_context kcontext; + krb5_principal principal; + krb5_principal dest_princ; +{ + aent_t *entry; + krb5_error_code kret; + int i; + int matchgood; + + DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_find_entry()\n")); + for (entry=acl_list_head; entry; entry = entry->ae_next) { + if (!strcmp(entry->ae_name, "*")) { + DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n")); + break; + } + if (!entry->ae_principal && !entry->ae_name_bad) { + kret = krb5_parse_name(kcontext, + entry->ae_name, + &entry->ae_principal); + if (kret) + entry->ae_name_bad = 1; + } + if (entry->ae_name_bad) { + DPRINT(DEBUG_ACL, acl_debug_level, + ("A Bad ACL entry %s\n", entry->ae_name)); + continue; + } + if (entry->ae_target && + !entry->ae_target_princ && + !entry->ae_target_bad) { + kret = krb5_parse_name(kcontext, + entry->ae_target, + &entry->ae_target_princ); + if (kret) + entry->ae_target_bad = 1; + } + if (entry->ae_target_bad) { + DPRINT(DEBUG_ACL, acl_debug_level, + ("A Bad target in an ACL entry for %s\n", entry->ae_name)); + entry->ae_name_bad = 1; + continue; + } + matchgood = 0; + if (acl_match_data(&entry->ae_principal->realm, + &principal->realm) && + (entry->ae_principal->length == principal->length)) { + matchgood = 1; + for (i=0; i<principal->length; i++) { + if (!acl_match_data(&entry->ae_principal->data[i], + &principal->data[i])) { + matchgood = 0; + break; + } + } + } + if (!matchgood) + continue; + + /* We've matched the principal. If we have a target, then try it */ + if (entry->ae_target && entry->ae_target_princ && dest_princ) { + if (acl_match_data(&entry->ae_target_princ->realm, + &dest_princ->realm) && + (entry->ae_target_princ->length == dest_princ->length)) { + for (i=0; i<dest_princ->length; i++) { + if (!acl_match_data(&entry->ae_target_princ->data[i], + &dest_princ->data[i])) { + matchgood = 0; + break; + } + } + } + else + matchgood = 0; + } + + if (matchgood) + break; + } + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_find_entry()=%x\n",entry)); + return(entry); +} + +/* + * acl_init() - Initialize ACL context. + */ +krb5_error_code +acl_init(kcontext, debug_level, acl_file) + krb5_context kcontext; + int debug_level; + char *acl_file; +{ + krb5_error_code kret; + + kret = 0; + acl_debug_level = debug_level; + DPRINT(DEBUG_CALLS, acl_debug_level, + ("* acl_init(afile=%s)\n", + ((acl_file) ? acl_file : "(null)"))); + acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL; + acl_inited = acl_load_acl_file(); + + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_init() = %d\n", kret)); + return(kret); +} + +/* + * acl_finish - Terminate ACL context. + */ +void +acl_finish(kcontext, debug_level) + krb5_context kcontext; + int debug_level; +{ + DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_finish()\n")); + acl_free_entries(); + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_finish()\n")); +} + +/* + * acl_op_permitted() - Is this operation permitted for this principal? + * this code used not to be based on gssapi. In order + * to minimize porting hassles, I've put all the + * gssapi hair in this function. This might not be + * the best medium-term solution. (The best long-term + * solution is, of course, a real authorization service.) + */ +krb5_boolean +acl_check(kcontext, caller, opmask, principal) + krb5_context kcontext; + gss_name_t caller; + krb5_int32 opmask; + krb5_principal principal; +{ + krb5_boolean retval; + aent_t *aentry; + gss_buffer_desc caller_buf; + gss_OID caller_oid; + OM_uint32 emaj, emin; + krb5_error_code code; + krb5_principal caller_princ; + + DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n")); + + if (GSS_ERROR(emaj = gss_display_name(&emin, caller, &caller_buf, + &caller_oid))) + return(0); + + code = krb5_parse_name(kcontext, (char *) caller_buf.value, + &caller_princ); + + gss_release_buffer(&emin, &caller_buf); + + if (code) + return(code); + + retval = 0; + if (aentry = acl_find_entry(kcontext, caller_princ, principal)) { + if ((aentry->ae_op_allowed & opmask) == opmask) + retval = 1; + } + + krb5_free_principal(kcontext, caller_princ); + + DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n", + retval)); + return(retval); +} + +kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs) +{ + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + /* this is impossible to do with the current interface. For now, + return all privs, which will confuse some clients, but not + deny any access to users of "smart" clients which try to cache */ + + *privs = ~0; + + return KADM5_OK; +} diff --git a/src/lib/kadm5/server_acl.h b/src/lib/kadm5/server_acl.h new file mode 100644 index 000000000..9dfc8daba --- /dev/null +++ b/src/lib/kadm5/server_acl.h @@ -0,0 +1,81 @@ +/* + * kadmin/v5server/kadm5_defs.h + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +#ifndef SERVER_ACL_H__ +#define SERVER_ACL_H__ + +/* + * Debug definitions. + */ +#define DEBUG_SPROC 1 +#define DEBUG_OPERATION 2 +#define DEBUG_HOST 4 +#define DEBUG_REALM 8 +#define DEBUG_REQUESTS 16 +#define DEBUG_ACL 32 +#define DEBUG_PROTO 64 +#define DEBUG_CALLS 128 +#define DEBUG_NOSLAVES 256 +#ifdef DEBUG +#define DPRINT(l1, cl, al) if ((cl & l1) != 0) xprintf al +#else /* DEBUG */ +#define DPRINT(l1, cl, al) +#endif /* DEBUG */ +#define DLOG(l1, cl, msg) if ((cl & l1) != 0) \ + com_err(programname, 0, msg) + +/* + * Access control bits. + */ +#define ACL_ADD 1 +#define ACL_DELETE 2 +#define ACL_MODIFY 4 +#define ACL_CHANGEPW 8 +/* #define ACL_CHANGE_OWN_PW 16 */ +#define ACL_INQUIRE 32 +/* #define ACL_EXTRACT 64 */ +#define ACL_LIST 128 +#define ACL_RENAME (ACL_ADD+ACL_DELETE) + +#define ACL_ALL_MASK (ACL_ADD | \ + ACL_DELETE | \ + ACL_MODIFY | \ + ACL_CHANGEPW | \ + ACL_INQUIRE | \ + ACL_LIST) + +krb5_error_code acl_init + KRB5_PROTOTYPE((krb5_context, + int, + char *)); +void acl_finish + KRB5_PROTOTYPE((krb5_context, + int)); +krb5_boolean acl_check + KRB5_PROTOTYPE((krb5_context, + gss_name_t, + krb5_int32, + krb5_principal)); + +#endif /* SERVER_ACL_H__ */ diff --git a/src/lib/kadm5/server_dict.c b/src/lib/kadm5/server_dict.c new file mode 100644 index 000000000..6c0bcef03 --- /dev/null +++ b/src/lib/kadm5/server_dict.c @@ -0,0 +1,199 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/types.h> +#include <sys/file.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> +#include <kadm5/admin.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include <memory.h> +#include <syslog.h> +#include "server_internal.h" + +static char **word_list = NULL; /* list of word pointers */ +static char *word_block = NULL; /* actual word data */ +static int word_count = 0; /* number of words */ +extern int errno; + +/* + * Function: word_compare + * + * Purpose: compare two words in the dictionary. + * + * Arguments: + * w1 (input) pointer to first word + * w2 (input) pointer to second word + * <return value> result of strcmp + * + * Requires: + * w1 and w2 to point to valid memory + * + */ + +static int +word_compare(const void *s1, const void *s2) +{ + return (strcasecmp(*(char **)s1, *(char **)s2)); +} + +/* + * Function: init-dict + * + * Purpose: Initialize in memory word dictionary + * + * Arguments: + * none + * <return value> KADM5_OK on sucsess errno on failure; + * (but success on ENOENT) + * + * Requires: + * If WORDFILE exists, it must contain a list of words, + * one word per-line. + * + * Effects: + * If WORDFILE exists, it is read into memory sorted for future + * use. If it does not exist, it syslogs an error message and returns + * success. + * + * Modifies: + * word_list to point to a chunck of allocated memory containing + * pointers to words + * word_block to contain the dictionary. + * + */ + +int init_dict(kadm5_config_params *params) +{ + int fd, + len, + i; + char *p, + *t; + struct stat sb; + + if(word_list != NULL && word_block != NULL) + return KADM5_OK; + if (! (params->mask & KADM5_CONFIG_DICT_FILE)) { + syslog(LOG_INFO, "No dictionary file specified, continuing " + "without one."); + return KADM5_OK; + } + if ((fd = open(params->dict_file, O_RDONLY)) == -1) { + if (errno == ENOENT) { + syslog(LOG_ERR, "WARNING! Cannot find dictionary file %s, " + "continuing without one.", params->dict_file); + return KADM5_OK; + } else + return errno; + } + if (fstat(fd, &sb) == -1) + return errno; + if ((word_block = (char *) malloc(sb.st_size + 1)) == NULL) + return errno; + if (read(fd, word_block, sb.st_size) != sb.st_size) + return errno; + (void) close(fd); + word_block[sb.st_size] = '\0'; + + p = word_block; + len = sb.st_size; + while(len > 0 && (t = memchr(p, '\n', len)) != NULL) { + *t = '\0'; + len -= t - p + 1; + p = t + 1; + word_count++; + } + if ((word_list = (char **) malloc(word_count * sizeof(char *))) == NULL) + return errno; + p = word_block; + for (i = 0; i < word_count; i++) { + word_list[i] = p; + p += strlen(p) + 1; + } + qsort(word_list, word_count, sizeof(char *), word_compare); + return KADM5_OK; +} + +/* + * Function: find_word + * + * Purpose: See if the specified word exists in the in-core dictionary + * + * Arguments: + * word (input) word to search for. + * <return value> WORD_NOT_FOUND if not in dictionary, + * KADM5_OK if if found word + * errno if init needs to be called and returns an + * error + * + * Requires: + * word to be a null terminated string. + * That word_list and word_block besetup + * + * Effects: + * finds word in dictionary. + * Modifies: + * nothing. + * + */ + +int +find_word(const char *word) +{ + char **value; + + if(word_list == NULL || word_block == NULL) + return WORD_NOT_FOUND; + if ((value = (char **) bsearch(&word, word_list, word_count, sizeof(char *), + word_compare)) == NULL) + return WORD_NOT_FOUND; + else + return KADM5_OK; +} + +/* + * Function: destroy_dict + * + * Purpose: destroy in-core copy of dictionary. + * + * Arguments: + * none + * <return value> none + * Requires: + * nothing + * Effects: + * frees up memory occupied by word_list and word_block + * sets count back to 0, and resets the pointers to NULL + * + * Modifies: + * word_list, word_block, and word_count. + * + */ + +void +destroy_dict(void) +{ + if(word_list) { + free(word_list); + word_list = NULL; + } + if(word_block) { + free(word_block); + word_block = NULL; + } + if(word_count) + word_count = 0; + return; +} diff --git a/src/lib/kadm5/server_handle.c b/src/lib/kadm5/server_handle.c new file mode 100644 index 000000000..53abe94dd --- /dev/null +++ b/src/lib/kadm5/server_handle.c @@ -0,0 +1,9 @@ +#include <krb5.h> +#include <kadm5/admin.h> +#include "server_internal.h" + +int _kadm5_check_handle(void *handle) +{ + CHECK_HANDLE(handle); + return 0; +} diff --git a/src/lib/kadm5/server_init.c b/src/lib/kadm5/server_init.c new file mode 100644 index 000000000..653f6d896 --- /dev/null +++ b/src/lib/kadm5/server_init.c @@ -0,0 +1,330 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <com_err.h> +#include <kadm5/admin.h> +#include <krb5.h> +#include "server_internal.h" + +/* + * 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; +} + +kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + return kadm5_init(client_name, pass, service_name, params, + struct_version, api_version, + server_handle); +} + +kadm5_ret_t kadm5_init_with_creds(char *client_name, + krb5_ccache ccache, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + /* + * A program calling init_with_creds *never* expects to prompt the + * user. Therefore, always pass a dummy password in case this is + * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and + * MKEY_FROM_KBD is non-zero, return an error. + */ + if (api_version == KADM5_API_VERSION_2 && params && + (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) && + params->mkey_from_kbd) + return KADM5_BAD_SERVER_PARAMS; + return kadm5_init(client_name, NULL, service_name, params, + struct_version, api_version, + server_handle); +} + + +kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab, + char *service_name, + kadm5_config_params *params, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + /* + * A program calling init_with_skey *never* expects to prompt the + * user. Therefore, always pass a dummy password in case this is + * KADM5_API_VERSION_1. If this is KADM5_API_VERSION_2 and + * MKEY_FROM_KBD is non-zero, return an error. + */ + if (api_version == KADM5_API_VERSION_2 && params && + (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) && + params->mkey_from_kbd) + return KADM5_BAD_SERVER_PARAMS; + return kadm5_init(client_name, NULL, service_name, params, + struct_version, api_version, + server_handle); +} + +kadm5_ret_t kadm5_init(char *client_name, char *pass, + char *service_name, + kadm5_config_params *params_in, + krb5_ui_4 struct_version, + krb5_ui_4 api_version, + void **server_handle) +{ + int ret; + kadm5_server_handle_t handle; + kadm5_config_params params_local; /* for v1 compat */ + + if (! server_handle) + return EINVAL; + + if (! client_name) + return EINVAL; + + if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle))) + return ENOMEM; + memset(handle, 0, sizeof(*handle)); + + if (ret = (int) krb5_init_context(&(handle->context))) { + free(handle); + return(ret); + } + + initialize_ovk_error_table(); + initialize_adb_error_table(); + initialize_ovku_error_table(); + krb5_init_ets(handle->context); + + handle->magic_number = KADM5_SERVER_HANDLE_MAGIC; + handle->struct_version = struct_version; + handle->api_version = api_version; + + /* + * Verify the version numbers before proceeding; we can't use + * CHECK_HANDLE because not all fields are set yet. + */ + GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION, + KADM5_NEW_SERVER_API_VERSION); + + /* + * Acquire relevant profile entries. In version 2, merge values + * in params_in with values from profile, based on + * params_in->mask. + * + * In version 1, we've given a realm (which may be NULL) instead + * of params_in. So use that realm, make params_in contain an + * empty mask, and behave like version 2. + */ + memset((char *) ¶ms_local, 0, sizeof(params_local)); + if (api_version == KADM5_API_VERSION_1) { + params_local.realm = (char *) params_in; + if (params_in) + params_local.mask = KADM5_CONFIG_REALM; + params_in = ¶ms_local; + } + +#define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER) + if (params_in && (params_in->mask & ILLEGAL_PARAMS)) { + krb5_free_context(handle->context); + free(handle); + return KADM5_BAD_SERVER_PARAMS; + } + + if (ret = kadm5_get_config_params(handle->context, + (char *) NULL, + (char *) NULL, + params_in, + &handle->params)) { + krb5_free_context(handle->context); + free(handle); + return(ret); + } + +#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \ + KADM5_CONFIG_ADBNAME | \ + KADM5_CONFIG_ADB_LOCKFILE | \ + KADM5_CONFIG_ENCTYPE | \ + KADM5_CONFIG_FLAGS | \ + KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \ + KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES) + + if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { + krb5_free_context(handle->context); + free(handle); + return KRB5_CONFIG_BADFORMAT; + } + + /* + * Set the db_name based on configuration before calling + * krb5_db_init, so it will get used. + */ + if (ret = krb5_dbm_db_set_name(handle->context, + handle->params.dbname)) { + free(handle); + return(ret); + } + + if (ret = krb5_db_init(handle->context)) { + krb5_free_context(handle->context); + free(handle); + return(ret); + } + + if ((ret = krb5_parse_name(handle->context, client_name, + &handle->current_caller))) { + krb5_db_fini(handle->context); + krb5_free_context(handle->context); + free(handle); + return ret; + } + + if (! (handle->lhandle = malloc(sizeof(*handle)))) { + krb5_db_fini(handle->context); + krb5_free_context(handle->context); + free(handle); + return ENOMEM; + } + *handle->lhandle = *handle; + handle->lhandle->api_version = KADM5_API_VERSION_2; + handle->lhandle->struct_version = KADM5_STRUCT_VERSION; + handle->lhandle->lhandle = handle->lhandle; + + /* can't check the handle until current_caller is set */ + if (ret = check_handle((void *) handle)) { + free(handle); + return ret; + } + + /* + * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL + * or an empty string, reads the master password from [the stash + * file]. Otherwise, the non-NULL password is ignored and the + * user is prompted for it via the tty." However, the code was + * implemented the other way: when a non-NULL password was + * provided, the stash file was used. This is somewhat more + * sensible, as then a local or remote client that provides a + * password does not prompt the user. This code maintains the + * previous actual behavior, and not the old spec behavior, + * because that is how the unit tests are written. + * + * In KADM5_API_VERSION_2, this decision is controlled by + * params. + * + * kdb_init_master's third argument is "from_keyboard". + */ + if (ret = kdb_init_master(handle, handle->params.realm, + (handle->api_version == KADM5_API_VERSION_1 ? + ((pass == NULL) || !(strlen(pass))) : + ((handle->params.mask & + KADM5_CONFIG_MKEY_FROM_KBD) && + handle->params.mkey_from_kbd)) + )) { + krb5_db_fini(handle->context); + krb5_free_context(handle->context); + free(handle); + return ret; + } + + if ((ret = kdb_init_hist(handle, handle->params.realm))) { + krb5_db_fini(handle->context); + krb5_free_context(handle->context); + free(handle); + return ret; + } + + if (ret = init_dict(&handle->params)) { + krb5_db_fini(handle->context); + krb5_free_principal(handle->context, handle->current_caller); + krb5_free_context(handle->context); + free(handle); + return ret; + } + + if (ret = adb_policy_init(handle)) { + krb5_db_fini(handle->context); + krb5_free_principal(handle->context, handle->current_caller); + krb5_free_context(handle->context); + free(handle); + return ret; + } + handle->lhandle->policy_db = handle->policy_db; + + *server_handle = (void *) handle; + + return KADM5_OK; +} + +kadm5_ret_t kadm5_destroy(void *server_handle) +{ + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + destroy_dict(); + + adb_policy_close(handle); + krb5_db_fini(handle->context); + krb5_free_principal(handle->context, handle->current_caller); + krb5_free_context(handle->context); + handle->magic_number = 0; + free(handle->lhandle); + free(handle); + + return KADM5_OK; +} + +kadm5_ret_t kadm5_flush(void *server_handle) +{ + kadm5_server_handle_t handle = server_handle; + kadm5_ret_t ret; + + CHECK_HANDLE(server_handle); + + if ((ret = krb5_db_fini(handle->context)) || + /* + * Set the db_name based on configuration before calling + * krb5_db_init, so it will get used. + */ + (ret = krb5_dbm_db_set_name(handle->context, + handle->params.dbname)) || + (ret = krb5_db_init(handle->context)) || + (ret = adb_policy_close(handle)) || + (ret = adb_policy_init(handle))) { + (void) kadm5_destroy(server_handle); + return ret; + } + return KADM5_OK; +} + +int _kadm5_check_handle(void *handle) +{ + CHECK_HANDLE(handle); + return 0; +} diff --git a/src/lib/kadm5/server_internal.h b/src/lib/kadm5/server_internal.h new file mode 100644 index 000000000..415f6d7d7 --- /dev/null +++ b/src/lib/kadm5/server_internal.h @@ -0,0 +1,103 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +/* + * This header file is used internally by the Admin API server + * libraries and Admin server. IF YOU THINK YOU NEED TO USE THIS FILE + * FOR ANYTHING, YOU'RE ALMOST CERTAINLY WRONG. + */ + +#ifndef __KADM5_SERVER_INTERNAL_H__ +#define __KADM5_SERVER_INTERNAL_H__ + +#include <memory.h> +#include <malloc.h> +#include "k5-int.h" +#include <krb5/kdb.h> +#include <kadm5/admin.h> +#include "admin_internal.h" +#include "adb.h" + +typedef struct _kadm5_server_handle_t { + krb5_ui_4 magic_number; + krb5_ui_4 struct_version; + krb5_ui_4 api_version; + krb5_context context; + krb5_principal current_caller; + kadm5_config_params params; + struct _kadm5_server_handle_t *lhandle; + osa_adb_policy_t policy_db; +} kadm5_server_handle_rec, *kadm5_server_handle_t; + +kadm5_ret_t adb_policy_init(kadm5_server_handle_t handle); +kadm5_ret_t adb_policy_close(kadm5_server_handle_t handle); +kadm5_ret_t passwd_check(kadm5_server_handle_t handle, + char *pass, int use_policy, + kadm5_policy_ent_t policy, + krb5_principal principal); +kadm5_ret_t principal_exists(krb5_principal principal); +krb5_error_code kdb_init_master(kadm5_server_handle_t handle, + char *r, int from_keyboard); +krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, + char *r); +krb5_error_code kdb_get_entry(kadm5_server_handle_t handle, + krb5_principal principal, krb5_db_entry *kdb, + osa_princ_ent_rec *adb); +krb5_error_code kdb_free_entry(kadm5_server_handle_t handle, + krb5_db_entry *kdb, osa_princ_ent_rec *adb); +krb5_error_code kdb_put_entry(kadm5_server_handle_t handle, + krb5_db_entry *kdb, osa_princ_ent_rec *adb); +krb5_error_code kdb_delete_entry(kadm5_server_handle_t handle, + krb5_principal name); + +int init_dict(kadm5_config_params *); +int find_word(const char *word); +void destroy_dict(void); + +/* + * *Warning* + * *Warning* This is going to break if we + * *Warning* ever go multi-threaded + * *Warning* + */ +extern krb5_principal current_caller; + +/* + * Why is this (or something similar) not defined *anywhere* in krb5? + */ +#define KSUCCESS 0 +#define WORD_NOT_FOUND 1 + +/* + * all the various mask bits or'd together + */ + +#define ALL_PRINC_MASK (KADM5_PRINCIPAL | KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION | \ + KADM5_LAST_PWD_CHANGE | KADM5_ATTRIBUTES | KADM5_MAX_LIFE | \ + KADM5_MOD_TIME | KADM5_MOD_NAME | KADM5_KVNO | KADM5_MKVNO | \ + KADM5_AUX_ATTRIBUTES | KADM5_POLICY_CLR | KADM5_POLICY) + +#define ALL_POLICY_MASK (KADM5_POLICY | KADM5_PW_MAX_LIFE | KADM5_PW_MIN_LIFE | \ + KADM5_PW_MIN_LENGTH | KADM5_PW_MIN_CLASSES | KADM5_PW_HISTORY_NUM | \ + KADM5_REF_COUNT) + +#define SERVER_CHECK_HANDLE(handle) \ +{ \ + kadm5_server_handle_t srvr = \ + (kadm5_server_handle_t) handle; \ + \ + if (! srvr->current_caller) \ + return KADM5_BAD_SERVER_HANDLE; \ + if (! srvr->lhandle) \ + return KADM5_BAD_SERVER_HANDLE; \ +} + +#define CHECK_HANDLE(handle) \ + GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION, \ + KADM5_NEW_SERVER_API_VERSION) \ + SERVER_CHECK_HANDLE(handle) + +#endif /* __KADM5_SERVER_INTERNAL_H__ */ diff --git a/src/lib/kadm5/server_kdb.c b/src/lib/kadm5/server_kdb.c new file mode 100644 index 000000000..1a900a380 --- /dev/null +++ b/src/lib/kadm5/server_kdb.c @@ -0,0 +1,424 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include "k5-int.h" +#include <kadm5/admin.h> +#include "server_internal.h" + +krb5_principal master_princ; +krb5_encrypt_block master_encblock; +krb5_keyblock master_keyblock; +krb5_db_entry master_db; + +krb5_principal hist_princ; +krb5_encrypt_block hist_encblock; +krb5_keyblock hist_key; +krb5_db_entry hist_db; +krb5_kvno hist_kvno; + +/* much of this code is stolen from the kdc. there should be some + library code to deal with this. */ + +krb5_error_code kdb_init_master(kadm5_server_handle_t handle, + char *r, int from_keyboard) +{ + int ret = 0; + char *realm; + krb5_keyblock tmk; + + if (r == NULL) { + if ((ret = krb5_get_default_realm(handle->context, &realm))) + return ret; + } else { + realm = r; + } + + if ((ret = krb5_db_setup_mkey_name(handle->context, + handle->params.mkey_name, + realm, NULL, &master_princ))) + goto done; + + master_keyblock.enctype = handle->params.enctype; + + krb5_use_enctype(handle->context, &master_encblock, + master_keyblock.enctype); + + if (ret = krb5_db_fetch_mkey(handle->context, master_princ, + &master_encblock, from_keyboard, + FALSE /* only prompt once */, + handle->params.stash_file, + NULL /* I'm not sure about this, + but it's what the kdc does --marc */, + &master_keyblock)) + goto done; + + if ((ret = krb5_db_init(handle->context)) != KSUCCESS) + goto done; + + if ((ret = krb5_db_verify_master_key(handle->context, master_princ, + &master_keyblock, + &master_encblock))) { + krb5_db_fini(handle->context); + return ret; + } + + /* the kdc gets the db mkvno here. The admin server never uses this + bit of information, so there's no reason to retrieve it. */ + + if ((ret = krb5_process_key(handle->context, &master_encblock, + &master_keyblock))) { + krb5_db_fini(handle->context); + goto done; + } + +done: + if (r == NULL) + free(realm); + + return(ret); +} + +/* + * Function: kdb_init_hist + * + * Purpose: Initializes the global history variables. + * + * Arguments: + * + * handle (r) kadm5 api server handle + * r (r) realm of history principal to use, or NULL + * + * Effects: This function sets the value of the following global + * variables: + * + * hist_princ krb5_principal holding the history principal + * hist_db krb5_db_entry of the history principal + * hist_key krb5_keyblock holding the history principal's key + * hist_encblock krb5_encrypt_block holding the procssed hist_key + * hist_kvno the version number of the history key + * + * If the history principal does not already exist, this function + * attempts to create it with kadm5_create_principal. WARNING! + * If the history principal is deleted and this function is executed + * (by kadmind, or kadmin.local, or anything else with permission), + * the principal will be assigned a new random key and all existing + * password history information will become useless. + */ +krb5_error_code kdb_init_hist(kadm5_server_handle_t handle, char *r) +{ + int ret = 0; + char *realm, *hist_name; + krb5_key_data *key_data; + + if (r == NULL) { + if ((ret = krb5_get_default_realm(handle->context, &realm))) + return ret; + } else { + realm = r; + } + + if ((hist_name = (char *) malloc(strlen(KADM5_HIST_PRINCIPAL) + + strlen(realm) + 2)) == NULL) + goto done; + + (void) sprintf(hist_name, "%s@%s", KADM5_HIST_PRINCIPAL, realm); + + if ((ret = krb5_parse_name(handle->context, hist_name, &hist_princ))) + goto done; + + if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) { + kadm5_principal_ent_rec ent; + + if (ret != KADM5_UNK_PRINC) + goto done; + + /* try to create the principal */ + + memset(&ent, 0, sizeof(ent)); + + ent.principal = hist_princ; + ent.max_life = KRB5_KDB_DISALLOW_ALL_TIX; + ent.attributes = 0; + + /* this uses hist_kvno. So we set it to 2, which will be the + correct value once the principal is created and randomized. + Of course, it doesn't make sense to keep a history for the + history principal, anyway. */ + + hist_kvno = 2; + + if (ret = kadm5_create_principal(handle, &ent, + (KADM5_PRINCIPAL | + KADM5_MAX_LIFE | + KADM5_ATTRIBUTES), + "to-be-random")) + goto done; + + /* this won't let us randomize the hist_princ. So we cheat. */ + + hist_princ = NULL; + + ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL); + + hist_princ = ent.principal; + + if (ret) + goto done; + + /* now read the newly-created kdb record out of the + database. */ + + if ((ret = kdb_get_entry(handle, hist_princ, &hist_db, NULL))) + goto done; + + } + + if (ret = krb5_dbe_find_enctype(handle->context, + &hist_db, + handle->params.enctype, + -1, + -1, + &key_data)) + goto done; + + if (ret = krb5_dbekd_decrypt_key_data(handle->context, &master_encblock, + key_data, &hist_key, NULL)) + goto done; + + krb5_use_enctype(handle->context, &hist_encblock, hist_key.enctype); + + if ((ret = krb5_process_key(handle->context, &hist_encblock, + &hist_key)) != KSUCCESS) + goto done; + + hist_kvno = key_data->key_data_kvno; + +done: + free(hist_name); + if (r == NULL) + free(realm); + return ret; +} + +/* + * Function: kdb_get_entry + * + * Purpose: Gets an entry from the kerberos database and breaks + * it out into a krb5_db_entry and an osa_princ_ent_t. + * + * Arguments: + * + * handle (r) the server_handle + * principal (r) the principal to get + * kdb (w) krb5_db_entry to fill in + * adb (w) osa_princ_ent_rec to fill in + * + * when the caller is done with kdb and adb, kdb_free_entry must be + * called to release them. The adb record is filled in with the + * contents of the KRB5_TL_KADM_DATA record; if that record doesn't + * exist, an empty but valid adb record is returned. + */ +krb5_error_code +kdb_get_entry(kadm5_server_handle_t handle, + krb5_principal principal, krb5_db_entry *kdb, + osa_princ_ent_rec *adb) +{ + krb5_error_code ret; + int nprincs; + krb5_boolean more; + krb5_tl_data tl_data; + XDR xdrs; + + if (ret = krb5_db_get_principal(handle->context, principal, kdb, &nprincs, + &more)) + return(ret); + + if (more) { + krb5_db_free_principal(handle->context, kdb, nprincs); + return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); + } else if (nprincs != 1) { + krb5_db_free_principal(handle->context, kdb, nprincs); + return(KADM5_UNK_PRINC); + } + + if (adb) { + memset(adb, 0, sizeof(*adb)); + + tl_data.tl_data_type = KRB5_TL_KADM_DATA; + /* + * 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... + */ + if ((ret = krb5_dbe_lookup_tl_data(handle->context, kdb, &tl_data)) + || (tl_data.tl_data_length == 0)) { + /* there's no admin data. this can happen, if the admin + server is put into production after some principals + are created. In this case, return valid admin + data (which is all zeros with the hist_kvno filled + in), and when the entry is written, the admin + data will get stored correctly. */ + + adb->admin_history_kvno = hist_kvno; + + return(ret); + } + + xdrmem_create(&xdrs, tl_data.tl_data_contents, + tl_data.tl_data_length, XDR_DECODE); + if (! xdr_osa_princ_ent_rec(&xdrs, adb)) { + xdr_destroy(&xdrs); + krb5_db_free_principal(handle->context, kdb, 1); + return(OSA_ADB_XDR_FAILURE); + } + xdr_destroy(&xdrs); + } + + return(0); +} + +/* + * Function: kdb_free_entry + * + * Purpose: frees the resources allocated by kdb_get_entry + * + * Arguments: + * + * handle (r) the server_handle + * kdb (w) krb5_db_entry to fill in + * adb (w) osa_princ_ent_rec to fill in + * + * when the caller is done with kdb and adb, kdb_free_entry must be + * called to release them. + */ + +krb5_error_code +kdb_free_entry(kadm5_server_handle_t handle, + krb5_db_entry *kdb, osa_princ_ent_rec *adb) +{ + XDR xdrs; + + + if (kdb) + krb5_db_free_principal(handle->context, kdb, 1); + + if (adb) { + xdrmem_create(&xdrs, NULL, 0, XDR_FREE); + xdr_osa_princ_ent_rec(&xdrs, adb); + xdr_destroy(&xdrs); + } + + return(0); +} + +/* + * Function: kdb_put_entry + * + * Purpose: Stores the osa_princ_ent_t and krb5_db_entry into to + * database. + * + * Arguments: + * + * handle (r) the server_handle + * kdb (r/w) the krb5_db_entry to store + * adb (r) the osa_princ_db_ent to store + * + * Effects: + * + * The last modifier field of the kdb is set to the caller at now. + * adb is encoded with xdr_osa_princ_ent_ret and stored in kbd as + * KRB5_TL_KADM_DATA. kdb is then written to the database. + */ +krb5_error_code +kdb_put_entry(kadm5_server_handle_t handle, + krb5_db_entry *kdb, osa_princ_ent_rec *adb) +{ + krb5_error_code ret; + krb5_int32 now; + XDR xdrs; + krb5_tl_data tl_data; + int one; + + if (ret = krb5_timeofday(handle->context, &now)) + return(ret); + + if (ret = krb5_dbe_update_mod_princ_data(handle->context, kdb, now, + handle->current_caller)) + return(ret); + + xdralloc_create(&xdrs, XDR_ENCODE); + if(! xdr_osa_princ_ent_rec(&xdrs, adb)) { + xdr_destroy(&xdrs); + return(OSA_ADB_XDR_FAILURE); + } + tl_data.tl_data_type = KRB5_TL_KADM_DATA; + tl_data.tl_data_length = xdr_getpos(&xdrs); + tl_data.tl_data_contents = xdralloc_getdata(&xdrs); + + ret = krb5_dbe_update_tl_data(handle->context, kdb, &tl_data); + + xdr_destroy(&xdrs); + + if (ret) + return(ret); + + one = 1; + + if (ret = krb5_db_put_principal(handle->context, kdb, &one)) + return(ret); + + return(0); +} + +krb5_error_code +kdb_delete_entry(kadm5_server_handle_t handle, krb5_principal name) +{ + int one = 1; + krb5_error_code ret; + + ret = krb5_db_delete_principal(handle->context, name, &one); + + return ret; +} + +typedef struct _iter_data { + void (*func)(void *, krb5_principal); + void *data; +} iter_data; + +static krb5_error_code +kdb_iter_func(krb5_pointer data, krb5_db_entry *kdb) +{ + iter_data *id = (iter_data *) data; + + (*(id->func))(id->data, kdb->princ); + + return(0); +} + +krb5_error_code +kdb_iter_entry(kadm5_server_handle_t handle, + void (*iter_fct)(void *, krb5_principal), void *data) +{ + iter_data id; + krb5_error_code ret; + + id.func = iter_fct; + id.data = data; + + if (ret = krb5_db_iterate(handle->context, kdb_iter_func, &id)) + return(ret); + + return(0); +} + + diff --git a/src/lib/kadm5/server_misc.c b/src/lib/kadm5/server_misc.c new file mode 100644 index 000000000..24f101ce5 --- /dev/null +++ b/src/lib/kadm5/server_misc.c @@ -0,0 +1,101 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include "k5-int.h" +#include <krb5/kdb.h> +#include <ctype.h> +#include "adb.h" + +/* for strcasecmp */ +#include <string.h> + +#include "server_internal.h" + +kadm5_ret_t +adb_policy_init(kadm5_server_handle_t handle) +{ + osa_adb_ret_t ret; + if(handle->policy_db == (osa_adb_policy_t) NULL) + if((ret = osa_adb_open_policy(&handle->policy_db, + &handle->params)) != OSA_ADB_OK) + return ret; + return KADM5_OK; +} + +kadm5_ret_t +adb_policy_close(kadm5_server_handle_t handle) +{ + osa_adb_ret_t ret; + if(handle->policy_db != (osa_adb_policy_t) NULL) + if((ret = osa_adb_close_policy(handle->policy_db)) != OSA_ADB_OK) + return ret; + handle->policy_db = NULL; + return KADM5_OK; +} + +/* some of this is stolen from gatekeeper ... */ +kadm5_ret_t +passwd_check(kadm5_server_handle_t handle, + char *password, int use_policy, kadm5_policy_ent_t pol, + krb5_principal principal) +{ + int nupper = 0, + nlower = 0, + ndigit = 0, + npunct = 0, + nspec = 0; + char c, *s; + + if(use_policy) { + if(strlen(password) < pol->pw_min_length) + return KADM5_PASS_Q_TOOSHORT; + s = password; + while ((c = *s++)) { + if (islower(c)) { + nlower = 1; + continue; + } + else if (isupper(c)) { + nupper = 1; + continue; + } else if (isdigit(c)) { + ndigit = 1; + continue; + } else if (ispunct(c)) { + npunct = 1; + continue; + } else { + nspec = 1; + continue; + } + } + if ((nupper + nlower + ndigit + npunct + nspec) < pol->pw_min_classes) + return KADM5_PASS_Q_CLASS; + if((find_word(password) == KADM5_OK)) + return KADM5_PASS_Q_DICT; + else { + char *cp; + int c, n = krb5_princ_size(handle->context, principal); + cp = krb5_princ_realm(handle->context, principal)->data; + if (strcasecmp(cp, password) == 0) + return KADM5_PASS_Q_DICT; + for (c = 0; c < n ; c++) { + cp = krb5_princ_component(handle->context, principal, c)->data; + if (strcasecmp(cp, password) == 0) + return KADM5_PASS_Q_DICT; + } + return KADM5_OK; + } + } else { + if (strlen(password) < 1) + return KADM5_PASS_Q_TOOSHORT; + } + return KADM5_OK; +} diff --git a/src/lib/kadm5/setenv.c b/src/lib/kadm5/setenv.c new file mode 100644 index 000000000..47904de1b --- /dev/null +++ b/src/lib/kadm5/setenv.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* based on @(#)setenv.c 5.2 (Berkeley) 6/27/88 */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* + * setenv -- + * Set the value of the environmental variable "name" to be + * "value". If rewrite is set, replace any current value. + */ +setenv(name, value, rewrite) + register char *name, *value; + int rewrite; +{ + extern char **environ; + static int alloced; /* if allocated space before */ + register char *C; + int l_value, offset; +#if !defined(sun) && !defined(hpux) + char *malloc(), *realloc(); +#endif + char *_findenv(); + + if (*value == '=') /* no `=' in value */ + ++value; + l_value = strlen(value); + if ((C = _findenv(name, &offset))) { /* find if already exists */ + if (!rewrite) + return(0); + if (strlen(C) >= l_value) { /* old larger; copy over */ + while (*C++ = *value++); + return(0); + } + } + else { /* create new slot */ + register int cnt; + register char **P; + + for (P = environ, cnt = 0; *P; ++P, ++cnt); + if (alloced) { /* just increase size */ + environ = (char **)realloc((char *)environ, + (u_int)(sizeof(char *) * (cnt + 2))); + if (!environ) + return(-1); + } + else { /* get new space */ + alloced = 1; /* copy old entries into it */ + P = (char **)malloc((u_int)(sizeof(char *) * + (cnt + 2))); + if (!P) + return(-1); + memcpy(P, environ, cnt * sizeof(char *)); + environ = P; + } + environ[cnt + 1] = NULL; + offset = cnt; + } + for (C = name; *C && *C != '='; ++C); /* no `=' in name */ + if (!(environ[offset] = /* name + `=' + value */ + malloc((u_int)((int)(C - name) + l_value + 2)))) + return(-1); + for (C = environ[offset]; (*C = *name++) && *C != '='; ++C); + for (*C++ = '='; *C++ = *value++;); + return(0); +} + +/* + * unsetenv(name) -- + * Delete environmental variable "name". + */ +void +unsetenv(name) + char *name; +{ + extern char **environ; + register char **P; + int offset; + char *_findenv(); + + while (_findenv(name, &offset)) /* if set multiple times */ + for (P = &environ[offset];; ++P) + if (!(*P = *(P + 1))) + break; +} +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* based on @(#)getenv.c 5.5 (Berkeley) 6/27/88 */ + +/* + * getenv -- + * Returns ptr to value associated with name, if any, else NULL. + */ +char * +getenv(name) + const char *name; +{ + int offset; + char *_findenv(); + + return(_findenv(name, &offset)); +} + +/* + * _findenv -- + * Returns pointer to value associated with name, if any, else NULL. + * Sets offset to be the offset of the name/value combination in the + * environmental array, for use by setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + * + * This routine *should* be a static; don't use it. + */ +char * +_findenv(name, offset) + register char *name; + int *offset; +{ + extern char **environ; + register int len; + register char **P, *C; + + for (C = name, len = 0; *C && *C != '='; ++C, ++len); + for (P = environ; *P; ++P) + if (!strncmp(*P, name, len)) + if (*(C = *P + len) == '=') { + *offset = P - environ; + return(++C); + } + return(NULL); +} diff --git a/src/lib/kadm5/str_conv.c b/src/lib/kadm5/str_conv.c new file mode 100644 index 000000000..882892933 --- /dev/null +++ b/src/lib/kadm5/str_conv.c @@ -0,0 +1,397 @@ +/* + * lib/kadm/str_conv.c + * + * Copyright 1995 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * str_conv.c - Convert between strings and Kerberos internal data. + */ + +/* + * Table of contents: + * + * String decoding: + * ---------------- + * krb5_string_to_flags() - Convert string to krb5_flags. + * + * String encoding: + * ---------------- + * krb5_flags_to_string() - Convert krb5_flags to string. + */ + +#include "k5-int.h" +#include "admin_internal.h" + +/* + * Local data structures. + */ +struct flags_lookup_entry { + krb5_flags fl_flags; /* Flag */ + krb5_boolean fl_sense; /* Sense of the flag */ + const char * fl_specifier; /* How to recognize it */ + const char * fl_output; /* How to spit it out */ +}; + +/* + * Local strings + */ + +static const char default_tupleseps[] = ", \t"; +static const char default_ksaltseps[] = ":."; + +/* Keytype strings */ +/* Flags strings */ +static const char flags_pdate_in[] = "postdateable"; +static const char flags_fwd_in[] = "forwardable"; +static const char flags_tgtbased_in[] = "tgt-based"; +static const char flags_renew_in[] = "renewable"; +static const char flags_proxy_in[] = "proxiable"; +static const char flags_dup_skey_in[] = "dup-skey"; +static const char flags_tickets_in[] = "allow-tickets"; +static const char flags_preauth_in[] = "preauth"; +static const char flags_hwauth_in[] = "hwauth"; +static const char flags_pwchange_in[] = "pwchange"; +static const char flags_service_in[] = "service"; +static const char flags_pwsvc_in[] = "pwservice"; +static const char flags_md5_in[] = "md5"; +static const char flags_pdate_out[] = "Not Postdateable"; +static const char flags_fwd_out[] = "Not Forwardable"; +static const char flags_tgtbased_out[] = "No TGT-based requests"; +static const char flags_renew_out[] = "Not renewable"; +static const char flags_proxy_out[] = "Not proxiable"; +static const char flags_dup_skey_out[] = "No DUP_SKEY requests"; +static const char flags_tickets_out[] = "All Tickets Disallowed"; +static const char flags_preauth_out[] = "Preauthorization required"; +static const char flags_hwauth_out[] = "HW Authorization required"; +static const char flags_pwchange_out[] = "Password Change required"; +static const char flags_service_out[] = "Service Disabled"; +static const char flags_pwsvc_out[] = "Password Changing Service"; +static const char flags_md5_out[] = "RSA-MD5 supported"; +static const char flags_default_neg[] = "-"; +static const char flags_default_sep[] = " "; + +/* + * Lookup tables. + */ + +static const struct flags_lookup_entry flags_table[] = { +/* flag sense input specifier output string */ +/*----------------------------- ------- ------------------ ------------------*/ +{ KRB5_KDB_DISALLOW_POSTDATED, 0, flags_pdate_in, flags_pdate_out }, +{ KRB5_KDB_DISALLOW_FORWARDABLE,0, flags_fwd_in, flags_fwd_out }, +{ KRB5_KDB_DISALLOW_TGT_BASED, 0, flags_tgtbased_in, flags_tgtbased_out}, +{ KRB5_KDB_DISALLOW_RENEWABLE, 0, flags_renew_in, flags_renew_out }, +{ KRB5_KDB_DISALLOW_PROXIABLE, 0, flags_proxy_in, flags_proxy_out }, +{ KRB5_KDB_DISALLOW_DUP_SKEY, 0, flags_dup_skey_in, flags_dup_skey_out}, +{ KRB5_KDB_DISALLOW_ALL_TIX, 0, flags_tickets_in, flags_tickets_out }, +{ KRB5_KDB_REQUIRES_PRE_AUTH, 1, flags_preauth_in, flags_preauth_out }, +{ KRB5_KDB_REQUIRES_HW_AUTH, 1, flags_hwauth_in, flags_hwauth_out }, +{ KRB5_KDB_REQUIRES_PWCHANGE, 1, flags_pwchange_in, flags_pwchange_out}, +{ KRB5_KDB_DISALLOW_SVR, 0, flags_service_in, flags_service_out }, +{ KRB5_KDB_PWCHANGE_SERVICE, 1, flags_pwsvc_in, flags_pwsvc_out }, +{ KRB5_KDB_SUPPORT_DESMD5, 1, flags_md5_in, flags_md5_out } +}; +static const int flags_table_nents = sizeof(flags_table)/ + sizeof(flags_table[0]); + + +krb5_error_code +krb5_string_to_flags(string, positive, negative, flagsp) + char * string; + const char * positive; + const char * negative; + krb5_flags * flagsp; +{ + int i; + int found; + const char *neg; + size_t nsize, psize; + int cpos; + int sense; + + found = 0; + /* We need to have a way to negate it. */ + neg = (negative) ? negative : flags_default_neg; + nsize = strlen(neg); + psize = (positive) ? strlen(positive) : 0; + + cpos = 0; + sense = 1; + /* First check for positive or negative sense */ + if (!strncasecmp(neg, string, nsize)) { + sense = 0; + cpos += (int) nsize; + } + else if (psize && !strncasecmp(positive, string, psize)) { + cpos += (int) psize; + } + + for (i=0; i<flags_table_nents; i++) { + if (!strcasecmp(&string[cpos], flags_table[i].fl_specifier)) { + found = 1; + if (sense == (int) flags_table[i].fl_sense) + *flagsp |= flags_table[i].fl_flags; + else + *flagsp &= ~flags_table[i].fl_flags; + + break; + } + } + return((found) ? 0 : EINVAL); +} + +krb5_error_code +krb5_flags_to_string(flags, sep, buffer, buflen) + krb5_flags flags; + const char * sep; + char * buffer; + size_t buflen; +{ + int i; + krb5_flags pflags; + const char *sepstring; + char *op; + int initial; + krb5_error_code retval; + + retval = 0; + op = buffer; + pflags = 0; + initial = 1; + sepstring = (sep) ? sep : flags_default_sep; + /* Blast through the table matching all we can */ + for (i=0; i<flags_table_nents; i++) { + if (flags & flags_table[i].fl_flags) { + /* Found a match, see if it'll fit into the output buffer */ + if ((op+strlen(flags_table[i].fl_output)+strlen(sepstring)) < + (buffer + buflen)) { + if (!initial) { + strcpy(op, sep); + op += strlen(sep); + } + initial = 0; + strcpy(op, flags_table[i].fl_output); + op += strlen(flags_table[i].fl_output); + } + else { + retval = ENOMEM; + break; + } + /* Keep track of what we matched */ + pflags |= flags_table[i].fl_flags; + } + } + if (!retval) { + /* See if there's any leftovers */ + if (flags & ~pflags) + retval = EINVAL; + else if (initial) + *buffer = '\0'; + } + return(retval); +} + +krb5_error_code +krb5_input_flag_to_string(flag, buffer, buflen) + int flag; + char * buffer; + size_t buflen; +{ + if(flag < 0 || flag >= flags_table_nents) return ENOENT; /* End of list */ + if(strlen(flags_table[flag].fl_specifier) > buflen) return ENOMEM; + strcpy(buffer, flags_table[flag].fl_specifier); + return 0; +} + +/* + * krb5_keysalt_is_present() - Determine if a key/salt pair is present + * in a list of key/salt tuples. + * + * Salttype may be negative to indicate a search for only a enctype. + */ +krb5_boolean +krb5_keysalt_is_present(ksaltlist, nksalts, enctype, salttype) + krb5_key_salt_tuple *ksaltlist; + krb5_int32 nksalts; + krb5_enctype enctype; + krb5_int32 salttype; +{ + krb5_boolean foundit; + int i; + + foundit = 0; + if (ksaltlist) { + for (i=0; i<nksalts; i++) { + if ((ksaltlist[i].ks_enctype == enctype) && + ((ksaltlist[i].ks_salttype == salttype) || + (salttype < 0))) { + foundit = 1; + break; + } + } + } + return(foundit); +} + +/* + * krb5_string_to_keysalts() - Convert a string representation to a list + * of key/salt tuples. + */ +krb5_error_code +krb5_string_to_keysalts(string, tupleseps, ksaltseps, dups, ksaltp, nksaltp) + char *string; + const char *tupleseps; + const char *ksaltseps; + krb5_boolean dups; + krb5_key_salt_tuple **ksaltp; + krb5_int32 *nksaltp; +{ + krb5_error_code kret; + char *kp, *sp, *ep; + char sepchar, trailchar; + krb5_enctype ktype; + krb5_int32 stype; + krb5_key_salt_tuple *savep; + const char *tseplist; + const char *ksseplist; + const char *septmp; + size_t len; + + kret = 0; + kp = string; + tseplist = (tupleseps) ? tupleseps : default_tupleseps; + ksseplist = (ksaltseps) ? ksaltseps : default_ksaltseps; + while (kp) { + /* Attempt to find a separator */ + ep = (char *) NULL; + if (*tseplist) { + septmp = tseplist; + for (ep = strchr(kp, (int) *septmp); + *(++septmp) && !ep; + ep = strchr(kp, (int) *septmp)); + } + + if (ep) { + trailchar = *ep; + *ep = '\0'; + ep++; + } + /* + * kp points to something (hopefully) of the form: + * <enctype><ksseplist><salttype> + * or + * <enctype> + */ + sp = (char *) NULL; + /* Attempt to find a separator */ + septmp = ksseplist; + for (sp = strchr(kp, (int) *septmp); + *(++septmp) && !sp; + ep = strchr(kp, (int) *septmp)); + + if (sp) { + /* Separate enctype from salttype */ + sepchar = *sp; + *sp = '\0'; + sp++; + } + else + stype = -1; + + /* + * Attempt to parse enctype and salttype. If we parse well + * then make sure that it specifies a unique key/salt combo + */ + if (!(kret = krb5_string_to_enctype(kp, &ktype)) && + (!sp || !(kret = krb5_string_to_salttype(sp, &stype))) && + (dups || + !krb5_keysalt_is_present(*ksaltp, *nksaltp, ktype, stype))) { + + /* Squirrel away old keysalt array */ + savep = *ksaltp; + len = (size_t) *nksaltp; + + /* Get new keysalt array */ + if (*ksaltp = (krb5_key_salt_tuple *) + malloc((len + 1) * sizeof(krb5_key_salt_tuple))) { + + /* Copy old keysalt if appropriate */ + if (savep) { + memcpy(*ksaltp, savep, + len * sizeof(krb5_key_salt_tuple)); + krb5_xfree(savep); + } + + /* Save our values */ + (*ksaltp)[(*nksaltp)].ks_enctype = ktype; + (*ksaltp)[(*nksaltp)].ks_salttype = stype; + (*nksaltp)++; + } + else { + *ksaltp = savep; + break; + } + } + if (kret) + return kret; + if (sp) + sp[-1] = sepchar; + if (ep) + ep[-1] = trailchar; + kp = ep; + } + return(kret); +} + +/* + * krb5_keysalt_iterate() - Do something for each unique key/salt + * combination. + * + * If ignoresalt set, then salttype is ignored. + */ +krb5_error_code +krb5_keysalt_iterate(ksaltlist, nksalt, ignoresalt, iterator, arg) + krb5_key_salt_tuple *ksaltlist; + krb5_int32 nksalt; + krb5_boolean ignoresalt; + krb5_error_code (*iterator) KRB5_NPROTOTYPE((krb5_key_salt_tuple *, + krb5_pointer)); + krb5_pointer arg; +{ + int i; + krb5_error_code kret; + krb5_key_salt_tuple scratch; + + kret = 0; + for (i=0; i<nksalt; i++) { + scratch.ks_enctype = ksaltlist[i].ks_enctype; + scratch.ks_salttype = (ignoresalt) ? -1 : ksaltlist[i].ks_salttype; + if (!krb5_keysalt_is_present(ksaltlist, + i, + scratch.ks_enctype, + scratch.ks_salttype)) { + if (kret = (*iterator)(&scratch, arg)) + break; + } + } + return(kret); +} diff --git a/src/lib/kadm5/svr_chpass_util.c b/src/lib/kadm5/svr_chpass_util.c new file mode 100644 index 000000000..df2bf4c47 --- /dev/null +++ b/src/lib/kadm5/svr_chpass_util.c @@ -0,0 +1,15 @@ +#include <kadm5/admin.h> +#include "server_internal.h" + +kadm5_ret_t kadm5_chpass_principal_util(void *server_handle, + krb5_principal princ, + char *new_pw, + char **ret_pw, + char *msg_ret) +{ + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + return _kadm5_chpass_principal_util(handle, handle->lhandle, princ, + new_pw, ret_pw, msg_ret); +} diff --git a/src/lib/kadm5/svr_iters.c b/src/lib/kadm5/svr_iters.c new file mode 100644 index 000000000..19c900021 --- /dev/null +++ b/src/lib/kadm5/svr_iters.c @@ -0,0 +1,248 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#if defined(HAVE_COMPILE) && defined(HAVE_STEP) +#define SOLARIS_REGEXPS +#elif defined(HAVE_REGCOMP) && defined(HAVE_REGEXEC) +#define POSIX_REGEXPS +#elif defined(HAVE_RE_COMP) && defined(HAVE_RE_EXEC) +#define BSD_REGEXPS +#else +#error I cannot find any regexp functions +#endif + +#include <sys/types.h> +#include <string.h> +#include <kadm5/admin.h> +#include "adb.h" +#include <dyn.h> +#ifdef SOLARIS_REGEXPS +#include <regexpr.h> +#endif +#ifdef POSIX_REGEXPS +#include <regex.h> +#endif +#include <stdlib.h> + +#include "server_internal.h" + +struct iter_data { + krb5_context context; + DynObject matches; + char *exp; +#ifdef SOLARIS_REGEXPS + char *expbuf; +#endif +#ifdef POSIX_REGEXPS + regex_t preg; +#endif +}; + +/* + * Function: glob_to_regexp + * + * Arguments: + * + * glob (r) the shell-style glob (?*[]) to convert + * realm (r) the default realm to append, or NULL + * regexp (w) the ed-style regexp created from glob + * + * Effects: + * + * regexp is filled in with allocated memory contained a regular + * expression to be used with re_comp/compile that matches what the + * shell-style glob would match. If glob does not contain an "@" + * character and realm is not NULL, "@<realm>" is appended to the regexp. + * + * Conversion algorithm: + * + * quoted characters are copied quoted + * ? is converted to . + * * is converted to .* + * active characters are quoted: ^, $, . + * [ and ] are active but supported and have the same meaning, so + * they are copied + * other characters are copied + * regexp is anchored with ^ and $ + */ +kadm5_ret_t glob_to_regexp(char *glob, char *realm, char **regexp) +{ + int append_realm; + char *p; + + /* validate the glob */ + if (glob[strlen(glob)-1] == '\\') + return EINVAL; + + /* A character of glob can turn into two in regexp, plus ^ and $ */ + /* and trailing null. If glob has no @, also allocate space for */ + /* the realm. */ + append_realm = (realm != NULL) && (strchr(glob, '@') == NULL); + p = (char *) malloc(strlen(glob)*2+ 3 + + (append_realm ? (strlen(realm)+1) : 0)); + if (p == NULL) + return ENOMEM; + *regexp = p; + + *p++ = '^'; + while (*glob) { + switch (*glob) { + case '?': + *p++ = '.'; + break; + case '*': + *p++ = '.'; + *p++ = '*'; + break; + case '.': + case '^': + case '$': + *p++ = '\\'; + *p++ = *glob; + break; + case '\\': + *p++ = '\\'; + *p++ = ++*glob; + break; + default: + *p++ = *glob; + break; + } + glob++; + } + + if (append_realm) { + *p++ = '@'; + strcpy(p, realm); + p += strlen(realm); + } + + *p++ = '$'; + *p++ = '\0'; + return KADM5_OK; +} + +void get_either_iter(struct iter_data *data, char *name) +{ + if ( +#ifdef SOLARIS_REGEXPS + (step(name, data->expbuf) != 0) +#endif +#ifdef POSIX_REGEXPS + (regexec(&data->preg, name, 0, NULL, 0) == 0) +#endif +#ifdef BSD_REGEXPS + (re_exec(name) != 0) +#endif + ) + { + (void) DynAdd(data->matches, &name); + } else + free(name); +} + +void get_pols_iter(void *data, osa_policy_ent_t entry) +{ + char *name; + + if ((name = strdup(entry->name)) == NULL) + return; + get_either_iter(data, name); +} + +void get_princs_iter(void *data, krb5_principal princ) +{ + struct iter_data *id = (struct iter_data *) data; + char *name; + + if (krb5_unparse_name(id->context, princ, &name) != 0) + return; + get_either_iter(data, name); +} + +kadm5_ret_t kadm5_get_either(int princ, + void *server_handle, + char *exp, + char ***princs, + int *count) +{ + struct iter_data data; + char *msg, *regexp; + int ret; + kadm5_server_handle_t handle = server_handle; + + *count = 0; + if (exp == NULL) + exp = "*"; + + CHECK_HANDLE(server_handle); + + if ((ret = glob_to_regexp(exp, princ ? handle->params.realm : NULL, + ®exp)) != KADM5_OK) + return ret; + + if ( +#ifdef SOLARIS_REGEXPS + ((data.expbuf = compile(regexp, NULL, NULL)) == NULL) +#endif +#ifdef POSIX_REGEXPS + ((regcomp(&data.preg, regexp, REG_NOSUB)) != 0) +#endif +#ifdef BSD_REGEXPS + ((msg = (char *) re_comp(regexp)) != NULL) +#endif + ) + { + /* XXX syslog msg or regerr(regerrno) */ + free(regexp); + return EINVAL; + } + + if ((data.matches = DynCreate(sizeof(char *), -4)) == NULL) { + free(regexp); + return ENOMEM; + } + + if (princ) { + data.context = handle->context; + ret = kdb_iter_entry(handle, get_princs_iter, (void *) &data); + } else { + ret = osa_adb_iter_policy(handle->policy_db, get_pols_iter, (void *)&data); + } + + if (ret != OSA_ADB_OK) { + free(regexp); + DynDestroy(data.matches); + return ret; + } + + (*princs) = (char **) DynArray(data.matches); + *count = DynSize(data.matches); + DynRelease(data.matches); + free(regexp); + return KADM5_OK; +} + +kadm5_ret_t kadm5_get_principals(void *server_handle, + char *exp, + char ***princs, + int *count) +{ + return kadm5_get_either(1, server_handle, exp, princs, count); +} + +kadm5_ret_t kadm5_get_policies(void *server_handle, + char *exp, + char ***pols, + int *count) +{ + return kadm5_get_either(0, server_handle, exp, pols, count); +} + diff --git a/src/lib/kadm5/svr_misc_free.c b/src/lib/kadm5/svr_misc_free.c new file mode 100644 index 000000000..5c76a1ebc --- /dev/null +++ b/src/lib/kadm5/svr_misc_free.c @@ -0,0 +1,37 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif +#include <kadm5/admin.h> +#include <malloc.h> +#include "server_internal.h" + +kadm5_ret_t +kadm5_free_principal_ent(void *server_handle, + kadm5_principal_ent_t val) +{ + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if(val) { + if(val->principal) + krb5_free_principal(handle->context, val->principal); + if(val->mod_name) + krb5_free_principal(handle->context, val->mod_name); + if(val->policy) + free(val->policy); + + /* XXX free key_data and tl_data */ + + if (handle->api_version == KADM5_API_VERSION_1) + free(val); + } + return KADM5_OK; +} diff --git a/src/lib/kadm5/svr_policy.c b/src/lib/kadm5/svr_policy.c new file mode 100644 index 000000000..74e252115 --- /dev/null +++ b/src/lib/kadm5/svr_policy.c @@ -0,0 +1,315 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/types.h> +#include <kadm5/admin.h> +#include "adb.h" +#include "server_internal.h" +#include <stdlib.h> + +#define MAX_PW_HISTORY 10 +#define MIN_PW_HISTORY 1 +#define MIN_PW_CLASSES 1 +#define MAX_PW_CLASSES 5 +#define MIN_PW_LENGTH 1 + +/* + * Function: kadm5_create_policy + * + * Purpose: Create Policies in the policy DB. + * + * Arguments: + * entry (input) The policy entry to be written out to the DB. + * mask (input) Specifies which fields in entry are to ge written out + * and which get default values. + * <return value> 0 if sucsessfull otherwise an error code is returned. + * + * Requires: + * Entry must be a valid principal entry, and mask have a valid value. + * + * Effects: + * Verifies that mask does not specify that the refcount should + * be set as part of the creation, and calls + * kadm5_create_policy_internal. If the refcount *is* + * specified, returns KADM5_BAD_MASK. + */ + +kadm5_ret_t +kadm5_create_policy(void *server_handle, + kadm5_policy_ent_t entry, long mask) +{ + CHECK_HANDLE(server_handle); + + if (mask & KADM5_REF_COUNT) + return KADM5_BAD_MASK; + else + return kadm5_create_policy_internal(server_handle, entry, mask); +} + +/* + * Function: kadm5_create_policy_internal + * + * Purpose: Create Policies in the policy DB. + * + * Arguments: + * entry (input) The policy entry to be written out to the DB. + * mask (input) Specifies which fields in entry are to ge written out + * and which get default values. + * <return value> 0 if sucsessfull otherwise an error code is returned. + * + * Requires: + * Entry must be a valid principal entry, and mask have a valid value. + * + * Effects: + * Writes the data to the database, and does a database sync if + * sucsessfull. + * + */ + +kadm5_ret_t +kadm5_create_policy_internal(void *server_handle, + kadm5_policy_ent_t entry, long mask) +{ + kadm5_server_handle_t handle = server_handle; + osa_policy_ent_rec pent; + int ret; + char *p; + + CHECK_HANDLE(server_handle); + + if ((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL)) + return EINVAL; + if(strlen(entry->policy) == 0) + return KADM5_BAD_POLICY; + if (!(mask & KADM5_POLICY)) + return KADM5_BAD_MASK; + + pent.name = entry->policy; + p = entry->policy; + while(*p != '\0') { + if(*p < ' ' || *p > '~') + return KADM5_BAD_POLICY; + else + p++; + } + if (!(mask & KADM5_PW_MAX_LIFE)) + pent.pw_max_life = 0; + else + pent.pw_max_life = entry->pw_max_life; + if (!(mask & KADM5_PW_MIN_LIFE)) + pent.pw_min_life = 0; + else { + if((mask & KADM5_PW_MAX_LIFE)) { + if(entry->pw_min_life > entry->pw_max_life && entry->pw_max_life != 0) + return KADM5_BAD_MIN_PASS_LIFE; + } + pent.pw_min_life = entry->pw_min_life; + } + if (!(mask & KADM5_PW_MIN_LENGTH)) + pent.pw_min_length = MIN_PW_LENGTH; + else { + if(entry->pw_min_length < MIN_PW_LENGTH) + return KADM5_BAD_LENGTH; + pent.pw_min_length = entry->pw_min_length; + } + if (!(mask & KADM5_PW_MIN_CLASSES)) + pent.pw_min_classes = MIN_PW_CLASSES; + else { + if(entry->pw_min_classes > MAX_PW_CLASSES || entry->pw_min_classes < MIN_PW_CLASSES) + return KADM5_BAD_CLASS; + pent.pw_min_classes = entry->pw_min_classes; + } + if (!(mask & KADM5_PW_HISTORY_NUM)) + pent.pw_history_num = MIN_PW_HISTORY; + else { + if(entry->pw_history_num < MIN_PW_HISTORY || + entry->pw_history_num > MAX_PW_HISTORY) + return KADM5_BAD_HISTORY; + else + pent.pw_history_num = entry->pw_history_num; + } + if (!(mask & KADM5_REF_COUNT)) + pent.policy_refcnt = 0; + else + pent.policy_refcnt = entry->policy_refcnt; + if ((ret = osa_adb_create_policy(handle->policy_db, &pent)) == OSA_ADB_OK) + return KADM5_OK; + else + return ret; +} + +kadm5_ret_t +kadm5_delete_policy(void *server_handle, kadm5_policy_t name) +{ + kadm5_server_handle_t handle = server_handle; + osa_policy_ent_t entry; + int ret; + + CHECK_HANDLE(server_handle); + + if(name == (kadm5_policy_t) NULL) + return EINVAL; + if(strlen(name) == 0) + return KADM5_BAD_POLICY; + if ((ret = osa_adb_get_policy(handle->policy_db, name, &entry)) != OSA_ADB_OK) + return ret; + if(entry->policy_refcnt != 0) { + osa_free_policy_ent(entry); + return KADM5_POLICY_REF; + } + osa_free_policy_ent(entry); + if ((ret = osa_adb_destroy_policy(handle->policy_db, name)) == OSA_ADB_OK) + return KADM5_OK; + else + return ret; +} + +kadm5_ret_t +kadm5_modify_policy(void *server_handle, + kadm5_policy_ent_t entry, long mask) +{ + CHECK_HANDLE(server_handle); + + if (mask & KADM5_REF_COUNT) + return KADM5_BAD_MASK; + else + return kadm5_modify_policy_internal(server_handle, entry, mask); +} + +kadm5_ret_t +kadm5_modify_policy_internal(void *server_handle, + kadm5_policy_ent_t entry, long mask) +{ + kadm5_server_handle_t handle = server_handle; + osa_policy_ent_t p; + int ret; + + CHECK_HANDLE(server_handle); + + if((entry == (kadm5_policy_ent_t) NULL) || (entry->policy == NULL)) + return EINVAL; + if(strlen(entry->policy) == 0) + return KADM5_BAD_POLICY; + if((mask & KADM5_POLICY)) + return KADM5_BAD_MASK; + + switch ((ret = osa_adb_get_policy(handle->policy_db, entry->policy, &p))) { + case OSA_ADB_OK: + break; + case OSA_ADB_NOENT: + return KADM5_UNK_POLICY; + default: + break; + } + if ((mask & KADM5_PW_MAX_LIFE)) + p->pw_max_life = entry->pw_max_life; + if ((mask & KADM5_PW_MIN_LIFE)) { + if(entry->pw_min_life > p->pw_max_life && p->pw_max_life != 0) { + osa_free_policy_ent(p); + return KADM5_BAD_MIN_PASS_LIFE; + } + p->pw_min_life = entry->pw_min_life; + } + if ((mask & KADM5_PW_MIN_LENGTH)) { + if(entry->pw_min_length < MIN_PW_LENGTH) { + osa_free_policy_ent(p); + return KADM5_BAD_LENGTH; + } + p->pw_min_length = entry->pw_min_length; + } + if ((mask & KADM5_PW_MIN_CLASSES)) { + if(entry->pw_min_classes > MAX_PW_CLASSES || + entry->pw_min_classes < MIN_PW_CLASSES) { + osa_free_policy_ent(p); + return KADM5_BAD_CLASS; + } + p->pw_min_classes = entry->pw_min_classes; + } + if ((mask & KADM5_PW_HISTORY_NUM)) { + if(entry->pw_history_num < MIN_PW_HISTORY || + entry->pw_history_num > MAX_PW_HISTORY) { + osa_free_policy_ent(p); + return KADM5_BAD_HISTORY; + } + p->pw_history_num = entry->pw_history_num; + } + if ((mask & KADM5_REF_COUNT)) + p->policy_refcnt = entry->policy_refcnt; + switch ((ret = osa_adb_put_policy(handle->policy_db, p))) { + case OSA_ADB_OK: + ret = KADM5_OK; + break; + case OSA_ADB_NOENT: /* this should not happen here ... */ + ret = KADM5_UNK_POLICY; + break; + } + osa_free_policy_ent(p); + return ret; +} + +kadm5_ret_t +kadm5_get_policy(void *server_handle, kadm5_policy_t name, + kadm5_policy_ent_t entry) +{ + osa_policy_ent_t t; + kadm5_policy_ent_rec entry_local, **entry_orig, *new; + int ret; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + /* + * In version 1, entry is a pointer to a kadm5_policy_ent_t that + * should be filled with allocated memory. + */ + if (handle->api_version == KADM5_API_VERSION_1) { + entry_orig = (kadm5_policy_ent_rec **) entry; + *entry_orig = NULL; + entry = &entry_local; + } + + if (name == (kadm5_policy_t) NULL) + return EINVAL; + if(strlen(name) == 0) + return KADM5_BAD_POLICY; + switch((ret = osa_adb_get_policy(handle->policy_db, name, &t))) { + case OSA_ADB_OK: + break; + case OSA_ADB_NOENT: + return KADM5_UNK_POLICY; + default: + return ret; + } + if ((entry->policy = (char *) malloc(strlen(t->name) + 1)) == NULL) { + osa_free_policy_ent(t); + return ENOMEM; + } + strcpy(entry->policy, t->name); + entry->pw_min_life = t->pw_min_life; + entry->pw_max_life = t->pw_max_life; + entry->pw_min_length = t->pw_min_length; + entry->pw_min_classes = t->pw_min_classes; + entry->pw_history_num = t->pw_history_num; + entry->policy_refcnt = t->policy_refcnt; + osa_free_policy_ent(t); + + if (handle->api_version == KADM5_API_VERSION_1) { + new = (kadm5_policy_ent_t) malloc(sizeof(kadm5_policy_ent_rec)); + if (new == NULL) { + free(entry->policy); + osa_free_policy_ent(t); + return ENOMEM; + } + *new = *entry; + *entry_orig = new; + } + + return KADM5_OK; +} diff --git a/src/lib/kadm5/svr_principal.c b/src/lib/kadm5/svr_principal.c new file mode 100644 index 000000000..6f9671fcf --- /dev/null +++ b/src/lib/kadm5/svr_principal.c @@ -0,0 +1,1350 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <sys/types.h> +#include <sys/time.h> +#include <kadm5/admin.h> +#include "adb.h" +#include "k5-int.h" +#include <krb5/kdb.h> +#include <stdio.h> +#include <string.h> +#include "server_internal.h" +#include <stdarg.h> +#include <stdlib.h> + +extern krb5_principal master_princ; +extern krb5_principal hist_princ; +extern krb5_encrypt_block master_encblock; +extern krb5_encrypt_block hist_encblock; +extern krb5_keyblock master_keyblock; +extern krb5_keyblock hist_key; +extern krb5_db_entry master_db; +extern krb5_db_entry hist_db; +extern krb5_kvno hist_kvno; + +static int decrypt_key_data(krb5_context context, + int n_key_data, krb5_key_data *key_data, + krb5_keyblock **keyblocks, int *n_keys); + +/* + * XXX Functions that ought to be in libkrb5.a, but aren't. + */ +int krb5_free_keyblock_contents(context, key) + krb5_context context; + krb5_keyblock *key; +{ + memset(key->contents, 0, key->length); + krb5_xfree(key->contents); + return 0; +} + +kadm5_ret_t krb5_copy_key_data_contents(context, from, to) + krb5_context context; + krb5_key_data *from, *to; +{ + int i, idx; + + *to = *from; + + idx = (from->key_data_ver == 1 ? 1 : 2); + + for (i = 0; i < idx; i++) { + to->key_data_contents[i] = malloc(from->key_data_length[i]); + if (to->key_data_contents[i] == NULL) { + for (i = 0; i < idx; i++) { + if (to->key_data_contents[i]) { + memset(to->key_data_contents[i], 0, + to->key_data_length[i]); + free(to->key_data_contents[i]); + } + } + return ENOMEM; + } + memcpy(to->key_data_contents[i], from->key_data_contents[i], + from->key_data_length[i]); + } + return 0; +} + +static krb5_tl_data *dup_tl_data(krb5_tl_data *tl) +{ + krb5_tl_data *n; + + n = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)); + if (n == NULL) + return NULL; + n->tl_data_contents = malloc(tl->tl_data_length); + if (n->tl_data_contents == NULL) { + free(n); + return NULL; + } + memcpy(n->tl_data_contents, tl->tl_data_contents, tl->tl_data_length); + n->tl_data_type = tl->tl_data_type; + n->tl_data_length = tl->tl_data_length; + n->tl_data_next = NULL; + return n; +} + +kadm5_ret_t +kadm5_create_principal(void *server_handle, + kadm5_principal_ent_t entry, long mask, + char *password) +{ + krb5_db_entry kdb; + osa_princ_ent_rec adb; + kadm5_policy_ent_rec polent; + krb5_int32 now; + krb5_tl_data *tl_data_orig, *tl_data_tail; + unsigned int ret; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + /* + * Argument sanity checking, and opening up the DB + */ + if(!(mask & KADM5_PRINCIPAL) || (mask & KADM5_MOD_NAME) || + (mask & KADM5_MOD_TIME) || (mask & KADM5_LAST_PWD_CHANGE) || + (mask & KADM5_MKVNO) || (mask & KADM5_POLICY_CLR) || + (mask & KADM5_AUX_ATTRIBUTES) || (mask & KADM5_KEY_DATA) || + (mask & KADM5_LAST_SUCCESS) || (mask & KADM5_LAST_FAILED) || + (mask & KADM5_FAIL_AUTH_COUNT)) + return KADM5_BAD_MASK; + if((mask & ~ALL_PRINC_MASK)) + return KADM5_BAD_MASK; + if (entry == (kadm5_principal_ent_t) NULL || password == NULL) + return EINVAL; + + /* + * Check to see if the principal exists + */ + ret = kdb_get_entry(handle, entry->principal, &kdb, &adb); + + switch(ret) { + case KADM5_UNK_PRINC: + break; + case 0: + kdb_free_entry(handle, &kdb, &adb); + return KADM5_DUP; + default: + return ret; + } + + memset(&kdb, 0, sizeof(krb5_db_entry)); + memset(&adb, 0, sizeof(osa_princ_ent_rec)); + + /* + * If a policy was specified, load it. + * If we can not find the one specified return an error + */ + if ((mask & KADM5_POLICY)) { + if ((ret = kadm5_get_policy(handle->lhandle, entry->policy, + &polent)) != KADM5_OK) { + if(ret == EINVAL) + return KADM5_BAD_POLICY; + else + return ret; + } + } + if (ret = passwd_check(handle, password, (mask & KADM5_POLICY), + &polent, entry->principal)) { + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return ret; + } + /* + * Start populating the various DB fields, using the + * "defaults" for fields that were not specified by the + * mask. + */ + if (ret = krb5_timeofday(handle->context, &now)) { + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return ret; + } + + kdb.magic = KRB5_KDB_MAGIC_NUMBER; + kdb.len = KRB5_KDB_V1_BASE_LENGTH; /* gag me with a chainsaw */ + + if ((mask & KADM5_ATTRIBUTES)) + kdb.attributes = entry->attributes; + else + kdb.attributes = handle->params.flags; + + if ((mask & KADM5_MAX_LIFE)) + kdb.max_life = entry->max_life; + else + kdb.max_life = handle->params.max_life; + + if (mask & KADM5_MAX_RLIFE) + kdb.max_renewable_life = entry->max_renewable_life; + else + kdb.max_renewable_life = handle->params.max_rlife; + + if ((mask & KADM5_PRINC_EXPIRE_TIME)) + kdb.expiration = entry->princ_expire_time; + else + kdb.expiration = handle->params.expiration; + + kdb.pw_expiration = 0; + if ((mask & KADM5_POLICY)) { + if(polent.pw_max_life) + kdb.pw_expiration = now + polent.pw_max_life; + else + kdb.pw_expiration = 0; + } + if ((mask & KADM5_PW_EXPIRATION)) { + if(!kdb.pw_expiration) + kdb.pw_expiration = entry->pw_expiration; + else { + if(entry->pw_expiration != 0) + kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ? + entry->pw_expiration : kdb.pw_expiration; + } + } + + kdb.last_success = 0; + kdb.last_failed = 0; + kdb.fail_auth_count = 0; + + /* this is kind of gross, but in order to free the tl data, I need + to free the entire kdb entry, and that will try to free the + principal. */ + + if (ret = krb5_copy_principal(handle->context, + entry->principal, &(kdb.princ))) { + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return(ret); + } + + if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) { + krb5_dbe_free_contents(handle->context, &kdb); + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return(ret); + } + + /* initialize the keys */ + + if (ret = krb5_dbe_cpw(handle->context, &master_encblock, + handle->params.keysalts, + handle->params.num_keysalts, + password, + (mask & KADM5_KVNO)?entry->kvno:1, &kdb)) { + krb5_dbe_free_contents(handle->context, &kdb); + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return(ret); + } + + /* populate the admin-server-specific fields. In the OV server, + this used to be in a separate database. Since there's already + marshalling code for the admin fields, to keep things simple, + I'm going to keep it, and make all the admin stuff occupy a + single tl_data record, */ + + adb.admin_history_kvno = hist_kvno; + if ((mask & KADM5_POLICY)) { + adb.aux_attributes = KADM5_POLICY; + + /* this does *not* need to be strdup'ed, because adb is xdr */ + /* encoded in osa_adb_create_princ, and not ever freed */ + + adb.policy = entry->policy; + } + + /* increment the policy ref count, if any */ + + if ((mask & KADM5_POLICY)) { + polent.policy_refcnt++; + if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, + KADM5_REF_COUNT)) + != KADM5_OK) { + krb5_dbe_free_contents(handle->context, &kdb); + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return(ret); + } + } + + if (mask & KADM5_TL_DATA) { + /* splice entry->tl_data onto the front of kdb.tl_data */ + tl_data_orig = kdb.tl_data; + for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next; + tl_data_tail = tl_data_tail->tl_data_next) + ; + tl_data_tail->tl_data_next = kdb.tl_data; + kdb.tl_data = entry->tl_data; + } + + /* store the new db entry */ + ret = kdb_put_entry(handle, &kdb, &adb); + + if (mask & KADM5_TL_DATA) { + /* remove entry->tl_data from the front of kdb.tl_data */ + tl_data_tail->tl_data_next = NULL; + kdb.tl_data = tl_data_orig; + } + + krb5_dbe_free_contents(handle->context, &kdb); + + if (ret) { + if ((mask & KADM5_POLICY)) { + /* decrement the policy ref count */ + + polent.policy_refcnt--; + /* + * if this fails, there's nothing we can do anyway. the + * policy refcount wil be too high. + */ + (void) kadm5_modify_policy_internal(handle->lhandle, &polent, + KADM5_REF_COUNT); + } + + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + return(ret); + } + + if (mask & KADM5_POLICY) + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + + return KADM5_OK; +} + + +kadm5_ret_t +kadm5_delete_principal(void *server_handle, krb5_principal principal) +{ + unsigned int ret; + kadm5_policy_ent_rec polent; + krb5_db_entry kdb; + osa_princ_ent_rec adb; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if (principal == NULL) + return EINVAL; + + if (ret = kdb_get_entry(handle, principal, &kdb, &adb)) + return(ret); + + if ((adb.aux_attributes & KADM5_POLICY)) { + if ((ret = kadm5_get_policy(handle->lhandle, + adb.policy, &polent)) + == KADM5_OK) { + polent.policy_refcnt--; + if ((ret = kadm5_modify_policy_internal(handle->lhandle, &polent, + KADM5_REF_COUNT)) + != KADM5_OK) { + (void) kadm5_free_policy_ent(handle->lhandle, &polent); + kdb_free_entry(handle, &kdb, &adb); + return(ret); + } + } + if (ret = kadm5_free_policy_ent(handle->lhandle, &polent)) { + kdb_free_entry(handle, &kdb, &adb); + return ret; + } + } + + ret = kdb_delete_entry(handle, principal); + + kdb_free_entry(handle, &kdb, &adb); + + return ret; +} + +kadm5_ret_t +kadm5_modify_principal(void *server_handle, + kadm5_principal_ent_t entry, long mask) +{ + int ret, ret2, i; + kadm5_policy_ent_rec npol, opol; + int have_npol = 0, have_opol = 0; + krb5_db_entry kdb; + krb5_tl_data *tl_data_orig, *tl_data_tail; + osa_princ_ent_rec adb; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if((mask & KADM5_PRINCIPAL) || (mask & KADM5_LAST_PWD_CHANGE) || + (mask & KADM5_MOD_TIME) || (mask & KADM5_MOD_NAME) || + (mask & KADM5_MKVNO) || (mask & KADM5_AUX_ATTRIBUTES) || + (mask & KADM5_KEY_DATA) || (mask & KADM5_LAST_SUCCESS) || + (mask & KADM5_LAST_FAILED)) + return KADM5_BAD_MASK; + if((mask & ~ALL_PRINC_MASK)) + return KADM5_BAD_MASK; + if((mask & KADM5_POLICY) && (mask & KADM5_POLICY_CLR)) + return KADM5_BAD_MASK; + if(entry == (kadm5_principal_ent_t) NULL) + return EINVAL; + + if (ret = kdb_get_entry(handle, entry->principal, &kdb, &adb)) + return(ret); + + /* + * This is pretty much the same as create ... + */ + + if ((mask & KADM5_POLICY)) { + ret = kadm5_get_policy(handle->lhandle, entry->policy, &npol); + switch(ret) { + case EINVAL: + ret = KADM5_BAD_POLICY; + break; + case KADM5_UNK_POLICY: + case KADM5_BAD_POLICY: + ret = KADM5_UNK_POLICY; + goto done; + break; + case KADM5_OK: + have_npol = 1; + if(adb.aux_attributes & KADM5_POLICY) { + if(strcmp(adb.policy, entry->policy)) { + ret = kadm5_get_policy(handle->lhandle, + adb.policy, &opol); + switch(ret) { + case EINVAL: + case KADM5_BAD_POLICY: + case KADM5_UNK_POLICY: + break; + case KADM5_OK: + have_opol = 1; + opol.policy_refcnt--; + break; + default: + goto done; + break; + } + npol.policy_refcnt++; + } + } else npol.policy_refcnt++; + adb.aux_attributes |= KADM5_POLICY; + if (adb.policy) + free(adb.policy); + adb.policy = strdup(entry->policy); + if (npol.pw_max_life) { + if (ret = + krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, + &(kdb.pw_expiration))) + goto done; + kdb.pw_expiration += npol.pw_max_life; + } else { + kdb.pw_expiration = 0; + } + break; + default: + goto done; + } + if ((mask & KADM5_PW_EXPIRATION)) { + if(kdb.pw_expiration == 0) + kdb.pw_expiration = entry->pw_expiration; + else if(entry->pw_expiration != 0) + kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ? + entry->pw_expiration : kdb.pw_expiration; + } + } + if ((mask & KADM5_PW_EXPIRATION) && !(mask & KADM5_POLICY)) { + if(kdb.pw_expiration == 0) + kdb.pw_expiration = entry->pw_expiration; + else if(entry->pw_expiration != 0) + kdb.pw_expiration = (entry->pw_expiration < kdb.pw_expiration) ? + entry->pw_expiration : kdb.pw_expiration; + } + + if ((mask & KADM5_POLICY_CLR)) { + if (adb.aux_attributes & KADM5_POLICY) { + adb.aux_attributes &= ~KADM5_POLICY; + kdb.pw_expiration = 0; + ret = kadm5_get_policy(handle->lhandle, adb.policy, &opol); + switch(ret) { + case EINVAL: + case KADM5_BAD_POLICY: + case KADM5_UNK_POLICY: + ret = KADM5_BAD_DB; + goto done; + break; + case KADM5_OK: + have_opol = 1; + if (adb.policy) + free(adb.policy); + adb.policy = NULL; + opol.policy_refcnt--; + break; + default: + goto done; + break; + } + } + } + if (((mask & KADM5_POLICY) || + (mask & KADM5_POLICY_CLR)) && + (((have_opol) && + (ret = + kadm5_modify_policy_internal(handle->lhandle, &opol, + KADM5_REF_COUNT))) || + ((have_npol) && + (ret = + kadm5_modify_policy_internal(handle->lhandle, &npol, + KADM5_REF_COUNT))))) + goto done; + + if ((mask & KADM5_ATTRIBUTES)) + kdb.attributes = entry->attributes; + if ((mask & KADM5_MAX_LIFE)) + kdb.max_life = entry->max_life; + if ((mask & KADM5_PRINC_EXPIRE_TIME)) + kdb.expiration = entry->princ_expire_time; + /* the pw_expiration logic would go here if it wasn't spread + all over the policy code */ + if (mask & KADM5_MAX_RLIFE) + kdb.max_renewable_life = entry->max_renewable_life; + if (mask & KADM5_FAIL_AUTH_COUNT) + kdb.fail_auth_count = entry->fail_auth_count; + + if((mask & KADM5_KVNO)) { + for (i = 0; i < kdb.n_key_data; i++) + kdb.key_data[i].key_data_kvno = entry->kvno; + } + + if (mask & KADM5_TL_DATA) { + /* splice entry->tl_data onto the front of kdb.tl_data */ + tl_data_orig = kdb.tl_data; + for (tl_data_tail = entry->tl_data; tl_data_tail->tl_data_next; + tl_data_tail = tl_data_tail->tl_data_next) + ; + tl_data_tail->tl_data_next = kdb.tl_data; + kdb.tl_data = entry->tl_data; + } + + if ((ret = kdb_put_entry(handle, &kdb, &adb))) + goto done; + + if (mask & KADM5_TL_DATA) { + /* remove entry->tl_data from the front of kdb.tl_data */ + tl_data_tail->tl_data_next = NULL; + kdb.tl_data = tl_data_orig; + } + + ret = KADM5_OK; +done: + if (have_opol) { + ret2 = kadm5_free_policy_ent(handle->lhandle, &opol); + ret = ret ? ret : ret2; + } + if (have_npol) { + ret2 = kadm5_free_policy_ent(handle->lhandle, &npol); + ret = ret ? ret : ret2; + } + kdb_free_entry(handle, &kdb, &adb); + return ret; +} + +kadm5_ret_t +kadm5_rename_principal(void *server_handle, + krb5_principal source, krb5_principal target) +{ + krb5_db_entry kdb; + osa_princ_ent_rec adb; + int ret, i; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + + if (source == NULL || target == NULL) + return EINVAL; + + if ((ret = kdb_get_entry(handle, target, &kdb, &adb)) == 0) { + kdb_free_entry(handle, &kdb, &adb); + return(KADM5_DUP); + } + + if ((ret = kdb_get_entry(handle, source, &kdb, &adb))) + return ret; + + /* this is kinda gross, but unavoidable */ + + for (i=0; i<kdb.n_key_data; i++) { + if ((kdb.key_data[i].key_data_ver == 1) || + (kdb.key_data[i].key_data_type[1] == KRB5_KDB_SALTTYPE_NORMAL)) { + ret = KADM5_NO_RENAME_SALT; + goto done; + } + } + + krb5_free_principal(handle->context, kdb.princ); + if (ret = krb5_copy_principal(handle->context, target, &kdb.princ)) { + kdb.princ = NULL; /* so freeing the dbe doesn't lose */ + goto done; + } + + if ((ret = kdb_put_entry(handle, &kdb, &adb))) + goto done; + + ret = kdb_delete_entry(handle, source); + +done: + kdb_free_entry(handle, &kdb, &adb); + return ret; +} + +kadm5_ret_t +kadm5_get_principal(void *server_handle, krb5_principal principal, + kadm5_principal_ent_t entry, + long in_mask) +{ + krb5_db_entry kdb; + osa_princ_ent_rec adb; + osa_adb_ret_t ret = 0; + long mask; + int i; + kadm5_server_handle_t handle = server_handle; + kadm5_principal_ent_rec entry_local, *entry_orig; + + CHECK_HANDLE(server_handle); + + /* + * In version 1, all the defined fields are always returned. + * entry is a pointer to a kadm5_principal_ent_t_v1 that should be + * filled with allocated memory. + */ + if (handle->api_version == KADM5_API_VERSION_1) { + mask = KADM5_PRINCIPAL_NORMAL_MASK; + entry_orig = entry; + entry = &entry_local; + } else { + mask = in_mask; + } + + memset((char *) entry, 0, sizeof(*entry)); + + if (principal == NULL) + return EINVAL; + + if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) + return ret; + + if ((mask & KADM5_POLICY) && + adb.policy && (adb.aux_attributes & KADM5_POLICY)) { + if ((entry->policy = (char *) malloc(strlen(adb.policy) + 1)) == NULL) { + ret = ENOMEM; + goto done; + } + strcpy(entry->policy, adb.policy); + } + + if (mask & KADM5_AUX_ATTRIBUTES) + entry->aux_attributes = adb.aux_attributes; + + if ((mask & KADM5_PRINCIPAL) && + (ret = krb5_copy_principal(handle->context, principal, + &entry->principal))) { + goto done; + } + + if (mask & KADM5_PRINC_EXPIRE_TIME) + entry->princ_expire_time = kdb.expiration; + + if ((mask & KADM5_LAST_PWD_CHANGE) && + (ret = krb5_dbe_lookup_last_pwd_change(handle->context, &kdb, + &(entry->last_pwd_change)))) { + goto done; + } + + if (mask & KADM5_PW_EXPIRATION) + entry->pw_expiration = kdb.pw_expiration; + if (mask & KADM5_MAX_LIFE) + entry->max_life = kdb.max_life; + + /* this is a little non-sensical because the function returns two */ + /* values that must be checked separately against the mask */ + if ((mask & KADM5_MOD_NAME) || (mask & KADM5_MOD_TIME)) { + if (ret = krb5_dbe_lookup_mod_princ_data(handle->context, &kdb, + &(entry->mod_date), + &(entry->mod_name))) { + goto done; + } + if (! (mask & KADM5_MOD_TIME)) + entry->mod_date = 0; + if (! (mask & KADM5_MOD_NAME)) { + krb5_free_principal(handle->context, entry->principal); + entry->principal = NULL; + } + } + + if (mask & KADM5_ATTRIBUTES) + entry->attributes = kdb.attributes; + + if (mask & KADM5_KVNO) + for (entry->kvno = 0, i=0; i<kdb.n_key_data; i++) + if (kdb.key_data[i].key_data_kvno > entry->kvno) + entry->kvno = kdb.key_data[i].key_data_kvno; + + if (handle->api_version == KADM5_API_VERSION_2) + entry->mkvno = 0; + else { + /* XXX I'll be damned if I know how to deal with this one --marc */ + entry->mkvno = 1; + } + + /* + * The new fields that only exist in version 2 start here + */ + if (handle->api_version == KADM5_API_VERSION_2) { + if (mask & KADM5_MAX_RLIFE) + entry->max_renewable_life = kdb.max_renewable_life; + if (mask & KADM5_LAST_SUCCESS) + entry->last_success = kdb.last_success; + if (mask & KADM5_LAST_FAILED) + entry->last_failed = kdb.last_failed; + if (mask & KADM5_FAIL_AUTH_COUNT) + entry->fail_auth_count = kdb.fail_auth_count; + if (mask & KADM5_TL_DATA) { + krb5_tl_data td, *tl, *tl2; + + entry->n_tl_data = kdb.n_tl_data; + entry->tl_data = NULL; + + tl = kdb.tl_data; + while (tl) { + if ((tl2 = dup_tl_data(tl)) == NULL) { + ret = ENOMEM; + goto done; + } + tl2->tl_data_next = entry->tl_data; + entry->tl_data = tl2; + + tl = tl->tl_data_next; + } + + if (kdb.e_length) { + td.tl_data_type = KRB5_TL_KADM5_E_DATA; + td.tl_data_length = kdb.e_length; + td.tl_data_contents = kdb.e_data; + + if ((tl = dup_tl_data(&td)) == NULL) { + ret = ENOMEM; + goto done; + } + tl->tl_data_next = entry->tl_data; + entry->tl_data = tl; + } + } + if (mask & KADM5_KEY_DATA) { + entry->n_key_data = kdb.n_key_data; + entry->key_data = (krb5_key_data *) + malloc(entry->n_key_data*sizeof(krb5_key_data)); + if (entry->key_data == NULL) { + ret = ENOMEM; + goto done; + } + for (i = 0; i < entry->n_key_data; i++) + if (ret = krb5_copy_key_data_contents(handle->context, + &kdb.key_data[i], + &entry->key_data[i])) + goto done; + } + } + + /* + * If KADM5_API_VERSION_1, we return an allocated structure, and + * we need to convert the new structure back into the format the + * caller is expecting. + */ + if (handle->api_version == KADM5_API_VERSION_1) { + kadm5_principal_ent_t_v1 newv1; + + newv1 = ((kadm5_principal_ent_t_v1) calloc(1, sizeof(*newv1))); + if (newv1 == NULL) { + ret = ENOMEM; + goto done; + } + + newv1->principal = entry->principal; + newv1->princ_expire_time = entry->princ_expire_time; + newv1->last_pwd_change = entry->last_pwd_change; + newv1->pw_expiration = entry->pw_expiration; + newv1->max_life = entry->max_life; + newv1->mod_name = entry->mod_name; + newv1->mod_date = entry->mod_date; + newv1->attributes = entry->attributes; + newv1->kvno = entry->kvno; + newv1->mkvno = entry->mkvno; + newv1->policy = entry->policy; + newv1->aux_attributes = entry->aux_attributes; + + *((kadm5_principal_ent_t_v1 *) entry_orig) = newv1; + } + + ret = KADM5_OK; + +done: + if (ret && entry->principal) + krb5_free_principal(handle->context, entry->principal); + kdb_free_entry(handle, &kdb, &adb); + + return ret; +} + +/* + * Function: check_pw_reuse + * + * Purpose: Check if a key appears in a list of keys, in order to + * enforce password history. + * + * Arguments: + * + * context (r) the krb5 context + * histkey_encblock (r) the encblock that hist_key_data is + * encrypted in + * n_new_key_data (r) length of new_key_data + * new_key_data (r) keys to check against + * pw_hist_data, encrypted in histkey_encblock + * n_pw_hist_data (r) length of pw_hist_data + * pw_hist_data (r) passwords to check new_key_data against + * + * Effects: + * For each new_key in new_key_data: + * decrypt new_key with the master_encblock + * for each password in pw_hist_data: + * for each hist_key in password: + * decrypt hist_key with histkey_encblock + * compare the new_key and hist_key + * + * Returns krb5 errors, KADM5_PASS_RESUSE if a key in + * new_key_data is the same as a key in pw_hist_data, or 0. + */ +static kadm5_ret_t +check_pw_reuse(krb5_context context, + krb5_encrypt_block *histkey_encblock, + int n_new_key_data, krb5_key_data *new_key_data, + int n_pw_hist_data, osa_pw_hist_ent *pw_hist_data) +{ + int x, y, z; + krb5_keyblock newkey, histkey; + krb5_error_code ret; + + for (x = 0; x < n_new_key_data; x++) { + if (ret = krb5_dbekd_decrypt_key_data(context, + &master_encblock, + &(new_key_data[x]), + &newkey, NULL)) + return(ret); + for (y = 0; y < n_pw_hist_data; y++) { + for (z = 0; z < pw_hist_data[y].n_key_data; z++) { + if (ret = + krb5_dbekd_decrypt_key_data(context, + histkey_encblock, + &pw_hist_data[y].key_data[z], + &histkey, NULL)) + return(ret); + + if ((newkey.length == histkey.length) && + (newkey.enctype == histkey.enctype) && + (memcmp(newkey.contents, histkey.contents, + histkey.length) == 0)) { + krb5_free_keyblock_contents(context, &histkey); + krb5_free_keyblock_contents(context, &newkey); + + return(KADM5_PASS_REUSE); + } + krb5_free_keyblock_contents(context, &histkey); + } + } + krb5_free_keyblock_contents(context, &newkey); + } + + return(0); +} + +/* + * Function: create_history_entry + * + * Purpose: Creates a password history entry from an array of + * key_data. + * + * Arguments: + * + * context (r) krb5_context to use + * n_key_data (r) number of elements in key_data + * key_data (r) keys to add to the history entry + * hist (w) history entry to fill in + * + * Effects: + * + * hist->key_data is allocated to store n_key_data key_datas. Each + * element of key_data is decrypted with master_encblock, re-encrypted + * in hist_encblock, and added to hist->key_data. hist->n_key_data is + * set to n_key_data. + */ +int create_history_entry(krb5_context context, int n_key_data, + krb5_key_data *key_data, osa_pw_hist_ent *hist) +{ + int i, ret; + krb5_keyblock key; + krb5_keysalt salt; + + hist->key_data = (krb5_key_data*)malloc(n_key_data*sizeof(krb5_key_data)); + if (hist->key_data == NULL) + return ENOMEM; + memset(hist->key_data, 0, n_key_data*sizeof(krb5_key_data)); + + for (i = 0; i < n_key_data; i++) { + if (ret = krb5_dbekd_decrypt_key_data(context, + &master_encblock, + &key_data[i], + &key, &salt)) + return ret; + if (ret = krb5_dbekd_encrypt_key_data(context, + &hist_encblock, + &key, &salt, + key_data[i].key_data_kvno, + &hist->key_data[i])) + return ret; + krb5_free_keyblock_contents(context, &key); + /* krb5_free_keysalt(context, &salt); */ + } + + hist->n_key_data = n_key_data; + return 0; +} + +int free_history_entry(krb5_context context, osa_pw_hist_ent *hist) +{ + int i; + + for (i = 0; i < hist->n_key_data; i++) + krb5_free_key_data_contents(context, &hist->key_data[i]); + free(hist->key_data); +} + +/* + * Function: add_to_history + * + * Purpose: Adds a password to a principal's password history. + * + * Arguments: + * + * context (r) krb5_context to use + * adb (r/w) admin principal entry to add keys to + * pol (r) adb's policy + * pw (r) keys for the password to add to adb's key history + * + * Effects: + * + * add_to_history adds a single password to adb's password history. + * pw contains n_key_data keys in its key_data, in storage should be + * allocated but not freed by the caller (XXX blech!). + * + * This function maintains adb->old_keys as a circular queue. It + * starts empty, and grows each time this function is called until it + * is pol->pw_history_num items long. adb->old_key_len holds the + * number of allocated entries in the array, and must therefore be [0, + * pol->pw_history_num). adb->old_key_next is the index into the + * array where the next element should be written, and must be [0, + * adb->old_key_len). + */ +static kadm5_ret_t add_to_history(krb5_context context, + osa_princ_ent_t adb, + kadm5_policy_ent_t pol, + osa_pw_hist_ent *pw) +{ + osa_pw_hist_ent hist, *histp; + int ret, i; + + /* A history of 1 means just check the current password */ + if (pol->pw_history_num == 1) + return 0; + + /* resize the adb->old_keys array if necessary */ + if (adb->old_key_len < pol->pw_history_num-1) { + adb->old_keys = (osa_pw_hist_ent *) + realloc(adb->old_keys, + (adb->old_key_len+1)*sizeof(osa_pw_hist_ent)); + if (adb->old_keys == NULL) + return(ENOMEM); + + memset(&adb->old_keys[adb->old_key_len],0,sizeof(osa_pw_hist_ent)); + adb->old_key_len++; + } + + /* free the old pw history entry if it contains data */ + histp = &adb->old_keys[adb->old_key_next]; + for (i = 0; i < histp->n_key_data; i++) + krb5_free_key_data_contents(context, &histp->key_data[i]); + + /* store the new entry */ + adb->old_keys[adb->old_key_next] = *pw; + + /* update the next pointer */ + if (++adb->old_key_next == pol->pw_history_num-1) + adb->old_key_next = 0; + + return(0); +} + +kadm5_ret_t +kadm5_chpass_principal(void *server_handle, + krb5_principal principal, char *password) +{ + krb5_int32 now; + kadm5_policy_ent_rec pol; + osa_princ_ent_rec adb; + krb5_db_entry kdb, kdb_save; + int ret, ret2, last_pwd, i, hist_added; + int have_pol = 0; + kadm5_server_handle_t handle = server_handle; + osa_pw_hist_ent hist; + + CHECK_HANDLE(server_handle); + + hist_added = 0; + memset(&hist, 0, sizeof(hist)); + + if (principal == NULL || password == NULL) + return EINVAL; + if ((krb5_principal_compare(handle->context, + principal, hist_princ)) == TRUE) + return KADM5_PROTECT_PRINCIPAL; + + if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) + return(ret); + + /* we are going to need the current keys after the new keys are set */ + if ((ret = kdb_get_entry(handle, principal, &kdb_save, NULL))) { + kdb_free_entry(handle, &kdb, &adb); + return(ret); + } + + if ((adb.aux_attributes & KADM5_POLICY)) { + if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, &pol))) + goto done; + have_pol = 1; + } + + if ((ret = passwd_check(handle, password, adb.aux_attributes & + KADM5_POLICY, &pol, principal))) + goto done; + + if (ret = krb5_dbe_cpw(handle->context, &master_encblock, + handle->params.keysalts, + handle->params.num_keysalts, + password, 0 /* increment kvno */, &kdb)) + goto done; + + kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; + + if (ret = krb5_timeofday(handle->context, &now)) + goto done; + + if ((adb.aux_attributes & KADM5_POLICY)) { + /* the policy was loaded before */ + + if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, + &kdb, &last_pwd)) + goto done; + +#if 0 + /* + * The spec says this check is overridden if the caller has + * modify privilege. The admin server therefore makes this + * check itself (in chpass_principal_wrapper, misc.c). A + * local caller implicitly has all authorization bits. + */ + if ((now - last_pwd) < pol.pw_min_life && + !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + ret = KADM5_PASS_TOOSOON; + goto done; + } +#endif + + if (ret = create_history_entry(handle->context, + kdb_save.n_key_data, + kdb_save.key_data, &hist)) + goto done; + + if (ret = check_pw_reuse(handle->context, + &hist_encblock, + kdb.n_key_data, kdb.key_data, + 1, &hist)) + goto done; + + if (pol.pw_history_num > 1) { + if (adb.admin_history_kvno != hist_kvno) { + ret = KADM5_BAD_HIST_KEY; + goto done; + } + + if (ret = check_pw_reuse(handle->context, + &hist_encblock, + kdb.n_key_data, kdb.key_data, + adb.old_key_len, adb.old_keys)) + goto done; + + if (ret = add_to_history(handle->context, &adb, &pol, &hist)) + goto done; + hist_added = 1; + } + + if (pol.pw_max_life) + kdb.pw_expiration = now + pol.pw_max_life; + else + kdb.pw_expiration = 0; + } else { + kdb.pw_expiration = 0; + } + + if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) + goto done; + + if ((ret = kdb_put_entry(handle, &kdb, &adb))) + goto done; + + ret = KADM5_OK; +done: + if (!hist_added && hist.key_data) + free_history_entry(handle->context, &hist); + kdb_free_entry(handle, &kdb, &adb); + kdb_free_entry(handle, &kdb_save, NULL); + krb5_dbe_free_contents(handle->context, &kdb); + + if (have_pol && (ret2 = kadm5_free_policy_ent(handle->lhandle, &pol)) + && !ret) + ret = ret2; + + return ret; +} + +kadm5_ret_t +kadm5_randkey_principal(void *server_handle, + krb5_principal principal, + krb5_keyblock **keyblocks, + int *n_keys) +{ + krb5_db_entry kdb; + osa_princ_ent_rec adb; + krb5_int32 now; + kadm5_policy_ent_rec pol; + krb5_key_data *key_data; + krb5_keyblock *keyblock; + int ret, last_pwd, have_pol = 0; + kadm5_server_handle_t handle = server_handle; + + if (keyblocks) + *keyblocks = NULL; + + CHECK_HANDLE(server_handle); + + if (principal == NULL) + return EINVAL; + if (hist_princ && /* this will be NULL when initializing the databse */ + ((krb5_principal_compare(handle->context, + principal, hist_princ)) == TRUE)) + return KADM5_PROTECT_PRINCIPAL; + + if ((ret = kdb_get_entry(handle, principal, &kdb, &adb))) + return(ret); + + if (ret = krb5_dbe_crk(handle->context, &master_encblock, + handle->params.keysalts, + handle->params.num_keysalts, + &kdb)) + goto done; + + kdb.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; + + if (ret = krb5_timeofday(handle->context, &now)) + goto done; + + if ((adb.aux_attributes & KADM5_POLICY)) { + if ((ret = kadm5_get_policy(handle->lhandle, adb.policy, + &pol)) != KADM5_OK) + goto done; + have_pol = 1; + + if (ret = krb5_dbe_lookup_last_pwd_change(handle->context, + &kdb, &last_pwd)) + goto done; + +#if 0 + /* + * The spec says this check is overridden if the caller has + * modify privilege. The admin server therefore makes this + * check itself (in chpass_principal_wrapper, misc.c). A + * local caller implicitly has all authorization bits. + */ + if((now - last_pwd) < pol.pw_min_life && + !(kdb.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + ret = KADM5_PASS_TOOSOON; + goto done; + } +#endif + + if(pol.pw_history_num > 1) { + if(adb.admin_history_kvno != hist_kvno) { + ret = KADM5_BAD_HIST_KEY; + goto done; + } + + if (ret = check_pw_reuse(handle->context, + &hist_encblock, + kdb.n_key_data, kdb.key_data, + adb.old_key_len, adb.old_keys)) + goto done; + } + if (pol.pw_max_life) + kdb.pw_expiration = now + pol.pw_max_life; + else + kdb.pw_expiration = 0; + } else { + kdb.pw_expiration = 0; + } + + if (ret = krb5_dbe_update_last_pwd_change(handle->context, &kdb, now)) + goto done; + + if (keyblocks) { + if (handle->api_version == KADM5_API_VERSION_1) { + /* Version 1 clients will expect to see a DES_CRC enctype. */ + if (ret = krb5_dbe_find_enctype(handle->context, &kdb, + ENCTYPE_DES_CBC_CRC, + -1, -1, &key_data)) + goto done; + + if (ret = decrypt_key_data(handle->context, 1, key_data, + keyblocks, NULL)) + goto done; + } else { + ret = decrypt_key_data(handle->context, + kdb.n_key_data, kdb.key_data, + keyblocks, n_keys); + if (ret) + goto done; + } + } + + if ((ret = kdb_put_entry(handle, &kdb, &adb))) + goto done; + + ret = KADM5_OK; +done: + kdb_free_entry(handle, &kdb, &adb); + if (have_pol) + kadm5_free_policy_ent(handle->lhandle, &pol); + + return ret; +} + +/* + * Allocate an array of n_key_data krb5_keyblocks, fill in each + * element with the results of decrypting the nth key in key_data with + * master_encblock, and if n_keys is not NULL fill it in with the + * number of keys decrypted. + */ +static int decrypt_key_data(krb5_context context, + int n_key_data, krb5_key_data *key_data, + krb5_keyblock **keyblocks, int *n_keys) +{ + krb5_keyblock *keys; + int ret, i; + + keys = (krb5_keyblock *) malloc(n_key_data*sizeof(krb5_keyblock)); + if (keys == NULL) + return ENOMEM; + memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); + + for (i = 0; i < n_key_data; i++) { + if (ret = krb5_dbekd_decrypt_key_data(context, + &master_encblock, + &key_data[i], + &keys[i], NULL)) { + + memset((char *) keys, 0, n_key_data*sizeof(krb5_keyblock)); + free(keys); + return ret; + } + } + + *keyblocks = keys; + if (n_keys) + *n_keys = n_key_data; + + return 0; +} + +/* + * Function: kadm5_decrypt_key + * + * Purpose: Retrieves and decrypts a principal key. + * + * Arguments: + * + * server_handle (r) kadm5 handle + * entry (r) principal retrieved with kadm5_get_principal + * ktype (r) enctype to search for, or -1 to ignore + * stype (r) salt type to search for, or -1 to ignore + * kvno (r) kvno to search for, -1 for max, 0 for max + * only if it also matches ktype and stype + * keyblock (w) keyblock to fill in + * keysalt (w) keysalt to fill in, or NULL + * kvnop (w) kvno to fill in, or NULL + * + * Effects: Searches the key_data array of entry, which must have been + * retrived with kadm5_get_principal with the KADM5_KEY_DATA mask, to + * find a key with a specified enctype, salt type, and kvno in a + * principal entry. If not found, return ENOENT. Otherwise, decrypt + * it with the master key, and return the key in keyblock, the salt + * in salttype, and the key version number in kvno. + * + * If ktype or stype is -1, it is ignored for the search. If kvno is + * -1, ktype and stype are ignored and the key with the max kvno is + * returned. If kvno is 0, only the key with the max kvno is returned + * and only if it matches the ktype and stype; otherwise, ENOENT is + * returned. + */ +kadm5_ret_t kadm5_decrypt_key(void *server_handle, + kadm5_principal_ent_t entry, krb5_int32 + ktype, krb5_int32 stype, krb5_int32 + kvno, krb5_keyblock *keyblock, + krb5_keysalt *keysalt, int *kvnop) +{ + kadm5_server_handle_t handle = server_handle; + krb5_db_entry dbent; + krb5_key_data *key_data; + int ret; + + CHECK_HANDLE(server_handle); + + if (entry->n_key_data == 0 || entry->key_data == NULL) + return EINVAL; + + /* find_enctype only uses these two fields */ + dbent.n_key_data = entry->n_key_data; + dbent.key_data = entry->key_data; + if (ret = krb5_dbe_find_enctype(handle->context, &dbent, ktype, + stype, kvno, &key_data)) + return ret; + + if (ret = krb5_dbekd_decrypt_key_data(handle->context, + &master_encblock, key_data, + keyblock, keysalt)) + return ret; + + if (kvnop) + *kvnop = key_data->key_data_kvno; + + return KADM5_OK; +} diff --git a/src/lib/kadm5/unit-test/ChangeLog b/src/lib/kadm5/unit-test/ChangeLog new file mode 100644 index 000000000..172084c20 --- /dev/null +++ b/src/lib/kadm5/unit-test/ChangeLog @@ -0,0 +1,18 @@ +Thu Jul 18 20:18:30 1996 Marc Horowitz <marc@mit.edu> + + * api.2/init-v2.exp (test150, test151): -s flag is now -S + +Mon Jul 8 17:00:26 1996 Barry Jaspan <bjaspan@mit.edu> + + * api.2/init-v2.exp: admin databases must now be created before + use (not created implicitly) + + * api.1/lock.exp: lock-test 13 should be a warning, not a failure. + + * api.0/rename-principal.exp: fix rename test to create principal + with correct salt first, and check explicitly for NO_RENAME_SALT + when appropriate + + * lib.t: add create_principal_with_keysalts + + diff --git a/src/lib/kadm5/unit-test/Makefile.ov b/src/lib/kadm5/unit-test/Makefile.ov new file mode 100644 index 000000000..208bedeb3 --- /dev/null +++ b/src/lib/kadm5/unit-test/Makefile.ov @@ -0,0 +1,154 @@ +TOP = ../../../kadmin +include $(TOP)/config.mk/template + +CFLAGS := $(CFLAGS) -DUSE_KADM5_API_VERSION=1 + +LIBS := $(LIBADMCLNT) $(LIBCOM_ERR) $(LIBRPCLIB) $(LIBDYN) \ + $(LIBGSSAPI_KRB5) $(LIBKDB5) \ + $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) $(LIBTCL) $(LIBM) \ + $(LIBDB) $(NDBMLIB) $(BSDLIB) $(NETLIB) + +INIT_SRCS = init-test.c ../client_init.c +DESTROY_SRCS = destroy-test.c +HANDLE_SRCS = handle-test.c +RANDKEY_SRCS = randkey-test.c +ITER_SRCS = iter-test.c +LOCKTEST_SRCS = lock-test.c +SIZE_SRCS = sizes-test.c + +PROG = init-test +SRCS = $(INIT_SRCS) +OBJS = init-test.o client_init.o + +client_init.o: ../client_init.c + $(CC) $(CFLAGS) -DUSE_KADM5_API_VERSION=2 -DINIT_TEST -c -I.. $< + +expand Program + +PROG = destroy-test +SRCS = $(DESTROY_SRCS) +OBJS = destroy-test.o + +expand Program + +PROG = client-handle-test +SRCS = $(HANDLE_SRCS) +OBJS = handle-test.o + +expand Program + +PROG = client-iter-test +SRCS = $(ITER_SRCS) +OBJS = iter-test.o + +expand Program + +LIBS := $(LIBADMSRV) $(LIBCOM_ERR) $(LIBRPCLIB) $(LIBDYN) \ + $(LIBGSSAPI_KRB5) $(LIBKDB5) $(LIBKRB5) \ + $(LIBCRYPTO) $(LIBISODE) $(LIBTCL) $(LIBM) $(LIBDB) \ + $(NDBMLIB) $(BSDLIB) $(NETLIB) + +PROG = randkey-test +SRCS = $(RANDKEY_SRCS) +OBJS = randkey-test.o + +expand Program + +PROG = server-handle-test +SRCS = $(HANDLE_SRCS) +OBJS = handle-test.o + +expand Program + +PROG = lock-test +SRCS = $(LOCKTEST_SRCS) +OBJS = lock-test.o + +expand Program + +LIBS := $(LIBS) $(REGEXLIB) +PROG = server-iter-test +SRCS = $(ITER_SRCS) +OBJS = iter-test.o + +expand Program + +PROG = sizes-test +SRCS = $(SIZE_SRCS) +OBJS = sizes-test.o + +expand Program + +SRCS = $(INIT_SRCS) $(DESTROY_SRCS) $(HANDLE_SRCS) \ + $(RANDKEY_SRCS) $(LOCKTEST_SRCS) $(ITER_SRCS) \ + $(SIZE_SRCS) + +expand Depend + +unit-test:: unit-test-client unit-test-server + +unit-test-client: unit-test-client-setup unit-test-client-body \ + unit-test-client-cleanup + +unit-test-server: unit-test-server-setup unit-test-server-body \ + unit-test-server-cleanup + +test-randkey:: randkey-test + ./randkey-test + +test-handle-server:: server-handle-test + ./server-handle-test + +test-handle-client:: client-handle-test + ./client-handle-test + +test-noauth: init-test + ./init-test + +test-destroy: destroy-test + ./destroy-test + +test-sizes: sizes-test + ./sizes-test + +unit-test-client-setup:: + $(START_SERVERS) + +unit-test-client-cleanup:: + $(STOP_SERVERS) + +unit-test-server-setup:: + $(START_SERVERS_LOCAL) + +unit-test-server-cleanup:: + $(STOP_SERVERS_LOCAL) + +capi.0: api.0 + -rm -f capi.0 + ln -s api.0 capi.0 + +capi.2: api.2 + -rm -f capi.2 + ln -s api.2 capi.2 + +unit-test-client-body: capi.0 capi.2 site.exp test-noauth test-destroy test-handle-client test-sizes + $(RUNTEST) --tool capi API=$(CLNTTCL) KDBFIVE_EDIT=$(TOP)/../admin/edit/kdb5_edit KINIT=$(TOP)/../clients/kinit/kinit KDESTROY=$(TOP)/../clients/kdestroy/kdestroy KADMIN_LOCAL=$(TOP)/cli/kadmin.local TOP=$(TOP) RPC=1 + +sapi.0: api.0 + -rm -f sapi.0 + ln -s api.0 sapi.0 + +sapi.1: api.1 + -rm -f sapi.1 + ln -s api.1 sapi.1 + +sapi.2: api.2 + -rm -f sapi.2 + ln -s api.2 sapi.2 + +unit-test-server-body: sapi.0 sapi.1 sapi.2 site.exp randkey-test test-handle-server \ + lock-test test-sizes + $(RUNTEST) --tool sapi API=$(SRVTCL) LOCKTEST=./lock-test KDBFIVE_EDIT=$(TOP)/../admin/edit/kdb5_edit KADMIN_LOCAL=$(TOP)/cli/kadmin.local TOP=$(TOP) RPC=0 + +clean:: + $(CLEAN) -r *.log *.plog *.sum *.psum unit-test-log.* diff --git a/src/lib/kadm5/unit-test/api.0/chpass-principal.exp b/src/lib/kadm5/unit-test/api.0/chpass-principal.exp new file mode 100644 index 000000000..12fa3b9d1 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/chpass-principal.exp @@ -0,0 +1,176 @@ +source lib.t +api_exit +api_start + +test "chpass-principal 180" +proc test180 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_chpass_principal $server_handle "%s/a" FoobarBax + } $test] + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test180 } + +test "chpass-principal 180.5" +proc test1805 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_chpass_principal $server_handle "%s/a" FoobarBax + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test1805 } + +# +# admin with changepw service tickets try to change other principals +# password, failes with AUTH error +test "chpass-principal 180.625" +proc test180625 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_chpass_principal $server_handle "%s/a" password + } $test] "AUTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test180625 } + +test "chpass-principal 180.75" +proc test18075 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_chpass_principal $server_handle "%s/a" Foobar + } $test] "AUTH_CHANGEPW" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test18075 } + +test "chpass-principal 182" +proc test182 {} { + global test + + if { ! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_chpass_principal $server_handle kadmin/history password + } "PROTECT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test182 + +test "chpass-principal 183" +proc test183 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if { ! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_chpass_principal null "%s/a" password + } $test] "BAD_SERVER_HANDLE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test183 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/crte-policy.exp b/src/lib/kadm5/unit-test/api.0/crte-policy.exp new file mode 100644 index 000000000..dbf4f1cbc --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/crte-policy.exp @@ -0,0 +1,991 @@ +source lib.t +api_exit +api_start + +# Description: (1) Fails for mask with undefined bit set. +# 01/24/94: pshuang: untried. +test "create-policy 1" +proc test1 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + 0xF01000 + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test1 + +# Description: (2) Fails if caller connected with CHANGEPW_SERVICE. +test "create-policy 2" +proc test2 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy"; + return + } +} +if {$RPC} { test2 } + +# Description: (3) Fails for mask without POLICY bit set. +# 01/24/94: pshuang: untried. +test "create-policy 3" +proc test3 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + 0x000000 + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3 + +# Description: (4) Fails for mask with REF_COUNT bit set. +test "create-policy 4" +proc test4 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_REF_COUNT} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + +# Description: (5) Fails for invalid policy name. +# 01/24/94: pshuang: untried. +test "create-policy 5" +proc test5 {} { + global test + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/"] \ + {OVSEC_KADM_POLICY} + } $test] "BAD_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +# Description: (6) Fails for existing policy name. +test "create-policy 6" +proc test6 {} { + global test +# set prms_id 777 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_create_policy $server_handle [simple_policy test-pol] \ + {OVSEC_KADM_POLICY} + } "DUP" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test6 + +# Description: (7) Fails for null policy name. +# 01/24/94: pshuang: untried. +test "create-policy 7" +proc test7 {} { + global test +# set prms_id 1977 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_create_policy $server_handle [simple_policy null] \ + {OVSEC_KADM_POLICY} + } "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test7 + +# Description: (8) Fails for empty-string policy name. +test "create-policy 8" +proc test8 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_create_policy $server_handle [simple_policy ""] \ + {OVSEC_KADM_POLICY} + } "BAD_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +# Description: (9) Accepts 0 for pw_min_life. +test "create-policy 9" +proc test9 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE} + } $test]]} { + fail "$test: create failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +# Description: (10) Accepts non-zero for pw_min_life. +test "create-policy 10" +proc test10 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 32 0 0 0 0 0 } \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +# Description: (11) Accepts 0 for pw_max_life. +test "create-policy 11" +proc test11 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MAX_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +# Description: (12) Accepts non-zero for pw_max_life. +test "create-policy 12" +proc test12 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 32 0 0 0 0 } \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MAX_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +# Description: (13) Rejects 0 for pw_min_length. +test "create-policy 13" +proc test13 {} { + global test + global prompt + + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH} + } $test] "BAD_LENGTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +# Description: (14) Accepts non-zero for pw_min_length. +test "create-policy 14" +proc test14 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 8 0 0 0 } \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_LENGTH} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 3\n" + expect { + -re "8\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +# Description: (15) Rejects 0 for pw_min_classes. +test "create-policy 15" +proc test15 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +# Description: (16) Accepts 1 for pw_min_classes. +test "create-policy 16" +proc test16 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 1 0 0 } \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +# Description: (17) Accepts 4 for pw_min_classes. +test "create-policy 17" +proc test17 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 5 0 0} \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "5\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +# Description: (18) Rejects 5 for pw_min_classes. +test "create-policy 18" +proc test18 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 6 0 0} \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +# Description: (19) Rejects 0 for pw_history_num. +test "create-policy 19" +proc test19 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +# Description: (20) Accepts 1 for pw_history_num. +test "create-policy 20" +proc test20 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 1 0} \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +# Description: (21) Accepts 10 for pw_history_num. +test "create-policy 21" +proc test21 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 10 0} \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "10\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +# Description: (21.5) Rejects 11 for pw_history_num. +# 01/24/94: pshuang: untried. + +test "create-policy 21.5" +proc test215 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle {"%s/a" 0 0 0 0 11 0} \ + {OVSEC_KADM_POLICY OVSEC_KADM_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test215 + + +# Description: (22) Fails for user with no access bits. +test "create-policy 22" +proc test22 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test22 + +# Description: (23) Fails for user with "get" but not "add". +test "create-policy 23" +proc test23 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test23 + +# Description: (24) Fails for user with "modify" but not "add". +# 01/24/94: pshuang: untried. +test "create-policy 24" +proc test24 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test24 + +# Description: (25) Fails for user with "delete" but not "add". +# 01/24/94: pshuang: untried. +test "create-policy 25" +proc test25 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test25 + +# Description: Succeeds for user with "add". +test "create-policy 26" +proc test26 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +# Description: Succeeds for user with "get" and "add". +# 01/24/94: pshuang: untried. +test "create-policy 27" +proc test27 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get-add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test27 + +# Description: (28) Rejects null policy argument. +# 01/24/94: pshuang: untried. +test "create-policy 28" +proc test28 {} { + global test + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_create_policy $server_handle null {OVSEC_KADM_POLICY} + } "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "create-policy 30" +proc test30 {} { + global test + one_line_fail_test [format { + ovsec_kadm_create_policy null [simple_policy "%s/a"] \ + {OVSEC_KADM_POLICY} + } $test] "BAD_SERVER_HANDLE" +} +test30 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/crte-principal.exp b/src/lib/kadm5/unit-test/api.0/crte-principal.exp new file mode 100644 index 000000000..12c300793 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/crte-principal.exp @@ -0,0 +1,1330 @@ +source lib.t +api_exit +api_start + +#test "create-principal 1" +# +#proc test1 {} { +# global test +# begin_dump +# one_line_fail_test [format { +# ovsec_kadm_create_principal $server_handle \ +# [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a" +# } $test $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test1 + +test "create-principal 2" + +proc test2 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_create_principal $server_handle null \ + {OVSEC_KADM_PRINCIPAL} testpass + } "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test2 + +test "create-principal 3" +proc test3 {} { + global test +# set prms_id 777 +# setup_xfail {*-*-*} $prms_id + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} null + } $test] "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test3 + +test "create-principal 4" +proc test4 {} { + global test + + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} "" + } $test] "_Q_TOOSHORT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test4 + +test "create-principal 5" +proc test5 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle \ + [simple_principal "%s/a"] {0x100001} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test5 + +test "create-principal 6" +proc test6 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_LAST_PWD_CHANGE} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test6 + +test "create-principal 7" +proc test7 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MOD_TIME} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test7 + +test "create-principal 8" +proc test8 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MOD_NAME} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test8 + +test "create-principal 9" +proc test9 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MKVNO} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test9 + +test "create-principal 10" +proc test10 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_AUX_ATTRIBUTES} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test10 + +test "create-principal 11" +proc test11 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_POLICY_CLR} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test11 + +test "create-principal 12" +proc test12 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" + +} +if {$RPC} { test12 } + +test "create-principal 13" +proc test13 {} { + global test + begin_dump + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test13 } + +test "create-principal 14" +proc test14 {} { + global test + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test14 } + +test "create-principal 15" +proc test15 {} { + global test + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test15 } + +test "create-principal 16" +proc test16 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test16 } + +test "create-principal 17" +proc test17 {} { + global test + + begin_dump + if {! (( [principal_exists "$test/a"]) || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} testpass + } $test] "DUP" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test17 + +test "create-principal 18" +proc test18 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} tP + } $test] "_Q_TOOSHORT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test18 + +test "create-principal 19" +proc test19 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} testpassword + } $test] "_Q_CLASS" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test19 + +test "create-principal 20" +proc test20 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} Abyssinia + } $test] "_Q_DICT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test20 + +test "create-principal 21" +proc test21 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" non-existant-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} NotinTheDictionary + } $test] "UNK_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test21 + +test "create-principal 23" +proc test23 {} { + global test + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + one_line_succeed_test \ + [format {ovsec_kadm_get_principal $server_handle "%s/a" p} $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test23 + +test "create-principal 24" +proc test24 {} { + global test + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + one_line_succeed_test \ + [format {ovsec_kadm_get_principal $server_handle "%s/a" p} $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test24 } + + +test "create-principal 28" +proc test28 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "create-principal 29" +proc test29 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_PRINC_EXPIRE_TIME} \ + inTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 1\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test29 + +test "create-principal 30" +proc test30 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "create-principal 31" +proc test31 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol-nopw] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \ + OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "create-principal 32" +proc test32 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \ + OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "create-principal 33" +proc test33 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + {"%s/a" 0 0 1234 0 null 0 0 0 0 null 0} \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test33 + +test "create-principal 34" +proc test34 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + { "%s/a" 0 0 1234 0 null 0 0 0 0 test-pol-nopw 0} \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \ + OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test34 + +test "create-principal 35" +proc test35 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + {"%s/a" 0 0 1234 0 null 0 0 0 0 test-pol 0} \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \ + OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test35 + +test "create-principal 36" +proc test36 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle \ + {"%s/a" 0 0 999999999 0 null 0 0 0 0 test-pol 0} \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY \ + OVSEC_KADM_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy} ]} { + error_and_restart "$test: cannot retrieve policy" + return + } + + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test36 + +test "create-principal 37" +proc test37 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test37 + +test "create-principal 38" +proc test38 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test38 + +test "create-principal 39" +proc test39 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if { ! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: cannot not retrieve principal" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test39 + +test "create-principal 40" +proc test40 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL OVSEC_KADM_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 4\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test40 + +test "create-principal 43" +proc test43 {} { + global test + one_line_fail_test [format { + ovsec_kadm_create_principal null \ + [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a" + } $test $test] "BAD_SERVER_HANDLE" +} +test43 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/destroy.exp b/src/lib/kadm5/unit-test/api.0/destroy.exp new file mode 100644 index 000000000..31b844786 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/destroy.exp @@ -0,0 +1,203 @@ +source lib.t +api_exit +api_start + +test "destroy 1" + +proc test1 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_destroy $server_handle} + end_dump_compare "no-diffs" +} +test1 + +#test "destroy 2" +# +#proc test2 {} { +# global test +# begin_dump +# if {! [cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test \ +# {ovsec_kadm_get_principal $server_handle admin principal} \ +# "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test2 + +#test "destroy 3" +#proc test3 {} { +# global test +# +# begin_dump +# if {! (( ! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} { +# error_and_restart "$test couldn't delete principal \"$test/a\"" +# return +# } +# if {! [cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# ovsec_kadm_create_principal $server_handle \ +# [simple_principal "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a" +# } $test $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test3 + +#test "destroy 4" +#proc test4 {} { +# global test prompt +# +# if {! (([principal_exists "$test/a"]) || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! ([cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }] && +# [cmd [format { +# ovsec_kadm_get_principal $server_handle "%s/a" principal +# } $test]])} { +# error_and_restart "$test: error getting principal" +# return; +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# ovsec_kadm_modify_principal $server_handle \ +# {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {OVSEC_KADM_KVNO} +# } $test "77"] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test4 + +#test "destroy 5" +# +#proc test5 {} { +# global test +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! [cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# ovsec_kadm_delete_principal $server_handle "%s/a" +# } $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test5 + +#test "destroy 6" +# +#proc test6 {} { +# global test +# begin_dump +# one_line_fail_test {ovsec_kadm_destroy $server_handle} "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test6 + + +#test "destroy 7" +# +#proc test7 {} { +# global test +# begin_dump +# if {! [cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }]} { +# error "$test: unexpected failure in init" +# return +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +# one_line_fail_test {ovsec_kadm_destroy $server_handle} "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test7 + +test "destroy 8" +proc test8 {} { + global test + begin_dump + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } + one_line_succeed_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } + end_dump_compare "no-diffs" +} +test8 + +test "destroy 9" +proc test9 {} { + global test + one_line_fail_test {ovsec_kadm_destroy null} "BAD_SERVER_HANDLE" +} +test9 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/dlte-policy.exp b/src/lib/kadm5/unit-test/api.0/dlte-policy.exp new file mode 100644 index 000000000..7f349b02c --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/dlte-policy.exp @@ -0,0 +1,207 @@ +source lib.t +api_exit +api_start + +test "delete-policy 2" +proc test2 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {ovsec_kadm_delete_policy $server_handle ""} "BAD_POL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test2 + +test "delete-policy 5" +proc test5 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} test5 + +test "delete-policy 6" +proc test6 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} test6 + +test "delete-policy 7" +proc test7 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test7 + +test "delete-policy 10" +proc test10 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_delete_policy $server_handle "%s/a" + } $test]]} { + fail "$test" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if { [policy_exists "$test/a"]} { + fail "$test" + return + } +} +test10 + +test "delete-policy 12" +proc test12 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test unexecpted failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_create_principal $server_handle [princ_w_pol "%s/a" \ + "%s/a"] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} \ + NotinTheDictionary + } $test $test]]} { + fail "$test: can not create principal" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {ovsec_kadm_delete_policy $server_handle test-pol} "POLICY_REF" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "delete-policy 13" +proc test13 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_policy null "%s/a" + } $test] "BAD_SERVER_HANDLE" +} +test13 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/dlte-principal.exp b/src/lib/kadm5/unit-test/api.0/dlte-principal.exp new file mode 100644 index 000000000..bb52301df --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/dlte-principal.exp @@ -0,0 +1,329 @@ +source lib.t + +api_exit +api_start + +#test "delete-principal 1" +#proc test1 {} { +# global test +# one_line_fail_test [format { +# ovsec_kadm_delete_principal $server_handle "%s/a" +# } $test] "NOT_INIT" +#} +#test1 + +test "delete-principal 2" +proc test2 {} { + global test + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {ovsec_kadm_delete_principal $server_handle null} "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: unexpected failure in destroy" + return + } +} +test2 + +test "delete-principal 5" +proc test5 {} { + global test + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "UNK_PRINC" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +test "delete-principal 6" +proc test6 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test6 } + + +test "delete-principal 7" +proc test7 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test7 } + + +test "delete-principal 8" +proc test8 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test8 } + +test "delete-principal 9" +proc test9 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test9 } + +test "delete-principal 10" +proc test10 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test10 } + +test "delete-principal 11" +proc test11 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test]]} { + fail "$test: delete failed" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if { [principal_exists "$test/a"] } { + fail "$test" + return + } +} +test11 + +test "delete-principal 12" +proc test12 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd [format { + ovsec_kadm_delete_principal $server_handle "%s/a" + } $test]]} { + fail "$test: delete failed" + return + } + if { [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test]]} { + fail "$test: principal still exists" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref - 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + pass "$test" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} + +test12 + +test "delete-principal 13" +proc test13 {} { + global test + one_line_fail_test [format { + ovsec_kadm_delete_principal null "%s/a" + } $test] "BAD_SERVER_HANDLE" +} +test13 + +return "" + + + + + diff --git a/src/lib/kadm5/unit-test/api.0/get-policy.exp b/src/lib/kadm5/unit-test/api.0/get-policy.exp new file mode 100644 index 000000000..329e7886a --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/get-policy.exp @@ -0,0 +1,199 @@ +source lib.t +api_exit +api_start + +test "get-policy 3" +proc test3 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {ovsec_kadm_get_policy $server_handle "" p} "BAD_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3 + +test "get-policy 6" +proc test6 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test6 + +test "get-policy 7" +proc test7 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test7 + +test "get-policy 11" +proc test11 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/get-pol StupidAdmin $OVSEC_KADM_ADMIN_SERVICE \ + null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_policy $server_handle test-pol p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "get-policy 12" +proc test12 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/get-pol StupidAdmin \ + $OVSEC_KADM_CHANGEPW_SERVICE null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "get-policy 15" +proc test15 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/pol StupidAdmin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "get-policy 16" +proc test16 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/pol StupidAdmin $OVSEC_KADM_CHANGEPW_SERVICE \ + null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +test "get-policy 17" +proc test17 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_policy $server_handle test-pol p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "get-policy 18" +proc test18 {} { + global test + + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {ovsec_kadm_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test18 + +test "get-policy 21" +proc test21 {} { + global test + + one_line_fail_test {ovsec_kadm_get_policy null "pol1" p} "BAD_SERVER_HANDLE" +} +test21 diff --git a/src/lib/kadm5/unit-test/api.0/get-principal.exp b/src/lib/kadm5/unit-test/api.0/get-principal.exp new file mode 100644 index 000000000..05937055e --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/get-principal.exp @@ -0,0 +1,346 @@ +source lib.t +api_exit +api_start + +test "get-principal 1" +proc test1 {} { + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {ovsec_kadm_get_principal $server_handle null p} "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test1 + +test "get-principal 2" +proc test2 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "UNK_PRINC" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test2 + +test "get-principal 3" +proc test3 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test3 } + +test "get-principal 4" +proc test4 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test4 } + +test "get-principal 5" +proc test5 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test5 } + +test "get-principal 6" +proc test6 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test6 } + +test "get-principal 7" +proc test7 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test7 } + + +test "get-principal 8" +proc test8 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_get_principal $server_handle "%s/a" p + } $test] "AUTH_GET" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test8 } + + +test "get-principal 9" +proc test9 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_principal $server_handle admin/none p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "get-principal 10" +proc test10 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_principal $server_handle admin/none p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +test "get-principal 11" +proc test11 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/get p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "get-principal 12" +proc test12 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/get p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "get-principal 13" +proc test13 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/add p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "get-principal 14" +proc test14 {} { + global test + if {! [cmd { + ovsec_kadm_init admin/get-mod admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {ovsec_kadm_get_principal $server_handle admin/add p} + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +test "get-principal 15" +proc test15 {} { + one_line_fail_test \ + {ovsec_kadm_get_principal null "admin" p} "BAD_SERVER_HANDLE" +} +test15 + +return "" + + + + diff --git a/src/lib/kadm5/unit-test/api.0/init.exp b/src/lib/kadm5/unit-test/api.0/init.exp new file mode 100644 index 000000000..5df5dcfc9 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/init.exp @@ -0,0 +1,727 @@ +source lib.t + +# Assumptions: +# +# Principal "admin" exists, with "get", "add", "modify" and "delete" +# access bits and password "admin". +# The string "not-the-password" isn't the password of any user in the database. +# Database master password is "mrroot". + +api_exit +api_start +test "init 1" + +one_line_fail_test_nochk \ + {ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE "" \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle} + +test "init 2" + +one_line_fail_test_nochk \ + {ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE @ \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle} + +test "init 2.5" + +one_line_fail_test_nochk \ + {ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE BAD.REALM \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle} + +test "init 3" + +proc test3 {} { + global test + if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + one_line_fail_test_nochk [format { + ovsec_kadm_init admin admin "%s/a" null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + } $test] +} +if {$RPC} { test3 } + +test "init 4" + +proc test4 {} { + global test + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + one_line_fail_test_nochk [format { + ovsec_kadm_init admin admin "%s/a" null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test] +} +if {$RPC} { test4 } + +test "init 5" + +if {$RPC} { + one_line_fail_test_nochk { + ovsec_kadm_init admin admin admin null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + } +} + +test "init 6" + +proc test6 {} { + global test + + send "ovsec_kadm_init admin null \$OVSEC_KADM_ADMIN_SERVICE null \$OVSEC_KADM_STRUCT_VERSION \$OVSEC_KADM_API_VERSION_1 server_handle\n" + + expect { + {Enter password:} { } + eof { + fail "$test: eof instead of password prompt" + api_exit + api_start + return + } + timeout { + fail "$test: timeout instead of password prompt" + return + } + } + one_line_succeed_test "admin" + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if { $RPC } { test6 } + +test "init 7" +proc test7 {} { + global test + + send "ovsec_kadm_init admin \"\" \$OVSEC_KADM_ADMIN_SERVICE null \$OVSEC_KADM_STRUCT_VERSION \$OVSEC_KADM_API_VERSION_1 server_handle\n" + + expect { + {Enter password:} { } + -re "key:$" { } + eof { + fail "$test: eof instead of password prompt" + api_exit + api_start + return + } + timeout { + fail "$test: timeout instead of password prompt" + return + } + } + one_line_succeed_test "admin" + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if { $RPC } { test7 } + +test "init 8" + +proc test8 {} { + global test + if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + one_line_fail_test_nochk [format { + ovsec_kadm_init "%s/a" admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test] +} +if {$RPC} { test8 } + +test "init 9" + +if {$RPC} { + global test + one_line_fail_test_nochk { + ovsec_kadm_init admin not-the-password $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } +} + +test "init 10" + +proc test10 {} { + global test +# set prms_id 562 +# setup_xfail {*-*-*} $prms_id + one_line_fail_test_nochk { + ovsec_kadm_init null admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } +} +test10 + +#test "init 11" +# +#proc test11 {} { +# global test +# set prms_id 563 +# setup_xfail {*-*-*} $prms_id +# one_line_fail_test_nochk { +# ovsec_kadm_init "" admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# } +#} +#test11 + +test "init 12" + +proc test12 {} { + global test + one_line_fail_test_nochk [format { + ovsec_kadm_init "%s/a" admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test] +} +if {$RPC} { test12 } + +test "init 13" + +proc test13 {} { + global test + one_line_fail_test_nochk [format { + ovsec_kadm_init "%s/a@SECURE-TEST.OV.COM" admin \ + $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + } $test] +} +if {$RPC} { test13 } + +test "init 14" + +proc test14 {} { + global test + one_line_fail_test_nochk [format { + ovsec_kadm_init "%s/a@BAD.REALM" admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test] +} +if {$RPC} { test14 } + +test "init 15" + +if {$RPC} { + one_line_fail_test_nochk { + ovsec_kadm_init admin@BAD.REALM admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } +} + +test "init 16" + +proc test16 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test16 + +test "init 17" + +proc test17 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin@SECURE-TEST.OV.COM admin \ + $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test17 + +test "init 18" + +proc test18 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test18 + +test "init 19" + +proc test19 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin@SECURE-TEST.OV.COM admin \ + $OVSEC_KADM_ADMIN_SERVICE SECURE-TEST.OV.COM \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test19 + +test "init 20" + +proc test20 {} { + global test + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error_and_restart "$test: couldn't init database" + return + } + one_line_succeed_test \ + {ovsec_kadm_get_principal $server_handle admin principal} + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test20 + +#test "init 21" +# +#proc test21 {} { +# global test +# if {! [cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }]} { +# error_and_restart "$test: couldn't init database" +# return +# } +# one_line_fail_test_nochk { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# } +# if {! [cmd {ovsec_kadm_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +#} +#test21 + + +proc test22 {} { + global test prompt + set prompting 0 + send [string trim { + ovsec_kadm_init admin null null null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + }] + send "\n" + expect { + -re ":$" { set prompting 1} + -re "\nOK .*$prompt$" { fail "$test: premature success" } + -re "\nERROR .*$prompt$" { fail "$test: premature failure" } + timeout { fail "$test: timeout" } + eof { fail "$test: eof" } + } + if {$prompting} { + one_line_succeed_test mrroot + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test22 } + +test "init 22.5" +proc test225 {} { + global test prompt + set prompting 0 + send [string trim { + ovsec_kadm_init admin null null null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + }] + send "\n" + expect { + -re ":$" { set prompting 1} + -re "\nOK .*$prompt$" { fail "$test: premature success" } + -re "\nERROR .*$prompt$" { fail "$test: premature failure" } + timeout { fail "$test: timeout" } + eof { fail "$test: eof" } + } + if {$prompting} { + one_line_succeed_test mrroot + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test225 } + +test "init 23" + +proc test23 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin not-the-password $OVSEC_KADM_ADMIN_SERVICE \ + null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test23 } + +test "init 24" + +proc test24 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin admin null null $OVSEC_KADM_STRUCT_VERSION \ + $OVSEC_KADM_API_VERSION_1 server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test24 } + +test "init 25" + +proc test25 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin admin foobar null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test25 } + +test "init 26" + +#proc test26 {} { +# global test +# +# api_exit +# api_start +# one_line_fail_test_nochk { +# ovsec_kadm_get_principal $server_handle admin principal +# } +#} +#test26 + +#test "init 27" +# +#proc test27 {} { +# global test +# +# if {! ((! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} { +# error_and_restart "$test: couldn't delete principal \"$test/a\"" +# return +# } +# begin_dump +# if {[cmd [format { +# ovsec_kadm_create_principal $server_handle [simple_principal \ +# "%s/a"] {OVSEC_KADM_PRINCIPAL} "%s/a" +# } $test $test]]} { +# fail "$test: unexpected success in add" +# return +# } +# end_dump_compare "no-diffs" +#} +#test27 + +#test "init 28" +# +#proc test28 {} { +# global test prompt +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! ([cmd { +# ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ +# $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ +# server_handle +# }] && [cmd [format { +# ovsec_kadm_get_principal $server_handle "%s/a" principal +# } $test]])} { +# error_and_restart "$test: error getting principal" +# return; +# } +# send "lindex \$principal 8\n" +# expect { +# -re "\n(\[0-9\]+).*$prompt$" {set kvno $expect_out(1,string) } +# timeout { +# error_and_restart "$test: timeout getting principal kvno" +# return +# } +# eof { +# error_and_restart "$test: eof getting principal kvno" +# return +# } +# } +# api_exit +# api_start +# set new_kvno [expr "$kvno + 1"] +# if {[cmd [format { +# ovsec_kadm_modify_principal $server_handle \ +# {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {OVSEC_KADM_KVNO} +# } $test $new_kvno]]} { +# fail "$test: unexpected success in modify" +# return; +# } +# end_dump_compare "no-diffs" +#} +#test28 + +#test "init 29" +# +#proc test29 {} { +# global test +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {[cmd [format { +# ovsec_kadm_delete_principal $server_handle "%s/a" +# } $test]]} { +# fail "$test: unexpected success in delete" +# return +# } +# end_dump_compare "no-diffs" +#} +#test29 + +test "init 30" +proc test30 {} { + global test + if {[cmd { + ovsec_kadm_init admin foobar $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error_and_restart "$test: unexpected succsess" + return + } + one_line_succeed_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if ${RPC} { test30 } + +test "init 31" +proc test31 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $bad_struct_version_mask $OVSEC_KADM_API_VERSION_1 \ + server_handle + } "BAD_STRUCT_VERSION" +} +test31 + +test "init 32" +proc test32 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $no_struct_version_mask $OVSEC_KADM_API_VERSION_1 \ + server_handle + } "BAD_STRUCT_VERSION" +} +test32 + +test "init 33" +proc test33 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $old_struct_version $OVSEC_KADM_API_VERSION_1 \ + server_handle + } "OLD_STRUCT_VERSION" +} +test33 + +test "init 34" +proc test34 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $new_struct_version $OVSEC_KADM_API_VERSION_1 \ + server_handle + } "NEW_STRUCT_VERSION" +} +test34 + +test "init 35" +proc test35 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $bad_api_version_mask \ + server_handle + } "BAD_API_VERSION" +} +test35 + +test "init 36" +proc test36 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $no_api_version_mask \ + server_handle + } "BAD_API_VERSION" +} +test36 + +test "init 37" +proc test37 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $old_api_version \ + server_handle + } "OLD_LIB_API_VERSION" +} +if { $RPC } test37 + +test "init 38" +proc test38 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $old_api_version \ + server_handle + } "OLD_SERVER_API_VERSION" +} +if { ! $RPC } test38 + +test "init 39" +proc test39 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $new_api_version \ + server_handle + } "NEW_LIB_API_VERSION" +} +if { $RPC } test39 + +test "init 40" +proc test40 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $new_api_version \ + server_handle + } "NEW_SERVER_API_VERSION" +} +if { ! $RPC } test40 + +test "init 41" +proc test41 {} { + global test + one_line_fail_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_API_VERSION_1 $OVSEC_KADM_STRUCT_VERSION \ + server_handle + } "BAD_" +} +test41 + +test "init 42" +proc test42 {} { + global test + one_line_succeed_test { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } + if {! [cmd {ovsec_kadm_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test42 + + +proc test45_46 {service} { + global test kdb5_edit env + + spawn $kdb5_edit -R "del $service" + expect { + {Type 'yes' to confirm:} { + send "yes\n" + } + default { + error "kdb5_edit del failed\n"; + } + } + expect eof + wait + + one_line_fail_test [concat {ovsec_kadm_init admin admin } \ + $service \ + { null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle}] "SECURE_PRINC_MISSING" + + # this leaves the keytab with an incorrect entry + exec $kdb5_edit -R "ark $service" + + # restart the api so it gets a new ccache + api_exit + api_start +} + +if {$RPC} { + test "init 45" + + test45_46 ovsec_adm/admin + + test "init 46" + + test45_46 ovsec_adm/changepw + + # re-extract the keytab so it is right + exec rm /krb5/ovsec_adm.srvtab + exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \ + -princ kadmin/admin -princ kadmin/changepw /krb5/ovsec_adm.srvtab +} + +return "" + diff --git a/src/lib/kadm5/unit-test/api.0/mod-policy.exp b/src/lib/kadm5/unit-test/api.0/mod-policy.exp new file mode 100644 index 000000000..67f8457b6 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/mod-policy.exp @@ -0,0 +1,703 @@ +source lib.t +api_exit +api_start + +test "modify-policy 2" +proc test2 {} { + global test + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2 } + +test "modify-policy 4" +proc test4 {} { + global test + + if {! ([policy_exists "$test/a"] || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_REF_COUNT} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + +test "modify-policy 8" +proc test8 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_modify_policy $server_handle [simple_policy ""] \ + {OVSEC_KADM_PW_MAX_LIFE} + } "BAD_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +test "modify-policy 9" +proc test9 {} { + global test + global prompt + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MIN_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "modify-policy 10" +proc test10 {} { + global test + global prompt + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 32 0 0 0 0 0} \ + {OVSEC_KADM_PW_MIN_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + + +test "modify-policy 11" +proc test11 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "modify-policy 12" +proc test12 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 32 0 0 0 0} \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "modify-policy 13" +proc test13 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MIN_LENGTH} + } $test] "BAD_LENGTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "modify-policy 14" +proc test14 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 8 0 0 0} \ + {OVSEC_KADM_PW_MIN_LENGTH} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 3\n" + expect { + -re "8\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +test "modify-policy 15" +proc test15 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "modify-policy 16" +proc test16 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 1 0 0} \ + {OVSEC_KADM_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +test "modify-policy 17" +proc test17 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 5 0 0} \ + {OVSEC_KADM_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "5\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "modify-policy 18" +proc test18 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 6 0 0} \ + {OVSEC_KADM_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +test "modify-policy 19" +proc test19 {} { + global test + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +test "modify-policy 20" +proc test20 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 0 1 0} \ + {OVSEC_KADM_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +test "modify-policy 21" +proc test21 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_policy $server_handle {"%s/a" 0 0 0 0 10 0} \ + {OVSEC_KADM_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + ovsec_kadm_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "10\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +test "modify-policy 22" +proc test22 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test22 + +test "modify-policy 23" +proc test23 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test23 + +test "modify-policy 26" +proc test26 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_modify_policy $server_handle [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +test "modify-policy 30" +proc test30 {} { + global test + + one_line_fail_test [format { + ovsec_kadm_modify_policy null [simple_policy "%s/a"] \ + {OVSEC_KADM_PW_MAX_LIFE} + } $test] "BAD_SERVER_HANDLE" +} +test30 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/mod-principal.exp b/src/lib/kadm5/unit-test/api.0/mod-principal.exp new file mode 100644 index 000000000..c4bc2bed1 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/mod-principal.exp @@ -0,0 +1,1942 @@ +source lib.t +api_exit +api_start + +#test "modify-principal 1" +#proc test1 {} { +# global test +# one_line_fail_test [format { +# ovsec_kadm_modify_principal $server_handle [simple_principal \ +# "%s/a"] {OVSEC_KADM_PW_EXPIRATION} +# } $test] "NOT_INIT" +#} +#test1 + +test "modify-principal 2" +proc test2 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "AUTH_MODIFY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2 } + +test "modify-principal 4" +proc test4 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINCIPAL} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + + +test "modify-principal 5" +proc test5 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_LAST_PWD_CHANGE} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +test "modify-principal 6" +proc test6 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MOD_TIME} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test6 + +test "modify-principal 7" +proc test7 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MOD_NAME} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test7 + +test "modify-principal 8" +proc test8 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MKVNO} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +test "modify-principal 9" +proc test9 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_AUX_ATTRIBUTES} + } $test] "BAD_MASK" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "modify-principal 10" +proc test10 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "UNK_PRINC" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +test "modify-principal 11" +proc test11 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test11 } + +test "modify-principal 12" +proc test12 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test12 } + +test "modify-principal 13" +proc test13 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test13 } + +test "modify-principal 14" +proc test14 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test14 } + +test "modify-principal 15" +proc test15 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "modify-principal 17" +proc test17 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + no-policy] {OVSEC_KADM_POLICY} + } $test] "UNK_POLICY" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "modify-principal 18" +proc test18 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref + 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +test "modify-principal 19" +proc test19 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref + 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +test "modify-principal 20" +proc test20 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_POLICY_CLR} + } $test]]} { + error "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { fail "$test" } + timeout { pass "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref - 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +test "modify-principal 21" +proc test21 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw old_p2}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$old_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + send "lindex \$old_p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p2_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol new_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol-nopw new_p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$new_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + send "lindex \$new_p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p2_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$old_p1_ref - 1"] != $new_p1_ref } { + fail "$test: policy reference count is wrong" + return; + } + if { [expr "$old_p2_ref + 1"] != $new_p2_ref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +test "modify-principal 21.5" +proc test21.5 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol old_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$old_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol new_p1}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$new_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if {$old_p1_ref != $new_p1_ref} { + fail "$test: policy reference count changed ($old_p1_ref to $new_p1_ref)" + return + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21.5 + +test "modify-principal 22" +proc test22 {} { + global test + global prompt + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test22 + +test "modify-principal 23" +proc test23 {} { + global test + global prompt + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol-nopw])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test23 + +test "modify-principal 24" +proc test24 {} { + global test + global prompt +# set prms_id 1358 +# setup_xfail {*-*-*} $prms_id + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error_and_restart "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: could not modify principal" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd [format { + ovsec_kadm_get_policy $server_handle %s policy + } test-pol]]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test24 + +test "modify-principal 25" +proc test25 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test25 + +test "modify-principal 26" +proc test26 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol-nopw" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +test "modify-principal 27" +proc test27 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test27 + +test "modify-principal 28" +proc test28 {} { + global test + global prompt +# set prms_id 1358 +# setup_xfail {*-*-*} $prms_id + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 900 0 0 0 0 0 0 0 0} {OVSEC_KADM_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] == $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + pass "$test" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "modify-principal 29" +proc test29 {} { + global test + global prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { ! ([create_principal_pol "$test/a" test-pol])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_POLICY_CLR} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test29 + +test "modify-principal 30" +proc test30 {} { + global test + global prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal_pol "$test/a" test-pol])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "modify-principal 31" +proc test31 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_POLICY} + } $test]]} { + fail "modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "modify-principal 32" +proc test32 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 1234 0 0 0 0 0 0 0 0 0 0} \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 1\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "modify-principal 33" +proc test33 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_ALL_TIX 0 0 0 0} \ + {OVSEC_KADM_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_DISALLOW_ALL_TIX.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test33 + +test "modify-principal 33.25" +proc test3325 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_REQUIRES_PWCHANGE 0 0 0 0} \ + {OVSEC_KADM_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_REQUIRES_PWCHANGE.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3325 + +test "modify-principal 33.5" +proc test335 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_TGT_BASED 0 0 0 0} \ + {OVSEC_KADM_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_DISALLOW_TGT_BASED.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test335 + + +test "modify-principal 34" +proc test34 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 0 3456 0 0 0 0 0 0 0} {OVSEC_KADM_MAX_LIFE} + } $test]]} { + fail "$test: modify failed" + return + } + + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 4\n" + expect { + -re "3456\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test34 + +test "modify-principal 35" +proc test35 {} { + global prompt + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + ovsec_kadm_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 0 7 0 0 0} {OVSEC_KADM_KVNO} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 8\n" + expect { + -re "7\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test35 + +test "modify-principal 36" +proc test36 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol pol}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {OVSEC_KADM_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$pol 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {ovsec_kadm_get_policy $server_handle test-pol pol2}]} { + error "$test: unexpected failure on get policy" + return + } + send "lindex \$pol2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { $oldref != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test36 + +test "modify-principal 37" +proc test37 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_POLICY_CLR} + } $test]]} { + fail "$test: modify failed" + return + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test37 + +test "modify-principal 38" +proc test38 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test38 + +test "modify-principal 39" +proc test39 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [simple_principal "%s/a"] \ + {OVSEC_KADM_MAX_LIFE} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + ovsec_kadm_get_principal $server_handle "%s/a" principal + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 4\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test39 + +test "modify-principal 40" +proc test40 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_modify_principal $server_handle null \ + {OVSEC_KADM_PRINC_EXPIRE_TIME} + } "EINVAL" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test40 + +test "modify-principal 43" +proc test43 {} { + global test + one_line_fail_test [format { + ovsec_kadm_modify_principal null [simple_principal \ + "%s/a"] {OVSEC_KADM_PW_EXPIRATION} + } $test] "BAD_SERVER_HANDLE" +} +test43 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/randkey-principal.exp b/src/lib/kadm5/unit-test/api.0/randkey-principal.exp new file mode 100644 index 000000000..259cd8f03 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/randkey-principal.exp @@ -0,0 +1,319 @@ +source lib.t +api_exit +api_start + +test "randkey-principal 1" +proc test1 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] "PASS_TOOSOON" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test1 } + +test "randkey-principal 3" +proc test3 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] "PASS_TOOSOON" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} { test3 } + +test "randkey-principal 13" +proc test13 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + ovsec_kadm_modify_principal $server_handle [princ_w_pol "%s/a" \ + once-a-min] OVSEC_KADM_POLICY + } $test]]} { + error "$test: failed modify" + return + } + one_line_succeed_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "randkey-principal 15" +proc test15 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] "AUTH_CHANGEPW" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test15 } + +test "randkey-principal 28" +proc test28 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "randkey-principal 28.25" +proc test2825 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] "AUTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2825 } + +test "randkey-principal 28.5" +proc test285 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test285 + +test "randkey-principal 30" +proc test30 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + if {! [cmd [format { + ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "randkey-principal 31" +proc test31 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + ovsec_kadm_init "%s/a" "%s/a" $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_randkey_principal $server_handle "%s/a" key + } $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "randkey-principal 32" +proc test32 {} { + global test + + if { ! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + ovsec_kadm_randkey_principal $server_handle kadmin/history key + } "PROTECT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "randkey-principal 33" +proc test33 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if { ! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_randkey_principal null "%s/a" key + } $test] "BAD_SERVER_HANDLE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} + +test33 + +return "" diff --git a/src/lib/kadm5/unit-test/api.0/rename-principal.exp b/src/lib/kadm5/unit-test/api.0/rename-principal.exp new file mode 100644 index 000000000..56e412955 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.0/rename-principal.exp @@ -0,0 +1,509 @@ +source lib.t +api_exit +api_start + +#test "rename-principal 1" +#proc test1 {} { +# global test +# one_line_fail_test [format { +# ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" +# } $test $test] "NOT_INIT" +#} +#test1 + +test "rename-principal 2" +proc test2 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_CHANGEPW_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "INSUFFICIENT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + +} +if {$RPC} { test2 } + +test "rename-principal 3" +proc test3 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/none admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_INSUFFICIENT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test3 } + +test "rename-principal 4" +proc test4 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/modify admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_INSUFFICIENT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test4 } + +test "rename-principal 5" +proc test5 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_INSUFFICIENT" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test5 } + +test "rename-principal 6" +proc test6 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/mod-add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test6 } + +test "rename-principal 7" +proc test7 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/mod-delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test7 } + +test "rename-principal 8" +proc test8 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get-add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test8 } + +test "rename-principal 9" +proc test9 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/get-delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test9 } + +test "rename-principal 10" +proc test10 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/no-delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_DELETE" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test10 } + +test "rename-principal 11" +proc test11 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/no-add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH_ADD" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test11 } + +test "rename-principal 12" +proc test12 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/add admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test12 } + + +test "rename-principal 13" +proc test13 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/delete admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "AUTH" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test13 } + +test "rename-principal 14" +proc test14 {} { + global test + + if {[principal_exists "$test/a"]} { + delete_principal "$test/a" + } + + if {[create_principal_with_keysalts "$test/a" "des-cbc-crc:v4"]} { + error_and_restart "$test: couldn't create no-salt principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +test "rename-principal 15" +proc test15 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( [principal_exists "$test/b"]) || + [create_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "DUP" + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "rename-principal 16" +proc test16 {} { + global test + one_line_fail_test [format { + ovsec_kadm_rename_principal null "%s/a" "%s/b" + } $test $test] "BAD_SERVER_HANDLE" +} +test16 + +test "rename-principal 18" +proc test18 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! (( ! [principal_exists "$test/b"]) || + [delete_principal "$test/b"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + ovsec_kadm_init admin/rename admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + ovsec_kadm_rename_principal $server_handle "%s/a" "%s/b" + } $test $test] "NO_RENAME_SALT" + + if { ! [cmd {ovsec_kadm_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +return "" diff --git a/src/lib/kadm5/unit-test/api.1/lock.exp b/src/lib/kadm5/unit-test/api.1/lock.exp new file mode 100644 index 000000000..67ab80060 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.1/lock.exp @@ -0,0 +1,242 @@ +# This is in api.1 so that it happens after all the tests in api.0. +# If some API function does not unlock the database then the server +# (whichs runs through all api tests) will still have it locked, and +# these tests will fail. + +source lib.t + +if { $RPC } { + return +} + +set locktest $LOCKTEST +set lockfile "/krb5/ovsec_adm.lock" + +# The lock tests use the program lock-test in the unit test +# directory. The basic idea is that lock-test can be told to acquire +# various kinds of locks and then wait for input before proceeding; +# this is necessary because otherwise we'd have no way to test locking +# interactions without a race condition. +# +# lock_test_start and lock_test_continue work together to give a crude +# form of continuations. lock_test_continue expects a list of +# commands for lock-test (passed on the command line) and responses +# (read from stdout). When it gets to a command of "wait", +# lock_test_continue returns, and its return value is a list of the +# arguments that it should be passed to continue processing that +# particular list of commands for that particular lock-test after +# whatever that requried lock-test to wait has been completed. +# +# lock_test is simply a wrapper for tests that do not involve wait. + +proc lock_test_setup {test cmds} { + global locktest spawn_id + + verbose "test $test" + + set cmdline "" + foreach cmdpair $cmds { + if {[lindex $cmdpair 0] == "eof"} { + break + } + set cmdline "$cmdline [lindex $cmdpair 0]" + } + + verbose "spawning $locktest $cmdline" + eval "spawn $locktest $cmdline" +} + +proc lock_test {test cmds} { + global spawn_id + + lock_test_setup $test $cmds + set lockany [lock_test_continue $test $spawn_id 0 "" 0 $cmds] + while {$lockany != {}} { + set lockany [eval lock_test_continue $lockany] + } +} + +proc lock_test_start {test cmds} { + global spawn_id + + lock_test_setup $test $cmds + return [lock_test_continue $test $spawn_id 0 "" 0 $cmds] +} + +proc lock_test_continue {test my_spawn_id test_failed fail_output cont cmds} { + global wait_error_index wait_errno_index wait_status_index + + set spawn_id $my_spawn_id + + if {$cont == 1} { + send -i $spawn_id "\n" + } + + while {[llength $cmds] > 0} { + set cmdpair [lindex $cmds 0] + set cmds [lrange $cmds 1 end] + set cmd [lindex $cmdpair 0] + set output [lindex $cmdpair 1] + + verbose "test $test: command: $cmd" + + if {$cmd == "wait"} { + # ah, for continuations... + return [list $test $spawn_id $test_failed $fail_output 1 $cmds] + } + if {$cmd == "eof"} { + set status $output + set output "doesnotmatchanything" + } + + expect { + -i $spawn_id + -re "$output" { verbose "test $test: read: $output" } + timeout { + set test_failed 1 + set fail_output "timeout while waiting for $output" + } + eof { + if {$cmd != "eof"} { + set test_failed 1 + set fail_output "eof while waiting for $output" + } + } + } + + if {$test_failed == 1} { break } + } + + set ret [wait -i $spawn_id] + verbose "% Exit $ret" 2 + + if {$test_failed == 0} { + if {[lindex $ret $wait_error_index] == -1} { + set test_failed 1 + set fail_output "wait returned error [lindex $ret $wait_errno_index]" + } else { + if { [lindex $ret $wait_status_index] == $status || + (($status<0) && ([lindex $ret $wait_status_index] == ($status+256))) } { + verbose "test $test: status $status" + } else { + set test_failed 1 + set fail_output "unexpected return status [lindex $ret $wait_status_index], should be $status" + } + } + } + + if {$test_failed == 0} { + pass $test + } else { + fail "$test: $fail_output" + } + + return {} +} + +lock_test 1 [list \ + [list shared "shared"] \ + [list release "released"] \ + [list eof 0]] + +lock_test 2 [list \ + [list exclusive exclusive] \ + [list release released] \ + [list eof 0]] + +lock_test 3 [list \ + [list permanent permanent] \ + [list release released] \ + [list eof 0]] + +lock_test 4 [list \ + [list release "Database not locked"] \ + [list eof 0]] + +set lock5 [lock_test_start 5 [list \ + [list shared shared] \ + [list wait ""] \ + [list eof 0]]] +lock_test 5.1 [list \ + [list shared shared] \ + [list eof 0]] +eval lock_test_continue $lock5 + +set lock6 [lock_test_start 6 [list \ + [list exclusive exclusive] \ + [list wait ""] \ + [list eof 0]]] +lock_test 6.1 [list \ + [list shared "Cannot lock database"] \ + [list eof 0]] +eval lock_test_continue $lock6 + +set lock7 [lock_test_start 7 [list \ + [list shared shared] \ + [list wait ""] \ + [list eof 0]]] +lock_test 7.1 [list \ + [list exclusive "Cannot lock database"] \ + [list eof 0]] +eval lock_test_continue $lock7 + +set lock8 [lock_test_start 8 [list \ + [list permanent permanent] \ + [list wait ""] \ + [list release "released" ] \ + [list eof 0]]] +lock_test 8.1 [list \ + [list "" "administration database lock file missing while opening database" ] \ + [list eof 1]] +eval lock_test_continue $lock8 + +set lock9 [lock_test_start 9 [list \ + [list wait ""] \ + [list exclusive "database lock file missing while getting exclusive"] \ + [list eof 0]]] +set lock9_1 [lock_test_start 9.1 [list \ + [list permanent permanent] \ + [list wait ""] \ + [list release released] \ + [list eof 0]]] +eval lock_test_continue $lock9 +eval lock_test_continue $lock9_1 + +if {! [file exists $lockfile]} { + error "lock file missing before test 10" +} +set lock10 [lock_test_start 10 [list \ + [list permanent permanent] \ + [list wait ""] \ + [list release released] \ + [list eof 0]]] +if {[file exists $lockfile]} { + fail "test 10: lock file exists" +} +eval lock_test_continue $lock10 +if {[file exists $lockfile]} { + pass "test 11: lock file exists" +} else { + fail "test 11: lock file does not exist" +} + +set lock12 [lock_test_start 12 [list \ + [list shared shared] \ + [list wait ""] \ + [list eof 0]]] +lock_test 12.1 [list \ + [list "get test-pol" retrieved] \ + [list eof 0]] +eval lock_test_continue $lock12 + +# This test doesn't work yet, somehow I or expect am confused about +# the spawn_id's between the lock-test and api. +warning "test 13: doesn't work, bug in unit-test" +# set lock13 [lock_test_start 13 [list \ +# [list "get lock13" "Principal or policy does not exist"] \ +# [list wait ""] \ +# [list "get lock13" retrieved] \ +# [list eof 0]]] +# create_policy lock13 +# eval lock_test_continue $lock13 +# delete_policy lock13 diff --git a/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp new file mode 100644 index 000000000..88aed8bca --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/chpass-principal-v2.exp @@ -0,0 +1,68 @@ +source lib.t +api_exit +api_start + +test "chpass-principal 200" +proc test200 {} { + global test prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + + # I'd like to specify a long list of keysalt tuples and make sure + # that chpass does the right thing, but we can only use those + # enctypes that krbtgt has a key for: des-cbc-crc:normal and + # des-cbc-crc:v4, according to the prototype kdc.conf. + if {! [cmd [format { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_chpass_principal $server_handle "%s/a" newpassword + } $test]]} { + error "$test: unexpected failure in chpass_principal" + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" p \ + {KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA} + } $test]]} { + error "$test: unexpected failure in get_principal" + } + send "lindex \$p 16\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_keys" + return + } + eof { + error_and_restart "$test: eof getting num_keys" + return + } + } + + # XXX Perhaps I should actually check the key type returned. + if {$num_keys == 2} { + pass "$test" + } else { + fail "$test: $num_keys keys, should be 2" + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test200 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/chpass-principal.exp b/src/lib/kadm5/unit-test/api.2/chpass-principal.exp new file mode 100644 index 000000000..3efdfa9b9 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/chpass-principal.exp @@ -0,0 +1,176 @@ +source lib.t +api_exit +api_start + +test "chpass-principal 180" +proc test180 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_chpass_principal $server_handle "%s/a" FoobarBax + } $test] + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test180 } + +test "chpass-principal 180.5" +proc test1805 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_chpass_principal $server_handle "%s/a" FoobarBax + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test1805 } + +# +# admin with changepw service tickets try to change other principals +# password, failes with AUTH error +test "chpass-principal 180.625" +proc test180625 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_chpass_principal $server_handle "%s/a" password + } $test] "AUTH" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test180625 } + +test "chpass-principal 180.75" +proc test18075 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_chpass_principal $server_handle "%s/a" Foobar + } $test] "AUTH_CHANGEPW" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test18075 } + +test "chpass-principal 182" +proc test182 {} { + global test + + if { ! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_chpass_principal $server_handle kadmin/history password + } "PROTECT" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test182 + +test "chpass-principal 183" +proc test183 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if { ! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_chpass_principal null "%s/a" password + } $test] "BAD_SERVER_HANDLE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test183 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/crte-policy.exp b/src/lib/kadm5/unit-test/api.2/crte-policy.exp new file mode 100644 index 000000000..b0ea04630 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/crte-policy.exp @@ -0,0 +1,991 @@ +source lib.t +api_exit +api_start + +# Description: (1) Fails for mask with undefined bit set. +# 01/24/94: pshuang: untried. +test "create-policy 1" +proc test1 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + 0xF01000 + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test1 + +# Description: (2) Fails if caller connected with CHANGEPW_SERVICE. +test "create-policy 2" +proc test2 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy"; + return + } +} +if {$RPC} { test2 } + +# Description: (3) Fails for mask without POLICY bit set. +# 01/24/94: pshuang: untried. +test "create-policy 3" +proc test3 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + 0x000000 + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3 + +# Description: (4) Fails for mask with REF_COUNT bit set. +test "create-policy 4" +proc test4 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete policy \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_REF_COUNT} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + +# Description: (5) Fails for invalid policy name. +# 01/24/94: pshuang: untried. +test "create-policy 5" +proc test5 {} { + global test + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/"] \ + {KADM5_POLICY} + } $test] "BAD_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +# Description: (6) Fails for existing policy name. +test "create-policy 6" +proc test6 {} { + global test +# set prms_id 777 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_create_policy $server_handle [simple_policy test-pol] \ + {KADM5_POLICY} + } "DUP" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test6 + +# Description: (7) Fails for null policy name. +# 01/24/94: pshuang: untried. +test "create-policy 7" +proc test7 {} { + global test +# set prms_id 1977 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_create_policy $server_handle [simple_policy null] \ + {KADM5_POLICY} + } "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test7 + +# Description: (8) Fails for empty-string policy name. +test "create-policy 8" +proc test8 {} { + global test + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_create_policy $server_handle [simple_policy ""] \ + {KADM5_POLICY} + } "BAD_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +# Description: (9) Accepts 0 for pw_min_life. +test "create-policy 9" +proc test9 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_PW_MIN_LIFE} + } $test]]} { + fail "$test: create failed" + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +# Description: (10) Accepts non-zero for pw_min_life. +test "create-policy 10" +proc test10 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 32 0 0 0 0 0 } \ + {KADM5_POLICY KADM5_PW_MIN_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +# Description: (11) Accepts 0 for pw_max_life. +test "create-policy 11" +proc test11 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_PW_MAX_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +# Description: (12) Accepts non-zero for pw_max_life. +test "create-policy 12" +proc test12 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 32 0 0 0 0 } \ + {KADM5_POLICY KADM5_PW_MAX_LIFE} + } $test]]} { + fail "$test" + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +# Description: (13) Rejects 0 for pw_min_length. +test "create-policy 13" +proc test13 {} { + global test + global prompt + + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_PW_MIN_LENGTH} + } $test] "BAD_LENGTH" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +# Description: (14) Accepts non-zero for pw_min_length. +test "create-policy 14" +proc test14 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 8 0 0 0 } \ + {KADM5_POLICY KADM5_PW_MIN_LENGTH} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 3\n" + expect { + -re "8\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +# Description: (15) Rejects 0 for pw_min_classes. +test "create-policy 15" +proc test15 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +# Description: (16) Accepts 1 for pw_min_classes. +test "create-policy 16" +proc test16 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 1 0 0 } \ + {KADM5_POLICY KADM5_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +# Description: (17) Accepts 4 for pw_min_classes. +test "create-policy 17" +proc test17 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 5 0 0} \ + {KADM5_POLICY KADM5_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "5\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +# Description: (18) Rejects 5 for pw_min_classes. +test "create-policy 18" +proc test18 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 6 0 0} \ + {KADM5_POLICY KADM5_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +# Description: (19) Rejects 0 for pw_history_num. +test "create-policy 19" +proc test19 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY KADM5_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +# Description: (20) Accepts 1 for pw_history_num. +test "create-policy 20" +proc test20 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 1 0} \ + {KADM5_POLICY KADM5_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retreuve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +# Description: (21) Accepts 10 for pw_history_num. +test "create-policy 21" +proc test21 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 10 0} \ + {KADM5_POLICY KADM5_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "10\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +# Description: (21.5) Rejects 11 for pw_history_num. +# 01/24/94: pshuang: untried. + +test "create-policy 21.5" +proc test215 {} { + global test + global prompt + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + + one_line_fail_test [format { + kadm5_create_policy $server_handle {"%s/a" 0 0 0 0 11 0} \ + {KADM5_POLICY KADM5_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test215 + + +# Description: (22) Fails for user with no access bits. +test "create-policy 22" +proc test22 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test22 + +# Description: (23) Fails for user with "get" but not "add". +test "create-policy 23" +proc test23 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test23 + +# Description: (24) Fails for user with "modify" but not "add". +# 01/24/94: pshuang: untried. +test "create-policy 24" +proc test24 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test24 + +# Description: (25) Fails for user with "delete" but not "add". +# 01/24/94: pshuang: untried. +test "create-policy 25" +proc test25 {} { + global test + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test25 + +# Description: Succeeds for user with "add". +test "create-policy 26" +proc test26 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +# Description: Succeeds for user with "get" and "add". +# 01/24/94: pshuang: untried. +test "create-policy 27" +proc test27 {} { + global test + + if {! (( ! [policy_exists "$test/a"]) || + [delete_policy "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/get-add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_create_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test27 + +# Description: (28) Rejects null policy argument. +# 01/24/94: pshuang: untried. +test "create-policy 28" +proc test28 {} { + global test + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_create_policy $server_handle null {KADM5_POLICY} + } "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "create-policy 30" +proc test30 {} { + global test + one_line_fail_test [format { + kadm5_create_policy null [simple_policy "%s/a"] \ + {KADM5_POLICY} + } $test] "BAD_SERVER_HANDLE" +} +test30 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/crte-principal.exp b/src/lib/kadm5/unit-test/api.2/crte-principal.exp new file mode 100644 index 000000000..653d1222a --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/crte-principal.exp @@ -0,0 +1,1330 @@ +source lib.t +api_exit +api_start + +#test "create-principal 1" +# +#proc test1 {} { +# global test +# begin_dump +# one_line_fail_test [format { +# kadm5_create_principal $server_handle \ +# [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a" +# } $test $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test1 + +test "create-principal 2" + +proc test2 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_create_principal $server_handle null \ + {KADM5_PRINCIPAL} testpass + } "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test2 + +test "create-principal 3" +proc test3 {} { + global test +# set prms_id 777 +# setup_xfail {*-*-*} $prms_id + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} null + } $test] "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test3 + +test "create-principal 4" +proc test4 {} { + global test + + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} "" + } $test] "_Q_TOOSHORT" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test4 + +test "create-principal 5" +proc test5 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle \ + [simple_principal "%s/a"] {0x100001} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test5 + +test "create-principal 6" +proc test6 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_LAST_PWD_CHANGE} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test6 + +test "create-principal 7" +proc test7 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MOD_TIME} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test7 + +test "create-principal 8" +proc test8 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MOD_NAME} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test8 + +test "create-principal 9" +proc test9 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MKVNO} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test9 + +test "create-principal 10" +proc test10 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_AUX_ATTRIBUTES} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test10 + +test "create-principal 11" +proc test11 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_POLICY_CLR} "%s/a" + } $test $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test11 + +test "create-principal 12" +proc test12 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" + +} +if {$RPC} { test12 } + +test "create-principal 13" +proc test13 {} { + global test + begin_dump + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test13 } + +test "create-principal 14" +proc test14 {} { + global test + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test14 } + +test "create-principal 15" +proc test15 {} { + global test + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test15 } + +test "create-principal 16" +proc test16 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +if {$RPC} { test16 } + +test "create-principal 17" +proc test17 {} { + global test + + begin_dump + if {! (( [principal_exists "$test/a"]) || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "DUP" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test17 + +test "create-principal 18" +proc test18 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY} tP + } $test] "_Q_TOOSHORT" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test18 + +test "create-principal 19" +proc test19 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY} testpassword + } $test] "_Q_CLASS" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test19 + +test "create-principal 20" +proc test20 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY} Abyssinia + } $test] "_Q_DICT" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test20 + +test "create-principal 21" +proc test21 {} { + global test + + begin_dump + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" non-existant-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY} NotinTheDictionary + } $test] "UNK_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + end_dump_compare "no-diffs" +} +test21 + +test "create-principal 23" +proc test23 {} { + global test + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + one_line_succeed_test \ + [format {kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK} $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test23 + +test "create-principal 24" +proc test24 {} { + global test + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/rename admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + one_line_succeed_test \ + [format {kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK} $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test24 } + + +test "create-principal 28" +proc test28 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + + if {! [cmd [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "create-principal 29" +proc test29 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL KADM5_PRINC_EXPIRE_TIME} \ + inTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 1\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test29 + +test "create-principal 30" +proc test30 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "create-principal 31" +proc test31 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol-nopw] \ + {KADM5_PRINCIPAL KADM5_POLICY \ + KADM5_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "create-principal 32" +proc test32 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + [princ_w_pol "%s/a" test-pol] \ + {KADM5_PRINCIPAL KADM5_POLICY \ + KADM5_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "create-principal 33" +proc test33 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + {"%s/a" 0 0 1234 0 null 0 0 0 0 null 0} \ + {KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test33 + +test "create-principal 34" +proc test34 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + { "%s/a" 0 0 1234 0 null 0 0 0 0 test-pol-nopw 0} \ + {KADM5_PRINCIPAL KADM5_POLICY \ + KADM5_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test34 + +test "create-principal 35" +proc test35 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + {"%s/a" 0 0 1234 0 null 0 0 0 0 test-pol 0} \ + {KADM5_PRINCIPAL KADM5_POLICY \ + KADM5_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "1234.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test35 + +test "create-principal 36" +proc test36 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle \ + {"%s/a" 0 0 999999999 0 null 0 0 0 0 test-pol 0} \ + {KADM5_PRINCIPAL KADM5_POLICY \ + KADM5_PW_EXPIRATION} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol policy} ]} { + error_and_restart "$test: cannot retrieve policy" + return + } + + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test36 + +test "create-principal 37" +proc test37 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test37 + +test "create-principal 38" +proc test38 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {KADM5_PRINCIPAL KADM5_POLICY} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 3\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test38 + +test "create-principal 39" +proc test39 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_PRINCIPAL KADM5_POLICY} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if { ! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: cannot not retrieve principal" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 6\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$mod_date + $pw_max_life - $pw_expire"] > 5 } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test39 + +test "create-principal 40" +proc test40 {} { + global test + global prompt + + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL KADM5_PW_EXPIRATION} \ + NotinTheDictionary + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: can not retreive principal" + return; + } + send "lindex \$principal 4\n" + expect { + -re "0.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test40 + +test "create-principal 43" +proc test43 {} { + global test + one_line_fail_test [format { + kadm5_create_principal null \ + [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a" + } $test $test] "BAD_SERVER_HANDLE" +} +test43 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/destroy.exp b/src/lib/kadm5/unit-test/api.2/destroy.exp new file mode 100644 index 000000000..808f0b401 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/destroy.exp @@ -0,0 +1,203 @@ +source lib.t +api_exit +api_start + +test "destroy 1" + +proc test1 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_destroy $server_handle} + end_dump_compare "no-diffs" +} +test1 + +#test "destroy 2" +# +#proc test2 {} { +# global test +# begin_dump +# if {! [cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test \ +# {kadm5_get_principal $server_handle admin principal} \ +# "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test2 + +#test "destroy 3" +#proc test3 {} { +# global test +# +# begin_dump +# if {! (( ! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} { +# error_and_restart "$test couldn't delete principal \"$test/a\"" +# return +# } +# if {! [cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# kadm5_create_principal $server_handle \ +# [simple_principal "%s/a"] {KADM5_PRINCIPAL} "%s/a" +# } $test $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test3 + +#test "destroy 4" +#proc test4 {} { +# global test prompt +# +# if {! (([principal_exists "$test/a"]) || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! ([cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }] && +# [cmd [format { +# kadm5_get_principal $server_handle "%s/a" principal +# } $test]])} { +# error_and_restart "$test: error getting principal" +# return; +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# kadm5_modify_principal $server_handle \ +# {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {KADM5_KVNO} +# } $test "77"] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test4 + +#test "destroy 5" +# +#proc test5 {} { +# global test +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! [cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }]} { +# error "$test: unexpected failure on init" +# return +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# return +# } +# one_line_fail_test [format { +# kadm5_delete_principal $server_handle "%s/a" +# } $test] "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test5 + +#test "destroy 6" +# +#proc test6 {} { +# global test +# begin_dump +# one_line_fail_test {kadm5_destroy $server_handle} "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test6 + + +#test "destroy 7" +# +#proc test7 {} { +# global test +# begin_dump +# if {! [cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }]} { +# error "$test: unexpected failure in init" +# return +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +# one_line_fail_test {kadm5_destroy $server_handle} "NOT_INIT" +# end_dump_compare "no-diffs" +#} +#test7 + +test "destroy 8" +proc test8 {} { + global test + begin_dump + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } + one_line_succeed_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } + end_dump_compare "no-diffs" +} +test8 + +test "destroy 9" +proc test9 {} { + global test + one_line_fail_test {kadm5_destroy null} "BAD_SERVER_HANDLE" +} +test9 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/dlte-policy.exp b/src/lib/kadm5/unit-test/api.2/dlte-policy.exp new file mode 100644 index 000000000..95a57dc20 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/dlte-policy.exp @@ -0,0 +1,207 @@ +source lib.t +api_exit +api_start + +test "delete-policy 2" +proc test2 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {kadm5_delete_policy $server_handle ""} "BAD_POL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test2 + +test "delete-policy 5" +proc test5 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} test5 + +test "delete-policy 6" +proc test6 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} test6 + +test "delete-policy 7" +proc test7 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_policy $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test7 + +test "delete-policy 10" +proc test10 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_delete_policy $server_handle "%s/a" + } $test]]} { + fail "$test" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if { [policy_exists "$test/a"]} { + fail "$test" + return + } +} +test10 + +test "delete-policy 12" +proc test12 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test unexecpted failure in init" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [princ_w_pol "%s/a" \ + "%s/a"] {KADM5_PRINCIPAL KADM5_POLICY} \ + NotinTheDictionary + } $test $test]]} { + fail "$test: can not create principal" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {kadm5_delete_policy $server_handle test-pol} "POLICY_REF" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "delete-policy 13" +proc test13 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + one_line_fail_test [format { + kadm5_delete_policy null "%s/a" + } $test] "BAD_SERVER_HANDLE" +} +test13 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/dlte-principal.exp b/src/lib/kadm5/unit-test/api.2/dlte-principal.exp new file mode 100644 index 000000000..fe157e880 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/dlte-principal.exp @@ -0,0 +1,329 @@ +source lib.t + +api_exit +api_start + +#test "delete-principal 1" +#proc test1 {} { +# global test +# one_line_fail_test [format { +# kadm5_delete_principal $server_handle "%s/a" +# } $test] "NOT_INIT" +#} +#test1 + +test "delete-principal 2" +proc test2 {} { + global test + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {kadm5_delete_principal $server_handle null} "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: unexpected failure in destroy" + return + } +} +test2 + +test "delete-principal 5" +proc test5 {} { + global test + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "UNK_PRINC" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +test "delete-principal 6" +proc test6 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test6 } + + +test "delete-principal 7" +proc test7 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test7 } + + +test "delete-principal 8" +proc test8 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test8 } + +test "delete-principal 9" +proc test9 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test9 } + +test "delete-principal 10" +proc test10 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_delete_principal $server_handle "%s/a" + } $test] "AUTH_DELETE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test10 } + +test "delete-principal 11" +proc test11 {} { + global test + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_delete_principal $server_handle "%s/a" + } $test]]} { + fail "$test: delete failed" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if { [principal_exists "$test/a"] } { + fail "$test" + return + } +} +test11 + +test "delete-principal 12" +proc test12 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd [format { + kadm5_delete_principal $server_handle "%s/a" + } $test]]} { + fail "$test: delete failed" + return + } + if { [cmd [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + fail "$test: principal still exists" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref - 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + pass "$test" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} + +test12 + +test "delete-principal 13" +proc test13 {} { + global test + one_line_fail_test [format { + kadm5_delete_principal null "%s/a" + } $test] "BAD_SERVER_HANDLE" +} +test13 + +return "" + + + + + diff --git a/src/lib/kadm5/unit-test/api.2/get-policy.exp b/src/lib/kadm5/unit-test/api.2/get-policy.exp new file mode 100644 index 000000000..ff41c17b9 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/get-policy.exp @@ -0,0 +1,199 @@ +source lib.t +api_exit +api_start + +test "get-policy 3" +proc test3 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {kadm5_get_policy $server_handle "" p} "BAD_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3 + +test "get-policy 6" +proc test6 {} { + global test + + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test6 + +test "get-policy 7" +proc test7 {} { + global test + + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test7 + +test "get-policy 11" +proc test11 {} { + global test + + if {! [cmd { + kadm5_init admin/get-pol StupidAdmin $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_policy $server_handle test-pol p} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "get-policy 12" +proc test12 {} { + global test + + if {! [cmd { + kadm5_init admin/get-pol StupidAdmin \ + $KADM5_CHANGEPW_SERVICE null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {kadm5_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "get-policy 15" +proc test15 {} { + global test + + if {! [cmd { + kadm5_init admin/pol StupidAdmin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {kadm5_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "get-policy 16" +proc test16 {} { + global test + + if {! [cmd { + kadm5_init admin/pol StupidAdmin $KADM5_CHANGEPW_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {kadm5_get_policy $server_handle test-pol-nopw p} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +test "get-policy 17" +proc test17 {} { + global test + + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_policy $server_handle test-pol p} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "get-policy 18" +proc test18 {} { + global test + + if {! [cmd { + kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test {kadm5_get_policy $server_handle test-pol p} \ + "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } test18 + +test "get-policy 21" +proc test21 {} { + global test + + one_line_fail_test {kadm5_get_policy null "pol1" p} "BAD_SERVER_HANDLE" +} +test21 diff --git a/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp new file mode 100644 index 000000000..486d1a6ab --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/get-principal-v2.exp @@ -0,0 +1,234 @@ +source lib.t +api_exit +api_start + +test "get-principal 100" +proc test100 {} { + global test prompt + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd { + kadm5_get_principal $server_handle testuser p \ + {KADM5_PRINCIPAL_NORMAL_MASK} + }]} { + error "$test: unexpected failure in get_principal" + } + send "lindex \$p 16\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_keys" + return + } + eof { + error_and_restart "$test: eof getting num_keys" + return + } + } + send "lindex \$p 17\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_tl $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_tl" + return + } + eof { + error_and_restart "$test: eof getting num_tl" + return + } + } + send "lindex \$p 18\n" + expect { + -re "({.*})\n$prompt" {set key_data $expect_out(1,string) } + -re "\n$prompt" { set key_data {} } + timeout { + error_and_restart "$test: timeout getting key_data" + return + } + eof { + error_and_restart "$test: eof getting key_data" + return + } + } + send "lindex \$p 19\n" + expect { + -re "({.*})\n$prompt" {set tl_data $expect_out(1,string) } + -re "\n$prompt" { set tl_data {} } + timeout { + error_and_restart "$test: timeout getting tl_data" + return + } + eof { + error_and_restart "$test: eof getting tl_data" + return + } + } + + set failed 0 + if {$num_keys != 0} { + fail "$test: num_keys $num_keys should be 0" + set failed 1 + } + if {$num_tl != 0} { + fail "$test: num_tl $num_tl should be 0" + set failed 1 + } + if {$key_data != {}} { + fail "$test: key_data $key_data should be {}" + set failed 1 + } + if {$tl_data != "{}"} { + fail "$test: tl_data $tl_data should be {}" + set failed 1 + } + if {$failed == 0} { + pass "$test" + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test100 + +proc test101_102 {rpc} { + global test prompt + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd { + kadm5_get_principal $server_handle testuser p \ + {KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA} + }]} { + error "$test: unexpected failure in get_principal" + } + send "lindex \$p 16\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_keys" + return + } + eof { + error_and_restart "$test: eof getting num_keys" + return + } + } + send "lindex \$p 18\n" + expect { + -re "({.*})\n$prompt" {set key_data $expect_out(1,string) } + -re "\n$prompt" { set key_data {} } + timeout { + error_and_restart "$test: timeout getting key_data" + return + } + eof { + error_and_restart "$test: eof getting key_data" + return + } + } + + set failed 0 + if {$num_keys != 2} { + fail "$test: num_keys $num_keys should be 2" + set failed 1 + } + for {set i 0} {$i < $num_keys} {incr i} { + set key "[lindex [lindex $key_data $i] 2]" + if {($rpc && [string compare $key ""] != 0) || + ((! $rpc) && [string compare $key ""] == 0)} { + fail "$test: key_data $key is wrong" + set failed 1 + + } + } + if {$failed == 0} { pass "$test" } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test "get-principal 101" +if {$RPC} {test101_102 $RPC} +test "get-principal 102" +if {! $RPC} {test101_102 $RPC} + +test "get-principal 103" +proc test103 {} { + global test prompt + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd { + kadm5_get_principal $server_handle testuser p \ + {KADM5_PRINCIPAL_NORMAL_MASK KADM5_TL_DATA} + }]} { + error "$test: unexpected failure in get_principal" + } + send "lindex \$p 17\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_tl $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_tl" + return + } + eof { + error_and_restart "$test: eof getting num_tl" + return + } + } + send "lindex \$p 19\n" + expect { + -re "({.*})\n$prompt" {set tl_data $expect_out(1,string) } + -re "\n$prompt" { set tl_data {} } + timeout { + error_and_restart "$test: timeout getting tl_data" + return + } + eof { + error_and_restart "$test: eof getting tl_data" + return + } + } + + if {$num_tl == 0} { + fail "$test: num_tl $num_tl should not be 0" + } elseif {$tl_data == {}} { + fail "$test: tl_data $tl_data should not be {}" + } else { + pass "$test" + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test103 + +return "" + + + + diff --git a/src/lib/kadm5/unit-test/api.2/get-principal.exp b/src/lib/kadm5/unit-test/api.2/get-principal.exp new file mode 100644 index 000000000..4f91b33bb --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/get-principal.exp @@ -0,0 +1,346 @@ +source lib.t +api_exit +api_start + +test "get-principal 1" +proc test1 {} { + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test \ + {kadm5_get_principal $server_handle null p KADM5_PRINCIPAL_NORMAL_MASK} "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test1 + +test "get-principal 2" +proc test2 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "UNK_PRINC" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test2 + +test "get-principal 3" +proc test3 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test3 } + +test "get-principal 4" +proc test4 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test4 } + +test "get-principal 5" +proc test5 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test5 } + +test "get-principal 6" +proc test6 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test6 } + +test "get-principal 7" +proc test7 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/delete admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test7 } + + +test "get-principal 8" +proc test8 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_get_principal $server_handle "%s/a" p KADM5_PRINCIPAL_NORMAL_MASK + } $test] "AUTH_GET" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test8 } + + +test "get-principal 9" +proc test9 {} { + global test + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {kadm5_get_principal $server_handle admin/none p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "get-principal 10" +proc test10 {} { + global test + if {! [cmd { + kadm5_init admin/none admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test \ + {kadm5_get_principal $server_handle admin/none p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +test "get-principal 11" +proc test11 {} { + global test + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_principal $server_handle admin/get p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "get-principal 12" +proc test12 {} { + global test + if {! [cmd { + kadm5_init admin/get admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_principal $server_handle admin/get p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "get-principal 13" +proc test13 {} { + global test + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_principal $server_handle admin/add p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "get-principal 14" +proc test14 {} { + global test + if {! [cmd { + kadm5_init admin/get-mod admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test {kadm5_get_principal $server_handle admin/add p KADM5_PRINCIPAL_NORMAL_MASK} + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +test "get-principal 15" +proc test15 {} { + one_line_fail_test \ + {kadm5_get_principal null "admin" p KADM5_PRINCIPAL_NORMAL_MASK} "BAD_SERVER_HANDLE" +} +test15 + +return "" + + + + diff --git a/src/lib/kadm5/unit-test/api.2/init-v2.exp b/src/lib/kadm5/unit-test/api.2/init-v2.exp new file mode 100644 index 000000000..5de25d6fe --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/init-v2.exp @@ -0,0 +1,545 @@ +source lib.t + +api_exit +api_start + +test "init 100" +proc test100 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_PROFILE} /does-not-exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "ENOENT" +} +test100 + +test "init 101" +proc test101 {} { + global test + + # XXX Fix to work with a remote TEST_SERVER. For now, make sure + # it fails in that case. + one_line_succeed_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADMIN_SERVER KADM5_CONFIG_KADMIND_PORT} {localhost 1751}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADMIN_SERVER KADM5_CONFIG_KADMIND_PORT} {localhost 1}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "RPC_ERROR" +} +if {$RPC} test101 + +test "init 102" +proc test102 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADMIN_SERVER} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "CONFIG_BADFORMAT" +} +if {$RPC} test102 + +test "init 103" +proc test103 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_DBNAME} /does-not-exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "ENOENT" +} +if {! $RPC} test103 + +test "init 104" +proc test104 {} { + global test + + # This is slightly lame, but it works: if CONFIG_ADBNAME is obeyed, + # then the lock file will be set based on it, and it won't exist. + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADBNAME} /does-not-exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "NOLOCKFILE" +} +if {! $RPC} test104 + +test "init 105" +proc test105 {} { + global test + + # The lock info is stored in a static structure so that it applies + # to all handles in the process (why?). We need to restart the api + # in order to ensure we are using the new lockfile. + api_exit + api_start + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADB_LOCKFILE} /does-not-exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "NOLOCKFILE" + + api_exit + api_start +} +if {! $RPC} test105 + +test "init 106" +proc test106 {} { + global test prompt + + send [string trim { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MKEY_FROM_KBD} 1] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }] + send "\n" + expect { + -re ":$" { set prompting 1} + -re "\nOK .*$prompt$" { fail "$test: premature success" } + -re "\nERROR .*$prompt$" { fail "$test: premature failure" } + timeout { fail "$test: timeout" } + eof { fail "$test: eof" } + } + if {$prompting} { + one_line_succeed_test mrroot + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} test106 + +test "init 107" +proc test107 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_STASH_FILE} /does-not-exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "KDB_CANTREAD_STORED" +} +if {! $RPC} test107 + +test "init 108" +proc test108 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MKEY_NAME} does/not/exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "KDB_NOMASTERKEY" +} +if {! $RPC} test108 + +test "init 109-113" +proc test109 {} { + global test prompt + + delete_principal "$test/a" + + # I'd like to specify flags explicitly and check them, as in the + # following config_params, but tcl gets mighty confused if I do and + # I have no idea why. +# [config_params {KADM5_CONFIG_MAX_LIFE KADM5_CONFIG_MAX_RLIFE KADM5_CONFIG_EXPIRATION KADM5_CONFIG_FLAGS KADM5_CONFIG_ENCTYPES} {10 20 30 KRB5_KDB_DISALLOW_TGT_BASED {}} ] + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MAX_LIFE KADM5_CONFIG_MAX_RLIFE KADM5_CONFIG_EXPIRATION KADM5_CONFIG_ENCTYPES} {10 20 30 {}} ] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + fail "$test: cannot init with max_life" + return + } + if {! [cmd [format { + kadm5_create_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test]]} { + fail "$test: can not create principal" + return; + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" p \ + {KADM5_PRINCIPAL_NORMAL_MASK KADM5_KEY_DATA} + } $test]]} { + fail "$test: can not get principal" + return; + } + send "puts \$p\n" + send "lindex \$p 4\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting max_life" + return + } + eof { + error_and_restart "$test: eof getting max_life" + return + } + } + send "lindex \$p 12\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set max_rlife $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting max_rlife" + return + } + eof { + error_and_restart "$test: eof getting max_rlife" + return + } + } + send "lindex \$p 1\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set expiration $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting expiration" + return + } + eof { + error_and_restart "$test: eof getting expiration" + return + } + } + send "lindex \$p 7\n" + expect { + -re "(\[A-Z_\]*)\n$prompt" {set flags $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting flags" + return + } + eof { + error_and_restart "$test: eof getting flags" + return + } + } + # This sorta worries me. Since the test is setting ENCTYPES to + # nothing, the principal has no keys. That means that nothing is + # printed for the keys in the correct case; but it feels too + # likely that nothing will be printed in the case of some problem. + send "lindex \$p 18\n" + expect { + -re "({.*})\n$prompt" {set key_data $expect_out(1,string) } + -re "\n$prompt" { set key_data {} } + timeout { + error_and_restart "$test: timeout getting flags" + return + } + eof { + error_and_restart "$test: eof getting flags" + return + } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } + if {$max_life == 10} { + pass "$test" + } else { + fail "$test: $max_life is not 10" + } + if {$max_rlife == 20} { + pass "$test" + } else { + fail "$test: $max_rlife is not 20" + } + if {$expiration == 30} { + pass "$test" + } else { + fail "$test: $expiration is not 30" + } + if {$flags == ""} { + pass "$test" + } else { + fail "$test: flags $flags are wrong" + } + if {$key_data == {}} { + pass "$test" + } else { + fail "$test: key_data $key_data is wrong" + } +} +if {! $RPC} test109 + +test "init 114" +proc test114 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADMIN_SERVER} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_SERVER_PARAMS" +} +if {! $RPC} test114 + +test "init 115" +proc test115 {} { + global test + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_DBNAME} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADBNAME} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ACL_FILE} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_DICT_FILE} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ADMIN_KEYTAB} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MKEY_FROM_KBD} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_STASH_FILE} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MKEY_NAME} does.not.exist] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ENCTYPE} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MAX_LIFE} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_MAX_RLIFE} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_EXPIRATION} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_FLAGS} 0] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" + + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_ENCTYPES} {{}}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "BAD_CLIENT_PARAMS" +} +if {$RPC} test115 + +test "init 116" +proc test116 {} { + global test + + delete_principal "$test/a" + + if {! [cmd {kadm5_init admin/get-add admin $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + get_add_handle}]} { + error_and_restart "$test: couldn't init with admin/get-add" + } + + if {! [cmd {kadm5_init admin/mod-delete admin $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + mod_delete_handle}]} { + error_and_restart "$test: couldn't init with admin/get-add" + } + + one_line_succeed_test { + kadm5_get_principal $get_add_handle testuser p \ + KADM5_PRINCIPAL_NORMAL_MASK + } + one_line_succeed_test [format { + kadm5_create_principal $get_add_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] + one_line_fail_test { + kadm5_modify_principal $get_add_handle [simple_principal testuser] \ + {KADM5_PRINC_EXPIRE_TIME} + } "AUTH_MODIFY" + one_line_fail_test { + kadm5_delete_principal $get_add_handle testuser + } "AUTH_DELETE" + + one_line_fail_test { + kadm5_get_principal $mod_delete_handle testuser p \ + KADM5_PRINCIPAL_NORMAL_MASK + } "AUTH_GET" + one_line_fail_test [format { + kadm5_create_principal $mod_delete_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} testpass + } $test] "AUTH_ADD" + one_line_succeed_test { + kadm5_modify_principal $mod_delete_handle [simple_principal testuser] \ + {KADM5_PRINC_EXPIRE_TIME} + } + one_line_succeed_test [format { + kadm5_delete_principal $mod_delete_handle "%s/a" + } $test] + + if {! [cmd {kadm5_destroy $get_add_handle}]} { + error_and_restart "$test: couldn't close get_add_handle" + } + if {! [cmd {kadm5_destroy $mod_delete_handle}]} { + error_and_restart "$test: couldn't close mod_delete_handle" + } +} +if {$RPC} test116 + +send "puts \$KADM5_ADMIN_SERVICE\n" +expect { + -re "(\[a-zA-Z/@\]+)\n$prompt" { + set KADM5_ADMIN_SERVICE $expect_out(1,string) + } + default { + error_and_restart "$test: timeout/eof getting admin_service" + return + } +} + +send "puts \$KADM5_CHANGEPW_SERVICE\n" +expect { + -re "(\[a-zA-Z/@\]+)\n$prompt" { + set KADM5_CHANGEPW_SERVICE $expect_out(1,string) + } + default { + error_and_restart "$test: timeout/eof getting changepw_service" + return + } +} + +test "init 150" +proc test150 {} { + global test KADM5_ADMIN_SERVICE + + set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2 + kdestroy + kinit testuser notathena "-S $KADM5_ADMIN_SERVICE" + one_line_succeed_test { + kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + kdestroy +} +if {$RPC} test150 + +test "init 151" +proc test151 {} { + global test KADM5_CHANGEPW_SERVICE + + set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2 + kdestroy + kinit testuser notathena "-S $KADM5_CHANGEPW_SERVICE" + one_line_succeed_test { + kadm5_init_with_creds testuser null $KADM5_CHANGEPW_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + kdestroy +} +if {$RPC} test151 + +test "init 152" +proc test152 {} { + global test KADM5_ADMIN_SERVICE + + kdestroy + one_line_fail_test { + kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "GSS_ERROR" +} +if {$RPC} test152 + +test "init 153" +proc test153 {} { + global test KADM5_ADMIN_SERVICE + + set env(KRB5CCNAME) /tmp/krb5cc_kadm5_init_v2 + kinit testuser notathena + one_line_fail_test { + kadm5_init_with_creds testuser null $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } "GSS_ERROR" +} +if {$RPC} test153 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/init.exp b/src/lib/kadm5/unit-test/api.2/init.exp new file mode 100644 index 000000000..97a99e0ba --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/init.exp @@ -0,0 +1,731 @@ +source lib.t + +# Assumptions: +# +# Principal "admin" exists, with "get", "add", "modify" and "delete" +# access bits and password "admin". +# The string "not-the-password" isn't the password of any user in the database. +# Database master password is "mrroot". + +api_exit +api_start +test "init 1" + +one_line_fail_test_nochk \ + {kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_REALM} {""}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle} + +test "init 2" + +one_line_fail_test_nochk \ + {kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_REALM} {@}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle} + +test "init 2.5" + +one_line_fail_test_nochk \ + {kadm5_init admin admin $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_REALM} {BAD.REALM}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 server_handle} + +test "init 3" + +proc test3 {} { + global test + if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + one_line_fail_test_nochk [format { + kadm5_init admin admin "%s/a" null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + } $test] +} +if {$RPC} { test3 } + +test "init 4" + +proc test4 {} { + global test + if {! ((! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + + one_line_fail_test_nochk [format { + kadm5_init admin admin "%s/a" null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test] +} +if {$RPC} { test4 } + +test "init 5" + +if {$RPC} { + one_line_fail_test_nochk { + kadm5_init admin admin admin null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + } +} + +test "init 6" + +proc test6 {} { + global test + + send "kadm5_init admin null \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_2 server_handle\n" + + expect { + {Enter password:} { } + eof { + fail "$test: eof instead of password prompt" + api_exit + api_start + return + } + timeout { + fail "$test: timeout instead of password prompt" + return + } + } + one_line_succeed_test "admin" + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if { $RPC } { test6 } + +test "init 7" +proc test7 {} { + global test + + send "kadm5_init admin \"\" \$KADM5_ADMIN_SERVICE null \$KADM5_STRUCT_VERSION \$KADM5_API_VERSION_2 server_handle\n" + + expect { + {Enter password:} { } + -re "key:$" { } + eof { + fail "$test: eof instead of password prompt" + api_exit + api_start + return + } + timeout { + fail "$test: timeout instead of password prompt" + return + } + } + one_line_succeed_test "admin" + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if { $RPC } { test7 } + +test "init 8" + +proc test8 {} { + global test + if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + one_line_fail_test_nochk [format { + kadm5_init "%s/a" admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test] +} +if {$RPC} { test8 } + +test "init 9" + +if {$RPC} { + global test + one_line_fail_test_nochk { + kadm5_init admin not-the-password $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } +} + +test "init 10" + +proc test10 {} { + global test +# set prms_id 562 +# setup_xfail {*-*-*} $prms_id + one_line_fail_test_nochk { + kadm5_init null admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } +} +test10 + +#test "init 11" +# +#proc test11 {} { +# global test +# set prms_id 563 +# setup_xfail {*-*-*} $prms_id +# one_line_fail_test_nochk { +# kadm5_init "" admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# } +#} +#test11 + +test "init 12" + +proc test12 {} { + global test + one_line_fail_test_nochk [format { + kadm5_init "%s/a" admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test] +} +if {$RPC} { test12 } + +test "init 13" + +proc test13 {} { + global test + one_line_fail_test_nochk [format { + kadm5_init "%s/a@SECURE-TEST.OV.COM" admin \ + $KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + } $test] +} +if {$RPC} { test13 } + +test "init 14" + +proc test14 {} { + global test + one_line_fail_test_nochk [format { + kadm5_init "%s/a@BAD.REALM" admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test] +} +if {$RPC} { test14 } + +test "init 15" + +if {$RPC} { + one_line_fail_test_nochk { + kadm5_init admin@BAD.REALM admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } +} + +test "init 16" + +proc test16 {} { + global test + one_line_succeed_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test16 + +test "init 17" + +proc test17 {} { + global test + one_line_succeed_test { + kadm5_init admin@SECURE-TEST.OV.COM admin \ + $KADM5_ADMIN_SERVICE null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test17 + +test "init 18" + +proc test18 {} { + global test + one_line_succeed_test { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test18 + +test "init 19" + +proc test19 {} { + global test + one_line_succeed_test { + kadm5_init admin@SECURE-TEST.OV.COM admin \ + $KADM5_ADMIN_SERVICE \ + [config_params {KADM5_CONFIG_REALM} {SECURE-TEST.OV.COM}] \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test19 + +test "init 20" + +proc test20 {} { + global test + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error_and_restart "$test: couldn't init database" + return + } + one_line_succeed_test \ + {kadm5_get_principal $server_handle admin principal KADM5_PRINCIPAL_NORMAL_MASK} + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test20 + +#test "init 21" +# +#proc test21 {} { +# global test +# if {! [cmd { +# kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }]} { +# error_and_restart "$test: couldn't init database" +# return +# } +# one_line_fail_test_nochk { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +#} +#test21 + + +# proc test22 {} { +# global test prompt +# set prompting 0 +# send [string trim { +# kadm5_init admin null null null $KADM5_STRUCT_VERSION \ +# $KADM5_API_VERSION_2 server_handle +# }] +# send "\n" +# expect { +# -re ":$" { set prompting 1} +# -re "\nOK .*$prompt$" { fail "$test: premature success" } +# -re "\nERROR .*$prompt$" { fail "$test: premature failure" } +# timeout { fail "$test: timeout" } +# eof { fail "$test: eof" } +# } +# if {$prompting} { +# one_line_succeed_test mrroot +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +# } +# if {! $RPC} { test22 } +# +# test "init 22.5" +# proc test225 {} { +# global test prompt +# set prompting 0 +# send [string trim { +# kadm5_init admin null null null $KADM5_STRUCT_VERSION \ +# $KADM5_API_VERSION_2 server_handle +# }] +# send "\n" +# expect { +# -re ":$" { set prompting 1} +# -re "\nOK .*$prompt$" { fail "$test: premature success" } +# -re "\nERROR .*$prompt$" { fail "$test: premature failure" } +# timeout { fail "$test: timeout" } +# eof { fail "$test: eof" } +# } +# if {$prompting} { +# one_line_succeed_test mrroot +# } +# if {! [cmd {kadm5_destroy $server_handle}]} { +# error_and_restart "$test: couldn't close database" +# } +# } +# if {! $RPC} { test225 } + +test "init 23" + +proc test23 {} { + global test + one_line_succeed_test { + kadm5_init admin not-the-password $KADM5_ADMIN_SERVICE \ + null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test23 } + +test "init 24" + +proc test24 {} { + global test + one_line_succeed_test { + kadm5_init admin admin null null $KADM5_STRUCT_VERSION \ + $KADM5_API_VERSION_2 server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test24 } + +test "init 25" + +proc test25 {} { + global test + one_line_succeed_test { + kadm5_init admin admin foobar null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if {! $RPC} { test25 } + +test "init 26" + +#proc test26 {} { +# global test +# +# api_exit +# api_start +# one_line_fail_test_nochk { +# kadm5_get_principal $server_handle admin principal +# } +#} +#test26 + +#test "init 27" +# +#proc test27 {} { +# global test +# +# if {! ((! [principal_exists "$test/a"]) || [delete_principal "$test/a"])} { +# error_and_restart "$test: couldn't delete principal \"$test/a\"" +# return +# } +# begin_dump +# if {[cmd [format { +# kadm5_create_principal $server_handle [simple_principal \ +# "%s/a"] {KADM5_PRINCIPAL} "%s/a" +# } $test $test]]} { +# fail "$test: unexpected success in add" +# return +# } +# end_dump_compare "no-diffs" +#} +#test27 + +#test "init 28" +# +#proc test28 {} { +# global test prompt +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {! ([cmd { +# kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ +# $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ +# server_handle +# }] && [cmd [format { +# kadm5_get_principal $server_handle "%s/a" principal +# } $test]])} { +# error_and_restart "$test: error getting principal" +# return; +# } +# send "lindex \$principal 8\n" +# expect { +# -re "\n(\[0-9\]+).*$prompt$" {set kvno $expect_out(1,string) } +# timeout { +# error_and_restart "$test: timeout getting principal kvno" +# return +# } +# eof { +# error_and_restart "$test: eof getting principal kvno" +# return +# } +# } +# api_exit +# api_start +# set new_kvno [expr "$kvno + 1"] +# if {[cmd [format { +# kadm5_modify_principal $server_handle \ +# {"%s/a" 0 0 0 0 0 0 0 %d 0 0 0} {KADM5_KVNO} +# } $test $new_kvno]]} { +# fail "$test: unexpected success in modify" +# return; +# } +# end_dump_compare "no-diffs" +#} +#test28 + +#test "init 29" +# +#proc test29 {} { +# global test +# +# if {! ([principal_exists "$test/a"] || [create_principal "$test/a"])} { +# error_and_restart "$test: couldn't create principal \"$test/a\"" +# return +# } +# begin_dump +# if {[cmd [format { +# kadm5_delete_principal $server_handle "%s/a" +# } $test]]} { +# fail "$test: unexpected success in delete" +# return +# } +# end_dump_compare "no-diffs" +#} +#test29 + +test "init 30" +proc test30 {} { + global test + if {[cmd { + kadm5_init admin foobar $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error_and_restart "$test: unexpected succsess" + return + } + one_line_succeed_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +if ${RPC} { test30 } + +test "init 31" +proc test31 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $bad_struct_version_mask $KADM5_API_VERSION_2 \ + server_handle + } "BAD_STRUCT_VERSION" +} +test31 + +test "init 32" +proc test32 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $no_struct_version_mask $KADM5_API_VERSION_2 \ + server_handle + } "BAD_STRUCT_VERSION" +} +test32 + +test "init 33" +proc test33 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $old_struct_version $KADM5_API_VERSION_2 \ + server_handle + } "OLD_STRUCT_VERSION" +} +test33 + +test "init 34" +proc test34 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $new_struct_version $KADM5_API_VERSION_2 \ + server_handle + } "NEW_STRUCT_VERSION" +} +test34 + +test "init 35" +proc test35 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $bad_api_version_mask \ + server_handle + } "BAD_API_VERSION" +} +test35 + +test "init 36" +proc test36 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $no_api_version_mask \ + server_handle + } "BAD_API_VERSION" +} +test36 + +test "init 37" +proc test37 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $old_api_version \ + server_handle + } "OLD_LIB_API_VERSION" +} +if { $RPC } test37 + +test "init 38" +proc test38 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $old_api_version \ + server_handle + } "OLD_SERVER_API_VERSION" +} +if { ! $RPC } test38 + +test "init 39" +proc test39 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $new_api_version \ + server_handle + } "NEW_LIB_API_VERSION" +} +if { $RPC } test39 + +test "init 40" +proc test40 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $new_api_version \ + server_handle + } "NEW_SERVER_API_VERSION" +} +if { ! $RPC } test40 + +test "init 41" +proc test41 {} { + global test + one_line_fail_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_API_VERSION_2 $KADM5_STRUCT_VERSION \ + server_handle + } "BAD_" +} +test41 + +test "init 42" +proc test42 {} { + global test + one_line_succeed_test { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } + if {! [cmd {kadm5_destroy $server_handle}]} { + error_and_restart "$test: couldn't close database" + } +} +test42 + + +proc test45_46 {service} { + global test kdb5_edit env + + spawn $kdb5_edit -R "del $service" + expect { + {Type 'yes' to confirm:} { + send "yes\n" + } + default { + error "kdb5_edit del failed\n"; + } + } + expect eof + wait + + one_line_fail_test [concat {kadm5_init admin admin } \ + $service \ + { null $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle}] "SECURE_PRINC_MISSING" + + # this leaves the keytab with an incorrect entry + exec $kdb5_edit -R "ark $service" + + # restart the api so it gets a new ccache + api_exit + api_start +} + +if {$RPC} { + test "init 45" + + test45_46 ovsec_adm/admin + + test "init 46" + + test45_46 ovsec_adm/changepw + + # re-extract the keytab so it is right + exec rm /krb5/ovsec_adm.srvtab + exec $env(MAKE_KEYTAB) -princ ovsec_adm/admin -princ ovsec_adm/changepw \ + -princ kadmin/admin -princ kadmin/changepw /krb5/ovsec_adm.srvtab +} + +return "" + diff --git a/src/lib/kadm5/unit-test/api.2/mod-policy.exp b/src/lib/kadm5/unit-test/api.2/mod-policy.exp new file mode 100644 index 000000000..07e2e62db --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/mod-policy.exp @@ -0,0 +1,703 @@ +source lib.t +api_exit +api_start + +test "modify-policy 2" +proc test2 {} { + global test + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2 } + +test "modify-policy 4" +proc test4 {} { + global test + + if {! ([policy_exists "$test/a"] || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_REF_COUNT} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + +test "modify-policy 8" +proc test8 {} { + global test +# set prms_id 744 +# setup_xfail {*-*-*} $prms_id + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_modify_policy $server_handle [simple_policy ""] \ + {KADM5_PW_MAX_LIFE} + } "BAD_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +test "modify-policy 9" +proc test9 {} { + global test + global prompt + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MIN_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "modify-policy 10" +proc test10 {} { + global test + global prompt + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 32 0 0 0 0 0} \ + {KADM5_PW_MIN_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 1\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + + +test "modify-policy 11" +proc test11 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test11 + +test "modify-policy 12" +proc test12 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 32 0 0 0 0} \ + {KADM5_PW_MAX_LIFE} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 2\n" + expect { + -re "32\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test12 + +test "modify-policy 13" +proc test13 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MIN_LENGTH} + } $test] "BAD_LENGTH" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "modify-policy 14" +proc test14 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 8 0 0 0} \ + {KADM5_PW_MIN_LENGTH} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 3\n" + expect { + -re "8\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test14 + +test "modify-policy 15" +proc test15 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "modify-policy 16" +proc test16 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 0 1 0 0} \ + {KADM5_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test16 + +test "modify-policy 17" +proc test17 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a"])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 0 5 0 0} \ + {KADM5_PW_MIN_CLASSES} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 4\n" + expect { + -re "5\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "modify-policy 18" +proc test18 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 0 6 0 0} \ + {KADM5_PW_MIN_CLASSES} + } $test] "BAD_CLASS" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +test "modify-policy 19" +proc test19 {} { + global test + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_HISTORY_NUM} + } $test] "BAD_HISTORY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +test "modify-policy 20" +proc test20 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 0 0 1 0} \ + {KADM5_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "1\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +test "modify-policy 21" +proc test21 {} { + global test + global prompt + + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_policy $server_handle {"%s/a" 0 0 0 0 10 0} \ + {KADM5_PW_HISTORY_NUM} + } $test]]} { + fail $test + return + } + if {! [cmd [format { + kadm5_get_policy $server_handle "%s/a" policy + } $test]]} { + fail "$test: can not retrieve policy" + return + } + send "lindex \$policy 5\n" + expect { + -re "10\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +test "modify-policy 22" +proc test22 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test22 + +test "modify-policy 23" +proc test23 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test] "AUTH_MODIFY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} test23 + +test "modify-policy 26" +proc test26 {} { + global test + if {! (( [policy_exists "$test/a"]) || + [create_policy "$test/a" ])} { + error_and_restart "$test: couldn't create policy \"$test/a\"" + return + } + + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_modify_policy $server_handle [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +test "modify-policy 30" +proc test30 {} { + global test + + one_line_fail_test [format { + kadm5_modify_policy null [simple_policy "%s/a"] \ + {KADM5_PW_MAX_LIFE} + } $test] "BAD_SERVER_HANDLE" +} +test30 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/mod-principal.exp b/src/lib/kadm5/unit-test/api.2/mod-principal.exp new file mode 100644 index 000000000..5e24e08b0 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/mod-principal.exp @@ -0,0 +1,1942 @@ +source lib.t +api_exit +api_start + +#test "modify-principal 1" +#proc test1 {} { +# global test +# one_line_fail_test [format { +# kadm5_modify_principal $server_handle [simple_principal \ +# "%s/a"] {KADM5_PW_EXPIRATION} +# } $test] "NOT_INIT" +#} +#test1 + +test "modify-principal 2" +proc test2 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "AUTH_MODIFY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2 } + +test "modify-principal 4" +proc test4 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINCIPAL} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test4 + + +test "modify-principal 5" +proc test5 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_LAST_PWD_CHANGE} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test5 + +test "modify-principal 6" +proc test6 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MOD_TIME} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test6 + +test "modify-principal 7" +proc test7 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MOD_NAME} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test7 + +test "modify-principal 8" +proc test8 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MKVNO} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test8 + +test "modify-principal 9" +proc test9 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_AUX_ATTRIBUTES} + } $test] "BAD_MASK" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test9 + +test "modify-principal 10" +proc test10 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "UNK_PRINC" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test10 + +test "modify-principal 11" +proc test11 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/none admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test11 } + +test "modify-principal 12" +proc test12 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/get admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test12 } + +test "modify-principal 13" +proc test13 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/add admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test13 } + +test "modify-principal 14" +proc test14 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/delete admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] "AUTH_MOD" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test14 } + +test "modify-principal 15" +proc test15 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test15 + +test "modify-principal 17" +proc test17 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + no-policy] {KADM5_POLICY} + } $test] "UNK_POLICY" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test17 + +test "modify-principal 18" +proc test18 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref + 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test18 + +test "modify-principal 19" +proc test19 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref + 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test19 + +test "modify-principal 20" +proc test20 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_POLICY_CLR} + } $test]]} { + error "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { fail "$test" } + timeout { pass "$test" } + } + send "lindex \$p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$oldref - 1"] != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test20 + +test "modify-principal 21" +proc test21 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw old_p2}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$old_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + send "lindex \$old_p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p2_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if { ! [cmd {kadm5_get_policy $server_handle test-pol new_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol-nopw new_p2}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$new_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + send "lindex \$new_p2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p2_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { [expr "$old_p1_ref - 1"] != $new_p1_ref } { + fail "$test: policy reference count is wrong" + return; + } + if { [expr "$old_p2_ref + 1"] != $new_p2_ref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21 + +test "modify-principal 21.5" +proc test21.5 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol old_p1}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$old_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set old_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if { ! [cmd {kadm5_get_policy $server_handle test-pol new_p1}]} { + error "$test: unexpected failure on get policy" + return + } + + send "lindex \$new_p1 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set new_p1_ref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + + if {$old_p1_ref != $new_p1_ref} { + fail "$test: policy reference count changed ($old_p1_ref to $new_p1_ref)" + return + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test21.5 + +test "modify-principal 22" +proc test22 {} { + global test + global prompt + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test22 + +test "modify-principal 23" +proc test23 {} { + global test + global prompt + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" test-pol-nopw])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test23 + +test "modify-principal 24" +proc test24 {} { + global test + global prompt +# set prms_id 1358 +# setup_xfail {*-*-*} $prms_id + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error_and_restart "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: could not modify principal" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd [format { + kadm5_get_policy $server_handle %s policy + } test-pol]]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test24 + +test "modify-principal 25" +proc test25 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test25 + +test "modify-principal 26" +proc test26 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol-nopw" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test26 + +test "modify-principal 27" +proc test27 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 1234 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test27 + +test "modify-principal 28" +proc test28 {} { + global test + global prompt +# set prms_id 1358 +# setup_xfail {*-*-*} $prms_id + + if {! (( [principal_exists "$test/a"]) || + [create_principal_pol "$test/a" "test-pol" ])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 900 0 0 0 0 0 0 0 0} {KADM5_PW_EXPIRATION} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] == $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + pass "$test" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "modify-principal 29" +proc test29 {} { + global test + global prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { ! ([create_principal_pol "$test/a" test-pol])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_POLICY_CLR} + } $test]]} { + fail "$test: modifiy failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test29 + +test "modify-principal 30" +proc test30 {} { + global test + global prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal_pol "$test/a" test-pol])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol-nopw] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 3\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "modify-principal 31" +proc test31 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_POLICY} + } $test]]} { + fail "modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol policy}]} { + error_and_restart "$test: cannot retrieve policy" + return + } + send "lindex \$principal 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_mod_date $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_mod_date" + return + } + eof { + error_and_restart "$test: eof getting pw_mod_date" + return + } + } + + send "lindex \$principal 3\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_expire $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_expire" + return + } + eof { + error_and_restart "$test: eof getting pw_expire" + return + } + } + + send "lindex \$policy 2\n" + expect { + -re "(\[0-9\]+)\n$prompt" {set pw_max_life $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting pw_max_life" + return + } + eof { + error_and_restart "$test: eof getting pw_max_life" + return + } + } + if { [expr "$pw_mod_date + $pw_max_life"] != $pw_expire } { + fail "$test: pw_expire is wrong" + return + } + + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "modify-principal 32" +proc test32 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 1234 0 0 0 0 0 0 0 0 0 0} \ + {KADM5_PRINC_EXPIRE_TIME} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 1\n" + expect { + -re "1234\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "modify-principal 33" +proc test33 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_ALL_TIX 0 0 0 0} \ + {KADM5_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_DISALLOW_ALL_TIX.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test33 + +test "modify-principal 33.25" +proc test3325 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_REQUIRES_PWCHANGE 0 0 0 0} \ + {KADM5_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_REQUIRES_PWCHANGE.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test3325 + +test "modify-principal 33.5" +proc test335 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 KRB5_KDB_DISALLOW_TGT_BASED 0 0 0 0} \ + {KADM5_ATTRIBUTES} + } $test]]} { + fail "$test: modified fail" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 7\n" + expect { + -re "KRB5_KDB_DISALLOW_TGT_BASED.*$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test335 + + +test "modify-principal 34" +proc test34 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 0 3456 0 0 0 0 0 0 0} {KADM5_MAX_LIFE} + } $test]]} { + fail "$test: modify failed" + return + } + + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 4\n" + expect { + -re "3456\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test34 + +test "modify-principal 35" +proc test35 {} { + global prompt + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd [format { + kadm5_modify_principal $server_handle \ + {"%s/a" 0 0 0 0 0 0 0 7 0 0 0} {KADM5_KVNO} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 8\n" + expect { + -re "7\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test35 + +test "modify-principal 36" +proc test36 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal_pol "$test/a" "test-pol"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol pol}]} { + error "$test: unexpected failure on get policy" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + test-pol] {KADM5_POLICY} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 10\n" + expect { + -re "test-pol\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + send "lindex \$pol 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set oldref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { ! [cmd {kadm5_get_policy $server_handle test-pol pol2}]} { + error "$test: unexpected failure on get policy" + return + } + send "lindex \$pol2 6\n" + expect { + -re "(\[0-9\]+)\n$prompt$" {set newref $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting principal kvno (second time)" + return + } + eof { + error_and_restart "$test: eof getting principal kvno (second time)" + return + } + } + if { $oldref != $newref } { + fail "$test: policy reference count is wrong" + return; + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test36 + +test "modify-principal 37" +proc test37 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if { !( [create_principal "$test/a"])} { + error_and_restart "$test: could not create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_POLICY_CLR} + } $test]]} { + fail "$test: modify failed" + return + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test37 + +test "modify-principal 38" +proc test38 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_PRINC_EXPIRE_TIME} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 1\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test38 + +test "modify-principal 39" +proc test39 {} { + global test + global prompt + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! ([create_principal "$test/a"])} { + error "$test: unexpected failure in creating principal" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [simple_principal "%s/a"] \ + {KADM5_MAX_LIFE} + } $test]]} { + fail "$test: modify failed" + return + } + if {! [cmd [format { + kadm5_get_principal $server_handle "%s/a" principal KADM5_PRINCIPAL_NORMAL_MASK + } $test]]} { + error_and_restart "$test: could not retrieve principal" + return + } + send "lindex \$principal 4\n" + expect { + -re "0\n$prompt$" { pass "$test" } + timeout { fail "$test" } + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test39 + +test "modify-principal 40" +proc test40 {} { + global test + global prompt + + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_modify_principal $server_handle null \ + {KADM5_PRINC_EXPIRE_TIME} + } "EINVAL" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test40 + +test "modify-principal 43" +proc test43 {} { + global test + one_line_fail_test [format { + kadm5_modify_principal null [simple_principal \ + "%s/a"] {KADM5_PW_EXPIRATION} + } $test] "BAD_SERVER_HANDLE" +} +test43 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp b/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp new file mode 100644 index 000000000..c3dfd18df --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/randkey-principal-v2.exp @@ -0,0 +1,62 @@ +source lib.t +api_exit +api_start + +test "randkey-principal 100" +proc test100 {} { + global test prompt + + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + + # I'd like to specify a long list of keysalt tuples and make sure + # that randkey does the right thing, but we can only use those + # enctypes that krbtgt has a key for: des-cbc-crc:normal and + # des-cbc-crc:v4, according to the prototype kdc.conf. + if {! [cmd [format { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test]]} { + error "$test: unexpected failure in randkey_principal" + } + send "puts \$num_keys\n" + expect { + -re "(\[0-9\]+)\n$prompt" { set num_keys $expect_out(1,string) } + timeout { + error_and_restart "$test: timeout getting num_keys" + return + } + eof { + error_and_restart "$test: eof getting num_keys" + return + } + } + + # XXX Perhaps I should actually check the key type returned. + if {$num_keys == 1} { + pass "$test" + } else { + fail "$test: $num_keys keys, should be 1" + } + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test100 + +return "" diff --git a/src/lib/kadm5/unit-test/api.2/randkey-principal.exp b/src/lib/kadm5/unit-test/api.2/randkey-principal.exp new file mode 100644 index 000000000..d693a2ac1 --- /dev/null +++ b/src/lib/kadm5/unit-test/api.2/randkey-principal.exp @@ -0,0 +1,319 @@ +source lib.t +api_exit +api_start + +test "randkey-principal 1" +proc test1 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + kadm5_init "%s/a" "%s/a" $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] "PASS_TOOSOON" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test1 } + +test "randkey-principal 3" +proc test3 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + kadm5_init "%s/a" "%s/a" $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] "PASS_TOOSOON" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if ${RPC} { test3 } + +test "randkey-principal 13" +proc test13 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + if {! [cmd [format { + kadm5_modify_principal $server_handle [princ_w_pol "%s/a" \ + once-a-min] KADM5_POLICY + } $test]]} { + error "$test: failed modify" + return + } + one_line_succeed_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test13 + +test "randkey-principal 15" +proc test15 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal_pol "$test/a" once-a-min]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] "AUTH_CHANGEPW" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if { $RPC } { test15 } + +test "randkey-principal 28" +proc test28 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test28 + +test "randkey-principal 28.25" +proc test2825 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin admin $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] "AUTH" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +if {$RPC} { test2825 } + +test "randkey-principal 28.5" +proc test285 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [cmd { + kadm5_init admin/modify admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test285 + +test "randkey-principal 30" +proc test30 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't delete principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + if {! [cmd [format { + kadm5_init "%s/a" "%s/a" $KADM5_CHANGEPW_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test30 + +test "randkey-principal 31" +proc test31 {} { + global test + if {! (( ! [principal_exists "$test/a"]) || + [delete_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if {! [create_principal "$test/a"]} { + error_and_restart "$test: creating principal" + return + } + + if {! [cmd [format { + kadm5_init "%s/a" "%s/a" $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + } $test $test]]} { + error "$test: unexpected failure in init" + return + } + one_line_succeed_test [format { + kadm5_randkey_principal $server_handle "%s/a" keys num_keys + } $test] + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test31 + +test "randkey-principal 32" +proc test32 {} { + global test + + if { ! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test { + kadm5_randkey_principal $server_handle kadmin/history keys num_keys + } "PROTECT" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} +test32 + +test "randkey-principal 33" +proc test33 {} { + global test + if {! (( [principal_exists "$test/a"]) || + [create_principal "$test/a"])} { + error_and_restart "$test: couldn't create principal \"$test/a\"" + return + } + if { ! [cmd { + kadm5_init admin admin $KADM5_ADMIN_SERVICE null \ + $KADM5_STRUCT_VERSION $KADM5_API_VERSION_2 \ + server_handle + }]} { + error "$test: unexpected failure in init" + return + } + one_line_fail_test [format { + kadm5_randkey_principal null "%s/a" keys num_keys + } $test] "BAD_SERVER_HANDLE" + if { ! [cmd {kadm5_destroy $server_handle}]} { + error "$test: unexpected failure in destroy" + return + } +} + +test33 + +return "" diff --git a/src/lib/kadm5/unit-test/config/unix.exp b/src/lib/kadm5/unit-test/config/unix.exp new file mode 100644 index 000000000..e9a681f93 --- /dev/null +++ b/src/lib/kadm5/unit-test/config/unix.exp @@ -0,0 +1,113 @@ +set stty_init {-onlcr -opost intr \^C kill \^U} +set kdb5_edit $KDBFIVE_EDIT +set kadmin_local $KADMIN_LOCAL + +# Backward compatibility until we're using expect 5 everywhere +if {[info exists exp_version_4]} { + global wait_error_index wait_errno_index wait_status_index + set wait_error_index 0 + set wait_errno_index 1 + set wait_status_index 1 +} else { + set wait_error_index 2 + set wait_errno_index 3 + set wait_status_index 3 +} + +proc api_exit {} { + global spawn_id + +# puts stdout "Starting api_exit (spawn_id $spawn_id)." + catch {close} errMsg + catch {wait} errMsg +# puts stdout "Finishing api_exit." +} + +proc api_version {} { +} + +proc api_start {} { + global API + global env + global spawn_id + global prompt + + spawn $API + expect { + -re "$prompt$" {} + eof { error "EOF starting API" } + timeout { error "Timeout starting API" } + } + if {! [info exists env(TCLUTIL)]} { + error "TCLUTIL environment variable isn't set" + } + send "source $env(TCLUTIL)\n" + expect { + -re "$prompt$" {} + eof { error "EOF starting API" } + timeout { error "Timeout starting API" } + } + send "set current_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION &~ \$OVSEC_KADM_STRUCT_VERSION_MASK\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set current_api_version \[expr \$OVSEC_KADM_API_VERSION_1 &~ \$OVSEC_KADM_API_VERSION_MASK\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set bad_struct_version_mask \[expr 0x65432100 | \$current_struct_version\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set bad_api_version_mask \[expr 0x65432100 | \$current_api_version\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set no_api_version_mask \$current_api_version\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set no_struct_version_mask \$current_struct_version\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set old_api_version \[expr \$OVSEC_KADM_API_VERSION_MASK | 0x00\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set old_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION_MASK | 0x00\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set new_api_version \[expr \$OVSEC_KADM_API_VERSION_MASK | 0xca\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } + send "set new_struct_version \[expr \$OVSEC_KADM_STRUCT_VERSION_MASK | 0xca\]\n" + expect { + -re "$prompt$" {} + eof { error "EOF setting API varibles"} + timeout { error "timeout setting API varibles"} + } +# puts stdout "Finishing api_start (spawn_id $spawn_id)." +} +api_start + diff --git a/src/lib/kadm5/unit-test/destroy-test.c b/src/lib/kadm5/unit-test/destroy-test.c new file mode 100644 index 000000000..0db69c3a1 --- /dev/null +++ b/src/lib/kadm5/unit-test/destroy-test.c @@ -0,0 +1,42 @@ +#include <kadm5/admin.h> +#include <com_err.h> +#include <stdio.h> +#include <krb5.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <unistd.h> +#include <netinet/in.h> +#include <kadm5/client_internal.h> +#include <string.h> + +#define TEST_NUM 25 + +main() +{ + ovsec_kadm_ret_t ret; + char *cp; + int x, i; + void *server_handle; + kadm5_server_handle_t handle; + + for(x = 0; x < TEST_NUM; x++) { + ret = ovsec_kadm_init("admin", "admin", "ovsec_adm/admin", 0, + OVSEC_KADM_STRUCT_VERSION, + OVSEC_KADM_API_VERSION_1, + &server_handle); + if(ret != OVSEC_KADM_OK) { + com_err("test", ret, "init"); + exit(2); + } + handle = (kadm5_server_handle_t) server_handle; + cp = (char *) strdup(((char *) (strchr(handle->cache_name, ':')) + 1)); + ovsec_kadm_destroy(server_handle); + if(access(cp, F_OK) == 0) { + puts("ticket cache not destroyed"); + exit(2); + } + free(cp); + } + exit(0); +} + diff --git a/src/lib/kadm5/unit-test/diff-files/destroy-1 b/src/lib/kadm5/unit-test/diff-files/destroy-1 new file mode 100644 index 000000000..593d67320 --- /dev/null +++ b/src/lib/kadm5/unit-test/diff-files/destroy-1 @@ -0,0 +1,2 @@ +##! nochanges + diff --git a/src/lib/kadm5/unit-test/diff-files/no-diffs b/src/lib/kadm5/unit-test/diff-files/no-diffs new file mode 100644 index 000000000..593d67320 --- /dev/null +++ b/src/lib/kadm5/unit-test/diff-files/no-diffs @@ -0,0 +1,2 @@ +##! nochanges + diff --git a/src/lib/kadm5/unit-test/handle-test.c b/src/lib/kadm5/unit-test/handle-test.c new file mode 100644 index 000000000..ced1d183d --- /dev/null +++ b/src/lib/kadm5/unit-test/handle-test.c @@ -0,0 +1,131 @@ +#include <kadm5/admin.h> +#include <com_err.h> +#include <stdio.h> +#include <krb5.h> +#include <sys/socket.h> +#include <sys/file.h> +#include <unistd.h> +#include <netinet/in.h> +#include <kadm5/client_internal.h> + + +main(int argc, char *argv[]) +{ + ovsec_kadm_ret_t ret; + void *server_handle; + kadm5_server_handle_t handle; + kadm5_server_handle_rec orig_handle; + ovsec_kadm_policy_ent_t pol; + ovsec_kadm_principal_ent_t princ; + krb5_keyblock *key; + krb5_principal tprinc; + krb5_context context; + int *p; + + + krb5_init_context(&context); + + ret = ovsec_kadm_init("admin/none", "admin", "ovsec_adm/admin", 0, + OVSEC_KADM_STRUCT_VERSION, OVSEC_KADM_API_VERSION_1, + &server_handle); + if(ret != OVSEC_KADM_OK) { + com_err("test", ret, "init"); + exit(2); + } + handle = (kadm5_server_handle_t) server_handle; + orig_handle = *handle; + handle->magic_number = OVSEC_KADM_STRUCT_VERSION; + krb5_parse_name(context, "testuser", &tprinc); + ret = ovsec_kadm_get_principal(server_handle, tprinc, &princ); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "get-principal", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_get_policy(server_handle, "pol1", &pol); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "get-policy", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_create_principal(server_handle, princ, OVSEC_KADM_PRINCIPAL, "pass"); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "create-principal", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_create_policy(server_handle, pol, OVSEC_KADM_POLICY); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "create-policy", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_modify_principal(server_handle, princ, OVSEC_KADM_PW_EXPIRATION); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "modify-principal", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_modify_policy(server_handle, pol, OVSEC_KADM_PW_MAX_LIFE); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "modify-policy", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_delete_principal(server_handle, tprinc); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "delete-principal", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_delete_policy(server_handle, "pol1"); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "delete-policy", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_chpass_principal(server_handle, tprinc, "FooBar"); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "chpass", + error_message(ret)); + exit(1); + } + ret = ovsec_kadm_randkey_principal(server_handle, tprinc, &key); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "randkey", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_rename_principal(server_handle, tprinc, tprinc); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "rename", + error_message(ret)); + exit(1); + } + + ret = ovsec_kadm_destroy(server_handle); + if(ret != OVSEC_KADM_BAD_SERVER_HANDLE) { + fprintf(stderr, "%s -- returned -- %s\n", "destroy", + error_message(ret)); + exit(1); + } + + *handle = orig_handle; + ret = ovsec_kadm_destroy(server_handle); + if (ret != OVSEC_KADM_OK) { + fprintf(stderr, "valid %s -- returned -- %s\n", "destroy", + error_message(ret)); + exit(1); + } + + exit(0); +} diff --git a/src/lib/kadm5/unit-test/init-test.c b/src/lib/kadm5/unit-test/init-test.c new file mode 100644 index 000000000..823dd222b --- /dev/null +++ b/src/lib/kadm5/unit-test/init-test.c @@ -0,0 +1,26 @@ +#include <kadm5/admin.h> +#include <com_err.h> +#include <stdio.h> +#include <krb5.h> + +main() +{ + ovsec_kadm_ret_t ret; + void *server_handle; + + ret = ovsec_kadm_init("admin", "admin", OVSEC_KADM_ADMIN_SERVICE, 0, + OVSEC_KADM_STRUCT_VERSION, + OVSEC_KADM_API_VERSION_1, + &server_handle); + if (ret == OVSEC_KADM_RPC_ERROR) + exit(0); + else if (ret != OVSEC_KADM_OK) { + com_err("init-test", ret, "while (hacked) initializing"); + exit(1); + } + else { + fprintf(stderr, "Unexpected success while (hacked) initializing!\n"); + (void) ovsec_kadm_destroy(server_handle); + exit(1); + } +} diff --git a/src/lib/kadm5/unit-test/iter-test.c b/src/lib/kadm5/unit-test/iter-test.c new file mode 100644 index 000000000..7ca43d44f --- /dev/null +++ b/src/lib/kadm5/unit-test/iter-test.c @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <kadm5/admin.h> + +main(int argc, char **argv) +{ + ovsec_kadm_ret_t ret; + void *server_handle; + char **names; + int count, princ; + + if (argc != 3) { + fprintf(stderr, "Usage: %s [-princ|-pol] exp\n", argv[0]); + exit(1); + } + princ = (strcmp(argv[1], "-princ") == 0); + + ret = ovsec_kadm_init("admin", "admin", OVSEC_KADM_ADMIN_SERVICE, 0, + OVSEC_KADM_STRUCT_VERSION, + OVSEC_KADM_API_VERSION_1, + &server_handle); + if (ret != OVSEC_KADM_OK) { + com_err("iter-test", ret, "while initializing"); + exit(1); + } + + if (princ) + ret = ovsec_kadm_get_principals(server_handle, argv[2], &names, + &count); + else + ret = ovsec_kadm_get_policies(server_handle, argv[2], + &names, &count); + + if (ret != OVSEC_KADM_OK) { + com_err("iter-test", ret, "while retrieving list"); + exit(1); + } + + for (ret = 0; ret < count; ret++) + printf("%d: %s\n", ret, names[ret]); + + ovsec_kadm_free_name_list(server_handle, names, count); + + (void) ovsec_kadm_destroy(server_handle); + + return 0; +} + diff --git a/src/lib/kadm5/unit-test/lib.t b/src/lib/kadm5/unit-test/lib.t new file mode 100644 index 000000000..110514de8 --- /dev/null +++ b/src/lib/kadm5/unit-test/lib.t @@ -0,0 +1,367 @@ +global timeout +set timeout 60 + +proc cmd {command} { + global prompt + global spawn_id + global test + + send "[string trim $command]\n" + expect { + -re "OK .*$prompt$" { return 1 } + -re "ERROR .*$prompt$" { return 0 } + "wrong # args" { error "$test: wrong number args"; return 0 } + timeout { fail "$test: timeout"; return 0 } + eof { fail "$test: eof"; api_exit; api_start; return 0 } + } +} + +proc tcl_cmd {command} { + global prompt + global spawn_id + + send "[string trim $command]\n" + expect { + -re "$prompt$" { return 1} + "wrong # args" { error "$test: wrong number args"; return 0 } + timeout { error_and_restart "timeout" } + eof { api_exit; api_start; return 0 } + } +} + +proc one_line_succeed_test {command} { + global prompt + global spawn_id + global test + + send "[string trim $command]\n" + expect { + -re "OK .*$prompt$" { pass "$test"; return 1 } + -re "ERROR .*$prompt$" { + fail "$test: $expect_out(buffer)"; return 0 + } + "wrong # args" { error "$test: wrong number args"; return 0 } + timeout { fail "$test: timeout"; return 0 } + eof { fail "$test: eof"; api_exit; api_start; return 0 } + } +} + +proc one_line_fail_test {command code} { + global prompt + global spawn_id + global test + + send "[string trim $command]\n" + expect { + -re "ERROR .*$code.*$prompt$" { pass "$test"; return 1 } + -re "ERROR .*$prompt$" { fail "$test: bad failure"; return 0 } + -re "OK .*$prompt$" { fail "$test: bad success"; return 0 } + "wrong # args" { error "$test: wrong number args"; return 0 } + timeout { fail "$test: timeout"; return 0 } + eof { fail "$test: eof"; api_exit; api_start; return 0 } + } +} + +proc one_line_fail_test_nochk {command} { + global prompt + global spawn_id + global test + + send "[string trim $command]\n" + expect { + -re "ERROR .*$prompt$" { pass "$test:"; return 1 } + -re "OK .*$prompt$" { fail "$test: bad success"; return 0 } + "wrong # args" { error "$test: wrong number args"; return 0 } + timeout { fail "$test: timeout"; return 0 } + eof { fail "$test: eof"; api_exit; api_start; return 0 } + } +} + +proc resync {} { + global prompt + global spawn_id + + expect { + -re "$prompt$" {} + "wrong # args" { error "$test: wrong number args"; return 0 } + eof { api_exit; api_start } + } +} + +proc create_principal {name} { + api_exit + api_start + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_create_principal $server_handle [simple_principal \ + "%s"] {OVSEC_KADM_PRINCIPAL} "%s" + } $name $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + + return $ret +} + +proc create_policy {name} { + api_exit + api_start + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_create_policy $server_handle [simple_policy "%s"] \ + {OVSEC_KADM_POLICY} + } $name $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + + return $ret +} + +proc create_principal_pol {name policy} { + api_exit + api_start + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_create_principal $server_handle [princ_w_pol "%s" \ + "%s"] {OVSEC_KADM_PRINCIPAL OVSEC_KADM_POLICY} "%s" + } $name $policy $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + + return $ret +} + +proc delete_principal {name} { + api_exit + api_start + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_delete_principal $server_handle "%s" + } $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + + return $ret +} + +proc delete_policy {name} { + api_exit + api_start + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format {ovsec_kadm_delete_policy $server_handle "%s"} $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + + return $ret +} + +proc principal_exists {name} { + api_exit + api_start + +# puts stdout "Starting principal_exists." + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_get_principal $server_handle "%s" principal + } $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + +# puts stdout "Finishing principal_exists." + + return $ret +} + +proc policy_exists {name} { + api_exit + api_start + +# puts stdout "Starting policy_exists." + + set ret [expr { + [cmd { + ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null \ + $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 \ + server_handle + }] && + [cmd [format { + ovsec_kadm_get_policy $server_handle "%s" policy + } $name]] + }] + + cmd {ovsec_kadm_destroy $server_handle} + + api_exit + api_start + +# puts stdout "Finishing policy_exists." + + return $ret +} + +proc error_and_restart {error} { + api_exit + api_start + error $error +} + +proc test {name} { + global test verbose + + set test $name + if {$verbose >= 1} { + puts stdout "At $test" + } +} + +proc begin_dump {} { + global TOP + global RPC + + if { ! $RPC } { +# exec $env(SIMPLE_DUMP) > /tmp/dump.before + } +} + +proc end_dump_compare {name} { + global file + global TOP + global RPC + + if { ! $RPC } { +# set file $TOP/admin/lib/unit-test/diff-files/$name +# exec $env(SIMPLE_DUMP) > /tmp/dump.after +# exec $env(COMPARE_DUMP) /tmp/dump.before /tmp/dump.after $file + } +} + +proc kinit { princ pass {opts ""} } { + global env; + global KINIT + + eval spawn $KINIT $opts $princ + expect { + -re {Password for .*: $} + {send "$pass\n"} + timeout {puts "Timeout waiting for prompt" ; close } + } + + # this necessary so close(1) in the child will not sleep waiting for + # the parent, which is us, to read pending data. + + expect { + eof {} + } + wait +} + +proc kdestroy {} { + global KDESTROY + global errorCode errorInfo + global env + + if {[info exists errorCode]} { + set saveErrorCode $errorCode + } + if {[info exists errorInfo]} { + set saveErrorInfo $errorInfo + } + catch "system $KDESTROY 2>/dev/null" + if {[info exists saveErrorCode]} { + set errorCode $saveErrorCode + } elseif {[info exists errorCode]} { + unset errorCode + } + if {[info exists saveErrorInfo]} { + set errorInfo $saveErrorInfo + } elseif {[info exists errorInfo]} { + unset errorInfo + } +} + +proc create_principal_with_keysalts {name keysalts} { + global kadmin_local + + spawn $kadmin_local -e "$keysalts" + expect { + "kadmin.local:" {} + default { error "waiting for kadmin.local prompt"; return 1} + } + send "ank -pw \"$name\" \"$name\"\n" + expect { + -re "Principal \"$name.*\" created." {} + "kadmin.local:" { + error "expecting principal created message"; + return 1 + } + default { error "waiting for principal created message"; return 1 } + } + expect { + "kadmin.local:" {} + default { error "waiting for kadmin.local prompt"; return 1 } + } + close + wait + return 0 +} + + diff --git a/src/lib/kadm5/unit-test/lock-test.c b/src/lib/kadm5/unit-test/lock-test.c new file mode 100644 index 000000000..cff342386 --- /dev/null +++ b/src/lib/kadm5/unit-test/lock-test.c @@ -0,0 +1,105 @@ +#include <stdio.h> +#include <krb5.h> +#include <kadm5/admin.h> +#include <kadm5/adb.h> + +char *whoami; + +void usage() +{ + fprintf(stderr, + "Usage: %s {shared|exclusive|permanent|release|" + "get name|wait} ...\n", whoami); + exit(1); +} + +main(int argc, char **argv) +{ + osa_adb_ret_t ret; + osa_adb_policy_t policy_db; + osa_policy_ent_t entry; + krb5_context context; + kadm5_config_params params; + + whoami = argv[0]; + + krb5_init_context(&context); + + initialize_ovk_error_table(); + initialize_adb_error_table(); + initialize_ovku_error_table(); + krb5_init_ets(context); + + params.mask = 0; + if (ret = kadm5_get_config_params(context, NULL, NULL, ¶ms, + ¶ms)) { + com_err(whoami, ret, "while retrieving configuration parameters"); + exit(1); + } + if (! (params.mask & KADM5_CONFIG_ADBNAME)) { + com_err(whoami, KADM5_BAD_SERVER_PARAMS, + "while retrieving configuration parameters"); + exit(1); + } + + ret = osa_adb_open_policy(&policy_db, ¶ms); + if (ret != OSA_ADB_OK) { + com_err(whoami, ret, "while opening database"); + exit(1); + } + + argc--; argv++; + while (argc) { + if (strcmp(*argv, "shared") == 0) { + ret = osa_adb_get_lock(policy_db, OSA_ADB_SHARED); + if (ret != OSA_ADB_OK) + com_err(whoami, ret, "while getting shared lock"); + else + printf("shared\n"); + } else if (strcmp(*argv, "exclusive") == 0) { + ret = osa_adb_get_lock(policy_db, OSA_ADB_EXCLUSIVE); + if (ret != OSA_ADB_OK) + com_err(whoami, ret, "while getting exclusive lock"); + else + printf("exclusive\n"); + } else if (strcmp(*argv, "permanent") == 0) { + ret = osa_adb_get_lock(policy_db, OSA_ADB_PERMANENT); + if (ret != OSA_ADB_OK) + com_err(whoami, ret, "while getting permanent lock"); + else + printf("permanent\n"); + } else if (strcmp(*argv, "release") == 0) { + ret = osa_adb_release_lock(policy_db); + if (ret != OSA_ADB_OK) + com_err(whoami, ret, "while releasing lock"); + else + printf("released\n"); + } else if (strcmp(*argv, "get") == 0) { + argc--; argv++; + if (!argc) usage(); + if ((ret = osa_adb_get_policy(policy_db, *argv, + &entry)) != OSA_ADB_OK) { + com_err(whoami, ret, "while getting policy"); + } else { + printf("retrieved\n"); + osa_free_policy_ent(entry); + } + } else if (strcmp(*argv, "wait") == 0) { + getchar(); + } else { + fprintf(stderr, "%s: Invalid argument \"%s\"\n", + whoami, *argv); + usage(); + } + + argc--; argv++; + } + + ret = osa_adb_close_policy(policy_db); + if (ret != OSA_ADB_OK) { + com_err(whoami, ret, "while closing database"); + exit(1); + } + + return 0; +} diff --git a/src/lib/kadm5/unit-test/randkey-test.c b/src/lib/kadm5/unit-test/randkey-test.c new file mode 100644 index 000000000..8d7e2fece --- /dev/null +++ b/src/lib/kadm5/unit-test/randkey-test.c @@ -0,0 +1,44 @@ +#include <kadm5/admin.h> +#include <com_err.h> +#include <stdio.h> +#include <krb5.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#define TEST_NUM 1000 + +main() +{ + ovsec_kadm_ret_t ret; + krb5_keyblock *keys[TEST_NUM]; + krb5_principal tprinc; + krb5_keyblock *newkey; + krb5_context context; + void *server_handle; + + int x, i; + + krb5_init_context(&context); + + krb5_parse_name(context, "testuser", &tprinc); + ret = ovsec_kadm_init("admin", "admin", "ovsec_adm/admin", 0, + OVSEC_KADM_STRUCT_VERSION, + OVSEC_KADM_API_VERSION_1, + &server_handle); + if(ret != OVSEC_KADM_OK) { + com_err("test", ret, "init"); + exit(2); + } + for(x = 0; x < TEST_NUM; x++) { + ovsec_kadm_randkey_principal(server_handle, tprinc, &newkey); + for(i = 0; i < x; i++) { + if (!memcmp(newkey->contents, keys[i]->contents, newkey->length)) + puts("match found"); + } + krb5_copy_keyblock(context, newkey, &keys[x]); + krb5_free_keyblock(context, newkey); + } + ovsec_kadm_destroy(server_handle); + exit(0); +} + diff --git a/src/lib/kadm5/unit-test/site.exp b/src/lib/kadm5/unit-test/site.exp new file mode 100644 index 000000000..18b435dd1 --- /dev/null +++ b/src/lib/kadm5/unit-test/site.exp @@ -0,0 +1,2 @@ +set tool ovsec_kadm_srv_tcl +set prompt "% " diff --git a/src/lib/kadm5/unit-test/sizes-test.c b/src/lib/kadm5/unit-test/sizes-test.c new file mode 100644 index 000000000..5bcbd6252 --- /dev/null +++ b/src/lib/kadm5/unit-test/sizes-test.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <rpc/types.h> +#include <krb5.h> + +#define stringify(a) #a + +#define test_size(a,b) if (sizeof(a) != sizeof(b)) { \ + fprintf(stderr, "sizeof(%s) != sizeof(%s)\n", stringify(a), stringify(b)); \ + exit(1); \ +} + +main() +{ + test_size(unsigned long, krb5_ui_4); + test_size(long, krb5_timestamp); + test_size(long, krb5_deltat); + test_size(long, krb5_flags); + + exit(0); +} + diff --git a/src/lib/kdb/ChangeLog b/src/lib/kdb/ChangeLog index fa274c12a..4e5440cc9 100644 --- a/src/lib/kdb/ChangeLog +++ b/src/lib/kdb/ChangeLog @@ -1,3 +1,25 @@ +Fri Jul 12 15:32:26 1996 Marc Horowitz <marc@mit.edu> + + * kdb_cpw.c (add_key_pwd): initialize retval = 0, in case the + function is called with ks_tuple_count == 0. + +Wed Jul 10 16:22:14 1996 Marc Horowitz <marc@mit.edu> + + * configure.in (USE_KDB5_LIBRARY): removed. the library does not + need itself to build, and in fact fails to do so if I try. + * Makefile.in (clean-unix): remove the shared/ subdir + +Tue Jul 9 17:55:30 1996 Marc Horowitz <marc@mit.edu> + + * configure.in, Makefile.in: added rules and macros to do shared + library creation + +Mon Jul 8 17:06:00 1996 Barry Jaspan <bjaspan@mit.edu> + + * kdb_dbm.c: Create DB_OPENCLOSE, which opens and closes the + databases for each lock. This is slower than the previous method, + but unlike the previous method it works. + Tue Jun 11 19:27:22 1996 Ezra Peisach <epeisach@kangaroo.mit.edu> * keytab.c (krb5_ktkdb_close): Free memory allocated by @@ -12,6 +34,24 @@ Sat May 18 15:07:09 1996 Ezra Peisach (epeisach@paris) * kdb_dbm.c: Do not provide prototypes for dbm_error or dbm_clearerr if they are really macros. +Sun May 12 01:03:07 1996 Marc Horowitz <marc@mit.edu> + + * kdb_xdr.c: reworked all of the krb5_dbe_* tl_data functions. + This was necessary so that the admin system could store it's own + tl_data, without needing code here. This has the side-effect of + eliminating some structures which added no value, therefore + changing about a half-dozen files elsewhere in the tree. + + * kdb_cpw.c (add_key_rnd): handle kvno incrementing in the caller, + not here. + (krb5_dbe_crk): increment the kvno here, not in add_key_rnd + (krb5_dbe_ark): increment the kvno here, not in add_key_rnd + (add_key_pwd): handle kvno incrementing in the caller, not here. + (krb5_dbe_cpw): take an arg to specify the new kvno. if it's + <= the old kvno, just increment. Otherwise, pass it to add_key_pwd. + This is why all the code in this revision was changed. + (krb5_dbe_apw): increment the kvno here, not in add_key_pwd + Tue May 7 19:48:57 1996 Ezra Peisach <epeisach@dumpster.rose.brandeis.edu> * t_kdb.c (do_testing): Compile if using BERK_DB and dbm is not diff --git a/src/lib/kdb/Makefile.in b/src/lib/kdb/Makefile.in index 7b1176d89..ba683222a 100644 --- a/src/lib/kdb/Makefile.in +++ b/src/lib/kdb/Makefile.in @@ -3,6 +3,10 @@ KRB5_RUN_ENV = @KRB5_RUN_ENV@ all:: $(OBJS) +.c.o: + $(CC) $(CFLAGS) -c $(srcdir)/$*.c +@SHARED_RULE@ + SRCS= \ $(srcdir)/keytab.c \ $(srcdir)/encrypt_key.c \ @@ -27,6 +31,21 @@ OBJS= \ setup_mkey.o \ store_mkey.o +LIB_SUBDIRS= . +LIBDONE = DONE + +all-unix:: shared +shared:: + test -d shared || mkdir shared + +clean-unix:: + $(RM) shared/* + -rmdir shared + +DONE: $(OBJS) + $(RM) DONE + echo $(OBJS) > DONE + libkdb5.a: $(OBJS) $(RM) $@ $(ARADD) $@ $(OBJS) @@ -37,7 +56,7 @@ install:: libkdb5.a $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libkdb5.a clean:: - $(RM) libkdb5.a + $(RM) libkdb5.a DONE t_kdb: t_kdb.o $(DEPLIBS) $(LD) $(LDFLAGS) $(LDARGS) -o t_kdb t_kdb.o $(LIBS) diff --git a/src/lib/kdb/configure.in b/src/lib/kdb/configure.in index ec7f93ec1..e480603e4 100644 --- a/src/lib/kdb/configure.in +++ b/src/lib/kdb/configure.in @@ -8,8 +8,9 @@ AC_HAVE_HEADERS(unistd.h) AC_CHECK_FUNCS(srand48 srand srandom umask) KRB5_RUN_FLAGS V5_USE_SHARED_LIB -USE_KDB5_LIBRARY KRB5_LIBRARIES +V5_SHARED_LIB_OBJS +V5_MAKE_SHARED_LIB(libkdb5,0.1,.., ./kdb) LinkFileDir(../libkdb5.a, libkdb5.a, ./kdb) AppendRule([all:: libkdb5.a]) AppendRule([all-unix:: ../libkdb5.a]) diff --git a/src/lib/kdb/kdb_cpw.c b/src/lib/kdb/kdb_cpw.c index 0928eba2a..54316dde0 100644 --- a/src/lib/kdb/kdb_cpw.c +++ b/src/lib/kdb/kdb_cpw.c @@ -188,7 +188,7 @@ add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno) krb5_finish_key(context, &krbtgt_eblock); if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, - key, NULL, kvno + 1, + key, NULL, kvno, &db_entry->key_data[db_entry->n_key_data-1])) { krb5_free_keyblock(context, key); goto add_key_rnd_err; @@ -233,6 +233,9 @@ krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry) db_entry->key_data = NULL; db_entry->n_key_data = 0; + /* increment the kvno */ + kvno++; + if (retval = add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); @@ -271,15 +274,18 @@ krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry) db_entry->key_data = NULL; db_entry->n_key_data = 0; + /* increment the kvno */ + kvno++; + if (retval = add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); db_entry->n_key_data = key_data_count; db_entry->key_data = key_data; } else { - /* Copy keys with key_data_kvno = kvno */ + /* Copy keys with key_data_kvno == kvno - 1 ( = old kvno ) */ for (i = 0; i < key_data_count; i++) { - if (key_data[i].key_data_kvno = kvno) { + if (key_data[i].key_data_kvno == (kvno - 1)) { if (retval = krb5_dbe_create_key_data(context, db_entry)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); @@ -318,6 +324,8 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd, krb5_boolean found; int i, j; + retval = 0; + for (i = 0; i < ks_tuple_count; i++) { krb5_enctype new_enctype, old_enctype; @@ -405,7 +413,7 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd, if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key, (const krb5_keysalt *)&key_salt, - kvno + 1, &db_entry->key_data[db_entry->n_key_data-1])) { + kvno, &db_entry->key_data[db_entry->n_key_data-1])) { krb5_xfree(key.contents); return(retval); } @@ -421,28 +429,36 @@ add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd, * As a side effect all old keys are nuked. */ krb5_error_code -krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry) +krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, + new_kvno, db_entry) krb5_context context; krb5_encrypt_block * master_eblock; krb5_key_salt_tuple * ks_tuple; int ks_tuple_count; char * passwd; + int new_kvno; krb5_db_entry * db_entry; { int key_data_count; krb5_key_data * key_data; krb5_error_code retval; - int kvno; + int old_kvno; /* First save the old keydata */ - kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + old_kvno = get_key_data_kvno(context, db_entry->n_key_data, + db_entry->key_data); key_data_count = db_entry->n_key_data; key_data = db_entry->key_data; db_entry->key_data = NULL; db_entry->n_key_data = 0; + /* increment the kvno. if the requested kvno is too small, + increment the old kvno */ + if (new_kvno < old_kvno+1) + new_kvno = old_kvno+1; + if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, - passwd, db_entry, kvno)) { + passwd, db_entry, new_kvno)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); db_entry->n_key_data = key_data_count; db_entry->key_data = key_data; @@ -470,25 +486,29 @@ krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry) int key_data_count; krb5_key_data * key_data; krb5_error_code retval; - int kvno; + int old_kvno, new_kvno; int i; /* First save the old keydata */ - kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data); + old_kvno = get_key_data_kvno(context, db_entry->n_key_data, + db_entry->key_data); key_data_count = db_entry->n_key_data; key_data = db_entry->key_data; db_entry->key_data = NULL; db_entry->n_key_data = 0; + /* increment the kvno */ + new_kvno = old_kvno+1; + if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, - passwd, db_entry, kvno)) { + passwd, db_entry, new_kvno)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); db_entry->n_key_data = key_data_count; db_entry->key_data = key_data; } else { - /* Copy keys with key_data_kvno = kvno */ + /* Copy keys with key_data_kvno == old_kvno */ for (i = 0; i < key_data_count; i++) { - if (key_data[i].key_data_kvno = kvno) { + if (key_data[i].key_data_kvno == old_kvno) { if (retval = krb5_dbe_create_key_data(context, db_entry)) { cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data); diff --git a/src/lib/kdb/kdb_dbm.c b/src/lib/kdb/kdb_dbm.c index e42e31f9d..3931389f4 100644 --- a/src/lib/kdb/kdb_dbm.c +++ b/src/lib/kdb/kdb_dbm.c @@ -22,6 +22,8 @@ * */ +#define DB_OPENCLOSE + #if HAVE_UNISTD_H #include <unistd.h> #endif @@ -341,9 +343,13 @@ krb5_dbm_db_init(context) return(retval); db_ctx = context->db_context; +#ifdef DB_OPENCLOSE + db_ctx->db_dbm_ctx = NULL; +#else if (!(db_ctx->db_dbm_ctx = (DBM *)KDBM_OPEN(db_ctx, db_ctx->db_name, O_RDWR, 0600))) return errno; +#endif if (!(filename = gen_dbsuffix (db_ctx->db_name, KDBM_LOCK_EXT(db_ctx)))) return ENOMEM; @@ -367,7 +373,9 @@ krb5_dbm_db_init(context) return 0; err_out: +#ifndef DB_OPENCLOSE KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx); +#endif db_ctx->db_dbm_ctx = (DBM *) NULL; k5dbm_clear_context(db_ctx); return (retval); @@ -387,6 +395,7 @@ krb5_dbm_db_fini(context) db_ctx = (krb5_db_context *) context->db_context; if (k5dbm_inited(context)) { +#ifndef DB_OPENCLOSE if (db_ctx->db_dbm_ctx) { /* dbm_close returns void, but it is possible for there to be an error in close(). Possible changes to this routine: check errno @@ -395,6 +404,7 @@ krb5_dbm_db_fini(context) KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx); db_ctx->db_dbm_ctx = NULL; } +#endif if (close(db_ctx->db_lf_file)) retval = errno; @@ -471,6 +481,8 @@ krb5_dbm_db_get_mkey(context, db_context, eblock) * * Passing a null pointer as "name" will set back to the default. * If the alternate database doesn't exist, nothing is changed. + * + * XXX rethink this */ krb5_error_code @@ -621,6 +633,17 @@ krb5_dbm_db_lock(context, mode) if ((retval = krb5_dbm_db_get_age(context, NULL, &mod_time))) goto lock_error; +#ifdef DB_OPENCLOSE + if ((db = KDBM_OPEN(db_ctx, db_ctx->db_name, + mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, + 0600))) { + db_ctx->db_lf_time = mod_time; + db_ctx->db_dbm_ctx = db; + } else { + retval = errno; + goto lock_error; + } +#else if (mod_time != db_ctx->db_lf_time) { KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx); if ((db = KDBM_OPEN(db_ctx, db_ctx->db_name, O_RDWR, 0600))) { @@ -631,12 +654,15 @@ krb5_dbm_db_lock(context, mode) goto lock_error; } } +#endif db_ctx->db_lock_mode = mode; db_ctx->db_locks_held++; return 0; lock_error:; + db_ctx->db_lock_mode = 0; + db_ctx->db_locks_held = 0; (void) krb5_dbm_db_unlock(context); return retval; } @@ -655,6 +681,10 @@ krb5_dbm_db_unlock(context) if (!db_ctx->db_locks_held) /* lock already unlocked */ return KRB5_KDB_NOTLOCKED; +#ifdef DB_OPENCLOSE + KDBM_CLOSE(db_ctx, db_ctx->db_dbm_ctx); +#endif + if (--(db_ctx->db_locks_held) == 0) { retval = krb5_lock_file(context, db_ctx->db_lf_file, KRB5_LOCKMODE_UNLOCK); @@ -720,9 +750,8 @@ destroy_file_suffix(dbname, suffix) if (filename == 0) return ENOMEM; if ((fd = open(filename, O_RDWR, 0)) < 0) { - int retval = errno == ENOENT ? 0 : errno; free(filename); - return retval; + return errno; } /* fstat() will probably not fail unless using a remote filesystem (which is inappropriate for the kerberos database) so this check @@ -796,26 +825,40 @@ krb5_dbm_db_destroy(context, dbname) krb5_context context; char *dbname; { - krb5_error_code retval; + krb5_error_code retval1, retval2, retval3; krb5_boolean tmpcontext; tmpcontext = 0; if (!context->db_context) { tmpcontext = 1; - if ((retval = k5dbm_init_context(context))) - return(retval); + if ((retval1 = k5dbm_init_context(context))) + return(retval1); } - if (KDBM_DATA_EXT(context->db_context) && - (retval = destroy_file_suffix(dbname, - KDBM_DATA_EXT(context->db_context)))) - return(retval); - if (KDBM_INDEX_EXT(context->db_context) && - (retval = destroy_file_suffix(dbname, - KDBM_INDEX_EXT(context->db_context)))) - return(retval); - if ((retval = destroy_file_suffix(dbname, - KDBM_LOCK_EXT(context->db_context)))) - return(retval); + retval1 = retval2 = retval3 = 0; + if (KDBM_DATA_EXT(context->db_context)) + retval1 = destroy_file_suffix(dbname, + KDBM_DATA_EXT(context->db_context)); + if (KDBM_INDEX_EXT(context->db_context)) + retval2 = destroy_file_suffix(dbname, + KDBM_INDEX_EXT(context->db_context)); + retval3 = destroy_file_suffix(dbname, + KDBM_LOCK_EXT(context->db_context)); + /* + * This kludgery is needed because it is possible to link + * against BSD DB but use the ndbm interface. The result is + * that the dispatch table thinks the file extensions are + * .dir and .pag, but the database layer uses .db. + */ + if (retval1 == ENOENT && retval2 == ENOENT && + KDBM_INDEX_EXT(context->db_context) && + strcmp(KDBM_INDEX_EXT(context->db_context), ".dir") == 0 && + KDBM_DATA_EXT(context->db_context) && + strcmp(KDBM_DATA_EXT(context->db_context), ".pag") == 0) { + retval1 = retval2 = destroy_file_suffix(dbname, ".db"); + } + if (retval1 || retval2 || retval3) + return (retval1 ? retval1 : (retval2 ? retval2 : retval3)); + if (tmpcontext) { k5dbm_clear_context((krb5_db_context *) context->db_context); free(context->db_context); @@ -841,6 +884,7 @@ krb5_dbm_db_rename(context, from, to) char *from; char *to; { + DBM *db; char *fromdir = 0; char *todir = 0; char *frompag = 0; @@ -853,19 +897,28 @@ krb5_dbm_db_rename(context, from, to) s_context = context->db_context; context->db_context = (void *) NULL; if (!(retval = k5dbm_init_context(context))) { + db_ctx = (krb5_db_context *) context->db_context; + + /* + * Create the database, failing if it already exists; the + * files must exist because krb5_dbm_db_lock, called below, + * will fail otherwise. + */ + db = KDBM_OPEN(db_ctx, to, O_RDWR|O_CREAT|O_EXCL, 0600); + if (db == NULL) { + retval = errno; + goto errout; + } + else + KDBM_CLOSE(db_ctx, db); + /* * Set the database to the target, so that other processes sharing * the target will stop their activity, and notice the new database. */ - db_ctx = (krb5_db_context *) context->db_context; - retval = krb5_dbm_db_set_name(context, to); - if (retval) { - if (retval == ENOENT) - db_ctx->db_name = strdup(to); - else + if (retval) goto errout; - } db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDBM_LOCK_EXT(db_ctx)); @@ -931,8 +984,39 @@ krb5_dbm_db_rename(context, from, to) (void) unlink(fromok); retval = krb5_dbm_db_end_update(context); } else { - (void) krb5_dbm_db_end_update(context); - retval = errno; + /* + * This kludgery is needed because it is possible to link + * against BSD DB but use the ndbm interface. The result is + * that the dispatch table thinks the file extensions are + * .dir and .pag, but the database layer uses .db. + */ + if (errno == ENOENT && + KDBM_INDEX_EXT(context->db_context) && + strcmp(KDBM_INDEX_EXT(context->db_context), ".dir") == 0 && + KDBM_DATA_EXT(context->db_context) && + strcmp(KDBM_DATA_EXT(context->db_context), ".pag") == 0) { + free(fromdir); free(todir); free(frompag); free(topag); + + fromdir = todir = NULL; + frompag = gen_dbsuffix (from, ".db"); + topag = gen_dbsuffix (to, ".db"); + if (!frompag || !topag) { + retval = ENOMEM; + goto errout; + } + if (rename(frompag, topag) == 0) { + /* We only need to unlink the source lock file */ + if (fromok) + (void) unlink(fromok); + retval = krb5_dbm_db_end_update(context); + } else { + (void) krb5_dbm_db_end_update(context); + retval = errno; + } + } else { + (void) krb5_dbm_db_end_update(context); + retval = errno; + } } @@ -1082,6 +1166,7 @@ krb5_dbm_db_put_principal(context, entries, nentries) } if (KDBM_STORE(db_ctx, db_ctx->db_dbm_ctx, key, contents, DBM_REPLACE)) retval = errno; +#ifndef DB_OPENCLOSE else { DBM *db; @@ -1093,6 +1178,7 @@ krb5_dbm_db_put_principal(context, entries, nentries) else retval = errno; } +#endif krb5_free_princ_contents(context, &contents); krb5_free_princ_dbmkey(context, &key); if (retval) @@ -1166,6 +1252,7 @@ krb5_dbm_db_delete_principal(context, searchfor, nentries) else { if (KDBM_DELETE(db_ctx, db, key)) retval = errno; +#ifndef DB_OPENCLOSE else { DBM *db; @@ -1177,6 +1264,7 @@ krb5_dbm_db_delete_principal(context, searchfor, nentries) else retval = errno; } +#endif } krb5_free_princ_contents(context, &contents2); cleancontents: diff --git a/src/lib/kdb/kdb_xdr.c b/src/lib/kdb/kdb_xdr.c index 5953d6dd2..044ce4c7f 100644 --- a/src/lib/kdb/kdb_xdr.c +++ b/src/lib/kdb/kdb_xdr.c @@ -23,200 +23,223 @@ */ #include "k5-int.h" +#include <string.h> #include <stdio.h> #include <errno.h> +#define safe_realloc(p,n) ((p)?(realloc(p,n)):(malloc(n))) + krb5_error_code krb5_dbe_create_key_data(context, entry) krb5_context context; krb5_db_entry * entry; { - if (entry->n_key_data) { - if ((entry->key_data = (krb5_key_data *)realloc(entry->key_data, - sizeof(krb5_key_data) * (entry->n_key_data + 1)))) - memset(entry->key_data + entry->n_key_data,0,sizeof(krb5_key_data)); - else - return ENOMEM; - } else { - if ((entry->key_data = (krb5_key_data *)malloc(sizeof(krb5_key_data)))) - memset(entry->key_data, 0, sizeof(krb5_key_data)); - else - return ENOMEM; - } + if ((entry->key_data = + (krb5_key_data *) safe_realloc(entry->key_data, + (sizeof(krb5_key_data)* + (entry->n_key_data + 1)))) == NULL) + return(ENOMEM); + + + memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data)); entry->n_key_data++; + return 0; } krb5_error_code -krb5_dbe_encode_last_pwd_change(context, stamp, entry) +krb5_dbe_update_tl_data(context, entry, new_tl_data) krb5_context context; - krb5_tl_last_change * stamp; krb5_db_entry * entry; + krb5_tl_data * new_tl_data; { - krb5_tl_data ** tl_data; - krb5_octet * nextloc; - - /* Find any old versions and delete them. */ - for (tl_data = &(entry->tl_data); *tl_data; - tl_data = &((*tl_data)->tl_data_next)) { - if ((*tl_data)->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) { - break; - } - } + krb5_tl_data * tl_data; + krb5_octet * tmp; + + /* copy the new data first, so we can fail cleanly if malloc() + fails */ - if ((*tl_data) || - /* Only zero data if it is freshly allocated */ - ((*tl_data) = (krb5_tl_data *)calloc(1, sizeof(krb5_tl_data)))) { - if (!(*tl_data)->tl_data_type) { - if ((nextloc = (*tl_data)->tl_data_contents = - (krb5_octet *)malloc(sizeof(krb5_timestamp))) == NULL) { - krb5_xfree(*tl_data); - (*tl_data) = NULL; - return ENOMEM; - } - (*tl_data)->tl_data_type = KRB5_TL_LAST_PWD_CHANGE; - (*tl_data)->tl_data_length = sizeof(krb5_timestamp); - entry->n_tl_data++; - } - - *nextloc++ = (krb5_octet)(stamp->last_pwd_change & 0xff); - *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 8) & 0xff); - *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 16) & 0xff); - *nextloc++ = (krb5_octet)((stamp->last_pwd_change >> 24) & 0xff); - - return 0; + if ((tmp = (krb5_octet *) malloc(new_tl_data->tl_data_length)) == NULL) + return(ENOMEM); + + /* Find an existing entry of the specified type and point at + it, or NULL if not found */ + + for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) + if (tl_data->tl_data_type == new_tl_data->tl_data_type) + break; + + /* if necessary, chain a new record in the beginning and point at it */ + + if (!tl_data) { + if ((tl_data = (krb5_tl_data *) calloc(1, sizeof(krb5_tl_data))) + == NULL) { + free(tmp); + return(ENOMEM); + } + tl_data->tl_data_next = entry->tl_data; + entry->tl_data = tl_data; + entry->n_tl_data++; } - return ENOMEM; + + /* fill in the record */ + + if (tl_data->tl_data_contents) + free(tl_data->tl_data_contents); + + tl_data->tl_data_type = new_tl_data->tl_data_type; + tl_data->tl_data_length = new_tl_data->tl_data_length; + tl_data->tl_data_contents = tmp; + memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length); + + return(0); } krb5_error_code -krb5_dbe_decode_last_pwd_change(context, entry, stamp) +krb5_dbe_lookup_tl_data(context, entry, ret_tl_data) krb5_context context; krb5_db_entry * entry; - krb5_tl_last_change * stamp; + krb5_tl_data * ret_tl_data; { - krb5_tl_data * tl_data; + krb5_tl_data *tl_data; for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { - if (tl_data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE) { - krb5_octet * nextloc = tl_data->tl_data_contents; - - stamp->last_pwd_change = *nextloc++; - stamp->last_pwd_change += (*nextloc++ << 8); - stamp->last_pwd_change += (*nextloc++ << 16); - stamp->last_pwd_change += (*nextloc++ << 24); - return 0; - } + if (tl_data->tl_data_type == ret_tl_data->tl_data_type) { + *ret_tl_data = *tl_data; + return(0); + } } - stamp->last_pwd_change = 0; - return 0; + + /* if the requested record isn't found, return zero bytes. + if it ever means something to have a zero-length tl_data, + this code and its callers will have to be changed */ + + ret_tl_data->tl_data_length = 0; + ret_tl_data->tl_data_contents = NULL; + return(0); +} + +krb5_error_code +krb5_dbe_update_last_pwd_change(context, entry, stamp) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp stamp; +{ + krb5_tl_data tl_data; + krb5_octet buf[4]; /* this is the encoded size of an int32 */ + + tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; + tl_data.tl_data_length = sizeof(buf); + krb5_kdb_encode_int32((krb5_int32) stamp, buf); + tl_data.tl_data_contents = buf; + + return(krb5_dbe_update_tl_data(context, entry, &tl_data)); } krb5_error_code -krb5_dbe_encode_mod_princ_data(context, mod_princ, entry) +krb5_dbe_lookup_last_pwd_change(context, entry, stamp) + krb5_context context; + krb5_db_entry * entry; + krb5_timestamp * stamp; +{ + krb5_tl_data tl_data; + krb5_error_code code; + krb5_int32 tmp; + + tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE; + + if (code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)) + return(code); + + if (tl_data.tl_data_length != 4) { + *stamp = 0; + return(0); + } + + krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp); + + *stamp = (krb5_timestamp) tmp; + + return(0); +} + +/* it seems odd that there's no function to remove a tl_data, but if + I need one, I'll add one */ + +krb5_error_code +krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ) krb5_context context; - krb5_tl_mod_princ * mod_princ; krb5_db_entry * entry; + krb5_timestamp mod_date; + krb5_principal mod_princ; { + krb5_tl_data tl_data; + krb5_error_code retval = 0; - krb5_tl_data ** tl_data; krb5_octet * nextloc = 0; char * unparse_mod_princ = 0; int unparse_mod_princ_size; - /* - * Allocate *tl_data if necessary otherwise reuse it - * Need 04 bytes for date - * Need XX bytes for string - */ - if ((retval = krb5_unparse_name(context, mod_princ->mod_princ, - &unparse_mod_princ))) + if ((retval = krb5_unparse_name(context, mod_princ, + &unparse_mod_princ))) return(retval); unparse_mod_princ_size = (int) strlen(unparse_mod_princ) + 1; - if ((nextloc = malloc(unparse_mod_princ_size + 4)) == NULL) { - retval = ENOMEM; - goto cleanup; - } - - /* Find any old versions and delete them. */ - for (tl_data = &(entry->tl_data); *tl_data; - tl_data = &((*tl_data)->tl_data_next)) { - if ((*tl_data)->tl_data_type == KRB5_TL_MOD_PRINC) { - free((*tl_data)->tl_data_contents); - entry->n_tl_data--; - break; - } + if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4)) + == NULL) { + free(unparse_mod_princ); + return(ENOMEM); } - /* Allocate a new TL_MOD_PRINC structure if necessary */ - if (*tl_data == 0) { - (*tl_data) = (krb5_tl_data *)calloc(1, sizeof(krb5_tl_data)); - if (*tl_data == 0) { - retval = ENOMEM; - goto cleanup; - } - } - - entry->n_tl_data++; - (*tl_data)->tl_data_type = KRB5_TL_MOD_PRINC; - (*tl_data)->tl_data_length = unparse_mod_princ_size + 4; - (*tl_data)->tl_data_contents = nextloc; + tl_data.tl_data_type = KRB5_TL_MOD_PRINC; + tl_data.tl_data_length = unparse_mod_princ_size + 4; + tl_data.tl_data_contents = nextloc; /* Mod Date */ - krb5_kdb_encode_int32(mod_princ->mod_date, nextloc); - nextloc += 4; + krb5_kdb_encode_int32(mod_date, nextloc); /* Mod Princ */ - memcpy(nextloc, unparse_mod_princ, unparse_mod_princ_size); - nextloc = 0; + memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size); -cleanup: - if (nextloc) - free(nextloc); - if (unparse_mod_princ) - free(unparse_mod_princ); - return retval; + retval = krb5_dbe_update_tl_data(context, entry, &tl_data); + + free(unparse_mod_princ); + free(nextloc); + + return(retval); } krb5_error_code -krb5_dbe_decode_mod_princ_data(context, entry, mod_princ) +krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ) krb5_context context; krb5_db_entry * entry; - krb5_tl_mod_princ ** mod_princ; + krb5_timestamp * mod_time; + krb5_principal * mod_princ; { - krb5_error_code retval; - krb5_tl_data * tl_data; - krb5_octet * nextloc; + krb5_tl_data tl_data; + krb5_error_code code; + krb5_int32 tmp; - retval = 0; - for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) { - if (tl_data->tl_data_type == KRB5_TL_MOD_PRINC) { - if ((*mod_princ = malloc(sizeof(krb5_tl_mod_princ))) == NULL) - return ENOMEM; - - nextloc = tl_data->tl_data_contents; - - /* Mod Date */ - krb5_kdb_decode_int32(nextloc, (*mod_princ)->mod_date); - nextloc += 4; - - /* Mod Princ */ - if ((retval = krb5_parse_name(context, (const char *) nextloc, - &((*mod_princ)->mod_princ)))) - break; - if ((strlen((char *) nextloc) + 1 + 4) != - (size_t) tl_data->tl_data_length) { - retval = KRB5_KDB_TRUNCATED_RECORD; - break; - } - } - } + tl_data.tl_data_type = KRB5_TL_MOD_PRINC; - if (retval && (*mod_princ)) - free(*mod_princ); - return retval; + if (code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)) + return(code); + + if ((tl_data.tl_data_length < 5) || + (tl_data.tl_data_contents[tl_data.tl_data_length-1] != '\0')) + return(KRB5_KDB_TRUNCATED_RECORD); + + /* Mod Date */ + krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time); + + /* Mod Princ */ + if ((code = krb5_parse_name(context, + (const char *) (tl_data.tl_data_contents+4), + mod_princ))) + return(code); + + return(0); } krb5_error_code diff --git a/src/lib/krb5/keytab/file/ChangeLog b/src/lib/krb5/keytab/file/ChangeLog index 58112dccc..39c397434 100644 --- a/src/lib/krb5/keytab/file/ChangeLog +++ b/src/lib/krb5/keytab/file/ChangeLog @@ -1,3 +1,8 @@ +Fri Jul 12 21:16:50 1996 Marc Horowitz <marc@mit.edu> + + * ktf_g_name.c (krb5_ktfile_get_name): include the prefix in the + returned name. + Wed Jun 12 01:09:01 1996 Theodore Ts'o <tytso@rsts-11.mit.edu> * ser_ktf.c: Add #ifdef _WIN32 in places where we had #ifdef _MSDOS diff --git a/src/lib/krb5/keytab/file/ktf_g_name.c b/src/lib/krb5/keytab/file/ktf_g_name.c index a8f27c474..dd8aadc74 100644 --- a/src/lib/krb5/keytab/file/ktf_g_name.c +++ b/src/lib/krb5/keytab/file/ktf_g_name.c @@ -36,10 +36,24 @@ krb5_ktfile_get_name(context, id, name, len) /* * This routine returns the name of the name of the file associated with * this file-based keytab. name is zeroed and the filename is truncated - * to fit in name if necessary. + * to fit in name if necessary. The name is prefixed with PREFIX:, so that + * trt will happen if the name is passed back to resolve. */ { memset(name, 0, len); - strncpy(name, KTFILENAME(id), len); + + if (len < strlen(id->ops->prefix)+2) + return(ENAMETOOLONG); + strcpy(name, id->ops->prefix); + name += strlen(id->ops->prefix); + name[0] = ':'; + name++; + len -= strlen(id->ops->prefix)+1; + + if (len < strlen(KTFILENAME(id)+1)) + return(ENAMETOOLONG); + strcpy(name, KTFILENAME(id)); + /* strcpy will NUL-terminate the destination */ + return(0); } diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index 75d2f0d3e..721ce1e5e 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,8 @@ +Fri Jul 12 21:38:15 1996 Marc Horowitz <marc@mit.edu> + + * ktdefname.c (krb5_kt_default_name): allow the default keytab name + to be specified in the config file. + Wed Jun 12 01:12:32 1996 Theodore Ts'o <tytso@rsts-11.mit.edu> * net_read.c (krb5_net_read): diff --git a/src/lib/krb5/os/ktdefname.c b/src/lib/krb5/os/ktdefname.c index 433c1c9da..29eb54fe2 100644 --- a/src/lib/krb5/os/ktdefname.c +++ b/src/lib/krb5/os/ktdefname.c @@ -37,12 +37,22 @@ krb5_kt_default_name(context, name, namesize) int namesize; { char *cp = 0; + krb5_error_code code; + char *retval; - if (context->profile_secure == FALSE) cp = getenv("KRB5_KTNAME"); - if (cp) { + if ((context->profile_secure == FALSE) && + (cp = getenv("KRB5_KTNAME"))) { strncpy(name, cp, namesize); if (strlen(cp) >= (size_t) namesize) return KRB5_CONFIG_NOTENUFSPACE; + } else if (((code = profile_get_string(context->profile, + "libdefaults", + "default_keytab_name", NULL, + NULL, &retval)) == 0) && + retval) { + strncpy(name, retval, namesize); + if ((size_t) namesize < strlen(retval)) + return KRB5_CONFIG_NOTENUFSPACE; } else { #if defined (_MSDOS) || defined(_WIN32) { diff --git a/src/lib/rpc/ChangeLog b/src/lib/rpc/ChangeLog new file mode 100644 index 000000000..a78d05c37 --- /dev/null +++ b/src/lib/rpc/ChangeLog @@ -0,0 +1,20 @@ +Fri Jul 12 15:33:50 1996 Marc Horowitz <marc@mit.edu> + + * rpc_dtablesize.c (_rpc_dtablesize): put in a few checks to make + sure that the return value is never larger than FD_SETSIZE, since + this function's purpose is to be used as the first arg to + select(). + +Tue Jul 9 17:56:54 1996 Marc Horowitz <marc@mit.edu> + + * rpc.h, netdb.h, getrpcent.c: Our build can (and will) require + that the rpc header files shipped with kerberos be used if the + library shipped with kerberos is used. Thus, some simplifying + assumptions can be made, mostly having to do with the declaration + of struct rpcent and the related functions. + * clnt_perror.c: made usage of sys_errlist conditional on + NEED_SYS_ERRLIST + * configure.in (DECLARE_SYS_ERRLIST): added + * Makefile.in (DONE): added a few rules and variable so shared + library creation would work + diff --git a/src/lib/rpc/Makefile.in b/src/lib/rpc/Makefile.in new file mode 100644 index 000000000..9426bb94c --- /dev/null +++ b/src/lib/rpc/Makefile.in @@ -0,0 +1,148 @@ +CFLAGS = $(CCOPTS) $(DEFS) -DDEBUG_GSSAPI -I$(srcdir)/.. + +##DOSBUILDTOP = ..\.. +##DOSLIBNAME=libgssrpc.lib + +.c.o: + $(CC) $(CFLAGS) -c $(srcdir)/$*.c +@SHARED_RULE@ + +SRCS = $(srcdir)/auth_none.c \ + $(srcdir)/auth_unix.c \ + $(srcdir)/auth_any.c \ + $(srcdir)/authunix_prot.c \ + $(srcdir)/auth_gssapi.c \ + $(srcdir)/auth_gssapi_misc.c \ + $(srcdir)/bindresvport.c \ + $(srcdir)/clnt_generic.c \ + $(srcdir)/clnt_perror.c \ + $(srcdir)/clnt_raw.c \ + $(srcdir)/clnt_simple.c \ + $(srcdir)/clnt_tcp.c \ + $(srcdir)/clnt_udp.c \ + $(srcdir)/rpc_dtablesize.c \ + $(srcdir)/get_myaddress.c \ + $(srcdir)/getrpcent.c \ + $(srcdir)/getrpcport.c \ + $(srcdir)/pmap_clnt.c \ + $(srcdir)/pmap_getmaps.c \ + $(srcdir)/pmap_getport.c \ + $(srcdir)/pmap_prot.c \ + $(srcdir)/pmap_prot2.c \ + $(srcdir)/pmap_rmt.c \ + $(srcdir)/rpc_prot.c \ + $(srcdir)/rpc_commondata.c \ + $(srcdir)/rpc_callmsg.c \ + $(srcdir)/svc.c \ + $(srcdir)/svc_auth.c \ + $(srcdir)/svc_auth_unix.c \ + $(srcdir)/svc_auth_any.c \ + $(srcdir)/svc_auth_gssapi.c \ + $(srcdir)/svc_raw.c \ + $(srcdir)/svc_run.c \ + $(srcdir)/svc_simple.c \ + $(srcdir)/svc_tcp.c \ + $(srcdir)/svc_udp.c \ + $(srcdir)/xdr.c \ + $(srcdir)/xdr_array.c \ + $(srcdir)/xdr_float.c \ + $(srcdir)/xdr_mem.c \ + $(srcdir)/xdr_rec.c \ + $(srcdir)/xdr_reference.c \ + $(srcdir)/xdr_stdio.c \ + $(srcdir)/xdr_alloc.c + +OBJS = auth_none.$(OBJEXT) \ + auth_unix.$(OBJEXT) \ + auth_any.$(OBJEXT) \ + authunix_prot.$(OBJEXT) \ + auth_gssapi.$(OBJEXT) \ + auth_gssapi_misc.$(OBJEXT) \ + bindresvport.$(OBJEXT) \ + clnt_generic.$(OBJEXT) \ + clnt_perror.$(OBJEXT) \ + clnt_raw.$(OBJEXT) \ + clnt_simple.$(OBJEXT) \ + clnt_tcp.$(OBJEXT) \ + clnt_udp.$(OBJEXT) \ + rpc_dtablesize.$(OBJEXT) \ + get_myaddress.$(OBJEXT) \ + getrpcent.$(OBJEXT) \ + getrpcport.$(OBJEXT) \ + pmap_clnt.$(OBJEXT) \ + pmap_getmaps.$(OBJEXT) \ + pmap_getport.$(OBJEXT) \ + pmap_prot.$(OBJEXT) \ + pmap_prot2.$(OBJEXT) \ + pmap_rmt.$(OBJEXT) \ + rpc_prot.$(OBJEXT) \ + rpc_commondata.$(OBJEXT) \ + rpc_callmsg.$(OBJEXT) \ + svc.$(OBJEXT) \ + svc_auth.$(OBJEXT) \ + svc_auth_unix.$(OBJEXT) \ + svc_auth_any.$(OBJEXT) \ + svc_auth_gssapi.$(OBJEXT) \ + svc_raw.$(OBJEXT) \ + svc_run.$(OBJEXT) \ + svc_simple.$(OBJEXT) \ + svc_tcp.$(OBJEXT) \ + svc_udp.$(OBJEXT) \ + xdr.$(OBJEXT) \ + xdr_array.$(OBJEXT) \ + xdr_float.$(OBJEXT) \ + xdr_mem.$(OBJEXT) \ + xdr_rec.$(OBJEXT) \ + xdr_reference.$(OBJEXT) \ + xdr_stdio.$(OBJEXT) \ + xdr_alloc.$(OBJEXT) + +LIB_SUBDIRS= . +LIBDONE= DONE +# +# Depends on libgssapi_krb5, libkrb5, libcrypto, libcom_err +# +GSSAPI_KRB5_VER=@GSSAPI_KRB5_SH_VERS@ +KRB5_VER=@KRB5_SH_VERS@ +CRYPTO_VER=@CRYPTO_SH_VERS@ +COMERR_VER=@COMERR_SH_VERS@ +DEPLIBS=$(TOPLIBD)/libgssapi_krb5.$(SHEXT).$(COMERR_VER) \ + $(TOPLIBD)/libkrb5.$(SHEXT).$(KRB5_VER) \ + $(TOPLIBD)/libcrypto.$(SHEXT).$(CRYPTO_VER) \ + $(TOPLIBD)/libcom_err.$(SHEXT).$(COMERR_VER) + +SHLIB_LIBS=-lkrb5 -lcrypto -lcom_err -ldyn +SHLIB_LDFLAGS= $(LDFLAGS) @SHLIB_RPATH_DIRS@ +SHLIB_LIBDIRS= @SHLIB_LIBDIRS@ + +all-unix:: shared includes $(OBJS) +all-mac:: $(OBJS) +all-windows:: $(OBJS) + +shared: + mkdir shared + +check-windows:: + +clean-unix:: + $(RM) shared/* + +clean-mac:: +clean-windows:: + +DONE: $(OBJS) + $(RM) DONE + echo $(OBJS) > DONE + +libgssrpc.$(STEXT): $(OBJS) + $(RM) $@ + $(ARADD) $@ $(OBJS) + $(RANLIB) $@ + +install:: libgssrpc.a + $(INSTALL_DATA) libgssrpc.a $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a + $(RANLIB) $(DESTDIR)$(KRB5_LIBDIR)/libgssrpc.a + +clean:: + $(RM) libgssrpc.$(LIBEXT) libgssrpc.bak DONE + diff --git a/src/lib/rpc/Makefile.ov b/src/lib/rpc/Makefile.ov new file mode 100644 index 000000000..d64c77e22 --- /dev/null +++ b/src/lib/rpc/Makefile.ov @@ -0,0 +1,52 @@ +# +# Makefile for librpclib.a. +# +# $Id$ +# $Source$ +# +TOP = .. +include $(TOP)/config.mk/template + +SUBDIRS = unit-test + +SRCS = auth_none.c auth_unix.c auth_any.c authunix_prot.c \ + auth_gssapi.c auth_gssapi_misc.c bindresvport.c \ + clnt_generic.c clnt_perror.c clnt_raw.c clnt_simple.c clnt_tcp.c \ + clnt_udp.c rpc_dtablesize.c get_myaddress.c getrpcent.c getrpcport.c \ + pmap_clnt.c pmap_getmaps.c pmap_getport.c pmap_prot.c \ + pmap_prot2.c pmap_rmt.c rpc_prot.c rpc_commondata.c rpc_callmsg.c \ + svc.c svc_auth.c svc_auth_unix.c svc_auth_any.c svc_auth_gssapi.c \ + svc_raw.c svc_run.c svc_simple.c \ + svc_tcp.c svc_udp.c xdr.c xdr_array.c xdr_float.c xdr_mem.c \ + xdr_rec.c xdr_reference.c xdr_stdio.c xdr_alloc.c + +OBJS = auth_none.o auth_unix.o auth_any.o authunix_prot.o \ + auth_gssapi.o auth_gssapi_misc.o bindresvport.o \ + clnt_generic.o clnt_perror.o clnt_raw.o clnt_simple.o clnt_tcp.o \ + clnt_udp.o rpc_dtablesize.o get_myaddress.o getrpcent.o getrpcport.o \ + pmap_clnt.o pmap_getmaps.o pmap_getport.o pmap_prot.o \ + pmap_prot2.o pmap_rmt.o rpc_prot.o rpc_commondata.o rpc_callmsg.o \ + svc.o svc_auth.o svc_auth_unix.o svc_auth_any.o svc_auth_gssapi.o \ + svc_raw.o svc_run.o svc_simple.o \ + svc_tcp.o svc_udp.o xdr.o xdr_array.o xdr_float.o xdr_mem.o \ + xdr_rec.o xdr_reference.o xdr_stdio.o xdr_alloc.o + +HDRS = auth.h auth_unix.h auth_gssapi.h clnt.h pmap_clnt.h \ + pmap_prot.h pmap_rmt.h rpc.h rpc_msg.h svc.h svc_auth.h types.h xdr.h + +HDRS_DIR = rpc + +LIB = librpclib.a + +CFLAGS := -I.. $(CFLAGS) -DDEBUG_GSSAPI=0 $(D_NEEDS_RPCENT) + +expand StageLibrary + +expand StageIncludes + +expand Depend + +expand SubdirTarget + +expand Saber + diff --git a/src/lib/rpc/auth.h b/src/lib/rpc/auth.h new file mode 100644 index 000000000..4b0a40ccc --- /dev/null +++ b/src/lib/rpc/auth.h @@ -0,0 +1,197 @@ +/* @(#)auth.h 2.3 88/08/07 4.0 RPCSRC; from 1.17 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * auth.h, Authentication interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The data structures are completely opaque to the client. The client + * is required to pass a AUTH * to routines that create rpc + * "sessions". + */ + + +#define MAX_AUTH_BYTES 400 +#define MAXNETNAMELEN 255 /* maximum length of network user's name */ + +/* + * Status returned from authentication check + */ +enum auth_stat { + AUTH_OK=0, + /* + * failed at remote end + */ + AUTH_BADCRED=1, /* bogus credentials (seal broken) */ + AUTH_REJECTEDCRED=2, /* client should begin new session */ + AUTH_BADVERF=3, /* bogus verifier (seal broken) */ + AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */ + AUTH_TOOWEAK=5, /* rejected due to security reasons */ + /* + * failed locally + */ + AUTH_INVALIDRESP=6, /* bogus response verifier */ + AUTH_FAILED=7 /* some unknown reason */ +}; + +union des_block { +#if 0 /* XXX nothing uses this, anyway */ + struct { + rpc_u_int32 high; + rpc_u_int32 low; + } key; +#endif + char c[8]; +}; +typedef union des_block des_block; +extern bool_t xdr_des_block(); + +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + unsigned int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; + + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf)(); + int (*ah_marshal)(); /* nextverf & serialize */ + int (*ah_validate)(); /* validate varifier */ + int (*ah_refresh)(); /* refresh credentials */ + void (*ah_destroy)(); /* destroy this structure */ + int (*ah_wrap)(); /* encode data for wire */ + int (*ah_unwrap)(); /* decode data from wire */ + } *ah_ops; + caddr_t ah_private; +} AUTH; + + +/* + * Authentication ops. + * The ops and the auth handle provide the interface to the authenticators. + * + * AUTH *auth; + * XDR *xdrs; + * struct opaque_auth verf; + */ +#define AUTH_NEXTVERF(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) +#define auth_nextverf(auth) \ + ((*((auth)->ah_ops->ah_nextverf))(auth)) + +#define AUTH_MARSHALL(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) +#define auth_marshall(auth, xdrs) \ + ((*((auth)->ah_ops->ah_marshal))(auth, xdrs)) + +#define AUTH_VALIDATE(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) +#define auth_validate(auth, verfp) \ + ((*((auth)->ah_ops->ah_validate))((auth), verfp)) + +#define AUTH_REFRESH(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) +#define auth_refresh(auth, msg) \ + ((*((auth)->ah_ops->ah_refresh))(auth, msg)) + +#define AUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) +#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \ + xfunc, xwhere)) + +#define AUTH_DESTROY(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) + + +extern struct opaque_auth _null_auth; + + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * Any style authentication. These routines can be used by any + * authentication style that does not use the wrap/unwrap functions. + */ +int authany_wrap(), authany_unwrap(); + +/* + * Unix style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + * char *machname; + * int uid; + * int gid; + * int len; + * int *aup_gids; + */ +extern AUTH *authunix_create(); +extern AUTH *authunix_create_default(); /* takes no parameters */ +extern AUTH *authnone_create(); /* takes no parameters */ +extern AUTH *authdes_create(); + +/* + * GSS-API style authentication: + * see <rpc/auth_gssapi.h> + */ + +#define AUTH_NONE 0 /* no authentication */ +#define AUTH_NULL 0 /* backward compatibility */ +#define AUTH_UNIX 1 /* unix style (uid, gids) */ +#define AUTH_SHORT 2 /* short hand unix style */ +#define AUTH_DES 3 /* des style (encrypted timestamps) */ +#define AUTH_GSSAPI 300001 /* GSS-API style */ + +/* + * BACKWARDS COMPATIBILIY! OpenV*Secure 1.0 had AUTH_GSSAPI == 4. We + * need to accept this value until 1.0 is dead. + */ +#define AUTH_GSSAPI_COMPAT 4 diff --git a/src/lib/rpc/auth_any.c b/src/lib/rpc/auth_any.c new file mode 100644 index 000000000..5e2a8633a --- /dev/null +++ b/src/lib/rpc/auth_any.c @@ -0,0 +1,19 @@ +/* + * auth_any.c + * Provides default functions for authentication flavors that do not + * use all the fields in structauth_ops. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> + +int authany_wrap(auth, xdrs, xfunc, xwhere) + AUTH *auth; + XDR *xdrs; + xdrproc_t xfunc; + caddr_t xwhere; +{ + return (*xfunc)(xdrs, xwhere); +} diff --git a/src/lib/rpc/auth_gssapi.c b/src/lib/rpc/auth_gssapi.c new file mode 100644 index 000000000..0ffe96d18 --- /dev/null +++ b/src/lib/rpc/auth_gssapi.c @@ -0,0 +1,901 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.23 1996/07/22 20:39:39 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.22.4.1 1996/07/18 04:18:29 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.22.2.1 1996/06/20 23:35:31 marc + * File added to the repository on a branch + * + * Revision 1.22 1996/06/05 20:56:16 bjaspan + * memset bindings to zero before use + * + * Revision 1.21 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.20 1995/12/13 14:02:45 grier + * Longs to ints for Alpha + * + * Revision 1.19 1995/10/31 16:36:00 bjaspan + * GS reported this bug. When talking to a 1.1 server, the server will + * not fail indicating the version is wrong because it never checks the + * version; it just responds with call_res.version 1. So we have to + * deal. Oops. + * + * It's amazing what can fall through the cracks when most of the + * development team is fired.. + * + * Revision 1.18 1995/10/31 16:07:06 bjaspan + * fix from grier + * + * Revision 1.17 1995/08/24 21:06:26 bjaspan + * set acceptor channel bindings + * + * Revision 1.16 1995/08/23 20:27:37 bjaspan + * [secure-rpc/3392] add channel bindinds to the rpc + * + * Revision 1.15 1995/05/08 22:32:01 marc + * change call_arg.version from 1 to 2 to indicate the new client is in use. + * + * Revision 1.14 1995/03/22 22:05:20 jik + * Reorder the auth_ops structure, to agree with the order of the version of + * this library in the GK source tree. I chose to reorder this one rather + * than reorder the GK tree because Barry says that the order in the GK tree + * makes more sense. + * + * Revision 1.13 1994/10/27 12:39:02 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * change to use GSS_ERROR &c macros; I don't think this is correct + * ============================================================================= + * + * Revision 1.14 1994/10/26 20:03:46 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.13 1994/04/07 16:12:06 jik + * The second argument to xdr_opaque_auth is struct auth *, not struct + * auth. + * + * Revision 1.12 1993/12/08 21:42:43 bjaspan + * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent + * + * Revision 1.11 1993/12/06 21:21:03 bjaspan + * debugging levels + * + * Revision 1.10 1993/11/18 23:13:07 bjaspan + * add some function comments + * + * Revision 1.9 1993/11/15 19:50:03 bjaspan + * redefine AUTH_REFRESH to take the error message as an argument, and + * change auth_gssapi_refresh to increment the seq_num on REJECTEDVERF + * + * Revision 1.8 1993/11/12 02:31:59 bjaspan + * set rpc_createerr as appropriate + * + * Revision 1.7 1993/11/03 21:21:02 bjaspan + * fix seq_num handling in cases of errors and retransmission + * + * Revision 1.6 1993/11/01 19:55:20 bjaspan + * display gss_major and gss_minor, and unstatic auth_gssapi_debug + * + * Revision 1.5 1993/10/28 22:07:33 bjaspan + * create_default takes char *, use seq_num in args/results + * + * Revision 1.4 1993/10/26 21:11:53 bjaspan + * working + * + * Revision 1.3 1993/10/21 19:01:09 bjaspan + * added auth_gssapi_destroy, cleaned up a few things + * + * Revision 1.2 1993/10/19 03:10:58 bjaspan + * snapshot: GSS-API working in hacked up state, not seal/unseal + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <string.h> +#include <sys/errno.h> + +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_generic.h> + +#include <rpc/rpc.h> +#include <rpc/auth_gssapi.h> + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int auth_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (auth_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +static void auth_gssapi_nextverf(); +static bool_t auth_gssapi_marshall(); +static bool_t auth_gssapi_validate(); +static bool_t auth_gssapi_refresh(); +static bool_t auth_gssapi_wrap(); +static bool_t auth_gssapi_unwrap(); +static void auth_gssapi_destroy(); + +static bool_t marshall_new_creds(); + +static struct auth_ops auth_gssapi_ops = { + auth_gssapi_nextverf, + auth_gssapi_marshall, + auth_gssapi_validate, + auth_gssapi_refresh, + auth_gssapi_destroy, + auth_gssapi_wrap, + auth_gssapi_unwrap, +}; + +/* + * the ah_private data structure for an auth_handle + */ +struct auth_gssapi_data { + bool_t established; + CLIENT *clnt; + gss_ctx_id_t context; + gss_buffer_desc client_handle; + rpc_u_int32 seq_num; + int def_cred; + + /* pre-serialized ah_cred */ + unsigned char cred_buf[MAX_AUTH_BYTES]; + rpc_u_int32 cred_len; +}; +#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private) + +extern struct rpc_createerr rpc_createerr; + +/* + * Function: auth_gssapi_create_default + * + * Purpose: Create a GSS-API style authenticator, with default + * options, and return the handle. + * + * Effects: See design document, section XXX. + */ +AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name) +{ + AUTH *auth; + OM_uint32 gssstat, minor_stat; + gss_buffer_desc input_name; + gss_name_t target_name; + + input_name.value = service_name; + input_name.length = strlen(service_name) + 1; + + gssstat = gss_import_name(&minor_stat, &input_name, + gss_nt_service_name, &target_name); + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat, + minor_stat)); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return NULL; + } + + auth = auth_gssapi_create(clnt, + &gssstat, + &minor_stat, + GSS_C_NO_CREDENTIAL, + target_name, + GSS_C_NULL_OID, + GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, + 0, + NULL, + NULL, + NULL); + + gss_release_name(&minor_stat, &target_name); + return auth; +} + +/* + * Function: auth_gssapi_create + * + * Purpose: Create a GSS-API style authenticator, with all the + * options, and return the handle. + * + * Effects: See design document, section XXX. + */ +AUTH *auth_gssapi_create(CLIENT *clnt, + OM_uint32 *gssstat, + OM_uint32 *minor_stat, + gss_cred_id_t claimant_cred_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + OM_uint32 time_req, + gss_OID *actual_mech_type, + int *ret_flags, + OM_uint32 *time_rec) +{ + AUTH *auth, *save_auth; + struct auth_gssapi_data *pdata; + struct gss_channel_bindings_struct bindings, *bindp; + struct sockaddr_in laddr, raddr; + enum clnt_stat callstat; + struct timeval timeout; + int init_func; + + auth_gssapi_init_arg call_arg; + auth_gssapi_init_res call_res; + gss_buffer_desc *input_token, isn_buf; + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + /* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */ + /* has not already been called.. therefore, we can just pick */ + /* something reasonable-sounding.. */ + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + auth = NULL; + pdata = NULL; + + auth = (AUTH *) malloc(sizeof(*auth)); + pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata)); + if (auth == NULL || pdata == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + goto cleanup; + } + memset((char *) auth, 0, sizeof(*auth)); + memset((char *) pdata, 0, sizeof(*pdata)); + + auth->ah_ops = &auth_gssapi_ops; + auth->ah_private = (caddr_t) pdata; + + /* initial creds are auth_msg TRUE and no handle */ + marshall_new_creds(auth, TRUE, NULL); + + /* initial verifier is empty */ + auth->ah_verf.oa_flavor = AUTH_GSSAPI; + auth->ah_verf.oa_base = NULL; + auth->ah_verf.oa_length = 0; + + AUTH_PRIVATE(auth)->established = FALSE; + AUTH_PRIVATE(auth)->clnt = clnt; + AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle == + GSS_C_NO_CREDENTIAL); + + /* don't assume the caller will want to change clnt->cl_auth */ + save_auth = clnt->cl_auth; + clnt->cl_auth = auth; + + /* start by trying latest version */ + call_arg.version = 3; + +try_new_version: + /* set state for initial call to init_sec_context */ + input_token = GSS_C_NO_BUFFER; + AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT; + init_func = AUTH_GSSAPI_INIT; + + if (call_arg.version == 3) { + if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) { + PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed")); + goto cleanup; + } + if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) { + PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed")); + goto cleanup; + } + + memset(&bindings, 0, sizeof(bindings)); + bindings.application_data.length = 0; + bindings.initiator_addrtype = GSS_C_AF_INET; + bindings.initiator_address.length = 4; + bindings.initiator_address.value = &laddr.sin_addr.s_addr; + + bindings.acceptor_addrtype = GSS_C_AF_INET; + bindings.acceptor_address.length = 4; + bindings.acceptor_address.value = &raddr.sin_addr.s_addr; + bindp = &bindings; + } else { + bindp = NULL; + } + + memset((char *) &call_res, 0, sizeof(call_res)); + +next_token: + *gssstat = gss_init_sec_context(minor_stat, + claimant_cred_handle, + &AUTH_PRIVATE(auth)->context, + target_name, + mech_type, + req_flags, + time_req, + bindp, + input_token, + actual_mech_type, + &call_arg.token, + ret_flags, + time_rec); + + if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) { + AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat, + *minor_stat)); + goto cleanup; + } + + /* if we got a token, pass it on */ + if (call_arg.token.length != 0) { + + /* + * sanity check: if we received a signed isn in the last + * response then there *cannot* be another token to send + */ + if (call_res.signed_isn.length != 0) { + PRINTF(("gssapi_create: unexpected token from init_sec\n")); + goto cleanup; + } + + PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func)); + + memset((char *) &call_res, 0, sizeof(call_res)); + callstat = clnt_call(clnt, init_func, + xdr_authgssapi_init_arg, &call_arg, + xdr_authgssapi_init_res, &call_res, + timeout); + gss_release_buffer(minor_stat, &call_arg.token); + + if (callstat != RPC_SUCCESS) { + struct rpc_err err; + + clnt_geterr(clnt, &err); + if (callstat == RPC_AUTHERROR && + (err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED) + && call_arg.version >= 1) { + L_PRINTF(1, ("call_arg protocol " + "version %d rejected, trying %d.\n", + call_arg.version, call_arg.version-1)); + call_arg.version--; + goto try_new_version; + } else { + PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n", + init_func, callstat)); + } + + goto cleanup; + } else if (call_res.version != call_arg.version && + !(call_arg.version == 2 && call_res.version == 1)) { + /* + * The Secure 1.1 servers always respond with version + * 1. Thus, if we just tried a version >=3, fall all + * the way back to version 1 since that is all they + * understand + */ + if (call_arg.version > 2 && call_res.version == 1) { + L_PRINTF(1, ("Talking to Secure 1.1 server, " + "using version 1.\n")); + call_arg.version = 1; + goto try_new_version; + } + + PRINTF(("gssapi_create: invalid call_res vers %d\n", + call_res.version)); + goto cleanup; + } else if (call_res.gss_major != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("in response from server", + call_res.gss_major, + call_res.gss_minor)); + goto cleanup; + } + + PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func)); + init_func = AUTH_GSSAPI_CONTINUE_INIT; + + /* check for client_handle */ + if (AUTH_PRIVATE(auth)->client_handle.length == 0) { + if (call_res.client_handle.length == 0) { + PRINTF(("gssapi_create: expected client_handle\n")); + goto cleanup; + } else { + PRINTF(("gssapi_create: got client_handle %d\n", + *((rpc_u_int32 *)call_res.client_handle.value))); + + GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle, + call_res.client_handle); + + /* auth_msg is TRUE; there may be more tokens */ + marshall_new_creds(auth, TRUE, + &AUTH_PRIVATE(auth)->client_handle); + } + } else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle, + call_res.client_handle)) { + PRINTF(("gssapi_create: got different client_handle\n")); + goto cleanup; + } + + /* check for token */ + if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) { + PRINTF(("gssapi_create: expected token\n")); + goto cleanup; + } else if (call_res.token.length != 0) { + if (*gssstat == GSS_S_COMPLETE) { + PRINTF(("gssapi_create: got unexpected token\n")); + goto cleanup; + } else { + /* assumes call_res is safe until init_sec_context */ + input_token = &call_res.token; + PRINTF(("gssapi_create: got new token\n")); + } + } + } + + /* check for isn */ + if (*gssstat == GSS_S_COMPLETE) { + if (call_res.signed_isn.length == 0) { + PRINTF(("gssapi_created: expected signed isn\n")); + goto cleanup; + } else { + PRINTF(("gssapi_create: processing signed isn\n")); + + /* don't check conf (integ only) or qop (accpet default) */ + *gssstat = gss_unseal(minor_stat, + AUTH_PRIVATE(auth)->context, + &call_res.signed_isn, + &isn_buf, NULL, NULL); + + if (*gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn", + *gssstat, *minor_stat)); + goto cleanup; + } else if (isn_buf.length != sizeof(rpc_u_int32)) { + PRINTF(("gssapi_create: gss_unseal gave %d bytes\n", + isn_buf.length)); + goto cleanup; + } + + AUTH_PRIVATE(auth)->seq_num = (rpc_u_int32) + ntohl(*((rpc_u_int32*)isn_buf.value)); + *gssstat = gss_release_buffer(minor_stat, &isn_buf); + if (*gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn", + *gssstat, *minor_stat)); + goto cleanup; + } + + PRINTF(("gssapi_create: isn is %d\n", + AUTH_PRIVATE(auth)->seq_num)); + + /* we no longer need these results.. */ + xdr_free(xdr_authgssapi_init_res, &call_res); + } + } else if (call_res.signed_isn.length != 0) { + PRINTF(("gssapi_create: got signed isn, can't check yet\n")); + } + + /* results were okay.. continue if necessary */ + if (*gssstat == GSS_S_CONTINUE_NEEDED) { + PRINTF(("gssapi_create: not done, continuing\n")); + goto next_token; + } + + /* + * Done! Context is established, we have client_handle and isn. + */ + AUTH_PRIVATE(auth)->established = TRUE; + + marshall_new_creds(auth, FALSE, + &AUTH_PRIVATE(auth)->client_handle); + + PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n", + *((rpc_u_int32 *)AUTH_PRIVATE(auth)->client_handle.value), + AUTH_PRIVATE(auth)->seq_num)); + + /* don't assume the caller will want to change clnt->cl_auth */ + clnt->cl_auth = save_auth; + + return auth; + + /******************************************************************/ + +cleanup: + PRINTF(("gssapi_create: bailing\n\n")); + + if (AUTH_PRIVATE(auth)) + auth_gssapi_destroy(auth); + else if (auth) + free(auth); + auth = NULL; + + /* don't assume the caller will want to change clnt->cl_auth */ + clnt->cl_auth = save_auth; + + if (rpc_createerr.cf_stat == 0) + rpc_createerr.cf_stat = RPC_AUTHERROR; + + return auth; +} + +/* + * Function: marshall_new_creds + * + * Purpose: (pre-)serialize auth_msg and client_handle fields of + * auth_gssapi_creds into auth->cred_buf + * + * Arguments: + * + * auth (r/w) the AUTH structure to modify + * auth_msg (r) the auth_msg field to serialize + * client_handle (r) the client_handle field to serialize, or + * NULL + * + * Returns: TRUE if successful, FALSE if not + * + * Requires: auth must point to a valid GSS-API auth structure, auth_msg + * must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid + * value and length field or NULL. + * + * Effects: auth->ah_cred is set to the serialized auth_gssapi_creds + * version 2 structure (stored in the cred_buf field of private data) + * containing version, auth_msg and client_handle. + * auth->ah_cred.oa_flavor is set to AUTH_GSSAPI. If cliend_handle is + * NULL, it is treated as if it had a length of 0 and a value of NULL. + * + * Modifies: auth + */ +static bool_t marshall_new_creds(auth, auth_msg, client_handle) + AUTH *auth; + bool_t auth_msg; + gss_buffer_t client_handle; +{ + auth_gssapi_creds creds; + XDR xdrs; + + PRINTF(("marshall_new_creds: starting\n")); + + creds.version = 2; + + creds.auth_msg = auth_msg; + if (client_handle) + GSS_COPY_BUFFER(creds.client_handle, *client_handle) + else { + creds.client_handle.length = 0; + creds.client_handle.value = NULL; + } + + xdrmem_create(&xdrs, AUTH_PRIVATE(auth)->cred_buf, + MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authgssapi_creds(&xdrs, &creds)) { + PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n")); + XDR_DESTROY(&xdrs); + return FALSE; + } + AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs); + XDR_DESTROY(&xdrs); + + PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n", + AUTH_PRIVATE(auth)->cred_len)); + + auth->ah_cred.oa_flavor = AUTH_GSSAPI; + auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf; + auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len; + + PRINTF(("marshall_new_creds: succeeding\n")); + + return TRUE; +} + + +/* + * Function: auth_gssapi_nextverf + * + * Purpose: None. + * + * Effects: None. Never called. + */ +static void auth_gssapi_nextverf(/*auth*/) + /*AUTH *auth;*/ +{ +} + +/* + * Function: auth_gssapi_marhsall + * + * Purpose: Marshall RPC credentials and verifier onto xdr stream. + * + * Arguments: + * + * auth (r/w) AUTH structure for client + * xdrs (r/w) XDR stream to marshall to + * + * Returns: boolean indicating success/failure + * + * Effects: + * + * The pre-serialized credentials in cred_buf are serialized. If the + * context is established, the sealed sequence number is serialized as + * the verifier. If the context is not established, an empty verifier + * is serialized. The sequence number is *not* incremented, because + * this function is called multiple times if retransmission is required. + * + * If this took all the header fields as arguments, it could sign + * them. + */ +static bool_t auth_gssapi_marshall(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + OM_uint32 minor_stat; + gss_buffer_desc out_buf; + rpc_u_int32 seq_num; + + if (AUTH_PRIVATE(auth)->established == TRUE) { + PRINTF(("gssapi_marshall: starting\n")); + + seq_num = AUTH_PRIVATE(auth)->seq_num + 1; + + PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num)); + + if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num, + &out_buf) == FALSE) { + PRINTF(("gssapi_marhshall: seal failed\n")); + } + + auth->ah_verf.oa_base = out_buf.value; + auth->ah_verf.oa_length = out_buf.length; + + if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || + ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { + (void) gss_release_buffer(&minor_stat, &out_buf); + return FALSE; + } + (void) gss_release_buffer(&minor_stat, &out_buf); + } else { + PRINTF(("gssapi_marshall: not established, sending null verf\n")); + + auth->ah_verf.oa_base = NULL; + auth->ah_verf.oa_length = 0; + + if (! xdr_opaque_auth(xdrs, &auth->ah_cred) || + ! xdr_opaque_auth(xdrs, &auth->ah_verf)) { + return FALSE; + } + } + + return TRUE; +} + +/* + * Function: auth_gssapi_validate + * + * Purpose: Validate RPC response verifier from server. + * + * Effects: See design document, section XXX. + */ +static bool_t auth_gssapi_validate(auth, verf) + AUTH *auth; + struct opaque_auth *verf; +{ + gss_buffer_desc in_buf; + rpc_u_int32 seq_num; + + if (AUTH_PRIVATE(auth)->established == FALSE) { + PRINTF(("gssapi_validate: not established, noop\n")); + return TRUE; + } + + PRINTF(("gssapi_validate: starting\n")); + + in_buf.length = verf->oa_length; + in_buf.value = verf->oa_base; + if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf, + &seq_num) == FALSE) { + PRINTF(("gssapi_validate: failed unsealing verifier\n")); + return FALSE; + } + + /* we sent seq_num+1, so we should get back seq_num+2 */ + if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) { + PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n", + AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num)); + return FALSE; + } + PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num)); + + /* +1 for successful transmission, +1 for successful validation */ + AUTH_PRIVATE(auth)->seq_num += 2; + + PRINTF(("gssapi_validate: succeeding\n")); + + return TRUE; +} + +/* + * Function: auth_gssapi_refresh + * + * Purpose: Attempts to resyncrhonize the sequence number. + * + * Effects: + * + * When the server receives a properly authenticated RPC call, it + * increments the sequence number it is expecting from the client. + * But if the server's response is lost for any reason, the client + * can't know whether the server ever received it, assumes it didn't, + * and does *not* increment its sequence number. Thus, the client's + * next call will fail with AUTH_REJECTEDCRED because the server will + * think it is a replay attack. + * + * When an AUTH_REJECTEDCRED error arrives, this function attempts to + * resyncrhonize by incrementing the client's sequence number and + * returning TRUE. If any other error arrives, it returns FALSE. + */ +static bool_t auth_gssapi_refresh(auth, msg) + AUTH *auth; + struct rpc_msg *msg; +{ + if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR && + msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) { + PRINTF(("gssapi_refresh: rejected verifier, incrementing\n")); + AUTH_PRIVATE(auth)->seq_num++; + return TRUE; + } else { + PRINTF(("gssapi_refresh: failing\n")); + return FALSE; + } +} + +/* + * Function: auth_gssapi_destroy + * + * Purpose: Destroy a GSS-API authentication structure. + * + * Effects: This function destroys the GSS-API authentication + * context, and sends a message to the server instructing it to + * invokte gss_process_token() and thereby destroy its corresponding + * context. Since the client doesn't really care whether the server + * gets this message, no failures are reported. + */ +static void auth_gssapi_destroy(auth) + AUTH *auth; +{ + struct timeval timeout; + OM_uint32 gssstat, minor_stat; + gss_cred_id_t cred; + int callstat; + + if (AUTH_PRIVATE(auth)->client_handle.length == 0) { + PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n")); + goto skip_call; + } + + PRINTF(("gssapi_destroy: marshalling new creds\n")); + if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) { + PRINTF(("gssapi_destroy: marshall_new_creds failed\n")); + goto skip_call; + } + + PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n")); + timeout.tv_sec = 1; + timeout.tv_usec = 0; + callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY, + xdr_void, NULL, xdr_void, NULL, timeout); + if (callstat != RPC_SUCCESS) + clnt_sperror(AUTH_PRIVATE(auth)->clnt, + "gssapi_destroy: GSSAPI_DESTROY failed"); + +skip_call: + PRINTF(("gssapi_destroy: deleting context\n")); + gssstat = gss_delete_sec_context(&minor_stat, + &AUTH_PRIVATE(auth)->context, + NULL); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat, + minor_stat)); + if (AUTH_PRIVATE(auth)->def_cred) { + cred = GSS_C_NO_CREDENTIAL; + gssstat = gss_release_cred(&minor_stat, &cred); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential", + gssstat, minor_stat)); + } + + if (AUTH_PRIVATE(auth)->client_handle.length != 0) + gss_release_buffer(&minor_stat, + &AUTH_PRIVATE(auth)->client_handle); + +#if 0 + PRINTF(("gssapi_destroy: calling GSSAPI_EXIT\n")); + AUTH_PRIVATE(auth)->established = FALSE; + callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_EXIT, + xdr_void, NULL, xdr_void, NULL, timeout); +#endif + + free(auth->ah_private); + free(auth); + PRINTF(("gssapi_destroy: done\n")); +} + +/* + * Function: auth_gssapi_wrap + * + * Purpose: encrypt the serialized arguments from xdr_func applied to + * xdr_ptr and write the result to xdrs. + * + * Effects: See design doc, section XXX. + */ +static bool_t auth_gssapi_wrap(auth, out_xdrs, xdr_func, xdr_ptr) + AUTH *auth; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! AUTH_PRIVATE(auth)->established) { + PRINTF(("gssapi_wrap: context not established, noop\n")); + return (*xdr_func)(out_xdrs, xdr_ptr); + } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat, + AUTH_PRIVATE(auth)->context, + AUTH_PRIVATE(auth)->seq_num+1, + out_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} + +/* + * Function: auth_gssapi_unwrap + * + * Purpose: read encrypted arguments from xdrs, decrypt, and + * deserialize with xdr_func into xdr_ptr. + * + * Effects: See design doc, section XXX. + */ +static bool_t auth_gssapi_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) + AUTH *auth; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! AUTH_PRIVATE(auth)->established) { + PRINTF(("gssapi_unwrap: context not established, noop\n")); + return (*xdr_func)(in_xdrs, xdr_ptr); + } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat, + AUTH_PRIVATE(auth)->context, + AUTH_PRIVATE(auth)->seq_num, + in_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} diff --git a/src/lib/rpc/auth_gssapi.h b/src/lib/rpc/auth_gssapi.h new file mode 100644 index 000000000..9092149a5 --- /dev/null +++ b/src/lib/rpc/auth_gssapi.h @@ -0,0 +1,161 @@ +/* + * auth_gssapi.h, Protocol for GSS-API style authentication parameters for RPC + * + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.18 1996/07/22 20:39:41 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.17.4.1 1996/07/18 04:18:31 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.17.2.1 1996/06/20 23:35:44 marc + * File added to the repository on a branch + * + * Revision 1.17 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.16 1996/01/31 19:16:16 grier + * [secure/3570] + * Remove (void *) casts to memcpy() args + * + * Revision 1.15 1995/12/28 17:54:34 jik + * Don't define DEBUG_GSSAPI here. + * + * Revision 1.14 1995/12/13 14:03:01 grier + * Longs to ints for Alpha + * + * Revision 1.13 1995/11/07 23:15:26 grier + * memcpy() casts + * + * Revision 1.12 1995/05/25 18:35:59 bjaspan + * [secure-rpc/3103] log misc errors from RPC + * + * Revision 1.11 1994/10/27 12:39:14 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.11 1994/10/26 20:04:00 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.10 1993/11/12 02:32:50 bjaspan + * add badauth, don't use const_gss_OID + * + * Revision 1.9 1993/11/03 23:46:15 bjaspan + * new log_badverf format + * + * Revision 1.8 1993/11/03 21:21:38 bjaspan + * added log_badverf + * + * Revision 1.7 1993/11/03 01:29:56 bjaspan + * add const to gss_nt_* + * + */ + +#define AUTH_GSSAPI_EXIT 0 +#define AUTH_GSSAPI_INIT 1 +#define AUTH_GSSAPI_CONTINUE_INIT 2 +#define AUTH_GSSAPI_MSG 3 +#define AUTH_GSSAPI_DESTROY 4 + +typedef struct _auth_gssapi_name { + char *name; + gss_OID type; +} auth_gssapi_name; + +typedef struct _auth_gssapi_creds { + rpc_u_int32 version; + bool_t auth_msg; + gss_buffer_desc client_handle; +} auth_gssapi_creds; + +typedef struct _auth_gssapi_init_arg { + rpc_u_int32 version; + gss_buffer_desc token; +} auth_gssapi_init_arg; + +typedef struct _auth_gssapi_init_res { + rpc_u_int32 version; + gss_buffer_desc client_handle; + OM_uint32 gss_major, gss_minor; + gss_buffer_desc token; + gss_buffer_desc signed_isn; +} auth_gssapi_init_res; + +typedef void (*auth_gssapi_log_badauth_func)(OM_uint32 major, + OM_uint32 minor, + struct sockaddr_in *raddr, + caddr_t data); + +typedef void (*auth_gssapi_log_badverf_func)(gss_name_t client, + gss_name_t server, + struct svc_req *rqst, + struct rpc_msg *msg, + caddr_t data); + +typedef void (*auth_gssapi_log_miscerr_func)(struct svc_req *rqst, + struct rpc_msg *msg, + char *error, + caddr_t data); + +bool_t xdr_authgssapi_creds(); +bool_t xdr_authgssapi_init_arg(); +bool_t xdr_authgssapi_init_res(); + +bool_t auth_gssapi_wrap_data(OM_uint32 *major, OM_uint32 *minor, + gss_ctx_id_t context, rpc_u_int32 seq_num, XDR + *out_xdrs, bool_t (*xdr_func)(), caddr_t + xdr_ptr); +bool_t auth_gssapi_unwrap_data(OM_uint32 *major, OM_uint32 *minor, + gss_ctx_id_t context, rpc_u_int32 seq_num, XDR + *in_xdrs, bool_t (*xdr_func)(), caddr_t + xdr_ptr); + +AUTH *auth_gssapi_create(CLIENT *clnt, + OM_uint32 *major_status, + OM_uint32 *minor_status, + gss_cred_id_t claimant_cred_handle, + gss_name_t target_name, + gss_OID mech_type, + int req_flags, + OM_uint32 time_req, + gss_OID *actual_mech_type, + int *ret_flags, + OM_uint32 *time_rec); + +AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name); + +void auth_gssapi_display_status(char *msg, OM_uint32 major, + OM_uint32 minor); +bool_t _svcauth_gssapi_set_name(char *name, gss_OID name_type); + +void _svcauth_set_log_badauth_func(auth_gssapi_log_badauth_func func, + caddr_t data); +void _svcauth_set_log_badverf_func(auth_gssapi_log_badverf_func func, + caddr_t data); +void _svcauth_set_log_miscerr_func(auth_gssapi_log_miscerr_func func, + caddr_t data); + +#define GSS_COPY_BUFFER(dest, src) { \ + (dest).length = (src).length; \ + (dest).value = (src).value; } + +#define GSS_DUP_BUFFER(dest, src) { \ + (dest).length = (src).length; \ + (dest).value = (void *) malloc((dest).length); \ + memcpy((dest).value, (src).value, (dest).length); } + +#define GSS_BUFFERS_EQUAL(b1, b2) (((b1).length == (b2).length) && \ + !memcmp((b1).value,(b2).value,(b1.length))) + diff --git a/src/lib/rpc/auth_gssapi_misc.c b/src/lib/rpc/auth_gssapi_misc.c new file mode 100644 index 000000000..bd7b6e5a3 --- /dev/null +++ b/src/lib/rpc/auth_gssapi_misc.c @@ -0,0 +1,390 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.14 1996/07/22 20:39:44 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.13.4.1 1996/07/18 04:18:32 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.13.2.1 1996/06/20 23:35:49 marc + * File added to the repository on a branch + * + * Revision 1.13 1996/05/12 06:11:38 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.12 1996/02/25 15:53:57 grier + * [secure/3570] + * OSF1 long changes + * + * Revision 1.11 1995/12/13 14:03:30 grier + * Longs to ints for Alpha + * + * Revision 1.10 1994/10/27 12:39:23 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] back out the backwards compat hack (I only put it + * there in case we ever decide we want it, which we won't) and just + * handle the version field as if it were always there + * + * [secure-rpc/2808] add a backwards-compatible version field encoder + * + * change to use GSS_ERROR &c macros; I don't think this is correct + * ============================================================================= + * + * Revision 1.12 1994/10/26 19:48:45 bjaspan + * [secure-rpc/2808] back out the backwards compat hack (I only put it + * there in case we ever decide we want it, which we won't) and just + * handle the version field as if it were always there + * + * Revision 1.11 1994/10/26 19:47:42 bjaspan + * [secure-rpc/2808] add a backwards-compatible version field encoder + * + * Revision 1.10 1993/12/19 22:19:40 bjaspan + * [secure-rpc/1077] use free instead of xdr_free(xdr_bytes,...) because + * xdr_bytes takes non-standard arguments + * + * Revision 1.9 1993/12/08 21:43:37 bjaspan + * use AUTH_GSSAPI_DISPLAY_STATUS macro, reindent + * + * Revision 1.8 1993/12/06 21:21:21 bjaspan + * debugging levels + * + * Revision 1.7 1993/11/03 23:46:34 bjaspan + * add debugging printfs showing amount of data wrapped/unwrapped + * + * Revision 1.6 1993/11/03 21:21:53 bjaspan + * unstatic misc_debug_gssapi + * + * Revision 1.5 1993/11/01 19:55:54 bjaspan + * improve display_status messages, and include gss_{major,minor} + * + * Revision 1.4 1993/10/28 22:08:21 bjaspan + * wrap/unwrap_data include sequence number in arg/result block + * + * Revision 1.3 1993/10/27 18:26:16 bjaspan + * use xdr_free instead of free(in_buf.value); doesn't actually make a + * difference, though + * + * Revision 1.2 1993/10/26 21:12:38 bjaspan + * cleaning + * + * Revision 1.1 1993/10/19 03:12:28 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/rpc.h> +#include <stdio.h> + +#include <gssapi/gssapi.h> +#include <rpc/auth_gssapi.h> + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int misc_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (misc_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (misc_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +static void auth_gssapi_display_status_1(char *, OM_uint32, int, int); + +bool_t xdr_gss_buf(xdrs, buf) + XDR *xdrs; + gss_buffer_t buf; +{ + /* + * On decode, xdr_bytes will only allocate buf->value if the + * length read in is < maxsize (last arg). This is dumb, because + * the whole point of allocating memory is so that I don't *have* + * to know the maximum length. -1 effectively disables this + * braindamage. + */ + return xdr_bytes(xdrs, (char **) &buf->value, (unsigned int *) &buf->length, + (xdrs->x_op == XDR_DECODE && buf->value == NULL) + ? (unsigned int) -1 : (unsigned int) buf->length); +} + +bool_t xdr_authgssapi_creds(xdrs, creds) + XDR *xdrs; + auth_gssapi_creds *creds; +{ + if (! xdr_u_int32(xdrs, &creds->version) || + ! xdr_bool(xdrs, &creds->auth_msg) || + ! xdr_gss_buf(xdrs, &creds->client_handle)) + return FALSE; + return TRUE; +} + +bool_t xdr_authgssapi_init_arg(xdrs, init_arg) + XDR *xdrs; + auth_gssapi_init_arg *init_arg; +{ + if (! xdr_u_int32(xdrs, &init_arg->version) || + ! xdr_gss_buf(xdrs, &init_arg->token)) + return FALSE; + return TRUE; +} + +bool_t xdr_authgssapi_init_res(xdrs, init_res) + XDR *xdrs; + auth_gssapi_init_res *init_res; +{ + if (! xdr_u_int32(xdrs, &init_res->version) || + ! xdr_gss_buf(xdrs, &init_res->client_handle) || + ! xdr_u_int32(xdrs, &init_res->gss_major) || + ! xdr_u_int32(xdrs, &init_res->gss_minor) || + ! xdr_gss_buf(xdrs, &init_res->token) || + ! xdr_gss_buf(xdrs, &init_res->signed_isn)) + return FALSE; + return TRUE; +} + +bool_t auth_gssapi_seal_seq(context, seq_num, out_buf) + gss_ctx_id_t context; + rpc_u_int32 seq_num; + gss_buffer_t out_buf; +{ + gss_buffer_desc in_buf; + OM_uint32 gssstat, minor_stat; + rpc_u_int32 nl_seq_num; + + nl_seq_num = htonl(seq_num); + + in_buf.length = sizeof(rpc_u_int32); + in_buf.value = (char *) &nl_seq_num; + gssstat = gss_seal(&minor_stat, context, 0, GSS_C_QOP_DEFAULT, + &in_buf, NULL, out_buf); + if (gssstat != GSS_S_COMPLETE) { + PRINTF(("gssapi_seal_seq: failed\n")); + AUTH_GSSAPI_DISPLAY_STATUS(("sealing sequence number", + gssstat, minor_stat)); + return FALSE; + } + return TRUE; +} + +bool_t auth_gssapi_unseal_seq(context, in_buf, seq_num) + gss_ctx_id_t context; + gss_buffer_t in_buf; + rpc_u_int32 *seq_num; +{ + gss_buffer_desc out_buf; + OM_uint32 gssstat, minor_stat; + rpc_u_int32 nl_seq_num; + + gssstat = gss_unseal(&minor_stat, context, in_buf, &out_buf, + NULL, NULL); + if (gssstat != GSS_S_COMPLETE) { + PRINTF(("gssapi_unseal_seq: failed\n")); + AUTH_GSSAPI_DISPLAY_STATUS(("unsealing sequence number", + gssstat, minor_stat)); + return FALSE; + } else if (out_buf.length != sizeof(rpc_u_int32)) { + PRINTF(("gssapi_unseal_seq: unseal gave %d bytes\n", + out_buf.length)); + gss_release_buffer(&minor_stat, &out_buf); + return FALSE; + } + + nl_seq_num = *((rpc_u_int32 *) out_buf.value); + *seq_num = (rpc_u_int32) ntohl(nl_seq_num); + gss_release_buffer(&minor_stat, &out_buf); + + return TRUE; +} + +void auth_gssapi_display_status(char *msg, OM_uint32 major, OM_uint32 minor) +{ + auth_gssapi_display_status_1(msg, major, GSS_C_GSS_CODE, 0); + auth_gssapi_display_status_1(msg, minor, GSS_C_MECH_CODE, 0); +} + +static void auth_gssapi_display_status_1(char *m, OM_uint32 code, int type, + int rec) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc msg; + int msg_ctx; + + msg_ctx = 0; + while (1) { + gssstat = gss_display_status(&minor_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + if (gssstat != GSS_S_COMPLETE) { + if (!rec) { + auth_gssapi_display_status_1(m,gssstat,GSS_C_GSS_CODE,1); + auth_gssapi_display_status_1(m, minor_stat, + GSS_C_MECH_CODE, 1); + } else + fprintf(stderr,"GSS-API authentication error %s: " + "recursive failure!\n", msg); + return; + } + + fprintf(stderr, "GSS-API authentication error %s: %s\n", m, + (char *)msg.value); + (void) gss_release_buffer(&minor_stat, &msg); + + if (!msg_ctx) + break; + } +} + +bool_t auth_gssapi_wrap_data(major, minor, context, seq_num, out_xdrs, + xdr_func, xdr_ptr) + OM_uint32 *major, *minor; + gss_ctx_id_t context; + rpc_u_int32 seq_num; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + gss_buffer_desc in_buf, out_buf; + XDR temp_xdrs; + int conf_state; + + PRINTF(("gssapi_wrap_data: starting\n")); + + *major = GSS_S_COMPLETE; + *minor = 0; /* assumption */ + + xdralloc_create(&temp_xdrs, XDR_ENCODE); + + /* serialize the sequence number into local memory */ + PRINTF(("gssapi_wrap_data: encoding seq_num %d\n", seq_num)); + if (! xdr_u_int32(&temp_xdrs, &seq_num)) { + PRINTF(("gssapi_wrap_data: serializing seq_num failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + /* serialize the arguments into local memory */ + if (!(*xdr_func)(&temp_xdrs, xdr_ptr)) { + PRINTF(("gssapi_wrap_data: serializing arguments failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + in_buf.length = xdr_getpos(&temp_xdrs); + in_buf.value = xdralloc_getdata(&temp_xdrs); + + *major = gss_seal(minor, context, 1, + GSS_C_QOP_DEFAULT, &in_buf, &conf_state, + &out_buf); + if (*major != GSS_S_COMPLETE) { + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + PRINTF(("gssapi_wrap_data: %d bytes data, %d bytes sealed\n", + in_buf.length, out_buf.length)); + + /* write the token */ + if (! xdr_bytes(out_xdrs, (char **) &out_buf.value, + (unsigned int *) &out_buf.length, + out_buf.length)) { + PRINTF(("gssapi_wrap_data: serializing encrypted data failed\n")); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + *major = gss_release_buffer(minor, &out_buf); + + PRINTF(("gssapi_wrap_data: succeeding\n\n")); + XDR_DESTROY(&temp_xdrs); + return TRUE; +} + +bool_t auth_gssapi_unwrap_data(major, minor, context, seq_num, + in_xdrs, xdr_func, xdr_ptr) + OM_uint32 *major, *minor; + gss_ctx_id_t context; + rpc_u_int32 seq_num; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + gss_buffer_desc in_buf, out_buf; + XDR temp_xdrs; + rpc_u_int32 verf_seq_num; + int conf, qop; + + PRINTF(("gssapi_unwrap_data: starting\n")); + + *major = GSS_S_COMPLETE; + *minor = 0; /* assumption */ + + in_buf.value = NULL; + out_buf.value = NULL; + + if (! xdr_bytes(in_xdrs, (char **) &in_buf.value, + (unsigned int *) &in_buf.length, (unsigned int) -1)) { + PRINTF(("gssapi_unwrap_data: deserializing encrypted data failed\n")); + return FALSE; + } + + *major = gss_unseal(minor, context, &in_buf, &out_buf, &conf, + &qop); + free(in_buf.value); + if (*major != GSS_S_COMPLETE) + return FALSE; + + PRINTF(("gssapi_unwrap_data: %d bytes data, %d bytes sealed\n", + out_buf.length, in_buf.length)); + + xdrmem_create(&temp_xdrs, out_buf.value, out_buf.length, XDR_DECODE); + + /* deserialize the sequence number */ + if (! xdr_u_int32(&temp_xdrs, &verf_seq_num)) { + PRINTF(("gssapi_unwrap_data: deserializing verf_seq_num failed\n")); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + if (verf_seq_num != seq_num) { + PRINTF(("gssapi_unwrap_data: seq %d specified, read %d\n", + seq_num, verf_seq_num)); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + PRINTF(("gssapi_unwrap_data: unwrap seq_num %d okay\n", verf_seq_num)); + + /* deserialize the arguments into xdr_ptr */ + if (! (*xdr_func)(&temp_xdrs, xdr_ptr)) { + PRINTF(("gssapi_unwrap_data: deserializing arguments failed\n")); + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return FALSE; + } + + PRINTF(("gssapi_unwrap_data: succeeding\n\n")); + + gss_release_buffer(minor, &out_buf); + XDR_DESTROY(&temp_xdrs); + return TRUE; +} diff --git a/src/lib/rpc/auth_none.c b/src/lib/rpc/auth_none.c new file mode 100644 index 000000000..90f3bb8be --- /dev/null +++ b/src/lib/rpc/auth_none.c @@ -0,0 +1,136 @@ +/* @(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_none.c + * Creates a client authentication handle for passing "null" + * credentials and verifiers to remote systems. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <stdlib.h> +#define MAX_MARSHEL_SIZE 20 + +/* + * Authenticator operations routines + */ +static void authnone_verf(); +static void authnone_destroy(); +static bool_t authnone_marshal(); +static bool_t authnone_validate(); +static bool_t authnone_refresh(); + +static struct auth_ops ops = { + authnone_verf, + authnone_marshal, + authnone_validate, + authnone_refresh, + authnone_destroy, + authany_wrap, + authany_wrap, +}; + +static struct authnone_private { + AUTH no_client; + char marshalled_client[MAX_MARSHEL_SIZE]; + unsigned int mcnt; +} *authnone_private; + +AUTH * +authnone_create() +{ + register struct authnone_private *ap = authnone_private; + XDR xdr_stream; + register XDR *xdrs; + + if (ap == 0) { + ap = (struct authnone_private *)calloc(1, sizeof (*ap)); + if (ap == 0) + return (0); + authnone_private = ap; + } + if (!ap->mcnt) { + ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth; + ap->no_client.ah_ops = &ops; + xdrs = &xdr_stream; + xdrmem_create(xdrs, ap->marshalled_client, (unsigned int)MAX_MARSHEL_SIZE, + XDR_ENCODE); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred); + (void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf); + ap->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + } + return (&ap->no_client); +} + +/*ARGSUSED*/ +static bool_t +authnone_marshal(client, xdrs) + AUTH *client; + XDR *xdrs; +{ + register struct authnone_private *ap = authnone_private; + + if (ap == 0) + return (0); + return ((*xdrs->x_ops->x_putbytes)(xdrs, + ap->marshalled_client, ap->mcnt)); +} + +static void +authnone_verf() +{ +} + +static bool_t +authnone_validate() +{ + + return (TRUE); +} + +static bool_t +authnone_refresh() +{ + + return (FALSE); +} + +static void +authnone_destroy() +{ +} diff --git a/src/lib/rpc/auth_unix.c b/src/lib/rpc/auth_unix.c new file mode 100644 index 000000000..b41e442fc --- /dev/null +++ b/src/lib/rpc/auth_unix.c @@ -0,0 +1,322 @@ +/* @(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * auth_unix.c, Implements UNIX style authentication parameters. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The system is very weak. The client uses no encryption for it's + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + * + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> + + +/* + * Unix authenticator operations vector + */ +static void authunix_nextverf(); +static bool_t authunix_marshal(); +static bool_t authunix_validate(); +static bool_t authunix_refresh(); +static void authunix_destroy(); + +static struct auth_ops auth_unix_ops = { + authunix_nextverf, + authunix_marshal, + authunix_validate, + authunix_refresh, + authunix_destroy, + authany_wrap, + authany_wrap, +}; + +/* + * This struct is pointed to by the ah_private field of an auth_handle. + */ +struct audata { + struct opaque_auth au_origcred; /* original credentials */ + struct opaque_auth au_shcred; /* short hand cred */ + rpc_u_int32 au_shfaults; /* short hand cache faults */ + char au_marshed[MAX_AUTH_BYTES]; + unsigned int au_mpos; /* xdr pos at end of marshed */ +}; +#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private) + +static bool_t marshal_new_auth(); + + +/* + * Create a unix style authenticator. + * Returns an auth handle with the given stuff in it. + */ +AUTH * +authunix_create(machname, uid, gid, len, aup_gids) + char *machname; + int uid; + int gid; + register int len; + int *aup_gids; +{ + struct authunix_parms aup; + char mymem[MAX_AUTH_BYTES]; + struct timeval now; + XDR xdrs; + register AUTH *auth; + register struct audata *au; + + /* + * Allocate and set up auth handle + */ + auth = (AUTH *)mem_alloc(sizeof(*auth)); +#ifndef KERNEL + if (auth == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + au = (struct audata *)mem_alloc(sizeof(*au)); +#ifndef KERNEL + if (au == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + auth->ah_ops = &auth_unix_ops; + auth->ah_private = (caddr_t)au; + auth->ah_verf = au->au_shcred = _null_auth; + au->au_shfaults = 0; + + /* + * fill in param struct from the given params + */ + (void)gettimeofday(&now, (struct timezone *)0); + aup.aup_time = now.tv_sec; + aup.aup_machname = machname; + aup.aup_uid = uid; + aup.aup_gid = gid; + aup.aup_len = (unsigned int)len; + aup.aup_gids = aup_gids; + + /* + * Serialize the parameters into origcred + */ + xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE); + if (! xdr_authunix_parms(&xdrs, &aup)) + abort(); + au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs); + au->au_origcred.oa_flavor = AUTH_UNIX; +#ifdef KERNEL + au->au_origcred.oa_base = mem_alloc((unsigned int) len); +#else + if ((au->au_origcred.oa_base = mem_alloc((unsigned int) len)) == NULL) { + (void)fprintf(stderr, "authunix_create: out of memory\n"); + return (NULL); + } +#endif + memmove(au->au_origcred.oa_base, mymem, (unsigned int)len); + + /* + * set auth handle to reflect new cred. + */ + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); + return (auth); +} + +/* + * Returns an auth handle with parameters determined by doing lots of + * syscalls. + */ +AUTH * +authunix_create_default() +{ + register int len; + char machname[MAX_MACHINE_NAME + 1]; + register int uid; + register int gid; + int gids[NGRPS]; + + if (gethostname(machname, MAX_MACHINE_NAME) == -1) + abort(); + machname[MAX_MACHINE_NAME] = 0; + uid = geteuid(); + gid = getegid(); + if ((len = getgroups(NGRPS, gids)) < 0) + abort(); + return (authunix_create(machname, uid, gid, len, gids)); +} + +/* + * authunix operations + */ + +static void +authunix_nextverf(auth) + AUTH *auth; +{ + /* no action necessary */ +} + +static bool_t +authunix_marshal(auth, xdrs) + AUTH *auth; + XDR *xdrs; +{ + register struct audata *au = AUTH_PRIVATE(auth); + + return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos)); +} + +static bool_t +authunix_validate(auth, verf) + register AUTH *auth; + struct opaque_auth verf; +{ + register struct audata *au; + XDR xdrs; + + if (verf.oa_flavor == AUTH_SHORT) { + au = AUTH_PRIVATE(auth); + xdrmem_create(&xdrs, verf.oa_base, verf.oa_length, XDR_DECODE); + + if (au->au_shcred.oa_base != NULL) { + mem_free(au->au_shcred.oa_base, + au->au_shcred.oa_length); + au->au_shcred.oa_base = NULL; + } + if (xdr_opaque_auth(&xdrs, &au->au_shcred)) { + auth->ah_cred = au->au_shcred; + } else { + xdrs.x_op = XDR_FREE; + (void)xdr_opaque_auth(&xdrs, &au->au_shcred); + au->au_shcred.oa_base = NULL; + auth->ah_cred = au->au_origcred; + } + marshal_new_auth(auth); + } + return (TRUE); +} + +static bool_t +authunix_refresh(auth) + register AUTH *auth; +{ + register struct audata *au = AUTH_PRIVATE(auth); + struct authunix_parms aup; + struct timeval now; + XDR xdrs; + register int stat; + + if (auth->ah_cred.oa_base == au->au_origcred.oa_base) { + /* there is no hope. Punt */ + return (FALSE); + } + au->au_shfaults ++; + + /* first deserialize the creds back into a struct authunix_parms */ + aup.aup_machname = NULL; + aup.aup_gids = (int *)NULL; + xdrmem_create(&xdrs, au->au_origcred.oa_base, + au->au_origcred.oa_length, XDR_DECODE); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + + /* update the time and serialize in place */ + (void)gettimeofday(&now, (struct timezone *)0); + aup.aup_time = now.tv_sec; + xdrs.x_op = XDR_ENCODE; + XDR_SETPOS(&xdrs, 0); + stat = xdr_authunix_parms(&xdrs, &aup); + if (! stat) + goto done; + auth->ah_cred = au->au_origcred; + marshal_new_auth(auth); +done: + /* free the struct authunix_parms created by deserializing */ + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, &aup); + XDR_DESTROY(&xdrs); + return (stat); +} + +static void +authunix_destroy(auth) + register AUTH *auth; +{ + register struct audata *au = AUTH_PRIVATE(auth); + + mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length); + + if (au->au_shcred.oa_base != NULL) + mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length); + + mem_free(auth->ah_private, sizeof(struct audata)); + + if (auth->ah_verf.oa_base != NULL) + mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length); + + mem_free((caddr_t)auth, sizeof(*auth)); +} + +/* + * Marshals (pre-serializes) an auth struct. + * sets private data, au_marshed and au_mpos + */ +static bool_t +marshal_new_auth(auth) + register AUTH *auth; +{ + XDR xdr_stream; + register XDR *xdrs = &xdr_stream; + register struct audata *au = AUTH_PRIVATE(auth); + + xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE); + if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) || + (! xdr_opaque_auth(xdrs, &(auth->ah_verf)))) { + perror("auth_none.c - Fatal marshalling problem"); + } else { + au->au_mpos = XDR_GETPOS(xdrs); + } + XDR_DESTROY(xdrs); +} diff --git a/src/lib/rpc/auth_unix.h b/src/lib/rpc/auth_unix.h new file mode 100644 index 000000000..4b54f1db6 --- /dev/null +++ b/src/lib/rpc/auth_unix.h @@ -0,0 +1,72 @@ +/* @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC; from 1.8 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)auth_unix.h 1.5 86/07/16 SMI */ + +/* + * auth_unix.h, Protocol for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * The system is very weak. The client uses no encryption for it + * credentials and only sends null verifiers. The server sends backs + * null verifiers or optionally a verifier that suggests a new short hand + * for the credentials. + */ + +/* The machine name is part of a credential; it may not exceed 255 bytes */ +#define MAX_MACHINE_NAME 255 + +/* gids compose part of a credential; there may not be more than 16 of them */ +#define NGRPS 16 + +/* + * Unix style credentials. + */ +struct authunix_parms { + rpc_u_int32 aup_time; + char *aup_machname; + int aup_uid; + int aup_gid; + unsigned int aup_len; + int *aup_gids; +}; + +extern bool_t xdr_authunix_parms(); + +/* + * If a response verifier has flavor AUTH_SHORT, + * then the body of the response verifier encapsulates the following structure; + * again it is serialized in the obvious fashion. + */ +struct short_hand_verf { + struct opaque_auth new_cred; +}; diff --git a/src/lib/rpc/authunix_prot.c b/src/lib/rpc/authunix_prot.c new file mode 100644 index 000000000..36770f298 --- /dev/null +++ b/src/lib/rpc/authunix_prot.c @@ -0,0 +1,66 @@ +/* @(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * authunix_prot.c + * XDR for UNIX style authentication parameters for RPC + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/auth.h> +#include <rpc/auth_unix.h> + +/* + * XDR for unix authentication parameters. + */ +bool_t +xdr_authunix_parms(xdrs, p) + register XDR *xdrs; + register struct authunix_parms *p; +{ + + if (xdr_u_int32(xdrs, &(p->aup_time)) + && xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) + && xdr_int(xdrs, &(p->aup_uid)) + && xdr_int(xdrs, &(p->aup_gid)) + && xdr_array(xdrs, (caddr_t *)&(p->aup_gids), + &(p->aup_len), NGRPS, sizeof(int), xdr_int) ) { + return (TRUE); + } + return (FALSE); +} + diff --git a/src/lib/rpc/bindresvport.c b/src/lib/rpc/bindresvport.c new file mode 100644 index 000000000..875aeefb6 --- /dev/null +++ b/src/lib/rpc/bindresvport.c @@ -0,0 +1,79 @@ +static char sccsid[] = "@(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC 1.8 88/02/08 SMI"; +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1987 by Sun Microsystems, Inc. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* + * Bind a socket to a privileged IP port + */ +bindresvport(sd, sin) + int sd; + struct sockaddr_in *sin; +{ + int res; + static short port; + struct sockaddr_in myaddr; + extern int errno; + int i; + +#define STARTPORT 600 +#define ENDPORT (IPPORT_RESERVED - 1) +#define NPORTS (ENDPORT - STARTPORT + 1) + + if (sin == (struct sockaddr_in *)0) { + sin = &myaddr; + memset(sin, 0, sizeof (*sin)); + sin->sin_family = AF_INET; + } else if (sin->sin_family != AF_INET) { + errno = EPFNOSUPPORT; + return (-1); + } + if (port == 0) { + port = (getpid() % NPORTS) + STARTPORT; + } + res = -1; + errno = EADDRINUSE; + for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) { + sin->sin_port = htons(port++); + if (port > ENDPORT) { + port = STARTPORT; + } + res = bind(sd, (struct sockaddr *) sin, + sizeof(struct sockaddr_in)); + } + return (res); +} diff --git a/src/lib/rpc/clnt.h b/src/lib/rpc/clnt.h new file mode 100644 index 000000000..442a96d44 --- /dev/null +++ b/src/lib/rpc/clnt.h @@ -0,0 +1,335 @@ +/* @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.31 88/02/08 SMI*/ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _CLNT_ +#define _CLNT_ + +/* + * Rpc calls return an enum clnt_stat. This should be looked at more, + * since each implementation is required to live with this (implementation + * independent) list of errors. + */ +enum clnt_stat { + RPC_SUCCESS=0, /* call succeeded */ + /* + * local errors + */ + RPC_CANTENCODEARGS=1, /* can't encode arguments */ + RPC_CANTDECODERES=2, /* can't decode results */ + RPC_CANTSEND=3, /* failure in sending call */ + RPC_CANTRECV=4, /* failure in receiving result */ + RPC_TIMEDOUT=5, /* call timed out */ + /* + * remote errors + */ + RPC_VERSMISMATCH=6, /* rpc versions not compatible */ + RPC_AUTHERROR=7, /* authentication error */ + RPC_PROGUNAVAIL=8, /* program not available */ + RPC_PROGVERSMISMATCH=9, /* program version mismatched */ + RPC_PROCUNAVAIL=10, /* procedure unavailable */ + RPC_CANTDECODEARGS=11, /* decode arguments error */ + RPC_SYSTEMERROR=12, /* generic "other problem" */ + + /* + * callrpc & clnt_create errors + */ + RPC_UNKNOWNHOST=13, /* unknown host name */ + RPC_UNKNOWNPROTO=17, /* unkown protocol */ + + /* + * _ create errors + */ + RPC_PMAPFAILURE=14, /* the pmapper failed in its call */ + RPC_PROGNOTREGISTERED=15, /* remote program is not registered */ + /* + * unspecified error + */ + RPC_FAILED=16 +}; + + +/* + * Error info. + */ +struct rpc_err { + enum clnt_stat re_status; + union { + int RE_errno; /* realated system error */ + enum auth_stat RE_why; /* why the auth error occurred */ + struct { + rpc_u_int32 low; /* lowest verion supported */ + rpc_u_int32 high; /* highest verion supported */ + } RE_vers; + struct { /* maybe meaningful if RPC_FAILED */ + rpc_int32 s1; + rpc_int32 s2; + } RE_lb; /* life boot & debugging only */ + } ru; +#define re_errno ru.RE_errno +#define re_why ru.RE_why +#define re_vers ru.RE_vers +#define re_lb ru.RE_lb +}; + + +/* + * Client rpc handle. + * Created by individual implementations, see e.g. rpc_udp.c. + * Client is responsible for initializing auth, see e.g. auth_none.c. + */ +typedef struct { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + enum clnt_stat (*cl_call)(); /* call remote procedure */ + void (*cl_abort)(); /* abort a call */ + void (*cl_geterr)(); /* get specific error code */ + bool_t (*cl_freeres)(); /* frees results */ + void (*cl_destroy)();/* destroy this structure */ + bool_t (*cl_control)();/* the ioctl() of rpc */ + } *cl_ops; + caddr_t cl_private; /* private stuff */ +} CLIENT; + + +/* + * client side rpc interface ops + * + * Parameter types are: + * + */ + +/* + * enum clnt_stat + * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout) + * CLIENT *rh; + * rpc_u_int32 proc; + * xdrproc_t xargs; + * caddr_t argsp; + * xdrproc_t xres; + * caddr_t resp; + * struct timeval timeout; + */ +#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, argsp, xres, resp, secs)) + +/* + * void + * CLNT_ABORT(rh); + * CLIENT *rh; + */ +#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh)) +#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh)) + +/* + * struct rpc_err + * CLNT_GETERR(rh); + * CLIENT *rh; + */ +#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) +#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp)) + + +/* + * bool_t + * CLNT_FREERES(rh, xres, resp); + * CLIENT *rh; + * xdrproc_t xres; + * caddr_t resp; + */ +#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) +#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp)) + +/* + * bool_t + * CLNT_CONTROL(cl, request, info) + * CLIENT *cl; + * unsigned int request; + * char *info; + */ +#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) +#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in)) + +/* + * control operations that apply to both udp and tcp transports + */ +#define CLSET_TIMEOUT 1 /* set timeout (timeval) */ +#define CLGET_TIMEOUT 2 /* get timeout (timeval) */ +#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */ +/* + * udp only control operations + */ +#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */ +#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */ +/* + * new control operations + */ +#define CLGET_LOCAL_ADDR 6 /* get local address (sockaddr, getsockname)*/ + +/* + * void + * CLNT_DESTROY(rh); + * CLIENT *rh; + */ +#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) +#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh)) + + +/* + * RPCTEST is a test program which is accessable on every rpc + * transport/port. It is used for testing, performance evaluation, + * and network administration. + */ + +#define RPCTEST_PROGRAM ((rpc_u_int32)1) +#define RPCTEST_VERSION ((rpc_u_int32)1) +#define RPCTEST_NULL_PROC ((rpc_u_int32)2) +#define RPCTEST_NULL_BATCH_PROC ((rpc_u_int32)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((rpc_u_int32)0) + +/* + * Below are the client handle creation routines for the various + * implementations of client side rpc. They can return NULL if a + * creation failure occurs. + */ + +/* + * Memory based rpc (for speed check and testing) + * CLIENT * + * clntraw_create(prog, vers) + * rpc_u_int32 prog; + * rpc_u_int32 vers; + */ +extern CLIENT *clntraw_create(); + + +/* + * Generic client creation routine. Supported protocols are "udp" and "tcp" + */ +extern CLIENT * +clnt_create(/*host, prog, vers, prot*/); /* + char *host; -- hostname + rpc_u_int32 prog; -- program number + rpc_u_int32 vers; -- version number + char *prot; -- protocol +*/ + + + + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * rpc_u_int32 prog; + * rpc_u_int32 version; + * register int *sockp; + * unsigned int sendsz; + * unsigned int recvsz; + */ +extern CLIENT *clnttcp_create(); + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * rpc_u_int32 program; + * rpc_u_int32 version; + * struct timeval wait; + * int *sockp; + * + * Same as above, but you specify max packet sizes. + * CLIENT * + * clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * rpc_u_int32 program; + * rpc_u_int32 version; + * struct timeval wait; + * int *sockp; + * unsigned int sendsz; + * unsigned int recvsz; + */ +extern CLIENT *clntudp_create(); +extern CLIENT *clntudp_bufcreate(); + +/* + * Print why creation failed + */ +void clnt_pcreateerror(/* char *msg */); /* stderr */ +char *clnt_spcreateerror(/* char *msg */); /* string */ + +/* + * Like clnt_perror(), but is more verbose in its output + */ +void clnt_perrno(/* enum clnt_stat num */); /* stderr */ + +/* + * Print an English error message, given the client error code + */ +void clnt_perror(/* CLIENT *clnt, char *msg */); /* stderr */ +char *clnt_sperror(/* CLIENT *clnt, char *msg */); /* string */ + +/* + * If a creation fails, the following allows the user to figure out why. + */ +struct rpc_createerr { + enum clnt_stat cf_stat; + struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */ +}; + +extern struct rpc_createerr rpc_createerr; + + + +/* + * Copy error message to buffer. + */ +char *clnt_sperrno(/* enum clnt_stat num */); /* string */ + + + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +#endif /*!_CLNT_*/ diff --git a/src/lib/rpc/clnt_generic.c b/src/lib/rpc/clnt_generic.c new file mode 100644 index 000000000..f111c2e14 --- /dev/null +++ b/src/lib/rpc/clnt_generic.c @@ -0,0 +1,110 @@ +/* @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI"; +#endif +/* + * Copyright (C) 1987, Sun Microsystems, Inc. + */ +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <netdb.h> + +/* + * Generic client creation: takes (hostname, program-number, protocol) and + * returns client handle. Default options are set, which the user can + * change using the rpc equivalent of ioctl()'s. + */ +CLIENT * +clnt_create(hostname, prog, vers, proto) + char *hostname; + unsigned prog; + unsigned vers; + char *proto; +{ + struct hostent *h; + struct protoent *p; + struct sockaddr_in sin; + int sock; + struct timeval tv; + CLIENT *client; + + h = gethostbyname(hostname); + if (h == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNHOST; + return (NULL); + } + if (h->h_addrtype != AF_INET) { + /* + * Only support INET for now + */ + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = EAFNOSUPPORT; + return (NULL); + } + sin.sin_family = h->h_addrtype; + sin.sin_port = 0; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + memmove((char*)&sin.sin_addr, h->h_addr, h->h_length); + p = getprotobyname(proto); + if (p == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; + return (NULL); + } + sock = RPC_ANYSOCK; + switch (p->p_proto) { + case IPPROTO_UDP: + tv.tv_sec = 5; + tv.tv_usec = 0; + client = clntudp_create(&sin, prog, vers, tv, &sock); + if (client == NULL) { + return (NULL); + } + tv.tv_sec = 25; + clnt_control(client, CLSET_TIMEOUT, &tv); + break; + case IPPROTO_TCP: + client = clnttcp_create(&sin, prog, vers, &sock, 0, 0); + if (client == NULL) { + return (NULL); + } + tv.tv_sec = 25; + tv.tv_usec = 0; + clnt_control(client, CLSET_TIMEOUT, &tv); + break; + default: + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = EPFNOSUPPORT; + return (NULL); + } + return (client); +} diff --git a/src/lib/rpc/clnt_perror.c b/src/lib/rpc/clnt_perror.c new file mode 100644 index 000000000..63eef49f0 --- /dev/null +++ b/src/lib/rpc/clnt_perror.c @@ -0,0 +1,306 @@ +/* @(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_perror.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ +#include <stdio.h> +#include <string.h> + +#include <rpc/types.h> +#include <rpc/auth.h> +#include <rpc/clnt.h> + +#ifdef NEED_SYS_ERRLIST +extern char *sys_errlist[]; +#endif +static char *auth_errmsg(); + +extern char *strcpy(); + +static char *buf; + +static char * +_buf() +{ + + if (buf == 0) + buf = (char *)malloc(256); + return (buf); +} + +/* + * Print reply error info + */ +char * +clnt_sperror(rpch, s) + CLIENT *rpch; + char *s; +{ + struct rpc_err e; + void clnt_perrno(); + char *err; + char *str = _buf(); + char *strstart = str; + + if (str == 0) + return (0); + CLNT_GETERR(rpch, &e); + + (void) sprintf(str, "%s: ", s); + str += strlen(str); + + (void) strcpy(str, clnt_sperrno(e.re_status)); + str += strlen(str); + + switch (e.re_status) { + case RPC_SUCCESS: + case RPC_CANTENCODEARGS: + case RPC_CANTDECODERES: + case RPC_TIMEDOUT: + case RPC_PROGUNAVAIL: + case RPC_PROCUNAVAIL: + case RPC_CANTDECODEARGS: + case RPC_SYSTEMERROR: + case RPC_UNKNOWNHOST: + case RPC_UNKNOWNPROTO: + case RPC_PMAPFAILURE: + case RPC_PROGNOTREGISTERED: + case RPC_FAILED: + break; + + case RPC_CANTSEND: + case RPC_CANTRECV: + (void) sprintf(str, "; errno = %s", + sys_errlist[e.re_errno]); + str += strlen(str); + break; + + case RPC_VERSMISMATCH: + (void) sprintf(str, + "; low version = %lu, high version = %lu", + e.re_vers.low, e.re_vers.high); + str += strlen(str); + break; + + case RPC_AUTHERROR: + err = auth_errmsg(e.re_why); + (void) sprintf(str,"; why = "); + str += strlen(str); + if (err != NULL) { + (void) sprintf(str, "%s",err); + } else { + (void) sprintf(str, + "(unknown authentication error - %d)", + (int) e.re_why); + } + str += strlen(str); + break; + + case RPC_PROGVERSMISMATCH: + (void) sprintf(str, + "; low version = %lu, high version = %lu", + e.re_vers.low, e.re_vers.high); + str += strlen(str); + break; + + default: /* unknown */ + (void) sprintf(str, + "; s1 = %lu, s2 = %lu", + e.re_lb.s1, e.re_lb.s2); + str += strlen(str); + break; + } + (void) sprintf(str, "\n"); + return(strstart) ; +} + +void +clnt_perror(rpch, s) + CLIENT *rpch; + char *s; +{ + (void) fprintf(stderr,"%s",clnt_sperror(rpch,s)); +} + + +struct rpc_errtab { + enum clnt_stat status; + char *message; +}; + +static struct rpc_errtab rpc_errlist[] = { + { RPC_SUCCESS, + "RPC: Success" }, + { RPC_CANTENCODEARGS, + "RPC: Can't encode arguments" }, + { RPC_CANTDECODERES, + "RPC: Can't decode result" }, + { RPC_CANTSEND, + "RPC: Unable to send" }, + { RPC_CANTRECV, + "RPC: Unable to receive" }, + { RPC_TIMEDOUT, + "RPC: Timed out" }, + { RPC_VERSMISMATCH, + "RPC: Incompatible versions of RPC" }, + { RPC_AUTHERROR, + "RPC: Authentication error" }, + { RPC_PROGUNAVAIL, + "RPC: Program unavailable" }, + { RPC_PROGVERSMISMATCH, + "RPC: Program/version mismatch" }, + { RPC_PROCUNAVAIL, + "RPC: Procedure unavailable" }, + { RPC_CANTDECODEARGS, + "RPC: Server can't decode arguments" }, + { RPC_SYSTEMERROR, + "RPC: Remote system error" }, + { RPC_UNKNOWNHOST, + "RPC: Unknown host" }, + { RPC_UNKNOWNPROTO, + "RPC: Unknown protocol" }, + { RPC_PMAPFAILURE, + "RPC: Port mapper failure" }, + { RPC_PROGNOTREGISTERED, + "RPC: Program not registered"}, + { RPC_FAILED, + "RPC: Failed (unspecified error)"} +}; + + +/* + * This interface for use by clntrpc + */ +char * +clnt_sperrno(stat) + enum clnt_stat stat; +{ + int i; + + for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) { + if (rpc_errlist[i].status == stat) { + return (rpc_errlist[i].message); + } + } + return ("RPC: (unknown error code)"); +} + +void +clnt_perrno(num) + enum clnt_stat num; +{ + (void) fprintf(stderr,"%s",clnt_sperrno(num)); +} + + +char * +clnt_spcreateerror(s) + char *s; +{ + extern int sys_nerr; + char *str = _buf(); + + if (str == 0) + return(0); + (void) sprintf(str, "%s: ", s); + (void) strcat(str, clnt_sperrno(rpc_createerr.cf_stat)); + switch (rpc_createerr.cf_stat) { + case RPC_PMAPFAILURE: + (void) strcat(str, " - "); + (void) strcat(str, + clnt_sperrno(rpc_createerr.cf_error.re_status)); + break; + + case RPC_SYSTEMERROR: + (void) strcat(str, " - "); + if (rpc_createerr.cf_error.re_errno > 0 + && rpc_createerr.cf_error.re_errno < sys_nerr) + (void) strcat(str, + sys_errlist[rpc_createerr.cf_error.re_errno]); + else + (void) sprintf(&str[strlen(str)], "Error %d", + rpc_createerr.cf_error.re_errno); + break; + } + (void) strcat(str, "\n"); + return (str); +} + +void +clnt_pcreateerror(s) + char *s; +{ + (void) fprintf(stderr,"%s",clnt_spcreateerror(s)); +} + +struct auth_errtab { + enum auth_stat status; + char *message; +}; + +static struct auth_errtab auth_errlist[] = { + { AUTH_OK, + "Authentication OK" }, + { AUTH_BADCRED, + "Invalid client credential" }, + { AUTH_REJECTEDCRED, + "Server rejected credential" }, + { AUTH_BADVERF, + "Invalid client verifier" }, + { AUTH_REJECTEDVERF, + "Server rejected verifier" }, + { AUTH_TOOWEAK, + "Client credential too weak" }, + { AUTH_INVALIDRESP, + "Invalid server verifier" }, + { AUTH_FAILED, + "Failed (unspecified error)" }, +}; + +static char * +auth_errmsg(stat) + enum auth_stat stat; +{ + int i; + + for (i = 0; i < sizeof(auth_errlist)/sizeof(struct auth_errtab); i++) { + if (auth_errlist[i].status == stat) { + return(auth_errlist[i].message); + } + } + return(NULL); +} diff --git a/src/lib/rpc/clnt_raw.c b/src/lib/rpc/clnt_raw.c new file mode 100644 index 000000000..d05dbaa7e --- /dev/null +++ b/src/lib/rpc/clnt_raw.c @@ -0,0 +1,239 @@ +/* @(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_raw.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Memory based rpc for simple testing and timing. + * Interface to create an rpc client and server in the same process. + * This lets us similate rpc and get round trip overhead, without + * any interference from the kernal. + */ + +#include <rpc/rpc.h> + +#define MCALL_MSG_SIZE 24 + +/* + * This is the "network" we will be moving stuff over. + */ +static struct clntraw_private { + CLIENT client_object; + XDR xdr_stream; + char _raw_buf[UDPMSGSIZE]; + char mashl_callmsg[MCALL_MSG_SIZE]; + unsigned int mcnt; +} *clntraw_private; + +static enum clnt_stat clntraw_call(); +static void clntraw_abort(); +static void clntraw_geterr(); +static bool_t clntraw_freeres(); +static bool_t clntraw_control(); +static void clntraw_destroy(); + +static struct clnt_ops client_ops = { + clntraw_call, + clntraw_abort, + clntraw_geterr, + clntraw_freeres, + clntraw_destroy, + clntraw_control +}; + +void svc_getreq(); + +/* + * Create a client handle for memory based rpc. + */ +CLIENT * +clntraw_create(prog, vers) + rpc_u_int32 prog; + rpc_u_int32 vers; +{ + register struct clntraw_private *clp = clntraw_private; + struct rpc_msg call_msg; + XDR *xdrs = &clp->xdr_stream; + CLIENT *client = &clp->client_object; + + if (clp == 0) { + clp = (struct clntraw_private *)calloc(1, sizeof (*clp)); + if (clp == 0) + return (0); + clntraw_private = clp; + } + /* + * pre-serialize the staic part of the call msg and stash it away + */ + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = prog; + call_msg.rm_call.cb_vers = vers; + xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); + if (! xdr_callhdr(xdrs, &call_msg)) { + perror("clnt_raw.c - Fatal header serialization error."); + } + clp->mcnt = XDR_GETPOS(xdrs); + XDR_DESTROY(xdrs); + + /* + * Set xdrmem for client/server shared buffer + */ + xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE); + + /* + * create client handle + */ + client->cl_ops = &client_ops; + client->cl_auth = authnone_create(); + return (client); +} + +static enum clnt_stat +clntraw_call(h, proc, xargs, argsp, xresults, resultsp, timeout) + CLIENT *h; + rpc_u_int32 proc; + xdrproc_t xargs; + caddr_t argsp; + xdrproc_t xresults; + caddr_t resultsp; + struct timeval timeout; +{ + register struct clntraw_private *clp = clntraw_private; + register XDR *xdrs = &clp->xdr_stream; + struct rpc_msg msg; + enum clnt_stat status; + struct rpc_err error; + long procl = proc; + + if (clp == 0) + return (RPC_FAILED); +call_again: + /* + * send request + */ + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid ++ ; + if ((! XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || + (! XDR_PUTLONG(xdrs, &procl)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! (*xargs)(xdrs, argsp))) { + return (RPC_CANTENCODEARGS); + } + (void)XDR_GETPOS(xdrs); /* called just to cause overhead */ + + /* + * We have to call server input routine here because this is + * all going on in one process. Yuk. + */ + svc_getreq(1); + + /* + * get results + */ + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = resultsp; + msg.acpted_rply.ar_results.proc = xresults; + if (! xdr_replymsg(xdrs, &msg)) + return (RPC_CANTDECODERES); + sunrpc_seterr_reply(&msg, &error); + status = error.re_status; + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + } /* end successful completion */ + else { + if (AUTH_REFRESH(h->cl_auth, &msg)) + goto call_again; + } /* end of unsuccessful completion */ + + if (status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { + status = RPC_AUTHERROR; + } + if (msg.acpted_rply.ar_verf.oa_base != NULL) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf)); + } + } + + return (status); +} + +static void +clntraw_geterr() +{ +} + + +static bool_t +clntraw_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + caddr_t res_ptr; +{ + register struct clntraw_private *clp = clntraw_private; + register XDR *xdrs = &clp->xdr_stream; + bool_t rval; + + if (clp == 0) + { + rval = (bool_t) RPC_FAILED; + return (rval); + } + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clntraw_abort() +{ +} + +static bool_t +clntraw_control() +{ + return (FALSE); +} + +static void +clntraw_destroy() +{ +} diff --git a/src/lib/rpc/clnt_simple.c b/src/lib/rpc/clnt_simple.c new file mode 100644 index 000000000..0d8f7a4df --- /dev/null +++ b/src/lib/rpc/clnt_simple.c @@ -0,0 +1,112 @@ +/* @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <string.h> + +static struct callrpc_private { + CLIENT *client; + int socket; + int oldprognum, oldversnum, valid; + char *oldhost; +} *callrpc_private; + +callrpc(host, prognum, versnum, procnum, inproc, in, outproc, out) + char *host; + xdrproc_t inproc, outproc; + char *in, *out; +{ + register struct callrpc_private *crp = callrpc_private; + struct sockaddr_in server_addr; + enum clnt_stat clnt_stat; + struct hostent *hp; + struct timeval timeout, tottimeout; + + if (crp == 0) { + crp = (struct callrpc_private *)calloc(1, sizeof (*crp)); + if (crp == 0) + return (0); + callrpc_private = crp; + } + if (crp->oldhost == NULL) { + crp->oldhost = mem_alloc(256); + crp->oldhost[0] = 0; + crp->socket = RPC_ANYSOCK; + } + if (crp->valid && crp->oldprognum == prognum && crp->oldversnum == versnum + && strcmp(crp->oldhost, host) == 0) { + /* reuse old client */ + } else { + crp->valid = 0; + (void)close(crp->socket); + crp->socket = RPC_ANYSOCK; + if (crp->client) { + clnt_destroy(crp->client); + crp->client = NULL; + } + if ((hp = gethostbyname(host)) == NULL) + return ((int) RPC_UNKNOWNHOST); + timeout.tv_usec = 0; + timeout.tv_sec = 5; + memmove((char *)&server_addr.sin_addr, hp->h_addr, hp->h_length); + server_addr.sin_family = AF_INET; + server_addr.sin_port = 0; + if ((crp->client = clntudp_create(&server_addr, (rpc_u_int32)prognum, + (rpc_u_int32)versnum, timeout, &crp->socket)) == NULL) + return ((int) rpc_createerr.cf_stat); + crp->valid = 1; + crp->oldprognum = prognum; + crp->oldversnum = versnum; + (void) strcpy(crp->oldhost, host); + } + tottimeout.tv_sec = 25; + tottimeout.tv_usec = 0; + clnt_stat = clnt_call(crp->client, procnum, inproc, in, + outproc, out, tottimeout); + /* + * if call failed, empty cache + */ + if (clnt_stat != RPC_SUCCESS) + crp->valid = 0; + return ((int) clnt_stat); +} diff --git a/src/lib/rpc/clnt_tcp.c b/src/lib/rpc/clnt_tcp.c new file mode 100644 index 000000000..c573897f7 --- /dev/null +++ b/src/lib/rpc/clnt_tcp.c @@ -0,0 +1,476 @@ +/* @(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_tcp.c, Implements a TCP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * TCP based RPC supports 'batched calls'. + * A sequence of calls may be batched-up in a send buffer. The rpc call + * return immediately to the client even though the call was not necessarily + * sent. The batching occurs if the results' xdr routine is NULL (0) AND + * the rpc timeout value is zero (see clnt.h, rpc). + * + * Clients should NOT casually batch calls that in fact return results; that is, + * the server side should be aware that a call is batched and not produce any + * return message. Batched calls that produce many result messages can + * deadlock (netlock) the client and the server.... + * + * Now go hang yourself. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +#define MCALL_MSG_SIZE 24 + +extern int errno; + +static int readtcp(); +static int writetcp(); + +static enum clnt_stat clnttcp_call(); +static void clnttcp_abort(); +static void clnttcp_geterr(); +static bool_t clnttcp_freeres(); +static bool_t clnttcp_control(); +static void clnttcp_destroy(); + +static struct clnt_ops tcp_ops = { + clnttcp_call, + clnttcp_abort, + clnttcp_geterr, + clnttcp_freeres, + clnttcp_destroy, + clnttcp_control +}; + +struct ct_data { + int ct_sock; + bool_t ct_closeit; + struct timeval ct_wait; + bool_t ct_waitset; /* wait set by clnt_control? */ + struct sockaddr_in ct_addr; + struct rpc_err ct_error; + char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */ + unsigned int ct_mpos; /* pos after marshal */ + XDR ct_xdrs; +}; + +/* + * Create a client handle for a tcp/ip connection. + * If *sockp<0, *sockp is set to a newly created TCP socket and it is + * connected to raddr. If *sockp non-negative then + * raddr is ignored. The rpc/tcp package does buffering + * similar to stdio, so the client must pick send and receive buffer sizes,]; + * 0 => use the default. + * If raddr->sin_port is 0, then a binder on the remote machine is + * consulted for the right port number. + * NB: *sockp is copied into a private area. + * NB: It is the clients responsibility to close *sockp. + * NB: The rpch->cl_auth is set null authentication. Caller may wish to set this + * something more useful. + */ +CLIENT * +clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + rpc_u_int32 prog; + rpc_u_int32 vers; + register int *sockp; + unsigned int sendsz; + unsigned int recvsz; +{ + CLIENT *h; + register struct ct_data *ct; + struct timeval now; + struct rpc_msg call_msg; + + h = (CLIENT *)mem_alloc(sizeof(*h)); + if (h == NULL) { + (void)fprintf(stderr, "clnttcp_create: out of memory\n"); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto fooy; + } + ct = (struct ct_data *)mem_alloc(sizeof(*ct)); + if (ct == NULL) { + (void)fprintf(stderr, "clnttcp_create: out of memory\n"); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto fooy; + } + + /* + * If no port number given ask the pmap for one + */ + if (raddr->sin_port == 0) { + unsigned short port; + if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) { + mem_free((caddr_t)ct, sizeof(struct ct_data)); + mem_free((caddr_t)h, sizeof(CLIENT)); + return ((CLIENT *)NULL); + } + raddr->sin_port = htons(port); + } + + /* + * If no socket given, open one + */ + if (*sockp < 0) { + *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + (void)bindresvport(*sockp, (struct sockaddr_in *)0); + if ((*sockp < 0) + || (connect(*sockp, (struct sockaddr *)raddr, + sizeof(*raddr)) < 0)) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(*sockp); + goto fooy; + } + ct->ct_closeit = TRUE; + } else { + ct->ct_closeit = FALSE; + } + + /* + * Set up private data struct + */ + ct->ct_sock = *sockp; + ct->ct_wait.tv_usec = 0; + ct->ct_waitset = FALSE; + ct->ct_addr = *raddr; + + /* + * Initialize call message + */ + (void)gettimeofday(&now, (struct timezone *)0); + call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = prog; + call_msg.rm_call.cb_vers = vers; + + /* + * pre-serialize the staic part of the call msg and stash it away + */ + xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, + XDR_ENCODE); + if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { + if (ct->ct_closeit) { + (void)close(*sockp); + } + goto fooy; + } + ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); + XDR_DESTROY(&(ct->ct_xdrs)); + + /* + * Create a client handle which uses xdrrec for serialization + * and authnone for authentication. + */ + xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, + (caddr_t)ct, readtcp, writetcp); + h->cl_ops = &tcp_ops; + h->cl_private = (caddr_t) ct; + h->cl_auth = authnone_create(); + return (h); + +fooy: + /* + * Something goofed, free stuff and barf + */ + mem_free((caddr_t)ct, sizeof(struct ct_data)); + mem_free((caddr_t)h, sizeof(CLIENT)); + return ((CLIENT *)NULL); +} + +static enum clnt_stat +clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout) + register CLIENT *h; + rpc_u_int32 proc; + xdrproc_t xdr_args; + caddr_t args_ptr; + xdrproc_t xdr_results; + caddr_t results_ptr; + struct timeval timeout; +{ + register struct ct_data *ct = (struct ct_data *) h->cl_private; + register XDR *xdrs = &(ct->ct_xdrs); + struct rpc_msg reply_msg; + rpc_u_int32 x_id; + rpc_u_int32 *msg_x_id = (rpc_u_int32 *)(ct->ct_mcall); /* yuk */ + register bool_t shipnow; + int refreshes = 2; + long procl = proc; + + if (!ct->ct_waitset) { + ct->ct_wait = timeout; + } + + shipnow = + (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 + && timeout.tv_usec == 0) ? FALSE : TRUE; + +call_again: + xdrs->x_op = XDR_ENCODE; + ct->ct_error.re_status = RPC_SUCCESS; + x_id = ntohl(--(*msg_x_id)); + if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || + (! XDR_PUTLONG(xdrs, &procl)) || + (! AUTH_MARSHALL(h->cl_auth, xdrs)) || + (! AUTH_WRAP(h->cl_auth, xdrs, xdr_args, args_ptr))) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTENCODEARGS; + (void)xdrrec_endofrecord(xdrs, TRUE); + return (ct->ct_error.re_status); + } + if (! xdrrec_endofrecord(xdrs, shipnow)) + return (ct->ct_error.re_status = RPC_CANTSEND); + if (! shipnow) + return (RPC_SUCCESS); + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + return(ct->ct_error.re_status = RPC_TIMEDOUT); + } + + + /* + * Keep receiving until we get a valid transaction id + */ + xdrs->x_op = XDR_DECODE; + while (TRUE) { + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = xdr_void; + if (! xdrrec_skiprecord(xdrs)) + return (ct->ct_error.re_status); + /* now decode and validate the response header */ + if (! xdr_replymsg(xdrs, &reply_msg)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + continue; + return (ct->ct_error.re_status); + } + if (reply_msg.rm_xid == x_id) + break; + } + + /* + * process header + */ + sunrpc_seterr_reply(&reply_msg, &(ct->ct_error)); + if (ct->ct_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) { + ct->ct_error.re_status = RPC_AUTHERROR; + ct->ct_error.re_why = AUTH_INVALIDRESP; + } else if (! AUTH_UNWRAP(h->cl_auth, xdrs, + xdr_results, results_ptr)) { + if (ct->ct_error.re_status == RPC_SUCCESS) + ct->ct_error.re_status = RPC_CANTDECODERES; + } + } /* end successful completion */ + else { + /* maybe our credentials need to be refreshed ... */ + if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg)) + goto call_again; + } /* end of unsuccessful completion */ + /* free verifier ... */ + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf)); + } + return (ct->ct_error.re_status); +} + +static void +clnttcp_geterr(h, errp) + CLIENT *h; + struct rpc_err *errp; +{ + register struct ct_data *ct = + (struct ct_data *) h->cl_private; + + *errp = ct->ct_error; +} + +static bool_t +clnttcp_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + caddr_t res_ptr; +{ + register struct ct_data *ct = (struct ct_data *)cl->cl_private; + register XDR *xdrs = &(ct->ct_xdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clnttcp_abort() +{ +} + +static bool_t +clnttcp_control(cl, request, info) + CLIENT *cl; + int request; + char *info; +{ + register struct ct_data *ct = (struct ct_data *)cl->cl_private; + int len; + + switch (request) { + case CLSET_TIMEOUT: + ct->ct_wait = *(struct timeval *)info; + ct->ct_waitset = TRUE; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = ct->ct_wait; + break; + case CLGET_SERVER_ADDR: + *(struct sockaddr_in *)info = ct->ct_addr; + break; + case CLGET_LOCAL_ADDR: + len = sizeof(struct sockaddr); + if (getsockname(ct->ct_sock, (struct sockaddr*)info, &len) < 0) + return FALSE; + else + return TRUE; + default: + return (FALSE); + } + return (TRUE); +} + + +static void +clnttcp_destroy(h) + CLIENT *h; +{ + register struct ct_data *ct = + (struct ct_data *) h->cl_private; + + if (ct->ct_closeit) { + (void)close(ct->ct_sock); + } + XDR_DESTROY(&(ct->ct_xdrs)); + mem_free((caddr_t)ct, sizeof(struct ct_data)); + mem_free((caddr_t)h, sizeof(CLIENT)); +} + +/* + * Interface between xdr serializer and tcp connection. + * Behaves like the system calls, read & write, but keeps some error state + * around for the rpc level. + */ +static int +readtcp(ct, buf, len) + register struct ct_data *ct; + caddr_t buf; + register int len; +{ +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; + + if (len == 0) + return (0); + FD_ZERO(&mask); + FD_SET(ct->ct_sock, &mask); +#else + register int mask = 1 << (ct->ct_sock); + int readfds; + + if (len == 0) + return (0); + +#endif /* def FD_SETSIZE */ + while (TRUE) { + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL, (fd_set*)NULL, + &(ct->ct_wait))) { + case 0: + ct->ct_error.re_status = RPC_TIMEDOUT; + return (-1); + + case -1: + if (errno == EINTR) + continue; + ct->ct_error.re_status = RPC_CANTRECV; + ct->ct_error.re_errno = errno; + return (-1); + } + break; + } + switch (len = read(ct->ct_sock, buf, len)) { + + case 0: + /* premature eof */ + ct->ct_error.re_errno = ECONNRESET; + ct->ct_error.re_status = RPC_CANTRECV; + len = -1; /* it's really an error */ + break; + + case -1: + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTRECV; + break; + } + return (len); +} + +static int +writetcp(ct, buf, len) + struct ct_data *ct; + caddr_t buf; + int len; +{ + register int i, cnt; + + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = write(ct->ct_sock, buf, cnt)) == -1) { + ct->ct_error.re_errno = errno; + ct->ct_error.re_status = RPC_CANTSEND; + return (-1); + } + } + return (len); +} diff --git a/src/lib/rpc/clnt_udp.c b/src/lib/rpc/clnt_udp.c new file mode 100644 index 000000000..000b9683d --- /dev/null +++ b/src/lib/rpc/clnt_udp.c @@ -0,0 +1,460 @@ +/* @(#)clnt_udp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)clnt_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * clnt_udp.c, Implements a UDP/IP based, client side RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#if defined(sparc) +#include <sys/filio.h> +#endif +#include <netdb.h> +#include <errno.h> +#include <rpc/pmap_clnt.h> + +extern int errno; + +/* + * UDP bases client side rpc operations + */ +static enum clnt_stat clntudp_call(); +static void clntudp_abort(); +static void clntudp_geterr(); +static bool_t clntudp_freeres(); +static bool_t clntudp_control(); +static void clntudp_destroy(); + +static struct clnt_ops udp_ops = { + clntudp_call, + clntudp_abort, + clntudp_geterr, + clntudp_freeres, + clntudp_destroy, + clntudp_control +}; + +/* + * Private data kept per client handle + */ +struct cu_data { + int cu_sock; + bool_t cu_closeit; + struct sockaddr_in cu_raddr; + int cu_rlen; + struct timeval cu_wait; + struct timeval cu_total; + struct rpc_err cu_error; + XDR cu_outxdrs; + unsigned int cu_xdrpos; + unsigned int cu_sendsz; + char *cu_outbuf; + unsigned int cu_recvsz; + char cu_inbuf[1]; +}; + +/* + * Create a UDP based client handle. + * If *sockp<0, *sockp is set to a newly created UPD socket. + * If raddr->sin_port is 0 a binder on the remote machine + * is consulted for the correct port number. + * NB: It is the clients responsibility to close *sockp. + * NB: The rpch->cl_auth is initialized to null authentication. + * Caller may wish to set this something more useful. + * + * wait is the amount of time used between retransmitting a call if + * no response has been heard; retransmition occurs until the actual + * rpc call times out. + * + * sendsz and recvsz are the maximum allowable packet sizes that can be + * sent and received. + */ +CLIENT * +clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) + struct sockaddr_in *raddr; + rpc_u_int32 program; + rpc_u_int32 version; + struct timeval wait; + register int *sockp; + unsigned int sendsz; + unsigned int recvsz; +{ + CLIENT *cl; + register struct cu_data *cu; + struct timeval now; + struct rpc_msg call_msg; + + cl = (CLIENT *)mem_alloc(sizeof(CLIENT)); + if (cl == NULL) { + (void) fprintf(stderr, "clntudp_create: out of memory\n"); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto fooy; + } + sendsz = ((sendsz + 3) / 4) * 4; + recvsz = ((recvsz + 3) / 4) * 4; + cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz); + if (cu == NULL) { + (void) fprintf(stderr, "clntudp_create: out of memory\n"); + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto fooy; + } + cu->cu_outbuf = &cu->cu_inbuf[recvsz]; + + (void)gettimeofday(&now, (struct timezone *)0); + if (raddr->sin_port == 0) { + unsigned short port; + if ((port = + pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) { + goto fooy; + } + raddr->sin_port = htons(port); + } + cl->cl_ops = &udp_ops; + cl->cl_private = (caddr_t)cu; + cu->cu_raddr = *raddr; + cu->cu_rlen = sizeof (cu->cu_raddr); + cu->cu_wait = wait; + cu->cu_total.tv_sec = -1; + cu->cu_total.tv_usec = -1; + cu->cu_sendsz = sendsz; + cu->cu_recvsz = recvsz; + call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; + call_msg.rm_direction = CALL; + call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + call_msg.rm_call.cb_prog = program; + call_msg.rm_call.cb_vers = version; + xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, + sendsz, XDR_ENCODE); + if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { + goto fooy; + } + cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); + if (*sockp < 0) { + int dontblock = 1; + + *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (*sockp < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + goto fooy; + } + /* attempt to bind to prov port */ + (void)bindresvport(*sockp, (struct sockaddr_in *)0); + /* the sockets rpc controls are non-blocking */ + (void)ioctl(*sockp, FIONBIO, (char *) &dontblock); + cu->cu_closeit = TRUE; + } else { + cu->cu_closeit = FALSE; + } + cu->cu_sock = *sockp; + cl->cl_auth = authnone_create(); + return (cl); +fooy: + if (cu) + mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz); + if (cl) + mem_free((caddr_t)cl, sizeof(CLIENT)); + return ((CLIENT *)NULL); +} + +CLIENT * +clntudp_create(raddr, program, version, wait, sockp) + struct sockaddr_in *raddr; + rpc_u_int32 program; + rpc_u_int32 version; + struct timeval wait; + register int *sockp; +{ + + return(clntudp_bufcreate(raddr, program, version, wait, sockp, + UDPMSGSIZE, UDPMSGSIZE)); +} + +static enum clnt_stat +clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) + register CLIENT *cl; /* client handle */ + rpc_u_int32 proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + struct timeval utimeout; /* seconds to wait before giving up */ +{ + register struct cu_data *cu = (struct cu_data *)cl->cl_private; + register XDR *xdrs; + register int outlen; + register int inlen; + int fromlen; +#ifdef FD_SETSIZE + fd_set readfds; + fd_set mask; +#else + int readfds; + register int mask; +#endif /* def FD_SETSIZE */ + struct sockaddr_in from; + struct rpc_msg reply_msg; + XDR reply_xdrs; + struct timeval time_waited; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ + struct timeval timeout; + long procl = proc; + + if (cu->cu_total.tv_usec == -1) { + timeout = utimeout; /* use supplied timeout */ + } else { + timeout = cu->cu_total; /* use default timeout */ + } + + time_waited.tv_sec = 0; + time_waited.tv_usec = 0; +call_again: + xdrs = &(cu->cu_outxdrs); + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, cu->cu_xdrpos); + /* + * the transaction is the first thing in the out buffer + */ + (*(unsigned short *)(cu->cu_outbuf))++; + if ((! XDR_PUTLONG(xdrs, &procl)) || + (! AUTH_MARSHALL(cl->cl_auth, xdrs)) || + (! AUTH_WRAP(cl->cl_auth, xdrs, xargs, argsp))) + return (cu->cu_error.re_status = RPC_CANTENCODEARGS); + outlen = (int)XDR_GETPOS(xdrs); + +send_again: + if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, + (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) + != outlen) { + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTSEND); + } + + /* + * Hack to provide rpc-based message passing + */ + if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { + return (cu->cu_error.re_status = RPC_TIMEDOUT); + } + /* + * sub-optimal code appears here because we have + * some clock time to spare while the packets are in flight. + * (We assume that this is actually only executed once.) + */ + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = NULL; + reply_msg.acpted_rply.ar_results.proc = xdr_void; +#ifdef FD_SETSIZE + FD_ZERO(&mask); + FD_SET(cu->cu_sock, &mask); +#else + mask = 1 << cu->cu_sock; +#endif /* def FD_SETSIZE */ + for (;;) { + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, + (fd_set *)NULL, &(cu->cu_wait))) { + + case 0: + time_waited.tv_sec += cu->cu_wait.tv_sec; + time_waited.tv_usec += cu->cu_wait.tv_usec; + while (time_waited.tv_usec >= 1000000) { + time_waited.tv_sec++; + time_waited.tv_usec -= 1000000; + } + if ((time_waited.tv_sec < timeout.tv_sec) || + ((time_waited.tv_sec == timeout.tv_sec) && + (time_waited.tv_usec < timeout.tv_usec))) + goto send_again; + return (cu->cu_error.re_status = RPC_TIMEDOUT); + + /* + * buggy in other cases because time_waited is not being + * updated. + */ + case -1: + if (errno == EINTR) + continue; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } + do { + fromlen = sizeof(struct sockaddr); + inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, + (int) cu->cu_recvsz, 0, + (struct sockaddr *)&from, &fromlen); + } while (inlen < 0 && errno == EINTR); + if (inlen < 0) { + if (errno == EWOULDBLOCK) + continue; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } + if (inlen < sizeof(rpc_u_int32)) + continue; + /* see if reply transaction id matches sent id */ + if (*((rpc_u_int32 *)(cu->cu_inbuf)) != *((rpc_u_int32 *)(cu->cu_outbuf))) + continue; + /* we now assume we have the proper reply */ + break; + } + + /* + * now decode and validate the response + */ + xdrmem_create(&reply_xdrs, cu->cu_inbuf, (unsigned int)inlen, XDR_DECODE); + ok = xdr_replymsg(&reply_xdrs, &reply_msg); + /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ + if (ok) { + sunrpc_seterr_reply(&reply_msg, &(cu->cu_error)); + if (cu->cu_error.re_status == RPC_SUCCESS) { + if (! AUTH_VALIDATE(cl->cl_auth, + &reply_msg.acpted_rply.ar_verf)) { + cu->cu_error.re_status = RPC_AUTHERROR; + cu->cu_error.re_why = AUTH_INVALIDRESP; + } else if (! AUTH_UNWRAP(cl->cl_auth, &reply_xdrs, + xresults, resultsp)) { + if (cu->cu_error.re_status == RPC_SUCCESS) + cu->cu_error.re_status = RPC_CANTDECODERES; + } + } /* end successful completion */ + else { + /* maybe our credentials need to be refreshed ... */ + if (nrefreshes > 0 && + AUTH_REFRESH(cl->cl_auth, &reply_msg)) { + nrefreshes--; + goto call_again; + } + } /* end of unsuccessful completion */ + /* free verifier */ + if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (reply_msg.acpted_rply.ar_verf.oa_base != NULL)) { + xdrs->x_op = XDR_FREE; + (void)xdr_opaque_auth(xdrs, + &(reply_msg.acpted_rply.ar_verf)); + } + } /* end of valid reply message */ + else { + cu->cu_error.re_status = RPC_CANTDECODERES; + } + return (cu->cu_error.re_status); +} + +static void +clntudp_geterr(cl, errp) + CLIENT *cl; + struct rpc_err *errp; +{ + register struct cu_data *cu = (struct cu_data *)cl->cl_private; + + *errp = cu->cu_error; +} + + +static bool_t +clntudp_freeres(cl, xdr_res, res_ptr) + CLIENT *cl; + xdrproc_t xdr_res; + caddr_t res_ptr; +{ + register struct cu_data *cu = (struct cu_data *)cl->cl_private; + register XDR *xdrs = &(cu->cu_outxdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_res)(xdrs, res_ptr)); +} + +static void +clntudp_abort(/*h*/) + /*CLIENT *h;*/ +{ +} + +static bool_t +clntudp_control(cl, request, info) + CLIENT *cl; + int request; + char *info; +{ + register struct cu_data *cu = (struct cu_data *)cl->cl_private; + int len; + + switch (request) { + case CLSET_TIMEOUT: + cu->cu_total = *(struct timeval *)info; + break; + case CLGET_TIMEOUT: + *(struct timeval *)info = cu->cu_total; + break; + case CLSET_RETRY_TIMEOUT: + cu->cu_wait = *(struct timeval *)info; + break; + case CLGET_RETRY_TIMEOUT: + *(struct timeval *)info = cu->cu_wait; + break; + case CLGET_SERVER_ADDR: + *(struct sockaddr_in *)info = cu->cu_raddr; + break; + case CLGET_LOCAL_ADDR: + len = sizeof(struct sockaddr); + if (getsockname(cu->cu_sock, (struct sockaddr*)info, &len) < 0) + return FALSE; + else + return TRUE; + default: + return (FALSE); + } + return (TRUE); +} + +static void +clntudp_destroy(cl) + CLIENT *cl; +{ + register struct cu_data *cu = (struct cu_data *)cl->cl_private; + + if (cu->cu_closeit) { + (void)close(cu->cu_sock); + } + XDR_DESTROY(&(cu->cu_outxdrs)); + mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz)); + mem_free((caddr_t)cl, sizeof(CLIENT)); +} diff --git a/src/lib/rpc/configure.in b/src/lib/rpc/configure.in new file mode 100644 index 000000000..6084638d3 --- /dev/null +++ b/src/lib/rpc/configure.in @@ -0,0 +1,41 @@ +AC_INIT(auth_gssapi.c) +CONFIG_RULES +AC_PROG_ARCHIVE +AC_PROG_ARCHIVE_ADD +AC_PROG_RANLIB +AC_PROG_INSTALL + +AC_CHECK_SIZEOF(int) +SIZEOF_INT=$ac_cv_sizeof_int +AC_SUBST(SIZEOF_INT) +AC_CHECK_SIZEOF(long) +SIZEOF_LONG=$ac_cv_sizeof_long +AC_SUBST(SIZEOF_LONG) + +DECLARE_SYS_ERRLIST + +V5_SHARED_LIB_OBJS +V5_MAKE_SHARED_LIB(libgssrpc,1.0,.., ./rpc) +GSSAPI_KRB5_SH_VERS=$krb5_cv_shlib_version_libgssapi_krb5 +AC_SUBST(GSSAPI_KRB5_SH_VERS) +KRB5_SH_VERS=$krb5_cv_shlib_version_libkrb5 +AC_SUBST(KRB5_SH_VERS) +CRYPTO_SH_VERS=$krb5_cv_shlib_version_libcrypto +AC_SUBST(CRYPTO_SH_VERS) +COMERR_SH_VERS=$krb5_cv_shlib_version_libcom_err +AC_SUBST(COMERR_SH_VERS) +CopySrcHeader(auth.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(auth_gssapi.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(auth_unix.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(clnt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(netdb.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_clnt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_prot.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(pmap_rmt.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(rpc.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(rpc_msg.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(svc.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(svc_auth.h,[$](BUILDTOP)/include/rpc) +CopyHeader(types.h,[$](BUILDTOP)/include/rpc) +CopySrcHeader(xdr.h,[$](BUILDTOP)/include/rpc) +V5_AC_OUTPUT_MAKEFILE( ,types.h:types.hin) diff --git a/src/lib/rpc/get_myaddress.c b/src/lib/rpc/get_myaddress.c new file mode 100644 index 000000000..fa4c54e78 --- /dev/null +++ b/src/lib/rpc/get_myaddress.c @@ -0,0 +1,95 @@ +/* @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)get_myaddress.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * get_myaddress.c + * + * Get client's IP address via ioctl. This avoids using the yellowpages. + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/pmap_prot.h> +#include <sys/socket.h> +#if defined(sun) +#include <sys/sockio.h> +#endif +#include <stdio.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +/* + * don't use gethostbyname, which would invoke yellow pages + */ +get_myaddress(addr) + struct sockaddr_in *addr; +{ + int s; + char buf[BUFSIZ]; + struct ifconf ifc; + struct ifreq ifreq, *ifr; + int len; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("get_myaddress: socket"); + exit(1); + } + ifc.ifc_len = sizeof (buf); + ifc.ifc_buf = buf; + if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { + perror("get_myaddress: ioctl (get interface configuration)"); + exit(1); + } + ifr = ifc.ifc_req; + for (len = ifc.ifc_len; len; len -= sizeof ifreq) { + ifreq = *ifr; + if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + perror("get_myaddress: ioctl"); + exit(1); + } + if ((ifreq.ifr_flags & IFF_UP) && + ifr->ifr_addr.sa_family == AF_INET) { + *addr = *((struct sockaddr_in *)&ifr->ifr_addr); + addr->sin_port = htons(PMAPPORT); + break; + } + ifr++; + } + (void) close(s); +} diff --git a/src/lib/rpc/getrpcent.c b/src/lib/rpc/getrpcent.c new file mode 100644 index 000000000..e48d5b1e9 --- /dev/null +++ b/src/lib/rpc/getrpcent.c @@ -0,0 +1,256 @@ +/* @(#)getrpcent.c 2.2 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)getrpcent.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpc/netdb.h> +#include <netdb.h> +#include <string.h> +#include <sys/socket.h> + +/* setrpcent is declared as int-returning in netdb.h on hpux */ +/* setrpcent is declared as int-returning in rpc/rpcent.h on Solaris */ +#if !defined(hpux) && !(defined(sun) && defined(__svr4__)) +#define SETRPCENT_TYPE void +#else +#define SETRPCENT_TYPE int +#endif + +/* endrpcent is declared as int-returning in netdb.h on hpux */ +#ifndef hpux +#define ENDRPCENT_TYPE void +#else +#define ENDRPCENT_TYPE int +#endif + +SETRPCENT_TYPE setrpcent(int); +ENDRPCENT_TYPE endrpcent(void); + +/* + * Internet version. + */ +struct rpcdata { + FILE *rpcf; + char *current; + int currentlen; + int stayopen; +#define MAXALIASES 35 + char *rpc_aliases[MAXALIASES]; + struct rpcent rpc; + char line[BUFSIZ+1]; + char *domain; +} *rpcdata; +static struct rpcdata *_rpcdata(); + +static struct rpcent *interpret(); +struct hostent *gethostent(); +char *inet_ntoa(); + +static char RPCDB[] = "/etc/rpc"; + +static struct rpcdata * +_rpcdata() +{ + register struct rpcdata *d = rpcdata; + + if (d == 0) { + d = (struct rpcdata *)calloc(1, sizeof (struct rpcdata)); + rpcdata = d; + } + return (d); +} + +struct rpcent * +getrpcbynumber(number) + register int number; +{ + register struct rpcdata *d = _rpcdata(); + register struct rpcent *p; + int reason; + char adrstr[16], *val = NULL; + int vallen; + + if (d == 0) + return (0); + setrpcent(0); + while (p = getrpcent()) { + if (p->r_number == number) + break; + } + endrpcent(); + return (p); +} + +struct rpcent * +getrpcbyname(name) + const char *name; +{ + struct rpcent *rpc; + char **rp; + + setrpcent(0); + while(rpc = getrpcent()) { + if (strcmp(rpc->r_name, name) == 0) + return (rpc); + for (rp = rpc->r_aliases; *rp != NULL; rp++) { + if (strcmp(*rp, name) == 0) + return (rpc); + } + } + endrpcent(); + return (NULL); +} + +SETRPCENT_TYPE setrpcent(f) + int f; +{ + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; + if (d->rpcf == NULL) + d->rpcf = fopen(RPCDB, "r"); + else + rewind(d->rpcf); + if (d->current) + free(d->current); + d->current = NULL; + d->stayopen |= f; +} + +ENDRPCENT_TYPE endrpcent() +{ + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return; + if (d->current && !d->stayopen) { + free(d->current); + d->current = NULL; + } + if (d->rpcf && !d->stayopen) { + fclose(d->rpcf); + d->rpcf = NULL; + } +} + +struct rpcent * +getrpcent() +{ + struct rpcent *hp; + int reason; + char *key = NULL, *val = NULL; + int keylen, vallen; + register struct rpcdata *d = _rpcdata(); + + if (d == 0) + return(NULL); + if (d->rpcf == NULL && (d->rpcf = fopen(RPCDB, "r")) == NULL) + return (NULL); + if (fgets(d->line, BUFSIZ, d->rpcf) == NULL) + return (NULL); + return interpret(d->line, strlen(d->line)); +} + +static struct rpcent * +interpret(val, len) +char *val; +{ + register struct rpcdata *d = _rpcdata(); + char *p; + register char *cp, **q; + + if (d == 0) + return; + strncpy(d->line, val, len); + p = d->line; + d->line[len] = '\n'; + if (*p == '#') + return (getrpcent()); + cp = strchr(p, '#'); + if (cp == NULL) + { + cp = strchr(p, '\n'); + if (cp == NULL) + return (getrpcent()); + } + *cp = '\0'; + cp = strchr(p, ' '); + if (cp == NULL) + { + cp = strchr(p, '\t'); + if (cp == NULL) + return (getrpcent()); + } + *cp++ = '\0'; + /* THIS STUFF IS INTERNET SPECIFIC */ + d->rpc.r_name = d->line; + while (*cp == ' ' || *cp == '\t') + cp++; + d->rpc.r_number = atoi(cp); + q = d->rpc.r_aliases = d->rpc_aliases; + cp = strchr(p, ' '); + if (cp != NULL) + *cp++ = '\0'; + else + { + cp = strchr(p, '\t'); + if (cp != NULL) + *cp++ = '\0'; + } + while (cp && *cp) { + if (*cp == ' ' || *cp == '\t') { + cp++; + continue; + } + if (q < &(d->rpc_aliases[MAXALIASES - 1])) + *q++ = cp; + cp = strchr(p, ' '); + if (cp != NULL) + *cp++ = '\0'; + else + { + cp = strchr(p, '\t'); + if (cp != NULL) + *cp++ = '\0'; + } + } + *q = NULL; + return (&d->rpc); +} diff --git a/src/lib/rpc/getrpcport.c b/src/lib/rpc/getrpcport.c new file mode 100644 index 000000000..d209a1527 --- /dev/null +++ b/src/lib/rpc/getrpcport.c @@ -0,0 +1,55 @@ +/* @(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)getrpcport.c 1.3 87/08/11 SMI"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Copyright (c) 1985 by Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <netdb.h> +#include <sys/socket.h> + +getrpcport(host, prognum, versnum, proto) + char *host; +{ + struct sockaddr_in addr; + struct hostent *hp; + + if ((hp = gethostbyname(host)) == NULL) + return (0); + memmove((char *) &addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_family = AF_INET; + addr.sin_port = 0; + return (pmap_getport(&addr, prognum, versnum, proto)); +} diff --git a/src/lib/rpc/netdb.h b/src/lib/rpc/netdb.h new file mode 100644 index 000000000..f6b6374b5 --- /dev/null +++ b/src/lib/rpc/netdb.h @@ -0,0 +1,50 @@ +#ifndef RPC_NETDB_H +#define RPC_NETDB_H + +/* @(#)netdb.h 2.1 88/07/29 3.9 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)rpc.h 1.8 87/07/24 SMI */ + +/* since the gssrpc library requires that any application using it be +built with these header files, I am making the decision that any app +which uses the rpcent routines must use this header file, or something +compatible (which most <netdb.h> are) --marc */ + +/* Really belongs in <netdb.h> */ + +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +struct rpcent *getrpcbyname(), *getrpcbynumber(), *getrpcent(); + +#endif diff --git a/src/lib/rpc/pmap_clnt.c b/src/lib/rpc/pmap_clnt.c new file mode 100644 index 000000000..7218777cc --- /dev/null +++ b/src/lib/rpc/pmap_clnt.c @@ -0,0 +1,115 @@ +/* @(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_clnt.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +void clnt_perror(); + + +/* + * Set a mapping between program,version and port. + * Calls the pmap service remotely to do the mapping. + */ +bool_t +pmap_set(program, version, protocol, port) + rpc_u_int32 program; + rpc_u_int32 version; + int protocol; + unsigned short port; +{ + struct sockaddr_in myaddress; + int socket = -1; + register CLIENT *client; + struct pmap parms; + bool_t rslt; + + get_myaddress(&myaddress); + client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, + timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client == (CLIENT *)NULL) + return (FALSE); + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_prot = protocol; + parms.pm_port = port; + if (CLNT_CALL(client, PMAPPROC_SET, xdr_pmap, &parms, xdr_bool, &rslt, + tottimeout) != RPC_SUCCESS) { + clnt_perror(client, "Cannot register service"); + return (FALSE); + } + CLNT_DESTROY(client); + (void)close(socket); + return (rslt); +} + +/* + * Remove the mapping between program,version and port. + * Calls the pmap service remotely to do the un-mapping. + */ +bool_t +pmap_unset(program, version) + rpc_u_int32 program; + rpc_u_int32 version; +{ + struct sockaddr_in myaddress; + int socket = -1; + register CLIENT *client; + struct pmap parms; + bool_t rslt; + + get_myaddress(&myaddress); + client = clntudp_bufcreate(&myaddress, PMAPPROG, PMAPVERS, + timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client == (CLIENT *)NULL) + return (FALSE); + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_port = parms.pm_prot = 0; + CLNT_CALL(client, PMAPPROC_UNSET, xdr_pmap, &parms, xdr_bool, &rslt, + tottimeout); + CLNT_DESTROY(client); + (void)close(socket); + return (rslt); +} diff --git a/src/lib/rpc/pmap_clnt.h b/src/lib/rpc/pmap_clnt.h new file mode 100644 index 000000000..dfb00dcc5 --- /dev/null +++ b/src/lib/rpc/pmap_clnt.h @@ -0,0 +1,65 @@ +/* @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC; from 1.11 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * pmap_clnt.h + * Supplies C routines to get to portmap services. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Usage: + * success = pmap_set(program, version, protocol, port); + * success = pmap_unset(program, version); + * port = pmap_getport(address, program, version, protocol); + * head = pmap_getmaps(address); + * clnt_stat = pmap_rmtcall(address, program, version, procedure, + * xdrargs, argsp, xdrres, resp, tout, port_ptr) + * (works for udp only.) + * clnt_stat = clnt_broadcast(program, version, procedure, + * xdrargs, argsp, xdrres, resp, eachresult) + * (like pmap_rmtcall, except the call is broadcasted to all + * locally connected nets. For each valid response received, + * the procedure eachresult is called. Its form is: + * done = eachresult(resp, raddr) + * bool_t done; + * caddr_t resp; + * struct sockaddr_in raddr; + * where resp points to the results of the call and raddr is the + * address if the responder to the broadcast. + */ + +extern bool_t pmap_set(); +extern bool_t pmap_unset(); +extern struct pmaplist *pmap_getmaps(); +enum clnt_stat pmap_rmtcall(); +enum clnt_stat clnt_broadcast(); +extern unsigned short pmap_getport(); diff --git a/src/lib/rpc/pmap_getmaps.c b/src/lib/rpc/pmap_getmaps.c new file mode 100644 index 000000000..472b2a46d --- /dev/null +++ b/src/lib/rpc/pmap_getmaps.c @@ -0,0 +1,88 @@ +/* @(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getmap.c + * Client interface to pmap rpc service. + * contains pmap_getmaps, which is only tcp service involved + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#include <netdb.h> +#include <stdio.h> +#include <errno.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#define NAMELEN 255 +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; + +/* + * Get a copy of the current port maps. + * Calls the pmap service remotely to do get the maps. + */ +struct pmaplist * +pmap_getmaps(address) + struct sockaddr_in *address; +{ + struct pmaplist *head = (struct pmaplist *)NULL; + int socket = -1; + struct timeval minutetimeout; + register CLIENT *client; + + minutetimeout.tv_sec = 60; + minutetimeout.tv_usec = 0; + address->sin_port = htons(PMAPPORT); + client = clnttcp_create(address, PMAPPROG, + PMAPVERS, &socket, 50, 500); + if (client != (CLIENT *)NULL) { + if (CLNT_CALL(client, PMAPPROC_DUMP, xdr_void, NULL, xdr_pmaplist, + &head, minutetimeout) != RPC_SUCCESS) { + clnt_perror(client, "pmap_getmaps rpc problem"); + } + CLNT_DESTROY(client); + } + (void)close(socket); + address->sin_port = 0; + return (head); +} diff --git a/src/lib/rpc/pmap_getport.c b/src/lib/rpc/pmap_getport.c new file mode 100644 index 000000000..40b764880 --- /dev/null +++ b/src/lib/rpc/pmap_getport.c @@ -0,0 +1,91 @@ +/* @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_getport.c + * Client interface to pmap rpc service. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <sys/socket.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> + +static struct timeval timeout = { 5, 0 }; +static struct timeval tottimeout = { 60, 0 }; + +/* + * Find the mapped port for program,version. + * Calls the pmap service remotely to do the lookup. + * Returns 0 if no map exists. + */ +unsigned short +pmap_getport(address, program, version, protocol) + struct sockaddr_in *address; + rpc_u_int32 program; + rpc_u_int32 version; + unsigned int protocol; +{ + unsigned short port = 0; + int socket = -1; + register CLIENT *client; + struct pmap parms; + + address->sin_port = htons(PMAPPORT); + client = clntudp_bufcreate(address, PMAPPROG, + PMAPVERS, timeout, &socket, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE); + if (client != (CLIENT *)NULL) { + parms.pm_prog = program; + parms.pm_vers = version; + parms.pm_prot = protocol; + parms.pm_port = 0; /* not needed or used */ + if (CLNT_CALL(client, PMAPPROC_GETPORT, xdr_pmap, &parms, + xdr_u_short, &port, tottimeout) != RPC_SUCCESS){ + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + clnt_geterr(client, &rpc_createerr.cf_error); + } else if (port == 0) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + } + CLNT_DESTROY(client); + } + (void)close(socket); + address->sin_port = 0; + return (port); +} diff --git a/src/lib/rpc/pmap_prot.c b/src/lib/rpc/pmap_prot.c new file mode 100644 index 000000000..1dffffe17 --- /dev/null +++ b/src/lib/rpc/pmap_prot.c @@ -0,0 +1,57 @@ +/* @(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +bool_t +xdr_pmap(xdrs, regs) + XDR *xdrs; + struct pmap *regs; +{ + + if (xdr_u_int32(xdrs, ®s->pm_prog) && + xdr_u_int32(xdrs, ®s->pm_vers) && + xdr_u_int32(xdrs, ®s->pm_prot)) + return (xdr_u_int32(xdrs, ®s->pm_port)); + return (FALSE); +} diff --git a/src/lib/rpc/pmap_prot.h b/src/lib/rpc/pmap_prot.h new file mode 100644 index 000000000..4f76580f4 --- /dev/null +++ b/src/lib/rpc/pmap_prot.h @@ -0,0 +1,94 @@ +/* @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC; from 1.14 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * pmap_prot.h + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * The following procedures are supported by the protocol: + * + * PMAPPROC_NULL() returns () + * takes nothing, returns nothing + * + * PMAPPROC_SET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Registers the tuple + * [prog, vers, prot, port]. + * + * PMAPPROC_UNSET(struct pmap) returns (bool_t) + * TRUE is success, FALSE is failure. Un-registers pair + * [prog, vers]. prot and port are ignored. + * + * PMAPPROC_GETPORT(struct pmap) returns (rpc_int32 unsigned). + * 0 is failure. Otherwise returns the port number where the pair + * [prog, vers] is registered. It may lie! + * + * PMAPPROC_DUMP() RETURNS (struct pmaplist *) + * + * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>) + * RETURNS (port, string<>); + * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs); + * Calls the procedure on the local machine. If it is not registered, + * this procedure is quite; ie it does not return error information!!! + * This procedure only is supported on rpc/udp and calls via + * rpc/udp. This routine only passes null authentication parameters. + * This file has no interface to xdr routines for PMAPPROC_CALLIT. + * + * The service supports remote procedure calls on udp/ip or tcp/ip socket 111. + */ + +#define PMAPPORT ((unsigned short)111) +#define PMAPPROG ((rpc_u_int32)100000) +#define PMAPVERS ((rpc_u_int32)2) +#define PMAPVERS_PROTO ((rpc_u_int32)2) +#define PMAPVERS_ORIG ((rpc_u_int32)1) +#define PMAPPROC_NULL ((rpc_u_int32)0) +#define PMAPPROC_SET ((rpc_u_int32)1) +#define PMAPPROC_UNSET ((rpc_u_int32)2) +#define PMAPPROC_GETPORT ((rpc_u_int32)3) +#define PMAPPROC_DUMP ((rpc_u_int32)4) +#define PMAPPROC_CALLIT ((rpc_u_int32)5) + +struct pmap { + rpc_u_int32 pm_prog; + rpc_u_int32 pm_vers; + rpc_u_int32 pm_prot; + rpc_u_int32 pm_port; +}; + +extern bool_t xdr_pmap(); + +struct pmaplist { + struct pmap pml_map; + struct pmaplist *pml_next; +}; + +extern bool_t xdr_pmaplist(); diff --git a/src/lib/rpc/pmap_prot2.c b/src/lib/rpc/pmap_prot2.c new file mode 100644 index 000000000..5f48f2a28 --- /dev/null +++ b/src/lib/rpc/pmap_prot2.c @@ -0,0 +1,116 @@ +/* @(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_prot2.c + * Protocol for the local binder service, or pmap. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/pmap_prot.h> + + +/* + * What is going on with linked lists? (!) + * First recall the link list declaration from pmap_prot.h: + * + * struct pmaplist { + * struct pmap pml_map; + * struct pmaplist *pml_map; + * }; + * + * Compare that declaration with a corresponding xdr declaration that + * is (a) pointer-less, and (b) recursive: + * + * typedef union switch (bool_t) { + * + * case TRUE: struct { + * struct pmap; + * pmaplist_t foo; + * }; + * + * case FALSE: struct {}; + * } pmaplist_t; + * + * Notice that the xdr declaration has no nxt pointer while + * the C declaration has no bool_t variable. The bool_t can be + * interpreted as ``more data follows me''; if FALSE then nothing + * follows this bool_t; if TRUE then the bool_t is followed by + * an actual struct pmap, and then (recursively) by the + * xdr union, pamplist_t. + * + * This could be implemented via the xdr_union primitive, though this + * would cause a one recursive call per element in the list. Rather than do + * that we can ``unwind'' the recursion + * into a while loop and do the union arms in-place. + * + * The head of the list is what the C programmer wishes to past around + * the net, yet is the data that the pointer points to which is interesting; + * this sounds like a job for xdr_reference! + */ +bool_t +xdr_pmaplist(xdrs, rp) + register XDR *xdrs; + register struct pmaplist **rp; +{ + /* + * more_elements is pre-computed in case the direction is + * XDR_ENCODE or XDR_FREE. more_elements is overwritten by + * xdr_bool when the direction is XDR_DECODE. + */ + bool_t more_elements; + register int freeing = (xdrs->x_op == XDR_FREE); + register struct pmaplist **next; + + while (TRUE) { + more_elements = (bool_t)(*rp != NULL); + if (! xdr_bool(xdrs, &more_elements)) + return (FALSE); + if (! more_elements) + return (TRUE); /* we are done */ + /* + * the unfortunate side effect of non-recursion is that in + * the case of freeing we must remember the next object + * before we free the current object ... + */ + if (freeing) + next = &((*rp)->pml_next); + if (! xdr_reference(xdrs, (caddr_t *)rp, + (unsigned int)sizeof(struct pmaplist), xdr_pmap)) + return (FALSE); + rp = (freeing) ? next : &((*rp)->pml_next); + } +} diff --git a/src/lib/rpc/pmap_rmt.c b/src/lib/rpc/pmap_rmt.c new file mode 100644 index 000000000..6a2376763 --- /dev/null +++ b/src/lib/rpc/pmap_rmt.c @@ -0,0 +1,403 @@ +/* @(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro"; +#endif + +/* + * pmap_rmt.c + * Client interface to pmap rpc service. + * remote call and broadcast service + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_clnt.h> +#include <rpc/pmap_rmt.h> +#include <sys/socket.h> +#ifdef sparc +#include <sys/sockio.h> +#endif +#include <stdio.h> +#include <errno.h> +#ifdef OSF1 +#include <net/route.h> +#include <sys/mbuf.h> +#endif +#include <net/if.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#define MAX_BROADCAST_SIZE 1400 + +extern int errno; +static struct timeval timeout = { 3, 0 }; + + +/* + * pmapper remote-call-service interface. + * This routine is used to call the pmapper remote call service + * which will look up a service program in the port maps, and then + * remotely call that routine with the given parameters. This allows + * programs to do a lookup and call in one step. +*/ +enum clnt_stat +pmap_rmtcall(addr, prog, vers, proc, xdrargs, argsp, xdrres, resp, tout, port_ptr) + struct sockaddr_in *addr; + rpc_u_int32 prog, vers, proc; + xdrproc_t xdrargs, xdrres; + caddr_t argsp, resp; + struct timeval tout; + rpc_u_int32 *port_ptr; +{ + int socket = -1; + register CLIENT *client; + struct rmtcallargs a; + struct rmtcallres r; + enum clnt_stat stat; + + addr->sin_port = htons(PMAPPORT); + client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &socket); + if (client != (CLIENT *)NULL) { + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.args_ptr = argsp; + a.xdr_args = xdrargs; + r.port_ptr = port_ptr; + r.results_ptr = resp; + r.xdr_results = xdrres; + stat = CLNT_CALL(client, PMAPPROC_CALLIT, xdr_rmtcall_args, &a, + xdr_rmtcallres, &r, tout); + CLNT_DESTROY(client); + } else { + stat = RPC_FAILED; + } + (void)close(socket); + addr->sin_port = 0; + return (stat); +} + + +/* + * XDR remote call arguments + * written for XDR_ENCODE direction only + */ +bool_t +xdr_rmtcall_args(xdrs, cap) + register XDR *xdrs; + register struct rmtcallargs *cap; +{ + unsigned int lenposition, argposition, position; + + if (xdr_u_int32(xdrs, &(cap->prog)) && + xdr_u_int32(xdrs, &(cap->vers)) && + xdr_u_int32(xdrs, &(cap->proc))) { + lenposition = XDR_GETPOS(xdrs); + if (! xdr_u_int32(xdrs, &(cap->arglen))) + return (FALSE); + argposition = XDR_GETPOS(xdrs); + if (! (*(cap->xdr_args))(xdrs, cap->args_ptr)) + return (FALSE); + position = XDR_GETPOS(xdrs); + cap->arglen = (rpc_u_int32)position - (rpc_u_int32)argposition; + XDR_SETPOS(xdrs, lenposition); + if (! xdr_u_int32(xdrs, &(cap->arglen))) + return (FALSE); + XDR_SETPOS(xdrs, position); + return (TRUE); + } + return (FALSE); +} + +/* + * XDR remote call results + * written for XDR_DECODE direction only + */ +bool_t +xdr_rmtcallres(xdrs, crp) + register XDR *xdrs; + register struct rmtcallres *crp; +{ + caddr_t port_ptr; + + port_ptr = (caddr_t)crp->port_ptr; + if (xdr_reference(xdrs, &port_ptr, sizeof (rpc_u_int32), + xdr_u_int32) && xdr_u_int32(xdrs, &crp->resultslen)) { + crp->port_ptr = (rpc_u_int32 *)port_ptr; + return ((*(crp->xdr_results))(xdrs, crp->results_ptr)); + } + return (FALSE); +} + + +/* + * The following is kludged-up support for simple rpc broadcasts. + * Someday a large, complicated system will replace these trivial + * routines which only support udp/ip . + */ + +static int +getbroadcastnets(addrs, sock, buf) + struct in_addr *addrs; + int sock; /* any valid socket will do */ + char *buf; /* why allocxate more when we can use existing... */ +{ + struct ifconf ifc; + struct ifreq ifreq, *ifr; + struct sockaddr_in *sin; + int n, i; + + ifc.ifc_len = UDPMSGSIZE; + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { + perror("broadcast: ioctl (get interface configuration)"); + return (0); + } + ifr = ifc.ifc_req; + for (i = 0, n = ifc.ifc_len/sizeof (struct ifreq); n > 0; n--, ifr++) { + ifreq = *ifr; + if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreq) < 0) { + perror("broadcast: ioctl (get interface flags)"); + continue; + } + if ((ifreq.ifr_flags & IFF_BROADCAST) && + (ifreq.ifr_flags & IFF_UP) && + ifr->ifr_addr.sa_family == AF_INET) { + sin = (struct sockaddr_in *)&ifr->ifr_addr; +#ifdef SIOCGIFBRDADDR /* 4.3BSD */ + if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { + addrs[i++].s_addr = INADDR_ANY; +#if 0 /* this is uuuuugly */ + addrs[i++] = inet_makeaddr(inet_netof +#if defined(hpux) || (defined(sparc) && defined(__svr4__)) || defined(linux) || (defined(__osf__) && defined(__alpha__)) + (sin->sin_addr), INADDR_ANY); +#else /* hpux or solaris */ + (sin->sin_addr.s_addr), INADDR_ANY); +#endif +#endif + } else { + addrs[i++] = ((struct sockaddr_in*) + &ifreq.ifr_addr)->sin_addr; + } +#else /* 4.2 BSD */ + addrs[i++] = inet_makeaddr(inet_netof + (sin->sin_addr.s_addr), INADDR_ANY); +#endif + } + } + return (i); +} + +typedef bool_t (*resultproc_t)(); + +enum clnt_stat +clnt_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp, eachresult) + rpc_u_int32 prog; /* program number */ + rpc_u_int32 vers; /* version number */ + rpc_u_int32 proc; /* procedure number */ + xdrproc_t xargs; /* xdr routine for args */ + caddr_t argsp; /* pointer to args */ + xdrproc_t xresults; /* xdr routine for results */ + caddr_t resultsp; /* pointer to results */ + resultproc_t eachresult; /* call with each result obtained */ +{ + enum clnt_stat stat; + AUTH *unix_auth = authunix_create_default(); + XDR xdr_stream; + register XDR *xdrs = &xdr_stream; + int outlen, inlen, fromlen, nets; + register int sock; + int on = 1; +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; +#else + int readfds; + register int mask; +#endif /* def FD_SETSIZE */ + register int i; + bool_t done = FALSE; + register rpc_u_int32 xid; + rpc_u_int32 port; + struct in_addr addrs[20]; + struct sockaddr_in baddr, raddr; /* broadcast and response addresses */ + struct rmtcallargs a; + struct rmtcallres r; + struct rpc_msg msg; + struct timeval t; + char outbuf[MAX_BROADCAST_SIZE], inbuf[UDPMSGSIZE]; + + /* + * initialization: create a socket, a broadcast address, and + * preserialize the arguments into a send buffer. + */ + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + perror("Cannot create socket for broadcast rpc"); + stat = RPC_CANTSEND; + goto done_broad; + } +#ifdef SO_BROADCAST + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *) &on, + sizeof (on)) < 0) { + perror("Cannot set socket option SO_BROADCAST"); + stat = RPC_CANTSEND; + goto done_broad; + } +#endif /* def SO_BROADCAST */ +#ifdef FD_SETSIZE + FD_ZERO(&mask); + FD_SET(sock, &mask); +#else + mask = (1 << sock); +#endif /* def FD_SETSIZE */ + nets = getbroadcastnets(addrs, sock, inbuf); + bzero((char *)&baddr, sizeof (baddr)); + baddr.sin_family = AF_INET; + baddr.sin_port = htons(PMAPPORT); + baddr.sin_addr.s_addr = htonl(INADDR_ANY); +/* baddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY); */ + (void)gettimeofday(&t, (struct timezone *)0); + msg.rm_xid = xid = getpid() ^ t.tv_sec ^ t.tv_usec; + t.tv_usec = 0; + msg.rm_direction = CALL; + msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; + msg.rm_call.cb_prog = PMAPPROG; + msg.rm_call.cb_vers = PMAPVERS; + msg.rm_call.cb_proc = PMAPPROC_CALLIT; + msg.rm_call.cb_cred = unix_auth->ah_cred; + msg.rm_call.cb_verf = unix_auth->ah_verf; + a.prog = prog; + a.vers = vers; + a.proc = proc; + a.xdr_args = xargs; + a.args_ptr = argsp; + r.port_ptr = &port; + r.xdr_results = xresults; + r.results_ptr = resultsp; + xdrmem_create(xdrs, outbuf, MAX_BROADCAST_SIZE, XDR_ENCODE); + if ((! xdr_callmsg(xdrs, &msg)) || (! xdr_rmtcall_args(xdrs, &a))) { + stat = RPC_CANTENCODEARGS; + goto done_broad; + } + outlen = (int)xdr_getpos(xdrs); + xdr_destroy(xdrs); + /* + * Basic loop: broadcast a packet and wait a while for response(s). + * The response timeout grows larger per iteration. + */ + for (t.tv_sec = 4; t.tv_sec <= 14; t.tv_sec += 2) { + for (i = 0; i < nets; i++) { + baddr.sin_addr = addrs[i]; + if (sendto(sock, outbuf, outlen, 0, + (struct sockaddr *)&baddr, + sizeof (struct sockaddr)) != outlen) { + perror("Cannot send broadcast packet"); + stat = RPC_CANTSEND; + goto done_broad; + } + } + if (eachresult == NULL) { + stat = RPC_SUCCESS; + goto done_broad; + } + recv_again: + msg.acpted_rply.ar_verf = _null_auth; + msg.acpted_rply.ar_results.where = (caddr_t)&r; + msg.acpted_rply.ar_results.proc = xdr_rmtcallres; + readfds = mask; + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)NULL, + (fd_set *)NULL, &t)) { + + case 0: /* timed out */ + stat = RPC_TIMEDOUT; + continue; + + case -1: /* some kind of error */ + if (errno == EINTR) + goto recv_again; + perror("Broadcast select problem"); + stat = RPC_CANTRECV; + goto done_broad; + + } /* end of select results switch */ + try_again: + fromlen = sizeof(struct sockaddr); + inlen = recvfrom(sock, inbuf, UDPMSGSIZE, 0, + (struct sockaddr *)&raddr, &fromlen); + if (inlen < 0) { + if (errno == EINTR) + goto try_again; + perror("Cannot receive reply to broadcast"); + stat = RPC_CANTRECV; + goto done_broad; + } + if (inlen < sizeof(rpc_u_int32)) + goto recv_again; + /* + * see if reply transaction id matches sent id. + * If so, decode the results. + */ + xdrmem_create(xdrs, inbuf, (unsigned int)inlen, XDR_DECODE); + if (xdr_replymsg(xdrs, &msg)) { + if ((msg.rm_xid == xid) && + (msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (msg.acpted_rply.ar_stat == SUCCESS)) { + raddr.sin_port = htons((unsigned short)port); + done = (*eachresult)(resultsp, &raddr); + } + /* otherwise, we just ignore the errors ... */ + } else { +#ifdef notdef + /* some kind of deserialization problem ... */ + if (msg.rm_xid == xid) + fprintf(stderr, "Broadcast deserialization problem"); + /* otherwise, just random garbage */ +#endif + } + xdrs->x_op = XDR_FREE; + msg.acpted_rply.ar_results.proc = xdr_void; + (void)xdr_replymsg(xdrs, &msg); + (void)(*xresults)(xdrs, resultsp); + xdr_destroy(xdrs); + if (done) { + stat = RPC_SUCCESS; + goto done_broad; + } else { + goto recv_again; + } + } +done_broad: + (void)close(sock); + AUTH_DESTROY(unix_auth); + return (stat); +} + diff --git a/src/lib/rpc/pmap_rmt.h b/src/lib/rpc/pmap_rmt.h new file mode 100644 index 000000000..2ea22120e --- /dev/null +++ b/src/lib/rpc/pmap_rmt.h @@ -0,0 +1,53 @@ +/* @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC; from 1.2 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +struct rmtcallargs { + rpc_u_int32 prog, vers, proc, arglen; + caddr_t args_ptr; + xdrproc_t xdr_args; +}; + +bool_t xdr_rmtcall_args(); + +struct rmtcallres { + rpc_u_int32 *port_ptr; + rpc_u_int32 resultslen; + caddr_t results_ptr; + xdrproc_t xdr_results; +}; + +bool_t xdr_rmtcallres(); diff --git a/src/lib/rpc/rpc.h b/src/lib/rpc/rpc.h new file mode 100644 index 000000000..d0280aaa0 --- /dev/null +++ b/src/lib/rpc/rpc.h @@ -0,0 +1,74 @@ +/* @(#)rpc.h 2.3 88/08/10 4.0 RPCSRC; from 1.9 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef __RPC_HEADER__ +#define __RPC_HEADER__ + +#include <rpc/types.h> /* some typedefs */ +#include <netinet/in.h> + +/* external data representation interfaces */ +#include <rpc/xdr.h> /* generic (de)serializer */ + +/* Client side only authentication */ +#include <rpc/auth.h> /* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include <rpc/clnt.h> /* generic rpc stuff */ + +/* semi-private protocol headers */ +#include <rpc/rpc_msg.h> /* protocol for rpc messages */ +#include <rpc/auth_unix.h> /* protocol for unix style cred */ +/* + * Uncomment-out the next line if you are building the rpc library with + * DES Authentication (see the README file in the secure_rpc/ directory). + */ +/*#include <rpc/auth_des.h> protocol for des style cred */ + +/* Server side only remote procedure callee */ +#include <rpc/svc_auth.h> /* service side authenticator */ +#include <rpc/svc.h> /* service manager and multiplexer */ + +/* + * COMMENT OUT THE NEXT INCLUDE IF RUNNING ON SUN OS OR ON A VERSION + * OF UNIX BASED ON NFSSRC. These systems will already have the structures + * defined by <rpc/netdb.h> included in <netdb.h>. + */ +/* routines for parsing /etc/rpc */ +#include <netdb.h> +#include <rpc/netdb.h> /* structures and routines to parse /etc/rpc */ + +#endif /* ndef __RPC_HEADER__ */ diff --git a/src/lib/rpc/rpc_callmsg.c b/src/lib/rpc/rpc_callmsg.c new file mode 100644 index 000000000..370e79ff9 --- /dev/null +++ b/src/lib/rpc/rpc_callmsg.c @@ -0,0 +1,195 @@ +/* @(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_callmsg.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* + * XDR a call message + */ +bool_t +xdr_callmsg(xdrs, cmsg) + register XDR *xdrs; + register struct rpc_msg *cmsg; +{ + register rpc_int32 *buf; + register struct opaque_auth *oa; + + if (xdrs->x_op == XDR_ENCODE) { + if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + buf = (rpc_int32 *) XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_cred.oa_length) + + 2 * BYTES_PER_XDR_UNIT + + RNDUP(cmsg->rm_call.cb_verf.oa_length)); + if (buf != NULL) { + IXDR_PUT_LONG(buf, cmsg->rm_xid); + IXDR_PUT_ENUM(buf, cmsg->rm_direction); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + IXDR_PUT_LONG(buf, cmsg->rm_call.cb_rpcvers); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + IXDR_PUT_LONG(buf, cmsg->rm_call.cb_prog); + IXDR_PUT_LONG(buf, cmsg->rm_call.cb_vers); + IXDR_PUT_LONG(buf, cmsg->rm_call.cb_proc); + oa = &cmsg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memmove((caddr_t)buf, oa->oa_base, + oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof (rpc_int32); + } + oa = &cmsg->rm_call.cb_verf; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memmove((caddr_t)buf, oa->oa_base, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / sizeof (rpc_int32); + */ + } + return (TRUE); + } + } + if (xdrs->x_op == XDR_DECODE) { + buf = (rpc_int32 *) XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT); + if (buf != NULL) { + cmsg->rm_xid = IXDR_GET_LONG(buf); + cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type); + if (cmsg->rm_direction != CALL) { + return (FALSE); + } + cmsg->rm_call.cb_rpcvers = IXDR_GET_LONG(buf); + if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) { + return (FALSE); + } + cmsg->rm_call.cb_prog = IXDR_GET_LONG(buf); + cmsg->rm_call.cb_vers = IXDR_GET_LONG(buf); + cmsg->rm_call.cb_proc = IXDR_GET_LONG(buf); + oa = &cmsg->rm_call.cb_cred; + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = IXDR_GET_LONG(buf); + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + } + buf = (rpc_int32 *) + XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, (caddr_t)buf, + oa->oa_length); + /* no real need.... + buf += RNDUP(oa->oa_length) / + sizeof (rpc_int32); + */ + } + } + oa = &cmsg->rm_call.cb_verf; + buf = (rpc_int32 *) + XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE || + xdr_u_int(xdrs, &oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t); + oa->oa_length = IXDR_GET_LONG(buf); + } + if (oa->oa_length) { + if (oa->oa_length > MAX_AUTH_BYTES) { + return (FALSE); + } + if (oa->oa_base == NULL) { + oa->oa_base = (caddr_t) + mem_alloc(oa->oa_length); + } + buf = (rpc_int32 *) + XDR_INLINE(xdrs, RNDUP(oa->oa_length)); + if (buf == NULL) { + if (xdr_opaque(xdrs, oa->oa_base, + oa->oa_length) == FALSE) { + return (FALSE); + } + } else { + memmove(oa->oa_base, (caddr_t) buf, + oa->oa_length); + /* no real need... + buf += RNDUP(oa->oa_length) / + sizeof (rpc_int32); + */ + } + } + return (TRUE); + } + } + if ( + xdr_u_int32(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + (cmsg->rm_direction == CALL) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_proc)) && + xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) ) + return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf))); + return (FALSE); +} + diff --git a/src/lib/rpc/rpc_commondata.c b/src/lib/rpc/rpc_commondata.c new file mode 100644 index 000000000..75cead087 --- /dev/null +++ b/src/lib/rpc/rpc_commondata.c @@ -0,0 +1,41 @@ +/* @(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#include <rpc/rpc.h> +/* + * This file should only contain common data (global data) that is exported + * by public interfaces + */ +struct opaque_auth _null_auth; +#ifdef FD_SETSIZE +fd_set svc_fdset; +#else +int svc_fds; +#endif /* def FD_SETSIZE */ +struct rpc_createerr rpc_createerr; diff --git a/src/lib/rpc/rpc_dtablesize.c b/src/lib/rpc/rpc_dtablesize.c new file mode 100644 index 000000000..d252d6acd --- /dev/null +++ b/src/lib/rpc/rpc_dtablesize.c @@ -0,0 +1,60 @@ +/* @(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro"; +#endif + +#include <unistd.h> + +/* + * Cache the result of getdtablesize(), so we don't have to do an + * expensive system call every time. + */ +_rpc_dtablesize() +{ + static int size; + + if (size == 0) { +#ifdef _SC_OPEN_MAX + size = (int) sysconf(_SC_OPEN_MAX); +#else + size = getdtablesize(); +#endif + +/* sysconf() can return a number larger than what will fit in an + fd_set. we can't use fd's larger than this, anyway. */ + +#ifdef FD_SETSIZE + if (size >= FD_SETSIZE) + size = FD_SETSIZE-1; +#endif + } + return (size); +} diff --git a/src/lib/rpc/rpc_msg.h b/src/lib/rpc/rpc_msg.h new file mode 100644 index 000000000..66b10c5fb --- /dev/null +++ b/src/lib/rpc/rpc_msg.h @@ -0,0 +1,187 @@ +/* @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)rpc_msg.h 1.7 86/07/16 SMI */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#define RPC_MSG_VERSION ((rpc_u_int32) 2) +#define RPC_SERVICE_PORT ((unsigned short) 2048) + +/* + * Bottom up definition of an rpc message. + * NOTE: call and reply use the same overall stuct but + * different parts of unions within it. + */ + +enum msg_type { + CALL=0, + REPLY=1 +}; + +enum reply_stat { + MSG_ACCEPTED=0, + MSG_DENIED=1 +}; + +enum accept_stat { + SUCCESS=0, + PROG_UNAVAIL=1, + PROG_MISMATCH=2, + PROC_UNAVAIL=3, + GARBAGE_ARGS=4, + SYSTEM_ERR=5 +}; + +enum reject_stat { + RPC_MISMATCH=0, + AUTH_ERROR=1 +}; + +/* + * Reply part of an rpc exchange + */ + +/* + * Reply to an rpc request that was accepted by the server. + * Note: there could be an error even though the request was + * accepted. + */ +struct accepted_reply { + struct opaque_auth ar_verf; + enum accept_stat ar_stat; + union { + struct { + rpc_u_int32 low; + rpc_u_int32 high; + } AR_versions; + struct { + caddr_t where; + xdrproc_t proc; + } AR_results; + /* and many other null cases */ + } ru; +#define ar_results ru.AR_results +#define ar_vers ru.AR_versions +}; + +/* + * Reply to an rpc request that was rejected by the server. + */ +struct rejected_reply { + enum reject_stat rj_stat; + union { + struct { + rpc_u_int32 low; + rpc_u_int32 high; + } RJ_versions; + enum auth_stat RJ_why; /* why authentication did not work */ + } ru; +#define rj_vers ru.RJ_versions +#define rj_why ru.RJ_why +}; + +/* + * Body of a reply to an rpc request. + */ +struct reply_body { + enum reply_stat rp_stat; + union { + struct accepted_reply RP_ar; + struct rejected_reply RP_dr; + } ru; +#define rp_acpt ru.RP_ar +#define rp_rjct ru.RP_dr +}; + +/* + * Body of an rpc request call. + */ +struct call_body { + rpc_u_int32 cb_rpcvers; /* must be equal to two */ + rpc_u_int32 cb_prog; + rpc_u_int32 cb_vers; + rpc_u_int32 cb_proc; + struct opaque_auth cb_cred; + struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { + rpc_u_int32 rm_xid; + enum msg_type rm_direction; + union { + struct call_body RM_cmb; + struct reply_body RM_rmb; + } ru; +#define rm_call ru.RM_cmb +#define rm_reply ru.RM_rmb +}; +#define acpted_rply ru.RM_rmb.ru.RP_ar +#define rjcted_rply ru.RM_rmb.ru.RP_dr + + +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callmsg(); + +/* + * XDR routine to pre-serialize the static part of a rpc message. + * xdr_callhdr(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callhdr(); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_replymsg(); + +/* + * Fills in the error part of a reply message. + * _seterr_reply(msg, error) + * struct rpc_msg *msg; + * struct rpc_err *error; + */ +extern void _seterr_reply(); diff --git a/src/lib/rpc/rpc_prot.c b/src/lib/rpc/rpc_prot.c new file mode 100644 index 000000000..6fea605e6 --- /dev/null +++ b/src/lib/rpc/rpc_prot.c @@ -0,0 +1,287 @@ +/* @(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * rpc_prot.c + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements the rpc message definition, + * its serializer and some common rpc utility routines. + * The routines are meant for various implementations of rpc - + * they are NOT for the rpc client or rpc service implementations! + * Because authentication stuff is easy and is part of rpc, the opaque + * routines are also in this program. + */ + +#include <sys/param.h> + +#include <rpc/rpc.h> + +/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */ + +/* + * XDR an opaque authentication struct + * (see auth.h) + */ +bool_t +xdr_opaque_auth(xdrs, ap) + register XDR *xdrs; + register struct opaque_auth *ap; +{ + + if (xdr_enum(xdrs, &(ap->oa_flavor))) + return (xdr_bytes(xdrs, &ap->oa_base, + &ap->oa_length, MAX_AUTH_BYTES)); + return (FALSE); +} + +/* + * XDR a DES block + */ +bool_t +xdr_des_block(xdrs, blkp) + register XDR *xdrs; + register des_block *blkp; +{ + return (xdr_opaque(xdrs, (caddr_t)blkp, sizeof(des_block))); +} + +/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */ + +/* + * XDR the MSG_ACCEPTED part of a reply message union + */ +bool_t +xdr_accepted_reply(xdrs, ar) + register XDR *xdrs; + register struct accepted_reply *ar; +{ + + /* personalized union, rather than calling xdr_union */ + if (! xdr_opaque_auth(xdrs, &(ar->ar_verf))) + return (FALSE); + if (! xdr_enum(xdrs, (enum_t *)&(ar->ar_stat))) + return (FALSE); + switch (ar->ar_stat) { + + case SUCCESS: + return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where)); + + case PROG_MISMATCH: + if (! xdr_u_int32(xdrs, &(ar->ar_vers.low))) + return (FALSE); + return (xdr_u_int32(xdrs, &(ar->ar_vers.high))); + } + return (TRUE); /* TRUE => open ended set of problems */ +} + +/* + * XDR the MSG_DENIED part of a reply message union + */ +bool_t +xdr_rejected_reply(xdrs, rr) + register XDR *xdrs; + register struct rejected_reply *rr; +{ + + /* personalized union, rather than calling xdr_union */ + if (! xdr_enum(xdrs, (enum_t *)&(rr->rj_stat))) + return (FALSE); + switch (rr->rj_stat) { + + case RPC_MISMATCH: + if (! xdr_u_int32(xdrs, &(rr->rj_vers.low))) + return (FALSE); + return (xdr_u_int32(xdrs, &(rr->rj_vers.high))); + + case AUTH_ERROR: + return (xdr_enum(xdrs, (enum_t *)&(rr->rj_why))); + } + return (FALSE); +} + +static struct xdr_discrim reply_dscrm[3] = { + { (int)MSG_ACCEPTED, xdr_accepted_reply }, + { (int)MSG_DENIED, xdr_rejected_reply }, + { __dontcare__, NULL_xdrproc_t } }; + +/* + * XDR a reply message + */ +bool_t +xdr_replymsg(xdrs, rmsg) + register XDR *xdrs; + register struct rpc_msg *rmsg; +{ + if ( + xdr_u_int32(xdrs, &(rmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(rmsg->rm_direction)) && + (rmsg->rm_direction == REPLY) ) + return (xdr_union(xdrs, (enum_t *)&(rmsg->rm_reply.rp_stat), + (caddr_t)&(rmsg->rm_reply.ru), reply_dscrm, NULL_xdrproc_t)); + return (FALSE); +} + + +/* + * Serializes the "static part" of a call message header. + * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers. + * The rm_xid is not really static, but the user can easily munge on the fly. + */ +bool_t +xdr_callhdr(xdrs, cmsg) + register XDR *xdrs; + register struct rpc_msg *cmsg; +{ + + cmsg->rm_direction = CALL; + cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION; + if ( + (xdrs->x_op == XDR_ENCODE) && + xdr_u_int32(xdrs, &(cmsg->rm_xid)) && + xdr_enum(xdrs, (enum_t *)&(cmsg->rm_direction)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_rpcvers)) && + xdr_u_int32(xdrs, &(cmsg->rm_call.cb_prog)) ) + return (xdr_u_int32(xdrs, &(cmsg->rm_call.cb_vers))); + return (FALSE); +} + +/* ************************** Client utility routine ************* */ + +static void +accepted(acpt_stat, error) + register enum accept_stat acpt_stat; + register struct rpc_err *error; +{ + + switch (acpt_stat) { + + case PROG_UNAVAIL: + error->re_status = RPC_PROGUNAVAIL; + return; + + case PROG_MISMATCH: + error->re_status = RPC_PROGVERSMISMATCH; + return; + + case PROC_UNAVAIL: + error->re_status = RPC_PROCUNAVAIL; + return; + + case GARBAGE_ARGS: + error->re_status = RPC_CANTDECODEARGS; + return; + + case SYSTEM_ERR: + error->re_status = RPC_SYSTEMERROR; + return; + + case SUCCESS: + error->re_status = RPC_SUCCESS; + return; + } + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)MSG_ACCEPTED; + error->re_lb.s2 = (rpc_int32)acpt_stat; +} + +static void +rejected(rjct_stat, error) + register enum reject_stat rjct_stat; + register struct rpc_err *error; +{ + + switch (rjct_stat) { + + case RPC_VERSMISMATCH: + error->re_status = RPC_VERSMISMATCH; + return; + + case AUTH_ERROR: + error->re_status = RPC_AUTHERROR; + return; + } + /* something's wrong, but we don't know what ... */ + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)MSG_DENIED; + error->re_lb.s2 = (rpc_int32)rjct_stat; +} + +/* + * given a reply message, fills in the error + */ +void +sunrpc_seterr_reply(msg, error) + register struct rpc_msg *msg; + register struct rpc_err *error; +{ + + /* optimized for normal, SUCCESSful case */ + switch (msg->rm_reply.rp_stat) { + + case MSG_ACCEPTED: + if (msg->acpted_rply.ar_stat == SUCCESS) { + error->re_status = RPC_SUCCESS; + return; + }; + accepted(msg->acpted_rply.ar_stat, error); + break; + + case MSG_DENIED: + rejected(msg->rjcted_rply.rj_stat, error); + break; + + default: + error->re_status = RPC_FAILED; + error->re_lb.s1 = (rpc_int32)(msg->rm_reply.rp_stat); + break; + } + switch (error->re_status) { + + case RPC_VERSMISMATCH: + error->re_vers.low = msg->rjcted_rply.rj_vers.low; + error->re_vers.high = msg->rjcted_rply.rj_vers.high; + break; + + case RPC_AUTHERROR: + error->re_why = msg->rjcted_rply.rj_why; + break; + + case RPC_PROGVERSMISMATCH: + error->re_vers.low = msg->acpted_rply.ar_vers.low; + error->re_vers.high = msg->acpted_rply.ar_vers.high; + break; + } +} diff --git a/src/lib/rpc/svc.c b/src/lib/rpc/svc.c new file mode 100644 index 000000000..cb4d877a7 --- /dev/null +++ b/src/lib/rpc/svc.c @@ -0,0 +1,492 @@ +/* @(#)svc.c 2.4 88/08/11 4.0 RPCSRC; from 1.44 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc.c 1.41 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * svc.c, Server-side remote procedure call interface. + * + * There are two sets of procedures here. The xprt routines are + * for handling transport handles. The svc routines handle the + * list of service routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <sys/errno.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <stdio.h> + +extern int errno; + +#ifdef FD_SETSIZE +static SVCXPRT **xports; +#else +#define NOFILE 32 + +static SVCXPRT *xports[NOFILE]; +#endif /* def FD_SETSIZE */ + +#define NULL_SVC ((struct svc_callout *)0) +#define RQCRED_SIZE 400 /* this size is excessive */ + +/* + * The services list + * Each entry represents a set of procedures (an rpc program). + * The dispatch routine takes request structs and runs the + * apropriate procedure. + */ +static struct svc_callout { + struct svc_callout *sc_next; + rpc_u_int32 sc_prog; + rpc_u_int32 sc_vers; + void (*sc_dispatch)(); +} *svc_head; + +static struct svc_callout *svc_find(); + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE + if (xports == NULL) { + xports = (SVCXPRT **) + mem_alloc(FD_SETSIZE * sizeof(SVCXPRT *)); + } + if (sock < _rpc_dtablesize()) { + xports[sock] = xprt; + FD_SET(sock, &svc_fdset); + } +#else + if (sock < NOFILE) { + xports[sock] = xprt; + svc_fds |= (1 << sock); + } +#endif /* def FD_SETSIZE */ + +} + +/* + * De-activate a transport handle. + */ +void +xprt_unregister(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + +#ifdef FD_SETSIZE + if ((sock < _rpc_dtablesize()) && (xports[sock] == xprt)) { + xports[sock] = (SVCXPRT *)0; + FD_CLR(sock, &svc_fdset); + } +#else + if ((sock < NOFILE) && (xports[sock] == xprt)) { + xports[sock] = (SVCXPRT *)0; + svc_fds &= ~(1 << sock); + } +#endif /* def FD_SETSIZE */ +} + + +/* ********************** CALLOUT list related stuff ************* */ + +/* + * Add a service program to the callout list. + * The dispatch routine will be called when a rpc request for this + * program number comes in. + */ +bool_t +svc_register(xprt, prog, vers, dispatch, protocol) + SVCXPRT *xprt; + rpc_u_int32 prog; + rpc_u_int32 vers; + void (*dispatch)(); + int protocol; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) != NULL_SVC) { + if (s->sc_dispatch == dispatch) + goto pmap_it; /* he is registering another xptr */ + return (FALSE); + } + s = (struct svc_callout *)mem_alloc(sizeof(struct svc_callout)); + if (s == (struct svc_callout *)0) { + return (FALSE); + } + s->sc_prog = prog; + s->sc_vers = vers; + s->sc_dispatch = dispatch; + s->sc_next = svc_head; + svc_head = s; +pmap_it: + /* now register the information with the local binder service */ + if (protocol) { + return (pmap_set(prog, vers, protocol, xprt->xp_port)); + } + return (TRUE); +} + +/* + * Remove a service program from the callout list. + */ +void +svc_unregister(prog, vers) + rpc_u_int32 prog; + rpc_u_int32 vers; +{ + struct svc_callout *prev; + register struct svc_callout *s; + + if ((s = svc_find(prog, vers, &prev)) == NULL_SVC) + return; + if (prev == NULL_SVC) { + svc_head = s->sc_next; + } else { + prev->sc_next = s->sc_next; + } + s->sc_next = NULL_SVC; + mem_free((char *) s, (unsigned int) sizeof(struct svc_callout)); + /* now unregister the information with the local binder service */ + (void)pmap_unset(prog, vers); +} + +/* + * Search the callout list for a program number, return the callout + * struct. + */ +static struct svc_callout * +svc_find(prog, vers, prev) + rpc_u_int32 prog; + rpc_u_int32 vers; + struct svc_callout **prev; +{ + register struct svc_callout *s, *p; + + p = NULL_SVC; + for (s = svc_head; s != NULL_SVC; s = s->sc_next) { + if ((s->sc_prog == prog) && (s->sc_vers == vers)) + goto done; + p = s; + } +done: + *prev = p; + return (s); +} + +/* ******************* REPLY GENERATION ROUTINES ************ */ + +/* + * Send a reply to an rpc request + */ +bool_t +svc_sendreply(xprt, xdr_results, xdr_location) + register SVCXPRT *xprt; + xdrproc_t xdr_results; + caddr_t xdr_location; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SUCCESS; + rply.acpted_rply.ar_results.where = xdr_location; + rply.acpted_rply.ar_results.proc = xdr_results; + return (SVC_REPLY(xprt, &rply)); +} + +/* + * No procedure error reply + */ +void +svcerr_noproc(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROC_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Can't decode args error reply + */ +void +svcerr_decode(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = GARBAGE_ARGS; + SVC_REPLY(xprt, &rply); +} + +/* + * Some system error + */ +void +svcerr_systemerr(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = SYSTEM_ERR; + SVC_REPLY(xprt, &rply); +} + +/* + * Authentication error reply + */ +void +svcerr_auth(xprt, why) + SVCXPRT *xprt; + enum auth_stat why; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_DENIED; + rply.rjcted_rply.rj_stat = AUTH_ERROR; + rply.rjcted_rply.rj_why = why; + SVC_REPLY(xprt, &rply); +} + +/* + * Auth too weak error reply + */ +void +svcerr_weakauth(xprt) + SVCXPRT *xprt; +{ + + svcerr_auth(xprt, AUTH_TOOWEAK); +} + +/* + * Program unavailable error reply + */ +void +svcerr_noprog(xprt) + register SVCXPRT *xprt; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_UNAVAIL; + SVC_REPLY(xprt, &rply); +} + +/* + * Program version mismatch error reply + */ +void +svcerr_progvers(xprt, low_vers, high_vers) + register SVCXPRT *xprt; + rpc_u_int32 low_vers; + rpc_u_int32 high_vers; +{ + struct rpc_msg rply; + + rply.rm_direction = REPLY; + rply.rm_reply.rp_stat = MSG_ACCEPTED; + rply.acpted_rply.ar_verf = xprt->xp_verf; + rply.acpted_rply.ar_stat = PROG_MISMATCH; + rply.acpted_rply.ar_vers.low = low_vers; + rply.acpted_rply.ar_vers.high = high_vers; + SVC_REPLY(xprt, &rply); +} + +/* ******************* SERVER INPUT STUFF ******************* */ + +/* + * Get server side input from some transport. + * + * Statement of authentication parameters management: + * This function owns and manages all authentication parameters, specifically + * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and + * the "cooked" credentials (rqst->rq_clntcred). + * However, this function does not know the structure of the cooked + * credentials, so it make the following assumptions: + * a) the structure is contiguous (no pointers), and + * b) the cred structure size does not exceed RQCRED_SIZE bytes. + * In all events, all three parameters are freed upon exit from this routine. + * The storage is trivially management on the call stack in user land, but + * is mallocated in kernel land. + */ + +void +svc_getreq(rdfds) + int rdfds; +{ +#ifdef FD_SETSIZE + fd_set readfds; + + FD_ZERO(&readfds); + readfds.fds_bits[0] = rdfds; + svc_getreqset(&readfds); +#else + int readfds = rdfds & svc_fds; + + svc_getreqset(&readfds); +#endif /* def FD_SETSIZE */ +} + +void +svc_getreqset(readfds) +#ifdef FD_SETSIZE + fd_set *readfds; +{ +#else + int *readfds; +{ + int readfds_local = *readfds; +#endif /* def FD_SETSIZE */ + enum xprt_stat stat; + struct rpc_msg msg; + int prog_found; + rpc_u_int32 low_vers; + rpc_u_int32 high_vers; + struct svc_req r; + register SVCXPRT *xprt; + rpc_u_int32 mask; + int bit; + rpc_u_int32 *maskp; + register int setsize; + register int sock; + bool_t no_dispatch; + + char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE]; + msg.rm_call.cb_cred.oa_base = cred_area; + msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]); + r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]); + +#ifdef FD_SETSIZE + setsize = _rpc_dtablesize(); + + maskp = (rpc_u_int32 *)readfds->fds_bits; + for (sock = 0; sock < setsize; sock += NFDBITS) { + for (mask = *maskp++; bit = ffs(mask); mask ^= (1 << (bit - 1))) { + /* sock has input waiting */ + xprt = xports[sock + bit - 1]; +#else + for (sock = 0; readfds_local != 0; sock++, readfds_local >>= 1) { + if ((readfds_local & 1) != 0) { + /* sock has input waiting */ + xprt = xports[sock]; +#endif /* def FD_SETSIZE */ + /* now receive msgs from xprtprt (support batch calls) */ + do { + if (SVC_RECV(xprt, &msg)) { + + /* now find the exported program and call it */ + register struct svc_callout *s; + enum auth_stat why; + + r.rq_xprt = xprt; + r.rq_prog = msg.rm_call.cb_prog; + r.rq_vers = msg.rm_call.cb_vers; + r.rq_proc = msg.rm_call.cb_proc; + r.rq_cred = msg.rm_call.cb_cred; + + /* in case _authenticate has been replaced + with an old-style version */ + r.rq_xprt->xp_auth = &svc_auth_any; + no_dispatch = FALSE; + + /* first authenticate the message */ + why=_authenticate(&r, &msg, &no_dispatch); + if (why != AUTH_OK) { + svcerr_auth(xprt, why); + goto call_done; + } else if (no_dispatch) { + goto call_done; + } + + /* now match message with a registered service*/ + prog_found = FALSE; + low_vers = 0 - 1; + high_vers = 0; + for (s = svc_head; s != NULL_SVC; s = s->sc_next) { + if (s->sc_prog == r.rq_prog) { + if (s->sc_vers == r.rq_vers) { + (*s->sc_dispatch)(&r, xprt); + goto call_done; + } /* found correct version */ + prog_found = TRUE; + if (s->sc_vers < low_vers) + low_vers = s->sc_vers; + if (s->sc_vers > high_vers) + high_vers = s->sc_vers; + } /* found correct program */ + } + /* + * if we got here, the program or version + * is not served ... + */ + if (prog_found) + svcerr_progvers(xprt, + low_vers, high_vers); + else + svcerr_noprog(xprt); + /* Fall through to ... */ + } + call_done: + if ((stat = SVC_STAT(xprt)) == XPRT_DIED){ + SVC_DESTROY(xprt); + break; + } + } while (stat == XPRT_MOREREQS); + } + } +} diff --git a/src/lib/rpc/svc.h b/src/lib/rpc/svc.h new file mode 100644 index 000000000..2114d6249 --- /dev/null +++ b/src/lib/rpc/svc.h @@ -0,0 +1,298 @@ +/* @(#)svc.h 2.2 88/07/29 4.0 RPCSRC; from 1.20 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __SVC_HEADER__ +#define __SVC_HEADER__ + +/* + * This interface must manage two items concerning remote procedure calling: + * + * 1) An arbitrary number of transport connections upon which rpc requests + * are received. The two most notable transports are TCP and UDP; they are + * created and registered by routines in svc_tcp.c and svc_udp.c, respectively; + * they in turn call xprt_register and xprt_unregister. + * + * 2) An arbitrary number of locally registered services. Services are + * described by the following four data: program number, version number, + * "service dispatch" function, a transport handle, and a boolean that + * indicates whether or not the exported program should be registered with a + * local binder service; if true the program's number and version and the + * port number from the transport handle are registered with the binder. + * These data are registered with the rpc svc system via svc_register. + * + * A service's dispatch function is called whenever an rpc request comes in + * on a transport. The request's program and version numbers must match + * those of the registered service. The dispatch function is passed two + * parameters, struct svc_req * and SVCXPRT *, defined below. + */ + +enum xprt_stat { + XPRT_DIED, + XPRT_MOREREQS, + XPRT_IDLE +}; + +/* + * Server side transport handle + */ +typedef struct { + int xp_sock; + unsigned short xp_port; /* associated port number */ + struct xp_ops { + bool_t (*xp_recv)(); /* receive incomming requests */ + enum xprt_stat (*xp_stat)(); /* get transport status */ + bool_t (*xp_getargs)(); /* get arguments */ + bool_t (*xp_reply)(); /* send reply */ + bool_t (*xp_freeargs)();/* free mem allocated for args */ + void (*xp_destroy)(); /* destroy this struct */ + } *xp_ops; + int xp_addrlen; /* length of remote address */ + struct sockaddr_in xp_raddr; /* remote address */ + struct opaque_auth xp_verf; /* raw response verifier */ + SVCAUTH *xp_auth; /* auth flavor of current req */ + caddr_t xp_p1; /* private */ + caddr_t xp_p2; /* private */ +} SVCXPRT; + +/* + * Approved way of getting address of caller + */ +#define svc_getcaller(x) (&(x)->xp_raddr) + +/* + * Operations defined on an SVCXPRT handle + * + * SVCXPRT *xprt; + * struct rpc_msg *msg; + * xdrproc_t xargs; + * caddr_t argsp; + */ +#define SVC_RECV(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) +#define svc_recv(xprt, msg) \ + (*(xprt)->xp_ops->xp_recv)((xprt), (msg)) + +#define SVC_STAT(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) +#define svc_stat(xprt) \ + (*(xprt)->xp_ops->xp_stat)(xprt) + +#define SVC_GETARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) +#define svc_getargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp)) + +#define SVC_GETARGS_REQ(xprt, req, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp)) +#define svc_getargs_req(xprt, req, xargs, argsp) \ + (*(xprt)->xp_ops->xp_getargs_req)((xprt), (req), (xargs), (argsp)) + +#define SVC_REPLY(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) + +#define SVC_REPLY_REQ(xprt, req, msg) \ + (*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg)) +#define svc_reply_req(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply_req) ((xprt), (req), (msg)) + +#define SVC_FREEARGS(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) +#define svc_freeargs(xprt, xargs, argsp) \ + (*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp)) + +#define SVC_DESTROY(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) +#define svc_destroy(xprt) \ + (*(xprt)->xp_ops->xp_destroy)(xprt) + + +/* + * Service request + */ +struct svc_req { + rpc_u_int32 rq_prog; /* service program number */ + rpc_u_int32 rq_vers; /* service protocol version */ + rpc_u_int32 rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked client cred */ + caddr_t rq_svccred; /* read only cooked svc cred */ + SVCXPRT *rq_xprt; /* associated transport */ + + /* The request's auth flavor *should* be here, but the svc_req */ + /* isn't passed around everywhere it is necessary. The */ + /* transport *is* passed around, so the auth flavor it stored */ + /* there. This means that the transport must be single */ + /* threaded, but other parts of SunRPC already require that. */ + /*SVCAUTH *rq_auth; associated auth flavor */ +}; + + +/* + * Service registration + * + * svc_register(xprt, prog, vers, dispatch, protocol) + * SVCXPRT *xprt; + * rpc_u_int32 prog; + * rpc_u_int32 vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +extern bool_t svc_register(); + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * rpc_u_int32 prog; + * rpc_u_int32 vers; + */ +extern void svc_unregister(); + +/* + * Transport registration. + * + * xprt_register(xprt) + * SVCXPRT *xprt; + */ +extern void xprt_register(); + +/* + * Transport un-register + * + * xprt_unregister(xprt) + * SVCXPRT *xprt; + */ +extern void xprt_unregister(); + + + + +/* + * When the service routine is called, it must first check to see if + * it knows about the procedure; if not, it should call svcerr_noproc + * and return. If so, it should deserialize its arguments via + * SVC_GETARGS or the new SVC_GETARGS_REQ (both defined above). If + * the deserialization does not work, svcerr_decode should be called + * followed by a return. Successful decoding of the arguments should + * be followed the execution of the procedure's code and a call to + * svc_sendreply or the new svc_sendreply_req. + * + * Also, if the service refuses to execute the procedure due to too- + * weak authentication parameters, svcerr_weakauth should be called. + * Note: do not confuse access-control failure with weak authentication! + * + * NB: In pure implementations of rpc, the caller always waits for a reply + * msg. This message is sent when svc_sendreply is called. + * Therefore pure service implementations should always call + * svc_sendreply even if the function logically returns void; use + * xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows + * for the abuse of pure rpc via batched calling or pipelining. In the + * case of a batched call, svc_sendreply should NOT be called since + * this would send a return message, which is what batching tries to avoid. + * It is the service/protocol writer's responsibility to know which calls are + * batched and which are not. Warning: responding to batch calls may + * deadlock the caller and server processes! + */ + +extern bool_t svc_sendreply(); +extern void svcerr_decode(); +extern void svcerr_weakauth(); +extern void svcerr_noproc(); +extern void svcerr_progvers(); +extern void svcerr_auth(); +extern void svcerr_noprog(); +extern void svcerr_systemerr(); + +/* + * Lowest level dispatching -OR- who owns this process anyway. + * Somebody has to wait for incoming requests and then call the correct + * service routine. The routine svc_run does infinite waiting; i.e., + * svc_run never returns. + * Since another (co-existant) package may wish to selectively wait for + * incoming calls or other events outside of the rpc architecture, the + * routine svc_getreq is provided. It must be passed readfds, the + * "in-place" results of a select system call (see select, section 2). + */ + +/* + * Global keeper of rpc service descriptors in use + * dynamic; must be inspected before each call to select + */ +#ifdef FD_SETSIZE +extern fd_set svc_fdset; +#define svc_fds svc_fdset.fds_bits[0] /* compatibility */ +#else +extern int svc_fds; +#endif /* def FD_SETSIZE */ + +/* + * a small program implemented by the svc_rpc implementation itself; + * also see clnt.h for protocol numbers. + */ +extern void rpctest_service(); + +extern void svc_getreq(); +extern void svc_getreqset(); /* takes fdset instead of int */ +extern void svc_run(); /* never returns */ + +/* + * Socket to use on svcxxx_create call to get default socket + */ +#define RPC_ANYSOCK -1 + +/* + * These are the existing service side transport implementations + */ + +/* + * Memory based rpc for testing and timing. + */ +extern SVCXPRT *svcraw_create(); + +/* + * Udp based rpc. + */ +extern SVCXPRT *svcudp_create(); +extern SVCXPRT *svcudp_bufcreate(); + +/* + * Tcp based rpc. + */ +extern SVCXPRT *svctcp_create(); + +#endif /* !__SVC_HEADER__ */ diff --git a/src/lib/rpc/svc_auth.c b/src/lib/rpc/svc_auth.c new file mode 100644 index 000000000..281d7cba4 --- /dev/null +++ b/src/lib/rpc/svc_auth.c @@ -0,0 +1,119 @@ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth.c 2.1 88/08/07 4.0 RPCSRC; from 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * svc_auth_nodes.c, Server-side rpc authenticator interface, + * *WITHOUT* DES authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + +/* + * Server side authenticators are called from authenticate by + * using the client auth struct flavor field to index into svcauthsw. + * The server auth flavors must implement a routine that looks + * like: + * + * enum auth_stat + * flavorx_auth(rqst, msg) + * register struct svc_req *rqst; + * register struct rpc_msg *msg; + * + */ + +enum auth_stat _svcauth_null(); /* no authentication */ +enum auth_stat _svcauth_unix(); /* unix style (uid, gids) */ +enum auth_stat _svcauth_short(); /* short hand unix style */ +enum auth_stat _svcauth_gssapi(); /* GSS-API style */ + +static struct svcauthsw_type { + unsigned int flavor; + enum auth_stat (*authenticator)(); +} svcauthsw[] = { + AUTH_GSSAPI, _svcauth_gssapi, /* AUTH_GSSAPI */ + AUTH_NONE, _svcauth_null, /* AUTH_NULL */ + AUTH_GSSAPI_COMPAT, _svcauth_gssapi, /* AUTH_GSSAPI_COMPAT */ + AUTH_UNIX, _svcauth_unix, /* AUTH_UNIX */ + AUTH_SHORT, _svcauth_short, /* AUTH_SHORT */ +}; +static int svcauthnum = sizeof(svcauthsw) / sizeof(struct svcauthsw_type); + +/* + * The call rpc message, msg has been obtained from the wire. The msg contains + * the raw form of credentials and verifiers. authenticate returns AUTH_OK + * if the msg is successfully authenticated. If AUTH_OK then the routine also + * does the following things: + * set rqst->rq_xprt->verf to the appropriate response verifier; + * sets rqst->rq_client_cred to the "cooked" form of the credentials. + * + * NB: rqst->rq_cxprt->verf must be pre-alloctaed; + * its length is set appropriately. + * + * The caller still owns and is responsible for msg->u.cmb.cred and + * msg->u.cmb.verf. The authentication system retains ownership of + * rqst->rq_client_cred, the cooked credentials. + */ +enum auth_stat +_authenticate(rqst, msg, no_dispatch) + register struct svc_req *rqst; + struct rpc_msg *msg; + bool_t *no_dispatch; +{ + register int cred_flavor, i; + + rqst->rq_cred = msg->rm_call.cb_cred; + rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; + rqst->rq_xprt->xp_verf.oa_length = 0; + cred_flavor = rqst->rq_cred.oa_flavor; + *no_dispatch = FALSE; + for (i = 0; i < svcauthnum; i++) { + if (cred_flavor == svcauthsw[i].flavor && + svcauthsw[i].authenticator != NULL) { + return ((*(svcauthsw[i].authenticator))(rqst, + msg, + no_dispatch)); + } + } + + return (AUTH_REJECTEDCRED); +} + +enum auth_stat +_svcauth_null(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + rqst->rq_xprt->xp_auth = &svc_auth_any; + return (AUTH_OK); +} diff --git a/src/lib/rpc/svc_auth.h b/src/lib/rpc/svc_auth.h new file mode 100644 index 000000000..4d5963144 --- /dev/null +++ b/src/lib/rpc/svc_auth.h @@ -0,0 +1,61 @@ +/* @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)svc_auth.h 1.6 86/07/16 SMI */ + +/* + * svc_auth.h, Service side of rpc authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +/* + * Interface to server-side authentication flavors. + */ +typedef struct { + struct svc_auth_ops { + int (*svc_ah_wrap)(); + int (*svc_ah_unwrap)(); + } *svc_ah_ops; + caddr_t svc_ah_private; +} SVCAUTH; + +extern SVCAUTH svc_auth_any; + +/* + * Server side authenticator + */ +extern enum auth_stat _authenticate(); + +#define SVCAUTH_WRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->svc_ah_ops->svc_ah_wrap))(auth, xdrs, xfunc, xwhere)) +#define SVCAUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \ + ((*((auth)->svc_ah_ops->svc_ah_unwrap))(auth, xdrs, xfunc, xwhere)) + + diff --git a/src/lib/rpc/svc_auth_any.c b/src/lib/rpc/svc_auth_any.c new file mode 100644 index 000000000..2f0a66dc8 --- /dev/null +++ b/src/lib/rpc/svc_auth_any.c @@ -0,0 +1,22 @@ +/* + * svc_auth_any.c + * Provides default service-side functions for authentication flavors + * that do not use all the fields in struct svc_auth_ops. + * + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + */ + +#include <stdio.h> +#include <rpc/rpc.h> + +extern int authany_wrap(); + +struct svc_auth_ops svc_auth_any_ops = { + authany_wrap, + authany_wrap, +}; + +SVCAUTH svc_auth_any = { + &svc_auth_any_ops, + NULL, +}; diff --git a/src/lib/rpc/svc_auth_gssapi.c b/src/lib/rpc/svc_auth_gssapi.c new file mode 100644 index 000000000..07cf59ab8 --- /dev/null +++ b/src/lib/rpc/svc_auth_gssapi.c @@ -0,0 +1,1181 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.37 1996/07/22 20:41:00 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.36.4.1 1996/07/18 04:19:34 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.36.2.1 1996/06/20 23:39:22 marc + * File added to the repository on a branch + * + * Revision 1.36 1996/05/30 19:25:02 bjaspan + * zero bindings structure before using it + * + * Revision 1.35 1996/05/12 06:17:25 marc + * changed around the file includes, since krb5 has changed some. + * + * added conditionalization GSS_BACKWARD_HACK until and if this hack is + * reimplemented in the newly merged gssapi. + * + * conditionalize out the host-specific cruft for setting the local + * address to INADDR_ANY, since you can just assign it that way on all + * platforms I know of. + * + * Revision 1.34 1996/02/12 15:14:00 grier + * [secure/3570] + * restore (struct sockaddr *) cast that got mangled + * + * Revision 1.33 1996/02/07 13:09:52 jik + * Actually, I should have used krb5_error_code, not krb5_int32. + * + * Revision 1.32 1996/02/07 13:08:31 jik + * Include <krb5/krb5.h> to get the krb5_int32 typedef, which we then use + * in a cast when checking if the GSS-API minor status value is equal to + * a krb5 error code. + * + * Revision 1.31 1996/02/01 18:29:29 grier + * Restore use of error code definition. + * Return original code structure. + * + * Revision 1.30 1996/01/31 19:15:49 grier + * [secure/3570] + * Remove (void *) casts to memcpy() args + * + * Revision 1.29 1996/01/25 03:58:04 grier + * Remove debug code + * + * Revision 1.28 1996/01/25 03:56:50 grier + * secure/3570 - missed Alpha checkin + * + * Revision 1.26 1995/11/07 23:17:23 grier + * memcpy() cast + * + * Revision 1.25 1995/08/24 21:05:48 bjaspan + * set acceptor channel bindings + * + * Revision 1.24 1995/08/23 20:28:02 bjaspan + * [secure-rpc/3392] add channel bindinds to the rpc + * + * Revision 1.23 1995/07/10 18:49:22 bjaspan + * [secure-build/3377] remove use of BSD db + * + * Revision 1.22 1995/05/25 18:35:53 bjaspan + * [secure-rpc/3103] log misc errors from RPC + * + * Revision 1.21 1995/05/24 17:34:03 bjaspan + * [secure-rpc/3302] don't allow client to make server exit unless + * debugging is enabled + * + * Revision 1.20 1995/05/08 22:32:44 marc + * if a new client is in use, set the krb5 gssapi mech into + * backward-compatibility mode. + * + * Revision 1.19 1994/10/27 12:38:51 jik + * [secure-rpc/2808: add credential versioning] + * + * Sandbox: + * + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.22 1994/10/26 20:03:27 bjaspan + * [secure-rpc/2808] add version field to client creds + * + * Revision 1.21 1994/05/23 01:26:01 bjaspan + * [secure-rpc/1911] set rq_svccred to the context instead of the service + * gss name + * + * Revision 1.20 1994/05/09 17:48:39 shanzer + * change sys/fcntl.h to fcntl.h + * + * Revision 1.19 1994/04/08 17:21:32 bjaspan + * remove KRB5KTNAME hack + * + * Revision 1.18 1994/03/18 15:48:13 shanzer + * include sys/fcntl.h + * + * Revision 1.17 1994/03/08 00:05:56 shanzer + * call rand() instead random() + * + * Revision 1.16 1993/12/08 21:43:54 bjaspan + * gss_delete_sec_context failure is not fatal (in fact, the context + * will often be expired); use AUTH_GSSAPI_DISPLAY_STATUS macro + * + * Revision 1.15 1993/12/08 20:20:08 bjaspan + * add debugging info to expire_client, correct comment above btree->put + * + * Revision 1.14 1993/12/08 06:52:49 bjaspan + * *many* debugging improvements to help find secure-rpc/586, and (I hope) + * the fix: don't change client_data->expiration without deleting it + * and reinserting it into the btree + * + * Revision 1.13 1993/12/06 21:22:26 bjaspan + * debugging levels, #ifdef PURIFY, call abort() on impossible failures + * + * Revision 1.12 1993/11/12 02:33:14 bjaspan + * add badauth + * / + * + * Revision 1.11 1993/11/03 23:46:15 bjaspan + * new log_badverf format + * + * Revision 1.10 1993/11/03 21:23:30 bjaspan + * handle GSS_C_INDEFINITE expiration, add log_badverf, set rq_svccred + * + * Revision 1.9 1993/11/03 01:30:36 bjaspan + * don't include gssapi_krb5.h, it isn't needed + * + * Revision 1.8 1993/11/02 22:09:02 bjaspan + * support multiple service-side names via _svcauth_gssapi_set_names + * + * Revision 1.7 1993/11/01 19:56:22 bjaspan + * unstatic svc_debug_gssapi, and send gss_{major,minor} back if + * accept_sec_context fails + * + * Revision 1.6 1993/10/28 22:09:58 bjaspan + * fix verifier mem leak, clean_clients() first to avoid dangling ref, + * only include hacked kt_default_name if DEBUG_GSSAPI defined + * + * Revision 1.5 1993/10/27 18:26:51 bjaspan + * use xdr_free instead of gss_release_buffer; this fixes memory leaks + * that were probably caused by zero-length seal/unseal tokens + * + * Revision 1.4 1993/10/26 21:12:51 bjaspan + * fully working + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +/* + * svc_auth_gssapi.c + * Handles the GSS-API flavor authentication parameters on the service + * side of RPC. + */ + +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <rpc/rpc.h> + +#include <gssapi/gssapi_generic.h> +#include <rpc/auth_gssapi.h> + +#ifdef GSS_BACKWARD_HACK +#include <gssapi/gssapi_krb5.h> +#endif + +/* This is here for the krb5_error_code typedef and the + KRB5KRB_AP_WRONG_PRINC #define.*/ +#include <krb5.h> + +#include <sys/file.h> +#include <fcntl.h> + +#define INITIATION_TIMEOUT 60*15 /* seconds until partially created */ + /* context is destroed */ +#define INDEF_EXPIRE 60*60*24 /* seconds until an context with no */ + /* expiration time is expired */ + +#ifdef __CODECENTER__ +#define DEBUG_GSSAPI 1 +#endif + +#ifdef DEBUG_GSSAPI +int svc_debug_gssapi = DEBUG_GSSAPI; +#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) printf args +#define PRINTF(args) L_PRINTF(99, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) \ + if (svc_debug_gssapi) auth_gssapi_display_status args +#else +#define PRINTF(args) +#define L_PRINTF(l, args) +#define AUTH_GSSAPI_DISPLAY_STATUS(args) +#endif + +typedef struct _svc_auth_gssapi_data { + bool_t established; + + gss_ctx_id_t context; + gss_name_t client_name, server_name; + gss_cred_id_t server_creds; + + rpc_u_int32 expiration; + rpc_u_int32 seq_num; + rpc_u_int32 key; + + SVCAUTH svcauth; + + /* kludge to free verifiers on next call */ + gss_buffer_desc prev_verf; +} svc_auth_gssapi_data; + +#define SVCAUTH_PRIVATE(auth) \ + ((svc_auth_gssapi_data *)(auth)->svc_ah_private) + +static bool_t svc_auth_gssapi_wrap(); +static bool_t svc_auth_gssapi_unwrap(); +static svc_auth_gssapi_data *create_client(); +static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle); +static void destroy_client(svc_auth_gssapi_data *client_data); +static void clean_client(), cleanup(); +static void client_expire(svc_auth_gssapi_data *client_data, rpc_u_int32 exp); +static void dump_db(char *msg); + +struct svc_auth_ops svc_auth_gssapi_ops = { + svc_auth_gssapi_wrap, + svc_auth_gssapi_unwrap, +}; + +/* + * Globals! Eeek! Run for the hills! + */ +static gss_cred_id_t *server_creds_list = NULL; +static gss_name_t *server_name_list = NULL; +static int server_creds_count = 0; + +static auth_gssapi_log_badauth_func log_badauth = NULL; +static caddr_t log_badauth_data = NULL; +static auth_gssapi_log_badverf_func log_badverf = NULL; +static caddr_t log_badverf_data = NULL; +static auth_gssapi_log_miscerr_func log_miscerr = NULL; +static caddr_t log_miscerr_data = NULL; + +#define LOG_MISCERR(arg) if (log_miscerr) \ + (*log_miscerr)(rqst, msg, arg, log_miscerr_data) + +typedef struct _client_list { + svc_auth_gssapi_data *client; + struct _client_list *next; +} client_list; + +static client_list *clients = NULL; + +extern int errno; + +enum auth_stat _svcauth_gssapi(rqst, msg, no_dispatch) + register struct svc_req *rqst; + register struct rpc_msg *msg; + bool_t *no_dispatch; +{ + XDR xdrs; + auth_gssapi_creds creds; + auth_gssapi_init_arg call_arg; + auth_gssapi_init_res call_res; + gss_buffer_desc output_token, in_buf, out_buf; + gss_cred_id_t server_creds; + struct gss_channel_bindings_struct bindings, *bindp; + struct sockaddr_in sockname; + OM_uint32 gssstat, minor_stat, time_rec; + struct opaque_auth *cred, *verf; + svc_auth_gssapi_data *client_data; + int ret_flags, ret, i; + rpc_u_int32 seq_num; + int flag; + + PRINTF(("svcauth_gssapi: starting\n")); + + /* clean up expired entries */ + clean_client(); + + /* use AUTH_NONE until there is a client_handle */ + rqst->rq_xprt->xp_auth = &svc_auth_any; + + memset((char *) &call_res, 0, sizeof(call_res)); + + cred = &msg->rm_call.cb_cred; + verf = &msg->rm_call.cb_verf; + + if (cred->oa_length == 0) { + PRINTF(("svcauth_gssapi: empty creds, failing\n")); + LOG_MISCERR("empty client credentials"); + ret = AUTH_BADCRED; + goto error; + } + + PRINTF(("svcauth_gssapi: decoding credentials\n")); + xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE); + memset((char *) &creds, 0, sizeof(creds)); + if (! xdr_authgssapi_creds(&xdrs, &creds)) { + PRINTF(("svcauth_gssapi: failed decoding creds\n")); + LOG_MISCERR("protocol error in client credentials"); + XDR_DESTROY(&xdrs); + ret = AUTH_BADCRED; + goto error; + } + XDR_DESTROY(&xdrs); + + PRINTF(("svcauth_gssapi: got credentials, version %d, " + "client_handle len %d\n", creds.version, + creds.client_handle.length)); + + if (creds.version != 2) { + PRINTF(("svcauth_gssapi: bad credential version\n")); + LOG_MISCERR("unsupported client credentials version"); + ret = AUTH_BADCRED; + goto error; + } + +#ifdef DEBUG_GSSAPI + if (svc_debug_gssapi) { + if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) { + PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n")); + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + xdr_free(xdr_authgssapi_creds, &creds); + cleanup(); + exit(0); + } + } +#endif + + /* + * If this is an auth_msg and proc is GSSAPI_INIT, then create a + * client handle for this client. Otherwise, look up the + * existing handle. + */ + if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) { + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n")); + LOG_MISCERR("protocol error in client handle"); + ret = AUTH_FAILED; + goto error; + } + + PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n")); + + client_data = create_client(); + if (client_data == NULL) { + PRINTF(("svcauth_gssapi: create_client failed\n")); + LOG_MISCERR("internal error creating client record"); + ret = AUTH_FAILED; + goto error; + } + } else { + if (creds.client_handle.length == 0) { + PRINTF(("svcauth_gssapi: expected non-empty creds\n")); + LOG_MISCERR("protocol error in client credentials"); + ret = AUTH_FAILED; + goto error; + } + + PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n", + *((rpc_u_int32 *) creds.client_handle.value), + creds.client_handle.length)); + + client_data = get_client(&creds.client_handle); + if (client_data == NULL) { + PRINTF(("svcauth_gssapi: client_handle lookup failed\n")); + LOG_MISCERR("invalid client handle received"); + ret = AUTH_BADCRED; + goto error; + } + PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n")); + } + + /* any response we send will use client_handle, so set it now */ + call_res.client_handle.length = sizeof(client_data->key); + call_res.client_handle.value = (char *) &client_data->key; + + /* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */ + rqst->rq_xprt->xp_auth = &client_data->svcauth; + + if (client_data->established == FALSE) { + PRINTF(("svcauth_gssapi: context is not established\n")); + + if (creds.auth_msg == FALSE) { + PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n")); + LOG_MISCERR("protocol error on incomplete connection"); + ret = AUTH_REJECTEDCRED; + goto error; + } + + /* + * If the context is not established, then only GSSAPI_INIT + * and _CONTINUE requests are valid. + */ + if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc != + AUTH_GSSAPI_CONTINUE_INIT) { + PRINTF(("svcauth_gssapi: unacceptable procedure %d\n", + rqst->rq_proc)); + LOG_MISCERR("protocol error on incomplete connection"); + ret = AUTH_FAILED; + goto error; + } + + /* call is for us, deserialize arguments */ + memset(&call_arg, 0, sizeof(call_arg)); + if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg, + &call_arg)) { + PRINTF(("svcauth_gssapi: cannot decode args\n")); + LOG_MISCERR("protocol error in procedure arguments"); + ret = AUTH_BADCRED; + goto error; + } + + /* + * Process the call arg version number. + * + * Set the krb5_gss backwards-compatibility mode based on client + * version. This controls whether the AP_REP message is + * encrypted with the session key (version 2+, correct) or the + * session subkey (version 1, incorrect). This function can + * never fail, so we don't bother checking its return value. + */ + switch (call_arg.version) { + case 1: + case 2: + LOG_MISCERR("Warning: Accepted old RPC protocol request"); + call_res.version = 1; + break; + case 3: + call_res.version = call_arg.version; + break; + default: + PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n")); + LOG_MISCERR("unsupported GSSAPI_INIT version"); + ret = AUTH_BADCRED; + goto error; + } + +#ifdef GSS_BACKWARD_HACK + krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1); +#endif + + if (call_arg.version == 3) { + int len; + + memset(&bindings, 0, sizeof(bindings)); + bindings.application_data.length = 0; + bindings.initiator_addrtype = GSS_C_AF_INET; + bindings.initiator_address.length = 4; + bindings.initiator_address.value = + &svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr; + + len = sizeof(sockname); + if (getsockname(rqst->rq_xprt->xp_sock, + (struct sockaddr *) &sockname, &len) < 0) { + LOG_MISCERR("cannot get local address"); + PRINTF(("svcauth_gssapi: errno %d while getting address", + errno)); + ret = AUTH_FAILED; + goto error; + } + + bindings.acceptor_addrtype = GSS_C_AF_INET; + bindings.acceptor_address.length = 4; + bindings.acceptor_address.value = &sockname.sin_addr.s_addr; + + bindp = &bindings; + } else { + bindp = GSS_C_NO_CHANNEL_BINDINGS; + } + + /* + * If the client's server_creds is already set, use it. + * Otherwise, try each credential in server_creds_list until + * one of them succeedes, then set the client server_creds + * to that. If all fail, the client's server_creds isn't + * set (which is fine, because the client will be gc'ed + * anyway). + * + * If accept_sec_context returns something other than + * success and GSS_S_FAILURE, then assume different + * credentials won't help and stop looping. + * + * Note that there are really two cases here: (1) the client + * has a server_creds already, and (2) it does not. They + * are both written in the same loop so that there is only + * one textual call to gss_accept_sec_context; in fact, in + * case (1), the loop is executed exactly once. + */ + for (i = 0; i < server_creds_count; i++) { + if (client_data->server_creds != NULL) { + PRINTF(("svcauth_gssapi: using's clients server_creds\n")); + server_creds = client_data->server_creds; + } else { + PRINTF(("svcauth_gssapi: trying creds %d\n", i)); + server_creds = server_creds_list[i]; + } + + call_res.gss_major = + gss_accept_sec_context(&call_res.gss_minor, + &client_data->context, + server_creds, + &call_arg.token, + bindp, + &client_data->client_name, + NULL, + &output_token, + &ret_flags, + &time_rec, + NULL); + + if (server_creds == client_data->server_creds) + break; + + if (call_res.gss_major == GSS_S_COMPLETE || + call_res.gss_major == GSS_S_CONTINUE_NEEDED) { + /* server_creds was right, set it! */ + PRINTF(("svcauth_gssapi: creds are correct, storing\n")); + client_data->server_creds = server_creds; + client_data->server_name = server_name_list[i]; + break; + } else if (call_res.gss_major != GSS_S_FAILURE || + /* + * XXX hard-coded because there is no other + * way to prevent all GSS_S_FAILURES from + * returning a "wrong principal in request" + * error + */ + ((krb5_error_code) call_res.gss_minor != + (krb5_error_code) KRB5KRB_AP_WRONG_PRINC)) { + break; + } + } + + gssstat = call_res.gss_major; + minor_stat = call_res.gss_minor; + + /* done with call args */ + xdr_free(xdr_authgssapi_init_arg, &call_arg); + + PRINTF(("svcauth_gssapi: accept_sec_context returned %#x\n", + call_res.gss_major)); + if (call_res.gss_major != GSS_S_COMPLETE && + call_res.gss_major != GSS_S_CONTINUE_NEEDED) { + AUTH_GSSAPI_DISPLAY_STATUS(("accepting context", + call_res.gss_major, + call_res.gss_minor)); + + if (log_badauth != NULL) + (*log_badauth)(call_res.gss_major, + call_res.gss_minor, + &rqst->rq_xprt->xp_raddr, + log_badauth_data); + + svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res, + (caddr_t) &call_res); + *no_dispatch = TRUE; + ret = AUTH_OK; + goto error; + } + + if (output_token.length != 0) { + PRINTF(("svcauth_gssapi: got new output token\n")); + GSS_COPY_BUFFER(call_res.token, output_token); + } + + if (gssstat == GSS_S_COMPLETE) { + client_data->seq_num = rand(); + client_expire(client_data, + (time_rec == GSS_C_INDEFINITE ? + INDEF_EXPIRE : time_rec) + time(0)); + + PRINTF(("svcauth_gssapi: context established, isn %d\n", + client_data->seq_num)); + + if (auth_gssapi_seal_seq(client_data->context, + client_data->seq_num, + &call_res.signed_isn) == + FALSE) { + ret = AUTH_FAILED; + LOG_MISCERR("internal error sealing sequence number"); + goto error; + } + } + + PRINTF(("svcauth_gssapi: sending reply\n")); + svc_sendreply(rqst->rq_xprt, xdr_authgssapi_init_res, + (caddr_t) &call_res); + *no_dispatch = TRUE; + + /* + * If appropriate, set established to TRUE *after* sending + * response (otherwise, the client will receive the final + * token encrypted) + */ + if (gssstat == GSS_S_COMPLETE) { + gss_release_buffer(&minor_stat, &call_res.signed_isn); + client_data->established = TRUE; + } + gss_release_buffer(&minor_stat, &output_token); + } else { + PRINTF(("svcauth_gssapi: context is established\n")); + + /* check the verifier */ + PRINTF(("svcauth_gssapi: checking verifier, len %d\n", + verf->oa_length)); + + in_buf.length = verf->oa_length; + in_buf.value = verf->oa_base; + + if (auth_gssapi_unseal_seq(client_data->context, &in_buf, + &seq_num) == FALSE) { + ret = AUTH_BADVERF; + LOG_MISCERR("internal error unsealing sequence number"); + goto error; + } + + if (seq_num != client_data->seq_num + 1) { + PRINTF(("svcauth_gssapi: expected isn %d, got %d\n", + client_data->seq_num + 1, seq_num)); + if (log_badverf != NULL) + (*log_badverf)(client_data->client_name, + client_data->server_name, + rqst, msg, log_badverf_data); + + ret = AUTH_REJECTEDVERF; + goto error; + } + client_data->seq_num++; + + PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num)); + + /* free previous response verifier, if any */ + if (client_data->prev_verf.length != 0) { + gss_release_buffer(&minor_stat, &client_data->prev_verf); + client_data->prev_verf.length = 0; + } + + /* prepare response verifier */ + seq_num = client_data->seq_num + 1; + if (auth_gssapi_seal_seq(client_data->context, seq_num, + &out_buf) == FALSE) { + ret = AUTH_FAILED; + LOG_MISCERR("internal error sealing sequence number"); + goto error; + } + + client_data->seq_num++; + + PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num)); + + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI; + rqst->rq_xprt->xp_verf.oa_base = out_buf.value; + rqst->rq_xprt->xp_verf.oa_length = out_buf.length; + + /* save verifier so it can be freed next time */ + client_data->prev_verf.value = out_buf.value; + client_data->prev_verf.length = out_buf.length; + + /* + * Message is authentic. If auth_msg if true, process the + * call; otherwise, return AUTH_OK so it will be dispatched + * to the application server. + */ + + if (creds.auth_msg == TRUE) { + /* + * If process_token fails, then the token probably came + * from an attacker. No response (error or otherwise) + * should be returned to the client, since it won't be + * accepting one. + */ + + switch (rqst->rq_proc) { + case AUTH_GSSAPI_MSG: + PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n")); + memset(&call_arg, 0, sizeof(call_arg)); + if (! svc_getargs(rqst->rq_xprt, xdr_authgssapi_init_arg, + &call_arg)) { + PRINTF(("svcauth_gssapi: cannot decode args\n")); + LOG_MISCERR("protocol error in call arguments"); + ret = AUTH_BADCRED; + goto error; + } + + PRINTF(("svcauth_gssapi: processing token\n")); + gssstat = gss_process_context_token(&minor_stat, + client_data->context, + &call_arg.token); + + /* done with call args */ + xdr_free(xdr_authgssapi_init_arg, &call_arg); + + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("processing token", + gssstat, minor_stat)); + ret = AUTH_FAILED; + goto error; + } + + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + *no_dispatch = TRUE; + break; + + case AUTH_GSSAPI_DESTROY: + PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n")); + + PRINTF(("svcauth_gssapi: sending reply\n")); + svc_sendreply(rqst->rq_xprt, xdr_void, NULL); + *no_dispatch = TRUE; + + destroy_client(client_data); + break; + + default: + PRINTF(("svcauth_gssapi: unacceptable procedure %d\n", + rqst->rq_proc)); + LOG_MISCERR("invalid call procedure number"); + ret = AUTH_FAILED; + goto error; + } + } else { + /* set credentials for app server; comment in svc.c */ + /* seems to imply this is incorrect, but I don't see */ + /* any problem with it... */ + rqst->rq_clntcred = (char *)client_data->client_name; + rqst->rq_svccred = (char *)client_data->context; + } + } + + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: freeing client_handle len %d\n", + creds.client_handle.length)); + xdr_free(xdr_authgssapi_creds, &creds); + } + + PRINTF(("\n")); + return AUTH_OK; + +error: + if (creds.client_handle.length != 0) { + PRINTF(("svcauth_gssapi: freeing client_handle len %d\n", + creds.client_handle.length)); + xdr_free(xdr_authgssapi_creds, &creds); + } + + PRINTF(("\n")); + return ret; +} + +static void cleanup() +{ + client_list *c, *c2; + + PRINTF(("cleanup_and_exit: starting\n")); + + c = clients; + while (c) { + c2 = c; + c = c->next; + destroy_client(c2->client); + free(c2); + } + + exit(0); +} + +/* + * Function: create_client + * + * Purpose: Creates an new client_data structure and stores it in the + * database. + * + * Returns: the new client_data structure, or NULL on failure. + * + * Effects: + * + * A new client_data is created and stored in the hash table and + * b-tree. A new key that is unique in the current database is + * chosen; this key should be used as the client's client_handle. + */ +static svc_auth_gssapi_data *create_client() +{ + client_list *c; + svc_auth_gssapi_data *client_data; + static int client_key = 1; + int ret; + + PRINTF(("svcauth_gssapi: empty creds, creating\n")); + + client_data = (svc_auth_gssapi_data *) malloc(sizeof(*client_data)); + if (client_data == NULL) + return NULL; + memset((char *) client_data, 0, sizeof(*client_data)); + L_PRINTF(2, ("create_client: new client_data = %#x\n", client_data)); + + /* set up client data structure */ + client_data->established = 0; + client_data->context = GSS_C_NO_CONTEXT; + client_data->expiration = time(0) + INITIATION_TIMEOUT; + + /* set up psycho-recursive SVCAUTH hack */ + client_data->svcauth.svc_ah_ops = &svc_auth_gssapi_ops; + client_data->svcauth.svc_ah_private = (caddr_t) client_data; + + client_data->key = client_key++; + + c = (client_list *) malloc(sizeof(client_list)); + if (c == NULL) + return NULL; + c->client = client_data; + c->next = NULL; + + + if (clients == NULL) + clients = c; + else { + c->next = clients; + clients = c; + } + + PRINTF(("svcauth_gssapi: new handle %d\n", client_data->key)); + L_PRINTF(2, ("create_client: done\n")); + + return client_data; +} + +/* + * Function: client_expire + * + * Purpose: change the expiration time of a client in the database + * + * Arguments: + * + * client_data (r) the client_data to expire + * exp (r) the new expiration time + * + * Effects: + * + * client_data->expiration = exp + * + * This function used to remove client_data from the database, change + * its expiration time, and re-add it, which was necessary because the + * database was sorted by expiration time so a simple modification + * would break the rep invariant. Now the database is an unsorted + * linked list, so it doesn't matter. + */ +static void client_expire(svc_auth_gssapi_data *client_data, rpc_u_int32 exp) +{ + client_data->expiration = exp; +} + +/* + * Function get_client + * + * Purpose: retrieve a client_data structure from the database based + * on its client handle (key) + * + * Arguments: + * + * client_handle (r) the handle (key) to retrieve + * + * Effects: + * + * Searches the list and returns the client_data whose key field + * matches the contents of client_handle, or returns NULL if none was + * found. + */ +static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle) +{ + client_list *c; + rpc_u_int32 handle; + + memcpy(&handle, client_handle->value, 4); + + L_PRINTF(2, ("get_client: looking for client %d\n", handle)); + + c = clients; + while (c) { + if (c->client->key == handle) + return c->client; + c = c->next; + } + + L_PRINTF(2, ("get_client: client_handle lookup failed\n")); + return NULL; +} + +/* + * Function: destroy_client + * + * Purpose: destroys a client entry and removes it from the database + * + * Arguments: + * + * client_data (r) the client to be destroyed + * + * Effects: + * + * client_data->context is deleted with gss_delete_sec_context. + * client_data's entry in the database is destroyed. client_data is + * freed. + */ +static void destroy_client(svc_auth_gssapi_data *client_data) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc out_buf; + client_list *c, *c2; + int ret; + + PRINTF(("destroy_client: destroying client_data\n")); + L_PRINTF(2, ("destroy_client: client_data = %#x\n", client_data)); + +#ifdef DEBUG_GSSAPI + if (svc_debug_gssapi >= 3) + dump_db("before frees"); +#endif + + /* destroy client struct even if error occurs */ + + gssstat = gss_delete_sec_context(&minor_stat, &client_data->context, + &out_buf); + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat, + minor_stat)); + + gss_release_buffer(&minor_stat, &out_buf); + gss_release_name(&minor_stat, &client_data->client_name); + if (client_data->prev_verf.length != 0) + gss_release_buffer(&minor_stat, &client_data->prev_verf); + + if (clients == NULL) { + PRINTF(("destroy_client: called on empty database\n")); + abort(); + } else if (clients->client == client_data) { + c = clients; + clients = clients->next; + free(c); + } else { + c2 = clients; + c = clients->next; + while (c) { + if (c->client == client_data) { + c2->next = c->next; + free(c); + goto done; + } else + c = c->next; + } + PRINTF(("destroy_client: client_handle delete failed\n")); + abort(); + } + +done: + + L_PRINTF(2, ("destroy_client: client %d destroyed\n", client_data->key)); + + free(client_data); + +#ifdef PURIFY + purify_watch_n(client_data, sizeof(*client_data), "rw"); +#endif +} + +static void dump_db(char *msg) +{ + svc_auth_gssapi_data *client_data; + client_list *c; + + L_PRINTF(3, ("dump_db: %s:\n", msg)); + + c = clients; + while (c) { + client_data = c->client; + L_PRINTF(3, ("\tclient_data = %#x, exp = %d\n", + client_data, client_data->expiration)); + c = c->next; + } + + L_PRINTF(3, ("\n")); +} + +static void clean_client() +{ + svc_auth_gssapi_data *client_data; + client_list *c; + + PRINTF(("clean_client: starting\n")); + + c = clients; + while (c) { + client_data = c->client; + + L_PRINTF(2, ("clean_client: client_data = %#x\n", + client_data)); + + if (client_data->expiration < time(0)) { + PRINTF(("clean_client: client %d expired\n", + client_data->key)); + destroy_client(client_data); + c = clients; /* start over, just to be safe */ + } else { + c = c->next; + } + } + +done: + PRINTF(("clean_client: done\n")); +} + +/* + * Function: _svcauth_gssapi_set_name + * + * Purpose: Sets the list of service names for which incoming + * authentication requests should be honored. + * + * See functional specifications. + */ +bool_t _svcauth_gssapi_set_names(auth_gssapi_name *names, int num) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc in_buf; + int i; + + if (num == 0) + for (; names[num].name != NULL; num++) + ; + + server_creds_list = NULL; + server_name_list = NULL; + + server_creds_list = (gss_cred_id_t *) malloc(num*sizeof(gss_cred_id_t)); + if (server_creds_list == NULL) + goto fail; + server_name_list = (gss_name_t *) malloc(num*sizeof(gss_name_t)); + if (server_name_list == NULL) + goto fail; + + for (i = 0; i < num; i++) { + in_buf.value = names[i].name; + in_buf.length = strlen(in_buf.value) + 1; + + gssstat = gss_import_name(&minor_stat, &in_buf, names[i].type, + &server_name_list[i]); + + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("importing name", gssstat, + minor_stat)); + goto fail; + } + + gssstat = gss_acquire_cred(&minor_stat, server_name_list[i], 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &server_creds_list[i], NULL, NULL); + if (gssstat != GSS_S_COMPLETE) { + AUTH_GSSAPI_DISPLAY_STATUS(("acquiring credentials", + gssstat, minor_stat)); + goto fail; + } + } + + server_creds_count = num; + + return TRUE; + +fail: + /* memory leak: not releasing names/creds already acquired */ + if (server_creds_list) + free(server_creds_list); + if (server_name_list) + free(server_name_list); + return FALSE; +} + +/* + * Function: _svcauth_gssapi_set_log_badauth_func + * + * Purpose: sets the logging function called when an invalid RPC call + * arrives + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_badauth_func + (auth_gssapi_log_badauth_func func, caddr_t data) +{ + log_badauth = func; + log_badauth_data = data; +} + +/* + * Function: _svcauth_gssapi_set_log_badverf_func + * + * Purpose: sets the logging function called when an invalid RPC call + * arrives + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_badverf_func + (auth_gssapi_log_badverf_func func, caddr_t data) +{ + log_badverf = func; + log_badverf_data = data; +} + +/* + * Function: _svcauth_gssapi_set_log_miscerr_func + * + * Purpose: sets the logging function called when a miscellaneous + * AUTH_GSSAPI error occurs + * + * See functional specifications. + */ +void _svcauth_gssapi_set_log_miscerr_func + (auth_gssapi_log_miscerr_func func, caddr_t data) +{ + log_miscerr = func; + log_miscerr_data = data; +} + +/* + * Encrypt the serialized arguments from xdr_func applied to xdr_ptr + * and write the result to xdrs. + */ +static bool_t svc_auth_gssapi_wrap(auth, out_xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *out_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + OM_uint32 gssstat, minor_stat; + + if (! SVCAUTH_PRIVATE(auth)->established) { + PRINTF(("svc_gssapi_wrap: not established, noop\n")); + return (*xdr_func)(out_xdrs, xdr_ptr); + } else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat, + SVCAUTH_PRIVATE(auth)->context, + SVCAUTH_PRIVATE(auth)->seq_num, + out_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} + +static bool_t svc_auth_gssapi_unwrap(auth, in_xdrs, xdr_func, xdr_ptr) + SVCAUTH *auth; + XDR *in_xdrs; + bool_t (*xdr_func)(); + caddr_t xdr_ptr; +{ + svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth); + OM_uint32 gssstat, minor_stat; + + if (! client_data->established) { + PRINTF(("svc_gssapi_unwrap: not established, noop\n")); + return (*xdr_func)(in_xdrs, (auth_gssapi_init_arg *) xdr_ptr); + } else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat, + client_data->context, + client_data->seq_num-1, + in_xdrs, xdr_func, xdr_ptr)) { + if (gssstat != GSS_S_COMPLETE) + AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments", + gssstat, minor_stat)); + return FALSE; + } else + return TRUE; +} diff --git a/src/lib/rpc/svc_auth_unix.c b/src/lib/rpc/svc_auth_unix.c new file mode 100644 index 000000000..1ff21588c --- /dev/null +++ b/src/lib/rpc/svc_auth_unix.c @@ -0,0 +1,137 @@ +/* @(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC; from 1.28 88/02/08 SMI */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_auth_unix.c + * Handles UNIX flavor authentication parameters on the service side of rpc. + * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT. + * _svcauth_unix does full blown unix style uid,gid+gids auth, + * _svcauth_short uses a shorthand auth to index into a cache of longhand auths. + * Note: the shorthand has been gutted for efficiency. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> + +/* + * Unix longhand authenticator + */ +enum auth_stat +_svcauth_unix(rqst, msg) + register struct svc_req *rqst; + register struct rpc_msg *msg; +{ + register enum auth_stat stat; + XDR xdrs; + register struct authunix_parms *aup; + register rpc_int32 *buf; + struct area { + struct authunix_parms area_aup; + char area_machname[MAX_MACHINE_NAME+1]; + int area_gids[NGRPS]; + } *area; + unsigned int auth_len; + int str_len, gid_len; + register int i; + + rqst->rq_xprt->xp_auth = &svc_auth_any; + + area = (struct area *) rqst->rq_clntcred; + aup = &area->area_aup; + aup->aup_machname = area->area_machname; + aup->aup_gids = area->area_gids; + auth_len = (unsigned int)msg->rm_call.cb_cred.oa_length; + xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); + buf = (rpc_int32 *) XDR_INLINE(&xdrs, auth_len); + if (buf != NULL) { + aup->aup_time = IXDR_GET_LONG(buf); + str_len = IXDR_GET_U_LONG(buf); + if (str_len > MAX_MACHINE_NAME) { + stat = AUTH_BADCRED; + goto done; + } + memmove(aup->aup_machname, (caddr_t)buf, (unsigned int)str_len); + aup->aup_machname[str_len] = 0; + str_len = RNDUP(str_len); + buf += str_len / sizeof (rpc_int32); + aup->aup_uid = IXDR_GET_LONG(buf); + aup->aup_gid = IXDR_GET_LONG(buf); + gid_len = IXDR_GET_U_LONG(buf); + if (gid_len > NGRPS) { + stat = AUTH_BADCRED; + goto done; + } + aup->aup_len = gid_len; + for (i = 0; i < gid_len; i++) { + aup->aup_gids[i] = IXDR_GET_LONG(buf); + } + /* + * five is the smallest unix credentials structure - + * timestamp, hostname len (0), uid, gid, and gids len (0). + */ + if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) { + (void) printf("bad auth_len gid %d str %d auth %d\n", + gid_len, str_len, auth_len); + stat = AUTH_BADCRED; + goto done; + } + } else if (! xdr_authunix_parms(&xdrs, aup)) { + xdrs.x_op = XDR_FREE; + (void)xdr_authunix_parms(&xdrs, aup); + stat = AUTH_BADCRED; + goto done; + } + rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; + rqst->rq_xprt->xp_verf.oa_length = 0; + stat = AUTH_OK; +done: + XDR_DESTROY(&xdrs); + return (stat); +} + + +/* + * Shorthand unix authenticator + * Looks up longhand in a cache. + */ +/*ARGSUSED*/ +enum auth_stat +_svcauth_short(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + rqst->rq_xprt->xp_auth = &svc_auth_any; + return (AUTH_REJECTEDCRED); +} diff --git a/src/lib/rpc/svc_raw.c b/src/lib/rpc/svc_raw.c new file mode 100644 index 000000000..1170ecec8 --- /dev/null +++ b/src/lib/rpc/svc_raw.c @@ -0,0 +1,166 @@ +/* @(#)svc_raw.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_raw.c 1.15 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_raw.c, This a toy for simple testing and timing. + * Interface to create an rpc client and server in the same UNIX process. + * This lets us similate rpc and get rpc (round trip) overhead, without + * any interference from the kernal. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <rpc/rpc.h> + + +/* + * This is the "network" that we will be moving data over + */ +static struct svcraw_private { + char _raw_buf[UDPMSGSIZE]; + SVCXPRT server; + XDR xdr_stream; + char verf_body[MAX_AUTH_BYTES]; +} *svcraw_private; + +static bool_t svcraw_recv(); +static enum xprt_stat svcraw_stat(); +static bool_t svcraw_getargs(); +static bool_t svcraw_reply(); +static bool_t svcraw_freeargs(); +static void svcraw_destroy(); + +static struct xp_ops server_ops = { + svcraw_recv, + svcraw_stat, + svcraw_getargs, + svcraw_reply, + svcraw_freeargs, + svcraw_destroy +}; + +SVCXPRT * +svcraw_create() +{ + register struct svcraw_private *srp = svcraw_private; + + if (srp == 0) { + srp = (struct svcraw_private *)calloc(1, sizeof (*srp)); + if (srp == 0) + return (0); + } + srp->server.xp_sock = 0; + srp->server.xp_port = 0; + srp->server.xp_ops = &server_ops; + srp->server.xp_verf.oa_base = srp->verf_body; + xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE); + return (&srp->server); +} + +static enum xprt_stat +svcraw_stat() +{ + + return (XPRT_IDLE); +} + +static bool_t +svcraw_recv(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcraw_private *srp = svcraw_private; + register XDR *xdrs; + + if (srp == 0) + return (0); + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) + return (FALSE); + return (TRUE); +} + +static bool_t +svcraw_reply(xprt, msg) + SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcraw_private *srp = svcraw_private; + register XDR *xdrs; + + if (srp == 0) + return (FALSE); + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_replymsg(xdrs, msg)) + return (FALSE); + (void)XDR_GETPOS(xdrs); /* called just for overhead */ + return (TRUE); +} + +static bool_t +svcraw_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + register struct svcraw_private *srp = svcraw_private; + + if (srp == 0) + return (FALSE); + return ((*xdr_args)(&srp->xdr_stream, args_ptr)); +} + +static bool_t +svcraw_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + register struct svcraw_private *srp = svcraw_private; + register XDR *xdrs; + + if (srp == 0) + return (FALSE); + xdrs = &srp->xdr_stream; + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static void +svcraw_destroy() +{ +} diff --git a/src/lib/rpc/svc_run.c b/src/lib/rpc/svc_run.c new file mode 100644 index 000000000..d43aa2425 --- /dev/null +++ b/src/lib/rpc/svc_run.c @@ -0,0 +1,72 @@ +/* @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro"; +#endif + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include <rpc/rpc.h> +#include <sys/errno.h> + +void +svc_run() +{ +#ifdef FD_SETSIZE + fd_set readfds; +#else + int readfds; +#endif /* def FD_SETSIZE */ + extern int errno; + + for (;;) { +#ifdef FD_SETSIZE + readfds = svc_fdset; +#else + readfds = svc_fds; +#endif /* def FD_SETSIZE */ + switch (select(_rpc_dtablesize(), &readfds, (fd_set *)0, + (fd_set *)0, (struct timeval *)0)) { + case -1: + if (errno == EINTR) { + continue; + } + perror("svc_run: - select failed"); + return; + case 0: + continue; + default: + svc_getreqset(&readfds); + } + } +} diff --git a/src/lib/rpc/svc_simple.c b/src/lib/rpc/svc_simple.c new file mode 100644 index 000000000..2a22e5722 --- /dev/null +++ b/src/lib/rpc/svc_simple.c @@ -0,0 +1,143 @@ +/* @(#)svc_simple.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_simple.c 1.18 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <netdb.h> + +static struct proglst { + char *(*p_progname)(); + int p_prognum; + int p_procnum; + xdrproc_t p_inproc, p_outproc; + struct proglst *p_nxt; +} *proglst; +static void universal(); +static SVCXPRT *transp; +struct proglst *pl; + +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) + char *(*progname)(); + xdrproc_t inproc, outproc; +{ + + if (procnum == NULLPROC) { + (void) fprintf(stderr, + "can't reassign procedure number %d\n", NULLPROC); + return (-1); + } + if (transp == 0) { + transp = svcudp_create(RPC_ANYSOCK); + if (transp == NULL) { + (void) fprintf(stderr, "couldn't create an rpc server\n"); + return (-1); + } + } + (void) pmap_unset((rpc_u_int32)prognum, (rpc_u_int32)versnum); + if (!svc_register(transp, (rpc_u_int32)prognum, (rpc_u_int32)versnum, + universal, IPPROTO_UDP)) { + (void) fprintf(stderr, "couldn't register prog %d vers %d\n", + prognum, versnum); + return (-1); + } + pl = (struct proglst *)malloc(sizeof(struct proglst)); + if (pl == NULL) { + (void) fprintf(stderr, "registerrpc: out of memory\n"); + return (-1); + } + pl->p_progname = progname; + pl->p_prognum = prognum; + pl->p_procnum = procnum; + pl->p_inproc = inproc; + pl->p_outproc = outproc; + pl->p_nxt = proglst; + proglst = pl; + return (0); +} + +static void +universal(rqstp, transp) + struct svc_req *rqstp; + SVCXPRT *transp; +{ + int prog, proc; + char *outdata; + char xdrbuf[UDPMSGSIZE]; + struct proglst *pl; + + /* + * enforce "procnum 0 is echo" convention + */ + if (rqstp->rq_proc == NULLPROC) { + if (svc_sendreply(transp, xdr_void, (char *)NULL) == FALSE) { + (void) fprintf(stderr, "xxx\n"); + exit(1); + } + return; + } + prog = rqstp->rq_prog; + proc = rqstp->rq_proc; + for (pl = proglst; pl != NULL; pl = pl->p_nxt) + if (pl->p_prognum == prog && pl->p_procnum == proc) { + /* decode arguments into a CLEAN buffer */ + memset(xdrbuf, 0, sizeof(xdrbuf)); /* required ! */ + if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) { + svcerr_decode(transp); + return; + } + outdata = (*(pl->p_progname))(xdrbuf); + if (outdata == NULL && pl->p_outproc != xdr_void) + /* there was an error */ + return; + if (!svc_sendreply(transp, pl->p_outproc, outdata)) { + (void) fprintf(stderr, + "trouble replying to prog %d\n", + pl->p_prognum); + exit(1); + } + /* free the decoded arguments */ + (void)svc_freeargs(transp, pl->p_inproc, xdrbuf); + return; + } + (void) fprintf(stderr, "never registered prog %d\n", prog); + exit(1); +} + diff --git a/src/lib/rpc/svc_tcp.c b/src/lib/rpc/svc_tcp.c new file mode 100644 index 000000000..e20a29b19 --- /dev/null +++ b/src/lib/rpc/svc_tcp.c @@ -0,0 +1,453 @@ +/* @(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_tcp.c, Server side for TCP/IP based RPC. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * Actually implements two flavors of transporter - + * a tcp rendezvouser (a listner and connection establisher) + * and a record/tcp stream. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> +#include <stdlib.h> +/*extern bool_t abort();*. +extern errno; + +/* + * Ops vector for TCP/IP based rpc service handle + */ +static bool_t svctcp_recv(); +static enum xprt_stat svctcp_stat(); +static bool_t svctcp_getargs(); +static bool_t svctcp_reply(); +static bool_t svctcp_freeargs(); +static void svctcp_destroy(); + +static struct xp_ops svctcp_op = { + svctcp_recv, + svctcp_stat, + svctcp_getargs, + svctcp_reply, + svctcp_freeargs, + svctcp_destroy +}; + +/* + * Ops vector for TCP/IP rendezvous handler + */ +static bool_t rendezvous_request(); +static bool_t abortx(); +static enum xprt_stat rendezvous_stat(); + +static struct xp_ops svctcp_rendezvous_op = { + rendezvous_request, + rendezvous_stat, + abortx, + abortx, + abortx, + svctcp_destroy +}; + +static int readtcp(), writetcp(); +static SVCXPRT *makefd_xprt(); + +struct tcp_rendezvous { /* kept in xprt->xp_p1 */ + unsigned int sendsize; + unsigned int recvsize; +}; + +struct tcp_conn { /* kept in xprt->xp_p1 */ + enum xprt_stat strm_stat; + rpc_u_int32 x_id; + XDR xdrs; + char verf_body[MAX_AUTH_BYTES]; +}; + +/* + * Usage: + * xprt = svctcp_create(sock, send_buf_size, recv_buf_size); + * + * Creates, registers, and returns a (rpc) tcp based transporter. + * Once *xprt is initialized, it is registered as a transporter + * see (svc.h, xprt_register). This routine returns + * a NULL if a problem occurred. + * + * If sock<0 then a socket is created, else sock is used. + * If the socket, sock is not bound to a port then svctcp_create + * binds it to an arbitrary port. The routine then starts a tcp + * listener on the socket's associated port. In any (successful) case, + * xprt->xp_sock is the registered socket number and xprt->xp_port is the + * associated port number. + * + * Since tcp streams do buffered io similar to stdio, the caller can specify + * how big the send and receive buffers are via the second and third parms; + * 0 => use the system default. + */ +SVCXPRT * +svctcp_create(sock, sendsize, recvsize) + register int sock; + unsigned int sendsize; + unsigned int recvsize; +{ + bool_t madesock = FALSE; + register SVCXPRT *xprt; + register struct tcp_rendezvous *r; + struct sockaddr_in addr; + int len = sizeof(struct sockaddr_in); + + if (sock == RPC_ANYSOCK) { + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + perror("svctcp_.c - udp socket creation problem"); + return ((SVCXPRT *)NULL); + } + madesock = TRUE; + } + memset((char *)&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + if (bindresvport(sock, &addr)) { + addr.sin_port = 0; + (void)bind(sock, (struct sockaddr *)&addr, len); + } + if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { + perror("svc_tcp.c - cannot getsockname"); + if (madesock) + (void) close(sock); + return ((SVCXPRT *)NULL); + } + if (listen(sock, 2) != 0) { + perror("svctcp_.c - cannot listen"); + if (madesock) + (void)close(sock); + return ((SVCXPRT *)NULL); + } + r = (struct tcp_rendezvous *)mem_alloc(sizeof(*r)); + if (r == NULL) { + (void) fprintf(stderr, "svctcp_create: out of memory\n"); + return (NULL); + } + r->sendsize = sendsize; + r->recvsize = recvsize; + xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) { + (void) fprintf(stderr, "svctcp_create: out of memory\n"); + return (NULL); + } + xprt->xp_p2 = NULL; + xprt->xp_p1 = (caddr_t)r; + xprt->xp_verf = _null_auth; + xprt->xp_ops = &svctcp_rendezvous_op; + xprt->xp_port = ntohs(addr.sin_port); + xprt->xp_sock = sock; + xprt_register(xprt); + return (xprt); +} + +/* + * Like svtcp_create(), except the routine takes any *open* UNIX file + * descriptor as its first input. + */ +SVCXPRT * +svcfd_create(fd, sendsize, recvsize) + int fd; + unsigned int sendsize; + unsigned int recvsize; +{ + + return (makefd_xprt(fd, sendsize, recvsize)); +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + int fd; + unsigned int sendsize; + unsigned int recvsize; +{ + register SVCXPRT *xprt; + register struct tcp_conn *cd; + + xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); + if (xprt == (SVCXPRT *)NULL) { + (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); + goto done; + } + cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn)); + if (cd == (struct tcp_conn *)NULL) { + (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n"); + mem_free((char *) xprt, sizeof(SVCXPRT)); + xprt = (SVCXPRT *)NULL; + goto done; + } + cd->strm_stat = XPRT_IDLE; + xdrrec_create(&(cd->xdrs), sendsize, recvsize, + (caddr_t)xprt, readtcp, writetcp); + xprt->xp_p2 = NULL; + xprt->xp_p1 = (caddr_t)cd; + xprt->xp_verf.oa_base = cd->verf_body; + xprt->xp_addrlen = 0; + xprt->xp_ops = &svctcp_op; /* truely deals with calls */ + xprt->xp_port = 0; /* this is a connection, not a rendezvouser */ + xprt->xp_sock = fd; + xprt_register(xprt); + done: + return (xprt); +} + +static bool_t +rendezvous_request(xprt) + register SVCXPRT *xprt; +{ + int sock; + struct tcp_rendezvous *r; + struct sockaddr_in addr; + int len; + + r = (struct tcp_rendezvous *)xprt->xp_p1; + again: + len = sizeof(struct sockaddr_in); + if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr, + &len)) < 0) { + if (errno == EINTR) + goto again; + return (FALSE); + } + /* + * make a new transporter (re-uses xprt) + */ + xprt = makefd_xprt(sock, r->sendsize, r->recvsize); + xprt->xp_raddr = addr; + xprt->xp_addrlen = len; + return (FALSE); /* there is never an rpc msg to be processed */ +} + +static enum xprt_stat +rendezvous_stat() +{ + + return (XPRT_IDLE); +} + +static void +svctcp_destroy(xprt) + register SVCXPRT *xprt; +{ + register struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1; + + xprt_unregister(xprt); + (void)close(xprt->xp_sock); + if (xprt->xp_port != 0) { + /* a rendezvouser socket */ + xprt->xp_port = 0; + } else { + /* an actual connection socket */ + XDR_DESTROY(&(cd->xdrs)); + } + mem_free((caddr_t)cd, sizeof(struct tcp_conn)); + mem_free((caddr_t)xprt, sizeof(SVCXPRT)); +} + +/* + * All read operations timeout after 35 seconds. + * A timeout is fatal for the connection. + */ +static struct timeval wait_per_try = { 35, 0 }; + +/* + * reads data from the tcp conection. + * any error is fatal and the connection is closed. + * (And a read of zero bytes is a half closed stream => error.) + */ +static int +readtcp(xprt, buf, len) + register SVCXPRT *xprt; + caddr_t buf; + register int len; +{ + register int sock = xprt->xp_sock; +#ifdef FD_SETSIZE + fd_set mask; + fd_set readfds; + + FD_ZERO(&mask); + FD_SET(sock, &mask); +#else + register int mask = 1 << sock; + int readfds; +#endif /* def FD_SETSIZE */ + do { + readfds = mask; + if (select(_rpc_dtablesize(), &readfds, (fd_set*)NULL, + (fd_set*)NULL, &wait_per_try) <= 0) { + if (errno == EINTR) { + continue; + } + goto fatal_err; + } +#ifdef FD_SETSIZE + } while (!FD_ISSET(sock, &readfds)); +#else + } while (readfds != mask); +#endif /* def FD_SETSIZE */ + if ((len = read(sock, buf, len)) > 0) { + return (len); + } +fatal_err: + ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; + return (-1); +} + +/* + * writes data to the tcp connection. + * Any error is fatal and the connection is closed. + */ +static int +writetcp(xprt, buf, len) + register SVCXPRT *xprt; + caddr_t buf; + int len; +{ + register int i, cnt; + + for (cnt = len; cnt > 0; cnt -= i, buf += i) { + if ((i = write(xprt->xp_sock, buf, cnt)) < 0) { + ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = + XPRT_DIED; + return (-1); + } + } + return (len); +} + +static enum xprt_stat +svctcp_stat(xprt) + SVCXPRT *xprt; +{ + register struct tcp_conn *cd = + (struct tcp_conn *)(xprt->xp_p1); + + if (cd->strm_stat == XPRT_DIED) + return (XPRT_DIED); + if (! xdrrec_eof(&(cd->xdrs))) + return (XPRT_MOREREQS); + return (XPRT_IDLE); +} + +static bool_t +svctcp_recv(xprt, msg) + SVCXPRT *xprt; + register struct rpc_msg *msg; +{ + register struct tcp_conn *cd = + (struct tcp_conn *)(xprt->xp_p1); + register XDR *xdrs = &(cd->xdrs); + + xdrs->x_op = XDR_DECODE; + (void)xdrrec_skiprecord(xdrs); + if (xdr_callmsg(xdrs, msg)) { + cd->x_id = msg->rm_xid; + return (TRUE); + } + return (FALSE); +} + +static bool_t +svctcp_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + return (SVCAUTH_UNWRAP(xprt->xp_auth, + &(((struct tcp_conn *)(xprt->xp_p1))->xdrs), + xdr_args, args_ptr)); +} + +static bool_t +svctcp_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + register XDR *xdrs = + &(((struct tcp_conn *)(xprt->xp_p1))->xdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static bool_t svctcp_reply(xprt, msg) + SVCXPRT *xprt; + register struct rpc_msg *msg; +{ + register struct tcp_conn *cd = + (struct tcp_conn *)(xprt->xp_p1); + register XDR *xdrs = &(cd->xdrs); + register bool_t stat; + + xdrproc_t xdr_results; + caddr_t xdr_location; + bool_t has_args; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + has_args = TRUE; + xdr_results = msg->acpted_rply.ar_results.proc; + xdr_location = msg->acpted_rply.ar_results.where; + + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + } else + has_args = FALSE; + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + stat = FALSE; + if (xdr_replymsg(xdrs, msg) && + (!has_args || + (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { + stat = TRUE; + } + (void)xdrrec_endofrecord(xdrs, TRUE); + return (stat); +} + +static bool_t abortx() +{ + abort(); + return 1; +} + diff --git a/src/lib/rpc/svc_udp.c b/src/lib/rpc/svc_udp.c new file mode 100644 index 000000000..d44c7f5d8 --- /dev/null +++ b/src/lib/rpc/svc_udp.c @@ -0,0 +1,496 @@ +/* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * svc_udp.c, + * Server side for UDP/IP based RPC. (Does some caching in the hopes of + * achieving execute-at-most-once semantics.) + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include <stdio.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <errno.h> + + +#define rpc_buffer(xprt) ((xprt)->xp_p1) +#ifndef MAX +#define MAX(a, b) ((a > b) ? a : b) +#endif + +static bool_t svcudp_recv(); +static bool_t svcudp_reply(); +static enum xprt_stat svcudp_stat(); +static bool_t svcudp_getargs(); +static bool_t svcudp_freeargs(); +static void svcudp_destroy(); + +static void cache_set(); +static int cache_get(); + +static struct xp_ops svcudp_op = { + svcudp_recv, + svcudp_stat, + svcudp_getargs, + svcudp_reply, + svcudp_freeargs, + svcudp_destroy +}; + +extern int errno; + +/* + * kept in xprt->xp_p2 + */ +struct svcudp_data { + unsigned int su_iosz; /* byte size of send.recv buffer */ + rpc_u_int32 su_xid; /* transaction id */ + XDR su_xdrs; /* XDR handle */ + char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ + char * su_cache; /* cached data, NULL if no cache */ +}; +#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2)) + +/* + * Usage: + * xprt = svcudp_create(sock); + * + * If sock<0 then a socket is created, else sock is used. + * If the socket, sock is not bound to a port then svcudp_create + * binds it to an arbitrary port. In any (successful) case, + * xprt->xp_sock is the registered socket number and xprt->xp_port is the + * associated port number. + * Once *xprt is initialized, it is registered as a transporter; + * see (svc.h, xprt_register). + * The routines returns NULL if a problem occurred. + */ +SVCXPRT * +svcudp_bufcreate(sock, sendsz, recvsz) + register int sock; + unsigned int sendsz, recvsz; +{ + bool_t madesock = FALSE; + register SVCXPRT *xprt; + register struct svcudp_data *su; + struct sockaddr_in addr; + int len = sizeof(struct sockaddr_in); + + if (sock == RPC_ANYSOCK) { + if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + perror("svcudp_create: socket creation problem"); + return ((SVCXPRT *)NULL); + } + madesock = TRUE; + } + memset((char *)&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + if (bindresvport(sock, &addr)) { + addr.sin_port = 0; + (void)bind(sock, (struct sockaddr *)&addr, len); + } + if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) { + perror("svcudp_create - cannot getsockname"); + if (madesock) + (void)close(sock); + return ((SVCXPRT *)NULL); + } + xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT)); + if (xprt == NULL) { + (void)fprintf(stderr, "svcudp_create: out of memory\n"); + return (NULL); + } + su = (struct svcudp_data *)mem_alloc(sizeof(*su)); + if (su == NULL) { + (void)fprintf(stderr, "svcudp_create: out of memory\n"); + return (NULL); + } + su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4; + if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) { + (void)fprintf(stderr, "svcudp_create: out of memory\n"); + return (NULL); + } + xdrmem_create( + &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE); + su->su_cache = NULL; + xprt->xp_p2 = (caddr_t)su; + xprt->xp_verf.oa_base = su->su_verfbody; + xprt->xp_ops = &svcudp_op; + xprt->xp_port = ntohs(addr.sin_port); + xprt->xp_sock = sock; + xprt_register(xprt); + return (xprt); +} + +SVCXPRT * +svcudp_create(sock) + int sock; +{ + + return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE)); +} + +static enum xprt_stat +svcudp_stat(xprt) + SVCXPRT *xprt; +{ + + return (XPRT_IDLE); +} + +static bool_t +svcudp_recv(xprt, msg) + register SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcudp_data *su = su_data(xprt); + register XDR *xdrs = &(su->su_xdrs); + register int rlen; + char *reply; + rpc_u_int32 replylen; + + again: + xprt->xp_addrlen = sizeof(struct sockaddr_in); + rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz, + 0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen)); + if (rlen == -1 && errno == EINTR) + goto again; + if (rlen < (int) 4*sizeof(rpc_u_int32)) + return (FALSE); + xdrs->x_op = XDR_DECODE; + XDR_SETPOS(xdrs, 0); + if (! xdr_callmsg(xdrs, msg)) + return (FALSE); + su->su_xid = msg->rm_xid; + if (su->su_cache != NULL) { + if (cache_get(xprt, msg, &reply, &replylen)) { + (void) sendto(xprt->xp_sock, reply, (int) replylen, 0, + (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen); + return (TRUE); + } + } + return (TRUE); +} + +static bool_t svcudp_reply(xprt, msg) + register SVCXPRT *xprt; + struct rpc_msg *msg; +{ + register struct svcudp_data *su = su_data(xprt); + register XDR *xdrs = &(su->su_xdrs); + register int slen; + register bool_t stat = FALSE; + + xdrproc_t xdr_results; + caddr_t xdr_location; + bool_t has_args; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + has_args = TRUE; + xdr_results = msg->acpted_rply.ar_results.proc; + xdr_location = msg->acpted_rply.ar_results.where; + + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + } else + has_args = FALSE; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + if (xdr_replymsg(xdrs, msg) && + (!has_args || + (SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_results, xdr_location)))) { + slen = (int)XDR_GETPOS(xdrs); + if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, + (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) + == slen) { + stat = TRUE; + if (su->su_cache && slen >= 0) { + cache_set(xprt, (rpc_u_int32) slen); + } + } + } + return (stat); +} + +static bool_t +svcudp_getargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + return (SVCAUTH_UNWRAP(xprt->xp_auth, &(su_data(xprt)->su_xdrs), + xdr_args, args_ptr)); +} + +static bool_t +svcudp_freeargs(xprt, xdr_args, args_ptr) + SVCXPRT *xprt; + xdrproc_t xdr_args; + caddr_t args_ptr; +{ + register XDR *xdrs = &(su_data(xprt)->su_xdrs); + + xdrs->x_op = XDR_FREE; + return ((*xdr_args)(xdrs, args_ptr)); +} + +static void +svcudp_destroy(xprt) + register SVCXPRT *xprt; +{ + register struct svcudp_data *su = su_data(xprt); + + xprt_unregister(xprt); + (void)close(xprt->xp_sock); + XDR_DESTROY(&(su->su_xdrs)); + mem_free(rpc_buffer(xprt), su->su_iosz); + mem_free((caddr_t)su, sizeof(struct svcudp_data)); + mem_free((caddr_t)xprt, sizeof(SVCXPRT)); +} + + +/***********this could be a separate file*********************/ + +/* + * Fifo cache for udp server + * Copies pointers to reply buffers into fifo cache + * Buffers are sent again if retransmissions are detected. + */ + +#define SPARSENESS 4 /* 75% sparse */ + +#define CACHE_PERROR(msg) \ + (void) fprintf(stderr,"%s\n", msg) + +#define ALLOC(type, size) \ + (type *) mem_alloc((unsigned) (sizeof(type) * (size))) + +#define BZERO(addr, type, size) \ + memset((char *) addr, 0, sizeof(type) * (int) (size)) + +/* + * An entry in the cache + */ +typedef struct cache_node *cache_ptr; +struct cache_node { + /* + * Index into cache is xid, proc, vers, prog and address + */ + rpc_u_int32 cache_xid; + rpc_u_int32 cache_proc; + rpc_u_int32 cache_vers; + rpc_u_int32 cache_prog; + struct sockaddr_in cache_addr; + /* + * The cached reply and length + */ + char * cache_reply; + rpc_u_int32 cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + + + +/* + * The entire cache + */ +struct udp_cache { + rpc_u_int32 uc_size; /* size of cache */ + cache_ptr *uc_entries; /* hash table of entries in cache */ + cache_ptr *uc_fifo; /* fifo list of entries in cache */ + rpc_u_int32 uc_nextvictim; /* points to next victim in fifo list */ + rpc_u_int32 uc_prog; /* saved program number */ + rpc_u_int32 uc_vers; /* saved version number */ + rpc_u_int32 uc_proc; /* saved procedure number */ + struct sockaddr_in uc_addr; /* saved caller's address */ +}; + + +/* + * the hashing function + */ +#define CACHE_LOC(transp, xid) \ + (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size)) + + +/* + * Enable use of the cache. + * Note: there is no disable. + */ +svcudp_enablecache(transp, size) + SVCXPRT *transp; + rpc_u_int32 size; +{ + struct svcudp_data *su = su_data(transp); + struct udp_cache *uc; + + if (su->su_cache != NULL) { + CACHE_PERROR("enablecache: cache already enabled"); + return(0); + } + uc = ALLOC(struct udp_cache, 1); + if (uc == NULL) { + CACHE_PERROR("enablecache: could not allocate cache"); + return(0); + } + uc->uc_size = size; + uc->uc_nextvictim = 0; + uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS); + if (uc->uc_entries == NULL) { + CACHE_PERROR("enablecache: could not allocate cache data"); + return(0); + } + BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS); + uc->uc_fifo = ALLOC(cache_ptr, size); + if (uc->uc_fifo == NULL) { + CACHE_PERROR("enablecache: could not allocate cache fifo"); + return(0); + } + BZERO(uc->uc_fifo, cache_ptr, size); + su->su_cache = (char *) uc; + return(1); +} + + +/* + * Set an entry in the cache + */ +static void +cache_set(xprt, replylen) + SVCXPRT *xprt; + rpc_u_int32 replylen; +{ + register cache_ptr victim; + register cache_ptr *vicp; + register struct svcudp_data *su = su_data(xprt); + struct udp_cache *uc = (struct udp_cache *) su->su_cache; + unsigned int loc; + char *newbuf; + + /* + * Find space for the new entry, either by + * reusing an old entry, or by mallocing a new one + */ + victim = uc->uc_fifo[uc->uc_nextvictim]; + if (victim != NULL) { + loc = CACHE_LOC(xprt, victim->cache_xid); + for (vicp = &uc->uc_entries[loc]; + *vicp != NULL && *vicp != victim; + vicp = &(*vicp)->cache_next) + ; + if (*vicp == NULL) { + CACHE_PERROR("cache_set: victim not found"); + return; + } + *vicp = victim->cache_next; /* remote from cache */ + newbuf = victim->cache_reply; + } else { + victim = ALLOC(struct cache_node, 1); + if (victim == NULL) { + CACHE_PERROR("cache_set: victim alloc failed"); + return; + } + newbuf = mem_alloc(su->su_iosz); + if (newbuf == NULL) { + CACHE_PERROR("cache_set: could not allocate new rpc_buffer"); + return; + } + } + + /* + * Store it away + */ + victim->cache_replylen = replylen; + victim->cache_reply = rpc_buffer(xprt); + rpc_buffer(xprt) = newbuf; + xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE); + victim->cache_xid = su->su_xid; + victim->cache_proc = uc->uc_proc; + victim->cache_vers = uc->uc_vers; + victim->cache_prog = uc->uc_prog; + victim->cache_addr = uc->uc_addr; + loc = CACHE_LOC(xprt, victim->cache_xid); + victim->cache_next = uc->uc_entries[loc]; + uc->uc_entries[loc] = victim; + uc->uc_fifo[uc->uc_nextvictim++] = victim; + uc->uc_nextvictim %= uc->uc_size; +} + +/* + * Try to get an entry from the cache + * return 1 if found, 0 if not found + */ +static int +cache_get(xprt, msg, replyp, replylenp) + SVCXPRT *xprt; + struct rpc_msg *msg; + char **replyp; + rpc_u_int32 *replylenp; +{ + unsigned int loc; + register cache_ptr ent; + register struct svcudp_data *su = su_data(xprt); + register struct udp_cache *uc = (struct udp_cache *) su->su_cache; + +# define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0) + + loc = CACHE_LOC(xprt, su->su_xid); + for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) { + if (ent->cache_xid == su->su_xid && + ent->cache_proc == uc->uc_proc && + ent->cache_vers == uc->uc_vers && + ent->cache_prog == uc->uc_prog && + EQADDR(ent->cache_addr, uc->uc_addr)) { + *replyp = ent->cache_reply; + *replylenp = ent->cache_replylen; + return(1); + } + } + /* + * Failed to find entry + * Remember a few things so we can do a set later + */ + uc->uc_proc = msg->rm_call.cb_proc; + uc->uc_vers = msg->rm_call.cb_vers; + uc->uc_prog = msg->rm_call.cb_prog; + uc->uc_addr = xprt->xp_raddr; + return(0); +} + diff --git a/src/lib/rpc/types.hin b/src/lib/rpc/types.hin new file mode 100644 index 000000000..619a9ce20 --- /dev/null +++ b/src/lib/rpc/types.hin @@ -0,0 +1,90 @@ +/* @(#)types.h 2.3 88/08/15 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)types.h 1.18 87/07/24 SMI */ + +/* + * Rpc additions to <sys/types.h> + */ +#ifndef __TYPES_RPC_HEADER__ +#define __TYPES_RPC_HEADER__ + +#include <sys/types.h> + +/* this is a 32-bit int type */ + +#if @SIZEOF_INT@ == 4 +typedef int rpc_int32; +typedef unsigned int rpc_u_int32; +#elif @SIZEOF_LONG@ == 4 +typedef long rpc_int32; +typedef unsigned long rpc_u_int32; +#endif + +#define bool_t int +#define enum_t int +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (1) +#endif +#define __dontcare__ -1 +#ifndef NULL +# define NULL 0 +#endif + +#if defined(__osf__) +#include <stdlib.h> +#endif +#define mem_alloc(bsize) (char *) malloc(bsize) +#define mem_free(ptr, bsize) free(ptr) + +#ifndef makedev /* ie, we haven't already included it */ +#include <sys/types.h> +#endif +#ifdef _AIX +#include <sys/select.h> +#endif +#include <sys/time.h> +#include <netinet/in.h> +#include <sys/param.h> +#include <netdb.h> /* XXX This should not have to be here. + * I got sick of seeing the warnings for MAXHOSTNAMELEN + * and the two values were different. -- shanzer + */ + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK (rpc_u_int32)0x7F000001 +#endif +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +#endif /* ndef __TYPES_RPC_HEADER__ */ diff --git a/src/lib/rpc/unit-test/Makefile b/src/lib/rpc/unit-test/Makefile new file mode 100644 index 000000000..31853cb35 --- /dev/null +++ b/src/lib/rpc/unit-test/Makefile @@ -0,0 +1,97 @@ +# Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. +# +# $Id$ +# $Source$ +# +# $Log$ +# Revision 1.9 1996/07/22 20:41:38 marc +# this commit includes all the changes on the OV_9510_INTEGRATION and +# OV_MERGE branches. This includes, but is not limited to, the new openvision +# admin system, and major changes to gssapi to add functionality, and bring +# the implementation in line with rfc1964. before committing, the +# code was built and tested for netbsd and solaris. +# +# Revision 1.8.4.1 1996/07/18 04:20:01 marc +# merged in changes from OV_9510_BP to OV_9510_FINAL1 +# +# Revision 1.8.2.1 1996/06/20 23:41:48 marc +# File added to the repository on a branch +# +# Revision 1.8 1995/12/07 17:36:54 jik +# Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on +# some systems. See PR 3553. +# +# Revision 1.7 1995/10/02 08:02:49 jik +# Delete rpc-tset_clnt.c, rpc-test_svc.c and rpc-test.h before creating +# them, because rpcgen on some platforms won't output to a file that +# already exists. +# +# Revision 1.6 1994/10/24 19:35:57 bjaspan +# [secure-build/2649: cannot use -L when compiling] +# +# Sandbox: +# +# [secure-build/2649] don't use -L +# +# Revision 1.7 1994/10/11 20:06:14 bjaspan +# [secure-build/2649] don't use -L +# +# Revision 1.6 1994/09/30 22:25:29 jik +# Don't need to set MDFLAGS to -a anymore, because it's done +# automatically by the rules now. +# +# Revision 1.5 1994/03/22 19:55:34 shanzer +# change NETLIBS to NETLIB +# +# Revision 1.4 1994/03/18 17:47:00 shanzer +# added NETLIBS and BSDLIB +# +# Revision 1.3 1993/12/13 02:00:39 bjaspan +# recurse to testsuite subdir. +# +# Revision 1.2 1993/12/08 21:45:47 bjaspan +# misc +# +# Revision 1.1 1993/11/03 23:53:58 bjaspan +# Initial revision +# + +TOP = ../.. +include $(TOP)/config.mk/template + +SUBDIRS = testsuite + +expand SubdirTarget + +SRCS = client.c server.c + +CFLAGS := -I../.. -I. $(CFLAGS) + +#LIBS = ../librpclib.a $(LIBGSSAPI_TRUST) $(LIBDB) $(LIBCOM_ERR) $(LIBDYN) +LIBS = ../librpclib.a $(LIBGSSAPI_KRB5) $(LIBDB) $(LIBKRB5) \ + $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR) $(LIBDYN) $(BSDLIB) $(NETLIB) +DEPS = ../librpclib.a rpc_test.h +DEPENDS = rpc_test.h + +PROG = client +SRCS = client.c +OBJS = client.o rpc_test_clnt.o + +expand Program +expand Depend + +PROG = server +SRCS = server.c +OBJS = server.o rpc_test_svc.o + +expand Program +expand Depend + +rpc_test.h rpc_test_clnt.c rpc_test_svc.c: rpc_test.x + -rm -f rpc_test_clnt.c rpc_test_svc.c rpc_test.h + rpcgen -l rpc_test.x -o rpc_test_clnt.c + rpcgen -m rpc_test.x -o rpc_test_svc.c + rpcgen -h rpc_test.x -o rpc_test.h + +clean:: + rm -f rpc_test.h rpc_test_clnt.c rpc_test_svc.c diff --git a/src/lib/rpc/unit-test/client.c b/src/lib/rpc/unit-test/client.c new file mode 100644 index 000000000..bcf2700e5 --- /dev/null +++ b/src/lib/rpc/unit-test/client.c @@ -0,0 +1,320 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.13 1996/07/22 20:41:40 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.12.4.1 1996/07/18 04:20:03 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.12.2.1 1996/06/20 23:41:56 marc + * File added to the repository on a branch + * + * Revision 1.12 1996/05/12 06:58:10 marc + * type renamings for compatibility with beta6 + * + * Revision 1.11 1996/02/12 15:58:42 grier + * [secure/3570] + * long conversion + * + * Revision 1.10 1995/12/07 17:37:03 jik + * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on + * some systems. See PR 3553. + * + * Revision 1.9 1994/09/21 18:38:56 bjaspan + * [secure-rpc/2536: unit test client.c: memory initialization and out-of-bounds reference bugs] + * [secure-releng/2537: audit secure-rpc/2536: minor memory problems in unit-test client] + * + * Sandbox: + * + * 1. Don't allow the count specifie on the command line to be bigger + * than the size of the buffer use for testing. + * 2. When initializing the buffer for the lengths test, initialize it to + * count bytes. + * + * Revision 1.9 1994/09/19 01:28:04 root + * 1. Don't allow the count specifie on the command line to be bigger + * than the size of the buffer use for testing. + * 2. When initializing the buffer for the lengths test, initialize it to + * count bytes. + * + * Revision 1.8 1994/04/06 22:13:01 jik + * Change -auth_once to -o, add -a, -m and -s arguments to set + * auth_debug_gssapi, svc_debug_gssapi and misc_debug_gssapi variables. + * + * Revision 1.7 1994/04/05 20:50:09 bjaspan + * fix typo that causes coredump when server blocks/fails + * + * Revision 1.6 1993/12/08 21:44:45 bjaspan + * test fix for secure-rpc/586, improve arg handlng + * + * Revision 1.5 1993/12/06 21:23:30 bjaspan + * accept count arg for RPC_TEST_LENGTHS + * + * Revision 1.4 1993/12/01 23:41:45 bjaspan + * don't free echo_resp if call fails + * + * Revision 1.3 1993/11/15 19:53:09 bjaspan + * test auto-syncrhonization + * + * Revision 1.2 1993/11/12 02:33:43 bjaspan + * use clnt_pcreateerror for auth failures + * + * Revision 1.1 1993/11/03 23:53:58 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <rpc/rpc.h> +#include <gssapi/gssapi.h> +#include <rpc/rpc.h> +#include <rpc/auth_gssapi.h> +#include "rpc_test.h" + +#define BIG_BUF 4096 +/* copied from auth_gssapi.c for hackery */ +struct auth_gssapi_data { + bool_t established; + CLIENT *clnt; + gss_ctx_id_t context; + gss_buffer_desc client_handle; + OM_uint32 seq_num; + int def_cred; + + /* pre-serialized ah_cred */ + u_char cred_buf[MAX_AUTH_BYTES]; + rpc_int32 cred_len; +}; +#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private) + +extern int auth_debug_gssapi; +char *whoami; + +main(argc, argv) + int argc; + char **argv; +{ + char *host, *target, *echo_arg, **echo_resp, buf[BIG_BUF]; + CLIENT *clnt; + AUTH *tmp_auth; + struct rpc_err e; + int i, count, auth_once; + extern int optind; + extern char *optarg; + extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi; + int c; + + whoami = argv[0]; + count = 1026; + auth_once = 0; + + while ((c = getopt(argc, argv, "a:m:os:")) != -1) { + switch (c) { + case 'a': + auth_debug_gssapi = atoi(optarg); + break; + case 'm': + misc_debug_gssapi = atoi(optarg); + break; + case 'o': + auth_once++; + break; + case 's': + svc_debug_gssapi = atoi(optarg); + break; + case '?': + usage(); + break; + } + } + + argv += optind; + argc -= optind; + + switch (argc) { + case 3: + count = atoi(argv[2]); + if (count > BIG_BUF) { + fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF); + usage(); + } + case 2: + host = argv[0]; + target = argv[1]; + break; + default: + usage(); + } + + /* client handle to rstat */ + clnt = clnt_create(host, RPC_TEST_PROG, RPC_TEST_VERS_1, "tcp"); + if (clnt == NULL) { + clnt_pcreateerror(whoami); + exit(1); + } + + clnt->cl_auth = auth_gssapi_create_default(clnt, target); + if (clnt->cl_auth == NULL) { + clnt_pcreateerror(whoami); + exit(2); + } + + /* + * Call the echo service multiple times. + */ + echo_arg = buf; + for (i = 0; i < 3; i++) { + sprintf(buf, "testing %d\n", i); + + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + fprintf(stderr, "RPC_TEST_ECHO call %d%s", i, + clnt_sperror(clnt, "")); + } + if (strncmp(*echo_resp, "Echo: ", 6) && + strcmp(echo_arg, (*echo_resp) + 6) != 0) + fprintf(stderr, "RPC_TEST_ECHO call %d response wrong: " + "arg = %s, resp = %s\n", echo_arg, *echo_resp); + xdr_free(xdr_wrapstring, echo_resp); + } + + /* + * Make a call with an invalid verifier and check for error; + * server should log error message. It is important to + *increment* seq_num here, since a decrement would be fixed (see + * below). Note that seq_num will be incremented (by + * authg_gssapi_refresh) twice, so we need to decrement by three + * to reset. + */ + AUTH_PRIVATE(clnt->cl_auth)->seq_num++; + + echo_arg = "testing with bad verf"; + + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + CLNT_GETERR(clnt, &e); + if (e.re_status != RPC_AUTHERROR || e.re_why != AUTH_REJECTEDVERF) + clnt_perror(clnt, whoami); + } else { + fprintf(stderr, "bad seq didn't cause failure\n"); + } + + AUTH_PRIVATE(clnt->cl_auth)->seq_num -= 3; + + /* + * Make sure we're resyncronized. + */ + echo_arg = "testing for reset"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Sequence number improperly reset"); + + /* + * Now simulate a lost server response, and see if + * auth_gssapi_refresh recovers. + */ + AUTH_PRIVATE(clnt->cl_auth)->seq_num--; + echo_arg = "forcing auto-resynchronization"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Auto-resynchronization failed"); + + /* + * Now make sure auto-resyncrhonization actually worked + */ + echo_arg = "testing for resynchronization"; + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) + clnt_perror(clnt, "Auto-resynchronization did not work"); + + /* + * Test fix for secure-rpc/586, part 1: btree keys must be + * unique. Create another context from the same credentials; it + * should have the same expiration time and will cause the server + * to abort if the clients are not differentiated. + * + * Test fix for secure-rpc/586, part 2: btree keys cannot be + * mutated in place. To test this: a second client, *with a + * later expiration time*, must be run. The second client should + * destroy itself *after* the first one; if the key-mutating bug + * is not fixed, the second client_data will be in the btree + * before the first, but its key will be larger; thus, when the + * first client calls AUTH_DESTROY, the server won't find it in + * the btree and call abort. + * + * For unknown reasons, running just a second client didn't + * tickle the bug; the btree code seemed to guess which node to + * look at first. Running a total of three clients does ticket + * the bug. Thus, the full test sequence looks like this: + * + * kinit -l 20m user && client server test@ddn 200 + * sleep 1 + * kini -l 30m user && client server test@ddn 300 + * sleep 1 + * kinit -l 40m user && client server test@ddn 400 + */ + if (! auth_once) { + tmp_auth = clnt->cl_auth; + clnt->cl_auth = auth_gssapi_create_default(clnt, target); + if (clnt->cl_auth == NULL) { + clnt_pcreateerror(whoami); + exit(2); + } + AUTH_DESTROY(clnt->cl_auth); + clnt->cl_auth = tmp_auth; + } + + /* + * Try RPC calls with argument/result lengths [0, 1025]. Do + * this last, since it takes a while.. + */ + echo_arg = buf; + memset(buf, 0, count); + for (i = 0; i < count; i++) { + echo_resp = rpc_test_echo_1(&echo_arg, clnt); + if (echo_resp == NULL) { + fprintf(stderr, "RPC_TEST_LENGTHS call %d%s", i, + clnt_sperror(clnt, "")); + break; + } else { + if (strncmp(*echo_resp, "Echo: ", 6) && + strcmp(echo_arg, (*echo_resp) + 6) != 0) + fprintf(stderr, + "RPC_TEST_LENGTHS call %d response wrong\n"); + xdr_free(xdr_wrapstring, echo_resp); + } + + /* cycle from 1 to 255 */ + buf[i] = (i % 255) + 1; + + if (i % 100 == 0) { + fputc('.', stdout); + fflush(stdout); + } + } + fputc('\n', stdout); + + AUTH_DESTROY(clnt->cl_auth); + CLNT_DESTROY(clnt); + exit(0); +} + +usage() +{ + fprintf(stderr, "usage: %s [-a] [-s num] [-m num] host service [count]\n", + whoami); + exit(1); +} diff --git a/src/lib/rpc/unit-test/rpc_test.x b/src/lib/rpc/unit-test/rpc_test.x new file mode 100644 index 000000000..e9ae27c97 --- /dev/null +++ b/src/lib/rpc/unit-test/rpc_test.x @@ -0,0 +1,30 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.2 1996/07/22 20:41:42 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.1.4.1 1996/07/18 04:20:04 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * +# Revision 1.1.2.1 1996/06/20 23:42:06 marc +# File added to the repository on a branch +# +# Revision 1.1 1993/11/03 23:53:58 bjaspan +# Initial revision +# + */ + +program RPC_TEST_PROG { + version RPC_TEST_VERS_1 { + string RPC_TEST_ECHO(string) = 1; + } = 1; +} = 1000001; diff --git a/src/lib/rpc/unit-test/server.c b/src/lib/rpc/unit-test/server.c new file mode 100644 index 000000000..d98b2df0b --- /dev/null +++ b/src/lib/rpc/unit-test/server.c @@ -0,0 +1,306 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.15 1996/07/22 20:41:44 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.14.4.1 1996/07/18 04:20:06 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.14.2.1 1996/06/20 23:42:16 marc + * File added to the repository on a branch + * + * Revision 1.14 1996/05/12 06:59:06 marc + * change SERVICE_NAME to "host" instead of "server" + * + * remove KRB5KTNAME support, since the library supports it internally now. + * + * Revision 1.13 1995/12/07 17:36:58 jik + * Use "rpc_test" instead of "rpc-test", to avoid problems with rpcgen on + * some systems. See PR 3553. + * + * Revision 1.12 1995/11/07 23:20:44 grier + * Add stdlib.h + * Add string.h + * + * Revision 1.11 1995/03/24 19:55:28 jik + * Cast a const gss_OID to (gss_OID) to prevent a compiler warning. + * + * Revision 1.10 1995/02/22 15:54:17 jik + * I was a moron in revision 1.8. This is the server function, not the + * client function, so it gets a struct svc_req *, not a CLIENT *. + * + * Revision 1.9 1995/02/22 15:21:51 jik + * Linux's rpcgen names the server function differently from the client + * function ("_svc" is appended to the end of it). + * + * Revision 1.8 1995/02/22 14:35:05 jik + * RPC server functions have CLIENT * passed into them, so I added it as + * an argument to rpc_test_echo_1. + * + * Revision 1.7 1994/09/21 18:35:57 bjaspan + * [gssapi/438: gss_nt_service_name should default to local host] + * [secure-releng/2513: audit gssapi/438: gss_nt_service_name should default to local host] + * + * Sandbox: + * + * Don't need to get local host name and put it in the service name, + * since the gssapi library does that now. See PR 438. + * + * Revision 1.8 1994/09/01 17:21:59 jik + * Don't need to get local host name and put it in the service name, + * since the gssapi library does that now. See PR 438. + * + * Revision 1.7 1994/04/08 17:22:11 bjaspan + * add KRB5KTNAME hack so unit tests continue to work + * + * Revision 1.6 1994/04/05 20:50:26 bjaspan + * print "running" when ready to tests can proceed + * + * Revision 1.5 1994/04/05 19:49:54 jik + * Use host name instead of localhost. + * + * Revision 1.4 1994/03/08 00:14:58 shanzer + * changed call to inet_ntoa + * + * Revision 1.3 1993/12/13 01:37:54 bjaspan + * update for new test system + * ,. + * + * Revision 1.2 1993/12/08 21:45:16 bjaspan + * display badauth errors, improve arg handling + * + * Revision 1.1 1993/11/03 23:53:58 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <rpc/rpc.h> +#include <arpa/inet.h> /* inet_ntoa */ +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_generic.h> +#include <rpc/auth_gssapi.h> +#include <sys/param.h> /* MAXHOSTNAMELEN */ +#include "rpc_test.h" + +#ifdef linux +/* + For some reason, Linux's rpcgen names the server function + differently from the client function. I suppose this is useful if + you want to include them both in the same library or something, but + not useful at all if you want to link the client code directly to + the server code for testing, instead of going through the RPC layer. + */ +#define rpc_test_echo_1 rpc_test_echo_1_svc +#endif + +extern void rpc_test_prog_1(); + +extern int svc_debug_gssapi, misc_debug_gssapi; + +void rpc_test_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, void *data); +void log_badauth_display_status(OM_uint32 major, OM_uint32 minor); +void log_badauth_display_status_1(OM_uint32 code, int type, int rec); +static void rpc_test_badverf(gss_name_t client, gss_name_t server, + struct svc_req *rqst, struct rpc_msg *msg, + caddr_t data); + +#ifndef SERVICE_NAME +#define SERVICE_NAME "host" +#endif + +main(int argc, char **argv) +{ + auth_gssapi_name names[2]; + register SVCXPRT *transp; + + names[0].name = SERVICE_NAME; + names[0].type = (gss_OID) gss_nt_service_name; + names[1].name = 0; + names[1].type = 0; + + switch (argc) { + case 3: + misc_debug_gssapi = atoi(argv[2]); + case 2: + svc_debug_gssapi = atoi(argv[1]); + case 1: + break; + default: + fprintf(stderr, "Usage: server [svc-debug] [misc-debug]\n"); + exit(1); + } + + (void) pmap_unset(RPC_TEST_PROG, RPC_TEST_VERS_1); + + transp = svctcp_create(RPC_ANYSOCK, 0, 0); + if (transp == NULL) { + fprintf(stderr, "cannot create tcp service."); + exit(1); + } + if (!svc_register(transp, RPC_TEST_PROG, RPC_TEST_VERS_1, + rpc_test_prog_1, IPPROTO_TCP)) { + fprintf(stderr, + "unable to register (RPC_TEST_PROG, RPC_TEST_VERS_1, tcp)."); + exit(1); + } + + if (_svcauth_gssapi_set_names(names, 0) == FALSE) { + fprintf(stderr, "unable to set gssapi names\n"); + exit(1); + } + + _svcauth_gssapi_set_log_badauth_func(rpc_test_badauth, NULL); + _svcauth_gssapi_set_log_badverf_func(rpc_test_badverf, NULL); + + printf("running\n"); + + svc_run(); + fprintf(stderr, "svc_run returned"); + exit(1); + /* NOTREACHED */ +} + +char **rpc_test_echo_1(char **arg, struct svc_req *h) +{ + static char *res = NULL; + + if (res) + free(res); + res = (char *) malloc(strlen(*arg) + strlen("Echo: ") + 1); + sprintf(res, "Echo: %s", *arg); + return &res; +} + +static void rpc_test_badverf(gss_name_t client, gss_name_t server, + struct svc_req *rqst, struct rpc_msg *msg, + caddr_t data) +{ + OM_uint32 minor_stat; + gss_OID type; + gss_buffer_desc client_name, server_name; + + (void) gss_display_name(&minor_stat, client, &client_name, &type); + (void) gss_display_name(&minor_stat, server, &server_name, &type); + + printf("rpc_test server: bad verifier from %s at %s:%d for %s\n", + client_name.value, + inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr), + ntohs(rqst->rq_xprt->xp_raddr.sin_port), + server_name.value); + + (void) gss_release_buffer(&minor_stat, &client_name); + (void) gss_release_buffer(&minor_stat, &server_name); +} + +/* + * Function: log_badauth + * + * Purpose: Callback from GSS-API Sun RPC for authentication + * failures/errors. + * + * Arguments: + * major (r) GSS-API major status + * minor (r) GSS-API minor status + * addr (r) originating address + * data (r) arbitrary data (NULL), not used + * + * Effects: + * + * Logs the GSS-API error to stdout. + */ +void rpc_test_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, void *data) +{ + char *a; + + /* Authentication attempt failed: <IP address>, <GSS-API error */ + /* strings> */ + + a = inet_ntoa(addr->sin_addr); + + printf("rpc_test server: Authentication attempt failed: %s", a); + log_badauth_display_status(major, minor); + printf("\n"); +} + +void log_badauth_display_status(OM_uint32 major, OM_uint32 minor) +{ + log_badauth_display_status_1(major, GSS_C_GSS_CODE, 0); + log_badauth_display_status_1(minor, GSS_C_MECH_CODE, 0); +} + +void log_badauth_display_status_1(OM_uint32 code, int type, int rec) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc msg; + int msg_ctx; + + msg_ctx = 0; + while (1) { + gssstat = gss_display_status(&minor_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + if (gssstat != GSS_S_COMPLETE) { + if (!rec) { + log_badauth_display_status_1(gssstat,GSS_C_GSS_CODE,1); + log_badauth_display_status_1(minor_stat, + GSS_C_MECH_CODE, 1); + } else + printf("GSS-API authentication error %s: " + "recursive failure!\n", msg); + return; + } + + printf(", %s", (char *)msg.value); + (void) gss_release_buffer(&minor_stat, &msg); + + if (!msg_ctx) + break; + } +} + + +#if 0 + +/* this hack is no longer necessary, since the library supports it + internally */ + +/* This is a hack to change the default keytab name */ + +#include <krb5/krb5.h> +extern char *krb5_defkeyname; + +krb5_error_code +krb5_kt_default_name(char *name, int namesize) +{ + char *ktname; + + if ((ktname = getenv("KRB5KTNAME")) == NULL) + ktname = krb5_defkeyname; + + if (namesize < strlen(ktname)+1) + return(KRB5_CONFIG_NOTENUFSPACE); + + strcpy(name, ktname); + + return(0); +} + +#endif diff --git a/src/lib/rpc/unit-test/testsuite/Makefile b/src/lib/rpc/unit-test/testsuite/Makefile new file mode 100644 index 000000000..8a2cccdc2 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/Makefile @@ -0,0 +1,24 @@ +# +# $Id$ +# + +TOP = ../../.. +include $(TOP)/config.mk/template + +export RPC_TEST_SRVTAB := /tmp/rpc_test_v5srvtab + +unit-test:: unit-test-setup unit-test-body unit-test-cleanup + +unit-test-setup:: + $(START_SERVERS) + ./rpc_test_setup.sh + +unit-test-body:: + $(RUNTEST) SERVER=../server CLIENT=../client --tool rpc_test + +unit-test-cleanup:: + $(STOP_SERVERS) + -rm -f /tmp/rpc_test_v5srvtab /tmp/krb5cc_rpc_test_fullrun + +clean:: + $(CLEAN) rpc_test.log rpc_test.plog rpc_test.sum rpc_test.psum diff --git a/src/lib/rpc/unit-test/testsuite/config/unix.exp b/src/lib/rpc/unit-test/testsuite/config/unix.exp new file mode 100644 index 000000000..030837d49 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/config/unix.exp @@ -0,0 +1,79 @@ +# +# $Id$ +# + +set kill /bin/kill +set sleep /bin/sleep +set kinit $env(TOP)/install/bin/kinit +set kdestroy $env(TOP)/install/bin/kdestroy + +set hostname [exec hostname] + +proc rpc_test_version {} { + global CLIENT + global SERVER + + clone_output "$CLIENT version <unknown>" + clone_output "$SERVER version <unknown>" +} + +proc rpc_test_load {} { + # +} + +# rpc_test_exit -- clean up and exit +proc rpc_test_exit {} { + global server_id + global server_pid + global server_started + global kill + + if {[catch { + expect { + -i $server_id + eof { + fail "server exited!" + verbose $expect_out(buffer) 1 + } + timeout { pass "server survived" } + } + } tmp]} { + fail "server exited! (expect failed)" + } +} + +# +# rpc_test_start -- start the rpc_test server running +# +proc rpc_test_start { } { + global SERVER + global server_id + global server_pid + global server_started + global env + + set env(KRB5KTNAME) FILE:$env(RPC_TEST_SRVTAB) + + verbose "% $SERVER" 1 + set server_pid [spawn $SERVER] + set server_id $spawn_id + + unset env(KRB5KTNAME) + + set timeout 30 + + expect { + "running" { } + eof { + fail "server exited!" + verbose $expect_out(buffer) 1 + } + timeout { + fail "server didn't start in $timeout seconds" + verbose $expect_out(buffer) 1 + } + } + +} + +rpc_test_start diff --git a/src/lib/rpc/unit-test/testsuite/helpers.exp b/src/lib/rpc/unit-test/testsuite/helpers.exp new file mode 100644 index 000000000..1a37ad512 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/helpers.exp @@ -0,0 +1,128 @@ +if {[info commands exp_version] != {}} { + set exp_version_4 [regexp {^4} [exp_version]] +} else { + set exp_version_4 [regexp {^4} [expect_version]] +} + +# Backward compatibility until we're using expect 5 everywhere +if {$exp_version_4} { + global wait_error_index wait_errno_index wait_status_index + set wait_error_index 0 + set wait_errno_index 1 + set wait_status_index 1 +} else { + set wait_error_index 2 + set wait_errno_index 3 + set wait_status_index 3 +} + + +proc kinit {princ pass lifetime} { + global kinit + global wait_error_index wait_errno_index wait_status_index + + spawn -noecho $kinit -l $lifetime $princ + expect { + -re "Password for $princ.*: " { send "$pass\n" } + timeout { error "Timeout waiting for kinit"; close } + } + expect { eof {} } + + set ret [wait] + if {[lindex $ret $wait_error_index] == -1} { + error \ + "wait(kinit $princ) returned error [lindex $ret $wait_errno_index]" + } else { + if {[lindex $ret $wait_status_index] != 0} { + error \ + "kinit $princ failed with [lindex $ret $wait_status_index]" + } + } +} + +proc flush_server {} { + global server_id + global expect_out + + verbose "flushing server output" 1 + + while {1} { + set timeout 5 + + expect { + -i $server_id + -re "^.+$" { + verbose "server output: $expect_out(buffer)" + } + timeout { break } + } + } +} + +proc start_client {testname ccname user password lifetime count + {target ""}} { + global env + global CLIENT + global hostname + global spawn_id + global verbose + + if {$target == ""} { + set target "server@$hostname" + } + + set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname + kinit $user $password $lifetime + + if {$verbose > 0} { + spawn $CLIENT -a 1 -s 1 -m 1 $hostname $target $count + } else { + spawn $CLIENT $hostname $target $count + } + + verbose "$testname: client $ccname started" + + unset env(KRB5CCNAME) +} + +proc eof_client {testname ccname id status} { + verbose "$testname: eof'ing for client $ccname" 1 + + expect { + -i $id + eof { verbose $expect_out(buffer) 1 } + timeout { + fail "$testname: timeout waiting for client $ccname to exit" + } + } + wait_client $testname $ccname $id $status +} + + +proc wait_client {testname ccname id status} { + global env + global kill + global kdestroy + global wait_error_index wait_errno_index wait_status_index + + verbose "$testname: waiting for client $ccname" 1 + + set ret [wait -i $id] + if {[lindex $ret $wait_error_index] == -1} { + fail \ + "$testname: wait $ccname returned error [lindex $ret $wait_errno_index]" + } else { + if {[lindex $ret $wait_status_index] == $status} { + pass "$testname: client $ccname" + } else { + fail "$testname: client $ccname: unexpected return status [lindex $ret $wait_status_index], should be $status." + } + } + + set env(KRB5CCNAME) FILE:/tmp/krb5cc_rpc_test_$ccname + if {[catch "exec $kdestroy"] != 0} { + error "$testname: cannot destroy client $ccname ccache" + } + + unset env(KRB5CCNAME) +} diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp new file mode 100644 index 000000000..d80bae6da --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/expire.exp @@ -0,0 +1,21 @@ +set timeout 40 + +load_lib "helpers.exp" + +global spawn_id + +start_client expire 1 testuser notathena 20m 100 +set client1_id $spawn_id +flush_server + +start_client expire 2 testuser notathena 40m 300 +set client2_id $spawn_id +flush_server + +start_client expire 3 testuser notathena 60m 500 +set client3_id $spawn_id +flush_server + +eof_client expire 1 $client1_id 0 +eof_client expire 2 $client2_id 0 +eof_client expire 3 $client3_id 0 diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp new file mode 100644 index 000000000..6e8acf80e --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/fullrun.exp @@ -0,0 +1,95 @@ +set timeout 120 + +load_lib "helpers.exp" + +global spawn_id +global server_id + +# Start the client and do a full run +start_client "full run" fullrun testuser notathena 8 1026 +set client_id $spawn_id + +# +# test: did we get 11 dots? +# +verbose "Starting RPC echo test. This will take about 50 seconds.\n" + +set ver_line "rpc_test server: bad verifier\[^\r\n\]*\n" + +set dots 0 +set server_lines 0 +while {1} { + set oldtimeout $timeout + set timeout 5 + while {1} { + expect { + -i $server_id + -re $ver_line { + verbose "Got line from server." + incr server_lines + } + default { + break + } + } + } + set timeout $oldtimeout + expect { + -i $client_id + . { + incr dots + verbose "$expect_out(buffer)" 1 + if ($dots==11) { break } + } + eof { + # + # test: was the exit status right? + # + wait_client "full run" fullrun $client_id 0 + break + } + + timeout { + verbose "Timeout waiting for dot\n" 1 + fail "full run: timeout waiting for dot" + break + } + + } +} +if {$dots==11} { + pass "fullrun: echo test" +} else { + fail "fullrun: echo test: expected 11 dots, got $dots" +} + +# +# test: server logged four bad verifiers? +# +verbose "full run: checking server output" + +# Small timeout, since the server should have already printed everything +set timeout 5 + +while {$server_lines < 4} { + expect { + -i $server_id + -re $ver_line { + incr server_lines + } + -re ".+\r\n" { + verbose "Unexpected server output: $expect_out(buffer)" + } + default { + break + } + } +} + +if {$server_lines == 4} { + pass "fullrun: bad verifiers" +} else { + fail "fullrun: expected four bad verifiers, got $server_lines" +} + +flush_server diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp new file mode 100644 index 000000000..f9d53052d --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test.0/gsserr.exp @@ -0,0 +1,27 @@ +set timeout 30 + +load_lib "helpers.exp" + +global spawn_id +global server_id +global hostname + +start_client "gss err" gsserr testuser notathena 8 1026 notserver@$hostname + +eof_client "gss err" gsserr $spawn_id 2 + +# +# test: server logged an authentication attempted failed? +# +verbose "gss err: checking server output" + +expect { + -i $server_id + -re "rpc_test server: Authent.*failed: .* Wrong princ" { + pass "gss err: server logged auth error" + } + eof { fail "gss err: server exited" } + timeout { fail "gss err: timeout waiting for server output" } +} + +flush_server diff --git a/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh new file mode 100644 index 000000000..2a97af4d3 --- /dev/null +++ b/src/lib/rpc/unit-test/testsuite/rpc_test_setup.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# +# This script performs additional setup for the RPC unit test. It +# assumes that gmake has put TOP and RPC_TEST_SRVTAB into the +# environment. +# +# $Id$ +# $Source$ + +DUMMY=${TESTDIR=$TOP/testing} +DUMMY=${CLNTTCL=$TESTDIR/util/ovsec_kadm_clnt_tcl} +DUMMY=${TCLUTIL=$TESTDIR/tcl/util.t}; export TCLUTIL +DUMMY=${MAKE_KEYTAB=$TESTDIR/scripts/make-host-keytab.pl} + +# If it's set, set it to true +VERBOSE=${VERBOSE_TEST:+true} +# Otherwise, set it to false +DUMMY=${VERBOSE:=false} + +if $VERBOSE; then + REDIRECT= +else + REDIRECT='>/dev/null' +fi + +PATH=$TOP/install/admin:$PATH; export PATH + +CANON_HOST=`perl -e 'chop($_=\`hostname\`);($n,$a,$t,$l,@a)=gethostbyname($_);($_)=gethostbyaddr($a[0],$t); print;'` +export CANON_HOST + +eval $CLNTTCL <<'EOF' $REDIRECT +source $env(TCLUTIL) +set h $env(CANON_HOST) +puts stdout [ovsec_kadm_init admin admin $OVSEC_KADM_ADMIN_SERVICE null $OVSEC_KADM_STRUCT_VERSION $OVSEC_KADM_API_VERSION_1 server_handle] +puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal server/$h] {OVSEC_KADM_PRINCIPAL} admin] +puts stdout [ovsec_kadm_randkey_principal $server_handle server/$h key] +puts stdout [ovsec_kadm_create_principal $server_handle [simple_principal notserver/$h] {OVSEC_KADM_PRINCIPAL} admin] +puts stdout [ovsec_kadm_randkey_principal $server_handle notserver/$h key] +puts stdout [ovsec_kadm_destroy $server_handle] +EOF + +rm -f $RPC_TEST_SRVTAB + +eval $MAKE_KEYTAB -princ server/$CANON_HOST $RPC_TEST_SRVTAB $REDIRECT + +grep -s "$CANON_HOST SECURE-TEST.OV.COM" /etc/krb.realms +if [ $? != 0 ]; then + eval echo \"Adding \$CANON_HOST SECURE-TEST.OV.COM to /etc/krb.realms\" $REDIRECT + ed /etc/krb.realms <<EOF >/dev/null +1i +$CANON_HOST SECURE-TEST.OV.COM +. +w +q +EOF +fi diff --git a/src/lib/rpc/xdr.c b/src/lib/rpc/xdr.c new file mode 100644 index 000000000..7f4418162 --- /dev/null +++ b/src/lib/rpc/xdr.c @@ -0,0 +1,674 @@ +/* @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr.c 1.35 87/08/12"; +#endif + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> +#include <string.h> +char *malloc(); + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * constants specific to the xdr "protocol" + */ +#define XDR_FALSE ((rpc_int32) 0) +#define XDR_TRUE ((rpc_int32) 1) +#define LASTUNSIGNED ((unsigned int) 0-1) + +/* + * for unit alignment + */ +static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; + +/* + * Free a data structure using XDR + * Not a filter, but a convenient utility nonetheless + */ +void +xdr_free(proc, objp) + xdrproc_t proc; + char *objp; +{ + XDR x; + + x.x_op = XDR_FREE; + (*proc)(&x, objp); +} + +/* + * XDR nothing + */ +bool_t +xdr_void(/* xdrs, addr */) + /* XDR *xdrs; */ + /* caddr_t addr; */ +{ + + return (TRUE); +} + +/* + * XDR integers + */ +bool_t +xdr_int(xdrs, ip) + XDR *xdrs; + int *ip; +{ + +#ifdef lint + (void) (xdr_short(xdrs, (short *)ip)); + return (xdr_long(xdrs, (rpc_int32 *)ip)); +#else + if (sizeof (int) >= 4) { + long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *ip; + return (xdr_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_long(xdrs, &l)) { + return (FALSE); + } + *ip = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + } else { + return (xdr_short(xdrs, (short *)ip)); + } +#endif +} + +/* + * XDR unsigned integers + */ +bool_t +xdr_u_int(xdrs, up) + XDR *xdrs; + unsigned int *up; +{ +#ifdef lint + (void) (xdr_short(xdrs, (short *)up)); + return (xdr_u_long(xdrs, (rpc_u_int32 *)up)); +#else + if (sizeof (unsigned int) >= 4) { + unsigned long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *up; + return (xdr_u_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_u_long(xdrs, &l)) { + return (FALSE); + } + *up = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + } else { + return (xdr_short(xdrs, (short *)up)); + } +#endif +} + +/* + * XDR long integers + * same as xdr_u_long - open coded to save a proc call! + */ +bool_t +xdr_long(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + if (xdrs->x_op == XDR_ENCODE) { + if (sizeof (long) > 4) { + /* See if the dereferenced value fits in 4 bytes. If not, return FALSE. + * Check by loading value into a rpc_int32, then loading back and comparing + * results. + */ + rpc_int32 i = (int) *lp; + long l = i; + if (l != *lp) { + return (FALSE); + } + } + return (XDR_PUTLONG(xdrs, lp)); + } + if (xdrs->x_op == XDR_DECODE) + return (XDR_GETLONG(xdrs, lp)); + + if (xdrs->x_op == XDR_FREE) + return (TRUE); + + return (FALSE); +} + +/* + * XDR unsigned long integers + * same as xdr_long - open coded to save a proc call! + */ +bool_t +xdr_u_long(xdrs, ulp) + register XDR *xdrs; + unsigned long *ulp; +{ + if (xdrs->x_op == XDR_ENCODE) { + if (sizeof (unsigned long) > 4) { + /* See if the dereferenced value fits in 4 bytes. If not, return FALSE. + * Check by loading value into a rpc_int32, then loading back and comparing + * results. + */ + unsigned int ui = *ulp; + unsigned long ul = ui; + if (ul != *ulp) { + return (FALSE); + } + } + return (XDR_PUTLONG(xdrs, ulp)); + } + if (xdrs->x_op == XDR_DECODE) { + return (XDR_GETLONG(xdrs, (long *)ulp)); + } + if (xdrs->x_op == XDR_FREE) + return (TRUE); + return (FALSE); +} + +/* + * XDR short integers + */ +bool_t +xdr_short(xdrs, sp) + register XDR *xdrs; + short *sp; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *sp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *sp = (short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR unsigned short integers + */ +bool_t +xdr_u_short(xdrs, usp) + register XDR *xdrs; + unsigned short *usp; +{ + unsigned long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (unsigned long) *usp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *usp = (unsigned short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + + +/* + * XDR a char + */ +bool_t +xdr_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + int i; + + i = (*cp); + if (!xdr_int(xdrs, &i)) { + return (FALSE); + } + *cp = i; + return (TRUE); +} + +/* + * XDR an unsigned char + */ +bool_t +xdr_u_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + unsigned int u; + + u = (*cp); + if (!xdr_u_int(xdrs, &u)) { + return (FALSE); + } + *cp = u; + return (TRUE); +} + +/* + * XDR booleans + */ +bool_t +xdr_bool(xdrs, bp) + register XDR *xdrs; + bool_t *bp; +{ + long lb; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + lb = *bp ? XDR_TRUE : XDR_FALSE; + return (XDR_PUTLONG(xdrs, &lb)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &lb)) { + return (FALSE); + } + *bp = (lb == XDR_FALSE) ? FALSE : TRUE; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR enumerations + */ +bool_t +xdr_enum(xdrs, ep) + XDR *xdrs; + enum_t *ep; +{ +#ifndef lint + enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ + + /* + * enums are treated as ints + */ + if (sizeof (enum sizecheck) == sizeof (rpc_int32)) { + return (xdr_int32(xdrs, (rpc_int32 *)ep)); + } else if (sizeof (enum sizecheck) == sizeof (short)) { + return (xdr_short(xdrs, (short *)ep)); + } else { + return (FALSE); + } +#else + (void) (xdr_short(xdrs, (short *)ep)); + return (xdr_long(xdrs, (long *)ep)); +#endif +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +bool_t +xdr_opaque(xdrs, cp, cnt) + register XDR *xdrs; + caddr_t cp; + register unsigned int cnt; +{ + register unsigned int rndup; + static crud[BYTES_PER_XDR_UNIT]; + + /* + * if no data we are done + */ + if (cnt == 0) + return (TRUE); + + /* + * round byte count to full xdr units + */ + rndup = cnt % BYTES_PER_XDR_UNIT; + if (rndup > 0) + rndup = BYTES_PER_XDR_UNIT - rndup; + + if (xdrs->x_op == XDR_DECODE) { + if (!XDR_GETBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_GETBYTES(xdrs, crud, rndup)); + } + + if (xdrs->x_op == XDR_ENCODE) { + if (!XDR_PUTBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); + } + + if (xdrs->x_op == XDR_FREE) { + return (TRUE); + } + + return (FALSE); +} + +/* + * XDR counted bytes + * *cpp is a pointer to the bytes, *sizep is the count. + * If *cpp is NULL maxsize bytes are allocated + */ +bool_t +xdr_bytes(xdrs, cpp, sizep, maxsize) + register XDR *xdrs; + char **cpp; + register unsigned int *sizep; + unsigned int maxsize; +{ + register char *sp = *cpp; /* sp is the actual string pointer */ + register unsigned int nodesize; + + /* + * first deal with the length since xdr bytes are counted + */ + if (! xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + nodesize = *sizep; + if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (nodesize == 0) { + return (TRUE); + } + if (sp == NULL) { + *cpp = sp = (char *)mem_alloc(nodesize); + } + if (sp == NULL) { + (void) fprintf(stderr, "xdr_bytes: out of memory\n"); + return (FALSE); + } + /* fall into ... */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, nodesize)); + + case XDR_FREE: + if (sp != NULL) { + mem_free(sp, nodesize); + *cpp = NULL; + } + return (TRUE); + } + return (FALSE); +} + +/* + * Implemented here due to commonality of the object. + */ +bool_t +xdr_netobj(xdrs, np) + XDR *xdrs; + struct netobj *np; +{ + + return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); +} + +bool_t +xdr_int32(xdrs, ip) + XDR *xdrs; + rpc_int32 *ip; +{ + long l; + switch (xdrs->x_op) { + case XDR_ENCODE: + l = *ip; + return (xdr_long(xdrs, &l)); + + case XDR_DECODE: + if (!xdr_long(xdrs, &l)) { + return (FALSE); + } + *ip = l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } +} + +xdr_u_int32(xdrs, up) + XDR *xdrs; + rpc_u_int32 *up; +{ + unsigned long ul; + switch (xdrs->x_op) { + case XDR_ENCODE: + ul = *up; + return (xdr_u_long(xdrs, &ul)); + + case XDR_DECODE: + if (!xdr_u_long(xdrs, &ul)) { + return (FALSE); + } + *up = ul; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } +} + +/* + * XDR a descriminated union + * Support routine for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * an entry with a null procedure pointer. The routine gets + * the discriminant value and then searches the array of xdrdiscrims + * looking for that value. It calls the procedure given in the xdrdiscrim + * to handle the discriminant. If there is no specific routine a default + * routine may be called. + * If there is no specific or default routine an error is returned. + */ +bool_t +xdr_union(xdrs, dscmp, unp, choices, dfault) + register XDR *xdrs; + enum_t *dscmp; /* enum to decide which arm to work on */ + char *unp; /* the union itself */ + struct xdr_discrim *choices; /* [value, xdr proc] for each arm */ + xdrproc_t dfault; /* default xdr routine */ +{ + register enum_t dscm; + + /* + * we deal with the discriminator; it's an enum + */ + if (! xdr_enum(xdrs, dscmp)) { + return (FALSE); + } + dscm = *dscmp; + + /* + * search choices for a value that matches the discriminator. + * if we find one, execute the xdr routine for that value. + */ + for (; choices->proc != NULL_xdrproc_t; choices++) { + if (choices->value == dscm) + return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED)); + } + + /* + * no match - execute the default xdr routine if there is one + */ + return ((dfault == NULL_xdrproc_t) ? FALSE : + (*dfault)(xdrs, unp, LASTUNSIGNED)); +} + + +/* + * Non-portable xdr primitives. + * Care should be taken when moving these routines to new architectures. + */ + + +/* + * XDR null terminated ASCII strings + * xdr_string deals with "C strings" - arrays of bytes that are + * terminated by a NULL character. The parameter cpp references a + * pointer to storage; If the pointer is null, then the necessary + * storage is allocated. The last parameter is the max allowed length + * of the string as specified by a protocol. + */ +bool_t +xdr_string(xdrs, cpp, maxsize) + register XDR *xdrs; + char **cpp; + unsigned int maxsize; +{ + register char *sp = *cpp; /* sp is the actual string pointer */ + unsigned int size; + unsigned int nodesize; + + /* + * first deal with the length since xdr strings are counted-strings + */ + switch (xdrs->x_op) { + case XDR_FREE: + if (sp == NULL) { + return(TRUE); /* already free */ + } + /* fall through... */ + case XDR_ENCODE: + size = strlen(sp); + break; + } + if (! xdr_u_int(xdrs, &size)) { + return (FALSE); + } + if (size > maxsize) { + return (FALSE); + } + nodesize = size + 1; + + /* + * now deal with the actual bytes + */ + switch (xdrs->x_op) { + + case XDR_DECODE: + if (nodesize == 0) { + return (TRUE); + } + if (sp == NULL) + *cpp = sp = (char *)mem_alloc(nodesize); + if (sp == NULL) { + (void) fprintf(stderr, "xdr_string: out of memory\n"); + return (FALSE); + } + sp[size] = 0; + /* fall into ... */ + + case XDR_ENCODE: + return (xdr_opaque(xdrs, sp, size)); + + case XDR_FREE: + mem_free(sp, nodesize); + *cpp = NULL; + return (TRUE); + } + return (FALSE); +} + +/* + * Wrapper for xdr_string that can be called directly from + * routines like clnt_call + */ +bool_t +xdr_wrapstring(xdrs, cpp) + XDR *xdrs; + char **cpp; +{ + if (xdr_string(xdrs, cpp, LASTUNSIGNED)) { + return (TRUE); + } + return (FALSE); +} diff --git a/src/lib/rpc/xdr.h b/src/lib/rpc/xdr.h new file mode 100644 index 000000000..9f0819b61 --- /dev/null +++ b/src/lib/rpc/xdr.h @@ -0,0 +1,276 @@ +/* @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* @(#)xdr.h 1.19 87/04/22 SMI */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef __XDR_HEADER__ +#define __XDR_HEADER__ + +/* + * XDR provides a conventional way for converting between C data + * types and an external bit-string representation. Library supplied + * routines provide for the conversion on built-in C data types. These + * routines and utility routines defined here are used to help implement + * a type encode/decode routine for each user-defined type. + * + * Each data type provides a single procedure which takes two arguments: + * + * bool_t + * xdrproc(xdrs, argresp) + * XDR *xdrs; + * <type> *argresp; + * + * xdrs is an instance of a XDR handle, to which or from which the data + * type is to be converted. argresp is a pointer to the structure to be + * converted. The XDR handle contains an operation field which indicates + * which of the operations (ENCODE, DECODE * or FREE) is to be performed. + * + * XDR_DECODE may allocate space if the pointer argresp is null. This + * data can be freed with the XDR_FREE operation. + * + * We write only one procedure per data type to make it easy + * to keep the encode and decode procedures for a data type consistent. + * In many cases the same code performs all operations on a user defined type, + * because all the hard work is done in the component type routines. + * decode as a series of calls on the nested data types. + */ + +/* + * Xdr operations. XDR_ENCODE causes the type to be encoded into the + * stream. XDR_DECODE causes the type to be extracted from the stream. + * XDR_FREE can be used to release the space allocated by an XDR_DECODE + * request. + */ +enum xdr_op { + XDR_ENCODE=0, + XDR_DECODE=1, + XDR_FREE=2 +}; + +/* + * This is the number of bytes per unit of external data. + */ +#define BYTES_PER_XDR_UNIT (4) +#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \ + * BYTES_PER_XDR_UNIT) + +/* + * A xdrproc_t exists for each data type which is to be encoded or decoded. + * + * The second argument to the xdrproc_t is a pointer to an opaque pointer. + * The opaque pointer generally points to a structure of the data type + * to be decoded. If this pointer is 0, then the type routines should + * allocate dynamic storage of the appropriate size and return it. + * bool_t (*xdrproc_t)(XDR *, caddr_t *); + */ +typedef bool_t (*xdrproc_t)(); + +/* + * The XDR handle. + * Contains operation which is being applied to the stream, + * an operations vector for the paticular implementation (e.g. see xdr_mem.c), + * and two private fields for the use of the particular impelementation. + */ +typedef struct { + enum xdr_op x_op; /* operation; fast additional param */ + struct xdr_ops { + bool_t (*x_getlong)(); /* get a long from underlying stream */ + bool_t (*x_putlong)(); /* put a long to " */ + bool_t (*x_getbytes)();/* get some bytes from " */ + bool_t (*x_putbytes)();/* put some bytes to " */ + unsigned int (*x_getpostn)();/* returns bytes off from beginning */ + bool_t (*x_setpostn)();/* lets you reposition the stream */ + rpc_int32 * (*x_inline)(); /* buf quick ptr to buffered data */ + void (*x_destroy)(); /* free privates of this xdr_stream */ + } *x_ops; + caddr_t x_public; /* users' data */ + caddr_t x_private; /* pointer to private data */ + caddr_t x_base; /* private used for position info */ + int x_handy; /* extra private word */ +} XDR; + +/* + * Operations defined on a XDR handle + * + * XDR *xdrs; + * rpc_int32 *longp; + * caddr_t addr; + * unsigned int len; + * unsigned int pos; + */ +#define XDR_GETLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) +#define xdr_getlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_getlong)(xdrs, longp) + +#define XDR_PUTLONG(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) +#define xdr_putlong(xdrs, longp) \ + (*(xdrs)->x_ops->x_putlong)(xdrs, longp) + +#define XDR_GETBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) +#define xdr_getbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len) + +#define XDR_PUTBYTES(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) +#define xdr_putbytes(xdrs, addr, len) \ + (*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len) + +#define XDR_GETPOS(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) +#define xdr_getpos(xdrs) \ + (*(xdrs)->x_ops->x_getpostn)(xdrs) + +#define XDR_SETPOS(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) +#define xdr_setpos(xdrs, pos) \ + (*(xdrs)->x_ops->x_setpostn)(xdrs, pos) + +#define XDR_INLINE(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) +#define xdr_inline(xdrs, len) \ + (*(xdrs)->x_ops->x_inline)(xdrs, len) + +#define XDR_DESTROY(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) +#define xdr_destroy(xdrs) \ + if ((xdrs)->x_ops->x_destroy) \ + (*(xdrs)->x_ops->x_destroy)(xdrs) + +/* + * Support struct for discriminated unions. + * You create an array of xdrdiscrim structures, terminated with + * a entry with a null procedure pointer. The xdr_union routine gets + * the discriminant value and then searches the array of structures + * for a matching value. If a match is found the associated xdr routine + * is called to handle that part of the union. If there is + * no match, then a default routine may be called. + * If there is no match and no default routine it is an error. + */ +#define NULL_xdrproc_t ((xdrproc_t)0) +struct xdr_discrim { + int value; + xdrproc_t proc; +}; + +/* + * In-line routines for fast encode/decode of primitve data types. + * Caveat emptor: these use single memory cycles to get the + * data from the underlying buffer, and will fail to operate + * properly if the data is not aligned. The standard way to use these + * is to say: + * if ((buf = XDR_INLINE(xdrs, count)) == NULL) + * return (FALSE); + * <<< macro calls >>> + * where ``count'' is the number of bytes of data occupied + * by the primitive data types. + * + * N.B. and frozen for all time: each data type here uses 4 bytes + * of external representation. + */ +#define IXDR_GET_LONG(buf) ((long)ntohl((rpc_u_int32)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (rpc_int32)htonl((rpc_u_int32)v)) + +#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf)) +#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_LONG(buf) ((rpc_u_int32)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf) ((unsigned short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((rpc_int32)(v))) + +/* + * These are the "generic" xdr routines. + */ +extern bool_t xdr_void(); +extern bool_t xdr_int(XDR *, int *); +extern bool_t xdr_u_int(XDR *, unsigned int *); +extern bool_t xdr_long(XDR *, long *); +extern bool_t xdr_u_long(XDR *, unsigned long *); +extern bool_t xdr_short(XDR *, short *); +extern bool_t xdr_u_short(XDR *, unsigned short *); +extern bool_t xdr_bool(XDR *, bool_t *); +extern bool_t xdr_enum(XDR *, enum_t *); +extern bool_t xdr_array(XDR *, caddr_t *, unsigned int*, unsigned int, unsigned int, xdrproc_t); +extern bool_t xdr_bytes(XDR *, char **, unsigned int *, unsigned int); +extern bool_t xdr_opaque(XDR *, caddr_t, unsigned int); +extern bool_t xdr_string(XDR *, char **, unsigned int); +extern bool_t xdr_union(XDR *, enum_t *, char *, struct xdr_discrim *, xdrproc_t); +extern bool_t xdr_char(XDR *, char *); +extern bool_t xdr_u_char(XDR *, char *); +extern bool_t xdr_vector(XDR *, char *, unsigned int, unsigned int, xdrproc_t); +extern bool_t xdr_float(XDR *, float *); +extern bool_t xdr_double(XDR *, double *); +extern bool_t xdr_reference(XDR *, caddr_t *, unsigned int, xdrproc_t); +extern bool_t xdr_pointer(XDR *, char **, unsigned int, xdrproc_t); +extern bool_t xdr_wrapstring(XDR *, char **); + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ +#define MAX_NETOBJ_SZ 1024 +struct netobj { + unsigned int n_len; + char *n_bytes; +}; +typedef struct netobj netobj; +extern bool_t xdr_netobj(XDR *, struct netobj *); + +extern bool_t xdr_int32(XDR *, rpc_int32 *); +extern bool_t xdr_u_int32(XDR *, rpc_u_int32 *); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +extern void xdrmem_create(); /* XDR using memory buffers */ +extern void xdrstdio_create(); /* XDR using stdio library */ +extern void xdrrec_create(); /* XDR pseudo records for tcp */ +extern void xdralloc_create(); /* XDR allocating memory buffer */ +extern void xdralloc_release(); /* destroy xdralloc, save buf */ +extern bool_t xdrrec_endofrecord(); /* make end of xdr record */ +extern bool_t xdrrec_skiprecord(); /* move to beginning of next record */ +extern bool_t xdrrec_eof(); /* true if no more input */ +extern caddr_t xdralloc_getdata(); /* get buffer from xdralloc */ + +#endif /* !__XDR_HEADER__ */ diff --git a/src/lib/rpc/xdr_alloc.c b/src/lib/rpc/xdr_alloc.c new file mode 100644 index 000000000..37ae71e82 --- /dev/null +++ b/src/lib/rpc/xdr_alloc.c @@ -0,0 +1,173 @@ +/* @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Header$ + * + * $Log$ + * Revision 1.6 1996/07/22 20:41:21 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.5.4.1 1996/07/18 04:19:49 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.5.2.1 1996/06/20 23:40:30 marc + * File added to the repository on a branch + * + * Revision 1.5 1996/05/12 06:19:25 marc + * renamed lots of types: u_foo to unsigned foo, and foo32 to rpc_foo32. This is to make autoconfiscation less painful. + * + * Revision 1.4 1995/12/13 14:03:14 grier + * Longs to ints for Alpha + * + * Revision 1.3 1993/12/09 18:57:25 bjaspan + * [secure-releng/833] misc bugfixes to admin library + * + * Revision 1.3 1993/12/06 21:23:08 bjaspan + * add xdralloc_release + * + * Revision 1.2 1993/10/26 21:13:19 bjaspan + * add casts for correctness + * + * Revision 1.1 1993/10/19 03:11:39 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <dyn.h> + +static bool_t xdralloc_putlong(); +static bool_t xdralloc_putbytes(); +static unsigned int xdralloc_getpos(); +static rpc_int32 * xdralloc_inline(); +static void xdralloc_destroy(); +static bool_t xdralloc_notsup(); + +static struct xdr_ops xdralloc_ops = { + xdralloc_notsup, + xdralloc_putlong, + xdralloc_notsup, + xdralloc_putbytes, + xdralloc_getpos, + xdralloc_notsup, + xdralloc_inline, + xdralloc_destroy, +}; + +/* + * The procedure xdralloc_create initializes a stream descriptor for a + * memory buffer. + */ +void xdralloc_create(xdrs, op) + register XDR *xdrs; + enum xdr_op op; +{ + xdrs->x_op = op; + xdrs->x_ops = &xdralloc_ops; + xdrs->x_private = (caddr_t) DynCreate(sizeof(char), -4); + /* not allowed to fail */ +} + +caddr_t xdralloc_getdata(xdrs) + XDR *xdrs; +{ + return (caddr_t) DynGet((DynObject) xdrs->x_private, 0); +} + +void xdralloc_release(xdrs) + XDR *xdrs; +{ + DynRelease((DynObject) xdrs->x_private); +} + +static void xdralloc_destroy(xdrs) + XDR *xdrs; +{ + DynDestroy((DynObject) xdrs->x_private); +} + +static bool_t xdralloc_notsup() +{ + return FALSE; +} + +static bool_t xdralloc_putlong(xdrs, lp) + register XDR *xdrs; + rpc_int32 *lp; +{ + int l = htonl((rpc_u_int32) *(int *)lp); + + if (DynInsert((DynObject) xdrs->x_private, + DynSize((DynObject) xdrs->x_private), &l, + sizeof(int)) != DYN_OK) + return FALSE; + return (TRUE); +} + +static bool_t xdralloc_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + if (DynInsert((DynObject) xdrs->x_private, + DynSize((DynObject) xdrs->x_private), + addr, len) != DYN_OK) + return FALSE; + return TRUE; +} + +static unsigned int xdralloc_getpos(xdrs) + register XDR *xdrs; +{ + return DynSize((DynObject) xdrs->x_private); +} + + +static rpc_int32 *xdralloc_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + return (rpc_int32 *) 0; +} diff --git a/src/lib/rpc/xdr_array.c b/src/lib/rpc/xdr_array.c new file mode 100644 index 000000000..09bd50abd --- /dev/null +++ b/src/lib/rpc/xdr_array.c @@ -0,0 +1,153 @@ +/* @(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_array.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * arrays. See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED ((unsigned int)0-1) + + +/* + * XDR an array of arbitrary elements + * *addrp is a pointer to the array, *sizep is the number of elements. + * If addrp is NULL (*sizep * elsize) bytes are allocated. + * elsize is the size (in bytes) of each element, and elproc is the + * xdr procedure to call to handle each element of the array. + */ +bool_t +xdr_array(xdrs, addrp, sizep, maxsize, elsize, elproc) + register XDR *xdrs; + caddr_t *addrp; /* array pointer */ + unsigned int *sizep; /* number of elements */ + unsigned int maxsize; /* max numberof elements */ + unsigned int elsize; /* size in bytes of each element */ + xdrproc_t elproc; /* xdr routine to handle each element */ +{ + register unsigned int i; + register caddr_t target = *addrp; + register unsigned int c; /* the actual element count */ + register bool_t stat = TRUE; + register unsigned int nodesize; + + /* like strings, arrays are really counted arrays */ + if (! xdr_u_int(xdrs, sizep)) { + return (FALSE); + } + c = *sizep; + if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) { + return (FALSE); + } + nodesize = c * elsize; + + /* + * if we are deserializing, we may need to allocate an array. + * We also save time by checking for a null array if we are freeing. + */ + if (target == NULL) + switch (xdrs->x_op) { + case XDR_DECODE: + if (c == 0) + return (TRUE); + *addrp = target = mem_alloc(nodesize); + if (target == NULL) { + (void) fprintf(stderr, + "xdr_array: out of memory\n"); + return (FALSE); + } + memset(target, 0, nodesize); + break; + + case XDR_FREE: + return (TRUE); + } + + /* + * now we xdr each element of array + */ + for (i = 0; (i < c) && stat; i++) { + stat = (*elproc)(xdrs, target, LASTUNSIGNED); + target += elsize; + } + + /* + * the array may need freeing + */ + if (xdrs->x_op == XDR_FREE) { + mem_free(*addrp, nodesize); + *addrp = NULL; + } + return (stat); +} + +/* + * xdr_vector(): + * + * XDR a fixed length array. Unlike variable-length arrays, + * the storage of fixed length arrays is static and unfreeable. + * > basep: base of the array + * > size: size of the array + * > elemsize: size of each element + * > xdr_elem: routine to XDR each element + */ +bool_t +xdr_vector(xdrs, basep, nelem, elemsize, xdr_elem) + register XDR *xdrs; + register char *basep; + register unsigned int nelem; + register unsigned int elemsize; + register xdrproc_t xdr_elem; +{ + register unsigned int i; + register char *elptr; + + elptr = basep; + for (i = 0; i < nelem; i++) { + if (! (*xdr_elem)(xdrs, elptr, LASTUNSIGNED)) { + return(FALSE); + } + elptr += elemsize; + } + return(TRUE); +} + diff --git a/src/lib/rpc/xdr_float.c b/src/lib/rpc/xdr_float.c new file mode 100644 index 000000000..0c153c472 --- /dev/null +++ b/src/lib/rpc/xdr_float.c @@ -0,0 +1,293 @@ +/* @(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_float.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These are the "floating point" xdr routines used to (de)serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include <stdio.h> + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * NB: Not portable. + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ +#ifdef IGNORE + +#ifdef vax + +/* What IEEE single precision floating point looks like on a Vax */ +struct ieee_single { + unsigned int mantissa: 23; + unsigned int exp : 8; + unsigned int sign : 1; +}; + +/* Vax single precision floating point */ +struct vax_single { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; +}; + +#define VAX_SNG_BIAS 0x81 +#define IEEE_SNG_BIAS 0x7f + +static struct sgl_limits { + struct vax_single s; + struct ieee_single ieee; +} sgl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */ + { 0x0, 0xff, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */ + { 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; +#endif /* vax */ + +bool_t +xdr_float(xdrs, fp) + register XDR *xdrs; + register float *fp; +{ +#if defined(vax) + struct ieee_single is; + struct vax_single vs, *vsp; + struct sgl_limits *lim; + int i; +#endif + long lg; + + switch (xdrs->x_op) { + + case XDR_ENCODE: +#if !defined(vax) + lg = * (int_32 *) fp; + return (XDR_PUTLONG(xdrs, &lg)); +#else + vs = *((struct vax_single *)fp); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((vs.mantissa2 == lim->s.mantissa2) && + (vs.exp == lim->s.exp) && + (vs.mantissa1 == lim->s.mantissa1)) { + is = lim->ieee; + goto shipit; + } + } + is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS; + is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2; + shipit: + is.sign = vs.sign; + return (XDR_PUTLONG(xdrs, (rpc_int32 *)&is)); +#endif + + case XDR_DECODE: +#if !defined(vax) + if (!(XDR_GETLONG(xdrs, &lg))) { + return (FALSE); + } + *fp = (float) ((int) lg); + return (TRUE); +#else + vsp = (struct vax_single *)fp; + if (!XDR_GETLONG(xdrs, (rpc_int32 *)&is)) + return (FALSE); + for (i = 0, lim = sgl_limits; + i < sizeof(sgl_limits)/sizeof(struct sgl_limits); + i++, lim++) { + if ((is.exp == lim->ieee.exp) && + (is.mantissa == lim->ieee.mantissa)) { + *vsp = lim->s; + goto doneit; + } + } + vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS; + vsp->mantissa2 = is.mantissa; + vsp->mantissa1 = (is.mantissa >> 16); + doneit: + vsp->sign = is.sign; + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * This routine works on Suns (Sky / 68000's) and Vaxen. + */ + +#ifdef vax +/* What IEEE double precision floating point looks like on a Vax */ +struct ieee_double { + unsigned int mantissa1 : 20; + unsigned int exp : 11; + unsigned int sign : 1; + unsigned int mantissa2 : 32; +}; + +/* Vax double precision floating point */ +struct vax_double { + unsigned int mantissa1 : 7; + unsigned int exp : 8; + unsigned int sign : 1; + unsigned int mantissa2 : 16; + unsigned int mantissa3 : 16; + unsigned int mantissa4 : 16; +}; + +#define VAX_DBL_BIAS 0x81 +#define IEEE_DBL_BIAS 0x3ff +#define MASK(nbits) ((1 << nbits) - 1) + +static struct dbl_limits { + struct vax_double d; + struct ieee_double ieee; +} dbl_limits[2] = { + {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */ + { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */ + {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */ + { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */ +}; + +#endif /* vax */ + + +bool_t +xdr_double(xdrs, dp) + register XDR *xdrs; + double *dp; +{ + register rpc_int32 *lp; +#if defined(vax) + struct ieee_double id; + struct vax_double vd; + register struct dbl_limits *lim; + int i; +#endif + + switch (xdrs->x_op) { + + case XDR_ENCODE: +#if !defined(vax) + lp = (rpc_int32 *)dp; + if (sizeof(rpc_int32) == sizeof(long)) { + return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); + } else { + long lg1 = *lp++;; + long lg2 = *lp; + return (XDR_PUTLONG(xdrs, &lg1) && XDR_PUTLONG(xdrs, &lg2)); + } +#else + vd = *((struct vax_double *)dp); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((vd.mantissa4 == lim->d.mantissa4) && + (vd.mantissa3 == lim->d.mantissa3) && + (vd.mantissa2 == lim->d.mantissa2) && + (vd.mantissa1 == lim->d.mantissa1) && + (vd.exp == lim->d.exp)) { + id = lim->ieee; + goto shipit; + } + } + id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS; + id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3); + id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) | + (vd.mantissa3 << 13) | + ((vd.mantissa4 >> 3) & MASK(13)); + shipit: + id.sign = vd.sign; + lp = (rpc_int32 *)&id; + return (XDR_PUTLONG(xdrs, lp++) && XDR_PUTLONG(xdrs, lp)); +#endif + + case XDR_DECODE: +#if !defined(vax) + lp = (rpc_int32 *)dp; + if (sizeof(rpc_int32) == sizeof(long)) { + return (XDR_GETLONG(xdrs, lp++) && XDR_GETLONG(xdrs, lp)); + } else { + long lg1, lg2; + bool_t flag = + (XDR_GETLONG(xdrs, &lg1) && XDR_GETLONG(xdrs, &lg2)); + *lp++ = lg1; + *lp = lg2; + return flag; + } +#else + lp = (rpc_int32 *)&id; + if (!XDR_GETLONG(xdrs, lp++) || !XDR_GETLONG(xdrs, lp)) + return (FALSE); + for (i = 0, lim = dbl_limits; + i < sizeof(dbl_limits)/sizeof(struct dbl_limits); + i++, lim++) { + if ((id.mantissa2 == lim->ieee.mantissa2) && + (id.mantissa1 == lim->ieee.mantissa1) && + (id.exp == lim->ieee.exp)) { + vd = lim->d; + goto doneit; + } + } + vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS; + vd.mantissa1 = (id.mantissa1 >> 13); + vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) | + (id.mantissa2 >> 29); + vd.mantissa3 = (id.mantissa2 >> 13); + vd.mantissa4 = (id.mantissa2 << 3); + doneit: + vd.sign = id.sign; + *dp = *((double *)&vd); + return (TRUE); +#endif + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +#endif /* IGNORE */ diff --git a/src/lib/rpc/xdr_mem.c b/src/lib/rpc/xdr_mem.c new file mode 100644 index 000000000..39c0df203 --- /dev/null +++ b/src/lib/rpc/xdr_mem.c @@ -0,0 +1,188 @@ +/* @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * If you have some data to be interpreted as external data representation + * or to be converted to external data representation in a memory buffer, + * then this is the package for you. + * + */ + + +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> +#include <stdio.h> + +static bool_t xdrmem_getlong(); +static bool_t xdrmem_putlong(); +static bool_t xdrmem_getbytes(); +static bool_t xdrmem_putbytes(); +static unsigned int xdrmem_getpos(); +static bool_t xdrmem_setpos(); +static rpc_int32 * xdrmem_inline(); +static void xdrmem_destroy(); + +static struct xdr_ops xdrmem_ops = { + xdrmem_getlong, + xdrmem_putlong, + xdrmem_getbytes, + xdrmem_putbytes, + xdrmem_getpos, + xdrmem_setpos, + xdrmem_inline, + xdrmem_destroy +}; + +/* + * The procedure xdrmem_create initializes a stream descriptor for a + * memory buffer. + */ +void +xdrmem_create(xdrs, addr, size, op) + register XDR *xdrs; + caddr_t addr; + unsigned int size; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = &xdrmem_ops; + xdrs->x_private = xdrs->x_base = addr; + xdrs->x_handy = size; +} + +static void +xdrmem_destroy(/*xdrs*/) + /*XDR *xdrs;*/ +{ +} + +static bool_t +xdrmem_getlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0) + return (FALSE); + *lp = (long)ntohl(*((rpc_u_int32 *)(xdrs->x_private))); + xdrs->x_private += sizeof(rpc_int32); + return (TRUE); +} + +static bool_t +xdrmem_putlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + if ((xdrs->x_handy -= sizeof(rpc_int32)) < 0) + return (FALSE); + *(rpc_int32 *)xdrs->x_private = (rpc_int32)htonl((rpc_u_int32)(*lp)); + xdrs->x_private += sizeof(rpc_int32); + return (TRUE); +} + +static bool_t +xdrmem_getbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + + if ((xdrs->x_handy -= len) < 0) + return (FALSE); + memmove(addr, xdrs->x_private, len); + xdrs->x_private += len; + return (TRUE); +} + +static bool_t +xdrmem_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register unsigned int len; +{ + + if ((xdrs->x_handy -= len) < 0) + return (FALSE); + memmove(xdrs->x_private, addr, len); + xdrs->x_private += len; + return (TRUE); +} + +static unsigned int +xdrmem_getpos(xdrs) + register XDR *xdrs; +{ +/* + * 11/3/95 - JRG - Rather than recast everything for 64 bit, just convert + * pointers to longs, then cast to int. + */ + return (unsigned int)((unsigned long)xdrs->x_private - (unsigned long)xdrs->x_base); +} + +static bool_t +xdrmem_setpos(xdrs, pos) + register XDR *xdrs; + unsigned int pos; +{ + register caddr_t newaddr = xdrs->x_base + pos; + register caddr_t lastaddr = xdrs->x_private + xdrs->x_handy; + + if ((long)newaddr > (long)lastaddr) + return (FALSE); + xdrs->x_private = newaddr; + xdrs->x_handy = (int)((long)lastaddr - (long)newaddr); + return (TRUE); +} + +static rpc_int32 * +xdrmem_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + rpc_int32 *buf = 0; + + if (xdrs->x_handy >= len) { + xdrs->x_handy -= len; + buf = (rpc_int32 *) xdrs->x_private; + xdrs->x_private += len; + } + return (buf); +} diff --git a/src/lib/rpc/xdr_rec.c b/src/lib/rpc/xdr_rec.c new file mode 100644 index 000000000..99ce9235a --- /dev/null +++ b/src/lib/rpc/xdr_rec.c @@ -0,0 +1,596 @@ +/* @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" + * layer above tcp (for rpc's use). + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * These routines interface XDRSTREAMS to a tcp/ip connection. + * There is a record marking layer between the xdr stream + * and the tcp transport level. A record is composed on one or more + * record fragments. A record fragment is a thirty-two bit header followed + * by n bytes of data, where n is contained in the header. The header + * is represented as a htonl(rpc_u_int32). Thegh order bit encodes + * whether or not the fragment is the last fragment of the record + * (1 => fragment is last, 0 => more fragments to follow. + * The other 31 bits encode the byte length of the fragment. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <netinet/in.h> + +#include <unistd.h> + +static unsigned int fix_buf_size(); +static bool_t flush_out(); +static bool_t get_input_bytes(); +static bool_t set_input_fragment(); +static bool_t skip_input_bytes(); + +static bool_t xdrrec_getlong(); +static bool_t xdrrec_putlong(); +static bool_t xdrrec_getbytes(); +static bool_t xdrrec_putbytes(); +static unsigned int xdrrec_getpos(); +static bool_t xdrrec_setpos(); +static rpc_int32 * xdrrec_inline(); +static void xdrrec_destroy(); + +static struct xdr_ops xdrrec_ops = { + xdrrec_getlong, + xdrrec_putlong, + xdrrec_getbytes, + xdrrec_putbytes, + xdrrec_getpos, + xdrrec_setpos, + xdrrec_inline, + xdrrec_destroy +}; + +/* + * A record is composed of one or more record fragments. + * A record fragment is a two-byte header followed by zero to + * 2**32-1 bytes. The header is treated as an unsigned 32 bit integer and is + * encode/decoded to the network via htonl/ntohl. The low order 31 bits + * are a byte count of the fragment. The highest order bit is a boolean: + * 1 => this fragment is the last fragment of the record, + * 0 => this fragment is followed by more fragment(s). + * + * The fragment/record machinery is not general; it is constructed to + * meet the needs of xdr and rpc based on tcp. + */ + +#define LAST_FRAG ((rpc_u_int32)(1 << 31)) + +typedef struct rec_strm { + caddr_t tcp_handle; + caddr_t the_buffer; + /* + * out-goung bits + */ + int (*writeit)(); + caddr_t out_base; /* output buffer (points to frag header) */ + caddr_t out_finger; /* next output position */ + caddr_t out_boundry; /* data cannot up to this address */ + rpc_u_int32 *frag_header; /* beginning of curren fragment */ + bool_t frag_sent; /* true if buffer sent in middle of record */ + /* + * in-coming bits + */ + int (*readit)(); + rpc_u_int32 in_size; /* fixed size of the input buffer */ + caddr_t in_base; + caddr_t in_finger; /* location of next byte to be had */ + caddr_t in_boundry; /* can read up to this location */ + rpc_int32 fbtbc; /* fragment bytes to be consumed */ + bool_t last_frag; + unsigned int sendsize; + unsigned int recvsize; +} RECSTREAM; + + +/* + * Create an xdr handle for xdrrec + * xdrrec_create fills in xdrs. Sendsize and recvsize are + * send and recv buffer sizes (0 => use default). + * tcp_handle is an opaque handle that is passed as the first parameter to + * the procedures readit and writeit. Readit and writeit are read and + * write respectively. They are like the system + * calls expect that they take an opaque handle rather than an fd. + */ +void +xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) + register XDR *xdrs; + register unsigned int sendsize; + register unsigned int recvsize; + caddr_t tcp_handle; + int (*readit)(); /* like read, but pass it a tcp_handle, not sock */ + int (*writeit)(); /* like write, but pass it a tcp_handle, not sock */ +{ + register RECSTREAM *rstrm = + (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); + + if (rstrm == NULL) { + (void)fprintf(stderr, "xdrrec_create: out of memory\n"); + /* + * This is bad. Should rework xdrrec_create to + * return a handle, and in this case return NULL + */ + return; + } + /* + * adjust sizes and allocate buffer quad byte aligned + */ + rstrm->sendsize = sendsize = fix_buf_size(sendsize); + rstrm->recvsize = recvsize = fix_buf_size(recvsize); + rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); + if (rstrm->the_buffer == NULL) { + (void)fprintf(stderr, "xdrrec_create: out of memory\n"); + return; + } + for (rstrm->out_base = rstrm->the_buffer; + /* Pointer arithmetic - long cast allowed... */ + (unsigned long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; + rstrm->out_base++); + rstrm->in_base = rstrm->out_base + sendsize; + /* + * now the rest ... + */ + xdrs->x_ops = &xdrrec_ops; + xdrs->x_private = (caddr_t)rstrm; + rstrm->tcp_handle = tcp_handle; + rstrm->readit = readit; + rstrm->writeit = writeit; + rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_base; + rstrm->out_finger += sizeof(rpc_u_int32); + rstrm->out_boundry += sendsize; + rstrm->frag_sent = FALSE; + rstrm->in_size = recvsize; + rstrm->in_boundry = rstrm->in_base; + rstrm->in_finger = (rstrm->in_boundry += recvsize); + rstrm->fbtbc = 0; + rstrm->last_frag = TRUE; +} + + +/* + * The reoutines defined below are the xdr ops which will go into the + * xdr handle filled in by xdrrec_create. + */ + +static bool_t +xdrrec_getlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_int32 *buflp = (rpc_int32 *)(rstrm->in_finger); + int mylong; + + /* first try the inline, fast case */ + if ((rstrm->fbtbc >= sizeof(rpc_int32)) && + (((long)rstrm->in_boundry - (long)buflp) >= sizeof(rpc_int32))) { + *lp = (long)ntohl((rpc_u_int32)(*buflp)); + rstrm->fbtbc -= sizeof(rpc_int32); + rstrm->in_finger += sizeof(rpc_int32); + } else { + if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(rpc_int32))) + return (FALSE); + *lp = (long)ntohl((unsigned int)mylong); + } + return (TRUE); +} + +static bool_t +xdrrec_putlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_int32 *dest_lp = ((rpc_int32 *)(rstrm->out_finger)); + + if ((rstrm->out_finger += sizeof(rpc_int32)) > rstrm->out_boundry) { + /* + * this case should almost never happen so the code is + * inefficient + */ + rstrm->out_finger -= sizeof(rpc_int32); + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + dest_lp = ((rpc_int32 *)(rstrm->out_finger)); + rstrm->out_finger += sizeof(rpc_int32); + } + *dest_lp = (rpc_int32)htonl((rpc_u_int32)(*lp)); + return (TRUE); +} + +static bool_t /* must manage buffers, fragments, and records */ +xdrrec_getbytes(xdrs, addr, len) + XDR *xdrs; + register caddr_t addr; + register unsigned int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register int current; + + while (len > 0) { + current = rstrm->fbtbc; + if (current == 0) { + if (rstrm->last_frag) + return (FALSE); + if (! set_input_fragment(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + if (! get_input_bytes(rstrm, addr, current)) + return (FALSE); + addr += current; + rstrm->fbtbc -= current; + len -= current; + } + return (TRUE); +} + +static bool_t +xdrrec_putbytes(xdrs, addr, len) + XDR *xdrs; + register caddr_t addr; + register unsigned int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register int current; + + while (len > 0) { + current = (int) ((long)rstrm->out_boundry - + (long)rstrm->out_finger); + current = (len < current) ? len : current; + memmove(rstrm->out_finger, addr, current); + rstrm->out_finger += current; + addr += current; + len -= current; + if (rstrm->out_finger == rstrm->out_boundry) { + rstrm->frag_sent = TRUE; + if (! flush_out(rstrm, FALSE)) + return (FALSE); + } + } + return (TRUE); +} + +static unsigned int +xdrrec_getpos(xdrs) + register XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + register int pos; + +/* 11/5/95 JRG HELP! lseek() can't take a pointer as the first arg + * This code must have always failed, and the failure let the arithmetic + * calculations proceed + */ +#ifdef __osf__ + pos = -1; +#else + pos = lseek((int)rstrm->tcp_handle, (long) 0, 1); +#endif + if (pos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + pos += rstrm->out_finger - rstrm->out_base; + break; + + case XDR_DECODE: + pos -= rstrm->in_boundry - rstrm->in_finger; + break; + + default: + pos = (unsigned int) -1; + break; + } + return ((unsigned int) pos); +} + +static bool_t +xdrrec_setpos(xdrs, pos) + register XDR *xdrs; + unsigned int pos; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + unsigned int currpos = xdrrec_getpos(xdrs); + int delta = currpos - pos; + caddr_t newpos; + + if ((int)currpos != -1) + switch (xdrs->x_op) { + + case XDR_ENCODE: + newpos = rstrm->out_finger - delta; + if ((newpos > (caddr_t)(rstrm->frag_header)) && + (newpos < rstrm->out_boundry)) { + rstrm->out_finger = newpos; + return (TRUE); + } + break; + + case XDR_DECODE: + newpos = rstrm->in_finger - delta; + if ((delta < (int)(rstrm->fbtbc)) && + (newpos <= rstrm->in_boundry) && + (newpos >= rstrm->in_base)) { + rstrm->in_finger = newpos; + rstrm->fbtbc -= delta; + return (TRUE); + } + break; + } + return (FALSE); +} + +static rpc_int32 * +xdrrec_inline(xdrs, len) + register XDR *xdrs; + int len; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + rpc_int32 * buf = NULL; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + if ((rstrm->out_finger + len) <= rstrm->out_boundry) { + buf = (rpc_int32 *) rstrm->out_finger; + rstrm->out_finger += len; + } + break; + + case XDR_DECODE: + if ((len <= rstrm->fbtbc) && + ((rstrm->in_finger + len) <= rstrm->in_boundry)) { + buf = (rpc_int32 *) rstrm->in_finger; + rstrm->fbtbc -= len; + rstrm->in_finger += len; + } + break; + } + return (buf); +} + +static void +xdrrec_destroy(xdrs) + register XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; + + mem_free(rstrm->the_buffer, + rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); + mem_free((caddr_t)rstrm, sizeof(RECSTREAM)); +} + + +/* + * Exported routines to manage xdr records + */ + +/* + * Before reading (deserializing from the stream, one should always call + * this procedure to guarantee proper record alignment. + */ +bool_t +xdrrec_skiprecord(xdrs) + XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (FALSE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (FALSE); + } + rstrm->last_frag = FALSE; + return (TRUE); +} + +/* + * Look ahead fuction. + * Returns TRUE iff there is no more input in the buffer + * after consuming the rest of the current record. + */ +bool_t +xdrrec_eof(xdrs) + XDR *xdrs; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + + while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { + if (! skip_input_bytes(rstrm, rstrm->fbtbc)) + return (TRUE); + rstrm->fbtbc = 0; + if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) + return (TRUE); + } + if (rstrm->in_finger == rstrm->in_boundry) + return (TRUE); + return (FALSE); +} + +/* + * The client must tell the package when an end-of-record has occurred. + * The second paraemters tells whether the record should be flushed to the + * (output) tcp stream. (This let's the package support batched or + * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. + */ +bool_t +xdrrec_endofrecord(xdrs, sendnow) + XDR *xdrs; + bool_t sendnow; +{ + register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); + register rpc_u_int32 len; /* fragment length */ + + if (sendnow || rstrm->frag_sent || + ((long)rstrm->out_finger + sizeof(unsigned int) >= + (long)rstrm->out_boundry)) { + rstrm->frag_sent = FALSE; + return (flush_out(rstrm, TRUE)); + } + len = (long)(rstrm->out_finger) - (long)(rstrm->frag_header) - + sizeof(unsigned int); + *(rstrm->frag_header) = htonl((unsigned int)len | LAST_FRAG); + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_finger; + rstrm->out_finger += sizeof(unsigned int); + return (TRUE); +} + + +/* + * Internal useful routines + */ +static bool_t +flush_out(rstrm, eor) + register RECSTREAM *rstrm; + bool_t eor; +{ + register rpc_u_int32 eormask = (eor == TRUE) ? LAST_FRAG : 0; + register rpc_u_int32 len = (unsigned long)(rstrm->out_finger) - + (unsigned long)(rstrm->frag_header) - sizeof(rpc_u_int32); + + *(rstrm->frag_header) = htonl(len | eormask); + len = (unsigned long)(rstrm->out_finger) - (unsigned long)(rstrm->out_base); + if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) + != (int)len) + return (FALSE); + rstrm->frag_header = (rpc_u_int32 *)rstrm->out_base; + rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(rpc_u_int32); + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +fill_input_buf(rstrm) + register RECSTREAM *rstrm; +{ + register caddr_t where; + unsigned int i; + register int len; + + where = rstrm->in_base; + i = (unsigned int)((unsigned long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); + where += i; + len = rstrm->in_size - i; + if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) + return (FALSE); + rstrm->in_finger = where; + where += len; + rstrm->in_boundry = where; + return (TRUE); +} + +static bool_t /* knows nothing about records! Only about input buffers */ +get_input_bytes(rstrm, addr, len) + register RECSTREAM *rstrm; + register caddr_t addr; + register int len; +{ + register int current; + + while (len > 0) { + current = (int)((long)rstrm->in_boundry - + (long)rstrm->in_finger); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (len < current) ? len : current; + memmove(addr, rstrm->in_finger, current); + rstrm->in_finger += current; + addr += current; + len -= current; + } + return (TRUE); +} + +static bool_t /* next two bytes of the input stream are treated as a header */ +set_input_fragment(rstrm) + register RECSTREAM *rstrm; +{ + rpc_u_int32 header; + + if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) + return (FALSE); + header = (int)ntohl(header); + rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; + rstrm->fbtbc = header & (~LAST_FRAG); + return (TRUE); +} + +static bool_t /* consumes input bytes; knows nothing about records! */ +skip_input_bytes(rstrm, cnt) + register RECSTREAM *rstrm; + rpc_int32 cnt; +{ + register int current; + + while (cnt > 0) { + current = (int)((long)rstrm->in_boundry - + (long)rstrm->in_finger); + if (current == 0) { + if (! fill_input_buf(rstrm)) + return (FALSE); + continue; + } + current = (cnt < current) ? cnt : current; + rstrm->in_finger += current; + cnt -= current; + } + return (TRUE); +} + +static unsigned int +fix_buf_size(s) + register unsigned int s; +{ + + if (s < 100) + s = 4000; + return (RNDUP(s)); +} diff --git a/src/lib/rpc/xdr_reference.c b/src/lib/rpc/xdr_reference.c new file mode 100644 index 000000000..ebf14b68e --- /dev/null +++ b/src/lib/rpc/xdr_reference.c @@ -0,0 +1,132 @@ +/* @(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_reference.c 1.11 87/08/11 SMI"; +#endif + +/* + * xdr_reference.c, Generic XDR routines impelmentation. + * + * Copyright (C) 1987, Sun Microsystems, Inc. + * + * These are the "non-trivial" xdr primitives used to serialize and de-serialize + * "pointers". See xdr.h for more info on the interface to xdr. + */ + +#include <stdio.h> +#include <rpc/types.h> +#include <rpc/xdr.h> + +#define LASTUNSIGNED ((unsigned int)0-1) + +/* + * XDR an indirect pointer + * xdr_reference is for recursively translating a structure that is + * referenced by a pointer inside the structure that is currently being + * translated. pp references a pointer to storage. If *pp is null + * the necessary storage is allocated. + * size is the sizeof the referneced structure. + * proc is the routine to handle the referenced structure. + */ +bool_t +xdr_reference(xdrs, pp, size, proc) + register XDR *xdrs; + caddr_t *pp; /* the pointer to work on */ + unsigned int size; /* size of the object pointed to */ + xdrproc_t proc; /* xdr routine to handle the object */ +{ + register caddr_t loc = *pp; + register bool_t stat; + + if (loc == NULL) + switch (xdrs->x_op) { + case XDR_FREE: + return (TRUE); + + case XDR_DECODE: + *pp = loc = (caddr_t) mem_alloc(size); + if (loc == NULL) { + (void) fprintf(stderr, + "xdr_reference: out of memory\n"); + return (FALSE); + } + memset(loc, 0, (int)size); + break; + } + + stat = (*proc)(xdrs, loc, LASTUNSIGNED); + + if (xdrs->x_op == XDR_FREE) { + mem_free(loc, size); + *pp = NULL; + } + return (stat); +} + + +/* + * xdr_pointer(): + * + * XDR a pointer to a possibly recursive data structure. This + * differs with xdr_reference in that it can serialize/deserialiaze + * trees correctly. + * + * What's sent is actually a union: + * + * union object_pointer switch (boolean b) { + * case TRUE: object_data data; + * case FALSE: void nothing; + * } + * + * > objpp: Pointer to the pointer to the object. + * > obj_size: size of the object. + * > xdr_obj: routine to XDR an object. + * + */ +bool_t +xdr_pointer(xdrs,objpp,obj_size,xdr_obj) + register XDR *xdrs; + char **objpp; + unsigned int obj_size; + xdrproc_t xdr_obj; +{ + + bool_t more_data; + + more_data = (*objpp != NULL); + if (! xdr_bool(xdrs,&more_data)) { + return (FALSE); + } + if (! more_data) { + *objpp = NULL; + return (TRUE); + } + return (xdr_reference(xdrs,objpp,obj_size,xdr_obj)); +} diff --git a/src/lib/rpc/xdr_stdio.c b/src/lib/rpc/xdr_stdio.c new file mode 100644 index 000000000..6d59ad5c6 --- /dev/null +++ b/src/lib/rpc/xdr_stdio.c @@ -0,0 +1,189 @@ +/* @(#)xdr_stdio.c 2.1 88/07/29 4.0 RPCSRC */ +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +#if !defined(lint) && defined(SCCSIDS) +static char sccsid[] = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro"; +#endif + +/* + * xdr_stdio.c, XDR implementation on standard i/o file. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * This set of routines implements a XDR on a stdio stream. + * XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes + * from the stream. + */ + +#include <rpc/types.h> +#include <stdio.h> +#include <rpc/xdr.h> + +static bool_t xdrstdio_getlong(); +static bool_t xdrstdio_putlong(); +static bool_t xdrstdio_getbytes(); +static bool_t xdrstdio_putbytes(); +static unsigned int xdrstdio_getpos(); +static bool_t xdrstdio_setpos(); +static rpc_int32 * xdrstdio_inline(); +static void xdrstdio_destroy(); + +/* + * Ops vector for stdio type XDR + */ +static struct xdr_ops xdrstdio_ops = { + xdrstdio_getlong, /* deseraialize a long int */ + xdrstdio_putlong, /* seraialize a long int */ + xdrstdio_getbytes, /* deserialize counted bytes */ + xdrstdio_putbytes, /* serialize counted bytes */ + xdrstdio_getpos, /* get offset in the stream */ + xdrstdio_setpos, /* set offset in the stream */ + xdrstdio_inline, /* prime stream for inline macros */ + xdrstdio_destroy /* destroy stream */ +}; + +/* + * Initialize a stdio xdr stream. + * Sets the xdr stream handle xdrs for use on the stream file. + * Operation flag is set to op. + */ +void +xdrstdio_create(xdrs, file, op) + register XDR *xdrs; + FILE *file; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = &xdrstdio_ops; + xdrs->x_private = (caddr_t)file; + xdrs->x_handy = 0; + xdrs->x_base = 0; +} + +/* + * Destroy a stdio xdr stream. + * Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create. + */ +static void +xdrstdio_destroy(xdrs) + register XDR *xdrs; +{ + (void)fflush((FILE *)xdrs->x_private); + /* xx should we close the file ?? */ +} + +static bool_t +xdrstdio_getlong(xdrs, lp) + XDR *xdrs; + register long *lp; +{ + rpc_int32 tmp; + if (fread((caddr_t)&tmp, + sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); +#ifndef mc68000 + *lp = ntohl(tmp); +#endif + return (TRUE); +} + +static bool_t +xdrstdio_putlong(xdrs, lp) + XDR *xdrs; + long *lp; +{ + +#ifndef mc68000 + rpc_int32 mycopy = htonl((rpc_int32)*lp); +#endif + if (fwrite((caddr_t)&mycopy, sizeof(rpc_int32), 1, (FILE *)xdrs->x_private) != 1) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_getbytes(xdrs, addr, len) + XDR *xdrs; + caddr_t addr; + unsigned int len; +{ + + if ((len != 0) && (fread(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static bool_t +xdrstdio_putbytes(xdrs, addr, len) + XDR *xdrs; + caddr_t addr; + unsigned int len; +{ + + if ((len != 0) && (fwrite(addr, (int)len, 1, (FILE *)xdrs->x_private) != 1)) + return (FALSE); + return (TRUE); +} + +static unsigned int +xdrstdio_getpos(xdrs) + XDR *xdrs; +{ + + return ((unsigned int) ftell((FILE *)xdrs->x_private)); +} + +static bool_t +xdrstdio_setpos(xdrs, pos) + XDR *xdrs; + unsigned int pos; +{ + + return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ? + FALSE : TRUE); +} + +static rpc_int32 * +xdrstdio_inline(xdrs, len) + XDR *xdrs; + unsigned int len; +{ + + /* + * Must do some work to implement this: must insure + * enough data in the underlying stdio buffer, + * that the buffer is aligned so that we can indirect through a + * long *, and stuff this pointer in xdrs->x_buf. Doing + * a fread or fwrite to a scratch buffer would defeat + * most of the gains to be had here and require storage + * management on this buffer, so we don't do this. + */ + return (NULL); +} |
