]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Add gss support from citi @ umich nfs-utils-1-0-6-post7-gss
authorneilbrown <neilbrown>
Tue, 19 Oct 2004 00:22:53 +0000 (00:22 +0000)
committerneilbrown <neilbrown>
Tue, 19 Oct 2004 00:22:53 +0000 (00:22 +0000)
105 files changed:
config.mk.in
configure.in
support/Makefile
support/gssapi/Makefile [new file with mode: 0644]
support/gssapi/SAMPLE_gssapi_mech.conf [new file with mode: 0644]
support/gssapi/g_accept_sec_context.c [new file with mode: 0644]
support/gssapi/g_acquire_cred.c [new file with mode: 0644]
support/gssapi/g_compare_name.c [new file with mode: 0644]
support/gssapi/g_context_time.c [new file with mode: 0644]
support/gssapi/g_delete_sec_context.c [new file with mode: 0644]
support/gssapi/g_dsp_name.c [new file with mode: 0644]
support/gssapi/g_dsp_status.c [new file with mode: 0644]
support/gssapi/g_dup_name.c [new file with mode: 0644]
support/gssapi/g_exp_sec_context.c [new file with mode: 0644]
support/gssapi/g_glue.c [new file with mode: 0644]
support/gssapi/g_imp_name.c [new file with mode: 0644]
support/gssapi/g_imp_sec_context.c [new file with mode: 0644]
support/gssapi/g_indicate_mechs.c [new file with mode: 0644]
support/gssapi/g_init_sec_context.c [new file with mode: 0644]
support/gssapi/g_initialize.c [new file with mode: 0644]
support/gssapi/g_inq_context.c [new file with mode: 0644]
support/gssapi/g_inq_cred.c [new file with mode: 0644]
support/gssapi/g_inq_names.c [new file with mode: 0644]
support/gssapi/g_mechname.c [new file with mode: 0644]
support/gssapi/g_mit_krb5_mech.c [new file with mode: 0644]
support/gssapi/g_oid_ops.c [new file with mode: 0644]
support/gssapi/g_process_context.c [new file with mode: 0644]
support/gssapi/g_rel_buffer.c [new file with mode: 0644]
support/gssapi/g_rel_cred.c [new file with mode: 0644]
support/gssapi/g_rel_name.c [new file with mode: 0644]
support/gssapi/g_rel_oid_set.c [new file with mode: 0644]
support/gssapi/g_seal.c [new file with mode: 0644]
support/gssapi/g_set_allowable_enctypes.c [new file with mode: 0644]
support/gssapi/g_sign.c [new file with mode: 0644]
support/gssapi/g_unseal.c [new file with mode: 0644]
support/gssapi/g_verify.c [new file with mode: 0644]
support/gssapi/gen_oids.c [new file with mode: 0644]
support/gssapi/gssd_pname_to_uid.c [new file with mode: 0644]
support/gssapi/mechglue.h [new file with mode: 0644]
support/gssapi/mglueP.h [new file with mode: 0644]
support/gssapi/oid_ops.c [new file with mode: 0644]
support/include/config.h.in
support/include/gssapi/gssapi.h [new file with mode: 0644]
support/lib/Makefile
support/rpc/DISCLAIMER [new file with mode: 0644]
support/rpc/Makefile [new file with mode: 0644]
support/rpc/README [new file with mode: 0644]
support/rpc/auth_gss.c [new file with mode: 0644]
support/rpc/authgss_prot.c [new file with mode: 0644]
support/rpc/include/rpc/auth.h [new file with mode: 0644]
support/rpc/include/rpc/auth_gss.h [new file with mode: 0644]
support/rpc/include/rpc/auth_unix.h [new file with mode: 0644]
support/rpc/include/rpc/clnt.h [new file with mode: 0644]
support/rpc/include/rpc/pmap_clnt.h [new file with mode: 0644]
support/rpc/include/rpc/pmap_prot.h [new file with mode: 0644]
support/rpc/include/rpc/pmap_rmt.h [new file with mode: 0644]
support/rpc/include/rpc/rpc.h [new file with mode: 0644]
support/rpc/include/rpc/rpc_des.h [new file with mode: 0644]
support/rpc/include/rpc/rpc_msg.h [new file with mode: 0644]
support/rpc/include/rpc/svc.h [new file with mode: 0644]
support/rpc/include/rpc/svc_auth.h [new file with mode: 0644]
support/rpc/include/rpc/types.h [new file with mode: 0644]
support/rpc/include/rpc/xdr.h [new file with mode: 0644]
support/rpc/rpc_commondata.c [new file with mode: 0644]
support/rpc/svc.c [new file with mode: 0644]
support/rpc/svc_auth.c [new file with mode: 0644]
support/rpc/svc_auth_gss.c [new file with mode: 0644]
support/rpc/svc_auth_none.c [new file with mode: 0644]
support/rpc/svc_auth_unix.c [new file with mode: 0644]
support/rpc/svc_raw.c [new file with mode: 0644]
support/rpc/svc_run.c [new file with mode: 0644]
support/rpc/svc_simple.c [new file with mode: 0644]
support/rpc/svc_tcp.c [new file with mode: 0644]
support/rpc/svc_udp.c [new file with mode: 0644]
utils/Makefile.in
utils/gssd/Makefile [new file with mode: 0644]
utils/gssd/context.c [new file with mode: 0644]
utils/gssd/context.h [new file with mode: 0644]
utils/gssd/context_heimdal.c [new file with mode: 0644]
utils/gssd/err_util.c [new file with mode: 0644]
utils/gssd/err_util.h [new file with mode: 0644]
utils/gssd/gss_clnt_send_err.c [new file with mode: 0644]
utils/gssd/gss_destroy_creds [new file with mode: 0644]
utils/gssd/gss_oids.c [new file with mode: 0644]
utils/gssd/gss_oids.h [new file with mode: 0644]
utils/gssd/gss_util.c [new file with mode: 0644]
utils/gssd/gss_util.h [new file with mode: 0644]
utils/gssd/gssd.c [new file with mode: 0644]
utils/gssd/gssd.h [new file with mode: 0644]
utils/gssd/gssd.man [new file with mode: 0644]
utils/gssd/gssd_main_loop.c [new file with mode: 0644]
utils/gssd/gssd_proc.c [new file with mode: 0644]
utils/gssd/krb5_util.c [new file with mode: 0644]
utils/gssd/krb5_util.h [new file with mode: 0644]
utils/gssd/write_bytes.h [new file with mode: 0644]
utils/gssdestroycreds/Makefile [new file with mode: 0644]
utils/svcgssd/Makefile [new file with mode: 0644]
utils/svcgssd/cacheio.c [new file with mode: 0644]
utils/svcgssd/cacheio.h [new file with mode: 0644]
utils/svcgssd/svcgssd.c [new file with mode: 0644]
utils/svcgssd/svcgssd.h [new file with mode: 0644]
utils/svcgssd/svcgssd.man [new file with mode: 0644]
utils/svcgssd/svcgssd_main_loop.c [new file with mode: 0644]
utils/svcgssd/svcgssd_mech2file.c [new file with mode: 0644]
utils/svcgssd/svcgssd_proc.c [new file with mode: 0644]

