From: neilbrown Date: Tue, 19 Oct 2004 00:22:53 +0000 (+0000) Subject: Add gss support from citi @ umich X-Git-Tag: nfs-utils-1-0-6-post7-gss^0 X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=commitdiff_plain;h=f1bfe0916c04d93de7a4fae5315fff6e4ccac23f Add gss support from citi @ umich --- diff --git a/config.mk.in b/config.mk.in index 67f3d01..afbed88 100644 --- a/config.mk.in +++ b/config.mk.in @@ -33,6 +33,9 @@ MANGROUP = root LIBBSD = @LIBBSD@ LIBNSL = @LIBNSL@ LIBWRAP = @LIBWRAP@ +KRBLIB = @KRBLIB@ +KRBDIR = @KRBDIR@ +KRB5_VERSION = @K5VERS@ ################# END OF USER SERVICEABLE PARTS ################## ALLTARGETS = all clean distclean install installman \ @@ -58,6 +61,7 @@ INSTALL = install MAN2PS = groff -Tps -man AFLAGS = -I$(TOP)support/include \ + -I$(KRBDIR)/include \ -Wall $(ARCHFLAGS) -pipe ifdef KERNEL_INCDIR AFLAGS += -I$(KERNEL_INCDIR) diff --git a/configure.in b/configure.in index 93588c2..4962197 100644 --- a/configure.in +++ b/configure.in @@ -52,6 +52,22 @@ AC_ARG_ENABLE(nfsv4, fi AC_SUBST(IDMAPD) AC_SUBST(enable_nfsv4) +AC_ARG_ENABLE(gss, + [ --enable-gss enable support for rpcsec_gss], + enable_gss=$enableval, + enable_gss=yes) + if test "$enable_gss" = yes; then + AC_DEFINE(GSS_SUPPORTED) + GSSD=gssd + SVCGSSD=svcgssd + else + enable_gss= + GSSD= + SVCGSSD= + fi + AC_SUBST(GSSD) + AC_SUBST(SVCGSSD) + AC_SUBST(enable_gss) AC_ARG_ENABLE(kprefix, [ --enable-kprefix install progs as rpc.knfsd etc], test "$enableval" = "yes" && kprefix=k, @@ -117,6 +133,94 @@ AC_SUBST(LIBBSD) AC_TCP_WRAPPER AC_SUBST(LIBWRAP) +if test "$enable_gss" = yes; then + dnl Checks for Kerberos + dnl NOTE: while we intend to do generic gss-api, currently we + dnl have a requirement to get an initial Kerberos machine + dnl credential. Thus, the requirement for Kerberos. + dnl The Kerberos gssapi library will be dynamically loaded? + AC_MSG_CHECKING(for Kerberos v5) + AC_ARG_WITH(krb5, + [ --with-krb5=DIR use Kerberos v5 installation in DIR], + [ case "$withval" in + yes|no) + krb5_with="" + ;; + *) + krb5_with="$withval" + ;; + esac ] + ) + + for dir in $krb5_with /usr/kerberos /usr/local /usr/local/krb5 /usr/krb5 \ + /usr/heimdal /usr/local/heimdal /usr/athena /usr ; do + dnl This ugly hack brought on by the split installation of + dnl MIT Kerberos on Fedora Core 1 + K5CONFIG="" + if test -f $dir/bin/krb5-config; then + K5CONFIG=$dir/bin/krb5-config + elif test -f "/usr/kerberos/bin/krb5-config"; then + K5CONFIG="/usr/kerberos/bin/krb5-config" + fi + if test "$K5CONFIG" != ""; then + if test -f $dir/include/gssapi/gssapi_krb5.h -a \ + \( -f $dir/lib/libgssapi_krb5.a -o \ + -f $dir/lib/libgssapi_krb5.so \) ; then + AC_DEFINE(HAVE_KRB5) + KRBDIR="$dir" + K5VERS=`$K5CONFIG --version | awk '{split($4,v,"."); print v[[1]]v[[2]]v[[3]] }'` + AC_DEFINE_UNQUOTED(KRB5_VERSION,$K5VERS) + KRBLIB=`$K5CONFIG --libs gssapi` + if test $K5VERS -le 131; then + AC_DEFINE(USE_PRIVATE_KRB5_FUNCTIONS) + fi + AC_CHECK_LIB(gssapi_krb5, gss_krb5_export_lucid_sec_context, + AC_DEFINE(HAVE_LUCID_CONTEXT_SUPPORT),,$KRBLIB) + AC_CHECK_LIB(gssapi_krb5, gss_krb5_set_allowable_enctypes, + AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES),,$KRBLIB) + AC_CHECK_LIB(gssapi_krb5, gss_krb5_ccache_name, + AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME),,$KRBLIB) + break + dnl The following ugly hack brought on by the split installation + dnl of Heimdal Kerberos on SuSe + elif test \( -f $dir/include/heim_err.h -o\ + -f $dir/include/heimdal/heim_err.h \) -a \ + -f $dir/lib/libroken.a; then + AC_DEFINE(HAVE_HEIMDAL) + KRBDIR="$dir" + K5VERS=`$K5CONFIG --version | head -1 | awk '{split($2,v,"."); print v[[1]]v[[2]]v[[3]] }'` + AC_DEFINE_UNQUOTED(KRB5_VERSION,$K5VERS) + KRBLIB=`$K5CONFIG --libs gssapi` + AC_CHECK_LIB(gssapi, gss_krb5_export_lucid_sec_context, + AC_DEFINE(HAVE_LUCID_CONTEXT_SUPPORT),,$KRBLIB) + AC_CHECK_LIB(gssapi, gss_krb5_set_allowable_enctypes, + AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES),,$KRBLIB) + AC_CHECK_LIB(gssapi, gss_krb5_ccache_name, + AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME),,$KRBLIB) + break + fi + CFLAGS=$CFLAGS `K5CONFIG --cflags` + fi + done + dnl We didn't find a usable Kerberos environment + if test "x$KRBDIR" = "x"; then + if test "x$krb5_with" = "x"; then + AC_MSG_ERROR(Kerberos v5 with GSS support not found) + else + AC_MSG_ERROR(Kerberos v5 with GSS support not found at $krb5_with) + fi + fi + AC_MSG_RESULT($KRBDIR) + dnl If they specified a directory and it didn't work, give them a warning + if test "x$krb5_with" != "x" -a "$krb5_with" != "$KRBDIR"; then + AC_MSG_WARN(Using $KRBDIR instead of requested value of $krb5_with for Kerberos!) + fi + + AC_SUBST([KRBDIR]) + AC_SUBST([KRBLIB]) + AC_SUBST([K5VERS]) +fi + dnl ************************************************************* dnl Check for headers dnl ************************************************************* diff --git a/support/Makefile b/support/Makefile index 37b6359..aa56fa7 100644 --- a/support/Makefile +++ b/support/Makefile @@ -2,7 +2,7 @@ # Makefile for linux-nfs/support # -SUBDIRS = include nfs export lib misc +SUBDIRS = include nfs export lib misc rpc gssapi .DEFAULT: all include $(TOP)rules.mk diff --git a/support/gssapi/Makefile b/support/gssapi/Makefile new file mode 100644 index 0000000..65271f0 --- /dev/null +++ b/support/gssapi/Makefile @@ -0,0 +1,24 @@ +# +# libgssapi.a +# gssapi mechanism-switching layer +# + +LIBNAME = libgssapi.a +SRCS = g_accept_sec_context.c g_acquire_cred.c g_compare_name.c \ + g_context_time.c g_delete_sec_context.c g_dsp_name.c g_dsp_status.c \ + g_dup_name.c gen_oids.c g_exp_sec_context.c g_glue.c g_imp_name.c \ + g_imp_sec_context.c g_indicate_mechs.c g_initialize.c \ + g_init_sec_context.c g_inq_context.c g_inq_cred.c g_inq_names.c \ + g_mechname.c g_mit_krb5_mech.c g_oid_ops.c g_process_context.c \ + g_rel_buffer.c g_rel_cred.c g_rel_name.c g_rel_oid_set.c g_seal.c \ + g_sign.c gssd_pname_to_uid.c g_unseal.c g_verify.c oid_ops.c \ + g_set_allowable_enctypes.c + +OBJS = $(SRCS:.c=.o) + +include $(TOP)rules.mk + +CFLAGS += -DKRB5_VERSION=$(KRB5_VERSION) -I$(TOP)/support/include + +install:: + @: diff --git a/support/gssapi/SAMPLE_gssapi_mech.conf b/support/gssapi/SAMPLE_gssapi_mech.conf new file mode 100644 index 0000000..8eca824 --- /dev/null +++ b/support/gssapi/SAMPLE_gssapi_mech.conf @@ -0,0 +1,19 @@ +# GSSAPI Mechanism Definitions +# +# This configuration file determines which GSS-API mechanisms +# the gssd code should use +# +# NOTE: +# The initiaiization function "mechglue_internal_krb5_init" +# is used for the MIT krb5 gssapi mechanism. This special +# function name indicates that an internal function should +# be used to determine the entry points for the MIT gssapi +# mechanism funtions. +# +# library initialization function +# ================================ ========================== +# The MIT K5 gssapi library, use special function for initialization. +/usr/lib/libgssapi_krb5.so mechglue_internal_krb5_init +# +# The SPKM3 gssapi library function. Use the function spkm3_gss_initialize. +# /usr/local/gss_mechs/spkm/spkm3/libgssapi_spkm3.so spkm3_gss_initialize diff --git a/support/gssapi/g_accept_sec_context.c b/support/gssapi/g_accept_sec_context.c new file mode 100644 index 0000000..05e967b --- /dev/null +++ b/support/gssapi/g_accept_sec_context.c @@ -0,0 +1,213 @@ +/* #ident "@(#)gss_accept_sec_context.c 1.19 95/08/07 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_accept_sec_context + */ + +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +OM_uint32 KRB5_CALLCONV +gss_accept_sec_context (minor_status, + context_handle, + verifier_cred_handle, + input_token_buffer, + 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_buffer; +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; + +{ + OM_uint32 status, temp_status, temp_minor_status; + gss_union_ctx_id_t union_ctx_id; + gss_union_cred_t union_cred; + gss_cred_id_t input_cred_handle = GSS_C_NO_CREDENTIAL; + gss_name_t internal_name; + gss_OID_desc token_mech_type_desc; + gss_OID token_mech_type = &token_mech_type_desc; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == NULL) + return GSS_S_NO_CONTEXT; + + /* + * if context_handle is GSS_C_NO_CONTEXT, allocate a union context + * descriptor to hold the mech type information as well as the + * underlying mechanism context handle. Otherwise, cast the + * value of *context_handle to the union context variable. + */ + + if(*context_handle == GSS_C_NO_CONTEXT) { + + /* Get the token mech type */ + status = __gss_get_mech_type(token_mech_type, input_token_buffer); + if (status) + return status; + + status = GSS_S_FAILURE; + union_ctx_id = (gss_union_ctx_id_t) + malloc(sizeof(gss_union_ctx_id_desc)); + if (!union_ctx_id) { + *minor_status = ENOMEM; + goto error_out; + } + + union_ctx_id->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc)); + if (!union_ctx_id->mech_type) { + *minor_status = ENOMEM; + goto error_out; + } + + union_ctx_id->mech_type->elements = (void *) + malloc(token_mech_type->length); + if (!union_ctx_id->mech_type->elements) { + *minor_status = ENOMEM; + goto error_out; + } + + union_ctx_id->mech_type->length = token_mech_type->length; + memcpy(union_ctx_id->mech_type->elements, + token_mech_type->elements, + token_mech_type->length); + + /* copy the supplied context handle */ + + union_ctx_id->internal_ctx_id = *context_handle; + } else { + union_ctx_id = *context_handle; + token_mech_type = union_ctx_id->mech_type; + } + + /* + * get the appropriate cred handle from the union cred struct. + * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will + * use the default credential. + */ + union_cred = (gss_union_cred_t) verifier_cred_handle; + input_cred_handle = __gss_get_mechanism_cred(union_cred, token_mech_type); + + /* + * now select the approprate underlying mechanism routine and + * call it. + */ + + mech = __gss_get_mechanism (token_mech_type); + if (mech && mech->gss_accept_sec_context) { + + status = mech->gss_accept_sec_context( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + &union_ctx_id->internal_ctx_id, + input_cred_handle, + input_token_buffer, + input_chan_bindings, + &internal_name, + mech_type, + output_token, + ret_flags, + time_rec, + delegated_cred_handle); + + /* If there's more work to do, keep going... */ + if (status == GSS_S_CONTINUE_NEEDED) + return GSS_S_CONTINUE_NEEDED; + + /* if the call failed, return with failure */ + if (status != GSS_S_COMPLETE) + goto error_out; + + /* + * if src_name is non-NULL, + * convert internal_name into a union name equivalent + * First call the mechanism specific display_name() + * then call gss_import_name() to create + * the union name struct cast to src_name + */ +#if 0 + /* ANDROS: src_name is never null, it is a ptr from the gss_accept_sec_context + * caller. internal_name may or may not be set by the mechanism. so, don't + * call __gss_convert_name_to_union_name which sets the src_name + * unless the internal name is set + * by the above mech->gss_accept_sec_context. + */ + if (internal_name != NULL && status == GSS_S_COMPLETE) { +#else + if (src_name != NULL && status == GSS_S_COMPLETE) { +#endif + temp_status = __gss_convert_name_to_union_name( + &temp_minor_status, mech, internal_name, src_name); + if (temp_status != GSS_S_COMPLETE) { + if (minor_status) + *minor_status = temp_minor_status; + gss_release_buffer(&temp_minor_status, output_token); + __gss_release_internal_name(&temp_minor_status, + &mech->mech_type, &internal_name); + return (temp_status); + } + } + + if(*context_handle == GSS_C_NO_CONTEXT) + *context_handle = (gss_ctx_id_t *) union_ctx_id; + + return(status); + } + + return(GSS_S_BAD_MECH); + +error_out: + if (union_ctx_id) { + if (union_ctx_id->mech_type) { + if (union_ctx_id->mech_type->elements) + free(union_ctx_id->mech_type->elements); + free(union_ctx_id->mech_type); + } + free(union_ctx_id); + } + return (status); +} + diff --git a/support/gssapi/g_acquire_cred.c b/support/gssapi/g_acquire_cred.c new file mode 100644 index 0000000..50087db --- /dev/null +++ b/support/gssapi/g_acquire_cred.c @@ -0,0 +1,539 @@ +/* #ident "@(#)gss_acquire_cred.c 1.19 95/08/07 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_acquire_cred + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include +#include + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +static gss_OID_set +create_actual_mechs(creds) + gss_union_cred_t creds; +{ + gss_OID_set actual_mechs; + int i; + + actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); + if (!actual_mechs) + return NULL; + + actual_mechs->elements = (gss_OID) + malloc(sizeof(gss_OID_desc) * creds->count); + if (!actual_mechs->elements) { + free(actual_mechs); + return NULL; + } + + actual_mechs->count = creds->count; + + for (i=0; i < creds->count; i++) { + actual_mechs->elements[i].length = creds->mechs_array[i].length; + actual_mechs->elements[i].elements = (void *) + malloc(creds->mechs_array[i].length); + memcpy(actual_mechs->elements[i].elements, + creds->mechs_array[i].elements, creds->mechs_array[i].length); + } + + return actual_mechs; +} + + +OM_uint32 KRB5_CALLCONV +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; +int cred_usage; +gss_cred_id_t * output_cred_handle; +gss_OID_set * actual_mechs; +OM_uint32 * time_rec; + +{ + OM_uint32 status, temp_minor_status, temp_time_rec = ~0; + unsigned int i, j, creds_acquired = 0; + int k; + gss_union_name_t union_name; + gss_name_t internal_name; + gss_union_cred_t creds; + gss_OID_set_desc default_OID_set; + gss_OID_desc default_OID; + gss_OID specific_mech_type = 0; + gss_mechanism mech; + + /* + * This struct is used to keep track of which mech_types are + * actually available and to store the credentials returned + * from them by each mechanism specific gss_acquire_cred() call. + * The results are used to construct the final union_cred + * structure returned by the glue layer gss_acquire_cred() call + * and the actual_mechs gss_OID_set returned. + */ + + struct creds_returned { + unsigned char available; + gss_cred_id_t cred; + } *creds_returned; + + gss_initialize(); + + /* Set this to NULL for now */ + + if (actual_mechs) + *actual_mechs = GSS_C_NULL_OID_SET; + + if (minor_status) + *minor_status = 0; + + /* No need to continue if we don't have a place to store the creds */ + if (output_cred_handle == NULL) + return GSS_S_COMPLETE; + + /* get desired_name cast as a union_name type */ + + union_name = (gss_union_name_t) desired_name; + + if (union_name) + specific_mech_type = union_name->mech_type; + + /* + * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an + * appropriate default. + */ + if(desired_mechs == GSS_C_NULL_OID_SET) { + /* + * If union_name->mech_type is NULL then we get the default + * mechanism; otherwise, we get the mechanism for the + * mechanism-specific name. + */ + mech = __gss_get_mechanism(specific_mech_type); + if (mech == NULL) + return (GSS_S_BAD_MECH); + + desired_mechs = &default_OID_set; + default_OID_set.count = 1 ; + default_OID_set.elements = &default_OID; + default_OID.length = mech->mech_type.length; + default_OID.elements = mech->mech_type.elements; + } + + /* + * Now allocate the creds returned array. There is one element + * for each member of the desired_mechs argument. + */ + + creds_returned = (struct creds_returned *) + malloc(sizeof(struct creds_returned) * desired_mechs->count); + + /* + * For each requested mechanism in desired_mechs, determine if it + * is supported. If so, mark the corresponding element in + * creds_returned->available as 1 and call the mechanism + * specific gss_acquire_cred(), placing the returned cred in + * creds_returned->cred. If not, mark creds_returned->available as + * 0. + */ + status = GSS_S_BAD_MECH; + for (j=0; j < desired_mechs->count; j++) { + creds_returned[j].available = 0; + + mech = __gss_get_mechanism (&desired_mechs->elements[j]); + if (!mech || !mech->gss_acquire_cred) + continue; + /* + * If this is a mechanism-specific name, then only use the + * mechanism of the name. + */ + if (specific_mech_type && !g_OID_equal(specific_mech_type, + &mech->mech_type)) + continue; + /* + * If this is not a mechanism-specific name, then we need to + * do an import the external name in union_name first. + */ + if (union_name == 0) + internal_name = (gss_name_t) 0; + else if (!union_name->mech_type) { + if (__gss_import_internal_name(&temp_minor_status, + &mech->mech_type, + union_name, &internal_name)) { + continue; + } + } else + internal_name = union_name->mech_name; + +#ifdef USE_MECH_CONTEXT + status = mech->gss_acquire_cred(mech->context, minor_status, +#else + status = mech->gss_acquire_cred(minor_status, +#endif + internal_name, time_req, + desired_mechs, cred_usage, + &creds_returned[j].cred, + NULL, &temp_time_rec); + + /* Release the internal name, if allocated above */ + if (union_name && !union_name->mech_type) { + (void) __gss_release_internal_name(&temp_minor_status, + &mech->mech_type, + &internal_name); + } + + if (status != GSS_S_COMPLETE) + continue; + + /* + * Add this into the creds_returned structure, if we got + * a good credential for this mechanism. + */ + if (time_rec) { + *time_rec = *time_rec > temp_time_rec ? temp_time_rec : *time_rec; + temp_time_rec = *time_rec; + } + + creds_returned[j].available = 1; + creds_acquired++; + + /* + * If union_name is set, then we're done. Continue, and + * declare success. Otherwise, if do an inquire credentials + * from the first mechanism that succeeds and use that as the + * union name. + */ + if (union_name) + continue; + +#ifdef USE_MECH_CONTEXT + status = mech->gss_inquire_cred(mech->context, &temp_minor_status, +#else + status = mech->gss_inquire_cred(&temp_minor_status, +#endif + creds_returned[j].cred, + &internal_name, 0, 0, 0); + if (status) { + /* Should never happen */ + creds_returned[j].available = 0; + creds_acquired--; + if (mech->gss_release_cred) +#ifdef USE_MECH_CONTEXT + mech->gss_release_cred(mech->context, minor_status, +#else + mech->gss_release_cred(minor_status, +#endif + &creds_returned[j].cred); + continue; + } + + status = __gss_convert_name_to_union_name(&temp_minor_status, mech, + internal_name, + (gss_name_t *) &union_name); + } + + /* + * Now allocate the creds struct, which will be cast as a gss_cred_id_t + * and returned in the output_cred_handle argument. If there were + * no credentials found, return an error. Also, allocate the + * actual_mechs data. + */ + if (creds_acquired == 0) { + free (creds_returned); + return (status); + } + + creds = (gss_union_cred_t) malloc(sizeof(gss_union_cred_desc)); + + creds->count = creds_acquired; + + creds->mechs_array = (gss_OID) + malloc(sizeof(gss_OID_desc) * creds_acquired); + + creds->cred_array = (gss_cred_id_t *) + malloc(sizeof(gss_cred_id_t) * creds_acquired); + + if(actual_mechs != NULL) { + *actual_mechs = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); + + (*actual_mechs)->count = creds_acquired; + + (*actual_mechs)->elements = (gss_OID) + malloc(sizeof(gss_OID_desc) * creds_acquired); + } + + /* + * copy the mechanisms found and their allocated credentials into the + * creds structure. At the same time, build up the actual_mechs + * data. + */ + + j = 0; + + for (i=0; icount; i++) { + if(creds_returned[i].available) { + + creds->mechs_array[j].length = + desired_mechs->elements[i].length; + creds->mechs_array[j].elements = (void *) + malloc(desired_mechs->elements[i].length); + memcpy(creds->mechs_array[j].elements, + desired_mechs->elements[i].elements, + desired_mechs->elements[i].length); + creds->cred_array[j] = creds_returned[i].cred; + if (actual_mechs) { + (*actual_mechs)->elements[j].length = + desired_mechs->elements[i].length; + (*actual_mechs)->elements[j].elements = (void *) + malloc(desired_mechs->elements[i].length); + memcpy((*actual_mechs)->elements[j].elements, + desired_mechs->elements[i].elements, + desired_mechs->elements[i].length); + } + j++; + } + } + + /* free the creds_returned struct, since we are done with it. */ + + free(creds_returned); + + /* record the information needed for gss_inquire_cred() */ + + creds->auxinfo.creation_time = time(0); + creds->auxinfo.time_rec = temp_time_rec; + creds->auxinfo.cred_usage = cred_usage; + + /* + * we can't just record the internal name, desired_name, since + * it may be destroyed between now and the time gss_inquire_cred() + * is called. So we must record the printable name in a + * gss_buffer_t, calling gss_display_name() to fill it in. When + * gss_inquire_name() is called, we must then call gss_import_name() + * to get the internal name that is required at that point. + */ + if (desired_name) { + status = gss_display_name(&temp_minor_status, desired_name, + &creds->auxinfo.name, + &creds->auxinfo.name_type); + if (status) { + status = GSS_S_BAD_NAME; + goto error_out; + } + } else { + status = gss_display_name(&temp_minor_status, union_name, + &creds->auxinfo.name, + &creds->auxinfo.name_type); + if (status) { + status = GSS_S_BAD_NAME; + goto error_out; + } + } + + *output_cred_handle = (gss_cred_id_t) creds; + return(GSS_S_COMPLETE); + +error_out: + for (k=0; k < creds->count; k++) { + free(creds->mechs_array[k].elements); + if (actual_mechs) + free((*actual_mechs)->elements[k].elements); + } + + if (actual_mechs) { + free((*actual_mechs)->elements); + free(*actual_mechs); + *actual_mechs = GSS_C_NULL_OID_SET; + } + free(creds->cred_array); + free(creds->mechs_array); + free(creds); + + return(status); +} + +/* V2 KRB5_CALLCONV */ +OM_uint32 KRB5_CALLCONV +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; +{ + OM_uint32 status, temp_minor_status; + OM_uint32 time_req, time_rec; + gss_union_name_t union_name; + gss_union_cred_t new_union_cred, union_cred; + gss_name_t internal_name; + gss_mechanism mech; + gss_cred_id_t cred; + gss_OID new_mechs_array; + gss_cred_id_t * new_cred_array; + + if (input_cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_NO_CRED; + + union_cred = (gss_union_cred_t) input_cred_handle; + + mech = __gss_get_mechanism(desired_mech); + if (!mech) + return GSS_S_BAD_MECH; + + if (__gss_get_mechanism_cred(union_cred, desired_mech) != + GSS_C_NO_CREDENTIAL) + return GSS_S_DUPLICATE_ELEMENT; + + union_name = (gss_union_name_t) desired_name; + if (union_name->mech_type) { + if (!g_OID_equal(desired_mech, union_name->mech_type)) + return GSS_S_BAD_NAMETYPE; + internal_name = union_name->mech_name; + } else { + if (__gss_import_internal_name(minor_status, desired_mech, + union_name, &internal_name)) + return (GSS_S_BAD_NAME); + } + + if (cred_usage == GSS_C_ACCEPT) + time_req = acceptor_time_req; + else if (cred_usage == GSS_C_INITIATE) + time_req = initiator_time_req; + else if (cred_usage == GSS_C_BOTH) + time_req = (acceptor_time_req > initiator_time_req) ? + acceptor_time_req : initiator_time_req; + +#ifdef USE_MECH_CONTEXT + status = mech->gss_acquire_cred(mech->context, minor_status, +#else + status = mech->gss_acquire_cred(minor_status, +#endif + internal_name, time_req, + GSS_C_NULL_OID_SET, cred_usage, + &cred, NULL, &time_rec); + if (status != GSS_S_COMPLETE) + goto errout; + + new_mechs_array = (gss_OID) + malloc(sizeof(gss_OID_desc) * (union_cred->count+1)); + + new_cred_array = (gss_cred_id_t *) + malloc(sizeof(gss_cred_id_t) * (union_cred->count+1)); + + if (!new_mechs_array || !new_cred_array) { + *minor_status = ENOMEM; + status = GSS_S_FAILURE; + goto errout; + } + + + if (acceptor_time_rec) + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) + *acceptor_time_rec = time_rec; + if (initiator_time_rec) + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) + *initiator_time_rec = time_rec; + + /* + * OK, expand the mechanism array in the union credentials + * (Look for the union label...) + */ + memcpy(new_mechs_array, union_cred->mechs_array, + sizeof(gss_OID_desc) * union_cred->count); + memcpy(new_cred_array, union_cred->cred_array, + sizeof(gss_cred_id_t) * union_cred->count); + + new_cred_array[union_cred->count] = cred; + new_mechs_array[union_cred->count].length = desired_mech->length; + new_mechs_array[union_cred->count].elements = malloc(desired_mech->length); + if (!new_mechs_array[union_cred->count].elements) { + *minor_status = ENOMEM; + goto errout; + } + memcpy(new_mechs_array[union_cred->count].elements, desired_mech->elements, + desired_mech->length); + + if (output_cred_handle == NULL) { + free(union_cred->mechs_array); + free(union_cred->cred_array); + new_union_cred = union_cred; + } else { + new_union_cred = malloc(sizeof(gss_union_cred_desc)); + if (new_union_cred == NULL) { + *minor_status = ENOMEM; + goto errout; + } + *new_union_cred = *union_cred; + *output_cred_handle = new_union_cred; + } + new_union_cred->mechs_array = new_mechs_array; + new_union_cred->cred_array = new_cred_array; + new_union_cred->count++; + new_mechs_array = 0; + new_cred_array = 0; + + if (actual_mechs) + *actual_mechs = create_actual_mechs(new_union_cred); + + status = GSS_S_COMPLETE; + +errout: + if (new_mechs_array) + free(new_mechs_array); + if (new_cred_array) + free(new_cred_array); + if (!union_name->mech_type) { + (void) __gss_release_internal_name(&temp_minor_status, + desired_mech, &internal_name); + } + + return(status); +} diff --git a/support/gssapi/g_compare_name.c b/support/gssapi/g_compare_name.c new file mode 100644 index 0000000..496d497 --- /dev/null +++ b/support/gssapi/g_compare_name.c @@ -0,0 +1,165 @@ +/* #ident "@(#)gss_compare_name.c 1.13 95/08/02 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_compare_name + * + */ + +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +OM_uint32 KRB5_CALLCONV +gss_compare_name (minor_status, + name1, + name2, + name_equal) + +OM_uint32 * minor_status; +gss_name_t name1; +gss_name_t name2; +int * name_equal; + +{ + OM_uint32 major_status, temp_minor; + gss_union_name_t union_name1, union_name2; + gss_mechanism mech; + gss_name_t internal_name; + + gss_initialize(); + + if (name1 == 0 || name2 == 0) { + if (name_equal) + *name_equal = 0; + return GSS_S_BAD_NAME; + } + + union_name1 = (gss_union_name_t) name1; + union_name2 = (gss_union_name_t) name2; + /* + * Try our hardest to make union_name1 be the mechanism-specific + * name. (Of course we can't if both names aren't + * mechanism-specific.) + */ + if (union_name1->mech_type == 0) { + union_name1 = (gss_union_name_t) name2; + union_name2 = (gss_union_name_t) name1; + } + /* + * If union_name1 is mechanism specific, then fetch its mechanism + * information. + */ + if (union_name1->mech_type) { + mech = __gss_get_mechanism (union_name1->mech_type); + if (!mech) + return (GSS_S_BAD_MECH); + if (!mech->gss_compare_name) + return (GSS_S_BAD_BINDINGS); + } + + if (name_equal == NULL) + return GSS_S_COMPLETE; + + *name_equal = 0; /* Default to *not* equal.... */ + + /* + * First case... both names are mechanism-specific + */ + if (union_name1->mech_type && union_name2->mech_type) { + if (!g_OID_equal(union_name1->mech_type, union_name2->mech_type)) + return (GSS_S_COMPLETE); + if ((union_name1->mech_name == 0) || (union_name2->mech_name == 0)) + /* should never happen */ + return (GSS_S_BAD_NAME); +#ifdef USE_MECH_CONTEXT + return (mech->gss_compare_name(mech->context, minor_status, +#else + return (mech->gss_compare_name(minor_status, +#endif + union_name1->mech_name, + union_name2->mech_name, name_equal)); + + } + + /* + * Second case... both names are NOT mechanism specific. + * + * All we do here is make sure the two name_types are equal and then + * that the external_names are equal. Note the we do not take care + * of the case where two different external names map to the same + * internal name. We cannot determine this, since we as yet do not + * know what mechanism to use for calling the underlying + * gss_import_name(). + */ + if (!union_name1->mech_type && !union_name2->mech_type) { + if (!g_OID_equal(union_name1->name_type, union_name2->name_type)) + return (GSS_S_COMPLETE); + if ((union_name1->external_name->length != + union_name2->external_name->length) || + (memcmp(union_name1->external_name->value, + union_name2->external_name->value, + union_name1->external_name->length) != 0)) + return (GSS_S_COMPLETE); + *name_equal = 1; + return (GSS_S_COMPLETE); + } + + /* + * Final case... one name is mechanism specific, the other isn't. + * + * We attempt to convert the general name to the mechanism type of + * the mechanism-specific name, and then do the compare. If we + * can't import the general name, then we return that the name is + * _NOT_ equal. + */ + if (union_name2->mech_type) { + /* We make union_name1 the mechanism specific name. */ + union_name1 = (gss_union_name_t) name2; + union_name2 = (gss_union_name_t) name1; + } + major_status = __gss_import_internal_name(minor_status, + union_name1->mech_type, + union_name2, + &internal_name); + if (major_status != GSS_S_COMPLETE) + return (GSS_S_COMPLETE); +#ifdef USE_MECH_CONTEXT + major_status = mech->gss_compare_name(mech->context, minor_status, +#else + major_status = mech->gss_compare_name(minor_status, +#endif + union_name1->mech_name, + internal_name, name_equal); + __gss_release_internal_name(&temp_minor, union_name1->mech_type, + &internal_name); + return (major_status); + +} diff --git a/support/gssapi/g_context_time.c b/support/gssapi/g_context_time.c new file mode 100644 index 0000000..13ae5c8 --- /dev/null +++ b/support/gssapi/g_context_time.c @@ -0,0 +1,75 @@ +/* #ident "@(#)gss_context_time.c 1.8 95/08/07 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 routines for gss_context_time + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_context_time (minor_status, + context_handle, + time_rec) + +OM_uint32 * minor_status; +gss_ctx_id_t context_handle; +OM_uint32 * time_rec; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + + if (mech->gss_context_time) + status = mech->gss_context_time( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + time_rec); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} diff --git a/support/gssapi/g_delete_sec_context.c b/support/gssapi/g_delete_sec_context.c new file mode 100644 index 0000000..e9253c8 --- /dev/null +++ b/support/gssapi/g_delete_sec_context.c @@ -0,0 +1,88 @@ +/* #ident "@(#)gss_delete_sec_context.c 1.10 95/08/07 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_delete_sec_context + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + /* if the context_handle is Null, return NO_CONTEXT error */ + + if(context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) + return(GSS_S_NO_CONTEXT); + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) *context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + + if (mech->gss_delete_sec_context) + status = mech->gss_delete_sec_context( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + &ctx->internal_ctx_id, + output_token); + else + status = GSS_S_BAD_BINDINGS; + + /* now free up the space for the union context structure */ + + free(ctx->mech_type->elements); + free(ctx->mech_type); + free(*context_handle); + *context_handle = NULL; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} diff --git a/support/gssapi/g_dsp_name.c b/support/gssapi/g_dsp_name.c new file mode 100644 index 0000000..dcf1800 --- /dev/null +++ b/support/gssapi/g_dsp_name.c @@ -0,0 +1,96 @@ +/* #ident "@(#)g_dsp_name.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_display_name() + * + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 major_status; + gss_union_name_t union_name; + + if (input_name == 0) + return GSS_S_BAD_NAME; + + union_name = (gss_union_name_t) input_name; + + if (union_name->mech_type) { + /* + * OK, we have a mechanism-specific name; let's use it! + */ + return (__gss_display_internal_name(minor_status, + union_name->mech_type, + union_name->mech_name, + output_name_buffer, + output_name_type)); + } + + /* + * copy the value of the external_name component of the union + * name into the output_name_buffer and point the output_name_type + * to the name_type component of union_name + */ + if (output_name_type != NULL) { + major_status = generic_gss_copy_oid(minor_status, + union_name->name_type, + output_name_type); + if (major_status) + return (major_status); + } + + if (output_name_buffer != NULL) { + output_name_buffer->length = union_name->external_name->length; + + output_name_buffer->value = + (void *) malloc(output_name_buffer->length); + + memcpy(output_name_buffer->value, + union_name->external_name->value, + output_name_buffer->length); + } + + if (minor_status) + *minor_status = 0; + + return(GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_dsp_status.c b/support/gssapi/g_dsp_status.c new file mode 100644 index 0000000..42cae0d --- /dev/null +++ b/support/gssapi/g_dsp_status.c @@ -0,0 +1,86 @@ +/* #ident "@(#)gss_display_status.c 1.8 95/08/07 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 gss_display_status + * + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +OM_uint32 KRB5_CALLCONV +gss_display_status (minor_status, + status_value, + status_type, + req_mech_type, + message_context, + status_string) + +OM_uint32 * minor_status; +OM_uint32 status_value; +int status_type; +gss_OID req_mech_type; +OM_uint32 * message_context; +gss_buffer_t status_string; + +{ + OM_uint32 status; + gss_OID mech_type = (gss_OID) req_mech_type; + gss_mechanism mech; + + gss_initialize(); + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + mech = __gss_get_mechanism (mech_type); + + if (mech == NULL) + return (GSS_S_BAD_MECH); + + if (mech_type == GSS_C_NULL_OID) + mech_type = &mech->mech_type; + + if (mech->gss_display_status) + status = mech->gss_display_status( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + status_value, + status_type, + mech_type, + message_context, + status_string); + else + status = GSS_S_BAD_BINDINGS; + + return(status); +} diff --git a/support/gssapi/g_dup_name.c b/support/gssapi/g_dup_name.c new file mode 100644 index 0000000..bb88813 --- /dev/null +++ b/support/gssapi/g_dup_name.c @@ -0,0 +1,162 @@ +/* + * 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. + * + * created andros 2.24.01 from g_compare_name.c + */ + +/* + * glue routine for gss_duplicate_name + * + */ + +#include +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +OM_uint32 KRB5_CALLCONV +gss_duplicate_name (minor_status, + in_name, + exp_name) +OM_uint32 * minor_status; +const gss_name_t in_name; +gss_name_t *exp_name; +{ + OM_uint32 tmp,major_status = GSS_S_COMPLETE; + gss_union_name_t union_in_name, union_exp_name; + gss_mechanism mech; + + gss_initialize(); + + /* if exp_name is NULL, simply return */ + if (exp_name == NULL) + return (GSS_S_COMPLETE); + + *exp_name = NULL; + + if (in_name == 0) + return (GSS_S_BAD_NAME); + + union_in_name = (gss_union_name_t) in_name; + + /* + * Create the union name struct that will hold the exported + * name and the name type. + */ + + union_exp_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); + if (!union_exp_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } +#ifdef DEBUG + fprintf(stderr, "gss_duplicate_name: copying *oid %p\n", + union_in_name->mech_type); +#endif + union_exp_name->gss_mech = union_in_name->gss_mech; + union_exp_name->mech_type = GSS_C_NO_OID; + if (union_in_name->mech_type != GSS_C_NO_OID && + (generic_gss_copy_oid(&tmp, union_in_name->mech_type, + &union_exp_name->mech_type) != GSS_S_COMPLETE)) { + *minor_status = ENOMEM; + goto allocation_failure; + } + union_exp_name->mech_name = NULL; + union_exp_name->name_type = GSS_C_NO_OID; + if (union_in_name->name_type != GSS_C_NO_OID && + (generic_gss_copy_oid(&tmp, union_in_name->name_type, + &union_exp_name->name_type) != GSS_S_COMPLETE)) { + *minor_status = ENOMEM; + goto allocation_failure; + } + union_exp_name->external_name = NULL; + union_exp_name->external_name = + (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); + if (!union_exp_name->external_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } + union_exp_name->external_name->length = union_in_name->external_name->length; + /* + * we malloc length+1 to stick a NULL on the end, just in case + * Note that this NULL is not included in ->length for a reason! + */ + + union_exp_name->external_name->value = + (void *) malloc(union_in_name->external_name->length); + if (!union_exp_name->external_name->value) { + *minor_status = ENOMEM; + goto allocation_failure; + } + memcpy(union_exp_name->external_name->value, + union_in_name->external_name->value, + union_exp_name->external_name->length); + + /* + * Mechanism specific name + */ + + if (union_in_name->mech_type != GSS_C_NO_OID) { + mech = __gss_get_mechanism (union_in_name->mech_type); + if (!mech) + return (GSS_S_BAD_MECH); + if (!mech->gss_duplicate_name) + return (GSS_S_BAD_BINDINGS); + +#ifdef USE_MECH_CONTEXT + major_status = mech->gss_duplicate_name(mech->context, minor_status, +#else + major_status = mech->gss_duplicate_name(minor_status, +#endif + union_in_name->mech_name, &union_exp_name->mech_name); + if (major_status != GSS_S_COMPLETE) + return (major_status); + } +#ifdef DEBUG + fprintf(stderr, "gss_duplicate_name: returning union_exp_name %p\n", + union_exp_name); +#endif + *exp_name = union_exp_name; + return (major_status); + +allocation_failure: + if (union_exp_name) { + if (union_exp_name->external_name) { + if (union_exp_name->external_name->value) + free(union_exp_name->external_name->value); + free(union_exp_name->external_name); + } + if (union_exp_name->name_type) + generic_gss_release_oid(&tmp, &union_exp_name->name_type); + if (union_exp_name->mech_name) + __gss_release_internal_name(minor_status, union_exp_name->mech_type, + &union_exp_name->mech_name); + if (union_exp_name->mech_type) + generic_gss_release_oid(&tmp, &union_exp_name->mech_type); + free(union_exp_name); + } +return (major_status); + +} + diff --git a/support/gssapi/g_exp_sec_context.c b/support/gssapi/g_exp_sec_context.c new file mode 100644 index 0000000..59d9e80 --- /dev/null +++ b/support/gssapi/g_exp_sec_context.c @@ -0,0 +1,108 @@ +/* #ident "@(#)g_exp_sec_context.c 1.2 96/01/18 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_export_sec_context + */ + +#include "mglueP.h" +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + size_t length; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + gss_buffer_desc token; + char *buf; + + gss_initialize(); + + if (context_handle == NULL || *context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) *context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + if (!mech) + return GSS_S_BAD_MECH; + if (!mech->gss_export_sec_context) + return GSS_S_BAD_BINDINGS; + +#ifdef USE_MECH_CONTEXT + status = mech->gss_export_sec_context(mech->context, minor_status, +#else + status = mech->gss_export_sec_context(minor_status, +#endif + &ctx->internal_ctx_id, &token); + if (status != GSS_S_COMPLETE) + return (status); + + length = token.length + 4 + ctx->mech_type->length; + interprocess_token->length = length; + interprocess_token->value = malloc(length); + if (interprocess_token->value == 0) { + (void) gss_release_buffer(minor_status, &token); + *minor_status = ENOMEM; + return (GSS_S_FAILURE); + } + buf = interprocess_token->value; + length = ctx->mech_type->length; + buf[3] = (unsigned char) (length & 0xFF); + length >>= 8; + buf[2] = (unsigned char) (length & 0xFF); + length >>= 8; + buf[1] = (unsigned char) (length & 0xFF); + length >>= 8; + buf[0] = (unsigned char) (length & 0xFF); + memcpy(buf+4, ctx->mech_type->elements, (size_t) ctx->mech_type->length); + memcpy(buf+4+ctx->mech_type->length, token.value, token.length); + + (void) gss_release_buffer(minor_status, &token); + + free(ctx->mech_type->elements); + free(ctx->mech_type); + free(ctx); + *context_handle = 0; + + return(GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_glue.c b/support/gssapi/g_glue.c new file mode 100644 index 0000000..cf2f76a --- /dev/null +++ b/support/gssapi/g_glue.c @@ -0,0 +1,344 @@ +/* #ident "@(#)g_glue.c 1.1 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. + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +extern gss_mechanism *__gss_mechs_array; + +/* + * This file contains the support routines for the glue layer. + */ + +/* + * given the mechs_array and a mechanism OID, return the + * pointer to the mechanism, or NULL if that mechanism is + * not supported. If the requested OID is NULL, then return + * the first mechanism. + */ + +gss_mechanism __gss_get_mechanism (type) + gss_OID type; +{ + int i; + + if (type == GSS_C_NULL_OID) + return (__gss_mechs_array[0]); + + for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) { + if ((__gss_mechs_array[i]->mech_type.length == type->length) && + (memcmp (__gss_mechs_array[i]->mech_type.elements, type->elements, + type->length) == 0)) { + + return (__gss_mechs_array[i]); + } + } + return NULL; +} + + +/* + * glue routine for get_mech_type + * + */ + +OM_uint32 __gss_get_mech_type(OID, token) + gss_OID OID; + gss_buffer_t token; +{ + unsigned char * buffer_ptr; + int length; + + /* + * This routine reads the prefix of "token" in order to determine + * its mechanism type. It assumes the encoding suggested in + * Appendix B of RFC 1508. This format starts out as follows : + * + * tag for APPLICATION 0, Sequence[constructed, definite length] + * length of remainder of token + * tag of OBJECT IDENTIFIER + * length of mechanism OID + * encoding of mechanism OID + * + * + * Numerically, this looks like : + * + * 0x60 + * - could be multiple bytes + * 0x06 + * - assume only one byte, hence OID length < 127 + * + * + * The routine fills in the OID value and returns an error as necessary. + */ + + if (token == NULL) + return (GSS_S_DEFECTIVE_TOKEN); + + /* Skip past the APP/Sequnce byte and the token length */ + + buffer_ptr = (unsigned char *) token->value; + + if (*(buffer_ptr++) != 0x60) + return (GSS_S_DEFECTIVE_TOKEN); + length = *buffer_ptr++; + if (length & 0x80) { + if ((length & 0x7f) > 4) + return (GSS_S_DEFECTIVE_TOKEN); + buffer_ptr += length & 0x7f; + } + + if (*(buffer_ptr++) != 0x06) + return (GSS_S_DEFECTIVE_TOKEN); + + OID->length = (OM_uint32) *(buffer_ptr++); + OID->elements = (void *) buffer_ptr; + return (GSS_S_COMPLETE); +} + + +/* + * Internal routines to get and release an internal mechanism name + */ + +#include "mglueP.h" + +OM_uint32 __gss_import_internal_name (minor_status, mech_type, union_name, + internal_name) +OM_uint32 *minor_status; +gss_OID mech_type; +gss_union_name_t union_name; +gss_name_t *internal_name; +{ + OM_uint32 status; + gss_mechanism mech; + + mech = __gss_get_mechanism (mech_type); + if (mech) { + if (mech->gss_import_name) + status = mech->gss_import_name ( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + union_name->external_name, + union_name->name_type, + internal_name); + else + status = GSS_S_BAD_BINDINGS; + + return (status); + } + + return (GSS_S_BAD_MECH); +} + +OM_uint32 __gss_display_internal_name (minor_status, mech_type, internal_name, + external_name, name_type) +OM_uint32 *minor_status; +gss_OID mech_type; +gss_name_t internal_name; +gss_buffer_t external_name; +gss_OID *name_type; +{ + OM_uint32 status; + gss_mechanism mech; + + mech = __gss_get_mechanism (mech_type); + if (mech) { + if (mech->gss_display_name) + status = mech->gss_display_name ( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + internal_name, + external_name, + name_type); + else + status = GSS_S_BAD_BINDINGS; + + return (status); + } + + return (GSS_S_BAD_MECH); +} + +OM_uint32 __gss_release_internal_name (minor_status, mech_type, internal_name) +OM_uint32 *minor_status; +gss_OID mech_type; +gss_name_t *internal_name; +{ + OM_uint32 status; + gss_mechanism mech; + + mech = __gss_get_mechanism (mech_type); + if (mech) { + if (mech->gss_release_name) + status = mech->gss_release_name ( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + internal_name); + else + status = GSS_S_BAD_BINDINGS; + + return (status); + } + + return (GSS_S_BAD_MECH); +} + + +/* + * This function converts an internal gssapi name to a union gssapi + * name. Note that internal_name should be considered "consumed" by + * this call, whether or not we return an error. + */ +OM_uint32 __gss_convert_name_to_union_name(minor_status, mech, + internal_name, external_name) + OM_uint32 *minor_status; + gss_mechanism mech; + gss_name_t internal_name; + gss_name_t *external_name; +{ + OM_uint32 major_status,tmp; + gss_union_name_t union_name; + + union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); + if (!union_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } + union_name->mech_type = 0; + union_name->mech_name = internal_name; + union_name->name_type = 0; + union_name->external_name = 0; + union_name->gss_mech = mech; + + major_status = generic_gss_copy_oid(minor_status, &mech->mech_type, + &union_name->mech_type); + if (major_status != GSS_S_COMPLETE) + goto allocation_failure; + + union_name->external_name = + (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); + if (!union_name->external_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } + +#ifdef USE_MECH_CONTEXT + major_status = mech->gss_display_name(mech->context, minor_status, +#else + major_status = mech->gss_display_name(minor_status, +#endif + internal_name, + union_name->external_name, + &union_name->name_type); + if (major_status != GSS_S_COMPLETE) + goto allocation_failure; + + *external_name = union_name; + return (GSS_S_COMPLETE); + +allocation_failure: + if (union_name) { + if (union_name->external_name) { + if (union_name->external_name->value) + free(union_name->external_name->value); + free(union_name->external_name); + } + if (union_name->name_type) + generic_gss_release_oid(&tmp, &union_name->name_type); + if (union_name->mech_name) + __gss_release_internal_name(minor_status, union_name->mech_type, + &union_name->mech_name); + if (union_name->mech_type) + mech_gss_release_oid(&tmp, &union_name->mech_type, mech); + free(union_name); + } + return (major_status); +} + +/* + * Glue routine for returning the mechanism-specific credential from a + * external union credential. + */ +gss_cred_id_t +__gss_get_mechanism_cred(union_cred, mech_type) + gss_union_cred_t union_cred; + gss_OID mech_type; +{ + int i; + + if (union_cred == GSS_C_NO_CREDENTIAL) + return GSS_C_NO_CREDENTIAL; + + for (i=0; i < union_cred->count; i++) { + if (g_OID_equal(mech_type, &union_cred->mechs_array[i])) + return union_cred->cred_array[i]; + } + return GSS_C_NO_CREDENTIAL; +} + + +/* + * Glue routine to copy an external name buffer (used by gss_duplicate_name) + */ +OM_uint32 __gss_copy_namebuf(src, dest) + gss_buffer_t src; + gss_buffer_t *dest; +{ + gss_buffer_t temp = NULL; + + if (dest == NULL) + return (GSS_S_BAD_NAME); + + temp = (gss_buffer_t) malloc (sizeof(gss_buffer_t)); + if (!temp) { + return(GSS_S_FAILURE); + } + temp->value = (void *) malloc (src->length + 1); + if (temp->value == NULL) { + free(temp); + return(GSS_S_FAILURE); + } + + memcpy(temp->value, src->value, src->length); + temp->length = src->length; + + *dest = temp; + return (GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_imp_name.c b/support/gssapi/g_imp_name.c new file mode 100644 index 0000000..43f9c50 --- /dev/null +++ b/support/gssapi/g_imp_name.c @@ -0,0 +1,161 @@ +/* #ident "@(#)g_imp_name.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 gss_import_name + * + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +OM_uint32 KRB5_CALLCONV +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; + +{ + gss_union_name_t union_name; + OM_uint32 tmp, major_status = GSS_S_FAILURE; + gss_OID mech; + + gss_initialize(); + + if (minor_status) + *minor_status = 0; + + /* if output_name is NULL, simply return */ + + if(output_name == NULL) + return (GSS_S_COMPLETE); + + *output_name = 0; + + if (input_name_buffer == GSS_C_NO_BUFFER) + return (GSS_S_BAD_NAME); + + /* + * First create the union name struct that will hold the external + * name and the name type. + */ + + union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); + if (!union_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } + union_name->mech_type = 0; + union_name->mech_name = 0; + union_name->name_type = 0; + union_name->external_name = 0; + union_name->gss_mech = NULL; + + /* + * All we do here is record the external name and name_type. + * When the name is actually used, the underlying gss_import_name() + * is called for the appropriate mechanism. Note that the name type + * is assumed to be constant, so only a pointer to it is stored in + * union_name + */ + union_name->external_name = + (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); + if (!union_name->external_name) { + *minor_status = ENOMEM; + goto allocation_failure; + } + + union_name->external_name->length = input_name_buffer->length; + /* we malloc length+1 to stick a NULL on the end, just in case */ + /* Note that this NULL is not included in ->length for a reason! */ + union_name->external_name->value = + (void *) malloc(input_name_buffer->length+1); + if (!union_name->external_name->value) { + *minor_status = ENOMEM; + goto allocation_failure; + } + + memcpy(union_name->external_name->value, input_name_buffer->value, + input_name_buffer->length); + + /* add NULL to end of external_name->value, just in case... */ + ((char *)union_name->external_name->value) + [input_name_buffer->length] = '\0'; + + major_status = generic_gss_copy_oid(minor_status, input_name_type, + &union_name->name_type); + if (major_status != GSS_S_COMPLETE) + goto allocation_failure; + + /* + * See if this is a mechanism-specific name. If so, let's import + * it now so we can get any error messages, and to avoid trouble + * later... + */ + mech = gss_find_mechanism_from_name_type(input_name_type); + if (mech) { + major_status = generic_gss_copy_oid(minor_status, mech, + &union_name->mech_type); + if (major_status != GSS_S_COMPLETE) + goto allocation_failure; + + major_status = __gss_import_internal_name(minor_status, mech, + union_name, + &union_name->mech_name); + if (major_status) + goto allocation_failure; + } + + *output_name = (gss_name_t) union_name; + + return(GSS_S_COMPLETE); + +allocation_failure: + if (union_name) { + if (union_name->external_name) { + if (union_name->external_name->value) + free(union_name->external_name->value); + free(union_name->external_name); + } + if (union_name->name_type) + generic_gss_release_oid(&tmp, &union_name->name_type); + if (union_name->mech_name) + __gss_release_internal_name(minor_status, union_name->mech_type, + &union_name->mech_name); + if (union_name->mech_type) + generic_gss_release_oid(&tmp, &union_name->mech_type); + free(union_name); + } + return (major_status); +} diff --git a/support/gssapi/g_imp_sec_context.c b/support/gssapi/g_imp_sec_context.c new file mode 100644 index 0000000..faa58ed --- /dev/null +++ b/support/gssapi/g_imp_sec_context.c @@ -0,0 +1,128 @@ +/* #ident "@(#)g_imp_sec_context.c 1.2 96/01/18 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 gss_export_sec_context + */ + +#include "mglueP.h" +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +OM_uint32 KRB5_CALLCONV +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; + +{ + size_t length; + OM_uint32 status; + char *p; + gss_union_ctx_id_t ctx; + gss_buffer_desc token; + gss_mechanism mech; + + gss_initialize(); + + *minor_status = 0; + + if (interprocess_token->length == 0 || interprocess_token->value == 0) + return (GSS_S_DEFECTIVE_TOKEN); + + status = GSS_S_FAILURE; + + ctx = (gss_union_ctx_id_t) malloc(sizeof(gss_union_ctx_id_desc)); + if (!ctx) { + *minor_status = ENOMEM; + goto error_out; + } + ctx->mech_type = (gss_OID) malloc(sizeof(gss_OID_desc)); + if (!ctx->mech_type) { + *minor_status = ENOMEM; + goto error_out; + } + p = interprocess_token->value; + length = *p++; + length = (length << 8) + *p++; + length = (length << 8) + *p++; + length = (length << 8) + *p++; + + ctx->mech_type->length = length; + ctx->mech_type->elements = malloc(length); + if (!ctx->mech_type->elements) { + *minor_status = ENOMEM; + goto error_out; + } + memcpy(ctx->mech_type->elements, p, length); + p += length; + + token.length = interprocess_token->length - 4 - length; + token.value = p; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + mech = __gss_get_mechanism (ctx->mech_type); + if (!mech) { + status = GSS_S_BAD_MECH; + goto error_out; + } + if (!mech->gss_import_sec_context) { + status = GSS_S_BAD_BINDINGS; + goto error_out; + } + +#ifdef USE_MECH_CONTEXT + status = mech->gss_import_sec_context(mech->context, minor_status, +#else + status = mech->gss_import_sec_context(minor_status, +#endif + &token, &ctx->internal_ctx_id); + + if (status == GSS_S_COMPLETE) { + *context_handle = ctx; + return (GSS_S_COMPLETE); + } + +error_out: + if (ctx) { + if (ctx->mech_type) { + if (ctx->mech_type->elements) + free(ctx->mech_type->elements); + free(ctx->mech_type); + } + free(ctx); + } + return status; +} diff --git a/support/gssapi/g_indicate_mechs.c b/support/gssapi/g_indicate_mechs.c new file mode 100644 index 0000000..9006d6d --- /dev/null +++ b/support/gssapi/g_indicate_mechs.c @@ -0,0 +1,90 @@ +/* #ident "@(#)gss_indicate_mechs.c 1.13 95/08/04 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_indicate_mechs + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +extern gss_mechanism *__gss_mechs_array; + +static gss_OID_set_desc supported_mechs_desc; +static gss_OID_set supported_mechs = NULL; + +OM_uint32 KRB5_CALLCONV +gss_indicate_mechs (minor_status, + mech_set) + +OM_uint32 * minor_status; +gss_OID_set * mech_set; + +{ + int i; + + gss_initialize(); + + if (minor_status) + *minor_status = 0; + + /* + * If we have already computed the mechanisms supported, return + * a pointer to it. Otherwise, compute them and return the pointer. + */ + + if(supported_mechs == NULL) { + + supported_mechs = &supported_mechs_desc; + supported_mechs->count = 0; + + /* Build the mech_set from the OIDs in mechs_array. */ + + for(i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) + supported_mechs->count++; + + supported_mechs->elements = + (void *) malloc(supported_mechs->count * + sizeof(gss_OID_desc)); + + for(i=0; i < supported_mechs->count; i++) { + supported_mechs->elements[i].length = + __gss_mechs_array[i]->mech_type.length; + supported_mechs->elements[i].elements = (void *) + malloc(__gss_mechs_array[i]->mech_type.length); + memcpy(supported_mechs->elements[i].elements, + __gss_mechs_array[i]->mech_type.elements, + __gss_mechs_array[i]->mech_type.length); + } + } + + if(mech_set != NULL) + *mech_set = supported_mechs; + + return(GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_init_sec_context.c b/support/gssapi/g_init_sec_context.c new file mode 100644 index 0000000..a838597 --- /dev/null +++ b/support/gssapi/g_init_sec_context.c @@ -0,0 +1,194 @@ +/* #ident "@(#)gss_init_sec_context.c 1.20 95/08/07 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_init_sec_context + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +OM_uint32 KRB5_CALLCONV +gss_init_sec_context (minor_status, + claimant_cred_handle, + context_handle, + target_name, + req_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 req_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; + +{ + OM_uint32 status, temp_status, temp_minor_status; + gss_union_name_t union_name; + gss_union_cred_t union_cred; + gss_name_t internal_name; + gss_union_ctx_id_t union_ctx_id; + gss_OID mech_type = (gss_OID) req_mech_type; + gss_mechanism mech; + gss_cred_id_t input_cred_handle; + + gss_initialize(); + + if (context_handle == NULL) + return GSS_S_NO_CONTEXT; + + union_name = (gss_union_name_t) target_name; + + /* + * If mech_type is NULL, and the target_name is + * mechanism-specific, then set it to the mech_type of + * target_name. + */ + if ((mech_type == GSS_C_NULL_OID) && union_name->mech_type) + mech_type = union_name->mech_type; + + /* + * obtain the gss mechanism information for the requested + * mechanism. If mech_type is NULL, set it to the resultant + * mechanism + */ + mech = __gss_get_mechanism (mech_type); + if (mech == NULL) + return (GSS_S_BAD_MECH); + + if (mech_type == GSS_C_NULL_OID) + mech_type = &mech->mech_type; + + /* + * If target_name is mechanism_specific, then it must match the + * mech_type that we're about to use. Otherwise, do an import on + * the external_name form of the target name. + */ + if (union_name->mech_type) { + if (!g_OID_equal(union_name->mech_type, mech_type)) + return (GSS_S_BAD_MECH); + internal_name = union_name->mech_name; + } else { + if ((temp_status = __gss_import_internal_name(minor_status, mech_type, + union_name, + &internal_name))) + return (GSS_S_BAD_NAME); + } + + /* + * if context_handle is GSS_C_NO_CONTEXT, allocate a union context + * descriptor to hold the mech type information as well as the + * underlying mechanism context handle. Otherwise, cast the + * value of *context_handle to the union context variable. + */ + + if(*context_handle == GSS_C_NO_CONTEXT) { + union_ctx_id = (gss_union_ctx_id_t) + malloc(sizeof(gss_union_ctx_id_desc)); + + union_ctx_id->mech_type = (gss_OID) + malloc(sizeof(gss_OID_desc)); + + /* copy in the mech type information */ + + union_ctx_id->mech_type->elements = (void *) + malloc(mech_type->length); + + union_ctx_id->mech_type->length = mech_type->length; + memcpy(union_ctx_id->mech_type->elements, mech_type->elements, + mech_type->length); + + /* copy the supplied context handle */ + + union_ctx_id->internal_ctx_id = *context_handle; + } else + union_ctx_id = *context_handle; + + /* + * get the appropriate cred handle from the union cred struct. + * defaults to GSS_C_NO_CREDENTIAL if there is no cred, which will + * use the default credential. + */ + union_cred = (gss_union_cred_t) claimant_cred_handle; + input_cred_handle = __gss_get_mechanism_cred(union_cred, mech_type); + + /* + * now call the approprate underlying mechanism routine + */ + + if (mech->gss_init_sec_context) { + status = mech->gss_init_sec_context( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + input_cred_handle, + &union_ctx_id->internal_ctx_id, + internal_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + + if (*context_handle == GSS_C_NO_CONTEXT) + *context_handle = (gss_ctx_id_t) union_ctx_id; + + } else + status = GSS_S_BAD_BINDINGS; + + if (!union_name->mech_type) { + (void) __gss_release_internal_name(&temp_minor_status, + mech_type, &internal_name); + } + + return(status); +} diff --git a/support/gssapi/g_initialize.c b/support/gssapi/g_initialize.c new file mode 100644 index 0000000..9523d40 --- /dev/null +++ b/support/gssapi/g_initialize.c @@ -0,0 +1,380 @@ +/* #ident "@(#)g_initialize.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. + */ + +/* + * This function will initialize the gssapi mechglue library + */ + +#include "config.h" +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include +#include +#include + +#ifdef USE_SOLARIS_SHARED_LIBRARIES +#include + +#define MECH_CONF "/etc/mech.conf" +#define MECH_SYM "gss_mech_initialize" + +static void solaris_initialize (void); +#endif /* USE_SOLARIS_SHARED_LIBRARIES */ + +#ifdef __linux__ +#define USE_LINUX_SHARED_LIBRARIES +#endif + +#ifdef USE_LINUX_SHARED_LIBRARIES +#include +#define MECH_CONF "/etc/gssapi_mech.conf" +#define MECH_SYM "gss_mech_initialize" +static void linux_initialize (void); +#endif /* USE_LINUX_SHARED_LIBRARIES */ + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +extern gss_mechanism krb5_gss_initialize(); + +static int _gss_initialized = 0; + +static struct gss_config null_mech = { + {0,NULL}}; + +gss_mechanism *__gss_mechs_array = NULL; + +/* + * This function will add a new mechanism to the mechs_array + */ + +static OM_uint32 +add_mechanism (mech, replace) + gss_mechanism mech; + int replace; +{ + gss_mechanism * temp_array; + gss_OID_set mech_names; + OM_uint32 minor_status, major_status; + unsigned int i; + + if (mech == NULL) + return GSS_S_COMPLETE; + + /* initialize the mechs_array if it hasn't already been initialized */ + if (__gss_mechs_array == NULL) { + __gss_mechs_array = (gss_mechanism *) malloc (sizeof(gss_mechanism)); + + if (__gss_mechs_array == NULL) + return ENOMEM; + + __gss_mechs_array[0] = &null_mech; + } + + /* + * Find the length of __gss_mechs_array, and look for an existing + * entry for this OID + */ + for (i=0; __gss_mechs_array[i]->mech_type.length != 0; i++) { + if (!g_OID_equal(&__gss_mechs_array[i]->mech_type, + &mech->mech_type)) + continue; + + /* We found a match. Replace it? */ + if (!replace) + return GSS_S_FAILURE; + + __gss_mechs_array[i] = mech; + return GSS_S_COMPLETE; + } + + /* we didn't find it -- add it to the end of the __gss_mechs_array */ + temp_array = (gss_mechanism *) realloc(__gss_mechs_array, + (i+2)*sizeof(gss_mechanism)); + + if (temp_array == NULL) + return ENOMEM; + + temp_array[i++] = mech; + temp_array[i] = &null_mech; + + __gss_mechs_array = temp_array; + + /* + * OK, now let's register all of the name types this mechanism + * knows how to deal with. + */ + major_status = gss_inquire_names_for_mech(&minor_status, &mech->mech_type, + &mech_names); + if (major_status != GSS_S_COMPLETE) + return (GSS_S_COMPLETE); + for (i=0; i < mech_names->count; i++) { + gss_add_mech_name_type(&minor_status, &mech_names->elements[i], + &mech->mech_type); + } + (void) gss_release_oid_set(&minor_status, &mech_names); + + return GSS_S_COMPLETE; +} + +void gss_initialize () +{ + /* Make sure we've not run already */ + if (_gss_initialized) + return; + _gss_initialized = 1; + +#ifdef USE_SOLARIS_SHARED_LIBRARIES + solaris_initialize(); + +#elif defined(USE_LINUX_SHARED_LIBRARIES) + linux_initialize(); + +#else + { + gss_mechanism mech; + + /* + * Use hard-coded in mechanisms... I need to know what mechanisms + * are supported... As more mechanisms become supported, they + * should be added here, unless shared libraries are used. + */ + + /* Initialize the krb5 mechanism */ + mech = (gss_mechanism)krb5_gss_initialize(); + if (mech) + add_mechanism (mech, 1); + } + +#endif /* USE_SOLARIS_SHARED_LIBRARIES */ + +#if !defined(macintosh) + if (__gss_mechs_array == NULL) { /* this is very bad! */ + fprintf(stderr,"gss_initialize fatal error: no mechanisms loaded!\n"); + exit(-1); + } +#else + /* + * Nothing for now, since this should never happen using static + * mechanism loading. + */ +#endif + + return; +} + +#ifdef USE_SOLARIS_SHARED_LIBRARIES +/* + * read the configuration file to find out what mechanisms to + * load, load them, and then load the mechanism defitions in + * and add the mechanisms + */ +static void solaris_initialize () +{ + char buffer[BUFSIZ], *filename, *symname, *endp; + FILE *conffile; + void *dl; + gss_mechanism (*sym)(void), mech; + + if ((filename = getenv("GSSAPI_MECH_CONF")) == NULL) + filename = MECH_CONF; + + if ((conffile = fopen(filename, "r")) == NULL) { + fprintf(stderr,"fatal error: unable to open %s:" + " errno %d (%s)\n", filename, errno, strerror(errno)); + return; + } + + while (fgets (buffer, BUFSIZ, conffile) != NULL) { + /* ignore lines beginning with # */ + if (*buffer == '#') + continue; + + /* find the first white-space character after the filename */ + for (symname = buffer; *symname && !isspace(*symname); symname++); + + /* Now find the first non-white-space character */ + if (*symname) { + *symname = '\0'; + symname++; + while (*symname && isspace(*symname)) + symname++; + } + + if (! *symname) + symname = MECH_SYM; + else { + /* Find the end of the symname and make sure it is NULL-terminated */ + for (endp = symname; *endp && !isspace(*endp); endp++); + if (*endp) + *endp = '\0'; + } + + if ((dl = dlopen(buffer, RTLD_NOW)) == NULL) { + /* for debugging only */ + fprintf(stderr,"can't open %s: %s\n",buffer, dlerror()); + continue; + } + + if ((sym = (gss_mechanism (*)(void))dlsym(dl, symname)) == NULL) { + dlclose(dl); + continue; + } + + /* Call the symbol to get the mechanism table */ + mech = sym(); + + /* And add the mechanism (or close the shared library) */ + if (mech) + add_mechanism (mech, 1); + else + dlclose(dl); + + } /* while */ + + return; +} +#endif /* USE_SOLARIS_SHARED_LIBRARIES */ + +#ifdef USE_LINUX_SHARED_LIBRARIES +extern gss_mechanism internal_krb5_gss_initialize(void *dl); + +/* + * read the configuration file to find out what mechanisms to + * load, load them, and then load the mechanism defitions in + * and add the mechanisms + */ +static void linux_initialize () +{ + char buffer[BUFSIZ], *filename, *symname, *endp, *err_string; + FILE *conffile; + void *dl; + gss_mechanism (*sym)(void), mech; + + if ((filename = getenv("GSSAPI_MECH_CONF")) == NULL) + filename = MECH_CONF; + + if ((conffile = fopen(filename, "r")) == NULL) { + fprintf(stderr,"fatal error: unable to open %s:" + " errno %d (%s)\n", filename, errno, strerror(errno)); + return; + } + + while (fgets (buffer, BUFSIZ, conffile) != NULL) { + /* ignore lines beginning with # */ + if (*buffer == '#') + continue; + + /* find the first white-space character after the filename */ + for (symname = buffer; *symname && !isspace(*symname); symname++); + + /* Now find the first non-white-space character */ + if (*symname) { + *symname = '\0'; + symname++; + while (*symname && isspace(*symname)) + symname++; + } + + if (! *symname) + symname = MECH_SYM; + else { + /* Find the end of the symname and make sure it is + * NULL-terminated */ + for (endp = symname; *endp && !isspace(*endp); endp++); + if (*endp) + *endp = '\0'; + } + + if ((dl = dlopen(buffer, RTLD_NOW)) == NULL) { + /* for debugging only */ + fprintf(stderr,"can't open %s: %s\n",buffer, dlerror()); + continue; + } + +#if defined(HAVE_KRB5) && defined(HAVE_HEIMDAL) +#error Should not have both HAVE_KRB5 and HAVE_HEIMDAL defined!! +#endif + +#ifdef HAVE_KRB5 + /* Special case for dealing with MIT krb5 mechanism */ + if (strcmp(symname, "mechglue_internal_krb5_init") == 0) { +#ifdef DEBUG + fprintf(stderr, "Using special MIT initialization\n"); +#endif + mech = internal_krb5_gss_initialize(dl); + } + else +#endif + +#ifdef HAVE_HEIMDAL + /* Special case for dealing with heimdal krb5 mechanism */ + if (strcmp(symname, "mechglue_internal_heimdal_init") == 0) { +#ifdef DEBUG + fprintf(stderr, "Using special Heimdal initialization\n"); +#endif + mech = internal_heimdal_gss_initialize(dl); + } + else +#endif + { + if ((sym = (gss_mechanism (*)(void))dlsym(dl, symname)) == NULL) { + if ((err_string = dlerror()) != NULL) { + fprintf(stderr, "%s: searching for symbol '%s' in '%s'\n", + err_string, symname, buffer); + dlclose(dl); + } + continue; + } + + /* Call the symbol to get the mechanism table */ + mech = sym(); + } + + /* And add the mechanism (or close the shared library) */ + if (mech) { +#ifdef DEBUG + fprintf(stderr, "Adding mechanism for library '%s'\n", buffer); +#endif + add_mechanism (mech, 1); + } + else { +#ifdef DEBUG + fprintf(stderr, + "Failed to initialize mechanism for library '%s'\n", + buffer); +#endif + dlclose(dl); + } + + } /* while */ + + return; +} +#endif /* USE_LINUX_SHARED_LIBRARIES */ diff --git a/support/gssapi/g_inq_context.c b/support/gssapi/g_inq_context.c new file mode 100644 index 0000000..60f0e82 --- /dev/null +++ b/support/gssapi/g_inq_context.c @@ -0,0 +1,143 @@ +/* #ident "@(#)g_inquire_context.c 1.2 96/01/18 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_inquire_context + */ + +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif + +/* Last argument new for V2 */ +OM_uint32 KRB5_CALLCONV +gss_inquire_context( + minor_status, + context_handle, + src_name, + targ_name, + lifetime_rec, + mech_type, + ctx_flags, + locally_initiated, + open) + +OM_uint32 * minor_status; +gss_ctx_id_t context_handle; +gss_name_t * src_name; +gss_name_t * targ_name; +OM_uint32 * lifetime_rec; +gss_OID * mech_type; +OM_uint32 * ctx_flags; +int * locally_initiated; +int * open; + + +{ + gss_union_ctx_id_t ctx; + gss_mechanism mech; + OM_uint32 status, temp_minor; + + gss_initialize(); + + /* if the context_handle is Null, return NO_CONTEXT error */ + + if(context_handle == GSS_C_NO_CONTEXT) + return(GSS_S_NO_CONTEXT); + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (!mech || !mech->gss_inquire_context || !mech->gss_display_name) { + return(GSS_S_NO_CONTEXT); + + } + + status = mech->gss_inquire_context( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + src_name, + targ_name, + lifetime_rec, + mech_type, + ctx_flags, + locally_initiated, + open); + + if (status != GSS_S_COMPLETE) { + return status; + } + + /* need to convert names */ + + if (src_name) { + status = __gss_convert_name_to_union_name(minor_status, mech, + *src_name, src_name); + + if (status != GSS_S_COMPLETE) { +#ifdef USE_MECH_CONTEXT + (void) mech->gss_release_name(mech->context, +#else + (void) mech->gss_release_name( +#endif + &temp_minor, src_name); +#ifdef USE_MECH_CONTEXT + (void) mech->gss_release_name(mech->context, +#else + (void) mech->gss_release_name( +#endif + &temp_minor, targ_name); + if (mech_type) { + mech_gss_release_oid(&temp_minor, mech_type, + mech); + } + return (GSS_S_FAILURE); + } + + } + + if (targ_name) { + status = __gss_convert_name_to_union_name(minor_status, mech, + *targ_name, targ_name); + + if (status != GSS_S_COMPLETE) { + if (mech_type) { + mech_gss_release_oid(&temp_minor, mech_type, mech); + } + return (GSS_S_FAILURE); + } + } + + return(GSS_S_COMPLETE); +} + diff --git a/support/gssapi/g_inq_cred.c b/support/gssapi/g_inq_cred.c new file mode 100644 index 0000000..6671f70 --- /dev/null +++ b/support/gssapi/g_inq_cred.c @@ -0,0 +1,199 @@ +/* #ident "@(#)gss_inquire_cred.c 1.9 95/08/02 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_inquire_cred + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include +#include + +OM_uint32 KRB5_CALLCONV +gss_inquire_cred(minor_status, + cred_handle, + name, + lifetime, + cred_usage, + mechanisms) + +OM_uint32 * minor_status; +gss_cred_id_t cred_handle; +gss_name_t * name; +OM_uint32 * lifetime; +int * cred_usage; +gss_OID_set * mechanisms; + +{ + OM_uint32 status, elapsed_time, temp_minor_status; + gss_union_cred_t union_cred; + gss_mechanism mech; + gss_name_t internal_name; + int i; + + gss_initialize(); + + if (cred_handle == GSS_C_NO_CREDENTIAL) { + /* + * No credential was supplied. This means we can't get a mechanism + * pointer to call the mechanism specific gss_inquire_cred. + * So, call get_mechanism with an arguement of GSS_C_NULL_OID. + * get_mechanism will return the first mechanism in the mech + * array, which becomes the default mechanism. + */ + + if ((mech = __gss_get_mechanism(GSS_C_NULL_OID)) == NULL) + return(GSS_S_NO_CRED); + + if (!mech->gss_inquire_cred) + return (GSS_S_FAILURE); + +#ifdef USE_MECH_CONTEXT + status = mech->gss_inquire_cred(mech->context, minor_status, +#else + status = mech->gss_inquire_cred(minor_status, +#endif + GSS_C_NO_CREDENTIAL, + name ? &internal_name : NULL, + lifetime, cred_usage, mechanisms); + + if (status != GSS_S_COMPLETE) + return(status); + + if (name) { + /* + * Convert internal_name into a union_name equivalent. + */ + status = __gss_convert_name_to_union_name(&temp_minor_status, + mech, internal_name, + name); + if (status != GSS_S_COMPLETE) { + if (minor_status) + *minor_status = temp_minor_status; + __gss_release_internal_name(&temp_minor_status, + &mech->mech_type, &internal_name); + return (status); + } + } + return(GSS_S_COMPLETE); + } + + /* get the cred_handle cast as a union_credentials structure */ + + union_cred = (gss_union_cred_t) cred_handle; + + /* + * get the information out of the union_cred structure that was + * placed there during gss_acquire_cred. + */ + + if(cred_usage != NULL) + *cred_usage = union_cred->auxinfo.cred_usage; + + if(lifetime != NULL) { + elapsed_time = time(0) - union_cred->auxinfo.creation_time; + *lifetime = union_cred->auxinfo.time_rec < elapsed_time ? 0 : + union_cred->auxinfo.time_rec - elapsed_time; + } + + /* + * if name is non_null, + * call gss_import_name(), giving it the printable name held within + * union_cred in order to get an internal name to pass back to the + * caller. If this call fails, return failure to our caller. + */ + + if(name != NULL) + if(gss_import_name(&temp_minor_status, + &union_cred->auxinfo.name, + union_cred->auxinfo.name_type, + name) != GSS_S_COMPLETE) + return(GSS_S_DEFECTIVE_CREDENTIAL); + + /* + * copy the mechanism set in union_cred into an OID set and return in + * the mechanisms parameter. + */ + + if(mechanisms != NULL) { + + *mechanisms = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)); + + (*mechanisms)->count = union_cred->count; + (*mechanisms)->elements = + (gss_OID) malloc(sizeof(gss_OID_desc) * + union_cred->count); + + for(i=0; i < union_cred->count; i++) { + (*mechanisms)->elements[i].length = + union_cred->mechs_array[i].length; + (*mechanisms)->elements[i].elements = (void *) + malloc(union_cred->mechs_array[i].length); + memcpy((*mechanisms)->elements[i].elements, + union_cred->mechs_array[i].elements, + union_cred->mechs_array[i].length); + } + } + + return(GSS_S_COMPLETE); +} + +OM_uint32 KRB5_CALLCONV +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; +{ + gss_union_cred_t union_cred; + gss_cred_id_t mech_cred; + gss_mechanism mech; + + mech = __gss_get_mechanism (mech_type); + if (!mech) + return (GSS_S_BAD_MECH); + if (!mech->gss_inquire_cred_by_mech) + return (GSS_S_BAD_BINDINGS); + + union_cred = (gss_union_cred_t) cred_handle; + mech_cred = __gss_get_mechanism_cred(union_cred, mech_type); + +#ifdef USE_MECH_CONTEXT + return (mech->gss_inquire_cred_by_mech(mech->context, minor_status, +#else + return (mech->gss_inquire_cred_by_mech(minor_status, +#endif + mech_cred, mech_type, + name, initiator_lifetime, + acceptor_lifetime, cred_usage)); +} + diff --git a/support/gssapi/g_inq_names.c b/support/gssapi/g_inq_names.c new file mode 100644 index 0000000..cfcb27d --- /dev/null +++ b/support/gssapi/g_inq_names.c @@ -0,0 +1,69 @@ +/* #ident "@(#)g_inquire_names.c 1.1 95/12/19 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_inquire_context + */ + +#include "mglueP.h" + +/* Last argument new for V2 */ +OM_uint32 KRB5_CALLCONV +gss_inquire_names_for_mech(minor_status, mechanism, name_types) + +OM_uint32 * minor_status; +gss_OID mechanism; +gss_OID_set * name_types; + +{ + OM_uint32 status; + gss_mechanism mech; + + gss_initialize(); + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + mech = __gss_get_mechanism (mechanism); + + if (mech) { + + if (mech->gss_inquire_names_for_mech) + status = mech->gss_inquire_names_for_mech( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + mechanism, + name_types); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} diff --git a/support/gssapi/g_mechname.c b/support/gssapi/g_mechname.c new file mode 100644 index 0000000..4f0a013 --- /dev/null +++ b/support/gssapi/g_mechname.c @@ -0,0 +1,116 @@ +/* + * g_mechname.c --- registry of mechanism-specific name types + * + * This file contains a registry of mechanism-specific name types. It + * is used to determine which name types not should be lazy evaluated, + * but rather evaluated on the spot. + */ + +#include "mglueP.h" +#ifdef HAVE_STDLIB_H +#include +#endif + +#include +#include +#include + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +static gss_mech_spec_name name_list = NULL; + +/* + * generic searching helper function. + */ +static gss_mech_spec_name search_mech_spec(name_type) + gss_OID name_type; +{ + gss_mech_spec_name p; + + for (p = name_list; p; p = p->next) { + if (g_OID_equal(name_type, p->name_type)) + return p; + } + return NULL; +} + +/* + * Given a name_type, if it is specific to a mechanism, return the + * mechanism OID. Otherwise, return NULL. + */ +gss_OID gss_find_mechanism_from_name_type(name_type) + gss_OID name_type; +{ + gss_mech_spec_name p; + + p = search_mech_spec(name_type); + if (!p) + return NULL; + return p->mech; +} + +/* + * This function adds a (name_type, mechanism) pair to the + * mechanism-specific name type registry. If an entry for the + * name_type already exists, then zero out the mechanism entry. + * Otherwise, enter the pair into the registry. + */ +OM_uint32 +gss_add_mech_name_type(minor_status, name_type, mech) + OM_uint32 *minor_status; + gss_OID name_type; + gss_OID mech; +{ + OM_uint32 major_status, tmp; + gss_mech_spec_name p; + + p = search_mech_spec(name_type); + if (p) { + /* + * We found an entry for this name type; mark it as not being + * a mechanism-specific name type. + */ + if (p->mech) { + if (!g_OID_equal(mech, p->mech)) { + generic_gss_release_oid(minor_status, &p->mech); + p->mech = 0; + } + } + return GSS_S_COMPLETE; + } + p = malloc(sizeof(gss_mech_spec_name_desc)); + if (!p) { + *minor_status = ENOMEM; + goto allocation_failure; + } + p->name_type = 0; + p->mech = 0; + + major_status = generic_gss_copy_oid(minor_status, name_type, + &p->name_type); + if (major_status) + goto allocation_failure; + major_status = generic_gss_copy_oid(minor_status, mech, + &p->mech); + if (major_status) + goto allocation_failure; + + p->next = name_list; + p->prev = 0; + name_list = p; + + return GSS_S_COMPLETE; + +allocation_failure: + if (p) { + if (p->mech) + generic_gss_release_oid(&tmp, &p->mech); + if (p->name_type) + generic_gss_release_oid(&tmp, &p->name_type); + free(p); + } + return GSS_S_FAILURE; +} + diff --git a/support/gssapi/g_mit_krb5_mech.c b/support/gssapi/g_mit_krb5_mech.c new file mode 100644 index 0000000..1caa8d2 --- /dev/null +++ b/support/gssapi/g_mit_krb5_mech.c @@ -0,0 +1,297 @@ +/* + * g_mit_krb5_mech.c + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Kevin Coffman + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include +#include +#include "mglueP.h" + +/* + * Table of function names that we need to locate within a mechanism's + * shared library if it does not support the xxx_gss_initialize function. + */ +static char *glue_func_names[] = { + "gss_acquire_cred", + "gss_release_cred", + "gss_init_sec_context", + "gss_accept_sec_context", + "gss_process_context_token", + "gss_delete_sec_context", + "gss_context_time", + "gss_sign", + "gss_verify", + "gss_seal", + "gss_unseal", + "gss_display_status", + "gss_indicate_mechs", + "gss_compare_name", + "gss_display_name", + "gss_import_name", + "gss_release_name", + "gss_inquire_cred", + "gss_add_cred", + "gss_export_sec_context", + "gss_import_sec_context", + "gss_inquire_cred_by_mech", + "gss_inquire_names_for_mech", + "gss_inquire_context", + "gss_internal_release_oid", + "gss_wrap_size_limit", + "pname_to_uid", + "gss_duplicate_name", + "gss_set_allowable_enctypes", + "gss_verify_mic", + NULL +}; + +#ifdef HAVE_KRB5 +/* + * The MIT code does not support the krb5_gss_initialize function, so + * we need to locate the functions within the gssapi_krb5.so library + * and fill in this structure. + */ +static struct gss_config mit_krb5_mechanism = { + {9, "\052\206\110\206\367\022\001\002\002"}, + NULL, /* mechanism context -- we don't currently use this */ + NULL, /* gss_acquire_cred */ + NULL, /* gss_release_cred */ + NULL, /* gss_init_sec_context */ + NULL, /* gss_accept_sec_context */ + NULL, /* gss_process_context_token */ + NULL, /* gss_delete_sec_context */ + NULL, /* gss_context_time */ + NULL, /* gss_sign */ + NULL, /* gss_verify */ + NULL, /* gss_seal */ + NULL, /* gss_unseal */ + NULL, /* gss_display_status */ + NULL, /* gss_indicate_mechs */ + NULL, /* gss_compare_name */ + NULL, /* gss_display_name */ + NULL, /* gss_import_name */ + NULL, /* gss_release_name */ + NULL, /* gss_inquire_cred */ + NULL, /* gss_add_cred */ + NULL, /* gss_export_sec_context */ + NULL, /* gss_import_sec_context */ + NULL, /* gss_inquire_cred_by_mech */ + NULL, /* gss_inquire_names_for_mech */ + NULL, /* gss_inquire_context */ + NULL, /* gss_internal_release_oid */ + NULL, /* gss_wrap_size_limit */ + NULL, /* pname_to_uid */ + NULL, /* gss_duplicate_name */ + NULL, /* gss_set_allowable_enctypes */ + NULL, /* gss_verify_mic */ +}; +#endif + +#ifdef HAVE_HEIMDAL +/* + * The heimdal code does not support the krb5_gss_initialize function, so + * we need to locate the functions within the libgssapi.so library + * and fill in this structure. + */ +static struct gss_config heimdal_krb5_mechanism = { + {9, "\052\206\110\206\367\022\001\002\002"}, + NULL, /* mechanism context -- we don't currently use this */ + NULL, /* gss_acquire_cred */ + NULL, /* gss_release_cred */ + NULL, /* gss_init_sec_context */ + NULL, /* gss_accept_sec_context */ + NULL, /* gss_process_context_token */ + NULL, /* gss_delete_sec_context */ + NULL, /* gss_context_time */ + NULL, /* gss_sign */ + NULL, /* gss_verify */ + NULL, /* gss_seal */ + NULL, /* gss_unseal */ + NULL, /* gss_display_status */ + NULL, /* gss_indicate_mechs */ + NULL, /* gss_compare_name */ + NULL, /* gss_display_name */ + NULL, /* gss_import_name */ + NULL, /* gss_release_name */ + NULL, /* gss_inquire_cred */ + NULL, /* gss_add_cred */ + NULL, /* gss_export_sec_context */ + NULL, /* gss_import_sec_context */ + NULL, /* gss_inquire_cred_by_mech */ + NULL, /* gss_inquire_names_for_mech */ + NULL, /* gss_inquire_context */ + NULL, /* gss_internal_release_oid */ + NULL, /* gss_wrap_size_limit */ + NULL, /* pname_to_uid */ + NULL, /* gss_duplicate_name */ + NULL, /* gss_set_allowable_enctypes */ + NULL, /* gss_verify_mic */ +}; +#endif + + +/* + * Given a handle to a dynamic library (dl) and a symbol + * name (symname), return its address. Returns -1 if the + * symbol cannot be located. (Note that the value of the + * symbol could be NULL, which is valid.) + */ +void * +locate_symbol(void *dl, char *symname, char *prefix) +{ + void *sym; + const char *err_string; + char fullname[256]; + + snprintf(fullname, sizeof(fullname), "%s%s", prefix, symname); + + if ((sym = dlsym(dl, fullname)) == NULL) { + if ((sym = dlsym(dl, symname)) == NULL) { + if ((err_string = dlerror()) != NULL) { + return (void *)-1; + } + else { + return NULL; + } + } + } + return sym; +} + +#ifdef HAVE_KRB5 +/* + * Locate all the symbols in the MIT gssapi library and + * fill in the gss_config (gss_mechanism) structure. + */ +gss_mechanism +internal_krb5_gss_initialize(void *dl) +{ + char *fname; + void *p; + void **fptr; + int i; + static int mit_krb5_initialized = 0; + + if (mit_krb5_initialized) + return (&mit_krb5_mechanism); + + fptr = (void *) &mit_krb5_mechanism.gss_acquire_cred; + + + for (i = 0, fname = glue_func_names[i]; + fname; + i++, fname = glue_func_names[i]) { + if ((p = locate_symbol(dl, fname, "krb5_")) != (void *)-1) { + *fptr++ = p; + } + else { + *fptr++ = NULL; + } + } + if (mit_krb5_mechanism.gss_internal_release_oid == NULL || + mit_krb5_mechanism.gss_internal_release_oid == (void *) -1) { + fprintf(stderr, "WARNING: unable to locate function " + "krb5_gss_internal_release_oid in krb5 mechanism library: " + "there will be problems if multiple mechanisms are used!\n"); + p = locate_symbol(dl, "krb5_gss_release_oid", ""); + if (p == NULL || p == (void *) -1) { + fprintf(stderr, "ERROR: Unable to locate function " + "krb5_gss_internal_release_oid or " + "krb5_gss_release_oid in krb5 mechanism library\n"); + return NULL; + } + } +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + /* + * Special case for set_allowable_enctypes which has a different + * name format than the rest of the gss routines :-/ + */ + if ((p = locate_symbol(dl, "gss_krb5_set_allowable_enctypes", "")) + != (void *)-1) { + mit_krb5_mechanism.gss_set_allowable_enctypes = p; + } +#endif + mit_krb5_initialized = 1; + return (&mit_krb5_mechanism); +} +#endif + +#ifdef HAVE_HEIMDAL +/* + * Locate all the symbols in the MIT gssapi library and + * fill in the gss_config (gss_mechanism) structure. + */ +gss_mechanism +internal_heimdal_gss_initialize(void *dl) +{ + char *fname; + void *p; + void **fptr; + int i; + static int heimdal_krb5_initialized = 0; + + if (heimdal_krb5_initialized) + return (&heimdal_krb5_mechanism); + + fptr = (void *) &heimdal_krb5_mechanism.gss_acquire_cred; + + + for (i = 0, fname = glue_func_names[i]; + fname; + i++, fname = glue_func_names[i]) { + if ((p = locate_symbol(dl, fname, "")) != (void *)-1) { + *fptr++ = p; + } + else { +printf("Failed to locate function '%s' !!!\n", fname); + *fptr++ = NULL; + } + } + if (heimdal_krb5_mechanism.gss_internal_release_oid == NULL || + heimdal_krb5_mechanism.gss_internal_release_oid == (void *) -1) { + fprintf(stderr, "WARNING: unable to locate function " + "gss_internal_release_oid in krb5 mechanism library: " + "there will be problems if multiple mechanisms are used!\n"); + p = locate_symbol(dl, "krb5_gss_release_oid", ""); + if (p == NULL || p == (void *) -1) { + fprintf(stderr, "ERROR: Unable to locate function " + "gss_internal_release_oid or " + "gss_release_oid in krb5 mechanism library\n"); + return NULL; + } + } + heimdal_krb5_initialized = 1; + return (&heimdal_krb5_mechanism); +} +#endif diff --git a/support/gssapi/g_oid_ops.c b/support/gssapi/g_oid_ops.c new file mode 100644 index 0000000..da0d61a --- /dev/null +++ b/support/gssapi/g_oid_ops.c @@ -0,0 +1,121 @@ +/* + * lib/gssapi/mechglue/g_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. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs + */ + +#include +#include "mglueP.h" +/* should include to get protos #include "../generic/gssapiP_generic.h" */ + +extern gss_mechanism *__gss_mechs_array; + +OM_uint32 KRB5_CALLCONV +gss_release_oid(minor_status, oid) + OM_uint32 *minor_status; + gss_OID *oid; +{ + int i; + OM_uint32 major_status; + + /* first call the gss_internal_release_oid for each mechanism + * until one returns success. gss_internal_release_oid will only return + * success when the OID was recognized as an internal mechanism OID. + * if no mechanisms recognize the OID, then call the generic version. + */ + + for(i=0; __gss_mechs_array[i]->mech_type.length !=0; i++) { + if (__gss_mechs_array[i]->gss_internal_release_oid) { + major_status = __gss_mechs_array[i]->gss_internal_release_oid( +#ifdef USE_MECH_CONTEXT + __gss_mechs_array[i]->context, +#endif + minor_status, + oid); +#ifdef DEBUG + fprintf(stderr, "gss_release_oid (glue): mech returned 0x%08x\n", + major_status); +#endif + if (major_status == GSS_S_COMPLETE) { + return (GSS_S_COMPLETE); + } + } + } + +#ifdef DEBUG + fprintf(stderr, "gss_release_oid (glue): calling " + "generic_gss_release_oid with oid %p (*oid %p)\n", oid, *oid); +#endif + return generic_gss_release_oid(minor_status, oid); +} + +OM_uint32 KRB5_CALLCONV +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 KRB5_CALLCONV +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 KRB5_CALLCONV +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); +} + +OM_uint32 KRB5_CALLCONV +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 KRB5_CALLCONV +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); +} + diff --git a/support/gssapi/g_process_context.c b/support/gssapi/g_process_context.c new file mode 100644 index 0000000..322d597 --- /dev/null +++ b/support/gssapi/g_process_context.c @@ -0,0 +1,75 @@ +/* #ident "@(#)gss_process_context.c 1.9 95/08/07 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 gss_process_context + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + + if (mech->gss_process_context_token) + status = mech->gss_process_context_token( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + token_buffer); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} diff --git a/support/gssapi/g_rel_buffer.c b/support/gssapi/g_rel_buffer.c new file mode 100644 index 0000000..c1104fd --- /dev/null +++ b/support/gssapi/g_rel_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 "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +OM_uint32 KRB5_CALLCONV +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/support/gssapi/g_rel_cred.c b/support/gssapi/g_rel_cred.c new file mode 100644 index 0000000..27a6d82 --- /dev/null +++ b/support/gssapi/g_rel_cred.c @@ -0,0 +1,104 @@ +/* #ident "@(#)gss_release_cred.c 1.15 95/08/07 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_cred + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +OM_uint32 KRB5_CALLCONV +gss_release_cred(minor_status, + cred_handle) + +OM_uint32 * minor_status; +gss_cred_id_t * cred_handle; + +{ + OM_uint32 status, temp_status; + int j; + gss_union_cred_t union_cred; + gss_mechanism mech; + + gss_initialize(); + + if (minor_status) + *minor_status = 0; + + /* if the cred_handle is null, return a NO_CRED error */ + + if (cred_handle == GSS_C_NO_CREDENTIAL) + return(GSS_S_NO_CRED); + + /* + * Loop through the union_cred struct, selecting the approprate + * underlying mechanism routine and calling it. At the end, + * release all of the storage taken by the union_cred struct. + */ + + union_cred = (gss_union_cred_t) *cred_handle; + *cred_handle = NULL; + + if (union_cred == NULL) + return GSS_S_NO_CRED; + + status = GSS_S_COMPLETE; + + for(j=0; j < union_cred->count; j++) { + + mech = __gss_get_mechanism (&union_cred->mechs_array[j]); + + if (union_cred->mechs_array[j].elements) + free(union_cred->mechs_array[j].elements); + if (mech) { + if (mech->gss_release_cred) { + temp_status = mech->gss_release_cred +#ifdef USE_MECH_CONTEXT + (mech->context, +#else + ( +#endif + minor_status, + &union_cred->cred_array[j]); + + if (temp_status != GSS_S_COMPLETE) + status = GSS_S_NO_CRED; + + } else + status = GSS_S_NO_CRED; + } else + status = GSS_S_NO_CRED; + } + + gss_release_buffer(minor_status, &union_cred->auxinfo.name); + free(union_cred->cred_array); + free(union_cred->mechs_array); + free(union_cred); + + return(status); +} diff --git a/support/gssapi/g_rel_name.c b/support/gssapi/g_rel_name.c new file mode 100644 index 0000000..ec5593a --- /dev/null +++ b/support/gssapi/g_rel_name.c @@ -0,0 +1,92 @@ +/* #ident "@(#)gss_release_name.c 1.2 95/05/09 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_name + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +OM_uint32 KRB5_CALLCONV +gss_release_name (minor_status, + input_name) + +OM_uint32 * minor_status; +gss_name_t * input_name; + +{ + gss_union_name_t union_name; + + /* if input_name is NULL, return error */ + +#ifdef DEBUG + fprintf(stderr, "gss_release_name: input_name %p *input_name %p\n", + input_name, *input_name); +#endif + if (input_name == 0) + return(GSS_S_BAD_NAME); + + /* + * free up the space for the external_name and then + * free the union_name descriptor + */ + + union_name = (gss_union_name_t) *input_name; + *input_name = 0; + *minor_status = 0; + + if (union_name == GSS_C_NO_NAME) + return GSS_S_BAD_NAME; + + if (union_name->name_type != GSS_C_NO_OID) + mech_gss_release_oid(minor_status, &union_name->name_type, + union_name->gss_mech); + + free(union_name->external_name->value); + free(union_name->external_name); + + if (union_name->mech_type) { +#ifdef DEBUG + fprintf(stderr, + "gss_release_name: releasing internal name %p and oid %p\n", + union_name->mech_name, union_name->mech_type); +#endif + __gss_release_internal_name(minor_status, union_name->mech_type, + &union_name->mech_name); + mech_gss_release_oid(minor_status, &union_name->mech_type, + union_name->gss_mech); + } + +#ifdef DEBUG + fprintf(stderr, "gss_release_name: freeing union_name %p\n", union_name); +#endif + free(union_name); + + return(GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_rel_oid_set.c b/support/gssapi/g_rel_oid_set.c new file mode 100644 index 0000000..90430c1 --- /dev/null +++ b/support/gssapi/g_rel_oid_set.c @@ -0,0 +1,63 @@ +/* #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 "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif + +OM_uint32 KRB5_CALLCONV +gss_release_oid_set (minor_status, + set) + +OM_uint32 * minor_status; +gss_OID_set * set; +{ + size_t index; + 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 (index=0; index<(*set)->count; index++) { + oid = &(*set)->elements[index]; + free(oid->elements); + } + free((*set)->elements); + free(*set); + + *set = GSS_C_NULL_OID_SET; + + return(GSS_S_COMPLETE); +} diff --git a/support/gssapi/g_seal.c b/support/gssapi/g_seal.c new file mode 100644 index 0000000..ebc8f2e --- /dev/null +++ b/support/gssapi/g_seal.c @@ -0,0 +1,155 @@ +/* #ident "@(#)gss_seal.c 1.10 95/08/07 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_seal + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + if (mech->gss_seal) + status = mech->gss_seal( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + conf_req_flag, + qop_req, + input_message_buffer, + conf_state, + output_message_buffer); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} + +OM_uint32 KRB5_CALLCONV +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 gss_seal(minor_status, context_handle, conf_req_flag, + (int) qop_req, input_message_buffer, conf_state, + output_message_buffer); +} + +/* + * New for V2 + */ +OM_uint32 KRB5_CALLCONV +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; +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (!mech) + return (GSS_S_NO_CONTEXT); + + if (!mech->gss_wrap_size_limit) + return (GSS_S_BAD_BINDINGS); + +#ifdef USE_MECH_CONTEXT + status = mech->gss_wrap_size_limit(mech->context, minor_status, +#else + status = mech->gss_wrap_size_limit(minor_status, +#endif + context_handle, conf_req_flag, qop_req, + req_output_size, max_input_size); + return(status); +} diff --git a/support/gssapi/g_set_allowable_enctypes.c b/support/gssapi/g_set_allowable_enctypes.c new file mode 100644 index 0000000..27c52a4 --- /dev/null +++ b/support/gssapi/g_set_allowable_enctypes.c @@ -0,0 +1,81 @@ +/* #ident "@(#)gss_set_allowable_enctype.c 1.9 95/08/02 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_set_allowable_enctypes + */ + +#include "mglueP.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#include + +OM_uint32 KRB5_CALLCONV +gss_set_allowable_enctypes(minor_status, + cred_handle, + mech_type, + num_ktypes, + ktypes) + +OM_uint32 * minor_status; +gss_cred_id_t cred_handle; +gss_OID mech_type; +OM_uint32 num_ktypes; +void * ktypes; + +{ + gss_union_cred_t union_cred; + gss_mechanism mech; + gss_cred_id_t mech_cred; + + gss_initialize(); + + if (cred_handle == GSS_C_NO_CREDENTIAL) + return (GSS_S_NO_CRED); + + if ((mech = __gss_get_mechanism(mech_type)) == NULL) + return (GSS_S_BAD_MECH); + + if (!mech->gss_set_allowable_enctypes) + return (GSS_S_FAILURE); + + /* get the mechanism-specific cred handle */ + + union_cred = (gss_union_cred_t) cred_handle; + mech_cred = __gss_get_mechanism_cred(union_cred, mech_type); + + if (mech_cred == GSS_C_NO_CREDENTIAL) + return (GSS_S_NO_CRED); + + /* Call the mechanism-specific routine */ +#ifdef USE_MECH_CONTEXT + return (mech->gss_set_allowable_enctypes(mech->context, minor_status, +#else + return (mech->gss_set_allowable_enctypes(minor_status, +#endif + mech_cred, num_ktypes, ktypes)); +} + diff --git a/support/gssapi/g_sign.c b/support/gssapi/g_sign.c new file mode 100644 index 0000000..fe3398c --- /dev/null +++ b/support/gssapi/g_sign.c @@ -0,0 +1,99 @@ +/* #ident "@(#)gss_sign.c 1.10 95/08/07 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 gss_sign + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +gss_sign (minor_status, + context_handle, + qop_req, + message_buffer, + msg_token) + +OM_uint32 * minor_status; +gss_ctx_id_t context_handle; +int qop_req; +gss_buffer_t message_buffer; +gss_buffer_t msg_token; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + if (mech->gss_sign) + status = mech->gss_sign( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + qop_req, + message_buffer, + msg_token); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} + +OM_uint32 KRB5_CALLCONV +gss_get_mic (minor_status, + context_handle, + qop_req, + message_buffer, + msg_token) + +OM_uint32 * minor_status; +gss_ctx_id_t context_handle; +gss_qop_t qop_req; +gss_buffer_t message_buffer; +gss_buffer_t msg_token; + +{ + return (gss_sign(minor_status, context_handle, (int) qop_req, + message_buffer, msg_token)); +} + diff --git a/support/gssapi/g_unseal.c b/support/gssapi/g_unseal.c new file mode 100644 index 0000000..c274e38 --- /dev/null +++ b/support/gssapi/g_unseal.c @@ -0,0 +1,105 @@ +/* #ident "@(#)gss_unseal.c 1.10 95/08/07 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 gss_unseal + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + if (mech->gss_unseal) + status = mech->gss_unseal( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + input_message_buffer, + output_message_buffer, + conf_state, + qop_state); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} + +OM_uint32 KRB5_CALLCONV +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 (gss_unseal(minor_status, context_handle, + input_message_buffer, + output_message_buffer, + conf_state, (int *) qop_state)); +} diff --git a/support/gssapi/g_verify.c b/support/gssapi/g_verify.c new file mode 100644 index 0000000..404a6ee --- /dev/null +++ b/support/gssapi/g_verify.c @@ -0,0 +1,137 @@ +/* #ident "@(#)gss_verify.c 1.9 95/08/07 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_verify + */ + +#include "mglueP.h" + +OM_uint32 KRB5_CALLCONV +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; + +{ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + if (mech->gss_verify) + status = mech->gss_verify( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + message_buffer, + token_buffer, + qop_state); + else + status = GSS_S_BAD_BINDINGS; + + return(status); + } + + return(GSS_S_NO_CONTEXT); +} + +OM_uint32 KRB5_CALLCONV +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 (gss_verify(minor_status, context_handle, + message_buffer, token_buffer, (int *) qop_state)); + */ + OM_uint32 status; + gss_union_ctx_id_t ctx; + gss_mechanism mech; + + gss_initialize(); + + if (context_handle == GSS_C_NO_CONTEXT) + return GSS_S_NO_CONTEXT; + + /* + * select the approprate underlying mechanism routine and + * call it. + */ + + ctx = (gss_union_ctx_id_t) context_handle; + mech = __gss_get_mechanism (ctx->mech_type); + + if (mech) { + if (mech->gss_verify_mic) { + status = mech->gss_verify_mic( +#ifdef USE_MECH_CONTEXT + mech->context, +#endif + minor_status, + ctx->internal_ctx_id, + message_buffer, + token_buffer, + qop_state); + return (status); + } + else + return (gss_verify(minor_status, context_handle, + message_buffer, token_buffer, + (int *) qop_state)); + } + + return(GSS_S_NO_CONTEXT); +} diff --git a/support/gssapi/gen_oids.c b/support/gssapi/gen_oids.c new file mode 100644 index 0000000..e06d60e --- /dev/null +++ b/support/gssapi/gen_oids.c @@ -0,0 +1,80 @@ +/* + * 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 "mglueP.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 + * anonymous_name: + * iso(1) org(3) dod(6) internet(1) security(5) nametypes(6) + * gss-anonymous-name(3) = 1.3.6.1.5.6.3 + * exported_name: + * iso(1) org(3) dod(6) internet(1) security(5) nametypes(6) + * gss-api-exported-name(4) = 1.3.6.1.5.6.4 + * + */ + +static const 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"}, + {6, "\053\006\001\005\006\003"}, + {6, "\053\006\001\005\006\004"}, +}; + + +/* + * rfc2744 defines the UPPERCASE names, the lowercase names are + * the original MIT names and should not be used in new applications + */ +const gss_OID_desc * const GSS_C_NT_USER_NAME = oids+0; +const gss_OID_desc * const gss_nt_user_name = oids+0; + +const gss_OID_desc * const GSS_C_NT_MACHINE_UID_NAME = oids+1; +const gss_OID_desc * const gss_nt_machine_uid_name = oids+1; + +const gss_OID_desc * const GSS_C_NT_STRING_UID_NAME = oids+2; +const gss_OID_desc * const gss_nt_string_uid_name = oids+2; + +const gss_OID_desc * const GSS_C_NT_HOSTBASED_SERVICE = oids+3; +const gss_OID_desc * const gss_nt_service_name = oids+3; + +const gss_OID_desc * const GSS_C_NT_ANONYMOUS = oids+4; + +const gss_OID_desc * const GSS_C_NT_EXPORT_NAME = oids+5; diff --git a/support/gssapi/gssd_pname_to_uid.c b/support/gssapi/gssd_pname_to_uid.c new file mode 100644 index 0000000..b390974 --- /dev/null +++ b/support/gssapi/gssd_pname_to_uid.c @@ -0,0 +1,71 @@ +/* #ident "@(#)gssd_pname_to_uid.c 1.5 95/08/02 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 routines that test the mech id either passed in to + * gss_init_sec_contex() or gss_accept_sec_context() or within the glue + * routine supported version of the security context and then call + * the appropriate underlying mechanism library procedure. + * + */ + +#include "mglueP.h" + +int gssd_pname_to_uid(pname, name_type, mech_type, uid) + +char * pname; +gss_OID name_type; +gss_OID mech_type; +uid_t * uid; +{ + int status; + gss_mechanism mech; + + gss_initialize(); + + /* + * find the appropriate mechanism specific pname_to_uid procedure and + * call it. + */ + + mech = __gss_get_mechanism (mech_type); + + if (mech) { + if (mech_type == GSS_C_NULL_OID) + mech_type = &mech->mech_type; + + if (mech->pname_to_uid) +#ifdef USE_MECH_CONTEXT + status = mech->pname_to_uid(mech->context, +#else + status = mech->pname_to_uid( +#endif + pname, name_type, mech_type, uid); + else + status = GSS_S_BAD_MECH; + } else + status = GSS_S_BAD_MECH; + + return(status); +} diff --git a/support/gssapi/mechglue.h b/support/gssapi/mechglue.h new file mode 100644 index 0000000..079ea93 --- /dev/null +++ b/support/gssapi/mechglue.h @@ -0,0 +1,46 @@ +/* #ident "@(#)mechglue.h 1.13 95/08/07 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. + */ + +/* + * This header contains the mechglue definitions. + */ + +#ifndef _GSS_MECHGLUE_H +#define _GSS_MECHGLUE_H + +#include + +/********************************************************/ +/* GSSAPI Extension functions -- these functions aren't */ +/* in the GSSAPI, but they are provided in this library */ + +int gssd_pname_to_uid (char *, gss_OID, gss_OID, uid_t *); +void gss_initialize (void); +OM_uint32 gss_set_allowable_enctypes( OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_OID, /* mech type */ + OM_uint32, /* num_ktypes */ + void * /* ktypes */); + +#endif /* _GSS_MECHGLUE_H */ diff --git a/support/gssapi/mglueP.h b/support/gssapi/mglueP.h new file mode 100644 index 0000000..362b308 --- /dev/null +++ b/support/gssapi/mglueP.h @@ -0,0 +1,503 @@ +/* #ident "@(#)mglueP.h 1.2 96/01/18 SMI" */ + +/* + * This header contains the private mechglue definitions. + * + * Copyright (c) 1995, by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _GSS_MECHGLUEP_H +#define _GSS_MECHGLUEP_H + +#include "mechglue.h" + +/* + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +/* + * Structure for holding list of mechanism-specific name types + */ +typedef struct gss_mech_spec_name_t { + gss_OID name_type; + gss_OID mech; + struct gss_mech_spec_name_t *next, *prev; +} gss_mech_spec_name_desc, *gss_mech_spec_name; + +/* + * Credential auxiliary info, used in the credential structure + */ +typedef struct gss_union_cred_auxinfo { + gss_buffer_desc name; + gss_OID name_type; + time_t creation_time; + OM_uint32 time_rec; + int cred_usage; +} gss_union_cred_auxinfo; + +/* + * Set of Credentials typed on mechanism OID + */ +typedef struct gss_union_cred_t { + int count; + gss_OID mechs_array; + gss_cred_id_t * cred_array; + gss_union_cred_auxinfo auxinfo; +} gss_union_cred_desc, *gss_union_cred_t; + +/********************************************************/ +/* The Mechanism Dispatch Table -- a mechanism needs to */ +/* define one of these and provide a function to return */ +/* it to initialize the GSSAPI library */ + +/* + * This is the definition of the mechs_array struct, which is used to + * define the mechs array table. This table is used to indirectly + * access mechanism specific versions of the gssapi routines through + * the routines in the glue module (gssd_mech_glue.c) + * + * This contants all of the functions defined in gssapi.h except for + * gss_release_buffer() and gss_release_oid_set(), which I am + * assuming, for now, to be equal across mechanisms. + */ + +typedef struct gss_config { + gss_OID_desc mech_type; + void * context; + OM_uint32 (*gss_acquire_cred) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_name_t, /* desired_name */ + OM_uint32, /* time_req */ + gss_OID_set, /* desired_mechs */ + int, /* cred_usage */ + gss_cred_id_t*, /* output_cred_handle */ + gss_OID_set*, /* actual_mechs */ + OM_uint32* /* time_rec */ + ); + OM_uint32 (*gss_release_cred) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_cred_id_t* /* cred_handle */ + ); + OM_uint32 (*gss_init_sec_context) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + 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 */ + ); + OM_uint32 (*gss_accept_sec_context) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t*, /* context_handle */ + gss_cred_id_t, /* verifier_cred_handle */ + gss_buffer_t, /* input_token_buffer */ + 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 */ + ); + OM_uint32 (*gss_process_context_token) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t /* token_buffer */ + ); + OM_uint32 (*gss_delete_sec_context) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t*, /* context_handle */ + gss_buffer_t /* output_token */ + ); + OM_uint32 (*gss_context_time) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + OM_uint32* /* time_rec */ + ); + OM_uint32 (*gss_sign) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + ); + OM_uint32 (*gss_verify) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* token_buffer */ + int* /* qop_state */ + ); + OM_uint32 (*gss_seal) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + 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 */ + ); + OM_uint32 (*gss_unseal) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + 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 */ + ); + OM_uint32 (*gss_display_status) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + gss_OID, /* mech_type */ + OM_uint32*, /* message_context */ + gss_buffer_t /* status_string */ + ); + OM_uint32 (*gss_indicate_mechs) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_OID_set* /* mech_set */ + ); + OM_uint32 (*gss_compare_name) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_name_t, /* name1 */ + gss_name_t, /* name2 */ + int* /* name_equal */ + ); + OM_uint32 (*gss_display_name) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID* /* output_name_type */ + ); + OM_uint32 (*gss_import_name) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_buffer_t, /* input_name_buffer */ + gss_OID, /* input_name_type */ + gss_name_t* /* output_name */ + ); + OM_uint32 (*gss_release_name) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_name_t* /* input_name */ + ); + OM_uint32 (*gss_inquire_cred) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_name_t *, /* name */ + OM_uint32 *, /* lifetime */ + int *, /* cred_usage */ + gss_OID_set * /* mechanisms */ + ); + OM_uint32 (*gss_add_cred) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + 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 */ + ); + OM_uint32 (*gss_export_sec_context) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_ctx_id_t *, /* context_handle */ + gss_buffer_t /* interprocess_token */ + ); + OM_uint32 (*gss_import_sec_context) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_buffer_t, /* interprocess_token */ + gss_ctx_id_t * /* context_handle */ + ); + OM_uint32 (*gss_inquire_cred_by_mech) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + 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 */ + ); + OM_uint32 (*gss_inquire_names_for_mech) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_OID, /* mechanism */ + gss_OID_set * /* name_types */ + ); + OM_uint32 (*gss_inquire_context) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_name_t *, /* src_name */ + gss_name_t *, /* targ_name */ + OM_uint32 *, /* lifetime_rec */ + gss_OID *, /* mech_type */ + OM_uint32 *, /* ctx_flags */ + int *, /* locally_initiated */ + int * /* open */ + ); + OM_uint32 (*gss_internal_release_oid) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_OID * /* OID */ + ); + OM_uint32 (*gss_wrap_size_limit) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + 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 */ + ); + OM_uint32 (*pname_to_uid) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + char *, /* pname */ + gss_OID, /* name type */ + gss_OID, /* mech type */ + uid_t * /* uid */ + ); + OM_uint32 (*gss_duplicate_name) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_name_t * /* dest_name */ + ); + OM_uint32 (*gss_set_allowable_enctypes) + ( +#ifdef USE_MECH_CONTEXT + void *, /* context */ +#endif + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + OM_uint32, /* num_ktypes */ + void * /* ktypes */ + ); + OM_uint32 (*gss_verify_mic) + ( +#ifdef USE_MECH_CONTEXT + void*, /* context */ +#endif + OM_uint32*, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* token_buffer */ + int* /* qop_state */ + ); + +} *gss_mechanism; + +/* + * Generic GSSAPI names. A name can either be a generic name, or a + * mechanism specific name.... + */ +typedef struct gss_union_name_t { + gss_mechanism gss_mech; + gss_OID name_type; + gss_buffer_t external_name; + /* + * These last two fields are only filled in for mechanism + * names. + */ + gss_OID mech_type; + gss_name_t mech_name; +} gss_union_name_desc, *gss_union_name_t; + +/********************************************************/ +/* Internal mechglue routines */ + +gss_mechanism __gss_get_mechanism (gss_OID); +OM_uint32 __gss_get_mech_type (gss_OID, gss_buffer_t); +OM_uint32 __gss_import_internal_name (OM_uint32 *, gss_OID, gss_union_name_t, + gss_name_t *); +OM_uint32 __gss_display_internal_name (OM_uint32 *, gss_OID, gss_name_t, + gss_buffer_t, gss_OID *); +OM_uint32 __gss_release_internal_name (OM_uint32 *, gss_OID, gss_name_t *); + +OM_uint32 __gss_convert_name_to_union_name + (OM_uint32 *, /* minor_status */ + gss_mechanism, /* mech */ + gss_name_t, /* internal_name */ + gss_name_t * /* external_name */ + ); +gss_cred_id_t __gss_get_mechanism_cred + (gss_union_cred_t, /* union_cred */ + gss_OID /* mech_type */ + ); + +OM_uint32 generic_gss_release_oid + (OM_uint32 *, /* minor_status */ + gss_OID * /* oid */ + ); + +OM_uint32 mech_gss_release_oid + (OM_uint32 *, /* minor_status */ + gss_OID *, /* oid */ + gss_mechanism /* gss_mech */ + ); + +OM_uint32 generic_gss_copy_oid + (OM_uint32 *, /* minor_status */ + gss_OID, /* oid */ + gss_OID * /* new_oid */ + ); + +OM_uint32 generic_gss_create_empty_oid_set + (OM_uint32 *, /* minor_status */ + gss_OID_set * /* oid_set */ + ); + +OM_uint32 generic_gss_add_oid_set_member + (OM_uint32 *, /* minor_status */ + gss_OID, /* member_oid */ + gss_OID_set * /* oid_set */ + ); + +OM_uint32 generic_gss_test_oid_set_member + (OM_uint32 *, /* minor_status */ + gss_OID, /* member */ + gss_OID_set, /* set */ + int * /* present */ + ); + +OM_uint32 generic_gss_oid_to_str + (OM_uint32 *, /* minor_status */ + gss_OID, /* oid */ + gss_buffer_t /* oid_str */ + ); + +OM_uint32 generic_gss_str_to_oid + (OM_uint32 *, /* minor_status */ + gss_buffer_t, /* oid_str */ + gss_OID * /* oid */ + ); + + +gss_OID gss_find_mechanism_from_name_type (gss_OID); /* name_type */ + +OM_uint32 gss_add_mech_name_type + (OM_uint32 *, /* minor_status */ + gss_OID, /* name_type */ + gss_OID /* mech */ + ); + +#endif /* _GSS_MECHGLUEP_H */ diff --git a/support/gssapi/oid_ops.c b/support/gssapi/oid_ops.c new file mode 100644 index 0000000..ed24d58 --- /dev/null +++ b/support/gssapi/oid_ops.c @@ -0,0 +1,449 @@ +/* + * 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. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + */ + +/* + * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs + */ + +#include "mglueP.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#include +#include + +OM_uint32 +generic_gss_release_oid(minor_status, oid) + OM_uint32 *minor_status; + gss_OID *oid; +{ + *minor_status = 0; +#ifdef DEBUG + static int printed = 0; + + if (!printed++) + fprintf(stderr, "gss_generic_release_oid (glue):\n" + " GSS_C_NT_USER_NAME %p\n" + " GSS_C_NT_MACHINE_UID_NAME %p\n" + " GSS_C_NT_STRING_UID_NAME %p\n" + " GSS_C_NT_HOSTBASED_SERVICE %p\n" + " GSS_C_NT_ANONYMOUS %p\n" + " GSS_C_NT_EXPORT_NAME %p\n", + GSS_C_NT_USER_NAME, GSS_C_NT_MACHINE_UID_NAME, + GSS_C_NT_STRING_UID_NAME, GSS_C_NT_HOSTBASED_SERVICE, + GSS_C_NT_ANONYMOUS, GSS_C_NT_EXPORT_NAME); +#endif + + 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_C_NT_USER_NAME) && + (*oid != GSS_C_NT_MACHINE_UID_NAME) && + (*oid != GSS_C_NT_STRING_UID_NAME) && + (*oid != GSS_C_NT_HOSTBASED_SERVICE) && + (*oid != GSS_C_NT_ANONYMOUS) && + (*oid != GSS_C_NT_EXPORT_NAME)) { +#ifdef DEBUG + fprintf(stderr, "generic_gss_release_oid (glue): freeing *oid at %p\n", + *oid); +#endif + free((*oid)->elements); + free(*oid); + } + *oid = GSS_C_NO_OID; + return(GSS_S_COMPLETE); +} + +OM_uint32 +mech_gss_release_oid(minor_status, oid, gss_mech) + OM_uint32 *minor_status; + gss_OID *oid; + gss_mechanism gss_mech; +{ + *minor_status = 0; + +#ifdef DEBUG + fprintf(stderr, "mech_gss_release_oid: *oid %p, gss_mech %p\n", + *oid, gss_mech); +#endif + if (*oid == GSS_C_NO_OID) + return (GSS_S_COMPLETE); + + if (gss_mech == NULL) { +#ifdef DEBUG + fprintf(stderr, "mech_gss_release_oid: no gss_mech!\n"); +#endif + return (generic_gss_release_oid(minor_status, oid)); + } + + if (!gss_mech->gss_internal_release_oid) { +#ifdef DEBUG + fprintf(stderr, "mech_gss_release_oid: mechanism has " + "no gss_internal_release_oid function! using " + "generic_gss_release_oid\n"); +#endif + return (generic_gss_release_oid(minor_status, oid)); + } + +#ifdef DEBUG + fprintf(stderr, "mech_gss_release_oid: calling mechanism's " + "gss_internal_release_oid\n"); +#endif + return (gss_mech->gss_internal_release_oid(minor_status, oid)); +} + +OM_uint32 +generic_gss_copy_oid(minor_status, oid, new_oid) + OM_uint32 *minor_status; + gss_OID oid, *new_oid; +{ + gss_OID p; + + if (oid == GSS_C_NO_OID) { + *new_oid = GSS_C_NO_OID; + return (GSS_S_COMPLETE); + } + + 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; icount; 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; ilength; 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; ilength; 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/support/include/config.h.in b/support/include/config.h.in index f8c1497..6a6a065 100644 --- a/support/include/config.h.in +++ b/support/include/config.h.in @@ -23,3 +23,23 @@ * but lockd from using this service. */ #undef RESTRICTED_STATD + +/* Define this if you want support for rpcsec_gss with + * the MIT krb5 mechanism compiled in */ +#undef HAVE_KRB5 + +/* Define this if you want support for rpcsec_gss with + * the Heimdal krb5 mechanism compiled in */ +#undef HAVE_HEIMDAL + +/* Define this if the Kerberos gssapi library has function + * gss_krb5_export_lucid_sec_context */ +#undef HAVE_LUCID_CONTEXT_SUPPORT + +/* Define this if the Kerberos gssapi library has function + * gss_krb5_set_allowable_enctypes */ +#undef HAVE_SET_ALLOWABLE_ENCTYPES + +/* Define this if the Kerberos gssapi library has function + * gss_krb5_cache_name */ +#undef HAVE_GSS_KRB5_CCACHE_NAME diff --git a/support/include/gssapi/gssapi.h b/support/include/gssapi/gssapi.h new file mode 100644 index 0000000..18d62db --- /dev/null +++ b/support/include/gssapi/gssapi.h @@ -0,0 +1,846 @@ +/* This is the gssapi.h prologue. */ +/* It contains some choice pieces of autoconf.h */ +#define SIZEOF_INT 4 +#define SIZEOF_LONG 4 +#define SIZEOF_SHORT 2 +#define HAVE_STDARG_H 1 +/* #undef HAVE_VARARGS_H */ +/* #undef HAVE_MACSOCK_H */ +#define HAVE_NETINET_IN_H 1 +#define HAVE_STDDEF_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_FILE_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_SOCKET_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_UNISTD_H 1 +/* #undef HAVE_XOM_H */ +#define USE_DIRENT_H 1 +/* End of gssapi.h prologue. */ +/* + * 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. + */ + +#ifndef _GSSAPI_H_ +#define _GSSAPI_H_ + +/* + * Determine platform-dependent configuration. + */ + +#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__)) + #include + #if TARGET_RT_MAC_CFM + #error "Use KfM 4.0 SDK headers for CFM compilation." + #endif + + /* This is an API divergence in 1.2.3. This will be reconciled in 1.3, when + all platforms will have RFC-compliant OID declarations. */ + #define GSS_RFC_COMPLIANT_OIDS 1 +#else + #define GSS_RFC_COMPLIANT_OIDS 0 +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if TARGET_OS_MAC + #if defined(__MWERKS__) + #pragma import on + #pragma enumsalwaysint on + #endif + #pragma options align=mac68k +#endif + +#if defined(_MSDOS) || defined(_WIN32) +#include +#endif + +/* #ifndef KRB5_CALLCONV */ +#define KRB5_CALLCONV +#define KRB5_CALLCONV_C +#define KRB5_DLLIMP +#define GSS_DLLIMP +#define KRB5_EXPORTVAR +/* #endif */ +#ifndef FAR +#define FAR +#define NEAR +#endif + +#define GSS_SIZEOF_INT SIZEOF_INT +#define GSS_SIZEOF_LONG SIZEOF_LONG +#define GSS_SIZEOF_SHORT SIZEOF_SHORT + +/* + * Make sure we have a definition for PROTOTYPE. + */ +#if !defined(PROTOTYPE) +#if defined(__STDC__) || defined(__cplusplus) || defined(_MSDOS) || defined(_WIN32) || defined(__ultrix) +#define PROTOTYPE(x) x +#else +#define PROTOTYPE(x) () +#endif +#endif + +/* + * First, include stddef.h to get size_t defined. + */ +#if HAVE_STDDEF_H +#include +#endif /* HAVE_STDDEF_H */ + +/* + * POSIX says that sys/types.h is where size_t is defined. + */ +#ifndef macintosh +#include +#endif + +/* + * If the platform supports the xom.h header file, it should be included here. + */ +#if HAVE_XOM_H +#include +#endif /* HAVE_XOM_H */ + +/* + * $Id: gssapi.h,v 1.1 2004/10/19 00:22:57 neilbrown Exp $ + */ + +/* + * 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; + +/* + * The following type must be defined as the smallest natural unsigned integer + * supported by the platform that has at least 32 bits of precision. + */ +#if (GSS_SIZEOF_SHORT == 4) +typedef unsigned short gss_uint32; +typedef short gss_int32; +#elif (GSS_SIZEOF_INT == 4) +typedef unsigned int gss_uint32; +typedef int gss_int32; +#elif (GSS_SIZEOF_LONG == 4) +typedef unsigned long gss_uint32; +typedef long gss_int32; +#endif + +#ifdef OM_STRING +/* + * We have included the xom.h header file. Use the definition for + * OM_object identifier. + */ +typedef OM_object_identifier gss_OID_desc, *gss_OID; +#else /* OM_STRING */ +/* + * We can't use X/Open definitions, so roll our own. + */ +typedef gss_uint32 OM_uint32; + +typedef struct gss_OID_desc_struct { + OM_uint32 length; + void FAR *elements; +} gss_OID_desc, FAR *gss_OID; +#endif /* OM_STRING */ + +typedef struct gss_OID_set_desc_struct { + size_t count; + gss_OID elements; +} gss_OID_set_desc, FAR *gss_OID_set; + +typedef struct gss_buffer_desc_struct { + size_t length; + void FAR *value; +} gss_buffer_desc, FAR *gss_buffer_t; + +typedef struct gss_channel_bindings_struct { + OM_uint32 initiator_addrtype; + gss_buffer_desc initiator_address; + OM_uint32 acceptor_addrtype; + gss_buffer_desc acceptor_address; + gss_buffer_desc application_data; +} FAR *gss_channel_bindings_t; + +/* + * For now, define a QOP-type as an OM_uint32 (pending resolution of ongoing + * discussions). + */ +typedef OM_uint32 gss_qop_t; +typedef int gss_cred_usage_t; + +/* + * Flag bits for context-level services. + */ +#define GSS_C_DELEG_FLAG 1 +#define GSS_C_MUTUAL_FLAG 2 +#define GSS_C_REPLAY_FLAG 4 +#define GSS_C_SEQUENCE_FLAG 8 +#define GSS_C_CONF_FLAG 16 +#define GSS_C_INTEG_FLAG 32 +#define GSS_C_ANON_FLAG 64 +#define GSS_C_PROT_READY_FLAG 128 +#define GSS_C_TRANS_FLAG 256 + +/* + * Credential usage options + */ +#define GSS_C_BOTH 0 +#define GSS_C_INITIATE 1 +#define GSS_C_ACCEPT 2 + +/* + * Status code types for gss_display_status + */ +#define GSS_C_GSS_CODE 1 +#define GSS_C_MECH_CODE 2 + +/* + * The constant definitions for channel-bindings address families + */ +#define GSS_C_AF_UNSPEC 0 +#define GSS_C_AF_LOCAL 1 +#define GSS_C_AF_INET 2 +#define GSS_C_AF_IMPLINK 3 +#define GSS_C_AF_PUP 4 +#define GSS_C_AF_CHAOS 5 +#define GSS_C_AF_NS 6 +#define GSS_C_AF_NBS 7 +#define GSS_C_AF_ECMA 8 +#define GSS_C_AF_DATAKIT 9 +#define GSS_C_AF_CCITT 10 +#define GSS_C_AF_SNA 11 +#define GSS_C_AF_DECnet 12 +#define GSS_C_AF_DLI 13 +#define GSS_C_AF_LAT 14 +#define GSS_C_AF_HYLINK 15 +#define GSS_C_AF_APPLETALK 16 +#define GSS_C_AF_BSC 17 +#define GSS_C_AF_DSS 18 +#define GSS_C_AF_OSI 19 +#define GSS_C_AF_X25 21 + +#define GSS_C_AF_NULLADDR 255 + +/* + * Various Null values. + */ +#define GSS_C_NO_NAME ((gss_name_t) 0) +#define GSS_C_NO_BUFFER ((gss_buffer_t) 0) +#define GSS_C_NO_OID ((gss_OID) 0) +#define GSS_C_NO_OID_SET ((gss_OID_set) 0) +#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0) +#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0) +#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0) +#define GSS_C_EMPTY_BUFFER {0, NULL} + +/* + * Some alternate names for a couple of the above values. These are defined + * for V1 compatibility. + */ +#define GSS_C_NULL_OID GSS_C_NO_OID +#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET + +/* + * Define the default Quality of Protection for per-message services. Note + * that an implementation that offers multiple levels of QOP may either reserve + * a value (for example zero, as assumed here) to mean "default protection", or + * alternatively may simply equate GSS_C_QOP_DEFAULT to a specific explicit + * QOP value. However a value of 0 should always be interpreted by a GSSAPI + * implementation as a request for the default protection level. + */ +#define GSS_C_QOP_DEFAULT 0 + +/* + * Expiration time of 2^32-1 seconds means infinite lifetime for a + * credential or security context + */ +#define GSS_C_INDEFINITE ((OM_uint32) 0xfffffffful) + + +/* Major status codes */ + +#define GSS_S_COMPLETE 0 + +/* + * Some "helper" definitions to make the status code macros obvious. + */ +#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 ((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 + * GSS_ERROR() macro has changed slightly from the V1 GSSAPI so that it now + * evaluates its argument only once. + */ +#define GSS_CALLING_ERROR(x) \ + ((x) & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET)) +#define GSS_ROUTINE_ERROR(x) \ + ((x) & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)) +#define GSS_SUPPLEMENTARY_INFO(x) \ + ((x) & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET)) +#define GSS_ERROR(x) \ + ((x) & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \ + (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))) + +/* + * Now the actual status code definitions + */ + +/* + * Calling errors: + */ +#define GSS_S_CALL_INACCESSIBLE_READ \ + (((OM_uint32) 1ul) << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_INACCESSIBLE_WRITE \ + (((OM_uint32) 2ul) << GSS_C_CALLING_ERROR_OFFSET) +#define GSS_S_CALL_BAD_STRUCTURE \ + (((OM_uint32) 3ul) << GSS_C_CALLING_ERROR_OFFSET) + +/* + * Routine errors: + */ +#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) +#define GSS_S_DUPLICATE_ELEMENT \ + (((OM_uint32) 17ul) << GSS_C_ROUTINE_ERROR_OFFSET) +#define GSS_S_NAME_NOT_MN \ + (((OM_uint32) 18ul) << GSS_C_ROUTINE_ERROR_OFFSET) + +/* + * Supplementary info bits: + */ +#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)) +#define GSS_S_GAP_TOKEN (1 << (GSS_C_SUPPLEMENTARY_OFFSET + 4)) + + +/* + * Finally, function prototypes for the GSSAPI routines. + */ + +/* Reserved static storage for GSS_oids. Comments are quotes from RFC 2744. + * + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x01"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) user_name(1)}. The constant + * GSS_C_NT_USER_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_USER_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x02"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}. + * The constant GSS_C_NT_MACHINE_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_MACHINE_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x03"}, + * corresponding to an object-identifier value of + * {iso(1) member-body(2) United States(840) mit(113554) + * infosys(1) gssapi(2) generic(1) string_uid_name(3)}. + * The constant GSS_C_NT_STRING_UID_NAME should be + * initialized to point to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_STRING_UID_NAME; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x02"}, + * corresponding to an object-identifier value of + * {iso(1) org(3) dod(6) internet(1) security(5) + * nametypes(6) gss-host-based-services(2)). The constant + * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point + * to that gss_OID_desc. This is a deprecated OID value, and + * implementations wishing to support hostbased-service names + * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID, + * defined below, to identify such names; + * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym + * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input + * parameter, but should not be emitted by GSS-API + * implementations +GSS_DLLIMP extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X; + */ + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {10, (void *)"\x2a\x86\x48\x86\xf7\x12" + * "\x01\x02\x01\x04"}, corresponding to an + * object-identifier value of {iso(1) member-body(2) + * Unites States(840) mit(113554) infosys(1) gssapi(2) + * generic(1) service_name(4)}. The constant + * GSS_C_NT_HOSTBASED_SERVICE should be initialized + * to point to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_HOSTBASED_SERVICE; + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\01\x05\x06\x03"}, + * corresponding to an object identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 3(gss-anonymous-name)}. The constant + * and GSS_C_NT_ANONYMOUS should be initialized to point + * to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_ANONYMOUS; + + +/* + * The implementation must reserve static storage for a + * gss_OID_desc object containing the value + * {6, (void *)"\x2b\x06\x01\x05\x06\x04"}, + * corresponding to an object-identifier value of + * {1(iso), 3(org), 6(dod), 1(internet), 5(security), + * 6(nametypes), 4(gss-api-exported-name)}. The constant + * GSS_C_NT_EXPORT_NAME should be initialized to point + * to that gss_OID_desc. + */ +extern const gss_OID_desc * const GSS_C_NT_EXPORT_NAME; + + +/* Function Prototypes */ + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_acquire_cred +PROTOTYPE( (OM_uint32 FAR *, /* 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 FAR *, /* output_cred_handle */ + gss_OID_set FAR *, /* actual_mechs */ + OM_uint32 FAR * /* time_rec */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_release_cred +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_cred_id_t FAR * /* cred_handle */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_init_sec_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_cred_id_t, /* claimant_cred_handle */ + gss_ctx_id_t FAR *, /* context_handle */ + gss_name_t, /* target_name */ + gss_OID, /* mech_type (used to be const) */ + OM_uint32, /* req_flags */ + OM_uint32, /* time_req */ + gss_channel_bindings_t, /* input_chan_bindings */ + gss_buffer_t, /* input_token */ + gss_OID FAR *, /* actual_mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 FAR *, /* ret_flags */ + OM_uint32 FAR * /* time_rec */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_accept_sec_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t FAR *, /* context_handle */ + gss_cred_id_t, /* acceptor_cred_handle */ + gss_buffer_t, /* input_token_buffer */ + gss_channel_bindings_t, /* input_chan_bindings */ + gss_name_t FAR *, /* src_name */ + gss_OID FAR *, /* mech_type */ + gss_buffer_t, /* output_token */ + OM_uint32 FAR *, /* ret_flags */ + OM_uint32 FAR *, /* time_rec */ + gss_cred_id_t FAR * /* delegated_cred_handle */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_process_context_token +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t /* token_buffer */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_delete_sec_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t FAR *, /* context_handle */ + gss_buffer_t /* output_token */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_context_time +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + OM_uint32 FAR * /* time_rec */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_get_mic +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_qop_t, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_verify_mic +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* message_token */ + gss_qop_t * /* qop_state */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_wrap +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + gss_qop_t, /* qop_req */ + gss_buffer_t, /* input_message_buffer */ + int FAR *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_unwrap +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int FAR *, /* conf_state */ + gss_qop_t FAR * /* qop_state */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_display_status +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + OM_uint32, /* status_value */ + int, /* status_type */ + gss_OID, /* mech_type (used to be const) */ + OM_uint32 FAR *, /* message_context */ + gss_buffer_t /* status_string */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_indicate_mechs +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID_set FAR * /* mech_set */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_compare_name +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_name_t, /* name1 */ + gss_name_t, /* name2 */ + int FAR * /* name_equal */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_display_name +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_name_t, /* input_name */ + gss_buffer_t, /* output_name_buffer */ + gss_OID FAR * /* output_name_type */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_import_name +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_buffer_t, /* input_name_buffer */ + gss_OID, /* input_name_type(used to be const) */ + gss_name_t FAR * /* output_name */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_release_name +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_name_t FAR * /* input_name */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_release_buffer +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_buffer_t /* buffer */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_release_oid_set +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID_set FAR * /* set */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_inquire_cred +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_name_t FAR *, /* name */ + OM_uint32 FAR *, /* lifetime */ + gss_cred_usage_t FAR *, /* cred_usage */ + gss_OID_set FAR * /* mechanisms */ + )); + +/* Last argument new for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_inquire_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_name_t FAR *, /* src_name */ + gss_name_t FAR *, /* targ_name */ + OM_uint32 FAR *, /* lifetime_rec */ + gss_OID FAR *, /* mech_type */ + OM_uint32 FAR *, /* ctx_flags */ + int FAR *, /* locally_initiated */ + int FAR * /* open */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_wrap_size_limit +PROTOTYPE( (OM_uint32 FAR *, /* 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 */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_import_name_object +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + void FAR *, /* input_name */ + gss_OID, /* input_name_type */ + gss_name_t FAR * /* output_name */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_export_name_object +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_name_t, /* input_name */ + gss_OID, /* desired_name_type */ + void FAR * FAR * /* output_name */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_add_cred +PROTOTYPE( (OM_uint32 FAR *, /* 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 FAR *, /* output_cred_handle */ + gss_OID_set FAR *, /* actual_mechs */ + OM_uint32 FAR *, /* initiator_time_rec */ + OM_uint32 FAR * /* acceptor_time_rec */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_inquire_cred_by_mech +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_OID, /* mech_type */ + gss_name_t FAR *, /* name */ + OM_uint32 FAR *, /* initiator_lifetime */ + OM_uint32 FAR *, /* acceptor_lifetime */ + gss_cred_usage_t FAR * /* cred_usage */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_export_sec_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t FAR *, /* context_handle */ + gss_buffer_t /* interprocess_token */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_import_sec_context +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_buffer_t, /* interprocess_token */ + gss_ctx_id_t FAR * /* context_handle */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_release_oid +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID FAR * /* oid */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_create_empty_oid_set +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID_set FAR * /* oid_set */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_add_oid_set_member +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID, /* member_oid */ + gss_OID_set FAR * /* oid_set */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_test_oid_set_member +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID, /* member */ + gss_OID_set, /* set */ + int FAR * /* present */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_str_to_oid +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_buffer_t, /* oid_str */ + gss_OID FAR * /* oid */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_oid_to_str +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID, /* oid */ + gss_buffer_t /* oid_str */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_inquire_names_for_mech +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_OID, /* mechanism */ + gss_OID_set FAR * /* name_types */ + )); + +/* + * The following routines are obsolete variants of gss_get_mic, gss_wrap, + * gss_verify_mic and gss_unwrap. They should be provided by GSSAPI V2 + * implementations for backwards compatibility with V1 applications. Distinct + * entrypoints (as opposed to #defines) should be provided, to allow GSSAPI + * V1 applications to link against GSSAPI V2 implementations. + */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_sign +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* qop_req */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t /* message_token */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_verify +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* message_buffer */ + gss_buffer_t, /* token_buffer */ + int FAR * /* qop_state */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_seal +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + int, /* conf_req_flag */ + int, /* qop_req */ + gss_buffer_t, /* input_message_buffer */ + int FAR *, /* conf_state */ + gss_buffer_t /* output_message_buffer */ + )); + +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_unseal +PROTOTYPE( (OM_uint32 FAR *, /* minor_status */ + gss_ctx_id_t, /* context_handle */ + gss_buffer_t, /* input_message_buffer */ + gss_buffer_t, /* output_message_buffer */ + int FAR *, /* conf_state */ + int FAR * /* qop_state */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_export_name +PROTOTYPE( (OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_buffer_t /* exported_name */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_duplicate_name +PROTOTYPE( (OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + gss_name_t * /* dest_name */ + )); + +/* New for V2 */ +GSS_DLLIMP OM_uint32 KRB5_CALLCONV gss_canonicalize_name +PROTOTYPE( (OM_uint32 *, /* minor_status */ + const gss_name_t, /* input_name */ + const gss_OID, /* mech_type */ + gss_name_t * /* output_name */ + )); + +#if TARGET_OS_MAC + #if defined(__MWERKS__) + #pragma enumsalwaysint reset + #pragma import reset + #endif + #pragma options align=reset +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +/* XXXX these are not part of the GSSAPI C bindings! (but should be) */ + +#define GSS_CALLING_ERROR_FIELD(x) \ + (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK) +#define GSS_ROUTINE_ERROR_FIELD(x) \ + (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK) +#define GSS_SUPPLEMENTARY_INFO_FIELD(x) \ + (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK) + +/* XXXX This is a necessary evil until the spec is fixed */ +#define GSS_S_CRED_UNAVAIL GSS_S_FAILURE + +#endif /* _GSSAPI_H_ */ diff --git a/support/lib/Makefile b/support/lib/Makefile index 2eeb93b..58c84f8 100644 --- a/support/lib/Makefile +++ b/support/lib/Makefile @@ -1,7 +1,7 @@ include $(TOP)rules.mk -LIBS = libnfs.a libexport.a libmisc.a +LIBS = libnfs.a libexport.a libmisc.a librpc.a libgssapi.a all install:: $(LIBS) @: diff --git a/support/rpc/DISCLAIMER b/support/rpc/DISCLAIMER new file mode 100644 index 0000000..e5871a2 --- /dev/null +++ b/support/rpc/DISCLAIMER @@ -0,0 +1,30 @@ +/* $OpenBSD: DISCLAIMER,v 1.2 1996/07/20 06:12:14 deraadt Exp $ */ + +/* + * 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 + */ diff --git a/support/rpc/Makefile b/support/rpc/Makefile new file mode 100644 index 0000000..d678075 --- /dev/null +++ b/support/rpc/Makefile @@ -0,0 +1,18 @@ +# +# librpc.a +# rpc library with rpcsec_gss +# + +LIBNAME = librpc.a +SRCS = auth_gss.c authgss_prot.c svc.c svc_run.c svc_auth.c \ + svc_auth_none.c svc_auth_unix.c svc_auth_gss.c \ + svc_raw.c svc_simple.c svc_tcp.c svc_udp.c \ + rpc_commondata.c +OBJS = $(SRCS:.c=.o) + +include $(TOP)rules.mk + +CFLAGS += -I$(TOP)support/rpc/include -DDEBUG + +install:: + @: diff --git a/support/rpc/README b/support/rpc/README new file mode 100644 index 0000000..eb960e6 --- /dev/null +++ b/support/rpc/README @@ -0,0 +1,233 @@ +RPCSRC 4.0 7/11/89 + +This distribution contains Sun Microsystem's implementation of the +RPC and XDR protocols and is compatible with 4.2BSD and 4.3BSD. Also +included is complete documentation, utilities, RPC service +specification files, and demonstration services in the format used by +the RPC protocol compiler (rpcgen). See WHAT'S NEW below for +details. + +NOTE ABOUT SECURE RPC: + +This release of RPCSRC contains most of the code needed to implement +Secure RPC (see "DES Authentication" in the RPC Protocol Specification, +doc/rpc.rfc.ms). Due to legal considerations, we are unable to +distribute an implementation of DES, the Data Encryption Standard, which +Secure RPC requires. For this reason, all of the files, documentation, and +programs associated with Secure RPC have been placed into a separate +directory, secure_rpc. The RPC library contained in the main body of this +release *DOES NOT* support Secure RPC. See secure_rpc/README for more +details. (A DES library was posted in Volume 18 of comp.sources.unix.) + +If you wish to report bugs found in this release, send mail to: + +Portable ONC/NFS +Sun Microsystems, Inc +MS 12-33 +2550 Garcia Avenue +Mountain View, CA 94043 + +or send Email to nfsnet@sun.com (the Internet) or sun!nfsnet (Usenet). + +ROADMAP + +The directory hierarchy is as follows: + + demo/ Various demonstration services + demo/dir Remote directory lister + demo/msg Remote console message delivery service + demo/sort Remote sort service + + doc/ Documentation for RPC, XDR and NFS in "-ms" format. + + etc/ Utilities (rpcinfo and portmap). portmap must be + started by root before any other RPC network services are + used. SEE BELOW FOR BUGFIX TO 4.3BSD COMPILER. + + man/ Manual pages for RPC library, rpcgen, and utilities. + + rpc/ The RPC and XDR library. SEE BELOW + FOR BUGFIX TO 4.2BSD COMPILER. + + rpcgen/ The RPC Language compiler (for .x files) + + rpcsvc/ Service definition files for various services and the + server and client code for the Remote Status service. + + secure_rpc/ The files in this directory are used to build a version of + the RPC library with DES Authentication. See the README + file in that directory for more details. + +BUILD INSTRUCTIONS + +Makefiles can be found in all directories except for man. The +Makefile in the top directory will cause these others to be invoked +(except for in the doc, man and demo directories), in turn building the +entire release. + +WARNING! THE DEFAULT INSTALLATION PROCEDURES WILL INSTALL FILES +IN /usr/include, /usr/lib, /usr/bin and /etc. + +The master RPC include file, rpc/rpc.h, is used by all programs and +routines that use RPC. It includes other RPC and system include files +needed by the RPC system. PLEASE NOTE: If your system has NFS, it +may have been based on Sun's NFS Source. The include files installed +by this package may duplicate include files you will find on your NFS +system. The RPCSRC 4.0 include files are upwardly compatible to all +NFS Source include files as of the date of this distribution (not +including any new definitions or declarations added by your system +vendor). HOWEVER: Please read the comments towards the end of +rpc/rpc.h regarding rpc/netdb.h. You may need to uncomment the +inclusion of that file if the structures it defines are already +defined by your system's include files. + +After making any compiler fixes that are needed (see below), at +the top directory, type: + + make install + +For all installations, the Makefile macro DESTDIR is prepended to the +installation path. It is defined to be null in the Makefiles, so +installations are relative to root. (You will probably need root +privileges for installing the files under the default path.) To +install the files under some other tree (e.g., /usr/local), use the +command: + + make install DESTDIR=/usr/local + +This will place the include files in /usr/local/usr/include, the RPC +library in /usr/local/usr/lib, rpcgen in /usr/local/usr/bin, and the +utilities in /usr/local/etc. You'll have to edit the Makefiles or +install the files by hand if you want to do anything other than this +kind of relocation of the installation tree. + +The RPC library will be built and installed first. By default it is +installed in /usr/lib as "librpclib.a". The directory +/usr/include/rpc will also be created, and several header files will +be installed there. ALL RPC SERVICES INCLUDE THESE HEADER FILES. + +The programs in etc/ link in routines from librpclib.a. If you change +where it is installed, be sure to edit etc/'s Makefile to reflect this. +These programs are installed in /etc. PORTMAP MUST BE RUNNING ON +YOUR SYSTEM BEFORE YOU START ANY OTHER RPC SERVICE. + +rpcgen is installed in /usr/bin. This program is required to build +the demonstration services in demo and the rstat client and server in +rpcsvc/. + +The rpcsvc/ directory will install its files in the directory +/usr/include/rpcsvc. The Remote Status service (rstat_svc) will be +compiled and installed in /etc. If you wish to make this service +available, you should either start this service when needed or have +it started at boot time by invoking it in your /etc/rc.local script. +(Be sure that portmap is started first!) Sun has modified its +version of inetd to automatically start RPC services. (Use "make +LIB=" when building rstat on a Sun Workstation.) The Remote Status +client (rstat) will be installed in /usr/bin. This program queries +the rstat_svc on a remote host and prints a system status summary +similar to the one printed by "uptime". + +The documentation is not built during the "make install" command. +Typing "make" in the doc directory will cause all of the manuals to +be formatted using nroff into a single file. We have had a report +that certain "troff" equivalents have trouble processing the full +manual. If you have trouble, try building the manuals individually +(see the Makefile). + +The demonstration services in the demo directory are not built by the +top-level "make install" command. To build these, cd to the demo +directory and enter "make". The three services will be built. +RPCGEN MUST BE INSTALLED in a path that make can find. To run the +services, start the portmap program as root and invoke the service +(you probably will want to put it in the background). rpcinfo can be +used to check that the service succeeded in getting registered with +portmap, and to ping the service (see rpcinfo's man page). You can +then use the corresponding client program to exercise the service. +To build these services on a Sun workstation, you must prevent the +Makefile from trying to link the RPC library (as these routines are +already a part of Sun's libc). Use: "make LIB=". + +BUGFIX FOR 4.3BSD COMPILER + +The use of a 'void *' declaration for one of the arguments in +the reply_proc() procedure in etc/rpcinfo.c will trigger a bug +in the 4.3BSD compiler. The bug is fixed by the following change to +the compiler file mip/manifest.h: + +*** manifest.h.r1.1 Thu Apr 30 13:52:25 1987 +--- manifest.h.r1.2 Mon Nov 23 18:58:17 1987 +*************** +*** 21,27 **** + /* + * Bogus type values + */ +! #define TNULL PTR /* pointer to UNDEF */ + #define TVOID FTN /* function returning UNDEF (for void) */ + + /* +--- 21,27 ---- + /* + * Bogus type values + */ +! #define TNULL INCREF(MOETY) /* pointer to MOETY -- impossible type */ + #define TVOID FTN /* function returning UNDEF (for void) */ + + /* + +If you cannot fix your compiler, change the declaration in reply_proc() +from 'void *' to 'char *'. + +BUGFIX FOR 4.2BSD COMPILER + +Unpatched 4.2BSD compilers complain about valid C. You can make old +compilers happy by changing some voids to ints. However, the fix to +the 4.2 VAX compiler is as follows (to mip/trees.c): + +*** trees.c.r1.1 Mon May 11 13:47:58 1987 +--- trees.c.r1.2 Wed Jul 2 18:28:52 1986 +*************** +*** 1247,1253 **** + if(o==CAST && mt1==0)return(TYPL+TYMATCH); + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); + else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +! else if( mt12 == 0 ) break; + else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; +--- 1261,1269 ---- + if(o==CAST && mt1==0)return(TYPL+TYMATCH); + if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); + else if( (mt1&MENU)||(mt2&MENU) ) return( LVAL+NCVT+TYPL+PTMATCH+PUN ); +! /* if right is TVOID and looks like a CALL, is not ok */ +! else if (mt2 == 0 && (p->in.right->in.op == CALL || p->in.right->in.op == UNARY CALL)) +! break; + else if( mt1 & MPTR ) return( LVAL+PTMATCH+PUN ); + else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); + break; + +WHAT'S NEW IN THIS RELEASE: RPCSRC 4.0 + +The previous release was RPCSRC 3.9. As with all previous releases, +this release is based directly on files from Sun Microsystem's +implementation. + +Upgrade from RPCSRC 3.9 + +1) RPCSRC 4.0 upgrades RPCSRC 3.9. Improvements from SunOS 4.0 have + been integrated into this release. + +Secure RPC (in the secure_rpc/ directory) + +2) DES Authentication routines and programs are provided. +3) A new manual, "Secure NFS" is provided, which describes Secure RPC + and Secure NFS. +4) Skeleton routines and manual pages are provided which describe the + DES encryption procedures required by Secure RPC. HOWEVER, NO DES + ROUTINE IS PROVIDED. + +New Functionality + +5) rpcinfo can now be used to de-register services from the portmapper + which may have terminated abnormally. +6) A new client, rstat, is provided which queries the rstat_svc and + prints a status line similar to the one displayed by "uptime". diff --git a/support/rpc/auth_gss.c b/support/rpc/auth_gss.c new file mode 100644 index 0000000..f41d678 --- /dev/null +++ b/support/rpc/auth_gss.c @@ -0,0 +1,628 @@ +/* + auth_gss.c + + RPCSEC_GSS client routines. + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void authgss_nextverf(); +static bool_t authgss_marshal(); +static bool_t authgss_refresh(); +static bool_t authgss_validate(); +static void authgss_destroy(); +static void authgss_destroy_context(); +static bool_t authgss_wrap(); +static bool_t authgss_unwrap(); + + +/* + * from mit-krb5-1.2.1 mechglue/mglueP.h: + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +static struct auth_ops authgss_ops = { + authgss_nextverf, + authgss_marshal, + authgss_validate, + authgss_refresh, + authgss_destroy, + authgss_wrap, + authgss_unwrap +}; + +#ifdef DEBUG + +/* useful as i add more mechanisms */ +void +print_rpc_gss_sec(struct rpc_gss_sec *ptr) +{ +int i; +char *p; + + log_debug("rpc_gss_sec:"); + if(ptr->mech == NULL) + log_debug("NULL gss_OID mech"); + else { + fprintf(stderr, " mechanism_OID: {"); + p = (char *)ptr->mech->elements; + for (i=0; i < ptr->mech->length; i++) + /* First byte of OIDs encoded to save a byte */ + if (i == 0) { + int first, second; + if (*p < 40) { + first = 0; + second = *p; + } + else if (40 <= *p && *p < 80) { + first = 1; + second = *p - 40; + } + else if (80 <= *p && *p < 127) { + first = 2; + second = *p - 80; + } + else { + /* Invalid value! */ + first = -1; + second = -1; + } + fprintf(stderr, " %u %u", first, second); + p++; + } + else { + fprintf(stderr, " %u", (unsigned char)*p++); + } + fprintf(stderr, " }\n"); + } + fprintf(stderr, " qop: %d\n", ptr->qop); + fprintf(stderr, " service: %d\n", ptr->svc); + fprintf(stderr, " cred: %p\n", ptr->cred); +} +#endif /*DEBUG*/ + +struct rpc_gss_data { + bool_t established; /* context established */ + gss_buffer_desc gc_wire_verf; /* save GSS_S_COMPLETE NULL RPC verfier + * to process at end of context negotiation*/ + CLIENT *clnt; /* client handle */ + gss_name_t name; /* service name */ + struct rpc_gss_sec sec; /* security tuple */ + gss_ctx_id_t ctx; /* context id */ + struct rpc_gss_cred gc; /* client credentials */ + u_int win; /* sequence window */ +}; + +#define AUTH_PRIVATE(auth) ((struct rpc_gss_data *)auth->ah_private) + +static struct timeval AUTH_TIMEOUT = { 25, 0 }; + +AUTH * +authgss_create(CLIENT *clnt, gss_name_t name, struct rpc_gss_sec *sec) +{ + AUTH *auth, *save_auth; + struct rpc_gss_data *gd; + OM_uint32 min_stat = 0; + + log_debug("in authgss_create()"); + + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); + + if ((auth = calloc(sizeof(*auth), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + return (NULL); + } + if ((gd = calloc(sizeof(*gd), 1)) == NULL) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } +#ifdef DEBUG + fprintf(stderr, "authgss_create: name is %p\n", name); +#endif + if (name != GSS_C_NO_NAME) { + if (gss_duplicate_name(&min_stat, name, &gd->name) + != GSS_S_COMPLETE) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = ENOMEM; + free(auth); + return (NULL); + } + } + else + gd->name = name; + +#ifdef DEBUG + fprintf(stderr, "authgss_create: gd->name is %p\n", gd->name); +#endif + gd->clnt = clnt; + gd->ctx = GSS_C_NO_CONTEXT; + gd->sec = *sec; + + gd->gc.gc_v = RPCSEC_GSS_VERSION; + gd->gc.gc_proc = RPCSEC_GSS_INIT; + gd->gc.gc_svc = gd->sec.svc; + + auth->ah_ops = &authgss_ops; + auth->ah_private = (caddr_t)gd; + + save_auth = clnt->cl_auth; + clnt->cl_auth = auth; + + if (!authgss_refresh(auth)) + auth = NULL; + + clnt->cl_auth = save_auth; + + return (auth); +} + +AUTH * +authgss_create_default(CLIENT *clnt, char *service, struct rpc_gss_sec *sec) +{ + AUTH *auth; + OM_uint32 maj_stat = 0, min_stat = 0; + gss_buffer_desc sname; + gss_name_t name = GSS_C_NO_NAME; + + log_debug("in authgss_create_default()"); + + + sname.value = service; + sname.length = strlen(service); + + maj_stat = gss_import_name(&min_stat, &sname, + GSS_C_NT_HOSTBASED_SERVICE, + &name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", maj_stat, min_stat); + rpc_createerr.cf_stat = RPC_AUTHERROR; + return (NULL); + } + + auth = authgss_create(clnt, name, sec); + + if (name != GSS_C_NO_NAME) { +#ifdef DEBUG + fprintf(stderr, "authgss_create_default: freeing name %p\n", name); +#endif + gss_release_name(&min_stat, &name); + } + + return (auth); +} + +bool_t +authgss_get_private_data(AUTH *auth, struct authgss_private_data *pd) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_get_private_data()"); + + if (!auth || !pd) + return (FALSE); + + gd = AUTH_PRIVATE(auth); + + if (!gd || !gd->established) + return (FALSE); + + pd->pd_ctx = gd->ctx; + pd->pd_ctx_hndl = gd->gc.gc_ctx; + pd->pd_seq_win = gd->win; + + return (TRUE); +} + +static void +authgss_nextverf(AUTH *auth) +{ + log_debug("in authgss_nextverf()"); + /* no action necessary */ +} + +static bool_t +authgss_marshal(AUTH *auth, XDR *xdrs) +{ + XDR tmpxdrs; + char tmp[MAX_AUTH_BYTES]; + struct rpc_gss_data *gd; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat; + bool_t xdr_stat; + + log_debug("in authgss_marshal()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + gd->gc.gc_seq++; + + xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); + + if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { + XDR_DESTROY(&tmpxdrs); + return (FALSE); + } + auth->ah_cred.oa_flavor = RPCSEC_GSS; + auth->ah_cred.oa_base = tmp; + auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); + + XDR_DESTROY(&tmpxdrs); + + if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) + return (FALSE); + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + return (xdr_opaque_auth(xdrs, &_null_auth)); + } + /* Checksum serialized RPC header, up to and including credential. */ + rpcbuf.length = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, 0); + rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); + + maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, + &rpcbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + auth->ah_verf.oa_flavor = RPCSEC_GSS; + auth->ah_verf.oa_base = checksum.value; + auth->ah_verf.oa_length = checksum.length; + + xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); + gss_release_buffer(&min_stat, &checksum); + + return (xdr_stat); +} + +static bool_t +authgss_validate(AUTH *auth, struct opaque_auth *verf) +{ + struct rpc_gss_data *gd; + u_int num, qop_state; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in authgss_validate()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established == FALSE) { + /* would like to do this only on NULL rpc -- + * gc->established is good enough. + * save the on the wire verifier to validate last + * INIT phase packet after decode if the major + * status is GSS_S_COMPLETE + */ + if ((gd->gc_wire_verf.value = + mem_alloc(verf->oa_length)) == NULL) { + fprintf(stderr, "gss_validate: out of memory\n"); + return (FALSE); + } + memcpy(gd->gc_wire_verf.value, verf->oa_base, verf->oa_length); + gd->gc_wire_verf.length = verf->oa_length; + return (TRUE); + } + + if (gd->gc.gc_proc == RPCSEC_GSS_INIT || + gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { + num = htonl(gd->win); + } + else num = htonl(gd->gc.gc_seq); + + signbuf.value = # + signbuf.length = sizeof(num); + + checksum.value = verf->oa_base; + checksum.length = verf->oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, &signbuf, + &checksum, &qop_state); + if (maj_stat != GSS_S_COMPLETE || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + return (TRUE); +} + +static bool_t +authgss_refresh(AUTH *auth) +{ + struct rpc_gss_data *gd; + struct rpc_gss_init_res gr; + gss_buffer_desc *recv_tokenp, send_token; + OM_uint32 maj_stat, min_stat, call_stat, ret_flags; + OM_uint32 req_flags=0; + + log_debug("in authgss_refresh()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->established) + return (TRUE); + + /* GSS context establishment loop. */ + memset(&gr, 0, sizeof(gr)); + recv_tokenp = GSS_C_NO_BUFFER; + +#ifdef DEBUG + print_rpc_gss_sec(&gd->sec); +#endif /*DEBUG*/ + + for (;;) { +#ifdef DEBUG + /* print the token we just received */ + if (recv_tokenp != GSS_C_NO_BUFFER) { + log_debug("The token we just received (length %d):", + recv_tokenp->length); + log_hexdump(recv_tokenp->value, recv_tokenp->length, 0); + } +#endif + maj_stat = gss_init_sec_context(&min_stat, + gd->sec.cred, + &gd->ctx, + gd->name, + gd->sec.mech, + gd->sec.req_flags, + 0, /* time req */ + NULL, /* channel */ + recv_tokenp, + NULL, /* used mech */ + &send_token, + &ret_flags, + NULL); /* time rec */ + + if (recv_tokenp != GSS_C_NO_BUFFER) { + gss_release_buffer(&min_stat, &gr.gr_token); + recv_tokenp = GSS_C_NO_BUFFER; + } + if (maj_stat != GSS_S_COMPLETE && + maj_stat != GSS_S_CONTINUE_NEEDED) { + log_status("gss_init_sec_context", maj_stat, min_stat); + break; + } + if (send_token.length != 0) { + memset(&gr, 0, sizeof(gr)); + +#ifdef DEBUG + /* print the token we are about to send */ + log_debug("The token being sent (length %d):", + send_token.length); + log_hexdump(send_token.value, send_token.length, 0); +#endif + + call_stat = clnt_call(gd->clnt, NULLPROC, + xdr_rpc_gss_init_args, + &send_token, + xdr_rpc_gss_init_res, + (caddr_t)&gr, AUTH_TIMEOUT); + + gss_release_buffer(&min_stat, &send_token); + + if (call_stat != RPC_SUCCESS || + (gr.gr_major != GSS_S_COMPLETE && + gr.gr_major != GSS_S_CONTINUE_NEEDED)) + return FALSE; + + if (gr.gr_ctx.length != 0) { + if (gd->gc.gc_ctx.value) + gss_release_buffer(&min_stat, + &gd->gc.gc_ctx); + gd->gc.gc_ctx = gr.gr_ctx; + } + if (gr.gr_token.length != 0) { + if (maj_stat != GSS_S_CONTINUE_NEEDED) + break; + recv_tokenp = &gr.gr_token; + } + gd->gc.gc_proc = RPCSEC_GSS_CONTINUE_INIT; + } + + /* GSS_S_COMPLETE => check gss header verifier, + * usually checked in gss_validate + */ + if (maj_stat == GSS_S_COMPLETE) { + gss_buffer_desc bufin; + gss_buffer_desc bufout; + u_int seq, qop_state = 0; + + seq = htonl(gr.gr_win); + bufin.value = (unsigned char *)&seq; + bufin.length = sizeof(seq); + bufout.value = (unsigned char *)gd->gc_wire_verf.value; + bufout.length = gd->gc_wire_verf.length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, + &bufin, &bufout, &qop_state); + + if (maj_stat != GSS_S_COMPLETE + || qop_state != gd->sec.qop) { + log_status("gss_verify_mic", maj_stat, min_stat); + if (maj_stat == GSS_S_CONTEXT_EXPIRED) { + gd->established = FALSE; + authgss_destroy_context(auth); + } + return (FALSE); + } + gd->established = TRUE; + gd->gc.gc_proc = RPCSEC_GSS_DATA; + gd->gc.gc_seq = 0; + gd->win = gr.gr_win; + break; + } + } + /* End context negotiation loop. */ + if (gd->gc.gc_proc != RPCSEC_GSS_DATA) { + if (gr.gr_token.length != 0) + gss_release_buffer(&min_stat, &gr.gr_token); + + authgss_destroy(auth); + auth = NULL; + rpc_createerr.cf_stat = RPC_AUTHERROR; + + return (FALSE); + } + return (TRUE); +} + +bool_t +authgss_service(AUTH *auth, int svc) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_service()"); + + if (!auth) + return(FALSE); + gd = AUTH_PRIVATE(auth); + if (!gd || !gd->established) + return (FALSE); + gd->sec.svc = svc; + gd->gc.gc_svc = svc; + return (TRUE); +} + +static void +authgss_destroy_context(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy_context()"); + + gd = AUTH_PRIVATE(auth); + + if (gd->gc.gc_ctx.length != 0) { + if (gd->established) { + gd->gc.gc_proc = RPCSEC_GSS_DESTROY; + clnt_call(gd->clnt, NULLPROC, xdr_void, NULL, + xdr_void, NULL, AUTH_TIMEOUT); + } + gss_release_buffer(&min_stat, &gd->gc.gc_ctx); + /* XXX ANDROS check size of context - should be 8 */ + memset(&gd->gc.gc_ctx, 0, sizeof(gd->gc.gc_ctx)); + } + if (gd->ctx != GSS_C_NO_CONTEXT) { + gss_delete_sec_context(&min_stat, &gd->ctx, NULL); + gd->ctx = GSS_C_NO_CONTEXT; + } + gd->established = FALSE; +} + +static void +authgss_destroy(AUTH *auth) +{ + struct rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in authgss_destroy()"); + + gd = AUTH_PRIVATE(auth); + + authgss_destroy_context(auth); + +#ifdef DEBUG + fprintf(stderr, "authgss_destroy: freeing name %p\n", gd->name); +#endif + if (gd->name != GSS_C_NO_NAME) + gss_release_name(&min_stat, &gd->name); + + free(gd); + free(auth); +} + +bool_t +authgss_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_wrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} + +bool_t +authgss_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct rpc_gss_data *gd; + + log_debug("in authgss_unwrap()"); + + gd = AUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->gc.gc_seq)); +} diff --git a/support/rpc/authgss_prot.c b/support/rpc/authgss_prot.c new file mode 100644 index 0000000..97724f1 --- /dev/null +++ b/support/rpc/authgss_prot.c @@ -0,0 +1,355 @@ +/* + authgss_prot.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool_t +xdr_rpc_gss_cred(XDR *xdrs, struct rpc_gss_cred *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_u_int(xdrs, &p->gc_v) && + xdr_enum(xdrs, (enum_t *)&p->gc_proc) && + xdr_u_int(xdrs, &p->gc_seq) && + xdr_enum(xdrs, (enum_t *)&p->gc_svc) && + xdr_bytes(xdrs, (char **)&p->gc_ctx.value, + &p->gc_ctx.length, MAX_AUTH_BYTES)); + + log_debug("xdr_rpc_gss_cred: %s %s " + "(v %d, proc %d, seq %d, svc %d, ctx %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gc_v, p->gc_proc, p->gc_seq, p->gc_svc, + p->gc_ctx.value, p->gc_ctx.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_init_args(XDR *xdrs, gss_buffer_desc *p) +{ + bool_t xdr_stat; + + xdr_stat = xdr_bytes(xdrs, (char **)&p->value, + &p->length, MAX_NETOBJ_SZ); + + log_debug("xdr_rpc_gss_init_args: %s %s (token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->value, p->length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_init_res(XDR *xdrs, struct rpc_gss_init_res *p) +{ + bool_t xdr_stat; + + xdr_stat = (xdr_bytes(xdrs, (char **)&p->gr_ctx.value, + &p->gr_ctx.length, MAX_NETOBJ_SZ) && + xdr_u_int(xdrs, &p->gr_major) && + xdr_u_int(xdrs, &p->gr_minor) && + xdr_u_int(xdrs, &p->gr_win) && + xdr_bytes(xdrs, (char **)&p->gr_token.value, + &p->gr_token.length, MAX_NETOBJ_SZ)); + + log_debug("xdr_rpc_gss_init_res %s %s " + "(ctx %p:%d, maj %d, min %d, win %d, token %p:%d)", + (xdrs->x_op == XDR_ENCODE) ? "encode" : "decode", + (xdr_stat == TRUE) ? "success" : "failure", + p->gr_ctx.value, p->gr_ctx.length, + p->gr_major, p->gr_minor, p->gr_win, + p->gr_token.value, p->gr_token.length); + + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + gss_buffer_desc databuf, wrapbuf; + OM_uint32 maj_stat, min_stat; + int start, end, conf_state; + bool_t xdr_stat; + + /* Skip databody length. */ + start = XDR_GETPOS(xdrs); + XDR_SETPOS(xdrs, start + 4); + + /* Marshal rpc_gss_data_t (sequence number + arguments). */ + if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr)) + return (FALSE); + end = XDR_GETPOS(xdrs); + + /* Set databuf to marshalled rpc_gss_data_t. */ + databuf.length = end - start - 4; + XDR_SETPOS(xdrs, start + 4); + databuf.value = XDR_INLINE(xdrs, databuf.length); + + xdr_stat = FALSE; + + if (svc == RPCSEC_GSS_SVC_INTEGRITY) { + /* Marshal databody_integ length. */ + XDR_SETPOS(xdrs, start); + if (!xdr_u_int(xdrs, &databuf.length)) + return (FALSE); + + /* Checksum rpc_gss_data_t. */ + maj_stat = gss_get_mic(&min_stat, ctx, qop, + &databuf, &wrapbuf); + if (maj_stat != GSS_S_COMPLETE) { + log_debug("gss_get_mic failed"); + return (FALSE); + } + /* Marshal checksum. */ + XDR_SETPOS(xdrs, end); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + &wrapbuf.length, MAX_NETOBJ_SZ); + gss_release_buffer(&min_stat, &wrapbuf); + } + else if (svc == RPCSEC_GSS_SVC_PRIVACY) { + /* Encrypt rpc_gss_data_t. */ + maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, + &conf_state, &wrapbuf); + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_wrap", maj_stat, min_stat); + return (FALSE); + } + /* Marshal databody_priv. */ + XDR_SETPOS(xdrs, start); + xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value, + &wrapbuf.length, MAX_NETOBJ_SZ); + gss_release_buffer(&min_stat, &wrapbuf); + } + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + XDR tmpxdrs; + gss_buffer_desc databuf, wrapbuf; + OM_uint32 maj_stat, min_stat; + u_int seq_num, conf_state, qop_state; + bool_t xdr_stat; + + if (xdr_func == xdr_void || xdr_ptr == NULL) + return (TRUE); + + memset(&databuf, 0, sizeof(databuf)); + memset(&wrapbuf, 0, sizeof(wrapbuf)); + + if (svc == RPCSEC_GSS_SVC_INTEGRITY) { + /* Decode databody_integ. */ + if (!xdr_bytes(xdrs, (char **)&databuf.value, &databuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr decode databody_integ failed"); + return (FALSE); + } + /* Decode checksum. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, &wrapbuf.length, + MAX_NETOBJ_SZ)) { + gss_release_buffer(&min_stat, &databuf); + log_debug("xdr decode checksum failed"); + return (FALSE); + } + /* Verify checksum and QOP. */ + maj_stat = gss_verify_mic(&min_stat, ctx, &databuf, + &wrapbuf, &qop_state); + gss_release_buffer(&min_stat, &wrapbuf); + + if (maj_stat != GSS_S_COMPLETE || qop_state != qop) { + gss_release_buffer(&min_stat, &databuf); + log_status("gss_verify_mic", maj_stat, min_stat); + return (FALSE); + } + } + else if (svc == RPCSEC_GSS_SVC_PRIVACY) { + /* Decode databody_priv. */ + if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, &wrapbuf.length, + MAX_NETOBJ_SZ)) { + log_debug("xdr decode databody_priv failed"); + return (FALSE); + } + /* Decrypt databody. */ + maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf, + &conf_state, &qop_state); + + gss_release_buffer(&min_stat, &wrapbuf); + + /* Verify encryption and QOP. */ + if (maj_stat != GSS_S_COMPLETE || qop_state != qop || + conf_state != TRUE) { + gss_release_buffer(&min_stat, &databuf); + log_status("gss_unwrap", maj_stat, min_stat); + return (FALSE); + } + } + /* Decode rpc_gss_data_t (sequence number + arguments). */ + xdrmem_create(&tmpxdrs, databuf.value, databuf.length, XDR_DECODE); + xdr_stat = (xdr_u_int(&tmpxdrs, &seq_num) && + (*xdr_func)(&tmpxdrs, xdr_ptr)); + XDR_DESTROY(&tmpxdrs); + gss_release_buffer(&min_stat, &databuf); + + /* Verify sequence number. */ + if (xdr_stat == TRUE && seq_num != seq) { + log_debug("wrong sequence number in databody"); + return (FALSE); + } + return (xdr_stat); +} + +bool_t +xdr_rpc_gss_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, + gss_ctx_id_t ctx, gss_qop_t qop, + rpc_gss_svc_t svc, u_int seq) +{ + switch (xdrs->x_op) { + + case XDR_ENCODE: + return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop, svc, seq)); + case XDR_DECODE: + return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, + ctx, qop,svc, seq)); + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +#ifdef DEBUG +#include + +void +log_debug(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "rpcsec_gss: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void +log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) +{ + OM_uint32 min; + gss_buffer_desc msg; + int msg_ctx = 0; + + fprintf(stderr, "rpcsec_gss: %s: ", m); + + gss_display_status(&min, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s - ", (char *)msg.value); + gss_release_buffer(&min, &msg); + + gss_display_status(&min, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, + &msg_ctx, &msg); + fprintf(stderr, "%s\n", (char *)msg.value); + gss_release_buffer(&min, &msg); +} + +void +log_hexdump(const u_char *buf, int len, int offset) +{ + u_int i, j, jm; + int c; + + fprintf(stderr, "\n"); + for (i = 0; i < len; i += 0x10) { + fprintf(stderr, " %04x: ", (u_int)(i + offset)); + jm = len - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + if ((j % 2) == 1) + fprintf(stderr, "%02x ", (u_int) buf[i+j]); + else + fprintf(stderr, "%02x", (u_int) buf[i+j]); + } + for (; j < 16; j++) { + if ((j % 2) == 1) printf(" "); + else fprintf(stderr, " "); + } + fprintf(stderr, " "); + + for (j = 0; j < jm; j++) { + c = buf[i+j]; + c = isprint(c) ? c : '.'; + fprintf(stderr, "%c", c); + } + fprintf(stderr, "\n"); + } +} + +#else + +void +log_debug(const char *fmt, ...) +{ +} + +void +log_status(char *m, OM_uint32 maj_stat, OM_uint32 min_stat) +{ +} + +void +log_hexdump(const u_char *buf, int len, int offset) +{ +} + +#endif + + diff --git a/support/rpc/include/rpc/auth.h b/support/rpc/include/rpc/auth.h new file mode 100644 index 0000000..5924ce6 --- /dev/null +++ b/support/rpc/include/rpc/auth.h @@ -0,0 +1,216 @@ +/* $OpenBSD: auth.h,v 1.2 1997/09/21 10:46:09 niklas Exp $ */ +/* $NetBSD: auth.h,v 1.7 1995/04/29 05:27:55 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)auth.h 1.17 88/02/08 SMI + * @(#)auth.h 2.3 88/08/07 4.0 RPCSRC + */ + +/* + * 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". + */ + +#ifndef _RPC_AUTH_H +#define _RPC_AUTH_H +#include + +#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 */ + /* + * RPCSEC_GSS errors + */ + RPCSEC_GSS_CREDPROBLEM = 13, + RPCSEC_GSS_CTXPROBLEM = 14 +}; + +typedef u_int32_t u_int32; /* 32-bit unsigned integers */ + +union des_block { + struct { + u_int32 high; + u_int32 low; + } key; + char c[8]; +}; +typedef union des_block des_block; +__BEGIN_DECLS +extern bool_t xdr_des_block __P((XDR *, des_block *)); +__END_DECLS + +/* + * Authentication info. Opaque to client. + */ +struct opaque_auth { + enum_t oa_flavor; /* flavor of auth */ + caddr_t oa_base; /* address of more auth stuff */ + u_int oa_length; /* not to exceed MAX_AUTH_BYTES */ +}; + + +/* + * Auth handle, interface to client side authenticators. + */ +typedef struct __rpc_auth { + struct opaque_auth ah_cred; + struct opaque_auth ah_verf; + union des_block ah_key; + struct auth_ops { + void (*ah_nextverf) __P((struct __rpc_auth *)); + /* nextverf & serialize */ + int (*ah_marshal) __P((struct __rpc_auth *, XDR *)); + /* validate verifier */ + int (*ah_validate) __P((struct __rpc_auth *, + struct opaque_auth *)); + /* refresh credentials */ + int (*ah_refresh) __P((struct __rpc_auth *)); + /* destroy this structure */ + void (*ah_destroy) __P((struct __rpc_auth *)); + /* encode data for wire */ + int (*ah_wrap) __P((struct __rpc_auth *, XDR *, xdrproc_t, caddr_t)); + /* decode data for wire */ + int (*ah_unwrap) __P((struct __rpc_auth *, XDR *, xdrproc_t, caddr_t)); + + } *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) \ + ((*((auth)->ah_ops->ah_refresh))(auth)) +#define auth_refresh(auth) \ + ((*((auth)->ah_ops->ah_refresh))(auth)) + +#define AUTH_DESTROY(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) +#define auth_destroy(auth) \ + ((*((auth)->ah_ops->ah_destroy))(auth)) + +#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)) + + +extern struct opaque_auth _null_auth; + +/* + * 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(); + +/* + * These are the various implementations of client side authenticators. + */ + +/* + * Unix style authentication + * AUTH *authunix_create(machname, uid, gid, len, aup_gids) + * char *machname; + * int uid; + * int gid; + * int len; + * int *aup_gids; + */ +__BEGIN_DECLS +struct sockaddr_in; +extern AUTH *authunix_create __P((char *, int, int, int, int *)); +extern AUTH *authunix_create_default __P((void)); +extern AUTH *authnone_create __P((void)); +extern AUTH *authdes_create __P((char *, u_int, + struct sockaddr_in *, des_block *)); +extern bool_t xdr_opaque_auth __P((XDR *, struct opaque_auth *)); +__END_DECLS + +#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 RPCSEC_GSS 6 /* RPCSEC_GSS */ + +#endif /* !_RPC_AUTH_H */ diff --git a/support/rpc/include/rpc/auth_gss.h b/support/rpc/include/rpc/auth_gss.h new file mode 100644 index 0000000..dc206b0 --- /dev/null +++ b/support/rpc/include/rpc/auth_gss.h @@ -0,0 +1,123 @@ +/* + auth_gss.h + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _RPC_AUTH_GSS_H +#define _RPC_AUTH_GSS_H + +#include "config.h" +#include +#include "../../../include/gssapi/gssapi.h" + +/* RPCSEC_GSS control procedures. */ +typedef enum { + RPCSEC_GSS_DATA = 0, + RPCSEC_GSS_INIT = 1, + RPCSEC_GSS_CONTINUE_INIT = 2, + RPCSEC_GSS_DESTROY = 3 +} rpc_gss_proc_t; + +/* RPCSEC_GSS services. */ +typedef enum { + RPCSEC_GSS_SVC_NONE = 1, + RPCSEC_GSS_SVC_INTEGRITY = 2, + RPCSEC_GSS_SVC_PRIVACY = 3 +} rpc_gss_svc_t; + +#define RPCSEC_GSS_VERSION 1 + +/* RPCSEC_GSS security triple. */ +struct rpc_gss_sec { + gss_OID mech; /* mechanism */ + gss_qop_t qop; /* quality of protection */ + rpc_gss_svc_t svc; /* service */ + gss_cred_id_t cred; /* cred handle */ + u_int req_flags; /* req flags for init_sec_context */ +}; + +/* Private data required for kernel implementation */ +struct authgss_private_data { + gss_ctx_id_t pd_ctx; /* Session context handle */ + gss_buffer_desc pd_ctx_hndl; /* Credentials context handle */ + u_int pd_seq_win; /* Sequence window */ +}; + +/* Credentials. */ +struct rpc_gss_cred { + u_int gc_v; /* version */ + rpc_gss_proc_t gc_proc; /* control procedure */ + u_int gc_seq; /* sequence number */ + rpc_gss_svc_t gc_svc; /* service */ + gss_buffer_desc gc_ctx; /* context handle */ +}; + +/* Context creation response. */ +struct rpc_gss_init_res { + gss_buffer_desc gr_ctx; /* context handle */ + u_int gr_major; /* major status */ + u_int gr_minor; /* minor status */ + u_int gr_win; /* sequence window */ + gss_buffer_desc gr_token; /* token */ +}; + +/* Maximum sequence number value. */ +#define MAXSEQ 0x80000000 + +/* Prototypes. */ +__BEGIN_DECLS +bool_t xdr_rpc_gss_cred __P((XDR *xdrs, struct rpc_gss_cred *p)); +bool_t xdr_rpc_gss_init_args __P((XDR *xdrs, gss_buffer_desc *p)); +bool_t xdr_rpc_gss_init_res __P((XDR *xdrs, struct rpc_gss_init_res *p)); +bool_t xdr_rpc_gss_data __P((XDR *xdrs, xdrproc_t xdr_func, + caddr_t xdr_ptr, gss_ctx_id_t ctx, + gss_qop_t qop, rpc_gss_svc_t svc, + u_int seq)); + +AUTH *authgss_create __P((CLIENT *, gss_name_t, + struct rpc_gss_sec *)); +AUTH *authgss_create_default __P((CLIENT *, char *, struct rpc_gss_sec *)); +bool_t authgss_service __P((AUTH *auth, int svc)); +bool_t authgss_get_private_data __P((AUTH *auth, + struct authgss_private_data *)); + + +void log_debug __P((const char *fmt, ...)); +void log_status __P((char *m, OM_uint32 major, + OM_uint32 minor)); +void log_hexdump __P((const u_char *buf, int len, int offset)); + +__END_DECLS + +#endif /* !_RPC_AUTH_GSS_H */ diff --git a/support/rpc/include/rpc/auth_unix.h b/support/rpc/include/rpc/auth_unix.h new file mode 100644 index 0000000..06cff5d --- /dev/null +++ b/support/rpc/include/rpc/auth_unix.h @@ -0,0 +1,84 @@ +/* $OpenBSD: auth_unix.h,v 1.2 1997/09/21 10:46:09 niklas Exp $ */ +/* $NetBSD: auth_unix.h,v 1.4 1994/10/26 00:56:56 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)auth_unix.h 1.8 88/02/08 SMI + * @(#)auth_unix.h 2.2 88/07/29 4.0 RPCSRC + */ + +/* + * 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. + */ + +#ifndef _RPC_AUTH_UNIX_H +#define _RPC_AUTH_UNIX_H +#include + +/* 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 { + u_long aup_time; + char *aup_machname; + int aup_uid; + int aup_gid; + u_int aup_len; + int *aup_gids; +}; + +__BEGIN_DECLS +extern bool_t xdr_authunix_parms __P((XDR *, struct authunix_parms *)); +__END_DECLS + +/* + * 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; +}; + +#endif /* !_RPC_AUTH_UNIX_H */ diff --git a/support/rpc/include/rpc/clnt.h b/support/rpc/include/rpc/clnt.h new file mode 100644 index 0000000..4ac7be2 --- /dev/null +++ b/support/rpc/include/rpc/clnt.h @@ -0,0 +1,373 @@ +/* $OpenBSD: clnt.h,v 1.4 1998/03/19 00:27:17 millert Exp $ */ +/* $NetBSD: clnt.h,v 1.6 1995/04/29 05:27:58 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)clnt.h 1.31 88/02/08 SMI + * @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * clnt.h - Client side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_CLNT_H_ +#define _RPC_CLNT_H_ +#include + +/* + * 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 { + u_int32_t low; /* lowest verion supported */ + u_int32_t high; /* highest verion supported */ + } RE_vers; + struct { /* maybe meaningful if RPC_FAILED */ + int32_t s1; + int32_t 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 __rpc_client { + AUTH *cl_auth; /* authenticator */ + struct clnt_ops { + /* call remote procedure */ + enum clnt_stat (*cl_call) __P((struct __rpc_client *, + u_long, xdrproc_t, caddr_t, xdrproc_t, + caddr_t, struct timeval)); + /* abort a call */ + void (*cl_abort) __P((struct __rpc_client *)); + /* get specific error code */ + void (*cl_geterr) __P((struct __rpc_client *, + struct rpc_err *)); + /* frees results */ + bool_t (*cl_freeres) __P((struct __rpc_client *, + xdrproc_t, caddr_t)); + /* destroy this structure */ + void (*cl_destroy) __P((struct __rpc_client *)); + /* the ioctl() of rpc */ + bool_t (*cl_control) __P((struct __rpc_client *, u_int, + void *)); + } *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; + * u_long 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, (caddr_t)argsp, \ + xres, (caddr_t)resp, secs)) +#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \ + ((*(rh)->cl_ops->cl_call)(rh, proc, xargs, (caddr_t)argsp, \ + xres, (caddr_t)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; + * u_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) */ + +/* + * 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 ((u_long)1) +#define RPCTEST_VERSION ((u_long)1) +#define RPCTEST_NULL_PROC ((u_long)2) +#define RPCTEST_NULL_BATCH_PROC ((u_long)3) + +/* + * By convention, procedure 0 takes null arguments and returns them + */ + +#define NULLPROC ((u_int)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) + * u_long prog; + * u_long vers; + */ +__BEGIN_DECLS +extern CLIENT *clntraw_create __P((u_long, u_long)); +__END_DECLS + + +/* + * Generic client creation routine. Supported protocols are "udp" and "tcp" + * CLIENT * + * clnt_create(host, prog, vers, prot); + * char *host; -- hostname + * u_long prog; -- program number + * u_long vers; -- version number + * char *prot; -- protocol + */ +__BEGIN_DECLS +extern CLIENT *clnt_create __P((char *, u_long, u_long, char *)); +__END_DECLS + + +/* + * TCP based rpc + * CLIENT * + * clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz) + * struct sockaddr_in *raddr; + * u_long prog; + * u_long version; + * register int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clnttcp_create __P((struct sockaddr_in *, + u_long, + u_long, + int *, + u_int, + u_int)); +__END_DECLS + + +/* + * UDP based rpc. + * CLIENT * + * clntudp_create(raddr, program, version, wait, sockp) + * struct sockaddr_in *raddr; + * u_long program; + * u_long 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; + * u_long program; + * u_long version; + * struct timeval wait; + * int *sockp; + * u_int sendsz; + * u_int recvsz; + */ +__BEGIN_DECLS +extern CLIENT *clntudp_create __P((struct sockaddr_in *, + u_long, + u_long, + struct timeval, + int *)); +extern CLIENT *clntudp_bufcreate __P((struct sockaddr_in *, + u_long, + u_long, + struct timeval, + int *, + u_int, + u_int)); +__END_DECLS + + +/* + * Print why creation failed + */ +__BEGIN_DECLS +extern void clnt_pcreateerror __P((char *)); /* stderr */ +extern char *clnt_spcreateerror __P((char *)); /* string */ +__END_DECLS + +/* + * Like clnt_perror(), but is more verbose in its output + */ +__BEGIN_DECLS +extern void clnt_perrno __P((enum clnt_stat)); /* stderr */ +extern char *clnt_sperrno __P((enum clnt_stat)); /* string */ +__END_DECLS + +/* + * Print an English error message, given the client error code + */ +__BEGIN_DECLS +extern void clnt_perror __P((CLIENT *, char *)); /* stderr */ +extern char *clnt_sperror __P((CLIENT *, char *)); /* string */ +__END_DECLS + + +/* + * 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; + + +#define UDPMSGSIZE 8800 /* rpc imposed limit on udp msg size */ +#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */ + +#endif /* !_RPC_CLNT_H */ diff --git a/support/rpc/include/rpc/pmap_clnt.h b/support/rpc/include/rpc/pmap_clnt.h new file mode 100644 index 0000000..f7aff55 --- /dev/null +++ b/support/rpc/include/rpc/pmap_clnt.h @@ -0,0 +1,87 @@ +/* $OpenBSD: pmap_clnt.h,v 1.3 1998/08/29 18:57:14 deraadt Exp $ */ +/* $NetBSD: pmap_clnt.h,v 1.5 1994/12/04 01:12:42 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)pmap_clnt.h 1.11 88/02/08 SMI + * @(#)pmap_clnt.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * 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. + */ + +#ifndef _RPC_PMAPCLNT_H +#define _RPC_PMAPCLNT_H +#include + +__BEGIN_DECLS +extern bool_t pmap_set __P((u_long, u_long, u_int, int)); +extern bool_t pmap_unset __P((u_long, u_long)); +extern struct pmaplist *pmap_getmaps __P((struct sockaddr_in *)); +extern enum clnt_stat pmap_rmtcall __P((struct sockaddr_in *, + u_long, u_long, u_long, + xdrproc_t, caddr_t, + xdrproc_t, caddr_t, + struct timeval, u_long *)); +extern enum clnt_stat clnt_broadcast __P((u_long, u_long, u_long, + xdrproc_t, char *, + xdrproc_t, char *, + bool_t (*) __P((caddr_t, + struct sockaddr_in *)))); +extern u_short pmap_getport __P((struct sockaddr_in *, + u_long, u_long, u_int)); +__END_DECLS + +#endif /* !_RPC_PMAPCLNT_H */ diff --git a/support/rpc/include/rpc/pmap_prot.h b/support/rpc/include/rpc/pmap_prot.h new file mode 100644 index 0000000..68f5474 --- /dev/null +++ b/support/rpc/include/rpc/pmap_prot.h @@ -0,0 +1,106 @@ +/* $OpenBSD: pmap_prot.h,v 1.3 1998/02/10 06:25:32 deraadt Exp $ */ +/* $NetBSD: pmap_prot.h,v 1.4 1994/10/26 00:57:00 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)pmap_prot.h 1.14 88/02/08 SMI + * @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * 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 (unsigned long). + * 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 int, unsigned int, unsigned int, 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. + */ + +#ifndef _RPC_PMAPPROT_H +#define _RPC_PMAPPROT_H +#include + +#define PMAPPORT ((u_short)111) +#define PMAPPROG ((u_long)100000) +#define PMAPVERS ((u_long)2) +#define PMAPVERS_PROTO ((u_long)2) +#define PMAPVERS_ORIG ((u_long)1) +#define PMAPPROC_NULL ((u_long)0) +#define PMAPPROC_SET ((u_long)1) +#define PMAPPROC_UNSET ((u_long)2) +#define PMAPPROC_GETPORT ((u_long)3) +#define PMAPPROC_DUMP ((u_long)4) +#define PMAPPROC_CALLIT ((u_long)5) + +struct pmap { + unsigned long pm_prog; + unsigned long pm_vers; + unsigned long pm_prot; + unsigned long pm_port; +}; + +struct pmaplist { + struct pmap pml_map; + struct pmaplist *pml_next; +}; + +__BEGIN_DECLS +extern bool_t xdr_pmap __P((XDR *, struct pmap *)); +extern bool_t xdr_pmaplist __P((XDR *, struct pmaplist **)); +__END_DECLS + +#endif /* !_RPC_PMAPPROT_H */ diff --git a/support/rpc/include/rpc/pmap_rmt.h b/support/rpc/include/rpc/pmap_rmt.h new file mode 100644 index 0000000..203813f --- /dev/null +++ b/support/rpc/include/rpc/pmap_rmt.h @@ -0,0 +1,65 @@ +/* $OpenBSD: pmap_rmt.h,v 1.2 1997/09/21 10:46:13 niklas Exp $ */ +/* $NetBSD: pmap_rmt.h,v 1.4 1994/10/26 00:57:01 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)pmap_rmt.h 1.2 88/02/08 SMI + * @(#)pmap_rmt.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * Structures and XDR routines for parameters to and replies from + * the portmapper remote-call-service. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + */ + +#ifndef _RPC_PMAPRMT_H +#define _RPC_PMAPRMT_H +#include + +struct rmtcallargs { + u_long prog, vers, proc, arglen; + caddr_t args_ptr; + xdrproc_t xdr_args; +}; + +struct rmtcallres { + u_long *port_ptr; + u_long resultslen; + caddr_t results_ptr; + xdrproc_t xdr_results; +}; + +__BEGIN_DECLS +extern bool_t xdr_rmtcall_args __P((XDR *, struct rmtcallargs *)); +extern bool_t xdr_rmtcallres __P((XDR *, struct rmtcallres *)); +__END_DECLS + +#endif /* !_RPC_PMAPRMT_H */ diff --git a/support/rpc/include/rpc/rpc.h b/support/rpc/include/rpc/rpc.h new file mode 100644 index 0000000..5b62519 --- /dev/null +++ b/support/rpc/include/rpc/rpc.h @@ -0,0 +1,109 @@ +/* $OpenBSD: rpc.h,v 1.7 1998/12/20 23:43:18 millert Exp $ */ +/* $NetBSD: rpc.h,v 1.5 1994/12/04 01:15:30 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)rpc.h 1.9 88/02/08 SMI + * @(#)rpc.h 2.4 89/07/11 4.0 RPCSRC + */ + +/* + * rpc.h, Just includes the billions of rpc header files necessary to + * do remote procedure calling. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ +#ifndef _RPC_RPC_H +#define _RPC_RPC_H + +#include /* some typedefs */ +#include + +/* external data representation interfaces */ +#include /* generic (de)serializer */ + +/* Client side only authentication */ +#include /* generic authenticator (client side) */ + +/* Client side (mostly) remote procedure call */ +#include /* generic rpc stuff */ + +/* Client side (mostly) pmap functions */ +#include /* generic pmap stuff */ + +/* semi-private protocol headers */ +#include /* protocol for rpc messages */ +#include /* protocol for unix style cred */ +#include "auth_gss.h" /* RPCSEC_GSS */ + +/* + * Uncomment-out the next line if you are building the rpc library with + * DES Authentication (see the README file in the secure_rpc/ directory). + */ +#ifdef notdef +#include /* protocol for des style cred */ +#endif + +/* Server side only remote procedure callee */ +#include /* service side authenticator */ +#include /* service manager and multiplexer */ + +/* + * COMMENT OUT THE NEXT INCLUDE (or add to the #ifndef) IF RUNNING ON + * A VERSION OF UNIX THAT USES SUN'S NFS SOURCE. These systems will + * already have the structures defined by included in . + */ +/* routines for parsing /etc/rpc */ +#ifdef __linux__ +#include +#else +struct rpcent { + char *r_name; /* name of server for this rpc program */ + char **r_aliases; /* alias list */ + int r_number; /* rpc program number */ +}; + +__BEGIN_DECLS +extern struct rpcent *getrpcbyname __P((char *)); +extern struct rpcent *getrpcbynumber __P((int)); +extern struct rpcent *getrpcent __P((void)); +extern void setrpcent __P((int)); +extern void endrpcent __P((void)); + +extern int get_myaddress __P((struct sockaddr_in *)); +extern int registerrpc __P((int, int, int, char *(*) __P((char [UDPMSGSIZE])), + xdrproc_t, xdrproc_t)); +extern int callrpc __P((char *, int, int, int, xdrproc_t, char *, + xdrproc_t , char *)); +extern int getrpcport __P((char *, int, int, int)); + +__END_DECLS +#endif /* __linux__ */ + +#endif /* !_RPC_RPC_H */ diff --git a/support/rpc/include/rpc/rpc_des.h b/support/rpc/include/rpc/rpc_des.h new file mode 100644 index 0000000..597a473 --- /dev/null +++ b/support/rpc/include/rpc/rpc_des.h @@ -0,0 +1,133 @@ +/* $OpenBSD: rpc_des.h,v 1.3 1998/02/10 06:25:33 deraadt Exp $ */ + +/* crypto/des/rpc_des.h */ +/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@mincom.oz.au). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@mincom.oz.au). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@mincom.oz.au)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@mincom.oz.au)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* @(#)des.h 2.2 88/08/10 4.0 RPCSRC; from 2.7 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 + */ +/* + * Generic DES driver interface + * Keep this file hardware independent! + * Copyright (c) 1986 by Sun Microsystems, Inc. + */ + +#define DES_MAXLEN 65536 /* maximum # of bytes to encrypt */ +#define DES_QUICKLEN 16 /* maximum # of bytes to encrypt quickly */ + +#ifdef HEADER_DES_H +#undef ENCRYPT +#undef DECRYPT +#endif + +enum desdir { ENCRYPT, DECRYPT }; +enum desmode { CBC, ECB }; + +/* + * parameters to ioctl call + */ +struct desparams { + unsigned char des_key[8]; /* key (with low bit parity) */ + enum desdir des_dir; /* direction */ + enum desmode des_mode; /* mode */ + unsigned char des_ivec[8]; /* input vector */ + unsigned int des_len; /* number of bytes to crypt */ + union { + unsigned char UDES_data[DES_QUICKLEN]; + unsigned char *UDES_buf; + } UDES; +# define des_data UDES.UDES_data /* direct data here if quick */ +# define des_buf UDES.UDES_buf /* otherwise, pointer to data */ +}; + +/* + * Encrypt an arbitrary sized buffer + */ +#define DESIOCBLOCK _IOWR(d, 6, struct desparams) + +/* + * Encrypt of small amount of data, quickly + */ +#define DESIOCQUICK _IOWR(d, 7, struct desparams) + diff --git a/support/rpc/include/rpc/rpc_msg.h b/support/rpc/include/rpc/rpc_msg.h new file mode 100644 index 0000000..63432d1 --- /dev/null +++ b/support/rpc/include/rpc/rpc_msg.h @@ -0,0 +1,197 @@ +/* $OpenBSD: rpc_msg.h,v 1.2 1997/09/21 10:46:15 niklas Exp $ */ +/* $NetBSD: rpc_msg.h,v 1.5 1995/04/29 05:28:00 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)rpc_msg.h 1.7 86/07/16 SMI + * @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * rpc_msg.h + * rpc message definition + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_RPCMSG_H +#define _RPC_RPCMSG_H + +#define RPC_MSG_VERSION ((u_long) 2) +#define RPC_SERVICE_PORT ((u_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 { + u_int32_t low; + u_int32_t 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 { + u_int32_t low; + u_int32_t 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 { + u_int32_t cb_rpcvers; /* must be equal to two */ + u_int32_t cb_prog; + u_int32_t cb_vers; + u_int32_t cb_proc; + struct opaque_auth cb_cred; + struct opaque_auth cb_verf; /* protocol specific - provided by client */ +}; + +/* + * The rpc message + */ +struct rpc_msg { + u_int32_t 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 + +__BEGIN_DECLS +/* + * XDR routine to handle a rpc message. + * xdr_callmsg(xdrs, cmsg) + * XDR *xdrs; + * struct rpc_msg *cmsg; + */ +extern bool_t xdr_callmsg __P((XDR *, struct rpc_msg *)); + +/* + * 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 __P((XDR *, struct rpc_msg *)); + +/* + * XDR routine to handle a rpc reply. + * xdr_replymsg(xdrs, rmsg) + * XDR *xdrs; + * struct rpc_msg *rmsg; + */ +extern bool_t xdr_replymsg __P((XDR *, struct rpc_msg *)); + +/* + * 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 __P((struct rpc_msg *, struct rpc_err *)); +__END_DECLS + +#endif /* !_RPC_RPCMSG_H */ diff --git a/support/rpc/include/rpc/svc.h b/support/rpc/include/rpc/svc.h new file mode 100644 index 0000000..5c7c900 --- /dev/null +++ b/support/rpc/include/rpc/svc.h @@ -0,0 +1,334 @@ +/* $OpenBSD: svc.h,v 1.2 1997/09/21 10:46:16 niklas Exp $ */ +/* $NetBSD: svc.h,v 1.9 1995/04/29 05:28:01 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)svc.h 1.20 88/02/08 SMI + * @(#)svc.h 2.2 88/07/29 4.0 RPCSRC + */ + +/* + * svc.h, Server-side remote procedure call interface. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_SVC_H +#define _RPC_SVC_H +#include + +/* + * 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 __rpc_svcxprt { + int xp_sock; + u_short xp_port; /* associated port number */ + struct xp_ops { + /* receive incomming requests */ + bool_t (*xp_recv) __P((struct __rpc_svcxprt *, + struct rpc_msg *)); + /* get transport status */ + enum xprt_stat (*xp_stat) __P((struct __rpc_svcxprt *)); + /* get arguments */ + bool_t (*xp_getargs) __P((struct __rpc_svcxprt *, xdrproc_t, + caddr_t)); + /* send reply */ + bool_t (*xp_reply) __P((struct __rpc_svcxprt *, + struct rpc_msg *)); + /* free mem allocated for args */ + bool_t (*xp_freeargs) __P((struct __rpc_svcxprt *, xdrproc_t, + caddr_t)); + /* destroy this struct */ + void (*xp_destroy) __P((struct __rpc_svcxprt *)); + } *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 handle 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_REPLY(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (msg)) +#define svc_reply(xprt, msg) \ + (*(xprt)->xp_ops->xp_reply) ((xprt), (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 { + u_int32_t rq_prog; /* service program number */ + u_int32_t rq_vers; /* service protocol version */ + u_int32_t rq_proc; /* the desired procedure */ + struct opaque_auth rq_cred; /* raw creds from the wire */ + caddr_t rq_clntcred; /* read only cooked cred */ + caddr_t rq_clntname; /* read only client name */ + caddr_t rq_svcname; /* read only cooked service 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; + * u_long prog; + * u_long vers; + * void (*dispatch)(); + * int protocol; like TCP or UDP, zero means do not register + */ +__BEGIN_DECLS +extern bool_t svc_register __P((SVCXPRT *, u_long, u_long, + void (*) __P((struct svc_req *, SVCXPRT *)), int)); +__END_DECLS + +/* + * Service un-registration + * + * svc_unregister(prog, vers) + * u_long prog; + * u_long vers; + */ +__BEGIN_DECLS +extern void svc_unregister __P((u_long, u_long)); +__END_DECLS + +/* + * Transport registration. + * + * xprt_register(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_register __P((SVCXPRT *)); +__END_DECLS + +/* + * Transport un-register + * + * xprt_unregister(xprt) + * SVCXPRT *xprt; + */ +__BEGIN_DECLS +extern void xprt_unregister __P((SVCXPRT *)); +__END_DECLS + + + + +/* + * 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 (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. + * + * 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! + */ + +__BEGIN_DECLS +extern bool_t svc_sendreply __P((SVCXPRT *, xdrproc_t, char *)); +extern void svcerr_decode __P((SVCXPRT *)); +extern void svcerr_weakauth __P((SVCXPRT *)); +extern void svcerr_noproc __P((SVCXPRT *)); +extern void svcerr_progvers __P((SVCXPRT *, u_long, u_long)); +extern void svcerr_auth __P((SVCXPRT *, enum auth_stat)); +extern void svcerr_noprog __P((SVCXPRT *)); +extern void svcerr_systemerr __P((SVCXPRT *)); +__END_DECLS + +/* + * 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 + */ +extern int svc_maxfd; +#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(); /* XXX relic? */ + +__BEGIN_DECLS +extern void svc_getreq __P((int)); +extern void svc_getreqset __P((fd_set *)); +extern void svc_getreqset2 __P((fd_set *, int)); +extern void svc_run __P((void)); +__END_DECLS + +/* + * 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. + */ +__BEGIN_DECLS +extern SVCXPRT *svcraw_create __P((void)); +__END_DECLS + + +/* + * Udp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcudp_create __P((int)); +extern SVCXPRT *svcudp_bufcreate __P((int, u_int, u_int)); +__END_DECLS + + +/* + * Tcp based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svctcp_create __P((int, u_int, u_int)); +__END_DECLS + +/* + * Fd based rpc. + */ +__BEGIN_DECLS +extern SVCXPRT *svcfd_create __P((int, u_int, u_int)); +__END_DECLS + +#endif /* !_RPC_SVC_H */ diff --git a/support/rpc/include/rpc/svc_auth.h b/support/rpc/include/rpc/svc_auth.h new file mode 100644 index 0000000..2a1b0cc --- /dev/null +++ b/support/rpc/include/rpc/svc_auth.h @@ -0,0 +1,81 @@ +/* $OpenBSD: svc_auth.h,v 1.2 1997/09/21 10:46:16 niklas Exp $ */ +/* $NetBSD: svc_auth.h,v 1.4 1994/10/26 00:57:07 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)svc_auth.h 1.6 86/07/16 SMI + * @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC + */ + +/* + * svc_auth.h, Service side of rpc authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_SVCAUTH_H +#define _RPC_SVCAUTH_H + +/* + * Interface to server-side authentication flavors. + */ +typedef struct { + struct svc_auth_ops { + int (*svc_ah_wrap)(); + int (*svc_ah_unwrap)(); + int (*svc_ah_destroy)(); + } *svc_ah_ops; + caddr_t svc_ah_private; +} SVCAUTH; + +#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)) +#define SVCAUTH_DESTROY(auth) \ + ((*((auth)->svc_ah_ops->svc_ah_destroy))(auth)) + +/* + * Approved way of getting principal of caller + */ +char *svcauth_gss_get_principal __P((SVCAUTH *auth)); + +/* + * Approved way of setting server principal + */ +bool_t svcauth_gss_set_svc_name __P((gss_name_t name)); + +/* + * Server side authenticator + */ +__BEGIN_DECLS +extern enum auth_stat _authenticate(); +__END_DECLS + +#endif /* !_RPC_SVCAUTH_H */ diff --git a/support/rpc/include/rpc/types.h b/support/rpc/include/rpc/types.h new file mode 100644 index 0000000..21f17d8 --- /dev/null +++ b/support/rpc/include/rpc/types.h @@ -0,0 +1,66 @@ +/* $OpenBSD: types.h,v 1.2 1997/09/21 10:46:17 niklas Exp $ */ +/* $NetBSD: types.h,v 1.8 1995/04/29 05:28:05 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)types.h 1.18 87/07/24 SMI + * @(#)types.h 2.3 88/08/15 4.0 RPCSRC + */ + +/* + * Rpc additions to + */ +#ifndef _RPC_TYPES_H +#define _RPC_TYPES_H + +#define bool_t int32_t +#define enum_t int32_t +#define __dontcare__ -1 + +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (1) +#endif +#ifndef NULL +# define NULL 0 +#endif + +#define mem_alloc(bsize) malloc(bsize) +#define mem_free(ptr, bsize) free(ptr) + +#ifndef makedev /* ie, we haven't already included it */ +#include +#endif +#include +#include +#include + +#endif /* !_RPC_TYPES_H */ diff --git a/support/rpc/include/rpc/xdr.h b/support/rpc/include/rpc/xdr.h new file mode 100644 index 0000000..d293ea1 --- /dev/null +++ b/support/rpc/include/rpc/xdr.h @@ -0,0 +1,310 @@ +/* $OpenBSD: xdr.h,v 1.2 1997/09/21 10:46:18 niklas Exp $ */ +/* $NetBSD: xdr.h,v 1.7 1995/04/29 05:28:06 cgd Exp $ */ + +/* + * 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 + * + * from: @(#)xdr.h 1.19 87/04/22 SMI + * @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC + */ + +/* + * xdr.h, External Data Representation Serialization Routines. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#ifndef _RPC_XDR_H +#define _RPC_XDR_H +#include +#include + +/* + * 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; + * *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) + +/* + * 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 __rpc_xdr { + enum xdr_op x_op; /* operation; fast additional param */ + struct xdr_ops { + /* get a long from underlying stream */ + bool_t (*x_getlong) __P((struct __rpc_xdr *, long *)); + /* put a long to " */ + bool_t (*x_putlong) __P((struct __rpc_xdr *, long *)); + /* get some bytes from " */ + bool_t (*x_getbytes) __P((struct __rpc_xdr *, caddr_t, u_int)); + /* put some bytes to " */ + bool_t (*x_putbytes) __P((struct __rpc_xdr *, caddr_t, u_int)); + /* returns bytes off from beginning */ + u_int (*x_getpostn) __P((struct __rpc_xdr *)); + /* lets you reposition the stream */ + bool_t (*x_setpostn) __P((struct __rpc_xdr *, u_int)); + /* buf quick ptr to buffered data */ + int32_t *(*x_inline) __P((struct __rpc_xdr *, u_int)); + /* free privates of this xdr_stream */ + void (*x_destroy) __P((struct __rpc_xdr *)); + } *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; + +/* + * 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. + * + * XXX can't actually prototype it, because some take three args!!! + */ +typedef bool_t (*xdrproc_t) __P((/* XDR *, void *, u_int */)); + +/* + * Operations defined on a XDR handle + * + * XDR *xdrs; + * long *longp; + * caddr_t addr; + * u_int len; + * u_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((u_long)*(buf)++)) +#define IXDR_PUT_LONG(buf, v) (*(buf)++ = (long)htonl((u_long)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) ((u_long)IXDR_GET_LONG(buf)) +#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf)) +#define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf)) + +#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) +#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), ((long)(v))) + +/* + * These are the "generic" xdr routines. + */ +__BEGIN_DECLS +extern bool_t xdr_void __P((void)); +extern bool_t xdr_int __P((XDR *, int *)); +extern bool_t xdr_u_int __P((XDR *, u_int *)); +extern bool_t xdr_long __P((XDR *, long *)); +extern bool_t xdr_u_long __P((XDR *, u_long *)); +extern bool_t xdr_short __P((XDR *, short *)); +extern bool_t xdr_u_short __P((XDR *, u_short *)); +extern bool_t xdr_int16_t __P((XDR *, int16_t *)); +extern bool_t xdr_u_int16_t __P((XDR *, u_int16_t *)); +extern bool_t xdr_int32_t __P((XDR *, int32_t *)); +extern bool_t xdr_u_int32_t __P((XDR *, u_int32_t *)); +extern bool_t xdr_bool __P((XDR *, bool_t *)); +extern bool_t xdr_enum __P((XDR *, enum_t *)); +extern bool_t xdr_array __P((XDR *, char **, u_int *, u_int, u_int, xdrproc_t)); +extern bool_t xdr_bytes __P((XDR *, char **, u_int *, u_int)); +extern bool_t xdr_opaque __P((XDR *, caddr_t, u_int)); +extern bool_t xdr_string __P((XDR *, char **, u_int)); +extern bool_t xdr_union __P((XDR *, enum_t *, char *, struct xdr_discrim *, xdrproc_t)); +extern bool_t xdr_char __P((XDR *, char *)); +extern bool_t xdr_u_char __P((XDR *, u_char *)); +extern bool_t xdr_vector __P((XDR *, char *, u_int, u_int, xdrproc_t)); +extern bool_t xdr_float __P((XDR *, float *)); +extern bool_t xdr_double __P((XDR *, double *)); +extern bool_t xdr_reference __P((XDR *, caddr_t *, u_int, xdrproc_t)); +extern bool_t xdr_pointer __P((XDR *, caddr_t *, u_int, xdrproc_t)); +extern bool_t xdr_wrapstring __P((XDR *, char **)); +extern void xdr_free __P((xdrproc_t, char *)); +__END_DECLS + +/* + * Common opaque bytes objects used by many rpc protocols; + * declared here due to commonality. + */ + +#define MAX_NETOBJ_SZ 2048 +struct netobj { + u_int n_len; + char *n_bytes; +}; +typedef struct netobj netobj; +extern bool_t xdr_netobj __P((XDR *, struct netobj *)); + +/* + * These are the public routines for the various implementations of + * xdr streams. + */ +__BEGIN_DECLS +/* XDR using memory buffers */ +extern void xdrmem_create __P((XDR *, char *, u_int, enum xdr_op)); + +#ifdef _STDIO_H_ +/* XDR using stdio library */ +extern void xdrstdio_create __P((XDR *, FILE *, enum xdr_op)); +#endif + +/* XDR pseudo records for tcp */ +extern void xdrrec_create __P((XDR *, u_int, u_int, char *, + int (*) __P((caddr_t, caddr_t, int)), + int (*) __P((caddr_t, caddr_t, int)))); + +/* make end of xdr record */ +extern bool_t xdrrec_endofrecord __P((XDR *, int)); + +/* move to beginning of next record */ +extern bool_t xdrrec_skiprecord __P((XDR *)); + +/* true if no more input */ +extern bool_t xdrrec_eof __P((XDR *)); +__END_DECLS + +#endif /* !_RPC_XDR_H */ diff --git a/support/rpc/rpc_commondata.c b/support/rpc/rpc_commondata.c new file mode 100644 index 0000000..24e7611 --- /dev/null +++ b/support/rpc/rpc_commondata.c @@ -0,0 +1,42 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: rpc_commondata.c,v 1.3 1996/08/19 08:31:47 tholo Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include +/* + * This file should only contain common data (global data) that is exported + * by public interfaces + */ +struct opaque_auth _null_auth; +fd_set svc_fdset; +int svc_maxfd = -1; +struct rpc_createerr rpc_createerr; diff --git a/support/rpc/svc.c b/support/rpc/svc.c new file mode 100644 index 0000000..8e47d67 --- /dev/null +++ b/support/rpc/svc.c @@ -0,0 +1,508 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc.c,v 1.11 1998/02/25 12:21:18 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * 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 +#include + +#include +#include +#include +#include + +static SVCXPRT **xports; +static int xportssize; + +#define NULL_SVC ((struct svc_callout *)0) +#define RQCRED_SIZE 1024 /* this size is excessive */ + +#define max(a, b) (a > b ? a : b) + +#if 0 +#ifdef __linux__ +#define fds_bits __fds_bits /* XXX - Linux sux */ +#endif +#endif + +/* + * 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; + u_long sc_prog; + u_long sc_vers; + void (*sc_dispatch)(); +} *svc_head; + +static struct svc_callout *svc_find(); + +int __svc_fdsetsize; +fd_set *__svc_fdset; + +/* *************** SVCXPRT related stuff **************** */ + +/* + * Activate a transport handle. + */ +void +xprt_register(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + + if (sock+1 > __svc_fdsetsize) { + int bytes = howmany(sock+1, NFDBITS) * sizeof(fd_mask); + fd_set *fds; + + fds = (fd_set *)malloc(bytes); + memset(fds, 0, bytes); + if (__svc_fdset) { + memcpy(fds, __svc_fdset, howmany(__svc_fdsetsize, + NFDBITS) * sizeof(fd_mask)); + free(__svc_fdset); + } + __svc_fdset = fds; + __svc_fdsetsize = sock+1; + } + + if (sock < FD_SETSIZE) + FD_SET(sock, &svc_fdset); + FD_SET(sock, __svc_fdset); + + if (xports == NULL || sock+1 > xportssize) { + SVCXPRT **xp; + int size = FD_SETSIZE; + + if (sock+1 > size) + size = sock+1; + xp = (SVCXPRT **)mem_alloc(size * sizeof(SVCXPRT *)); + memset(xp, 0, size * sizeof(SVCXPRT *)); + if (xports) { + memcpy(xp, xports, xportssize * sizeof(SVCXPRT *)); + free(xports); + } + xportssize = size; + xports = xp; + } + xports[sock] = xprt; + svc_maxfd = max(svc_maxfd, sock); +} + +/* + * De-activate a transport handle. + */ +void +xprt_unregister(xprt) + SVCXPRT *xprt; +{ + register int sock = xprt->xp_sock; + + if (xports[sock] == xprt) { + xports[sock] = (SVCXPRT *)0; + if (sock < FD_SETSIZE) + FD_CLR(sock, &svc_fdset); + FD_CLR(sock, __svc_fdset); + if (sock == svc_maxfd) { + for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--) + if (xports[svc_maxfd]) + break; + } + /* + * XXX could use svc_maxfd as a hint to + * decrease the size of __svc_fdset + */ + } +} + + +/* ********************** 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; + u_long prog; + u_long 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) + u_long prog; + u_long 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, (u_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) + u_long prog; + u_long 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; + u_long low_vers; + u_long 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; +{ + fd_set readfds; + + FD_ZERO(&readfds); + readfds.fds_bits[0] = rdfds; + svc_getreqset(&readfds); +} + +void svc_getreqset2 __P((fd_set *, int)); + +void +svc_getreqset(readfds) + fd_set *readfds; +{ + svc_getreqset2(readfds, FD_SETSIZE); +} + +void +svc_getreqset2(readfds, width) + fd_set *readfds; + int width; +{ + enum xprt_stat stat; + struct rpc_msg msg; + int prog_found; + u_long low_vers; + u_long high_vers; + struct svc_req r; + register SVCXPRT *xprt; + register int bit; + register fd_mask mask, *maskp; + 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]); + + maskp = readfds->fds_bits; + for (sock = 0; sock < width; sock += NFDBITS) { + for (mask = *maskp++; (bit = ffs(mask)); mask ^= (1 << (bit - 1))) { + /* sock has input waiting */ + xprt = xports[sock + bit - 1]; + if (xprt == NULL) + /* But do we control sock? */ + continue; + /* 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; + + no_dispatch = FALSE; + + /* first authenticate the message */ + if ((why = _authenticate(&r, &msg, &no_dispatch)) != 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 = (u_long) -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/support/rpc/svc_auth.c b/support/rpc/svc_auth.c new file mode 100644 index 0000000..4a11be3 --- /dev/null +++ b/support/rpc/svc_auth.c @@ -0,0 +1,113 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_auth.c,v 1.4 1998/03/19 00:27:22 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * svc_auth_nodes.c, Server-side rpc authenticator interface, + * *WITHOUT* DES authentication. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include + +/* + * svcauthsw is the bdevsw of server side authentication. + * + * 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_none(); /* no authentication */ +enum auth_stat _svcauth_unix(); /* unix style (uid, gids) */ +enum auth_stat _svcauth_short(); /* short hand unix style */ +enum auth_stat _svcauth_gss(); /* RPCSEC_GSS */ + +static struct { + enum auth_stat (*authenticator)(); +} svcauthsw[] = { + { _svcauth_none }, /* AUTH_NONE */ + { _svcauth_unix }, /* AUTH_UNIX */ + { _svcauth_short }, /* AUTH_SHORT */ + { _svcauth_none }, /* AUTH_DES - does not exist */ + { _svcauth_none }, + { _svcauth_none }, + { _svcauth_gss } /* RPCSEC_GSS */ +}; +#define AUTH_MAX 6 /* HIGHEST AUTH NUMBER */ + +/* + * 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_clntcred to the "cooked" form of the credentials. + * + * NB: rqst->rq_xprt->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_clntcred, the cooked credentials. + * + * There is an assumption that any flavour less than AUTH_NONE is + * invalid. + */ +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; + + 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; + + if ((cred_flavor <= AUTH_MAX) && (cred_flavor >= AUTH_NONE)) { + return ((*(svcauthsw[cred_flavor].authenticator))(rqst, msg, no_dispatch)); + } + + return (AUTH_REJECTEDCRED); +} diff --git a/support/rpc/svc_auth_gss.c b/support/rpc/svc_auth_gss.c new file mode 100644 index 0000000..02153f9 --- /dev/null +++ b/support/rpc/svc_auth_gss.c @@ -0,0 +1,582 @@ +/* + svc_auth_gss.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +#include +#include +#include +#include +#include + +extern SVCAUTH svc_auth_none; + +/* + * from mit-krb5-1.2.1 mechglue/mglueP.h: + * Array of context IDs typed by mechanism OID + */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + + + +static bool_t svcauth_gss_destroy(); +static bool_t svcauth_gss_wrap(); +static bool_t svcauth_gss_unwrap(); + +struct svc_auth_ops svc_auth_gss_ops = { + svcauth_gss_wrap, + svcauth_gss_unwrap, + svcauth_gss_destroy +}; + +struct svc_rpc_gss_data { + bool_t established; /* context established */ + gss_ctx_id_t ctx; /* context id */ + struct rpc_gss_sec sec; /* security triple */ + gss_buffer_desc cname; /* GSS client name */ + u_int seq; /* sequence number */ + u_int win; /* sequence window */ + u_int seqlast; /* last sequence number */ + u_int32_t seqmask; /* bitmask of seqnums */ + gss_name_t client_name; /* unparsed name string */ +}; + +#define SVCAUTH_PRIVATE(auth) \ + ((struct svc_rpc_gss_data *)(auth)->svc_ah_private) + +/* Global server credentials. */ +gss_cred_id_t _svcauth_gss_creds; +static gss_name_t _svcauth_gss_name = NULL; + +bool_t +svcauth_gss_set_svc_name(gss_name_t name) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_set_svc_name()"); + + if (_svcauth_gss_name != NULL) { + maj_stat = gss_release_name(&min_stat, &_svcauth_gss_name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_release_name", maj_stat, min_stat); + return (FALSE); + } + _svcauth_gss_name = NULL; + } + maj_stat = gss_duplicate_name(&min_stat, name, &_svcauth_gss_name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_duplicate_name", maj_stat, min_stat); + return (FALSE); + } + + return (TRUE); +} + +static bool_t +svcauth_gss_import_name(char *service) +{ + gss_name_t name; + gss_buffer_desc namebuf; + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_import_name()"); + + namebuf.value = service; + namebuf.length = strlen(service); + + maj_stat = gss_import_name(&min_stat, &namebuf, + GSS_C_NT_HOSTBASED_SERVICE, &name); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_import_name", maj_stat, min_stat); + return (FALSE); + } + if (svcauth_gss_set_svc_name(name) != TRUE) { + gss_release_name(&min_stat, &name); + return (FALSE); + } + return (TRUE); +} + +static bool_t +svcauth_gss_acquire_cred(void) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_acquire_cred()"); + + maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name, 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &_svcauth_gss_creds, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_acquire_cred", maj_stat, min_stat); + return (FALSE); + } + return (TRUE); +} + +static bool_t +svcauth_gss_release_cred(void) +{ + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_release_cred()"); + + maj_stat = gss_release_cred(&min_stat, &_svcauth_gss_creds); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_release_cred", maj_stat, min_stat); + return (FALSE); + } + + _svcauth_gss_creds = NULL; + + return (TRUE); +} + +static bool_t +svcauth_gss_accept_sec_context(struct svc_req *rqst, + struct rpc_gss_init_res *gr) +{ + struct svc_rpc_gss_data *gd; + struct rpc_gss_cred *gc; + gss_buffer_desc recv_tok, seqbuf, checksum; + gss_OID mech; + OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq; + + log_debug("in svcauth_gss_accept_context()"); + + gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + gc = (struct rpc_gss_cred *)rqst->rq_clntcred; + memset(gr, 0, sizeof(*gr)); + + /* Deserialize arguments. */ + memset(&recv_tok, 0, sizeof(recv_tok)); + + if (!svc_getargs(rqst->rq_xprt, xdr_rpc_gss_init_args, + (caddr_t)&recv_tok)) + return (FALSE); + + gr->gr_major = gss_accept_sec_context(&gr->gr_minor, + &gd->ctx, + _svcauth_gss_creds, + &recv_tok, + GSS_C_NO_CHANNEL_BINDINGS, + &gd->client_name, + &mech, + &gr->gr_token, + &ret_flags, + NULL, + NULL); + + if (gr->gr_major != GSS_S_COMPLETE && + gr->gr_major != GSS_S_CONTINUE_NEEDED) { + log_status("accept_sec_context", gr->gr_major, gr->gr_minor); + gd->ctx = GSS_C_NO_CONTEXT; + gss_release_buffer(&min_stat, &gr->gr_token); + return (FALSE); + } + /* ANDROS: krb5 mechglue returns ctx of size 8 - two pointers, + * one to the mechanism oid, one to the internal_ctx_id */ + if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) { + fprintf(stderr, "svcauth_gss_accept_context: out of memory\n"); + return (FALSE); + } + memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc)); + gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc); + + /* ANDROS: change for debugging linux kernel version... + gr->gr_win = sizeof(gd->seqmask) * 8; + */ + gr->gr_win = 0x00000005; + + /* Save client info. */ + gd->sec.mech = mech; + gd->sec.qop = GSS_C_QOP_DEFAULT; + gd->sec.svc = gc->gc_svc; + gd->seq = gc->gc_seq; + gd->win = gr->gr_win; + + if (gr->gr_major == GSS_S_COMPLETE) { + maj_stat = gss_display_name(&min_stat, gd->client_name, + &gd->cname, &gd->sec.mech); + if (maj_stat != GSS_S_COMPLETE) { + log_status("display_name", maj_stat, min_stat); + return (FALSE); + } +#ifdef DEBUG +#ifdef HAVE_KRB5 + { + gss_buffer_desc mechname; + + gss_oid_to_str(&min_stat, mech, &mechname); + + log_debug("accepted context for %.*s with " + "", + gd->cname.length, (char *)gd->cname.value, + mechname.length, (char *)mechname.value, + gd->sec.qop, gd->sec.svc); + + gss_release_buffer(&min_stat, &mechname); + } +#elif HAVE_HEIMDAL + log_debug("accepted context for %.*s with " + "", + gd->cname.length, (char *)gd->cname.value, + gd->sec.qop, gd->sec.svc); +#endif +#endif /* DEBUG */ + seq = htonl(gr->gr_win); + seqbuf.value = &seq; + seqbuf.length = sizeof(seq); + + maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, + &seqbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) + return (FALSE); + + rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; + rqst->rq_xprt->xp_verf.oa_base = checksum.value; + rqst->rq_xprt->xp_verf.oa_length = checksum.length; + } + return (TRUE); +} + +static bool_t +svcauth_gss_validate(struct svc_rpc_gss_data *gd, struct rpc_msg *msg) +{ + struct opaque_auth *oa; + gss_buffer_desc rpcbuf, checksum; + OM_uint32 maj_stat, min_stat, qop_state; + u_char rpchdr[128]; + int32_t *buf; + + log_debug("in svcauth_gss_validate()"); + + memset(rpchdr, 0, sizeof(rpchdr)); + + /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */ + buf = (int32_t *)rpchdr; + IXDR_PUT_LONG(buf, msg->rm_xid); + IXDR_PUT_ENUM(buf, msg->rm_direction); + IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); + IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); + IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); + oa = &msg->rm_call.cb_cred; + IXDR_PUT_ENUM(buf, oa->oa_flavor); + IXDR_PUT_LONG(buf, oa->oa_length); + if (oa->oa_length) { + memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); + buf += RNDUP(oa->oa_length) / sizeof(int32_t); + } + rpcbuf.value = rpchdr; + rpcbuf.length = (u_char *)buf - rpchdr; + + checksum.value = msg->rm_call.cb_verf.oa_base; + checksum.length = msg->rm_call.cb_verf.oa_length; + + maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, + &qop_state); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_verify_mic", maj_stat, min_stat); + return (FALSE); + } + return (TRUE); +} + +bool_t +svcauth_gss_nextverf(struct svc_req *rqst, u_int num) +{ + struct svc_rpc_gss_data *gd; + gss_buffer_desc signbuf, checksum; + OM_uint32 maj_stat, min_stat; + + log_debug("in svcauth_gss_nextverf()"); + + if (rqst->rq_xprt->xp_auth == NULL) + return (FALSE); + + gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + + signbuf.value = # + signbuf.length = sizeof(num); + + maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, + &signbuf, &checksum); + + if (maj_stat != GSS_S_COMPLETE) { + log_status("gss_get_mic", maj_stat, min_stat); + return (FALSE); + } + rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; + rqst->rq_xprt->xp_verf.oa_base = (caddr_t)checksum.value; + rqst->rq_xprt->xp_verf.oa_length = (u_int)checksum.length; + + return (TRUE); +} + +enum auth_stat +_svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) +{ + XDR xdrs; + SVCAUTH *auth; + struct svc_rpc_gss_data *gd; + struct rpc_gss_cred *gc; + struct rpc_gss_init_res gr; + int call_stat, offset; + + log_debug("in svcauth_gss()"); + + /* Initialize reply. */ + rqst->rq_xprt->xp_verf = _null_auth; + + /* Allocate and set up server auth handle. */ + if (rqst->rq_xprt->xp_auth == NULL || + rqst->rq_xprt->xp_auth == &svc_auth_none) { + if ((auth = calloc(sizeof(*auth), 1)) == NULL) { + fprintf(stderr, "svcauth_gss: out_of_memory\n"); + return (AUTH_FAILED); + } + if ((gd = calloc(sizeof(*gd), 1)) == NULL) { + fprintf(stderr, "svcauth_gss: out_of_memory\n"); + return (AUTH_FAILED); + } + auth->svc_ah_ops = &svc_auth_gss_ops; + SVCAUTH_PRIVATE(auth) = gd; + rqst->rq_xprt->xp_auth = auth; + } + else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); + + /* Deserialize client credentials. */ + if (rqst->rq_cred.oa_length <= 0) + return (AUTH_BADCRED); + + gc = (struct rpc_gss_cred *)rqst->rq_clntcred; + memset(gc, 0, sizeof(*gc)); + + xdrmem_create(&xdrs, rqst->rq_cred.oa_base, + rqst->rq_cred.oa_length, XDR_DECODE); + + if (!xdr_rpc_gss_cred(&xdrs, gc)) { + XDR_DESTROY(&xdrs); + return (AUTH_BADCRED); + } + XDR_DESTROY(&xdrs); + + /* Check version. */ + if (gc->gc_v != RPCSEC_GSS_VERSION) + return (AUTH_BADCRED); + + /* Check RPCSEC_GSS service. */ + if (gc->gc_svc != RPCSEC_GSS_SVC_NONE && + gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY && + gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY) + return (AUTH_BADCRED); + + /* Check sequence number. */ + if (gd->established) { + if (gc->gc_seq > MAXSEQ) + return (RPCSEC_GSS_CTXPROBLEM); + + if ((offset = gd->seqlast - gc->gc_seq) < 0) { + gd->seqlast = gc->gc_seq; + offset = 0 - offset; + gd->seqmask <<= offset; + offset = 0; + } + else if (offset >= gd->win || (gd->seqmask & (1 << offset))) { + *no_dispatch = 1; + return (RPCSEC_GSS_CTXPROBLEM); + } + gd->seq = gc->gc_seq; + gd->seqmask |= (1 << offset); + } + + if (gd->established) { + rqst->rq_clntname = (char *)gd->client_name; + rqst->rq_svcname = (char *)gd->ctx; + } + + /* Handle RPCSEC_GSS control procedure. */ + switch (gc->gc_proc) { + + case RPCSEC_GSS_INIT: + case RPCSEC_GSS_CONTINUE_INIT: + if (rqst->rq_proc != NULLPROC) + return (AUTH_FAILED); /* XXX ? */ + + if (_svcauth_gss_name == NULL) { + if (!svcauth_gss_import_name("nfs")) + return (AUTH_FAILED); + } + + if (!svcauth_gss_acquire_cred()) + return (AUTH_FAILED); + + if (!svcauth_gss_accept_sec_context(rqst, &gr)) + return (AUTH_REJECTEDCRED); + + if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) + return (AUTH_FAILED); + + *no_dispatch = TRUE; + + call_stat = svc_sendreply(rqst->rq_xprt, xdr_rpc_gss_init_res, + (caddr_t)&gr); + + if (!call_stat) + return (AUTH_FAILED); + + if (gr.gr_major == GSS_S_COMPLETE) + gd->established = TRUE; + + break; + + case RPCSEC_GSS_DATA: + if (!svcauth_gss_validate(gd, msg)) + return (RPCSEC_GSS_CREDPROBLEM); + + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) + return (AUTH_FAILED); + break; + + case RPCSEC_GSS_DESTROY: + if (rqst->rq_proc != NULLPROC) + return (AUTH_FAILED); /* XXX ? */ + + if (!svcauth_gss_validate(gd, msg)) + return (RPCSEC_GSS_CREDPROBLEM); + + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) + return (AUTH_FAILED); + + if (!svcauth_gss_release_cred()) + return (AUTH_FAILED); + + SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth); + rqst->rq_xprt->xp_auth = &svc_auth_none; + + break; + + default: + return (AUTH_REJECTEDCRED); + break; + } + return (AUTH_OK); +} + +bool_t +svcauth_gss_destroy(SVCAUTH *auth) +{ + struct svc_rpc_gss_data *gd; + OM_uint32 min_stat; + + log_debug("in svcauth_gss_destroy()"); + + gd = SVCAUTH_PRIVATE(auth); + + gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER); + gss_release_buffer(&min_stat, &gd->cname); + + if (gd->client_name) + gss_release_name(&min_stat, &gd->client_name); + + mem_free(gd, sizeof(*gd)); + mem_free(auth, sizeof(*auth)); + + return (TRUE); +} + +bool_t +svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_data *gd; + + log_debug("in svcauth_gss_wrap()"); + + gd = SVCAUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->seq)); +} + +bool_t +svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) +{ + struct svc_rpc_gss_data *gd; + + log_debug("in svcauth_gss_unwrap()"); + + gd = SVCAUTH_PRIVATE(auth); + + if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { + return ((*xdr_func)(xdrs, xdr_ptr)); + } + return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, + gd->ctx, gd->sec.qop, + gd->sec.svc, gd->seq)); +} + +char * +svcauth_gss_get_principal(SVCAUTH *auth) +{ + struct svc_rpc_gss_data *gd; + char *pname; + + gd = SVCAUTH_PRIVATE(auth); + + if (gd->cname.length == 0) + return (NULL); + + if ((pname = malloc(gd->cname.length + 1)) == NULL) + return (NULL); + + memcpy(pname, gd->cname.value, gd->cname.length); + pname[gd->cname.length] = '\0'; + + return (pname); +} diff --git a/support/rpc/svc_auth_none.c b/support/rpc/svc_auth_none.c new file mode 100644 index 0000000..f1c6aa7 --- /dev/null +++ b/support/rpc/svc_auth_none.c @@ -0,0 +1,73 @@ +/* + svc_auth_none.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + $Id: svc_auth_none.c,v 1.1 2004/10/19 00:23:05 neilbrown Exp $ + */ + +#include + +static bool_t svcauth_none_destroy(); +static bool_t svcauth_none_wrap(); + +struct svc_auth_ops svc_auth_none_ops = { + svcauth_none_wrap, + svcauth_none_wrap, + svcauth_none_destroy +}; + +SVCAUTH svc_auth_none = { + &svc_auth_none_ops, + NULL, +}; + +static bool_t +svcauth_none_destroy(SVCAUTH *auth) +{ + return (TRUE); +} + +static bool_t +svcauth_none_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, + caddr_t xdr_ptr) +{ + return ((*xdr_func)(xdrs, xdr_ptr)); +} + +enum auth_stat +_svcauth_none(struct svc_req *rqst, struct rpc_msg *msg) +{ + rqst->rq_xprt->xp_auth = &svc_auth_none; + + return (AUTH_OK); +} diff --git a/support/rpc/svc_auth_unix.c b/support/rpc/svc_auth_unix.c new file mode 100644 index 0000000..4ff6b26 --- /dev/null +++ b/support/rpc/svc_auth_unix.c @@ -0,0 +1,140 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_auth_unix.c,v 1.6 1998/11/22 07:38:25 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * 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 +#include +#include + +extern SVCAUTH svc_auth_none; + +/* + * 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 int32_t *buf; + struct area { + struct authunix_parms area_aup; + char area_machname[MAX_MACHINE_NAME+1]; + int area_gids[NGRPS]; + } *area; + u_int auth_len; + u_int str_len, gid_len; + register u_int i; + + rqst->rq_xprt->xp_auth = &svc_auth_none; + + area = (struct area *) rqst->rq_clntcred; + aup = &area->area_aup; + aup->aup_machname = area->area_machname; + aup->aup_gids = area->area_gids; + auth_len = (u_int)msg->rm_call.cb_cred.oa_length; + xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE); + buf = 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; + } + memcpy(aup->aup_machname, (caddr_t)buf, (u_int)str_len); + aup->aup_machname[str_len] = 0; + str_len = RNDUP(str_len); + buf += str_len / sizeof (int32_t); + 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 %u str %u auth %u\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. + */ +enum auth_stat +_svcauth_short(rqst, msg) + struct svc_req *rqst; + struct rpc_msg *msg; +{ + rqst->rq_xprt->xp_auth = &svc_auth_none; + + return (AUTH_REJECTEDCRED); +} diff --git a/support/rpc/svc_raw.c b/support/rpc/svc_raw.c new file mode 100644 index 0000000..f210abd --- /dev/null +++ b/support/rpc/svc_raw.c @@ -0,0 +1,171 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_raw.c,v 1.4 1996/09/15 09:31:39 tholo Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * 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 +#include + + +/* + * 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); +} + +/* ARGSUSED */ +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); +} + +/* ARGSUSED */ +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); +} + +/* ARGSUSED */ +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)); +} + +/* ARGSUSED */ +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/support/rpc/svc_run.c b/support/rpc/svc_run.c new file mode 100644 index 0000000..5f5c046 --- /dev/null +++ b/support/rpc/svc_run.c @@ -0,0 +1,84 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_run.c,v 1.10 1998/03/19 00:27:24 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * This is the rpc server side idle loop + * Wait for input, call server program. + */ +#include +#include +#include +#include +#include +#include +#include + +extern int __svc_fdsetsize; +extern fd_set *__svc_fdset; + +void svc_getreqset2 __P((fd_set *, int)); + +void +svc_run() +{ + fd_set *fds; + + for (;;) { + if (__svc_fdset) { + int bytes = howmany(__svc_fdsetsize, NFDBITS) * + sizeof(fd_mask); + fds = (fd_set *)malloc(bytes); + memcpy(fds, __svc_fdset, bytes); + } else + fds = NULL; + switch (select(svc_maxfd+1, fds, 0, 0, (struct timeval *)0)) { + case -1: + if (errno == EINTR) { + if (fds) + free(fds); + continue; + } + perror("svc_run: - select failed"); + if (fds) + free(fds); + return; + case 0: + if (fds) + free(fds); + continue; + default: + svc_getreqset2(fds, svc_maxfd+1); + free(fds); + } + } +} diff --git a/support/rpc/svc_simple.c b/support/rpc/svc_simple.c new file mode 100644 index 0000000..b697c61 --- /dev/null +++ b/support/rpc/svc_simple.c @@ -0,0 +1,149 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_simple.c,v 1.6 1998/11/22 07:38:25 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * svc_simple.c + * Simplified front end to rpc. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +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; + +int +registerrpc(prognum, versnum, procnum, progname, inproc, outproc) + int prognum, versnum, procnum; + char *(*progname)(); + xdrproc_t inproc, outproc; +{ + + if (procnum == NULLPROC) { + (void) fprintf(stderr, + "can't reassign procedure number %u\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((u_long)prognum, (u_long)versnum); + if (!svc_register(transp, (u_long)prognum, (u_long)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, 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/support/rpc/svc_tcp.c b/support/rpc/svc_tcp.c new file mode 100644 index 0000000..6e6f785 --- /dev/null +++ b/support/rpc/svc_tcp.c @@ -0,0 +1,528 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_tcp.c,v 1.18 1998/05/22 04:23:01 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#ifndef __linux__ +#include +#endif + +/* + * 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 enum xprt_stat rendezvous_stat(); + +static struct xp_ops svctcp_rendezvous_op = { + rendezvous_request, + rendezvous_stat, + (bool_t (*)())abort, + (bool_t (*)())abort, + (bool_t (*)())abort, + svctcp_destroy +}; + +static int readtcp(), writetcp(); +static SVCXPRT *makefd_xprt(); + +struct tcp_rendezvous { /* kept in xprt->xp_p1 */ + u_int sendsize; + u_int recvsize; +}; + +struct tcp_conn { /* kept in xprt->xp_p1 */ + enum xprt_stat strm_stat; + u_long 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; + u_int sendsize; + u_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(&addr, 0, sizeof (addr)); +#ifndef __linux__ + addr.sin_len = sizeof(struct sockaddr_in); +#endif + 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) || + (listen(sock, 2) != 0)) { + perror("svctcp_.c - cannot getsockname or 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"); + if (madesock) + (void)close(sock); + 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"); + if (madesock) + (void)close(sock); + free(r); + return (NULL); + } + xprt->xp_p2 = NULL; + xprt->xp_p1 = (caddr_t)r; + xprt->xp_auth = NULL; + 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; + u_int sendsize; + u_int recvsize; +{ + + return (makefd_xprt(fd, sendsize, recvsize)); +} + +static SVCXPRT * +makefd_xprt(fd, sendsize, recvsize) + int fd; + u_int sendsize; + u_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_auth = NULL; + 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); + } + +#ifdef IP_OPTIONS + { +#ifdef __linux__ +#define ipopt_list ip_opts + struct ip_opts opts; +#else + struct ipoption opts; +#endif + int optsize = sizeof(opts), i; + + if (!getsockopt(sock, IPPROTO_IP, IP_OPTIONS, (char *)&opts, + &optsize) && optsize != 0) { + for (i = 0; (char *)&opts.ipopt_list[i] - (char *)&opts < + optsize; ) { + u_char c = (u_char)opts.ipopt_list[i]; + if (c == IPOPT_LSRR || c == IPOPT_SSRR) { + close(sock); + return (FALSE); + } + if (c == IPOPT_EOL) + break; + i += (c == IPOPT_NOP) ? 1 : + (u_char)opts.ipopt_list[i+1]; + } + } + } +#endif + + /* + * XXX careful for ftp bounce attacks. If discovered, close the + * socket and look for another connection. + */ + if (addr.sin_port == htons(20)) { + close(sock); + 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); + if (xprt->xp_sock != -1) + (void)close(xprt->xp_sock); + xprt->xp_sock = -1; + if (xprt->xp_port != 0) { + /* a rendezvouser socket */ + xprt->xp_port = 0; + } else { + /* an actual connection socket */ + XDR_DESTROY(&(cd->xdrs)); + } + if (xprt->xp_auth != NULL) { + SVCAUTH_DESTROY(xprt->xp_auth); + xprt->xp_auth = NULL; + } + 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; + struct timeval start, delta; + struct timeval tmp1, tmp2; + fd_set *fds = NULL; + int prevbytes = 0, bytes; + extern int __svc_fdsetsize; + extern fd_set *__svc_fdset; + + delta = wait_per_try; + gettimeofday(&start, NULL); + do { + bytes = howmany(__svc_fdsetsize, NFDBITS) * sizeof(fd_mask); + if (bytes != prevbytes) { + if (fds) + free(fds); + fds = (fd_set *)malloc(bytes); + prevbytes = bytes; + } + if (fds == NULL) + goto fatal_err; + memcpy(fds, __svc_fdset, bytes); + + FD_SET(sock, fds); + switch (select(svc_maxfd+1, fds, NULL, NULL, &delta)) { + case -1: + if (errno != EINTR) + goto fatal_err; + gettimeofday(&tmp1, NULL); + timersub(&tmp1, &start, &tmp2); + timersub(&wait_per_try, &tmp2, &tmp1); + if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) + goto fatal_err; + delta = tmp1; + continue; + case 0: + goto fatal_err; + default: + if (!FD_ISSET(sock, fds)) { + svc_getreqset2(fds, svc_maxfd+1); + gettimeofday(&tmp1, NULL); + timersub(&tmp1, &start, &tmp2); + timersub(&wait_per_try, &tmp2, &tmp1); + if (tmp1.tv_sec < 0 || !timerisset(&tmp1)) + goto fatal_err; + delta = tmp1; + continue; + } + } + } while (!FD_ISSET(sock, fds)); + if ((len = read(sock, buf, len)) > 0) { + if (fds) + free(fds); + return (len); + } +fatal_err: + ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED; + if (fds) + free(fds); + 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); + } + cd->strm_stat = XPRT_DIED; /* XXX */ + 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); + xdrproc_t xdr_proc; + caddr_t xdr_where; + + xdrs->x_op = XDR_ENCODE; + msg->rm_xid = cd->x_id; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where)) + return (FALSE); + } + else if (!xdr_replymsg(xdrs, msg)) { + return (FALSE); + } + (void)xdrrec_endofrecord(xdrs, TRUE); + + return (TRUE); +} diff --git a/support/rpc/svc_udp.c b/support/rpc/svc_udp.c new file mode 100644 index 0000000..70a5217 --- /dev/null +++ b/support/rpc/svc_udp.c @@ -0,0 +1,516 @@ +/* + * 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(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: svc_udp.c,v 1.8 1998/03/19 00:27:26 millert Exp $"; +#endif /* LIBC_SCCS and not lint */ + +/* + * 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 +#include +#include +#include +#include +#include +#include + + +#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 __P((SVCXPRT *, u_long)); +static int cache_get __P((SVCXPRT *, struct rpc_msg *, char **, u_long *)); + +static struct xp_ops svcudp_op = { + svcudp_recv, + svcudp_stat, + svcudp_getargs, + svcudp_reply, + svcudp_freeargs, + svcudp_destroy +}; + +/* + * kept in xprt->xp_p2 + */ +struct svcudp_data { + u_int su_iosz; /* byte size of send.recv buffer */ + u_long 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; + u_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(&addr, 0, sizeof (addr)); +#ifndef __linux__ + addr.sin_len = sizeof(struct sockaddr_in); +#endif + 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"); + if (madesock) + (void)close(sock); + return (NULL); + } + su = (struct svcudp_data *)mem_alloc(sizeof(*su)); + if (su == NULL) { + (void)fprintf(stderr, "svcudp_create: out of memory\n"); + if (madesock) + (void)close(sock); + free(xprt); + 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"); + if (madesock) + (void)close(sock); + free(xprt); + free(su); + 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_auth = NULL; + 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)); +} + +/* ARGSUSED */ +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; + u_long 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 == -1 || rlen < 4*sizeof(u_int32_t)) + 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; + xdrproc_t xdr_proc; + caddr_t xdr_where; + + xdrs->x_op = XDR_ENCODE; + XDR_SETPOS(xdrs, 0); + msg->rm_xid = su->su_xid; + + if (msg->rm_reply.rp_stat == MSG_ACCEPTED && + msg->rm_reply.rp_acpt.ar_stat == SUCCESS) { + xdr_proc = msg->acpted_rply.ar_results.proc; + xdr_where = msg->acpted_rply.ar_results.where; + msg->acpted_rply.ar_results.proc = xdr_void; + msg->acpted_rply.ar_results.where = NULL; + + if (!xdr_replymsg(xdrs, msg) || + !SVCAUTH_WRAP(xprt->xp_auth, xdrs, xdr_proc, xdr_where)) + return (FALSE); + } + else if (!xdr_replymsg(xdrs, msg)) { + return (FALSE); + } + slen = (int)XDR_GETPOS(xdrs); + + if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0, + (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen) + != slen) { + return (FALSE); + } + if (su->su_cache && slen >= 0) + cache_set(xprt, (u_long) slen); + + return (TRUE); +} + +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); + if (xprt->xp_sock != -1) + (void)close(xprt->xp_sock); + xprt->xp_sock = -1; + if (xprt->xp_auth != NULL) { + SVCAUTH_DESTROY(xprt->xp_auth); + xprt->xp_auth = NULL; + } + 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 + */ + u_long cache_xid; + u_long cache_proc; + u_long cache_vers; + u_long cache_prog; + struct sockaddr_in cache_addr; + /* + * The cached reply and length + */ + char * cache_reply; + u_long cache_replylen; + /* + * Next node on the list, if there is a collision + */ + cache_ptr cache_next; +}; + + + +/* + * The entire cache + */ +struct udp_cache { + u_long 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 */ + u_long uc_nextvictim; /* points to next victim in fifo list */ + u_long uc_prog; /* saved program number */ + u_long uc_vers; /* saved version number */ + u_long 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. + */ +int +svcudp_enablecache(transp, size) + SVCXPRT *transp; + u_long 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; + u_long 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; + u_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; + u_long *replylenp; +{ + u_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(&a1, &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/utils/Makefile.in b/utils/Makefile.in index 02bafbf..539632f 100644 --- a/utils/Makefile.in +++ b/utils/Makefile.in @@ -3,7 +3,7 @@ # SUBDIRS = exportfs mountd nfsd statd nfsstat @RQUOTAD@ showmount \ - nhfsstone lockd @IDMAPD@ + nhfsstone lockd @IDMAPD@ @GSSD@ @SVCGSSD@ include $(TOP)rules.mk diff --git a/utils/gssd/Makefile b/utils/gssd/Makefile new file mode 100644 index 0000000..6eba0f5 --- /dev/null +++ b/utils/gssd/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for rpc.gssd +# + +PROGRAM = gssd +PREFIX = rpc. +OBJS = gssd.o gssd_main_loop.o gssd_proc.o err_util.o gss_util.o \ + gss_oids.o context.o context_heimdal.o krb5_util.o +LIBDEPS = $(TOP)support/lib/librpc.a $(TOP)support/lib/libgssapi.a +LIBS = -Wl,-rpath=$(KRBDIR)/lib -lrpc -lgssapi -ldl $(KRBLIB) +MAN8 = gssd + +include $(TOP)rules.mk + +CFLAGS += -DKRB5_VERSION=$(KRB5_VERSION) -I$(TOP)support/rpc/include/ \ + -I$(KRBDIR)/include diff --git a/utils/gssd/context.c b/utils/gssd/context.c new file mode 100644 index 0000000..08979f3 --- /dev/null +++ b/utils/gssd/context.c @@ -0,0 +1,467 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" +#include +#include +#include +#ifdef HAVE_KRB5 +#include +#endif +#include +#include +#include "gss_util.h" +#include "gss_oids.h" +#include "err_util.h" +#include "context.h" + +/* spkm3 seems to actually want it this big, yipes. */ +#define MAX_CTX_LEN 4096 + +#ifdef HAVE_KRB5 /* MIT Kerberos */ + +#ifdef HAVE_LUCID_CONTEXT_SUPPORT + +/* Don't use the private structure, use the exported lucid structure */ +#include +#include + +#elif (KRB5_VERSION > 131) +/* XXX argggg, there's gotta be a better way than just duplicating this + * whole struct. Unfortunately, this is in a "private" header file, + * so this is our best choice at this point :-/ + * + * XXX Does this match the Heimdal definition? */ + +typedef struct _krb5_gss_ctx_id_rec { + unsigned int initiate : 1; /* nonzero if initiating, zero if accepting */ + unsigned int established : 1; + unsigned int big_endian : 1; + unsigned int have_acceptor_subkey : 1; + unsigned int seed_init : 1; /* XXX tested but never actually set */ +#ifdef CFX_EXERCISE + unsigned int testing_unknown_tokid : 1; /* for testing only */ +#endif + OM_uint32 gss_flags; + unsigned char seed[16]; + krb5_principal here; + krb5_principal there; + krb5_keyblock *subkey; + int signalg; + size_t cksum_size; + int sealalg; + krb5_keyblock *enc; + krb5_keyblock *seq; + krb5_timestamp endtime; + krb5_flags krb_flags; + /* XXX these used to be signed. the old spec is inspecific, and + the new spec specifies unsigned. I don't believe that the change + affects the wire encoding. */ + uint64_t seq_send; /* gssint_uint64 */ + uint64_t seq_recv; /* gssint_uint64 */ + void *seqstate; + krb5_auth_context auth_context; + gss_buffer_desc *mech_used; /* gss_OID_desc */ + /* Protocol spec revision + 0 => RFC 1964 with 3DES and RC4 enhancements + 1 => draft-ietf-krb-wg-gssapi-cfx-01 + No others defined so far. */ + int proto; + krb5_cksumtype cksumtype; /* for "main" subkey */ + krb5_keyblock *acceptor_subkey; /* CFX only */ + krb5_cksumtype acceptor_subkey_cksumtype; +#ifdef CFX_EXERCISE + gss_buffer_desc init_token; +#endif +} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; + +#else /* KRB5_VERSION */ + +typedef struct _krb5_gss_ctx_id_rec { + int initiate; + u_int32_t gss_flags; + int seed_init; + unsigned char seed[16]; + krb5_principal here; + krb5_principal there; + krb5_keyblock *subkey; + int signalg; + int cksum_size; + int sealalg; + krb5_keyblock *enc; + krb5_keyblock *seq; + krb5_timestamp endtime; + krb5_flags krb_flags; + krb5_ui_4 seq_send; + krb5_ui_4 seq_recv; + void *seqstate; + int established; + int big_endian; + krb5_auth_context auth_context; + gss_buffer_desc *mech_used; + int nctypes; + krb5_cksumtype *ctypes; +} krb5_gss_ctx_id_rec, *krb5_gss_ctx_id_t; + +#endif /* KRB5_VERSION */ +#endif /* HAVE_KRB5 */ + +/* XXX We have the same issue as above. We can require SPKM-3 source + * at the time we compile gssd, or copy the context structure definitions + * here. + */ + +/* structure typedefs */ + +typedef struct spkm3_ctx_id_t { + int length; + unsigned char *data; +} spkm3_ctx_id, + *spkm3_ctx_id_t; + +/* first pass at spkm3 context. will add a bunch of stuff .... */ + +typedef struct spkm3_gss_ctx_id_desc_t { + spkm3_ctx_id ctx_id; /* per spkm token contextid */ + int established; + int qop; /* negotiated qop */ + gss_OID mech_used; + OM_uint32 ret_flags; + OM_uint32 req_flags; + /* DH should be abstracted to an EVP_ struct able to hold + * various kalg results */ + /* XXX The following is defined as "DH *dh" in the original + * header we're gonna cheat and use "void *dh" here. */ + void *dh; + gss_buffer_desc share_key; + /* derived keys are result from applying the owf_alg to the + * shared key - see spkm3_derive_supkey */ + gss_buffer_desc derived_conf_key; + gss_buffer_desc derived_integ_key; + /* openssl NID's of the negotiated algorithms */ + int keyestb_alg; /* key establishment */ + int owf_alg; /* one way function */ + int intg_alg; /* integrity */ + int conf_alg; /* privacy */ + /* der encoded REQ_TOKEN reqcontets and length */ + unsigned char *der_reqcontents; + int der_req_len; +} spkm3_gss_ctx_id_desc; + + +/* adapted from mit kerberos 5 ../lib/gssapi/mechglue/mglueP.h + * this is what gets passed around when the mechglue code is enabled : */ +typedef struct gss_union_ctx_id_t { + gss_OID mech_type; + gss_ctx_id_t internal_ctx_id; +} gss_union_ctx_id_desc, *gss_union_ctx_id_t; + +#ifdef HAVE_KRB5 /* MIT Kerberos */ +#ifdef HAVE_LUCID_CONTEXT_SUPPORT /* Lucid context support */ +static int +write_lucid_keyblock(char **p, char *end, gss_krb5_lucid_key_t *key) +{ + gss_buffer_desc tmp; + + if (WRITE_BYTES(p, end, key->type)) return -1; + tmp.length = key->length; + tmp.value = key->data; + if (write_buffer(p, end, &tmp)) return -1; + return 0; +} + +#else /* lucid context support */ + +static int +write_keyblock(char **p, char *end, struct _krb5_keyblock *arg) +{ + gss_buffer_desc tmp; + + if (WRITE_BYTES(p, end, arg->enctype)) return -1; + tmp.length = arg->length; + tmp.value = arg->contents; + if (write_buffer(p, end, &tmp)) return -1; + return 0; +} +#endif /* lucid context support */ +#endif /* HAVE_KRB5 */ + +#ifdef HAVE_KRB5 +#ifdef HAVE_LUCID_CONTEXT_SUPPORT /* Lucid context support */ +static int +prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx, + gss_buffer_desc *buf) +{ + char *p, *end; + static int constant_zero = 0; + unsigned char fakeseed[16]; + uint32_t word_send_seq; + gss_krb5_lucid_key_t enc_key; + int i; + char *skd, *dkd; + gss_buffer_desc fakeoid; + + /* + * The new Kerberos interface to get the gss context + * does not include the seed or seed_init fields + * because we never really use them. But for now, + * send down a fake buffer so we can use the same + * interface to the kernel. + */ + memset(&enc_key, 0, sizeof(enc_key)); + memset(&fakeoid, 0, sizeof(fakeoid)); + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err; + + /* seed_init and seed not used by kernel anyway */ + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + if (write_bytes(&p, end, &fakeseed, 16)) goto out_err; + + if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.sign_alg)) goto out_err; + if (WRITE_BYTES(&p, end, lctx->rfc1964_kd.seal_alg)) goto out_err; + if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err; + word_send_seq = lctx->send_seq; /* XXX send_seq is 64-bit */ + if (WRITE_BYTES(&p, end, word_send_seq)) goto out_err; + if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err; + + /* derive the encryption key and copy it into buffer */ + enc_key.type = lctx->rfc1964_kd.ctx_key.type; + enc_key.length = lctx->rfc1964_kd.ctx_key.length; + if ((enc_key.data = calloc(1, enc_key.length)) == NULL) + goto out_err; + skd = (char *) lctx->rfc1964_kd.ctx_key.data; + dkd = (char *) enc_key.data; + for (i = 0; i < enc_key.length; i++) + dkd[i] = skd[i] ^ 0xf0; + if (write_lucid_keyblock(&p, end, &enc_key)) { + free(enc_key.data); + goto out_err; + } + free(enc_key.data); + + if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key)) + goto out_err; + + buf->length = p - (char *)buf->value; + return 0; +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; + if (enc_key.data) free(enc_key.data); + return -1; +} + +static int +prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx, + gss_buffer_desc *buf) +{ + printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n"); + return -1; +} + +static int +serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + OM_uint32 maj_stat, min_stat; + void *return_ctx = 0; + OM_uint32 vers; + gss_krb5_lucid_context_v1_t *lctx = 0; + int retcode = 0; + + printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n"); + maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, &ctx, + 1, &return_ctx); + if (maj_stat != GSS_S_COMPLETE) + goto out_err; + + /* Check the version returned, we only support v1 right now */ + vers = ((gss_krb5_lucid_context_version_t *)return_ctx)->version; + switch (vers) { + case 1: + lctx = (gss_krb5_lucid_context_v1_t *) return_ctx; + break; + default: + printerr(0, "ERROR: unsupported lucid sec context version %d\n", + vers); + goto out_err; + break; + } + + /* Now lctx points to a lucid context that we can send down to kernel */ + if (lctx->protocol == 0) + retcode = prepare_krb5_rfc1964_buffer(lctx, buf); + else + retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf); + + maj_stat = gss_krb5_free_lucid_sec_context(&min_stat, + (void *)lctx); + if (maj_stat != GSS_S_COMPLETE) + printerr(0, "WARN: failed to free lucid sec context\n"); + if (retcode) + goto out_err; + + return 0; + +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + return -1; +} + + +#else /* lucid context support */ + +static int +serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + krb5_gss_ctx_id_t kctx = (krb5_gss_ctx_id_t)ctx; + char *p, *end; + static int constant_one = 1; + static int constant_zero = 0; + uint32_t word_seq_send; + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + if (kctx->initiate) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + if (kctx->seed_init) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed))) + goto out_err; + if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err; + if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err; + if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err; + word_seq_send = kctx->seq_send; + if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err; + if (write_buffer(&p, end, kctx->mech_used)) goto out_err; + if (write_keyblock(&p, end, kctx->enc)) goto out_err; + if (write_keyblock(&p, end, kctx->seq)) goto out_err; + + buf->length = p - (char *)buf->value; + return 0; +out_err: + printerr(0, "ERROR: failed serializing krb5 context for kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; + return -1; +} +#endif /* lucid context support */ +#endif /* HAVE_KRB5 */ + + +/* ANDROS: need to determine which fields of the spkm3_gss_ctx_id_desc_t + * are needed in the kernel for get_mic, validate, wrap, unwrap, and destroy + * and only export those fields to the kernel. + */ +static int +serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + spkm3_gss_ctx_id_desc *sctx = (spkm3_gss_ctx_id_desc *)ctx; + char *p, *end; + + printerr(1, "serialize_spkm3_ctx called\n"); + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; +/* buf->length +ctx_id 4 + 12 +qop 4 +mech_used 4 + 7 +ret_fl 4 +req_fl 4 +share 4 + 16 +conf_alg 4 +d_conf_key 4 + 0 +intg_alg 4 +d_intg_key 4 + 0 +kyestb 4 +owl alg 4 +*/ + if (write_buffer(&p, end, (gss_buffer_desc *)&sctx->ctx_id)) + goto out_err; + if (WRITE_BYTES(&p, end, sctx->qop)) goto out_err; + if (write_buffer(&p, end, (gss_buffer_desc *)sctx->mech_used)) goto out_err; + if (WRITE_BYTES(&p, end, sctx->ret_flags)) goto out_err; + if (WRITE_BYTES(&p, end, sctx->req_flags)) goto out_err; + if (write_buffer(&p, end, &sctx->share_key)) + goto out_err; + + if (WRITE_BYTES(&p, end, sctx->conf_alg)) goto out_err; + if (write_buffer(&p, end, &sctx->derived_conf_key)) + goto out_err; + + if (WRITE_BYTES(&p, end, sctx->intg_alg)) goto out_err; + if (write_buffer(&p, end, &sctx->derived_integ_key)) + goto out_err; + + if (WRITE_BYTES(&p, end, sctx->keyestb_alg)) goto out_err; + if (WRITE_BYTES(&p, end, sctx->owf_alg)) goto out_err; + + buf->length = p - (char *)buf->value; + return 0; +out_err: + if (buf->value) free(buf->value); + buf->length = 0; + return -1; +} + +int +serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + gss_union_ctx_id_t uctx = (gss_union_ctx_id_t)ctx; + + if (g_OID_equal(&krb5oid, uctx->mech_type)) + return serialize_krb5_ctx(uctx->internal_ctx_id, buf); + else if (g_OID_equal(&spkm3oid, uctx->mech_type)) + return serialize_spkm3_ctx(uctx->internal_ctx_id, buf); + else { + printerr(0, "ERROR: attempting to serialize context with " + "unknown mechanism oid\n"); + return -1; + } +} diff --git a/utils/gssd/context.h b/utils/gssd/context.h new file mode 100644 index 0000000..d896bd0 --- /dev/null +++ b/utils/gssd/context.h @@ -0,0 +1,38 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CONTEXT_H_ +#define _CONTEXT_H_ + +#include + +int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf); + +#endif /* _CONTEXT_H_ */ diff --git a/utils/gssd/context_heimdal.c b/utils/gssd/context_heimdal.c new file mode 100644 index 0000000..27c44a3 --- /dev/null +++ b/utils/gssd/context_heimdal.c @@ -0,0 +1,256 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "config.h" + +#ifdef HAVE_HEIMDAL + +#include +#include +#include +#include +#include +#include +#include +#include +#include "err_util.h" +#include "gss_oids.h" +#include "write_bytes.h" + +#define MAX_CTX_LEN 4096 + +int write_heimdal_keyblock(char **p, char *end, krb5_keyblock *key) +{ + gss_buffer_desc tmp; + int code = -1; + + if (WRITE_BYTES(p, end, key->keytype)) goto out_err; + tmp.length = key->keyvalue.length; + tmp.value = key->keyvalue.data; + if (write_buffer(p, end, &tmp)) goto out_err; + code = 0; + out_err: + return(code); +} + +int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx) +{ + krb5_keyblock enc_key, *key; + krb5_context context; + krb5_error_code ret; + int i; + char *skd, *dkd; + int code = -1; + + if ((ret = krb5_init_context(&context))) { + printerr(0, "ERROR: initializing krb5_context: %s\n", + error_message(ret)); + goto out_err; + } + + if ((ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, &key))){ + printerr(0, "ERROR: getting auth_context key: %s\n", + error_message(ret)); + goto out_err_free_context; + } + + memset(&enc_key, 0, sizeof(enc_key)); + printerr(1, "WARN: write_heimdal_enc_key: " + "overriding heimdal keytype\n"); + enc_key.keytype = 4 /* XXX XXX XXX XXX key->keytype */; + enc_key.keyvalue.length = key->keyvalue.length; + if ((enc_key.keyvalue.data = + calloc(1, enc_key.keyvalue.length)) == NULL) { + + printerr(0, "ERROR: allocating memory for enc key: %s\n", + error_message(ENOMEM)); + goto out_err_free_key; + } + skd = (char *) key->keyvalue.data; + dkd = (char *) enc_key.keyvalue.data; + for (i = 0; i < enc_key.keyvalue.length; i++) + dkd[i] = skd[i] ^ 0xf0; + if (write_heimdal_keyblock(p, end, &enc_key)) { + goto out_err_free_enckey; + } + + code = 0; + + out_err_free_enckey: + krb5_free_keyblock_contents(context, &enc_key); + out_err_free_key: + krb5_free_keyblock(context, key); + out_err_free_context: + krb5_free_context(context); + out_err: + printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS"); + return(code); +} + +int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx) +{ + krb5_keyblock *key; + krb5_context context; + krb5_error_code ret; + int code = -1; + + if ((ret = krb5_init_context(&context))) { + printerr(0, "ERROR: initializing krb5_context: %s\n", + error_message(ret)); + goto out_err; + } + + if ((ret = krb5_auth_con_getlocalsubkey(context, + ctx->auth_context, &key))){ + printerr(0, "ERROR: getting auth_context key: %s\n", + error_message(ret)); + goto out_err_free_context; + } + + printerr(1, "WARN: write_heimdal_seq_key: " + "overriding heimdal keytype\n"); + key->keytype = 4; /* XXX XXX XXX XXX XXX */ + + if (write_heimdal_keyblock(p, end, key)) { + goto out_err_free_key; + } + + code = 0; + + out_err_free_key: + krb5_free_keyblock(context, key); + out_err_free_context: + krb5_free_context(context); + out_err: + printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS"); + return(code); +} + +/* + * The following is the kernel structure that we are filling in: + * + * struct krb5_ctx { + * int initiate; + * int seed_init; + * unsigned char seed[16]; + * int signalg; + * int sealalg; + * struct crypto_tfm *enc; + * struct crypto_tfm *seq; + * s32 endtime; + * u32 seq_send; + * struct xdr_netobj mech_used; + * }; + * + * However, note that we do not send the data fields in the + * order they appear in the structure. The order they are + * sent down in is: + * + * initiate + * seed_init + * seed + * signalg + * sealalg + * endtime + * seq_send + * mech_used + * enc key + * seq key + * + */ + +int +serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + + char *p, *end; + static int constant_one = 1; + static int constant_zero = 0; + unsigned char fakeseed[16]; + uint32_t algorithm; + + if (!(buf->value = calloc(1, MAX_CTX_LEN))) + goto out_err; + p = buf->value; + end = buf->value + MAX_CTX_LEN; + + + /* initiate: 1 => initiating 0 => accepting */ + if (ctx->more_flags & LOCAL) { + if (WRITE_BYTES(&p, end, constant_one)) goto out_err; + } + else { + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + } + + /* seed_init: not used by kernel code */ + if (WRITE_BYTES(&p, end, constant_zero)) goto out_err; + + /* seed: not used by kernel code */ + memset(&fakeseed, 0, sizeof(fakeseed)); + if (write_bytes(&p, end, &fakeseed, 16)) goto out_err; + + /* signalg */ + algorithm = 0; /* SGN_ALG_DES_MAC_MD5 XXX */ + if (WRITE_BYTES(&p, end, algorithm)) goto out_err; + + /* sealalg */ + algorithm = 0; /* SEAL_ALG_DES XXX */ + if (WRITE_BYTES(&p, end, algorithm)) goto out_err; + + /* endtime */ + if (WRITE_BYTES(&p, end, ctx->lifetime)) goto out_err; + + /* seq_send */ + if (WRITE_BYTES(&p, end, ctx->auth_context->local_seqnumber)) + goto out_err; + /* mech_used */ + if (write_buffer(&p, end, (gss_buffer_desc*)&krb5oid)) goto out_err; + + /* enc: derive the encryption key and copy it into buffer */ + if (write_heimdal_enc_key(&p, end, ctx)) goto out_err; + + /* seq: get the sequence number key and copy it into buffer */ + if (write_heimdal_seq_key(&p, end, ctx)) goto out_err; + + buf->length = p - (char *)buf->value; + printerr(2, "serialize_krb5_ctx: returning buffer " + "with %d bytes\n", buf->length); + + return 0; +out_err: + printerr(0, "ERROR: failed exporting Heimdal krb5 ctx to kernel\n"); + if (buf->value) free(buf->value); + buf->length = 0; + return -1; +} + +#endif /* HAVE_HEIMDAL */ diff --git a/utils/gssd/err_util.c b/utils/gssd/err_util.c new file mode 100644 index 0000000..ca9b028 --- /dev/null +++ b/utils/gssd/err_util.c @@ -0,0 +1,92 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include "err_util.h" + +static int verbosity = 0; +static int fg = 0; + +static char message_buf[500]; +static char tmp_buf[500]; + +void initerr(char *progname, int set_verbosity, int set_fg) +{ + verbosity = set_verbosity; + fg = set_fg; + if (!fg) + openlog(progname, LOG_PID, LOG_DAEMON); +} + +void printerr(int priority, char *format, ...) +{ + va_list args; + int ret; + + /* aggregate lines: only print buffer when we get to the end of a + * line or run out of space: */ + va_start(args, format); + ret = vsnprintf(tmp_buf, sizeof(tmp_buf), format, args); + va_end(args); + if ((ret < 0) || (ret >= sizeof(tmp_buf))) + goto output; + if (strlen(tmp_buf) + strlen(message_buf) + 1 > sizeof(message_buf)) + goto output; + strcat(message_buf, tmp_buf); + if (tmp_buf[strlen(tmp_buf) - 1] == '\n') + goto output; + return; +output: + priority -= verbosity; + if (priority < 0) + priority = 0; + if (fg) { + if (priority == 0) + fprintf(stderr, "%s", message_buf); + } else { + int sys_pri; + switch (priority) { + case 0: + sys_pri = LOG_ERR; + break; + case 1: + sys_pri = LOG_DEBUG; + break; + default: + goto out; + } + syslog(sys_pri, "%s", message_buf); + } +out: + memset(message_buf, 0, sizeof(message_buf)); +} diff --git a/utils/gssd/err_util.h b/utils/gssd/err_util.h new file mode 100644 index 0000000..5e5af48 --- /dev/null +++ b/utils/gssd/err_util.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _ERR_UTIL_H_ +#define _ERR_UTIL_H_ + +void initerr(char *progname, int verbosity, int fg); +void printerr(int priority, char *format, ...); + +#endif /* _ERR_UTIL_H_ */ diff --git a/utils/gssd/gss_clnt_send_err.c b/utils/gssd/gss_clnt_send_err.c new file mode 100644 index 0000000..5260b53 --- /dev/null +++ b/utils/gssd/gss_clnt_send_err.c @@ -0,0 +1,104 @@ +/* + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2004 Bruce Fields + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "gssd.h" +#include "write_bytes.h" + +char pipefsdir[PATH_MAX] = GSSD_PIPEFS_DIR; + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s clntdir user [user ...]\n", progname); + exit(1); +} + +static int +do_error_downcall(int k5_fd, uid_t uid, int err) +{ + char buf[1024]; + char *p = buf, *end = buf + 1024; + unsigned int timeout = 0; + int zero = 0; + + if (WRITE_BYTES(&p, end, uid)) return -1; + if (WRITE_BYTES(&p, end, timeout)) return -1; + /* use seq_win = 0 to indicate an error: */ + if (WRITE_BYTES(&p, end, zero)) return -1; + if (WRITE_BYTES(&p, end, err)) return -1; + + if (write(k5_fd, buf, p - buf) < p - buf) return -1; + return 0; +} + +int +main(int argc, char *argv[]) +{ + int fd; + int i; + uid_t uid; + char *endptr; + struct passwd *pw; + + if (argc < 3) + usage(argv[0]); + fd = open(argv[1], O_WRONLY); + if (fd == -1) + err(1, "unable to open %s", argv[1]); + + for (i = 2; i < argc; i++) { + uid = strtol(argv[i], &endptr, 10); + if (*endptr != '\0') { + pw = getpwnam(argv[i]); + if (!pw) + err(1, "unknown user %s", argv[i]); + uid = pw->pw_uid; + } + if (do_error_downcall(fd, uid, -1)) + err(1, "failed to destroy cred for user %s", argv[i]); + } + exit(0); +} diff --git a/utils/gssd/gss_destroy_creds b/utils/gssd/gss_destroy_creds new file mode 100644 index 0000000..666bdd9 --- /dev/null +++ b/utils/gssd/gss_destroy_creds @@ -0,0 +1,11 @@ +#!/bin/bash + +path=`mount|grep rpc_pipefs|head -1|awk '{ print $3 }'` + +if [ -z "$path" ]; then + echo "unable to find rpc_pipefs; is it mounted?" + exit 1 +fi; + +find "$path" -name 'krb5' -exec gss_clnt_send_err '{}' $* ';' + diff --git a/utils/gssd/gss_oids.c b/utils/gssd/gss_oids.c new file mode 100644 index 0000000..e800115 --- /dev/null +++ b/utils/gssd/gss_oids.c @@ -0,0 +1,39 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include + +/* from kerberos source, gssapi_krb5.c */ +gss_OID_desc krb5oid = + {9, "\052\206\110\206\367\022\001\002\002"}; + +gss_OID_desc spkm3oid = + {7, "\052\006\001\005\005\001\003"}; diff --git a/utils/gssd/gss_oids.h b/utils/gssd/gss_oids.h new file mode 100644 index 0000000..850c013 --- /dev/null +++ b/utils/gssd/gss_oids.h @@ -0,0 +1,46 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _GSS_OIDS_H_ +#define _GSS_OIDS_H_ + +#include +#include + +extern gss_OID_desc krb5oid; +extern gss_OID_desc spkm3oid; + +#ifndef g_OID_equal +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(unsigned int) (o1)->length) == 0)) +#endif + +#endif /* _GSS_OIDS_H_ */ diff --git a/utils/gssd/gss_util.c b/utils/gssd/gss_util.c new file mode 100644 index 0000000..3493280 --- /dev/null +++ b/utils/gssd/gss_util.c @@ -0,0 +1,212 @@ +/* + * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from + * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view + * + * Copyright (c) 2002 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson + * J. Bruce Fields + * Marius Aamodt Eriksen + */ + +/* + * slave/kprop.c + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Copyright 1994 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 "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gss_util.h" +#include "err_util.h" +#include "gssd.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_COM_ERR_H +#include +#endif + +/* Global gssd_credentials handle */ +gss_cred_id_t gssd_creds; + +gss_OID g_mechOid = GSS_C_NULL_OID;; + +#if 0 +static void +display_status_1(char *m, u_int32_t code, int type, const gss_OID mech) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; + u_int32_t msg_ctx = 0; + char *typestr; + + switch (type) { + case GSS_C_GSS_CODE: + typestr = "GSS"; + break; + case GSS_C_MECH_CODE: + typestr = "mechanism"; + break; + default: + return; + /* NOTREACHED */ + } + + for (;;) { + maj_stat = gss_display_status(&min_stat, code, + type, mech, &msg_ctx, &msg); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "ERROR: in call to " + "gss_display_status called from %s\n", m); + break; + } else { + printerr(0, "ERROR: GSS-API: (%s) error in %s(): %s\n", + typestr, m, (char *)msg.value); + } + + if (msg.length != 0) + (void) gss_release_buffer(&min_stat, &msg); + + if (msg_ctx == 0) + break; + } +} +#endif + +static void +display_status_2(char *m, u_int32_t major, u_int32_t minor, const gss_OID mech) +{ + u_int32_t maj_stat1, min_stat1; + u_int32_t maj_stat2, min_stat2; + gss_buffer_desc maj_gss_buf = GSS_C_EMPTY_BUFFER; + gss_buffer_desc min_gss_buf = GSS_C_EMPTY_BUFFER; + char maj_buf[30], min_buf[30]; + char *maj, *min; + u_int32_t msg_ctx = 0; + + /* Get major status message */ + maj_stat1 = gss_display_status(&min_stat1, major, + GSS_C_GSS_CODE, mech, &msg_ctx, &maj_gss_buf); + + if (maj_stat1 != GSS_S_COMPLETE) { + snprintf(maj_buf, sizeof(maj_buf), "(0x%08x)", major); + maj = &maj_buf[0]; + } else { + maj = maj_gss_buf.value; + } + + /* Get minor status message */ + maj_stat2 = gss_display_status(&min_stat2, minor, + GSS_C_MECH_CODE, mech, &msg_ctx, &min_gss_buf); + + if (maj_stat2 != GSS_S_COMPLETE) { + snprintf(min_buf, sizeof(min_buf), "(0x%08x)", minor); + min = &min_buf[0]; + } else { + min = min_gss_buf.value; + } + + printerr(0, "ERROR: GSS-API: error in %s(): %s - %s\n", + m, maj, min); + + if (maj_gss_buf.length != 0) + (void) gss_release_buffer(&min_stat1, &maj_gss_buf); + if (min_gss_buf.length != 0) + (void) gss_release_buffer(&min_stat2, &min_gss_buf); +} + +void +pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, const gss_OID mech) +{ + display_status_2(msg, maj_stat, min_stat, mech); +} + +int +gssd_acquire_cred(char *server_name) +{ + gss_buffer_desc name; + gss_name_t target_name; + u_int32_t maj_stat, min_stat; + u_int32_t ignore_maj_stat, ignore_min_stat; + + name.value = (void *)server_name; + name.length = strlen(server_name); + + maj_stat = gss_import_name(&min_stat, &name, + (const gss_OID) GSS_C_NT_HOSTBASED_SERVICE, + &target_name); + + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("gss_import_name", maj_stat, min_stat, g_mechOid); + return (FALSE); + } + + maj_stat = gss_acquire_cred(&min_stat, target_name, 0, + GSS_C_NULL_OID_SET, GSS_C_ACCEPT, + &gssd_creds, NULL, NULL); + + ignore_maj_stat = gss_release_name(&ignore_min_stat, &target_name); + + if (maj_stat != GSS_S_COMPLETE) + pgsserr("gss_acquire_cred", maj_stat, min_stat, g_mechOid); + + return (maj_stat == GSS_S_COMPLETE); +} diff --git a/utils/gssd/gss_util.h b/utils/gssd/gss_util.h new file mode 100644 index 0000000..9e480ac --- /dev/null +++ b/utils/gssd/gss_util.h @@ -0,0 +1,44 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _GSS_UTIL_H_ +#define _GSS_UTIL_H_ + +#include +#include +#include "write_bytes.h" + +extern gss_cred_id_t gssd_creds; + +int gssd_acquire_cred(char *server_name); +void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat, + const gss_OID mech); + +#endif /* _GSS_UTIL_H_ */ diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c new file mode 100644 index 0000000..0f7a7e5 --- /dev/null +++ b/utils/gssd/gssd.c @@ -0,0 +1,134 @@ +/* + gssd.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2002 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "krb5_util.h" + +char pipefsdir[PATH_MAX] = GSSD_PIPEFS_DIR; +char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE; + +void +sig_die(int signal) +{ + /* destroy krb5 machine creds */ + gssd_destroy_krb5_machine_creds(); + printerr(1, "exiting on signal %d\n", signal); + exit(1); +} + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-f] [-v] [-p pipefsdir] [-k keytab]\n", + progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int fg = 0; + int verbosity = 0; + int opt; + extern char *optarg; + char *progname; + + while ((opt = getopt(argc, argv, "fvmp:k:")) != -1) { + switch (opt) { + case 'f': + fg = 1; + break; + case 'm': + /* Accept but ignore this. Now the default. */ + break; + case 'v': + verbosity++; + break; + case 'p': + strncpy(pipefsdir, optarg, sizeof(pipefsdir)); + if (pipefsdir[sizeof(pipefsdir)-1] != '\0') + errx(1, "pipefs path name too long"); + break; + case 'k': + strncpy(keytabfile, optarg, sizeof(keytabfile)); + if (keytabfile[sizeof(keytabfile)-1] != '\0') + errx(1, "keytab path name too long"); + break; + default: + usage(argv[0]); + break; + } + } + strncat(pipefsdir + strlen(pipefsdir), "/" GSSD_SERVICE_NAME, + sizeof(pipefsdir)-strlen(pipefsdir)); + if (pipefsdir[sizeof(pipefsdir)-1] != '\0') + errx(1, "pipefs path name too long"); + + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + + initerr(progname, verbosity, fg); + + if (!fg && daemon(0, 0) < 0) + errx(1, "fork"); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + signal(SIGHUP, sig_die); + + /* Process keytab file and get machine credentials */ + gssd_refresh_krb5_machine_creds(); + + gssd_run(); + printerr(0, "gssd_run returned!\n"); + abort(); +} diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h new file mode 100644 index 0000000..d590401 --- /dev/null +++ b/utils/gssd/gssd.h @@ -0,0 +1,89 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _RPC_GSSD_H_ +#define _RPC_GSSD_H_ + +#include +#include +#include + +#define MAX_FILE_NAMELEN 32 +#define FD_ALLOC_BLOCK 32 +#ifndef GSSD_PIPEFS_DIR +#define GSSD_PIPEFS_DIR "/var/lib/nfs/rpc_pipefs" +#endif +#define INFO "info" +#define KRB5 "krb5" +#define DNOTIFY_SIGNAL (SIGRTMIN + 3) + +#define GSSD_DEFAULT_CRED_DIR "/tmp" +#define GSSD_DEFAULT_CRED_PREFIX "krb5cc_" +#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine" +#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab" +#define GSSD_SERVICE_NAME "nfs" +#define GSSD_SERVICE_NAME_LEN 3 + +/* + * The gss mechanisms that we can handle + */ +enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY}; + + + +extern char pipefsdir[PATH_MAX]; +extern char keytabfile[PATH_MAX]; + +TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; + +struct clnt_info { + TAILQ_ENTRY(clnt_info) list; + char *dirname; + int dir_fd; + char *servicename; + char *servername; + int prog; + int vers; + char *protocol; + int krb5_fd; + int krb5_poll_index; + int spkm3_fd; + int spkm3_poll_index; +}; + +void init_client_list(void); +int update_client_list(void); +void handle_krb5_upcall(struct clnt_info *clp); +void handle_spkm3_upcall(struct clnt_info *clp); +int gssd_acquire_cred(char *server_name); +void gssd_run(void); + + +#endif /* _RPC_GSSD_H_ */ diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man new file mode 100644 index 0000000..d8f9a0f --- /dev/null +++ b/utils/gssd/gssd.man @@ -0,0 +1,63 @@ +.\" +.\" rpc.gssd(8) +.\" +.\" Copyright (C) 2003 J. Bruce Fields +.TH rpc.gssd 8 "17 Mar 2003" +.SH NAME +rpc.gssd \- rpcsec_gss daemon +.SH SYNOPSIS +.B "rpc.gssd [-f] [-k keytab] [-p pipefsdir] [-v]" +.SH DESCRIPTION +The rpcsec_gss protocol gives a means of using the gss-api generic security +api to provide security for protocols using rpc (in particular, nfs). Before +exchanging any rpc requests using rpcsec_gss, the rpc client must first +establish a security context. The linux kernel's implementation of rpcsec_gss +depends on the userspace daemon +.B rpc.gssd +to establish security contexts. The +.B rpc.gssd +daemon uses files in the rpc_pipefs filesystem to communicate with the kernel. + +.SH OPTIONS +.TP +.B -f +Runs +.B rpc.gssd +in the foreground and sends output to stderr (as opposed to syslogd) +.TP +.B -k keytab +Tells +.B rpc.gssd +to use the keys for principals nfs/hostname in +.I keytab +to obtain machine credentials. +The default value is "/etc/krb5.keytab". +.\".TP +.\".B -m +.\"Ordinarily, +.\".B rpc.gssd +.\"looks for a cached ticket for user $UID in /tmp/krb5cc_$UID. +.\"With the -m option, the user with uid 0 will be treated specially, and will +.\"be mapped instead to the credentials for the principal nfs/hostname found in +.\"the keytab file. +.\"(This option is now the default and is ignored if specified.) +.TP +.B -p path +Tells +.B rpc.gssd +where to look for the rpc_pipefs filesystem. The default value is +"/var/lib/nfs/rpc_pipefs". +.TP +.B -v +Increases the verbosity of the output (can be specified multiple times). +.SH SEE ALSO +.BR rpc.svcgssd(8) +.SH AUTHORS +.br +Dug Song +.br +Andy Adamson +.br +Marius Aamodt Eriksen +.br +J. Bruce Fields diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c new file mode 100644 index 0000000..a086bb3 --- /dev/null +++ b/utils/gssd/gssd_main_loop.c @@ -0,0 +1,144 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gssd.h" +#include "err_util.h" + +extern struct pollfd *pollarray; +extern int pollsize; + +#define POLL_MILLISECS 500 + +static volatile int dir_changed = 1; + +static void dir_notify_handler(int sig, siginfo_t *si, void *data) +{ + dir_changed = 1; +} + +static void +scan_poll_results(int ret) +{ + int i; + struct clnt_info *clp; + + for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) + { + i = clp->krb5_poll_index; + if (i >= 0 && pollarray[i].revents) { + if (pollarray[i].revents & POLLHUP) + dir_changed = 1; + if (pollarray[i].revents & POLLIN) + handle_krb5_upcall(clp); + pollarray[clp->krb5_poll_index].revents = 0; + ret--; + if (!ret) + break; + } + i = clp->spkm3_poll_index; + if (i >= 0 && pollarray[i].revents) { + if (pollarray[i].revents & POLLHUP) + dir_changed = 1; + if (pollarray[i].revents & POLLIN) + handle_spkm3_upcall(clp); + pollarray[clp->spkm3_poll_index].revents = 0; + ret--; + if (!ret) + break; + } + } +}; + +void +gssd_run() +{ + int ret; + struct sigaction dn_act; + int fd; + + /* Taken from linux/Documentation/dnotify.txt: */ + dn_act.sa_sigaction = dir_notify_handler; + sigemptyset(&dn_act.sa_mask); + dn_act.sa_flags = SA_SIGINFO; + sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); + + if ((fd = open(pipefsdir, O_RDONLY)) == -1) { + printerr(0, "ERROR: failed to open %s: %s\n", + pipefsdir, strerror(errno)); + exit(1); + } + fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); + fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); + + init_client_list(); + + while (1) { + while (dir_changed) { + dir_changed = 0; + if (update_client_list()) { + printerr(0, "ERROR: couldn't update " + "client list\n"); + exit(1); + } + } + /* race condition here: dir_changed could be set before we + * enter the poll, and we'd never notice if it weren't for the + * timeout. */ + ret = poll(pollarray, pollsize, POLL_MILLISECS); + if (ret < 0) { + if (errno != EINTR) + printerr(0, + "WARNING: error return from poll\n"); + } else if (ret == 0) { + /* timeout */ + } else { /* ret > 0 */ + scan_poll_results(ret); + } + } + close(fd); + return; +} diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c new file mode 100644 index 0000000..1e7ebae --- /dev/null +++ b/utils/gssd/gssd_proc.c @@ -0,0 +1,661 @@ +/* + gssd_proc.c + + Copyright (c) 2000-2004 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2001 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + Copyright (c) 2002 Bruce Fields + Copyright (c) 2004 Kevin Coffman + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "config.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "gss_oids.h" +#include "krb5_util.h" +#include "context.h" + +/* + * pollarray: + * array of struct pollfd suitable to pass to poll. initialized to + * zero - a zero struct is ignored by poll() because the events mask is 0. + * + * clnt_list: + * linked list of struct clnt_info which associates a clntXXX directory + * with an index into pollarray[], and other basic data about that client. + * + * Directory structure: created by the kernel nfs client + * /pipefsdir/clntXX : one per rpc_clnt struct in the kernel + * /pipefsdir/clntXX/krb5 : read uid for which kernel wants + * a context, write the resulting context + * /pipefsdir/clntXX/info : stores info such as server name + * + * Algorithm: + * Poll all /pipefsdir/clntXX/krb5 files. When ready, data read + * is a uid; performs rpcsec_gss context initialization protocol to + * get a cred for that user. Writes result to corresponding krb5 file + * in a form the kernel code will understand. + * In addition, we make sure we are notified whenever anything is + * created or destroyed in pipefsdir/ or in an of the clntXX directories, + * and rescan the whole pipefsdir when this happens. + */ + +struct pollfd * pollarray; + +int pollsize; /* the size of pollaray (in pollfd's) */ + +/* XXX buffer problems: */ +static int +read_service_info(char *info_file_name, char **servicename, char **servername, + int *prog, int *vers, char **protocol) { +#define INFOBUFLEN 256 + char buf[INFOBUFLEN]; + static char dummy[128]; + int nbytes; + static char service[128]; + static char address[128]; + char program[16]; + char version[16]; + char protoname[16]; + in_addr_t inaddr; + int fd = -1; + struct hostent *ent = NULL; + int numfields; + + *servicename = *servername = *protocol = NULL; + + if ((fd = open(info_file_name, O_RDONLY)) == -1) { + printerr(0, "ERROR: can't open %s: %s\n", info_file_name, + strerror(errno)); + goto fail; + } + if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) + goto fail; + close(fd); + + numfields = sscanf(buf,"RPC server: %s\n" + "service: %s %s version %s\n" + "address: %s\n" + "protocol: %s\n", + dummy, + service, program, version, + address, + protoname); + + if (numfields == 5) { + strcpy(protoname, "tcp"); + } else if (numfields != 6) { + goto fail; + } + + /* check service, program, and version */ + if(memcmp(service, "nfs", 3)) return -1; + *prog = atoi(program + 1); /* skip open paren */ + *vers = atoi(version); + if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4))) + goto fail; + + /* create service name */ + inaddr = inet_addr(address); + if (!(ent = gethostbyaddr(&inaddr, sizeof(inaddr), AF_INET))) { + printerr(0, "ERROR: can't resolve server %s name\n", address); + goto fail; + } + if (!(*servername = calloc(strlen(ent->h_name) + 1, 1))) + goto fail; + memcpy(*servername, ent->h_name, strlen(ent->h_name)); + snprintf(buf, INFOBUFLEN, "%s@%s", service, ent->h_name); + if (!(*servicename = calloc(strlen(buf) + 1, 1))) + goto fail; + memcpy(*servicename, buf, strlen(buf)); + + if (!(*protocol = strdup(protoname))) + goto fail; + return 0; +fail: + printerr(0, "ERROR: failed to read service info\n"); + if (fd != -1) close(fd); + if (*servername) free(*servername); + if (*servicename) free(*servicename); + if (*protocol) free(*protocol); + return -1; +} + +static void +destroy_client(struct clnt_info *clp) +{ + if (clp->dir_fd != -1) close(clp->dir_fd); + if (clp->krb5_fd != -1) close(clp->krb5_fd); + if (clp->spkm3_fd != -1) close(clp->spkm3_fd); + if (clp->dirname) free(clp->dirname); + if (clp->servicename) free(clp->servicename); + if (clp->servername) free(clp->servername); + if (clp->protocol) free(clp->protocol); + free(clp); +} + +static struct clnt_info * +insert_new_clnt(void) +{ + struct clnt_info *clp = NULL; + + if (!(clp = (struct clnt_info *)calloc(1,sizeof(struct clnt_info)))) { + printerr(0, "ERROR: can't malloc clnt_info: %s\n", + strerror(errno)); + goto out; + } + clp->krb5_poll_index = -1; + clp->spkm3_poll_index = -1; + clp->krb5_fd = -1; + clp->spkm3_fd = -1; + clp->dir_fd = -1; + + TAILQ_INSERT_HEAD(&clnt_list, clp, list); +out: + return clp; +} + +static int +process_clnt_dir_files(struct clnt_info * clp) +{ + char kname[32]; + char sname[32]; + char info_file_name[32]; + + snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname); + clp->krb5_fd = open(kname, O_RDWR); + snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname); + clp->spkm3_fd = open(sname, O_RDWR); + if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1)) + return -1; + snprintf(info_file_name, sizeof(info_file_name), "%s/info", + clp->dirname); + if (read_service_info(info_file_name, &clp->servicename, + &clp->servername, &clp->prog, &clp->vers, + &clp->protocol)) + return -1; + return 0; +} + +static int +get_poll_index(int *ind) +{ + int i; + + *ind = -1; + for (i=0; idirname = calloc(strlen(dir) + 1, 1))) { + goto fail_destroy_client; + } + memcpy(clp->dirname, dir, strlen(dir)); + if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) { + printerr(0, "ERROR: can't open %s: %s\n", + clp->dirname, strerror(errno)); + goto fail_destroy_client; + } + fcntl(clp->dir_fd, F_SETSIG, DNOTIFY_SIGNAL); + fcntl(clp->dir_fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MULTISHOT); + + if (process_clnt_dir_files(clp)) + goto fail_keep_client; + + if(clp->krb5_fd != -1) { + if (get_poll_index(&clp->krb5_poll_index)) { + printerr(0, "ERROR: Too many krb5 clients\n"); + goto fail_destroy_client; + } + pollarray[clp->krb5_poll_index].fd = clp->krb5_fd; + pollarray[clp->krb5_poll_index].events |= POLLIN; + } + + if(clp->spkm3_fd != -1) { + if (get_poll_index(&clp->spkm3_poll_index)) { + printerr(0, "ERROR: Too many spkm3 clients\n"); + goto fail_destroy_client; + } + pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd; + pollarray[clp->spkm3_poll_index].events |= POLLIN; + } + + return; + +fail_destroy_client: + if (clp) { + TAILQ_REMOVE(&clnt_list, clp, list); + destroy_client(clp); + } +fail_keep_client: + /* We couldn't find some subdirectories, but we keep the client + * around in case we get a notification on the directory when the + * subdirectories are created. */ + return; +} + +void +init_client_list(void) +{ + TAILQ_INIT(&clnt_list); + /* Eventually plan to grow/shrink poll array: */ + pollsize = FD_ALLOC_BLOCK; + pollarray = calloc(pollsize, sizeof(struct pollfd)); +} + +static void +destroy_client_list(void) +{ + struct clnt_info *clp; + + printerr(1, "processing client list\n"); + + while (clnt_list.tqh_first != NULL) { + clp = clnt_list.tqh_first; + TAILQ_REMOVE(&clnt_list, clp, list); + destroy_client(clp); + } +} + +/* Used to read (and re-read) list of clients, set up poll array. */ +int +update_client_list(void) +{ + struct dirent **namelist; + int i,j; + + destroy_client_list(); + + if (chdir(pipefsdir) < 0) { + printerr(0, "ERROR: can't chdir to %s: %s\n", + pipefsdir, strerror(errno)); + return -1; + } + + memset(pollarray, 0, pollsize * sizeof(struct pollfd)); + + j = scandir(pipefsdir, &namelist, NULL, alphasort); + if (j < 0) { + printerr(0, "ERROR: can't scandir %s: %s\n", + pipefsdir, strerror(errno)); + return -1; + } + for (i=0; i < j; i++) { + if (i < FD_ALLOC_BLOCK + && !strncmp(namelist[i]->d_name, "clnt", 4)) + process_clnt_dir(namelist[i]->d_name); + free(namelist[i]); + } + + free(namelist); + return 0; +} + +static int +do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, + gss_buffer_desc *context_token) +{ + char buf[2048]; + char *p = buf, *end = buf + 2048; + unsigned int timeout = 0; /* XXX decide on a reasonable value */ + + printerr(1, "doing downcall\n"); + + if (WRITE_BYTES(&p, end, uid)) return -1; + /* Not setting any timeout for now: */ + if (WRITE_BYTES(&p, end, timeout)) return -1; + if (WRITE_BYTES(&p, end, pd->pd_seq_win)) return -1; + if (write_buffer(&p, end, &pd->pd_ctx_hndl)) return -1; + if (write_buffer(&p, end, context_token)) return -1; + + if (write(k5_fd, buf, p - buf) < p - buf) return -1; + return 0; +} + +static int +do_error_downcall(int k5_fd, uid_t uid, int err) +{ + char buf[1024]; + char *p = buf, *end = buf + 1024; + unsigned int timeout = 0; + int zero = 0; + + printerr(1, "doing error downcall\n"); + + if (WRITE_BYTES(&p, end, uid)) return -1; + if (WRITE_BYTES(&p, end, timeout)) return -1; + /* use seq_win = 0 to indicate an error: */ + if (WRITE_BYTES(&p, end, zero)) return -1; + if (WRITE_BYTES(&p, end, err)) return -1; + + if (write(k5_fd, buf, p - buf) < p - buf) return -1; + return 0; + +} + +/* + * Create an RPC connection and establish an authenticated + * gss context with a server. + */ +int create_auth_rpc_client(struct clnt_info *clp, + AUTH **auth_return, + uid_t uid, + int authtype) +{ + CLIENT *rpc_clnt = NULL; + struct rpc_gss_sec sec; + AUTH *auth = NULL; + uid_t save_uid = -1; + int retval = -1; + OM_uint32 min_stat; + + sec.qop = GSS_C_QOP_DEFAULT; + sec.svc = RPCSEC_GSS_SVC_NONE; + sec.cred = GSS_C_NO_CREDENTIAL; + sec.req_flags = 0; + if (authtype == AUTHTYPE_KRB5) { + sec.mech = (gss_OID)&krb5oid; + sec.req_flags = GSS_C_MUTUAL_FLAG; + } + else if (authtype == AUTHTYPE_SPKM3) { + sec.mech = (gss_OID)&spkm3oid; + sec.req_flags = GSS_C_ANON_FLAG; + } + else { + printerr(0, "ERROR: Invalid authentication type (%d) " + "in create_auth_rpc_client\n", authtype); + goto out_fail; + } + + + if (authtype == AUTHTYPE_KRB5) { +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES + /* + * Do this before creating rpc connection since we won't need + * rpc connection if it fails! + */ + if (limit_krb5_enctypes(&sec, uid)) { + printerr(1, "WARNING: Failed while limiting krb5 " + "encryption types for user with uid %d\n", + uid); + goto out_fail; + } +#endif + } + + /* Create the context as the user (not as root) */ + save_uid = geteuid(); + if (seteuid(uid) != 0) { + printerr(0, "WARNING: Failed to seteuid for " + "user with uid %d\n", uid); + goto out_fail; + } + printerr(2, "creating context using euid %d (save_uid %d)\n", + geteuid(), save_uid); + + /* create an rpc connection to the nfs server */ + + printerr(2, "creating %s client for server %s\n", clp->protocol, + clp->servername); + if ((rpc_clnt = clnt_create(clp->servername, clp->prog, clp->vers, + clp->protocol)) == NULL) { + printerr(0, "WARNING: can't create rpc_clnt for server " + "%s for user with uid %d\n", + clp->servername, uid); + goto out_fail; + } + + printerr(2, "creating context with server %s\n", clp->servicename); + auth = authgss_create_default(rpc_clnt, clp->servicename, &sec); + if (!auth) { + /* Our caller should print appropriate message */ + printerr(2, "WARNING: Failed to create krb5 context for " + "user with uid %d for server %s\n", + uid, clp->servername); + goto out_fail; + } + + /* Restore euid to original value */ + if (seteuid(save_uid) != 0) { + printerr(0, "WARNING: Failed to restore euid" + " to uid %d\n", save_uid); + goto out_fail; + } + save_uid = -1; + + /* Success !!! */ + *auth_return = auth; + retval = 0; + + out_fail: + if (sec.cred != GSS_C_NO_CREDENTIAL) + gss_release_cred(&min_stat, &sec.cred); + if (rpc_clnt) clnt_destroy(rpc_clnt); + + return retval; +} + + +/* + * this code uses the userland rpcsec gss library to create a krb5 + * context on behalf of the kernel + */ +void +handle_krb5_upcall(struct clnt_info *clp) +{ + uid_t uid; + AUTH *auth; + struct authgss_private_data pd; + gss_buffer_desc token; + char **credlist = NULL; + char **ccname; + + printerr(1, "handling krb5 upcall\n"); + + token.length = 0; + token.value = NULL; + + if (read(clp->krb5_fd, &uid, sizeof(uid)) < sizeof(uid)) { + printerr(0, "WARNING: failed reading uid from krb5 " + "upcall pipe: %s\n", strerror(errno)); + goto out; + } + + if (uid == 0) { + int success = 0; + + /* + * Get a list of credential cache names and try each + * of them until one works or we've tried them all + */ + if (gssd_get_krb5_machine_cred_list(&credlist)) { + printerr(0, "WARNING: Failed to obtain machine " + "credentials for connection to " + "server %s\n", clp->servername); + goto out_return_error; + } + for (ccname = credlist; ccname && *ccname; ccname++) { + gssd_setup_krb5_machine_gss_ccache(*ccname); + if ((create_auth_rpc_client(clp, &auth, uid, + AUTHTYPE_KRB5)) == 0) { + /* Success! */ + success++; + break; + } + printerr(2, "WARNING: Failed to create krb5 context " + "for user with uid %d with credentials " + "cache %s for server %s\n", + uid, *ccname, clp->servername); + } + gssd_free_krb5_machine_cred_list(credlist); + if (!success) { + printerr(0, "WARNING: Failed to create krb5 context " + "for user with uid %d with any " + "credentials cache for server %s\n", + uid, clp->servername); + goto out_return_error; + } + } + else { + /* Tell krb5 gss which credentials cache to use */ + gssd_setup_krb5_user_gss_ccache(uid, clp->servername); + + if (create_auth_rpc_client(clp, &auth, uid, AUTHTYPE_KRB5)) { + printerr(0, "WARNING: Failed to create krb5 context " + "for user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + } + + if (!authgss_get_private_data(auth, &pd)) { + printerr(0, "WARNING: Failed to obtain authentication " + "data for user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + + if (serialize_context_for_kernel(pd.pd_ctx, &token)) { + printerr(0, "WARNING: Failed to serialize krb5 context for " + "user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + + do_downcall(clp->krb5_fd, uid, &pd, &token); + + if (token.value) + free(token.value); +out: + return; + +out_return_error: + do_error_downcall(clp->krb5_fd, uid, -1); + return; +} + +/* + * this code uses the userland rpcsec gss library to create an spkm3 + * context on behalf of the kernel + */ +void +handle_spkm3_upcall(struct clnt_info *clp) +{ + uid_t uid; + AUTH *auth; + struct authgss_private_data pd; + gss_buffer_desc token; + + printerr(2, "handling spkm3 upcall\n"); + + token.length = 0; + token.value = NULL; + + if (read(clp->spkm3_fd, &uid, sizeof(uid)) < sizeof(uid)) { + printerr(0, "WARNING: failed reading uid from spkm3 " + "upcall pipe: %s\n", strerror(errno)); + goto out; + } + + if (create_auth_rpc_client(clp, &auth, uid, AUTHTYPE_SPKM3)) { + printerr(0, "WARNING: Failed to create spkm3 context for " + "user with uid %d\n", uid); + goto out_return_error; + } + + if (!authgss_get_private_data(auth, &pd)) { + printerr(0, "WARNING: Failed to obtain authentication " + "data for user with uid %d for server %s\n", + uid, clp->servername); + goto out_return_error; + } + + if (serialize_context_for_kernel(pd.pd_ctx, &token)) { + printerr(0, "WARNING: Failed to serialize spkm3 context for " + "user with uid %d for server\n", + uid, clp->servername); + goto out_return_error; + } + + do_downcall(clp->spkm3_fd, uid, &pd, &token); + + if (token.value) + free(token.value); +out: + return; + +out_return_error: + do_error_downcall(clp->spkm3_fd, uid, -1); + return; +} diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c new file mode 100644 index 0000000..2dcc2ee --- /dev/null +++ b/utils/gssd/krb5_util.c @@ -0,0 +1,809 @@ +/* + * Adapted in part from MIT Kerberos 5-1.2.1 slave/kprop.c and from + * http://docs.sun.com/?p=/doc/816-1331/6m7oo9sms&a=view + * + * Copyright (c) 2002-2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson + * J. Bruce Fields + * Marius Aamodt Eriksen + * Kevin Coffman + */ + +/* + * slave/kprop.c + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +/* + * Copyright 1994 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. + */ +/* + krb5_util.c + + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include "config.h" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef USE_PRIVATE_KRB5_FUNCTIONS +#include +#endif +#include +#include + +#include "gssd.h" +#include "err_util.h" +#include "gss_util.h" +#include "gss_oids.h" +#include "krb5_util.h" + +/* Global list of principals/cache file names for machine credentials */ +struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; + +/*==========================*/ +/*=== Internal routines ===*/ +/*==========================*/ + +static int select_krb5_ccache(const struct dirent *d); +static int gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d); +static int gssd_get_single_krb5_cred(krb5_context context, + krb5_keytab kt, struct gssd_k5_kt_princ *ple); +static int gssd_have_realm_ple(krb5_data *realm); +static int gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, + char *kt_name); + +/* + * Called from the scandir function to weed out potential krb5 + * credentials cache files + * + * Returns: + * 0 => don't select this one + * 1 => select this one + */ +static int +select_krb5_ccache(const struct dirent *d) +{ + /* Don't consider anything but regular files. (No symlinks, etc.) */ + if (d->d_type != DT_REG) + return 0; + + if (strstr(d->d_name, GSSD_DEFAULT_CRED_PREFIX)) + return 1; + else + return 0; +} + +/* + * Look in the GSSD_DEFAULT_CRED_DIR for files that look like they + * are Kerberos Credential Cache files for a given UID. Return + * non-zero and the dirent pointer for the entry most likely to be + * what we want. Otherwise, return zero and no dirent pointer. + * The caller is responsible for freeing the dirent if one is returned. + * + * Returns: + * 0 => could not find an existing entry + * 1 => found an existing entry + */ +static int +gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d) +{ + struct dirent **namelist; + int n; + int i; + int found = 0; + struct dirent *best_match_dir = NULL; + struct stat best_match_stat, tmp_stat; + + *d = NULL; + n = scandir(GSSD_DEFAULT_CRED_DIR, &namelist, select_krb5_ccache, 0); + if (n < 0) { + perror("scandir looking for krb5 credentials caches"); + } + else if (n > 0) { + char substring[128]; + char statname[1024]; + snprintf(substring, sizeof(substring), "_%d", uid); + for (i = 0; i < n; i++) { + printerr(3, "CC file '%s' being considered\n", + namelist[i]->d_name); + if (strstr(namelist[i]->d_name, substring)) { + snprintf(statname, sizeof(statname), + "%s/%s", GSSD_DEFAULT_CRED_DIR, + namelist[i]->d_name); + if (stat(statname, &tmp_stat)) { + printerr(0, "Error doing stat " + "on file '%s'\n", + statname); + continue; + } + printerr(3, "CC file '%s' matches " + "name check and has " + "mtime of %u\n", + namelist[i]->d_name, + tmp_stat.st_mtime); + /* if more than one match is found, + * return the most recent (the one + * with the latest mtime), + * and don't free the dirent */ + if (!found) { + best_match_dir = namelist[i]; + best_match_stat = tmp_stat; + found++; + } + else { + /* + * If the current match has + * an mtime later than the + * one we are looking at, + * then use the current match. + * Otherwise, we still have + * the best match. + */ + if (tmp_stat.st_mtime > + best_match_stat.st_mtime) { + free(best_match_dir); + best_match_dir = namelist[i]; + best_match_stat = tmp_stat; + } + else { + free(namelist[i]); + } + printerr(3, "CC file '%s' is our " + "current best match " + "with mtime of %u\n", + best_match_dir->d_name, + best_match_stat.st_mtime); + } + } + else + free(namelist[i]); + } + free(namelist); + } + if (found) + { + *d = best_match_dir; + } + return found; +} + + +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES +/* + * this routine obtains a credentials handle via gss_acquire_cred() + * then calls gss_krb5_set_allowable_enctypes() to limit the encryption + * types negotiated. + * + * XXX Should call some function to determine the enctypes supported + * by the kernel. (Only need to do that once!) + * + * Returns: + * 0 => all went well + * -1 => there was an error + */ + +int +limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) +{ + u_int maj_stat, min_stat; + gss_cred_id_t credh; +/* krb5_enctype enctypes[] = {ENCTYPE_DES3_CBC_SHA1}; + ENCTYPE_ARCFOUR_HMAC, */ + krb5_enctype enctypes[] = {ENCTYPE_DES3_CBC_SHA1, + ENCTYPE_DES_CBC_MD5, + ENCTYPE_DES_CBC_CRC}; + int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); + + maj_stat = gss_acquire_cred(&min_stat, NULL, 0, + GSS_C_NULL_OID_SET, GSS_C_INITIATE, + &credh, NULL, NULL); + + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "WARNING: error from gss_acquire_cred " + "for user with uid %d (%s)\n", + uid, error_message(min_stat)); + return -1; + } + + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, + num_enctypes, &enctypes); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "WARNING: error from gss_set_allowable_enctypes " + "for user with uid %d (%s)\n", + uid, error_message(min_stat)); + return -1; + } + sec->cred = credh; + + return 0; +} +#endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ + +/* + * Obtain credentials via a key in the keytab given + * a keytab handle and a gssd_k5_kt_princ structure. + * Checks to see if current credentials are expired, + * if not, uses the keytab to obtain new credentials. + * + * Returns: + * 0 => success (or credentials have not expired) + * nonzero => error + */ +static int +gssd_get_single_krb5_cred(krb5_context context, + krb5_keytab kt, + struct gssd_k5_kt_princ *ple) +{ + krb5_get_init_creds_opt options; + krb5_creds my_creds; + krb5_ccache ccache = NULL; + char kt_name[BUFSIZ]; + char cc_name[BUFSIZ]; + int code; + time_t now = time(0); + + memset(&my_creds, 0, sizeof(my_creds)); + + if (ple->ccname && ple->endtime > now) { + printerr(2, "INFO: Credentials in CC '%s' are good until %d\n", + ple->ccname, ple->endtime); + code = 0; + goto out; + } + + if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { + printerr(0, "ERROR: Unable to get keytab name in " + "gssd_get_single_krb5_cred\n"); + goto out; + } + + krb5_get_init_creds_opt_init(&options); + krb5_get_init_creds_opt_set_address_list(&options, NULL); + +#ifdef TEST_SHORT_LIFETIME + /* set a short lifetime (for debugging only!) */ + printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); + krb5_get_init_creds_opt_set_tkt_life(&options, 5*60); +#endif + if ((code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, + kt, 0, 0, &options))) { + char *pname; + if ((krb5_unparse_name(context, ple->princ, &pname))) { + pname = NULL; + } + printerr(0, "WARNING: %s while getting initial ticket for " + "principal '%s' from keytab '%s'\n", + error_message(code), + pname ? pname : "", kt_name); + if (pname) krb5_free_unparsed_name(context, pname); + goto out; + } + + /* + * Initialize cache file which we're going to be using + */ + + snprintf(cc_name, sizeof(cc_name), "FILE:%s/%s%s_%s", + GSSD_DEFAULT_CRED_DIR, GSSD_DEFAULT_CRED_PREFIX, + GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm); + ple->endtime = my_creds.times.endtime; + ple->ccname = strdup(cc_name); + if (ple->ccname == NULL) { + printerr(0, "ERROR: no storage to duplicate credentials " + "cache name\n"); + code = ENOMEM; + goto out; + } + if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { + printerr(0, "ERROR: %s while opening credential cache '%s'\n", + error_message(code), cc_name); + goto out; + } + if ((code = krb5_cc_initialize(context, ccache, ple->princ))) { + printerr(0, "ERROR: %s while initializing credential " + "cache '%s'\n", error_message(code), cc_name); + goto out; + } + if ((code = krb5_cc_store_cred(context, ccache, &my_creds))) { + printerr(0, "ERROR: %s while storing credentials in '%s'\n", + error_message(code), cc_name); + goto out; + } + + code = 0; + printerr(1, "Using (machine) credentials cache: '%s'\n", cc_name); + out: + if (ccache) + krb5_cc_close(context, ccache); + krb5_free_cred_contents(context, &my_creds); + return (code); +} + +/* + * Determine if we already have a ple for the given realm + * + * Returns: + * 0 => no ple found for given realm + * 1 => found ple for given realm + */ +static int +gssd_have_realm_ple(krb5_data *realm) +{ + struct gssd_k5_kt_princ *ple; + + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { + if ((realm->length == strlen(ple->realm)) && + (strncmp(realm->data, ple->realm, realm->length) == 0)) { + return 1; + } + } + return 0; +} + +/* + * Process the given keytab file and create a list of principals we + * might use to perform mount operations. + * + * Returns: + * 0 => Sucess + * nonzero => Error + */ +static int +gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, char *kt_name) +{ + krb5_kt_cursor cursor; + krb5_keytab_entry kte; + krb5_error_code code; + struct gssd_k5_kt_princ *ple; + int retval = -1; + + /* + * Look through each entry in the keytab file and determine + * if we might want to use it later to do a mount. If so, + * save info in the global principal list + * (gssd_k5_kt_princ_list). + * Note: (ple == principal list entry) + */ + if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) { + printerr(0, "ERROR: %s while beginning keytab scan " + "for keytab '%s'\n", + error_message(code), kt_name); + retval = code; + goto out; + } + + while ((code = krb5_kt_next_entry(context, kt, &kte, &cursor)) == 0) { + char *pname; + if ((code = krb5_unparse_name(context, kte.principal, + &pname))) { + printerr(0, "WARNING: Skipping keytab entry because " + "we failed to unparse principal name: %s\n", + error_message(code)); + continue; + } + printerr(2, "Processing keytab entry for principal '%s'\n", + pname); + if ( (kte.principal->data[0].length == GSSD_SERVICE_NAME_LEN) && + (strncmp(kte.principal->data[0].data, GSSD_SERVICE_NAME, + GSSD_SERVICE_NAME_LEN) == 0) && + (!gssd_have_realm_ple(&kte.principal->realm)) ) { + printerr(2, "We will use this entry (%s)\n", pname); + ple = malloc(sizeof(struct gssd_k5_kt_princ)); + if (ple == NULL) { + printerr(0, "ERROR: could not allocate storage " + "for principal list entry\n"); + krb5_free_unparsed_name(context, pname); + retval = ENOMEM; + goto out; + } + /* These will be filled in later */ + ple->next = NULL; + ple->ccname = NULL; + ple->endtime = 0; + if ((ple->realm = + strndup(kte.principal->realm.data, + kte.principal->realm.length)) + == NULL) { + printerr(0, "ERROR: %s while copying realm to " + "principal list entry\n", + "not enough memory"); + krb5_free_unparsed_name(context, pname); + retval = ENOMEM; + goto out; + } + if ((code = krb5_copy_principal(context, + kte.principal, &ple->princ))) { + printerr(0, "ERROR: %s while copying principal " + "to principal list entry\n", + error_message(code)); + krb5_free_unparsed_name(context, pname); + retval = code; + goto out; + } + if (gssd_k5_kt_princ_list == NULL) + gssd_k5_kt_princ_list = ple; + else { + ple->next = gssd_k5_kt_princ_list; + gssd_k5_kt_princ_list = ple; + } + } + else { + printerr(2, "We will NOT use this entry (%s)\n", + pname); + } + krb5_free_unparsed_name(context, pname); + } + + if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) { + printerr(0, "WARNING: %s while ending keytab scan for " + "keytab '%s'\n", + error_message(code), kt_name); + } + + retval = 0; + out: + return retval; +} + + +/*==========================*/ +/*=== External routines ===*/ +/*==========================*/ + +/* + * Attempt to find the best match for a credentials cache file + * given only a UID. We really need more information, but we + * do the best we can. + * + * Returns: + * void + */ +void +gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername) +{ + char buf[MAX_NETOBJ_SZ]; +#ifdef HAVE_GSS_KRB5_CCACHE_NAME + u_int min_stat; +#endif + struct dirent *d; + + printerr(2, "getting credentials for client with uid %u for " + "server %s\n", uid, servername); + memset(buf, 0, sizeof(buf)); + if (gssd_find_existing_krb5_ccache(uid, &d)) { + snprintf(buf, sizeof(buf), "FILE:%s/%s", + GSSD_DEFAULT_CRED_DIR, d->d_name); + free(d); + } + else + snprintf(buf, sizeof(buf), "FILE:%s/%s%u", + GSSD_DEFAULT_CRED_DIR, + GSSD_DEFAULT_CRED_PREFIX, uid); + printerr(2, "using %s as credentials cache for client with " + "uid %u for server %s\n", buf, uid, servername); +#ifdef HAVE_GSS_KRB5_CCACHE_NAME + gss_krb5_ccache_name(&min_stat, buf, NULL); +#else + /* + * Set the KRB5CCNAME environment variable to tell the krb5 code + * which credentials cache to use. (Instead of using the private + * function above for which there is no generic gssapi + * equivalent.) + */ + setenv("KRB5CCNAME", buf, 1); +#endif +} + +/* + * Let the gss code know where to find the machine credentials ccache. + * + * Returns: + * void + */ +void +gssd_setup_krb5_machine_gss_ccache(char *ccname) +{ +#ifdef HAVE_GSS_KRB5_CCACHE_NAME + u_int min_stat; +#endif + printerr(2, "using %s as credentials cache for machine creds\n", + ccname); +#ifdef HAVE_GSS_KRB5_CCACHE_NAME + gss_krb5_ccache_name(&min_stat, ccname, NULL); +#else + /* + * Set the KRB5CCNAME environment variable to tell the krb5 code + * which credentials cache to use. (Instead of using the private + * function above for which there is no generic gssapi + * equivalent.) + */ + setenv("KRB5CCNAME", ccname, 1); +#endif +} + +/* + * The first time through this routine, go through the keytab and + * determine which keys we will try to use as machine credentials. + * Every time through this routine, try to obtain credentials using + * the keytab entries selected the first time through. + * + * Returns: + * 0 => obtained one or more credentials + * nonzero => error + * + */ + +int +gssd_refresh_krb5_machine_creds(void) +{ + krb5_context context = NULL; + krb5_keytab kt = NULL;; + krb5_error_code code; + int retval = -1; + struct gssd_k5_kt_princ *ple; + int gotone = 0; + static int processed_keytab = 0; + + + code = krb5_init_context(&context); + if (code) { + printerr(0, "ERROR: %s while initializing krb5 in " + "gssd_refresh_krb5_machine_creds\n", + error_message(code)); + retval = code; + goto out; + } + + printerr(1, "Using keytab file '%s'\n", keytabfile); + + if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { + printerr(0, "ERROR: %s while resolving keytab '%s'\n", + error_message(code), keytabfile); + goto out; + } + + /* Only go through the keytab file once. Only print messages once. */ + if (gssd_k5_kt_princ_list == NULL && !processed_keytab) { + processed_keytab = 1; + gssd_process_krb5_keytab(context, kt, keytabfile); + if (gssd_k5_kt_princ_list == NULL) { + printerr(0, "ERROR: No usable keytab entries found in " + "keytab '%s'\n", keytabfile); + printerr(0, "Do you have a valid keytab entry for " + "%s/@ in " + "keytab file %s ?\n", + GSSD_SERVICE_NAME, keytabfile); + printerr(0, "Continuing without (machine) credentials " + "- nfs4 mounts with Kerberos will fail\n"); + } + } + + /* + * If we don't have any keytab entries we liked, then we have a problem + */ + if (gssd_k5_kt_princ_list == NULL) { + retval = ENOENT; + goto out; + } + + /* + * Now go through the list of saved entries and get initial + * credentials for them (We can't do this while making the + * list because it messes up the keytab iteration cursor + * when we use the keytab to get credentials.) + */ + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { + if ((gssd_get_single_krb5_cred(context, kt, ple)) == 0) { + gotone++; + } + } + if (!gotone) { + printerr(0, "ERROR: No usable machine credentials obtained\n"); + goto out; + } + + retval = 0; + out: + if (kt) krb5_kt_close(context, kt); + krb5_free_context(context); + + return retval; +} + + +/* + * Return an array of pointers to names of credential cache files + * which can be used to try to create gss contexts with a server. + * + * Returns: + * 0 => list is attached + * nonzero => error + */ +int +gssd_get_krb5_machine_cred_list(char ***list) +{ + char **l; + int listinc = 10; + int listsize = listinc; + int i = 0; + int retval; + struct gssd_k5_kt_princ *ple; + + /* Assume failure */ + retval = -1; + *list = (char **) NULL; + + /* Refresh machine credentials */ + if ((retval = gssd_refresh_krb5_machine_creds())) { + goto out; + } + + if ((l = (char **) malloc(listsize * sizeof(char *))) == NULL) { + retval = ENOMEM; + goto out; + } + + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { + if (ple->ccname) { + if (i + 1 > listsize) { + listsize += listinc; + l = (char **) + realloc(l, listsize * sizeof(char *)); + if (l == NULL) { + retval = ENOMEM; + goto out; + } + } + if ((l[i++] = strdup(ple->ccname)) == NULL) { + retval = ENOMEM; + goto out; + } + } + } + if (i > 0) { + l[i] = NULL; + *list = l; + retval = 0; + goto out; + } + out: + return retval; +} + +/* + * Frees the list of names returned in get_krb5_machine_cred_list() + */ +void +gssd_free_krb5_machine_cred_list(char **list) +{ + char **n; + + if (list == NULL) + return; + for (n = list; n && *n; n++) { + free(*n); + } + free(list); +} + +/* + * Called upon exit. Destroys machine credentials. + */ +void +gssd_destroy_krb5_machine_creds(void) +{ + krb5_context context; + krb5_error_code code = 0; + krb5_ccache ccache; + struct gssd_k5_kt_princ *ple; + + code = krb5_init_context(&context); + if (code) { + printerr(0, "ERROR: %s while initializing krb5\n", + error_message(code)); + goto out; + } + + for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { + if (!ple->ccname) + continue; + if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { + printerr(0, "WARNING: %s while resolving credential " + "cache '%s' for destruction\n", + error_message(code), ple->ccname); + continue; + } + + if ((code = krb5_cc_destroy(context, ccache))) { + printerr(0, "WARNING: %s while destroying credential " + "cache '%s'\n", + error_message(code), ple->ccname); + } + } + out: + krb5_free_context(context); +} + diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h new file mode 100644 index 0000000..da04530 --- /dev/null +++ b/utils/gssd/krb5_util.h @@ -0,0 +1,30 @@ +#ifndef KRB5_UTIL_H +#define KRB5_UTIL_H + +#include + +/* + * List of principals from our keytab that we + * may try to get credentials for + */ +struct gssd_k5_kt_princ { + struct gssd_k5_kt_princ *next; + krb5_principal princ; + char *ccname; + char *realm; + krb5_timestamp endtime; +}; + + +void gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername); +int gssd_get_krb5_machine_cred_list(char ***list); +int gssd_refresh_krb5_machine_creds(void); +void gssd_free_krb5_machine_cred_list(char **list); +void gssd_setup_krb5_machine_gss_ccache(char *servername); +void gssd_destroy_krb5_machine_creds(void); + +#ifdef HAVE_SET_ALLOWABLE_ENCTYPES +int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid); +#endif + +#endif /* KRB5_UTIL_H */ diff --git a/utils/gssd/write_bytes.h b/utils/gssd/write_bytes.h new file mode 100644 index 0000000..ba00598 --- /dev/null +++ b/utils/gssd/write_bytes.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _WRITE_BYTES_H_ +#define _WRITE_BYTES_H_ + +#include +#include +#include /* for ntohl */ + +inline static int +write_bytes(char **ptr, const char *end, const void *arg, int arg_len) +{ + char *p = *ptr, *arg_end; + + arg_end = p + arg_len; + if (arg_end > end || arg_end < p) + return -1; + memcpy(p, arg, arg_len); + *ptr = arg_end; + return 0; +} + +#define WRITE_BYTES(p, end, arg) write_bytes(p, end, &arg, sizeof(arg)) + +inline static int +write_buffer(char **p, char *end, gss_buffer_desc *arg) +{ + if (WRITE_BYTES(p, end, arg->length)) + return -1; + if (*p + arg->length > end) + return -1; + memcpy(*p, arg->value, arg->length); + *p += arg->length; + return 0; +} + +static inline int +get_bytes(char **ptr, const char *end, void *res, int len) +{ + char *p, *q; + p = *ptr; + q = p + len; + if (q > end || q < p) + return -1; + memcpy(res, p, len); + *ptr = q; + return 0; +} + +static inline int +get_buffer(char **ptr, const char *end, gss_buffer_desc *res) +{ + char *p, *q; + p = *ptr; + if (get_bytes(&p, end, &res->length, sizeof(res->length))) + return -1; + q = p + res->length; + if (q > end || q < p) + return -1; + if (!(res->value = malloc(res->length))) + return -1; + memcpy(res->value, p, res->length); + *ptr = q; + return 0; +} + +static inline int +xdr_get_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t *res) +{ + if (get_bytes((char **)ptr, (char *)end, res, sizeof(res))) + return -1; + *res = ntohl(*res); + return 0; +} + +static inline int +xdr_get_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *res) +{ + u_int32_t *p, *q; + p = *ptr; + if (xdr_get_u32(&p, end, &res->length)) + return -1; + q = p + ((res->length + 3) >> 2); + if (q > end || q < p) + return -1; + if (!(res->value = malloc(res->length))) + return -1; + memcpy(res->value, p, res->length); + *ptr = q; + return 0; +} + +static inline int +xdr_write_u32(u_int32_t **ptr, const u_int32_t *end, u_int32_t arg) +{ + u_int32_t tmp; + + tmp = htonl(arg); + return WRITE_BYTES((char **)ptr, (char *)end, tmp); +} + +static inline int +xdr_write_buffer(u_int32_t **ptr, const u_int32_t *end, gss_buffer_desc *arg) +{ + if (xdr_write_u32(ptr, end, arg->length)) + return -1; + return write_bytes((char **)ptr, (char *)end, arg->value, + (arg->length + 3) & ~3); +} + +#endif /* _WRITE_BYTES_H_ */ diff --git a/utils/gssdestroycreds/Makefile b/utils/gssdestroycreds/Makefile new file mode 100644 index 0000000..266e9de --- /dev/null +++ b/utils/gssdestroycreds/Makefile @@ -0,0 +1,14 @@ +# +# gss context destruction tool +# + +PROGRAM = gss_clnt_send_err +OBJS = gss_clnt_send_err.o + +include $(TOP)rules.mk + +gss_clnt_send_err.o: ../gssd/gss_clnt_send_err.c + $(CC) -c $(CFLAGS) $(?:.o=.c) + +install:: + $(INSTALLBIN) ../gssd/gss_destroy_creds $(SBINDIR)/$(PREFIX)$kgss_destroy_creds diff --git a/utils/svcgssd/Makefile b/utils/svcgssd/Makefile new file mode 100644 index 0000000..ed3fa98 --- /dev/null +++ b/utils/svcgssd/Makefile @@ -0,0 +1,23 @@ +# +# Makefile for rpc.gssd +# + +PROGRAM = svcgssd +PREFIX = rpc. +OBJS = svcgssd.o svcgssd_main_loop.o svcgssd_proc.o err_util.o gss_util.o \ + gss_oids.o context.o context_heimdal.o cacheio.o svcgssd_mech2file.o +LIBDEPS = $(TOP)support/lib/librpc.a $(TOP)support/lib/libgssapi.a +LIBS = -Wl,-rpath=$(KRBDIR)/lib -lrpc -lgssapi -ldl $(KRBLIB) +MAN8 = svcgssd + +predep :: + - ln ../gssd/err_util.c + - ln ../gssd/gss_util.c + - ln ../gssd/gss_oids.c + - ln ../gssd/context.c + - ln ../gssd/context_heimdal.c + +include $(TOP)rules.mk + +CFLAGS += -I../gssd -DKRB5_VERSION=$(KRB5_VERSION) \ + -I$(TOP)support/rpc/include/ -I$(KRBDIR)/include diff --git a/utils/svcgssd/cacheio.c b/utils/svcgssd/cacheio.c new file mode 100644 index 0000000..ac76c06 --- /dev/null +++ b/utils/svcgssd/cacheio.c @@ -0,0 +1,289 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * support/nfs/cacheio.c + * support IO on the cache channel files in 2.5 and beyond. + * These use 'qwords' which are like words, but with a little quoting. + * + */ + + +/* + * Support routines for text-based upcalls. + * Fields are separated by spaces. + * Fields are either mangled to quote space tab newline slosh with slosh + * or a hexified with a leading \x + * Record is terminated with newline. + * + */ + +#include "cacheio.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "err_util.h" + +void qword_add(char **bpp, int *lp, char *str) +{ + char *bp = *bpp; + int len = *lp; + char c; + + if (len < 0) return; + + while ((c=*str++) && len) + switch(c) { + case ' ': + case '\t': + case '\n': + case '\\': + if (len >= 4) { + *bp++ = '\\'; + *bp++ = '0' + ((c & 0300)>>6); + *bp++ = '0' + ((c & 0070)>>3); + *bp++ = '0' + ((c & 0007)>>0); + } + len -= 4; + break; + default: + *bp++ = c; + len--; + } + if (c || len <1) len = -1; + else { + *bp++ = ' '; + len--; + } + *bpp = bp; + *lp = len; +} + +void qword_addhex(char **bpp, int *lp, char *buf, int blen) +{ + char *bp = *bpp; + int len = *lp; + + if (len < 0) return; + + if (len > 2) { + *bp++ = '\\'; + *bp++ = 'x'; + len -= 2; + while (blen && len >= 2) { + unsigned char c = *buf++; + *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); + *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); + len -= 2; + blen--; + } + } + if (blen || len<1) len = -1; + else { + *bp++ = ' '; + len--; + } + *bpp = bp; + *lp = len; +} + +void qword_addint(char **bpp, int *lp, int n) +{ + int len; + + len = snprintf(*bpp, *lp, "%d ", n); + if (len > *lp) + len = *lp; + *bpp += len; + *lp -= len; +} + +void qword_addeol(char **bpp, int *lp) +{ + if (*lp <= 0) + return; + **bpp = '\n'; + (*bpp)++; + (*lp)--; +} + +static char qword_buf[8192]; +static char tmp_buf[8192]; +void qword_print(FILE *f, char *str) +{ + char *bp = qword_buf; + int len = sizeof(qword_buf); + qword_add(&bp, &len, str); + fwrite(qword_buf, bp-qword_buf, 1, f); + /* XXX: */ + memcpy(tmp_buf, qword_buf, bp-qword_buf); + tmp_buf[bp-qword_buf] = '\0'; + printerr(2, "%s", tmp_buf); +} + +void qword_printhex(FILE *f, char *str, int slen) +{ + char *bp = qword_buf; + int len = sizeof(qword_buf); + qword_addhex(&bp, &len, str, slen); + fwrite(qword_buf, bp-qword_buf, 1, f); + /* XXX: */ + memcpy(tmp_buf, qword_buf, bp-qword_buf); + tmp_buf[bp-qword_buf] = '\0'; + printerr(2, "%s", tmp_buf); +} + +void qword_printint(FILE *f, int num) +{ + fprintf(f, "%d ", num); + printerr(2, "%d ", num); +} + +void qword_eol(FILE *f) +{ + fprintf(f,"\n"); + fflush(f); + printerr(2, "\n"); +} + + + +#define isodigit(c) (isdigit(c) && c <= '7') +int qword_get(char **bpp, char *dest, int bufsize) +{ + /* return bytes copied, or -1 on error */ + char *bp = *bpp; + int len = 0; + + while (*bp == ' ') bp++; + + if (bp[0] == '\\' && bp[1] == 'x') { + /* HEX STRING */ + bp += 2; + while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) { + int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10; + bp++; + byte <<= 4; + byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10; + *dest++ = byte; + bp++; + len++; + } + } else { + /* text with \nnn octal quoting */ + while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) { + if (*bp == '\\' && + isodigit(bp[1]) && (bp[1] <= '3') && + isodigit(bp[2]) && + isodigit(bp[3])) { + int byte = (*++bp -'0'); + bp++; + byte = (byte << 3) | (*bp++ - '0'); + byte = (byte << 3) | (*bp++ - '0'); + *dest++ = byte; + len++; + } else { + *dest++ = *bp++; + len++; + } + } + } + + if (*bp != ' ' && *bp != '\n' && *bp != '\0') + return -1; + while (*bp == ' ') bp++; + *bpp = bp; + *dest = '\0'; + return len; +} + +int qword_get_int(char **bpp, int *anint) +{ + char buf[50]; + char *ep; + int rv; + int len = qword_get(bpp, buf, 50); + if (len < 0) return -1; + if (len ==0) return -1; + rv = strtol(buf, &ep, 0); + if (*ep) return -1; + *anint = rv; + return 0; +} + +int readline(int fd, char **buf, int *lenp) +{ + /* read a line into *buf, which is malloced *len long + * realloc if needed until we find a \n + * nul out the \n and return + * 0 of eof, 1 of success + */ + int len; + + if (*lenp == 0) { + char *b = malloc(128); + if (b == NULL) + return 0; + *buf = b; + *lenp = 128; + } + len = read(fd, *buf, *lenp); + if (len <= 0) { + printerr(2, "read error in readline: %d\n", len); + return 0; + } + while ((*buf)[len-1] != '\n') { + /* now the less common case. There was no newline, + * so we have to keep reading after re-alloc + */ + char *new; + int nl; + *lenp += 128; + new = realloc(*buf, *lenp); + if (new == NULL) + return 0; + *buf = new; + nl = read(fd, *buf +len, *lenp - len); + if (nl <= 0 ) { + printerr(2, "read error in readline: %d\n", nl); + return 0; + } + len += nl; + } + (*buf)[len-1] = 0; + printerr(1, "read line with %d characters:\n%s\n", *lenp, *buf); + return 1; +} diff --git a/utils/svcgssd/cacheio.h b/utils/svcgssd/cacheio.h new file mode 100644 index 0000000..cc97b36 --- /dev/null +++ b/utils/svcgssd/cacheio.h @@ -0,0 +1,48 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CACHEIO_H_ +#define _CACHEIO_H_ + +#include + +void qword_add(char **bpp, int *lp, char *str); +void qword_addhex(char **bpp, int *lp, char *buf, int blen); +void qword_addint(char **bpp, int *lp, int n); +void qword_addeol(char **bpp, int *lp); +void qword_print(FILE *f, char *str); +void qword_printhex(FILE *f, char *str, int slen); +void qword_printint(FILE *f, int num); +void qword_eol(FILE *f); +int readline(int fd, char **buf, int *lenp); +int qword_get(char **bpp, char *dest, int bufsize); +int qword_get_int(char **bpp, int *anint); + +#endif /* _CACHEIO_H_ */ diff --git a/utils/svcgssd/svcgssd.c b/utils/svcgssd/svcgssd.c new file mode 100644 index 0000000..9dd5a3a --- /dev/null +++ b/utils/svcgssd/svcgssd.c @@ -0,0 +1,209 @@ +/* + gssd.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song . + Copyright (c) 2002 Andy Adamson . + Copyright (c) 2002 Marius Aamodt Eriksen . + Copyright (c) 2002 J. Bruce Fields . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include "svcgssd.h" +#include "gss_util.h" +#include "err_util.h" + +/* + * mydaemon creates a pipe between the partent and child + * process. The parent process will wait until the + * child dies or writes a '1' on the pipe signaling + * that it started successfully. + */ +int pipefds[2] = { -1, -1}; + +static void +mydaemon(int nochdir, int noclose) +{ + int pid, status, tempfd, fdmax, filedes; + + if (pipe(pipefds) < 0) { + printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(1); + } + if ((pid = fork ()) < 0) { + printerr(1, "mydaemon: fork() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(1); + } + + if (pid != 0) { + /* + * Parent. Wait for status from child. + */ + close(pipefds[1]); + if (read(pipefds[0], &status, 1) != 1) + exit(1); + exit (0); + } + /* Child. */ + close(pipefds[0]); + setsid (); + if (nochdir == 0) { + if (chdir ("/") == -1) { + printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(1); + } + } + + while (pipefds[1] <= 2) { + pipefds[1] = dup(pipefds[1]); + if (pipefds[1] < 0) { + printerr(1, "mydaemon: dup() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(1); + } + } + + if (noclose == 0) { + tempfd = open("/dev/null", O_RDWR); + close(0); dup2(tempfd, 0); + close(1); dup2(tempfd, 1); + close(2); dup2(tempfd, 2); + fdmax = sysconf (_SC_OPEN_MAX); + for (filedes = 3; filedes < fdmax; filedes++) + if (filedes != pipefds[1]) + close (filedes); + } + + return; +} + +static void +release_parent() +{ + int status; + + if (pipefds[1] > 0) { + write(pipefds[1], &status, 1); + close(pipefds[1]); + pipefds[1] = -1; + } +} + +void +sig_die(int signal) +{ + /* destroy krb5 machine creds */ + printerr(1, "exiting on signal %d\n", signal); + exit(1); +} + +static void +usage(char *progname) +{ + fprintf(stderr, "usage: %s [-n] [-f] [-v]\n", + progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int get_creds = 1; + int fg = 0; + int verbosity = 0; + int opt; + extern char *optarg; + char *progname; + + while ((opt = getopt(argc, argv, "fvnp:")) != -1) { + switch (opt) { + case 'f': + fg = 1; + break; + case 'n': + get_creds = 0; + break; + case 'v': + verbosity++; + break; + default: + usage(argv[0]); + break; + } + } + + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + + initerr(progname, verbosity, fg); + + if (!fg) + mydaemon(0, 0); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); + signal(SIGHUP, sig_die); + + if (get_creds && !gssd_acquire_cred(GSSD_SERVICE_NAME)) { + printerr(0, "unable to obtain root (machine) credentials\n"); + printerr(0, "do you have a keytab entry for " + "nfs/@ in " + "/etc/krb5.keytab?\n"); + exit(1); + } + + if (!fg) + release_parent(); + + gssd_run(); + printerr(0, "gssd_run returned!\n"); + abort(); +} diff --git a/utils/svcgssd/svcgssd.h b/utils/svcgssd/svcgssd.h new file mode 100644 index 0000000..9a2e2e8 --- /dev/null +++ b/utils/svcgssd/svcgssd.h @@ -0,0 +1,43 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _RPC_SVCGSSD_H_ +#define _RPC_SVCGSSD_H_ + +#include +#include +#include + +void handle_nullreq(FILE *f); +void gssd_run(void); + +#define GSSD_SERVICE_NAME "nfs" + +#endif /* _RPC_SVCGSSD_H_ */ diff --git a/utils/svcgssd/svcgssd.man b/utils/svcgssd/svcgssd.man new file mode 100644 index 0000000..f17f772 --- /dev/null +++ b/utils/svcgssd/svcgssd.man @@ -0,0 +1,41 @@ +.\" +.\" rpc.svcgssd(8) +.\" +.\" Copyright (C) 2003 J. Bruce Fields +.TH rpc.svcgssd 8 "17 Mar 2003" +.SH NAME +rpc.svcgssd \- server-side rpcsec_gss daemon +.SH SYNOPSIS +.B "rpc.svcgssd [-v] [-f] [-p pipefsdir]" +.SH DESCRIPTION +The rpcsec_gss protocol gives a means of using the gss-api generic security +api to provide security for protocols using rpc (in particular, nfs). Before +exchanging any rpc requests using rpcsec_gss, the rpc client must first +establish a security context with the rpc server. The linux kernel's +implementation of rpcsec_gss depends on the userspace daemon +.B rpc.svcgssd +to handle context establishment on the rpc server. The +daemon uses files in the proc filesystem to communicate with +the kernel. + +.SH OPTIONS +.TP +.B -f +Runs +.B rpc.svcgssd +in the foreground and sends output to stderr (as opposed to syslogd) +.TP +.B -v +Increases the verbosity of the output (can be specified multiple times). + +.SH SEE ALSO +.BR rpc.gssd(8), +.SH AUTHORS +.br +Dug Song +.br +Andy Adamson +.br +Marius Aamodt Eriksen +.br +J. Bruce Fields diff --git a/utils/svcgssd/svcgssd_main_loop.c b/utils/svcgssd/svcgssd_main_loop.c new file mode 100644 index 0000000..477a44c --- /dev/null +++ b/utils/svcgssd/svcgssd_main_loop.c @@ -0,0 +1,86 @@ +/* + Copyright (c) 2004 The Regents of the University of Michigan. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "svcgssd.h" +#include "err_util.h" + +void +gssd_run() +{ + int ret; + FILE *f; + struct pollfd pollfd; + +#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel" + + f = fopen(NULLRPC_FILE, "rw"); + + if (!f) { + printerr(0, "failed to open %s\n", NULLRPC_FILE); + exit(1); + } + pollfd.fd = fileno(f); + pollfd.events = POLLIN; + while (1) { + pollfd.revents = 0; + printerr(1, "entering poll\n"); + ret = poll(&pollfd, 1, -1); + printerr(1, "leaving poll\n"); + if (ret < 0) { + if (errno != EINTR) + printerr(0, "error return from poll\n"); + } else if (ret == 0) { + /* timeout; shouldn't happen. */ + } else { + if (ret != 1) { + printerr(0, "bug: unexpected poll return %d\n", + ret); + exit(1); + } + if (pollfd.revents & POLLIN) + handle_nullreq(f); + } + } +} diff --git a/utils/svcgssd/svcgssd_mech2file.c b/utils/svcgssd/svcgssd_mech2file.c new file mode 100644 index 0000000..f44f7c6 --- /dev/null +++ b/utils/svcgssd/svcgssd_mech2file.c @@ -0,0 +1,77 @@ +/* + linux_downcall.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2004 Andy Adamson . + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "config.h" + +#ifdef HAVE_KRB5 +#include +#elif HAVE_HEIMDAL +#include +#endif +#include + + +#define g_OID_equal(o1,o2) \ + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->elements,(o2)->elements,(int) (o1)->length) == 0)) + +struct mech2file { + gss_OID_desc mech; + char filename[8]; +}; + +struct mech2file m2f[] = { + {{9, "\052\206\110\206\367\022\001\002\002"}, "krb5"}, + {{7, "\053\006\001\005\005\001\003"}, "spkm3"}, + {{7, "\053\006\001\005\005\001\009"}, "lipkey"}, + {{0,0},""}, +}; + +/* + * Find the Linux svcgssd downcall file name given the mechanism + */ +char * +mech2file(gss_OID mech) +{ + struct mech2file *m2fp = m2f; + + while(m2fp->mech.length != 0) { + if (g_OID_equal(mech,&m2fp->mech)) + return(m2fp->filename); + m2fp++; + } + return NULL; +} diff --git a/utils/svcgssd/svcgssd_proc.c b/utils/svcgssd/svcgssd_proc.c new file mode 100644 index 0000000..c2470c6 --- /dev/null +++ b/utils/svcgssd/svcgssd_proc.c @@ -0,0 +1,344 @@ +/* + svc_in_gssd_proc.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2002 Bruce Fields + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "svcgssd.h" +#include "gss_util.h" +#include "err_util.h" +#include "context.h" +#include "cacheio.h" + +/* XXX: ? */ +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +extern char * mech2file(gss_OID mech); +#define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" +#define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel" + +struct svc_cred { + uid_t cr_uid; + gid_t cr_gid; + gid_t cr_groups[NGROUPS]; +}; + +static int +do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, + gss_OID mech, gss_buffer_desc *context_token) +{ + FILE *f; + int i, ngroups; + char *fname = NULL; + + printerr(1, "doing downcall\n"); + if ((fname = mech2file(mech)) == NULL) + goto out_err; + f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w"); + if (f == NULL) { + printerr(0, "WARNING: unable to open downcall channel " + "%s: %s\n", + SVCGSSD_CONTEXT_CHANNEL, strerror(errno)); + goto out_err; + } + qword_printhex(f, out_handle->value, out_handle->length); + /* XXX are types OK for the rest of this? */ + qword_printint(f, 0x7fffffff); /*XXX need a better timeout */ + qword_printint(f, cred->cr_uid); + qword_printint(f, cred->cr_gid); + ngroups = NGROUPS; + for (i=0; i < NGROUPS; i++) { + if (cred->cr_groups[i] == NOGROUP) { + ngroups = i; + break; + } + } + qword_printint(f, ngroups); + for (i=0; i < ngroups; i++) + qword_printint(f, cred->cr_groups[i]); + qword_print(f, fname); + qword_printhex(f, context_token->value, context_token->length); + qword_eol(f); + fclose(f); + return 0; +out_err: + printerr(0, "WARNING: downcall failed\n"); + return -1; +} + +struct gss_verifier { + u_int32_t flav; + gss_buffer_desc body; +}; + +#define RPCSEC_GSS_SEQ_WIN 5 + +static int +send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, + u_int32_t maj_stat, u_int32_t min_stat, + gss_buffer_desc *out_handle, gss_buffer_desc *out_token) +{ + char buf[2 * 4096]; + char *bp = buf; + int blen = sizeof(buf); + /* XXXARG: */ + int g; + + printerr(1, "sending null reply\n"); + + qword_addhex(&bp, &blen, in_handle->value, in_handle->length); + qword_addhex(&bp, &blen, in_token->value, in_token->length); + qword_addint(&bp, &blen, 0x7fffffff); /*XXX need a better timeout */ + qword_addint(&bp, &blen, maj_stat); + qword_addint(&bp, &blen, min_stat); + qword_addhex(&bp, &blen, out_handle->value, out_handle->length); + qword_addhex(&bp, &blen, out_token->value, out_token->length); + qword_addeol(&bp, &blen); + if (blen <= 0) { + printerr(0, "WARNING: send_respsonse: message too long\n"); + return -1; + } + g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY); + if (g == -1) { + printerr(0, "WARNING: open %s failed: %s\n", + SVCGSSD_INIT_CHANNEL, strerror(errno)); + return -1; + } + *bp = '\0'; + printerr(1, "writing message: %s", buf); + if (write(g, buf, bp - buf) == -1) { + printerr(0, "WARNING: failed to write message\n"); + close(g); + return -1; + } + close(g); + return 0; +} + +#define rpc_auth_ok 0 +#define rpc_autherr_badcred 1 +#define rpc_autherr_rejectedcred 2 +#define rpc_autherr_badverf 3 +#define rpc_autherr_rejectedverf 4 +#define rpc_autherr_tooweak 5 +#define rpcsec_gsserr_credproblem 13 +#define rpcsec_gsserr_ctxproblem 14 + +/* XXX memory leaks everywhere: */ +static int +get_ids(gss_name_t client_name, gss_OID *mech, struct svc_cred *cred) +{ + u_int32_t maj_stat, min_stat; + gss_buffer_desc name; + char *sname; + int res = -1; + struct passwd *pw = NULL; + gss_OID name_type; + char *c; + + maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); + if (maj_stat != GSS_S_COMPLETE) + goto out; + if (!(sname = calloc(name.length + 1, 1))) + goto out; + memcpy(sname, name.value, name.length); + printerr(1, "sname = %s\n", sname); + /* XXX: should use same mapping as idmapd? Or something; for now + * I'm just chopping off the domain. */ + /* XXX: note that idmapd also does this! It doesn't check the domain + * name. */ + if ((c = strchr(sname, '@')) != NULL) + *c = '\0'; + /* XXX? mapping unknown users (including machine creds) to nobody: */ + if ( !(pw = getpwnam(sname)) && !(pw = getpwnam("nobody")) ) + goto out; + cred->cr_uid = pw->pw_uid; + cred->cr_gid = pw->pw_gid; + /* XXX Read password file? Use initgroups? I dunno...*/ + cred->cr_groups[0] = NOGROUP; + res = 0; +out: + if (res) + printerr(0, "WARNING: get_uid failed\n"); + return res; +} + +void +print_hexl(int pri, unsigned char *cp, int length) +{ + int i, j, jm; + unsigned char c; + + printerr(pri, "length %d\n",length); + printerr(pri, "\n"); + + for (i = 0; i < length; i += 0x10) { + printerr(pri, " %04x: ", (u_int)i); + jm = length - i; + jm = jm > 16 ? 16 : jm; + + for (j = 0; j < jm; j++) { + if ((j % 2) == 1) + printerr(pri,"%02x ", (u_int)cp[i+j]); + else + printerr(pri,"%02x", (u_int)cp[i+j]); + } + for (; j < 16; j++) { + if ((j % 2) == 1) + printerr(pri," "); + else + printerr(pri," "); + } + printerr(pri," "); + + for (j = 0; j < jm; j++) { + c = cp[i+j]; + c = isprint(c) ? c : '.'; + printerr(pri,"%c", c); + } + printerr(pri,"\n"); + } +} + +void +handle_nullreq(FILE *f) { + /* XXX initialize to a random integer to reduce chances of unnecessary + * invalidation of existing ctx's on restarting svcgssd. */ + static u_int32_t handle_seq = 0; + char in_tok_buf[1023]; + char in_handle_buf[15]; + char out_handle_buf[15]; + gss_buffer_desc in_tok = {.value = in_tok_buf}, + out_tok = {.value = NULL}, + in_handle = {.value = in_handle_buf}, + out_handle = {.value = out_handle_buf}, + ctx_token = {.value = NULL}, + /* XXX isn't there a define for this?: */ + null_token = {.value = NULL}; + u_int32_t ret_flags; + gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; + gss_name_t client_name; + gss_OID mech; + u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; + struct svc_cred cred; + static char *lbuf = NULL; + static int lbuflen = 0; + static char *cp; + + printerr(1, "handling null request\n"); + + if (readline(fileno(f), &lbuf, &lbuflen) != 1) { + printerr(0, "WARNING: handle_nullreq: " + "failed reading request\n"); + return; + } + + cp = lbuf; + + in_handle.length + = qword_get(&cp, in_handle.value, sizeof(in_handle_buf)); + printerr(2, "in_handle: \n"); + print_hexl(2, in_handle.value, in_handle.length); + handle_seq++; + out_handle.length = sizeof(handle_seq); + memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); + + in_tok.length = qword_get(&cp, in_tok.value, sizeof(in_tok_buf)); + printerr(2, "in_tok: \n"); + print_hexl(2, in_tok.value, in_tok.length); + + if (in_tok.length < 0) { + printerr(0, "WARNING: handle_nullreq: " + "failed parsing request\n"); + goto out_err; + } + + if (in_handle.length != 0) { /* CONTINUE_INIT case */ + printerr(0, "WARNING: handle_nullreq: " + "CONTINUE_INIT unsupported\n"); + send_response(f, &in_handle, &in_tok, -1, -1, &null_token, + &null_token); + goto out_err; + } + + maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds, + &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, + &mech, &out_tok, &ret_flags, NULL, NULL); + if (maj_stat != GSS_S_COMPLETE) { + printerr(0, "WARNING: gss_accept_sec_context failed\n"); + pgsserr("handle_nullreq: gss_accept_sec_context", + maj_stat, min_stat, mech); + send_response(f, &in_handle, &in_tok, maj_stat, min_stat, + &null_token, &null_token); + goto out_err; + } + if (get_ids(client_name, &mech, &cred)) { + printerr(0, "WARNING: handle_nullreq: get_uid failed\n"); + send_response(f, &in_handle, &in_tok, GSS_S_BAD_NAME /* XXX? */, + 0, &null_token, &null_token); + goto out_err; + } + + /* kernel needs ctx to calculate verifier on null response, so + * must give it context before doing null call: */ + if (serialize_context_for_kernel(ctx, &ctx_token)) { + printerr(0, "WARNING: handle_nullreq: " + "serialize_context_for_kernel failed\n"); + send_response(f, &in_handle, &in_tok, -1, /* XXX? */ + 0, &null_token, &null_token); + goto out_err; + } + do_svc_downcall(&out_handle, &cred, mech, &ctx_token); + send_response(f, &in_handle, &in_tok, maj_stat, min_stat, + &out_handle, &out_tok); + goto out; +out_err: +out: + if (ctx_token.value != NULL) + free(ctx_token.value); + printerr(1, "finished handling null request\n"); + return; +}