index 67f3d01382db001a0c046a310835a44c81b53d6e..afbed88265e1894e586d8fa305e3db3237921436 100644 (file)
@@ -33,6 +33,9 @@ MANGROUP      = root
 LIBBSD         = @LIBBSD@
 LIBNSL         = @LIBNSL@
 LIBWRAP                = @LIBWRAP@
 LIBBSD         = @LIBBSD@
 LIBNSL         = @LIBNSL@
 LIBWRAP                = @LIBWRAP@
+KRBLIB         = @KRBLIB@
+KRBDIR         = @KRBDIR@
+KRB5_VERSION   = @K5VERS@
 
 ################# END OF USER SERVICEABLE PARTS ##################
 ALLTARGETS     = all clean distclean install installman \
 
 ################# 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 \
 MAN2PS         = groff -Tps -man
 
 AFLAGS         = -I$(TOP)support/include \
+                 -I$(KRBDIR)/include \
                  -Wall $(ARCHFLAGS) -pipe
 ifdef KERNEL_INCDIR
 AFLAGS        += -I$(KERNEL_INCDIR)
                  -Wall $(ARCHFLAGS) -pipe
 ifdef KERNEL_INCDIR
 AFLAGS        += -I$(KERNEL_INCDIR)
index 93588c22b1b695395c5aa58e51a10d58962e9b1f..496219781eb9b00cf89417e208c47e51f2fa8379 100644 (file)
@@ -52,6 +52,22 @@ AC_ARG_ENABLE(nfsv4,
        fi
        AC_SUBST(IDMAPD)
        AC_SUBST(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,
 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)
 
 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 *************************************************************
 dnl *************************************************************
 dnl Check for headers
 dnl *************************************************************
index 37b6359267dbe1a8cd777186e083d56339fa2367..aa56fa7fc4c66fff18b4d33f3557da61385d3367 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for linux-nfs/support
 #
 
 # 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
 .DEFAULT: all
 
 include $(TOP)rules.mk
diff --git a/support/gssapi/Makefile b/support/gssapi/Makefile
new file mode 100644 (file)
index 0000000..65271f0
--- /dev/null
@@ -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 (file)
index 0000000..8eca824
--- /dev/null
@@ -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 (file)
index 0000000..05e967b
--- /dev/null
@@ -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 <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+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 (file)
index 0000000..50087db
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#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; i<desired_mechs->count; 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 (file)
index 0000000..496d497
--- /dev/null
@@ -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 <stdlib.h>
+#endif
+#include <string.h>
+
+#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 (file)
index 0000000..13ae5c8
--- /dev/null
@@ -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 (file)
index 0000000..e9253c8
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 (file)
index 0000000..dcf1800
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..42cae0d
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 (file)
index 0000000..bb88813
--- /dev/null
@@ -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 <stdio.h>
+#include "mglueP.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+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 (file)
index 0000000..59d9e80
--- /dev/null
@@ -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 <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..cf2f76a
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#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
+     * <the rest of the token>
+     *
+     * Numerically, this looks like :
+     *
+     * 0x60
+     * <length> - could be multiple bytes
+     * 0x06
+     * <length> - assume only one byte, hence OID length < 127
+     * <mech OID bytes>
+     *
+     * 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 (file)
index 0000000..43f9c50
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+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 (file)
index 0000000..faa58ed
--- /dev/null
@@ -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 <stdio.h>
+#include <errno.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..9006d6d
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..a838597
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+#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 (file)
index 0000000..9523d40
--- /dev/null
@@ -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 <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef USE_SOLARIS_SHARED_LIBRARIES
+#include <dlfcn.h>
+
+#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 <dlfcn.h>
+#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 (file)
index 0000000..60f0e82
--- /dev/null
@@ -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 <stdlib.h>
+#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 (file)
index 0000000..6671f70
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+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 (file)
index 0000000..cfcb27d
--- /dev/null
@@ -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 (file)
index 0000000..4f0a013
--- /dev/null
@@ -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 <stdlib.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..1caa8d2
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  g_mit_krb5_mech.c
+ *
+ *  Copyright (c) 2004 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Kevin Coffman <kwc@umich.edu>
+ *
+ *  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 <stdio.h>
+#include <dlfcn.h>
+#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 (file)
index 0000000..da0d61a
--- /dev/null
@@ -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 <stdio.h>
+#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 (file)
index 0000000..322d597
--- /dev/null
@@ -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 (file)
index 0000000..c1104fd
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 (file)
index 0000000..27a6d82
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 (file)
index 0000000..ec5593a
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..90430c1
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#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 (file)
index 0000000..ebc8f2e
--- /dev/null
@@ -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 (file)
index 0000000..27c52a4
--- /dev/null
@@ -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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+
+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 (file)
index 0000000..fe3398c
--- /dev/null
@@ -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 (file)
index 0000000..c274e38
--- /dev/null
@@ -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 (file)
index 0000000..404a6ee
--- /dev/null
@@ -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 (file)
index 0000000..e06d60e
--- /dev/null
@@ -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 (file)
index 0000000..b390974
--- /dev/null
@@ -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 (file)
index 0000000..079ea93
--- /dev/null
@@ -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/gssapi.h>
+
+/********************************************************/
+/* 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 (file)
index 0000000..362b308
--- /dev/null
@@ -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 (file)
index 0000000..ed24d58
--- /dev/null
@@ -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 <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+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; i<set->count; i++) {
+       if ((set->elements[i].length == member->length) &&
+           !memcmp(set->elements[i].elements,
+                   member->elements,
+                   (size_t) member->length)) {
+           result = 1;
+           break;
+       }
+    }
+    *present = result;
+    *minor_status = 0;
+    return(GSS_S_COMPLETE);
+}
+
+/*
+ * OID<->string routines.  These are uuuuugly.
+ */
+OM_uint32
+generic_gss_oid_to_str(minor_status, oid, oid_str)
+    OM_uint32          *minor_status;
+    gss_OID            oid;
+    gss_buffer_t       oid_str;
+{
+    char               numstr[128];
+    unsigned long      number;
+    int                        numshift;
+    size_t             string_length;
+    size_t             i;
+    unsigned char      *cp;
+    char               *bp;
+
+    /* Decoded according to krb5/gssapi_krb5.c */
+
+    /* First determine the size of the string */
+    string_length = 0;
+    number = 0;
+    numshift = 0;
+    cp = (unsigned char *) oid->elements;
+    number = (unsigned long) cp[0];
+    sprintf(numstr, "%ld ", number/40);
+    string_length += strlen(numstr);
+    sprintf(numstr, "%ld ", number%40);
+    string_length += strlen(numstr);
+    for (i=1; i<oid->length; i++) {
+       if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
+           number = (number << 7) | (cp[i] & 0x7f);
+           numshift += 7;
+       }
+       else {
+           *minor_status = EINVAL;
+           return(GSS_S_FAILURE);
+       }
+       if ((cp[i] & 0x80) == 0) {
+           sprintf(numstr, "%ld ", number);
+           string_length += strlen(numstr);
+           number = 0;
+           numshift = 0;
+       }
+    }
+    /*
+     * If we get here, we've calculated the length of "n n n ... n ".  Add 4
+     * here for "{ " and "}\0".
+     */
+    string_length += 4;
+    if ((bp = (char *) malloc(string_length))) {
+       strcpy(bp, "{ ");
+       number = (unsigned long) cp[0];
+       sprintf(numstr, "%ld ", number/40);
+       strcat(bp, numstr);
+       sprintf(numstr, "%ld ", number%40);
+       strcat(bp, numstr);
+       number = 0;
+       cp = (unsigned char *) oid->elements;
+       for (i=1; i<oid->length; i++) {
+           number = (number << 7) | (cp[i] & 0x7f);
+           if ((cp[i] & 0x80) == 0) {
+               sprintf(numstr, "%ld ", number);
+               strcat(bp, numstr);
+               number = 0;
+           }
+       }
+       strcat(bp, "}");
+       oid_str->length = strlen(bp)+1;
+       oid_str->value = (void *) bp;
+       *minor_status = 0;
+       return(GSS_S_COMPLETE);
+    }
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
+OM_uint32
+generic_gss_str_to_oid(minor_status, oid_str, oid)
+    OM_uint32          *minor_status;
+    gss_buffer_t       oid_str;
+    gss_OID            *oid;
+{
+    char       *cp, *bp, *startp;
+    int                brace;
+    long       numbuf;
+    long       onumbuf;
+    OM_uint32  nbytes;
+    int                index;
+    unsigned char *op;
+
+    brace = 0;
+    bp = (char *) oid_str->value;
+    cp = bp;
+    /* Skip over leading space */
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+       bp++;
+    if (*bp == '{') {
+       brace = 1;
+       bp++;
+    }
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+       bp++;
+    startp = bp;
+    nbytes = 0;
+
+    /*
+     * The first two numbers are chewed up by the first octet.
+     */
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+       *minor_status = EINVAL;
+       return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+       bp++;
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+       bp++;
+    if (sscanf(bp, "%ld", &numbuf) != 1) {
+       *minor_status = EINVAL;
+       return(GSS_S_FAILURE);
+    }
+    while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+       bp++;
+    while ((bp < &cp[oid_str->length]) && isspace(*bp))
+       bp++;
+    nbytes++;
+    while (isdigit(*bp)) {
+       if (sscanf(bp, "%ld", &numbuf) != 1) {
+           *minor_status = EINVAL;
+           return(GSS_S_FAILURE);
+       }
+       while (numbuf) {
+           nbytes++;
+           numbuf >>= 7;
+       }
+       while ((bp < &cp[oid_str->length]) && isdigit(*bp))
+           bp++;
+       while ((bp < &cp[oid_str->length]) && isspace(*bp))
+           bp++;
+    }
+    if (brace && (*bp != '}')) {
+       *minor_status = EINVAL;
+       return(GSS_S_FAILURE);
+    }
+
+    /*
+     * Phew!  We've come this far, so the syntax is good.
+     */
+    if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
+       if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
+           (*oid)->length = nbytes;
+           op = (unsigned char *) (*oid)->elements;
+           bp = startp;
+           sscanf(bp, "%ld", &numbuf);
+           while (isdigit(*bp))
+               bp++;
+           while (isspace(*bp))
+               bp++;
+           onumbuf = 40*numbuf;
+           sscanf(bp, "%ld", &numbuf);
+           onumbuf += numbuf;
+           *op = (unsigned char) onumbuf;
+           op++;
+           while (isdigit(*bp))
+               bp++;
+           while (isspace(*bp))
+               bp++;
+           while (isdigit(*bp)) {
+               sscanf(bp, "%ld", &numbuf);
+               nbytes = 0;
+               /* Have to fill in the bytes msb-first */
+               onumbuf = numbuf;
+               while (numbuf) {
+                   nbytes++;
+                   numbuf >>= 7;
+               }
+               numbuf = onumbuf;
+               op += nbytes;
+               index = -1;
+               while (numbuf) {
+                   op[index] = (unsigned char) numbuf & 0x7f;
+                   if (index != -1)
+                       op[index] |= 0x80;
+                   index--;
+                   numbuf >>= 7;
+               }
+               while (isdigit(*bp))
+                   bp++;
+               while (isspace(*bp))
+                   bp++;
+           }
+           *minor_status = 0;
+           return(GSS_S_COMPLETE);
+       }
+       else {
+           free(*oid);
+           *oid = GSS_C_NO_OID;
+       }
+    }
+    *minor_status = ENOMEM;
+    return(GSS_S_FAILURE);
+}
+
index f8c14975924edfeab4ce0b16a849c904e39bd78f..6a6a06573f9821b2efea228b43972e8d1782135e 100644 (file)
  * but lockd from using this service.
  */
 #undef RESTRICTED_STATD
  * 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 (file)
index 0000000..18d62db
--- /dev/null
@@ -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 <TargetConditionals.h>
+    #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 <win-mac.h>
+#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 <stddef.h>
+#endif /* HAVE_STDDEF_H */
+
+/*
+ * POSIX says that sys/types.h is where size_t is defined.
+ */
+#ifndef macintosh
+#include <sys/types.h>
+#endif
+
+/*
+ * If the platform supports the xom.h header file, it should be included here.
+ */
+#if    HAVE_XOM_H
+#include <xom.h>
+#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_ */
index 2eeb93bba8780235b8cd5612e4088f3678165755..58c84f80632eb3861a1d4f52135e0ef41a9470dd 100644 (file)
@@ -1,7 +1,7 @@
 
 include        $(TOP)rules.mk
 
 
 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)
        @:
 
 all install::  $(LIBS)
        @:
diff --git a/support/rpc/DISCLAIMER b/support/rpc/DISCLAIMER
new file mode 100644 (file)
index 0000000..e5871a2
--- /dev/null
@@ -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 (file)
index 0000000..d678075
--- /dev/null
@@ -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 (file)
index 0000000..eb960e6
--- /dev/null
@@ -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 (file)
index 0000000..f41d678
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_gss.h>
+#include <rpc/clnt.h>
+#include <netinet/in.h>
+#include <gssapi/gssapi.h>
+
+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 = &num;
+       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 (file)
index 0000000..97724f1
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/auth_gss.h>
+#include <rpc/rpc.h>
+#include <gssapi/gssapi.h>
+
+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 <ctype.h>
+
+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 (file)
index 0000000..5924ce6
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#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 (file)
index 0000000..dc206b0
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  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 <rpc/clnt.h>
+#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 (file)
index 0000000..06cff5d
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+/* 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 (file)
index 0000000..4ac7be2
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+/*
+ * 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 (file)
index 0000000..f7aff55
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+__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 (file)
index 0000000..68f5474
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+#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 (file)
index 0000000..203813f
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+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 (file)
index 0000000..5b62519
--- /dev/null
@@ -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 <rpc/types.h>         /* some typedefs */
+#include <netinet/in.h>
+
+/* external data representation interfaces */
+#include <rpc/xdr.h>           /* generic (de)serializer */
+
+/* Client side only authentication */
+#include <rpc/auth.h>          /* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include <rpc/clnt.h>          /* generic rpc stuff */
+
+/* Client side (mostly) pmap functions */
+#include <rpc/pmap_clnt.h>     /* generic pmap stuff */
+
+/* semi-private protocol headers */
+#include <rpc/rpc_msg.h>       /* protocol for rpc messages */
+#include <rpc/auth_unix.h>     /* 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 <rpc/auth_des.h>      /* protocol for des style cred */
+#endif
+
+/* Server side only remote procedure callee */
+#include <rpc/svc_auth.h>      /* service side authenticator */
+#include <rpc/svc.h>           /* service manager and multiplexer */
+
+/*
+ * COMMENT OUT THE NEXT INCLUDE (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 <rpc/netdb.h> included in <netdb.h>.
+ */
+/* routines for parsing /etc/rpc */
+#ifdef __linux__
+#include <rpc/netdb.h>
+#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 (file)
index 0000000..597a473
--- /dev/null
@@ -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 (file)
index 0000000..63432d1
--- /dev/null
@@ -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 (file)
index 0000000..5c7c900
--- /dev/null
@@ -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 <sys/cdefs.h>
+
+/*
+ * 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 (file)
index 0000000..2a1b0cc
--- /dev/null
@@ -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 (file)
index 0000000..21f17d8
--- /dev/null
@@ -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 <sys/types.h>
+ */
+#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 <sys/types.h>
+#endif
+#include <sys/time.h>
+#include <sys/param.h>
+#include <stdlib.h>
+
+#endif /* !_RPC_TYPES_H */
diff --git a/support/rpc/include/rpc/xdr.h b/support/rpc/include/rpc/xdr.h
new file mode 100644 (file)
index 0000000..d293ea1
--- /dev/null
@@ -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 <sys/cdefs.h>
+#include <stdio.h>
+
+/*
+ * XDR provides a conventional way for converting between C data
+ * types and an external bit-string representation.  Library supplied
+ * routines provide for the conversion on built-in C data types.  These
+ * routines and utility routines defined here are used to help implement
+ * a type encode/decode routine for each user-defined type.
+ *
+ * Each data type provides a single procedure which takes two arguments:
+ *
+ *     bool_t
+ *     xdrproc(xdrs, argresp)
+ *             XDR *xdrs;
+ *             <type> *argresp;
+ *
+ * xdrs is an instance of a XDR handle, to which or from which the data
+ * type is to be converted.  argresp is a pointer to the structure to be
+ * converted.  The XDR handle contains an operation field which indicates
+ * which of the operations (ENCODE, DECODE * or FREE) is to be performed.
+ *
+ * XDR_DECODE may allocate space if the pointer argresp is null.  This
+ * data can be freed with the XDR_FREE operation.
+ *
+ * We write only one procedure per data type to make it easy
+ * to keep the encode and decode procedures for a data type consistent.
+ * In many cases the same code performs all operations on a user defined type,
+ * because all the hard work is done in the component type routines.
+ * decode as a series of calls on the nested data types.
+ */
+
+/*
+ * Xdr operations.  XDR_ENCODE causes the type to be encoded into the
+ * stream.  XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+       XDR_ENCODE=0,
+       XDR_DECODE=1,
+       XDR_FREE=2
+};
+
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT     (4)
+#define RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
+                   * BYTES_PER_XDR_UNIT)
+
+/*
+ * 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 (file)
index 0000000..24e7611
--- /dev/null
@@ -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 <rpc/rpc.h>
+/*
+ * 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 (file)
index 0000000..8e47d67
--- /dev/null
@@ -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 <stdlib.h>
+#include <string.h>
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+
+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 (file)
index 0000000..4a11be3
--- /dev/null
@@ -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 <rpc/rpc.h>
+
+/*
+ * 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 (file)
index 0000000..02153f9
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <gssapi/gssapi.h>
+
+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 "
+                                 "<mech %.*s, qop %d, svc %d>",
+                                 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 "
+                         "<mech {}, qop %d, svc %d>",
+                         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 = &num;
+       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 (file)
index 0000000..f1c6aa7
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  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 <rpc/rpc.h>
+
+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 (file)
index 0000000..4ff6b26
--- /dev/null
@@ -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 <stdio.h>
+#include <rpc/rpc.h>
+#include <string.h>
+
+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 (file)
index 0000000..f210abd
--- /dev/null
@@ -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 <stdlib.h>
+#include <rpc/rpc.h>
+
+
+/*
+ * This is the "network" that we will be moving data over
+ */
+static struct svcraw_private {
+       char    _raw_buf[UDPMSGSIZE];
+       SVCXPRT server;
+       XDR     xdr_stream;
+       char    verf_body[MAX_AUTH_BYTES];
+} *svcraw_private;
+
+static bool_t          svcraw_recv();
+static enum xprt_stat  svcraw_stat();
+static bool_t          svcraw_getargs();
+static bool_t          svcraw_reply();
+static bool_t          svcraw_freeargs();
+static void            svcraw_destroy();
+
+static struct xp_ops server_ops = {
+       svcraw_recv,
+       svcraw_stat,
+       svcraw_getargs,
+       svcraw_reply,
+       svcraw_freeargs,
+       svcraw_destroy
+};
+
+SVCXPRT *
+svcraw_create()
+{
+       register struct svcraw_private *srp = svcraw_private;
+
+       if (srp == 0) {
+               srp = (struct svcraw_private *)calloc(1, sizeof (*srp));
+               if (srp == 0)
+                       return (0);
+       }
+       srp->server.xp_sock = 0;
+       srp->server.xp_port = 0;
+       srp->server.xp_ops = &server_ops;
+       srp->server.xp_verf.oa_base = srp->verf_body;
+       xdrmem_create(&srp->xdr_stream, srp->_raw_buf, UDPMSGSIZE, XDR_FREE);
+       return (&srp->server);
+}
+
+static enum xprt_stat
+svcraw_stat()
+{
+
+       return (XPRT_IDLE);
+}
+
+/* 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 (file)
index 0000000..5f5c046
--- /dev/null
@@ -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 <rpc/rpc.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+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 (file)
index 0000000..b697c61
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+static struct proglst {
+       char *(*p_progname)();
+       int  p_prognum;
+       int  p_procnum;
+       xdrproc_t p_inproc, p_outproc;
+       struct proglst *p_nxt;
+} *proglst;
+static void universal();
+static SVCXPRT *transp;
+struct proglst *pl;
+
+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 (file)
index 0000000..6e6f785
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <rpc/rpc.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#ifndef __linux__
+#include <netinet/ip_var.h>
+#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 (file)
index 0000000..70a5217
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rpc/rpc.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+
+
+#define rpc_buffer(xprt) ((xprt)->xp_p1)
+#ifndef MAX
+#define MAX(a, b)     ((a > b) ? a : b)
+#endif
+
+static bool_t          svcudp_recv();
+static bool_t          svcudp_reply();
+static enum xprt_stat  svcudp_stat();
+static bool_t          svcudp_getargs();
+static bool_t          svcudp_freeargs();
+static void            svcudp_destroy();
+static void            cache_set __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);
+}
+
index 02bafbf2a55c3d2b60804665992b084853c65203..539632fdeef7ea5dff09a7ddc07b509c0be8ba63 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 SUBDIRS        = exportfs mountd nfsd statd nfsstat @RQUOTAD@ showmount \
 #
 
 SUBDIRS        = exportfs mountd nfsd statd nfsstat @RQUOTAD@ showmount \
-         nhfsstone lockd @IDMAPD@
+         nhfsstone lockd @IDMAPD@ @GSSD@ @SVCGSSD@
 
 include $(TOP)rules.mk
 
 
 include $(TOP)rules.mk
 
diff --git a/utils/gssd/Makefile b/utils/gssd/Makefile
new file mode 100644 (file)
index 0000000..6eba0f5
--- /dev/null
@@ -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 (file)
index 0000000..08979f3
--- /dev/null
@@ -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 <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#ifdef HAVE_KRB5
+#include <krb5.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/auth_gss.h>
+#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 <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+
+#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 (file)
index 0000000..d896bd0
--- /dev/null
@@ -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 <rpc/rpc.h>
+
+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 (file)
index 0000000..27c44a3
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <errno.h>
+#include <gssapi.h>
+#include <krb5.h>
+#include <com_err.h>
+#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 (file)
index 0000000..ca9b028
--- /dev/null
@@ -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 <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <string.h>
+#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 (file)
index 0000000..5e5af48
--- /dev/null
@@ -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 (file)
index 0000000..5260b53
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2004 Bruce Fields <bfields@umich.edu>
+
+  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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <fcntl.h>
+
+#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 (file)
index 0000000..666bdd9
--- /dev/null
@@ -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 (file)
index 0000000..e800115
--- /dev/null
@@ -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 <sys/types.h>
+#include <gssapi/gssapi.h>
+
+/* 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 (file)
index 0000000..850c013
--- /dev/null
@@ -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 <sys/types.h>
+#include <gssapi/gssapi.h>
+
+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 (file)
index 0000000..3493280
--- /dev/null
@@ -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 <andros@umich.edu>
+ *  J. Bruce Fields <bfields@umich.edu>
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ */
+
+/*
+ * 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 <errno.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <gssapi/gssapi.h>
+#include "gss_util.h"
+#include "err_util.h"
+#include "gssd.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#ifdef HAVE_COM_ERR_H
+#include <com_err.h>
+#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 (file)
index 0000000..9e480ac
--- /dev/null
@@ -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 <stdlib.h>
+#include <rpc/rpc.h>
+#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 (file)
index 0000000..0f7a7e5
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+  gssd.c
+
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>.
+  Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
+  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 <sys/param.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#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 (file)
index 0000000..d590401
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/queue.h>
+#include <gssapi/gssapi.h>
+
+#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 (file)
index 0000000..d8f9a0f
--- /dev/null
@@ -0,0 +1,63 @@
+.\"
+.\" rpc.gssd(8)
+.\"
+.\" Copyright (C) 2003 J. Bruce Fields <bfields@umich.edu>
+.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 <dugsong@umich.edu>
+.br
+Andy Adamson <andros@umich.edu>
+.br
+Marius Aamodt Eriksen <marius@umich.edu>
+.br
+J. Bruce Fields <bfields@umich.edu>
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
new file mode 100644 (file)
index 0000000..a086bb3
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..1e7ebae
--- /dev/null
@@ -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 <dugsong@UMICH.EDU>.
+  Copyright (c) 2001 Andy Adamson <andros@UMICH.EDU>.
+  Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
+  Copyright (c) 2002 Bruce Fields <bfields@UMICH.EDU>
+  Copyright (c) 2004 Kevin Coffman <kwc@umich.edu>
+  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 <sys/param.h>
+#include <rpc/rpc.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <dirent.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <gssapi/gssapi.h>
+#include <netdb.h>
+
+#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; i<FD_ALLOC_BLOCK; i++) {
+               if (pollarray[i].events == 0) {
+                       *ind = i;
+                       break;
+               }
+       }
+       if (*ind == -1) {
+               printerr(0, "ERROR: No pollarray slots open\n");
+               return -1;
+       }
+       return 0;
+}
+
+static void
+process_clnt_dir(char *dir)
+{
+       struct clnt_info *      clp;
+
+       if (!(clp = insert_new_clnt()))
+               goto fail_destroy_client;
+
+       if (!(clp->dirname = 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 (file)
index 0000000..2dcc2ee
--- /dev/null
@@ -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 <andros@umich.edu>
+ *  J. Bruce Fields <bfields@umich.edu>
+ *  Marius Aamodt Eriksen <marius@umich.edu>
+ *  Kevin Coffman <kwc@umich.edu>
+ */
+
+/*
+ * 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 <sys/param.h>
+#include <rpc/rpc.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <time.h>
+#include <gssapi/gssapi.h>
+#ifdef USE_PRIVATE_KRB5_FUNCTIONS
+#include <gssapi/gssapi_krb5.h>
+#endif
+#include <krb5.h>
+#include <rpc/auth_gss.h>
+
+#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 : "<unparsable>", 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/<your.host>@<YOUR.REALM> 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 (file)
index 0000000..da04530
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef KRB5_UTIL_H
+#define KRB5_UTIL_H
+
+#include <krb5.h>
+
+/*
+ * 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 (file)
index 0000000..ba00598
--- /dev/null
@@ -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 <stdlib.h>
+#include <sys/types.h>
+#include <netinet/in.h>                /* 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 (file)
index 0000000..266e9de
--- /dev/null
@@ -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 (file)
index 0000000..ed3fa98
--- /dev/null
@@ -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 (file)
index 0000000..ac76c06
--- /dev/null
@@ -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 <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#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 (file)
index 0000000..cc97b36
--- /dev/null
@@ -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 <stdio.h>
+
+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 (file)
index 0000000..9dd5a3a
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+  gssd.c
+
+  Copyright (c) 2000 The Regents of the University of Michigan.
+  All rights reserved.
+
+  Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>.
+  Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>.
+  Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>.
+  Copyright (c) 2002 J. Bruce Fields <bfields@UMICH.EDU>.
+  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 <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <fcntl.h>
+#include <errno.h>
+
+
+#include <unistd.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#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/<your.host>@<YOUR.REALM> 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 (file)
index 0000000..9a2e2e8
--- /dev/null
@@ -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 <sys/types.h>
+#include <sys/queue.h>
+#include <gssapi/gssapi.h>
+
+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 (file)
index 0000000..f17f772
--- /dev/null
@@ -0,0 +1,41 @@
+.\"
+.\" rpc.svcgssd(8)
+.\"
+.\" Copyright (C) 2003 J. Bruce Fields <bfields@umich.edu>
+.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 <dugsong@umich.edu>
+.br
+Andy Adamson <andros@umich.edu>
+.br
+Marius Aamodt Eriksen <marius@umich.edu>
+.br
+J. Bruce Fields <bfields@umich.edu>
diff --git a/utils/svcgssd/svcgssd_main_loop.c b/utils/svcgssd/svcgssd_main_loop.c
new file mode 100644 (file)
index 0000000..477a44c
--- /dev/null
@@ -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 <sys/param.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+
+#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 (file)
index 0000000..f44f7c6
--- /dev/null
@@ -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 <andros@UMICH.EDU>.
+  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 <gssapi/gssapi_generic.h>
+#elif HAVE_HEIMDAL
+#include <gssapi.h>
+#endif
+#include <string.h>
+
+
+#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 (file)
index 0000000..c2470c6
--- /dev/null
@@ -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 <bfields@UMICH.EDU>
+
+  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 <sys/param.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+
+#include <pwd.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#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;
+}