]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Merge commit 'debian/1.0.7-2'
authorBen Hutchings <ben@decadent.org.uk>
Tue, 13 Jul 2010 03:03:30 +0000 (04:03 +0100)
committerBen Hutchings <ben@decadent.org.uk>
Tue, 13 Jul 2010 03:03:30 +0000 (04:03 +0100)
Conflicts:
debian/changelog

160 files changed:
ChangeLog
README
config.guess
config.mk.in
config.sub
configure
configure.in
debian/gssapi_mech.conf [new file with mode: 0644]
debian/idmapd.conf [new file with mode: 0644]
debian/nfs-common.install [new file with mode: 0644]
etc/nodist/nfs-client [deleted file]
etc/nodist/nfs-functions [deleted file]
etc/nodist/nfs-server [deleted file]
etc/redhat/nfs [deleted file]
etc/redhat/nfs.init [deleted file]
etc/redhat/nfslock.init [deleted file]
nfs-utils.spec [deleted file]
nfs-utils.spec.in [deleted file]
support/Makefile
support/export/client.c
support/export/nfsctl.c
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/exportfs.h
support/include/gssapi/gssapi.h [new file with mode: 0644]
support/include/ha-callout.h [new file with mode: 0644]
support/include/nfslib.h
support/include/xlog.h
support/lib/Makefile
support/nfs/cacheio.c
support/nfs/exports.c
support/nfs/xlog.c
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]
tools/rpcdebug/Makefile
tools/rpcdebug/rpcdebug.c
utils/Makefile.in
utils/exportfs/exportfs.c
utils/exportfs/exports.man
utils/exportfs/nfsd.man
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/idmapd/Makefile [new file with mode: 0644]
utils/idmapd/atomicio.c [new file with mode: 0644]
utils/idmapd/cfg.c [new file with mode: 0644]
utils/idmapd/cfg.h [new file with mode: 0644]
utils/idmapd/idmapd.c [new file with mode: 0644]
utils/idmapd/idmapd.conf [new file with mode: 0644]
utils/idmapd/idmapd.conf.man [new file with mode: 0644]
utils/idmapd/idmapd.man [new file with mode: 0644]
utils/idmapd/nfs_idmap.h [new file with mode: 0644]
utils/idmapd/queue.h [new file with mode: 0644]
utils/idmapd/setproctitle.c [new file with mode: 0644]
utils/idmapd/strlcat.c [new file with mode: 0644]
utils/idmapd/strlcpy.c [new file with mode: 0644]
utils/lockd/lockd.man
utils/mountd/auth.c
utils/mountd/cache.c
utils/mountd/mountd.c
utils/mountd/mountd.man
utils/mountd/rmtab.c
utils/statd/monitor.c
utils/statd/rmtcall.c
utils/statd/statd.c
utils/statd/statd.h
utils/statd/statd.man
utils/statd/svc_run.c
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 98893a178254d271f65511755d5bfb09aa3d70ef..a8ca3511dc5f20c7640b0c507840209a1c15feb6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,197 @@
+2005-04-07  Chip Salzenberg  <chip@pobox.com>
+
+       * debian/changelog: Version 1.0.7-2.
+
+2005-04-06  Chip Salzenberg  <chip@pobox.com>
+
+       * config.guess, config.sub: Update.
+
+       * support/rpc/svc_auth_gss.c (_svcauth_gss): Avoid using a cast as
+       an lvalue, as it is non-portable.
+
+       * support/nfs/exports.c (parseopts): Accept "acl" option to mean
+       ~NFSEXP_NOACL, and "no_acl" to mean NFSEXP_NOACL.
+       (putexportent): Report NFSEXP_NOACL as "no_acl", and ~NFSEXP_NOACL
+       as "acl".
+       * utils/exportfs/exportfs.c (dump): Report NFSEXP_NOACL as
+       "no_acl".
+       * utils/exportfs/exports.man: Document "no_acl".
+
+2005-03-14  NeilBrown <neilb@cse.unsw.edu.au>
+       Denis Vlasenko <vda@ilport.com.ua>
+       * support/export/client.c(client_init and client_gettype):
+       treat N.N.N.N as a special case of MCL_SUBNETWORK instead of 
+       MCL_FQDN
+
+2005-03-06  G. Allen Morris III <gam3@gam3.net>
+       * support/nfs/cacheio.c(readline): Could not read lines greater
+       than 128 bytes. [1157791] 
+       * utils/exportfs/exports.man: Added a SEE ALSO section and
+       fixed 2 typos. [1018450]
+
+2005-02-28  Trond Myklebust <trond.myklebust@fys.uio.no>
+       * utils/statd/rmtcall.c(statd_get_socket): If a port number is
+       explicitly given, make sure to try to bind to that.
+       
+2005-01-11  Chip Salzenberg  <chip@pobox.com>
+
+       * debian/changelog: Version 1.0.7-1.
+       * debian/nfs-common.default (NEED_IDMAPD, NEED_GSSD):
+       Disable by default, on advice of upstream.
+       * debian/nfs-kernel-server.default (NEED_SVCGSSD):
+       Likewise.
+
+       * utils/svcgssd/Makefile (predep): Symbolically link duplicated
+       source files.
+       (distclean): Remove symlinks to duplicated files.
+
+2004-12-17 NeilBrown <neilb@cse.unsw.edu.au>
+       Release 1.0.7
+
+       * config.mk, configure.in: update version number, run autoconf
+       * configure.in: require nfsidmap.h if gss is enabled.
+       
+2004-12-10 NeilBrown <neilb@cse.unsw.edu.au>
+       Release 1.0.7-pre2
+       
+       * config.mk, configure.in: update version number, run autoconf
+       
+2004-12-10 Neil Brown <neilb@cse.unsw.edu.au>
+       * README : note dependancy on kerberos, libevent, and nfsidmap
+       * configure.in : fail if --enable-nfsv4 and libevent or
+       libnfsidmap are missing.
+       * configuyre.in: improve message if krb5 support is missing
+       
+2004-12-06 Paul Clements <paul.clements@steeleye.com>  
+       * support/include/ha-callout.h: get return status from waitpid
+       correctly. 
+       * support/include/ha-callout.h: don't ignore SIGCHLD while waiting
+       for a callout to complete.
+       * utils/statd/statd.c(sigusr): print current start when re-reading
+       notify list due to SIGUSR1
+       * utils/statd/svc_run.c(my_svc_run): call change_state when
+       re-notifying clients.
+       
+2004-12-06 Marc Eshel <eshel@almaden.ibm.com>
+       * utils/statd/svc_run.c(my_svc_run): allow loop to exit when in
+       MODE_NOTIFY_ONLY
+       *utils/statd/rmtcall.c(statd_get_socket): if a hostname is given
+       to statd with -n, prefer it's IP address to the default for
+       listening on.
+       
+2004-12-06 Bruce Allan <bwa@us.ibm.com>
+       * utils/mountd/auth.c(auth_reload)  Clear the "my_client" cache on
+       an auth_reload to avoid old data getting used.
+       
+2004-12-03 NeilBrown <neilb@cse.unsw.edu.au>
+       Release 1.0.7-pre1 for testing
+       
+       * config.mk, configure.in: update version number, run autoconf
+       
+2004-12-03 Trond Myklebust <trond.myklebust@fys.uio.no>
+
+       * utils/statd/statd.c(main): ignore SIGPIPE
+       
+2004-11-22 "J. Bruce Fields" <bfields@fieldses.org>
+
+       * tools/rpcdebug/rpcdebug.c: support aliases "nfsdebug" and
+       "nfsddebug" and update flag names.
+       * configure.in, nodist/* redhat/* nfs-utils.spec*: remove redhat
+       specific files (as no-one actually uses them, especially not
+       redhat), and the nodist /etc files (as they drift out-of-date, and
+       the debian directory provides a suitable example.
+       * utils/svcgssd_proc.c(get_ids): fix memory leak
+       * utils/svcgssd/svcgssd_proc.c: Rely on count of the number of
+       groups instead of using a special guard value to identify the end
+       of the list. 
+       * utils/idmapd/idmapd.c: don't allow Default domain and anon-uid
+       or -gid to be specified on command line.
+       * utils/idmapd/idmapd.c: improve error messages
+       * utils/idmapd/idmapd.c: Reopen nfsd files on sighup.  Allows us
+       to start up client side only (even when nfsd module not loaded),
+       and then sighup later after insmodding nfsd module. 
+       * utils/idmapd/idmapd.c: Make sure we catch all errors on
+       daemonizing by waiting for child to report succesfull startup
+       using a pipe. 
+       * utils/idmapd/idmapd.c: Let libnfsidmapd parse the idmapd.conf
+       file for the default domain, instead of doing that ourselves.
+       * utils/gssd/gssd_proc.c: Make sure we get an error when a gssd
+       downcall fails. 
+       * utils/gssd/gssd_proc.c: We were forgetting to restore the euid
+       on certain failures, which meant gssd could get stuck in a state
+       where it didn't have permissions to read the files in rpc_pipefs
+       that it needed to. 
+       * utils/gssd/gssd_proc.c: Use libnfsidmapd to map gss principals
+       to uids. 
+       * debian/nfs-kernel-server.default: Document the NEED_SVCGSSD
+       variable in /etc/default/nfs-kernel-server. 
+
+       
+2004-11-22 NeilBrown <neilb@cse.unsw.edu.au>
+
+       * utils/exportfs/nfsd.man: corrected typo in .BR macro usage -
+       reported by Eric Raymond
+       
+2004-10-19 "J. Bruce Fields" <bfields@fieldses.org>
+
+       * support/gssapi/* support/rpc/* utils/gssd/* utils/svcgssd/* etc
+       initial support for GSSAPI authentication
+       
+2004-09-15 Neil Brown <neilb@cse.unsw.edu.au>
+
+       * utils/statd/monitor.c(sm_unmon_1_svc): is RESTRICTED_STATD, then
+       check IP address and force my_name to 127.0.0.1 to match 
+       what happens in sm_mon_1_svc.  This avoid spurious "erroneous
+       SM_UNMON" messages.
+       * utils/statd.monitor.c(sm_unmon_all_1_svc): likewise
+       
+2004-09-15 "J. Bruce Fields" <bfields@fieldses.org>    
+
+       * Assorted changes to support "gss/*" style authentication
+       * utils/idmapd: new idmapd daemon for nfsv4 username lookup
+       
+2004-09-06 Trond Myklebust <trond.myklebust@fys.uio.no>
+       Neil Brown <neilb@cse.unsw.edu.au>
+
+       * utils/mountd/auth.c(auth_authenticate_internal): fix
+       uninitialsed variable problem (causes bad error messages).
+
+2004-09-06 Paul Clements <paul.clements@steeleye.com>
+       Neil Brown <neilb@cse.unsw.edu.au>
+
+       * utils/mountd/mountd.c(main): support --ha-callout (-H) for
+       specifying a callout program
+       * utils/mountd/rmtab.c: Call ha_callout on mount/unmount
+       * utils/statd/monitor.c: Call ha_callout on add/del client
+       * utils/statd/rmtcall.c: as above
+       * utils/statd/statd.c: handle --ha-callout (-H)
+       * utils/statd/svc_run.c: call notify_hosts is we have received a
+       sighup
+       * support/include/ha-callout.h: define ha_callout function
+        
+       
+2004-08-31 NeilBrown <neilb@cse.unsw.edu.au>
+       * utils/mountd/cache.c(cache_process_req): clear fd after
+       processing so as not to confused libc/sunrpc into thinking
+       it need to do something with that fd.
+       
+2004-08-31 NeilBrown <neilb@cse.unsw.edu.au>
+
+       * debian/nfs-kernel-server.init(start,stop) mount the nfsd
+       filesystem, if available, before starting nfs services, and 
+       unmount it afterwards.
+       * etc/nodist/nfs-server: ditto
+       * etc/redhat/nfs.init: likewise
+       * etc/redhat/nfs: add "MOUNT_NFSD" flag to control above.
+       
+2004-06-08 NeilBrown <neilb@cse.unsw.edu.au>
+
+       * utils/exportfs/exportfs.c: Don't rmtab_read if new_cache, it
+         isn't necessary.
+       * support/nfs/cacheio.c(cache_flush): Change order in which caches
+         are flushed so that dependancies don't keep things in the cache
+         too long.
+       
 2004-03-18  Chip Salzenberg  <chip@pobox.com>
 
        * debian/changelog: Version 1.0.6-2.
diff --git a/README b/README
index 502c6731669e0dd6773c6beb74617a4cb661aefe..3fa3a58587329235ad928e694e7ec61f5f7564ec 100644 (file)
--- a/README
+++ b/README
@@ -5,6 +5,16 @@ This is version 1.0.1 of nfs-utils, the Linux NFS utility package.
 
 Home page:  http://sourceforge.net/projects/nfs/
 
+To use the 'gss' support you must have kerberos-5 development 
+libraries installed.
+Otherwise use  "--disable-gss"
+
+To use nfsv4 support you need libevent and libnfsidmap development
+libraries.  They are available from 
+   http://www.monkey.org/~provos/libevent/
+   http://www.citi.umich.edu/projects/nfsv4/linux/libnfsidmap/
+Otherwise use --disable-nfsv4
+
 
 1. COMPILING WITHOUT PACKAGE MANAGEMENT
 
index 71de137a6b6cb605f3e1758c87936e62eb542021..9c292ea45b88464ed079d493a7a932cd59d3a09a 100755 (executable)
@@ -1,9 +1,9 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-#   Free Software Foundation, Inc.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
-timestamp='2001-03-16'
+timestamp='2005-03-24'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -24,8 +24,9 @@ timestamp='2001-03-16'
 # configuration script generated by Autoconf, you may include it under
 # the same distribution terms that you use for the rest of that program.
 
-# Written by Per Bothner <bothner@cygnus.com>.
-# Please send patches to <config-patches@gnu.org>.
+# Originally written by Per Bothner <per@bothner.com>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
@@ -52,7 +53,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
@@ -87,33 +88,45 @@ if test $# != 0; then
   exit 1
 fi
 
+trap 'exit 1' 1 2 15
 
-dummy=dummy-$$
-trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
 
-# CC_FOR_BUILD -- compiler used by this script.
 # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
 # use `HOST_CC' if defined, but it is deprecated.
 
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
 case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,)    echo "int dummy(){}" > $dummy.c
-       for c in cc gcc c89 ; do
-         ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1
-         if test $? = 0 ; then
-            CC_FOR_BUILD="$c"; break
-         fi
-       done
-       rm -f $dummy.c $dummy.o $dummy.rel
+ ,,)    echo "int x;" > $dummy.c ;
+       for c in cc gcc c89 c99 ; do
+         if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+            CC_FOR_BUILD="$c"; break ;
+         fi ;
+       done ;
        if test x"$CC_FOR_BUILD" = x ; then
-         CC_FOR_BUILD=no_compiler_found
+         CC_FOR_BUILD=no_compiler_found ;
        fi
        ;;
  ,,*)   CC_FOR_BUILD=$CC ;;
  ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-esac
+esac ;'
 
 # This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
+# (ghazi@noc.rutgers.edu 1994-08-24)
 if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
        PATH=$PATH:/.attbin ; export PATH
 fi
@@ -127,29 +140,31 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:NetBSD:*:*)
-       # Netbsd (nbsd) targets should (where applicable) match one or
+       # NetBSD (nbsd) targets should (where applicable) match one or
        # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
        # *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
        # switched to ELF, *-*-netbsd* would select the old
        # object file format.  This provides both forward
        # compatibility and a consistent mechanism for selecting the
        # object file format.
-       # Determine the machine/vendor (is the vendor relevant).
-       case "${UNAME_MACHINE}" in
-           amiga) machine=m68k-unknown ;;
-           arm32) machine=arm-unknown ;;
-           atari*) machine=m68k-atari ;;
-           sun3*) machine=m68k-sun ;;
-           mac68k) machine=m68k-apple ;;
-           macppc) machine=powerpc-apple ;;
-           hp3[0-9][05]) machine=m68k-hp ;;
-           ibmrt|romp-ibm) machine=romp-ibm ;;
-           *) machine=${UNAME_MACHINE}-unknown ;;
+       #
+       # Note: NetBSD doesn't particularly care about the vendor
+       # portion of the name.  We always set it to "unknown".
+       sysctl="sysctl -n hw.machine_arch"
+       UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+           /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+       case "${UNAME_MACHINE_ARCH}" in
+           armeb) machine=armeb-unknown ;;
+           arm*) machine=arm-unknown ;;
+           sh3el) machine=shl-unknown ;;
+           sh3eb) machine=sh-unknown ;;
+           *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
        esac
        # The Operating System including object format, if it has switched
        # to ELF recently, or will in the future.
-       case "${UNAME_MACHINE}" in
-           i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+       case "${UNAME_MACHINE_ARCH}" in
+           arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+               eval $set_cc_for_build
                if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
                        | grep __ELF__ >/dev/null
                then
@@ -165,70 +180,123 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
                ;;
        esac
        # The OS release
-       release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+       # Debian GNU/NetBSD machines have a different userland, and
+       # thus, need a distinct triplet. However, they do not need
+       # kernel version information, so it can be replaced with a
+       # suitable tag, in the style of linux-gnu.
+       case "${UNAME_VERSION}" in
+           Debian*)
+               release='-gnu'
+               ;;
+           *)
+               release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+               ;;
+       esac
        # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
        # contains redundant information, the shorter form:
        # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
        echo "${machine}-${os}${release}"
        exit 0 ;;
+    amd64:OpenBSD:*:*)
+       echo x86_64-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    amiga:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    cats:OpenBSD:*:*)
+       echo arm-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    hp300:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    luna88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mac68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme68k:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvme88k:OpenBSD:*:*)
+       echo m88k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    mvmeppc:OpenBSD:*:*)
+       echo powerpc-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sgi:OpenBSD:*:*)
+       echo mips64-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    sun3:OpenBSD:*:*)
+       echo m68k-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:OpenBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:ekkoBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+       exit 0 ;;
+    macppc:MirBSD:*:*)
+       echo powerppc-unknown-mirbsd${UNAME_RELEASE}
+       exit 0 ;;
+    *:MirBSD:*:*)
+       echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+       exit 0 ;;
     alpha:OSF1:*:*)
-       if test $UNAME_RELEASE = "V4.0"; then
+       case $UNAME_RELEASE in
+       *4.0)
                UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
-       fi
+               ;;
+       *5.*)
+               UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+               ;;
+       esac
+       # According to Compaq, /usr/sbin/psrinfo has been available on
+       # OSF/1 and Tru64 systems produced since 1995.  I hope that
+       # covers most systems running today.  This code pipes the CPU
+       # types through head -n 1, so we only detect the type of CPU 0.
+       ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+       case "$ALPHA_CPU_TYPE" in
+           "EV4 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "EV4.5 (21064)")
+               UNAME_MACHINE="alpha" ;;
+           "LCA4 (21066/21068)")
+               UNAME_MACHINE="alpha" ;;
+           "EV5 (21164)")
+               UNAME_MACHINE="alphaev5" ;;
+           "EV5.6 (21164A)")
+               UNAME_MACHINE="alphaev56" ;;
+           "EV5.6 (21164PC)")
+               UNAME_MACHINE="alphapca56" ;;
+           "EV5.7 (21164PC)")
+               UNAME_MACHINE="alphapca57" ;;
+           "EV6 (21264)")
+               UNAME_MACHINE="alphaev6" ;;
+           "EV6.7 (21264A)")
+               UNAME_MACHINE="alphaev67" ;;
+           "EV6.8CB (21264C)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8AL (21264B)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.8CX (21264D)")
+               UNAME_MACHINE="alphaev68" ;;
+           "EV6.9A (21264/EV69A)")
+               UNAME_MACHINE="alphaev69" ;;
+           "EV7 (21364)")
+               UNAME_MACHINE="alphaev7" ;;
+           "EV7.9 (21364A)")
+               UNAME_MACHINE="alphaev79" ;;
+       esac
+       # A Pn.n version is a patched version.
        # A Vn.n version is a released version.
        # A Tn.n version is a released field test version.
        # A Xn.n version is an unreleased experimental baselevel.
        # 1.2 uses "1.2" for uname -r.
-       cat <<EOF >$dummy.s
-       .data
-\$Lformat:
-       .byte 37,100,45,37,120,10,0     # "%d-%x\n"
-
-       .text
-       .globl main
-       .align 4
-       .ent main
-main:
-       .frame \$30,16,\$26,0
-       ldgp \$29,0(\$27)
-       .prologue 1
-       .long 0x47e03d80 # implver \$0
-       lda \$2,-1
-       .long 0x47e20c21 # amask \$2,\$1
-       lda \$16,\$Lformat
-       mov \$0,\$17
-       not \$1,\$18
-       jsr \$26,printf
-       ldgp \$29,0(\$26)
-       mov 0,\$16
-       jsr \$26,exit
-       .end main
-EOF
-       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               case `./$dummy` in
-                       0-0)
-                               UNAME_MACHINE="alpha"
-                               ;;
-                       1-0)
-                               UNAME_MACHINE="alphaev5"
-                               ;;
-                       1-1)
-                               UNAME_MACHINE="alphaev56"
-                               ;;
-                       1-101)
-                               UNAME_MACHINE="alphapca56"
-                               ;;
-                       2-303)
-                               UNAME_MACHINE="alphaev6"
-                               ;;
-                       2-307)
-                               UNAME_MACHINE="alphaev67"
-                               ;;
-               esac
-       fi
-       rm -f $dummy.s $dummy
-       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+       echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
        exit 0 ;;
     Alpha\ *:Windows_NT*:*)
        # How do we know it's Interix rather than the generic POSIX subsystem?
@@ -242,33 +310,21 @@ EOF
     Amiga*:UNIX_System_V:4.0:*)
        echo m68k-unknown-sysv4
        exit 0;;
-    amiga:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
     *:[Aa]miga[Oo][Ss]:*:*)
        echo ${UNAME_MACHINE}-unknown-amigaos
        exit 0 ;;
-    arc64:OpenBSD:*:*)
-       echo mips64el-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    arc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    hkmips:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    pmax:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    sgi:OpenBSD:*:*)
-       echo mips-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    wgrisc:OpenBSD:*:*)
-       echo mipsel-unknown-openbsd${UNAME_RELEASE}
+    *:[Mm]orph[Oo][Ss]:*:*)
+       echo ${UNAME_MACHINE}-unknown-morphos
        exit 0 ;;
     *:OS/390:*:*)
        echo i370-ibm-openedition
        exit 0 ;;
+    *:z/VM:*:*)
+       echo s390-ibm-zvmoe
+       exit 0 ;;
+    *:OS400:*:*)
+        echo powerpc-ibm-os400
+       exit 0 ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
        echo arm-acorn-riscix${UNAME_RELEASE}
        exit 0;;
@@ -286,6 +342,13 @@ EOF
     NILE*:*:*:dcosx)
        echo pyramid-pyramid-svr4
        exit 0 ;;
+    DRS?6000:unix:4.0:6*)
+       echo sparc-icl-nx6
+       exit 0 ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+       case `/usr/bin/uname -p` in
+           sparc) echo sparc-icl-nx7 && exit 0 ;;
+       esac ;;
     sun4H:SunOS:5.*:*)
        echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit 0 ;;
@@ -314,7 +377,7 @@ EOF
        echo m68k-sun-sunos${UNAME_RELEASE}
        exit 0 ;;
     sun*:*:4.2BSD:*)
-       UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+       UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
        test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
        case "`/bin/arch`" in
            sun3)
@@ -328,9 +391,6 @@ EOF
     aushp:SunOS:*:*)
        echo sparc-auspex-sunos${UNAME_RELEASE}
        exit 0 ;;
-    atari*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
     # The situation for MiNT is a little confusing.  The machine name
     # can be virtually everything (everything which is not
     # "atarist" or "atariste" at least should have a processor
@@ -357,17 +417,8 @@ EOF
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
         echo m68k-unknown-mint${UNAME_RELEASE}
         exit 0 ;;
-    sun3*:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mac68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme68k:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
-       exit 0 ;;
-    mvme88k:OpenBSD:*:*)
-       echo m88k-unknown-openbsd${UNAME_RELEASE}
+    m68k:machten:*:*)
+       echo m68k-apple-machten${UNAME_RELEASE}
        exit 0 ;;
     powerpc:machten:*:*)
        echo powerpc-apple-machten${UNAME_RELEASE}
@@ -385,6 +436,7 @@ EOF
        echo clipper-intergraph-clix${UNAME_RELEASE}
        exit 0 ;;
     mips:*:*:UMIPS | mips:*:*:RISCos)
+       eval $set_cc_for_build
        sed 's/^        //' << EOF >$dummy.c
 #ifdef __cplusplus
 #include <stdio.h>  /* for printf() prototype */
@@ -406,12 +458,20 @@ EOF
          exit (-1);
        }
 EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy \
-         && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
-         && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
+       $CC_FOR_BUILD -o $dummy $dummy.c \
+         && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+         && exit 0
        echo mips-mips-riscos${UNAME_RELEASE}
        exit 0 ;;
+    Motorola:PowerMAX_OS:*:*)
+       echo powerpc-motorola-powermax
+       exit 0 ;;
+    Motorola:*:4.3:PL8-*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+       echo powerpc-harris-powermax
+       exit 0 ;;
     Night_Hawk:Power_UNIX:*:*)
        echo powerpc-harris-powerunix
        exit 0 ;;
@@ -459,7 +519,7 @@ EOF
     ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
        echo romp-ibm-aix      # uname -m gives an 8 hex-code CPU id
        exit 0 ;;              # Note that: echo "'`uname -s`'" gives 'AIX '
-    i?86:AIX:*:*)
+    i*86:AIX:*:*)
        echo i386-ibm-aix
        exit 0 ;;
     ia64:AIX:*:*)
@@ -472,6 +532,7 @@ EOF
        exit 0 ;;
     *:AIX:2:3)
        if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+               eval $set_cc_for_build
                sed 's/^                //' << EOF >$dummy.c
                #include <sys/systemcfg.h>
 
@@ -483,8 +544,7 @@ EOF
                        exit(0);
                        }
 EOF
-               $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
-               rm -f $dummy.c $dummy
+               $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
                echo rs6000-ibm-aix3.2.5
        elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
                echo rs6000-ibm-aix3.2.4
@@ -493,7 +553,7 @@ EOF
        fi
        exit 0 ;;
     *:AIX:*:[45])
-       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+       IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
        if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
                IBM_ARCH=rs6000
        else
@@ -533,10 +593,8 @@ EOF
            9000/31? )            HP_ARCH=m68000 ;;
            9000/[34]?? )         HP_ARCH=m68k ;;
            9000/[678][0-9][0-9])
-              case "${HPUX_REV}" in
-                11.[0-9][0-9])
-                  if [ -x /usr/bin/getconf ]; then
-                    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+               if [ -x /usr/bin/getconf ]; then
+                   sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
                     sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
                     case "${sc_cpu_version}" in
                       523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
@@ -545,12 +603,13 @@ EOF
                         case "${sc_kernel_bits}" in
                           32) HP_ARCH="hppa2.0n" ;;
                           64) HP_ARCH="hppa2.0w" ;;
+                         '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
                         esac ;;
                     esac
-                  fi ;;
-              esac
-              if [ "${HP_ARCH}" = "" ]; then
-              sed 's/^              //' << EOF >$dummy.c
+               fi
+               if [ "${HP_ARCH}" = "" ]; then
+                   eval $set_cc_for_build
+                   sed 's/^              //' << EOF >$dummy.c
 
               #define _HPUX_SOURCE
               #include <stdlib.h>
@@ -583,11 +642,21 @@ EOF
                   exit (0);
               }
 EOF
-       (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null ) && HP_ARCH=`./$dummy`
-       if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
-       rm -f $dummy.c $dummy
-       fi ;;
+                   (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+                   test -z "$HP_ARCH" && HP_ARCH=hppa
+               fi ;;
        esac
+       if [ ${HP_ARCH} = "hppa2.0w" ]
+       then
+           # avoid double evaluation of $set_cc_for_build
+           test -n "$CC_FOR_BUILD" || eval $set_cc_for_build
+           if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null
+           then
+               HP_ARCH="hppa2.0w"
+           else
+               HP_ARCH="hppa64"
+           fi
+       fi
        echo ${HP_ARCH}-hp-hpux${HPUX_REV}
        exit 0 ;;
     ia64:HP-UX:*:*)
@@ -595,6 +664,7 @@ EOF
        echo ia64-hp-hpux${HPUX_REV}
        exit 0 ;;
     3050*:HI-UX:*:*)
+       eval $set_cc_for_build
        sed 's/^        //' << EOF >$dummy.c
        #include <unistd.h>
        int
@@ -620,8 +690,7 @@ EOF
          exit (0);
        }
 EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
+       $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0
        echo unknown-hitachi-hiuxwe2
        exit 0 ;;
     9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
@@ -630,7 +699,7 @@ EOF
     9000/8??:4.3bsd:*:*)
        echo hppa1.0-hp-bsd
        exit 0 ;;
-    *9??*:MPE/iX:*:*)
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
        echo hppa1.0-hp-mpeix
        exit 0 ;;
     hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
@@ -639,7 +708,7 @@ EOF
     hp8??:OSF1:*:*)
        echo hppa1.0-hp-osf
        exit 0 ;;
-    i?86:OSF1:*:*)
+    i*86:OSF1:*:*)
        if [ -x /usr/sbin/sysversion ] ; then
            echo ${UNAME_MACHINE}-unknown-osf1mk
        else
@@ -649,9 +718,6 @@ EOF
     parisc*:Lites*:*:*)
        echo hppa1.1-hp-lites
        exit 0 ;;
-    hppa*:OpenBSD:*:*)
-       echo hppa-unknown-openbsd
-       exit 0 ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
        echo c1-convex-bsd
         exit 0 ;;
@@ -670,42 +736,39 @@ EOF
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
        echo c4-convex-bsd
         exit 0 ;;
-    CRAY*X-MP:*:*:*)
-       echo xmp-cray-unicos
-        exit 0 ;;
     CRAY*Y-MP:*:*:*)
-       echo ymp-cray-unicos${UNAME_RELEASE}
+       echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
        exit 0 ;;
     CRAY*[A-Z]90:*:*:*)
        echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
        | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
-             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
+             -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+             -e 's/\.[^.]*$/.X/'
        exit 0 ;;
     CRAY*TS:*:*:*)
        echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
        exit 0 ;;
-    CRAY*T3D:*:*:*)
-       echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
-       exit 0 ;;
     CRAY*T3E:*:*:*)
        echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
        exit 0 ;;
     CRAY*SV1:*:*:*)
        echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
        exit 0 ;;
-    CRAY-2:*:*:*)
-       echo cray2-cray-unicos
-        exit 0 ;;
+    *:UNICOS/mp:*:*)
+       echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+       exit 0 ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
        FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
         FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
         FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
         echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
         exit 0 ;;
-    hp300:OpenBSD:*:*)
-       echo m68k-unknown-openbsd${UNAME_RELEASE}
+    5000:UNIX_System_V:4.*:*)
+        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
        exit 0 ;;
-    i?86:BSD/386:*:* | i?86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
        echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
        exit 0 ;;
     sparc*:BSD/OS:*:*)
@@ -717,9 +780,6 @@ EOF
     *:FreeBSD:*:*)
        echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
        exit 0 ;;
-    *:OpenBSD:*:*)
-       echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
-       exit 0 ;;
     i*:CYGWIN*:*)
        echo ${UNAME_MACHINE}-pc-cygwin
        exit 0 ;;
@@ -729,15 +789,24 @@ EOF
     i*:PW*:*)
        echo ${UNAME_MACHINE}-pc-pw32
        exit 0 ;;
+    x86:Interix*:[34]*)
+       echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
+       exit 0 ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+       echo i${UNAME_MACHINE}-pc-mks
+       exit 0 ;;
     i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
        # How do we know it's Interix rather than the generic POSIX subsystem?
        # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
        # UNAME_MACHINE based on the output of uname instead of i386?
-       echo i386-pc-interix
+       echo i586-pc-interix
        exit 0 ;;
     i*:UWIN*:*)
        echo ${UNAME_MACHINE}-pc-uwin
        exit 0 ;;
+    amd64:CYGWIN*:*:*)
+       echo x86_64-unknown-cygwin
+       exit 0 ;;
     p*:CYGWIN*:*)
        echo powerpcle-unknown-cygwin
        exit 0 ;;
@@ -745,112 +814,93 @@ EOF
        echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
        exit 0 ;;
     *:GNU:*:*)
+       # the GNU system
        echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
        exit 0 ;;
+    *:GNU/*:*:*)
+       # other systems with GNU libc and userland
+       echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+       exit 0 ;;
     i*86:Minix:*:*)
        echo ${UNAME_MACHINE}-pc-minix
        exit 0 ;;
     arm*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit 0 ;;
+    cris:Linux:*:*)
+       echo cris-axis-linux-gnu
+       exit 0 ;;
+    crisv32:Linux:*:*)
+       echo crisv32-axis-linux-gnu
+       exit 0 ;;
+    frv:Linux:*:*)
+       echo frv-unknown-linux-gnu
+       exit 0 ;;
     ia64:Linux:*:*)
-       echo ${UNAME_MACHINE}-unknown-linux
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
+    m32r*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit 0 ;;
     m68*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit 0 ;;
     mips:Linux:*:*)
-       cat >$dummy.c <<EOF
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-int main (int argc, char *argv[]) {
-#else
-int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __MIPSEB__
-  printf ("%s-unknown-linux-gnu\n", argv[1]);
-#endif
-#ifdef __MIPSEL__
-  printf ("%sel-unknown-linux-gnu\n", argv[1]);
-#endif
-  return 0;
-}
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips
+       #undef mipsel
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mipsel
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips
+       #else
+       CPU=
+       #endif
+       #endif
 EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
        ;;
-    ppc:Linux:*:*)
-       # Determine Lib Version
-       cat >$dummy.c <<EOF
-#include <features.h>
-#if defined(__GLIBC__)
-extern char __libc_version[];
-extern char __libc_release[];
-#endif
-main(argc, argv)
-     int argc;
-     char *argv[];
-{
-#if defined(__GLIBC__)
-  printf("%s %s\n", __libc_version, __libc_release);
-#else
-  printf("unknown\n");
-#endif
-  return 0;
-}
+    mips64:Linux:*:*)
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #undef CPU
+       #undef mips64
+       #undef mips64el
+       #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+       CPU=mips64el
+       #else
+       #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+       CPU=mips64
+       #else
+       CPU=
+       #endif
+       #endif
 EOF
-       LIBC=""
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               ./$dummy | grep 1\.99 > /dev/null
-               if test "$?" = 0 ; then LIBC="libc1" ; fi
-       fi
-       rm -f $dummy.c $dummy
-       echo powerpc-unknown-linux-gnu${LIBC}
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=`
+       test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0
+       ;;
+    ppc:Linux:*:*)
+       echo powerpc-unknown-linux-gnu
+       exit 0 ;;
+    ppc64:Linux:*:*)
+       echo powerpc64-unknown-linux-gnu
        exit 0 ;;
     alpha:Linux:*:*)
-       cat <<EOF >$dummy.s
-         .data
-         \$Lformat:
-               .byte 37,100,45,37,120,10,0     # "%d-%x\n"
-          .text
-               .globl main
-               .align 4
-               .ent main
-           main:
-               .frame \$30,16,\$26,0
-               ldgp \$29,0(\$27)
-               .prologue 1
-               .long 0x47e03d80 # implver \$0
-               lda \$2,-1
-               .long 0x47e20c21 # amask \$2,\$1
-               lda \$16,\$Lformat
-               mov \$0,\$17
-               not \$1,\$18
-               jsr \$26,printf
-               ldgp \$29,0(\$26)
-               mov 0,\$16
-               jsr \$26,exit
-               .end main
-EOF
-       LIBC=""
-       $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
-       if test "$?" = 0 ; then
-               case `./$dummy` in
-               0-0)    UNAME_MACHINE="alpha" ;;
-               1-0)    UNAME_MACHINE="alphaev5" ;;
-               1-1)    UNAME_MACHINE="alphaev56" ;;
-               1-101)  UNAME_MACHINE="alphapca56" ;;
-               2-303)  UNAME_MACHINE="alphaev6" ;;
-               2-307)  UNAME_MACHINE="alphaev67" ;;
-               esac
-               objdump --private-headers $dummy | \
-                 grep ld.so.1 > /dev/null
-               if test "$?" = 0 ; then
-                       LIBC="libc1"
-               fi
-       fi
-       rm -f $dummy.s $dummy
+       case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+         EV5)   UNAME_MACHINE=alphaev5 ;;
+         EV56)  UNAME_MACHINE=alphaev56 ;;
+         PCA56) UNAME_MACHINE=alphapca56 ;;
+         PCA57) UNAME_MACHINE=alphapca56 ;;
+         EV6)   UNAME_MACHINE=alphaev6 ;;
+         EV67)  UNAME_MACHINE=alphaev67 ;;
+         EV68*) UNAME_MACHINE=alphaev68 ;;
+        esac
+       objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+       if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
        echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
        exit 0 ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
@@ -867,6 +917,9 @@ EOF
     s390:Linux:*:* | s390x:Linux:*:*)
        echo ${UNAME_MACHINE}-ibm-linux
        exit 0 ;;
+    sh64*:Linux:*:*)
+       echo ${UNAME_MACHINE}-unknown-linux-gnu
+       exit 0 ;;
     sh*:Linux:*:*)
        echo ${UNAME_MACHINE}-unknown-linux-gnu
        exit 0 ;;
@@ -876,78 +929,69 @@ EOF
     x86_64:Linux:*:*)
        echo x86_64-unknown-linux-gnu
        exit 0 ;;
-    i?86:Linux:*:*)
+    i*86:Linux:*:*)
        # The BFD linker knows what the default object file format is, so
        # first see if it will tell us. cd to the root directory to prevent
        # problems with other programs or directories called `ld' in the path.
-       ld_supported_emulations=`cd /; ld --help 2>&1 \
-                        | sed -ne '/supported emulations:/!d
+       # Set LC_ALL=C to ensure ld outputs messages in English.
+       ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+                        | sed -ne '/supported targets:/!d
                                    s/[         ][      ]*/ /g
-                                   s/.*supported emulations: *//
+                                   s/.*supported targets: *//
                                    s/ .*//
                                    p'`
-        case "$ld_supported_emulations" in
-         i?86linux)
-               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-               exit 0
-               ;;
-         elf_i?86)
+        case "$ld_supported_targets" in
+         elf32-i386)
                TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
                ;;
-         i?86coff)
+         a.out-i386-linux)
+               echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+               exit 0 ;;
+         coff-i386)
                echo "${UNAME_MACHINE}-pc-linux-gnucoff"
-               exit 0
-               ;;
-       esac
-       # Either a pre-BFD a.out linker (linux-gnuoldld)
-       # or one that does not give us useful --help.
-       # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout.
-       # If ld does not provide *any* "supported emulations:"
-       # that means it is gnuoldld.
-       test -z "$ld_supported_emulations" && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
-       case "${UNAME_MACHINE}" in
-       i?86)
-         VENDOR=pc;
-         ;;
-       *)
-         VENDOR=unknown;
-         ;;
+               exit 0 ;;
+         "")
+               # Either a pre-BFD a.out linker (linux-gnuoldld) or
+               # one that does not give us useful --help.
+               echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+               exit 0 ;;
        esac
        # Determine whether the default compiler is a.out or elf
-       cat >$dummy.c <<EOF
-#include <features.h>
-#ifdef __cplusplus
-#include <stdio.h>  /* for printf() prototype */
-       int main (int argc, char *argv[]) {
-#else
-       int main (argc, argv) int argc; char *argv[]; {
-#endif
-#ifdef __ELF__
-# ifdef __GLIBC__
-#  if __GLIBC__ >= 2
-    printf ("%s-${VENDOR}-linux-gnu\n", argv[1]);
-#  else
-    printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-#  endif
-# else
-   printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]);
-# endif
-#else
-  printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]);
-#endif
-  return 0;
-}
+       eval $set_cc_for_build
+       sed 's/^        //' << EOF >$dummy.c
+       #include <features.h>
+       #ifdef __ELF__
+       # ifdef __GLIBC__
+       #  if __GLIBC__ >= 2
+       LIBC=gnu
+       #  else
+       LIBC=gnulibc1
+       #  endif
+       # else
+       LIBC=gnulibc1
+       # endif
+       #else
+       #ifdef __INTEL_COMPILER
+       LIBC=gnu
+       #else
+       LIBC=gnuaout
+       #endif
+       #endif
+       #ifdef __dietlibc__
+       LIBC=dietlibc
+       #endif
 EOF
-       $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
-       rm -f $dummy.c $dummy
+       eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
+       test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0
        test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
        ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.  earlier versions
-# are messed up and put the nodename in both sysname and nodename.
-    i?86:DYNIX/ptx:4*:*)
+    i*86:DYNIX/ptx:4*:*)
+       # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+       # earlier versions are messed up and put the nodename in both
+       # sysname and nodename.
        echo i386-sequent-sysv4
        exit 0 ;;
-    i?86:UNIX_SV:4.2MP:2.*)
+    i*86:UNIX_SV:4.2MP:2.*)
         # Unixware is an offshoot of SVR4, but it has its own version
         # number series starting with 2...
         # I am not positive that other SVR4 systems won't match this,
@@ -955,7 +999,27 @@ EOF
         # Use sysv4.2uw... so that sysv4* matches it.
        echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
        exit 0 ;;
-    i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*)
+    i*86:OS/2:*:*)
+       # If we were able to find `uname', then EMX Unix compatibility
+       # is probably installed.
+       echo ${UNAME_MACHINE}-pc-os2-emx
+       exit 0 ;;
+    i*86:XTS-300:*:STOP)
+       echo ${UNAME_MACHINE}-unknown-stop
+       exit 0 ;;
+    i*86:atheos:*:*)
+       echo ${UNAME_MACHINE}-unknown-atheos
+       exit 0 ;;
+       i*86:syllable:*:*)
+       echo ${UNAME_MACHINE}-pc-syllable
+       exit 0 ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+       echo i386-unknown-lynxos${UNAME_RELEASE}
+       exit 0 ;;
+    i*86:*DOS:*:*)
+       echo ${UNAME_MACHINE}-pc-msdosdjgpp
+       exit 0 ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
        UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
        if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
                echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
@@ -963,36 +1027,32 @@ EOF
                echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
        fi
        exit 0 ;;
-    i?86:*:5:7*)
-        # Fixed at (any) Pentium or better
-        UNAME_MACHINE=i586
-        if [ ${UNAME_SYSTEM} = "UnixWare" ] ; then
-           echo ${UNAME_MACHINE}-sco-sysv${UNAME_RELEASE}uw${UNAME_VERSION}
-       else
-           echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE}
-       fi
+    i*86:*:5:[78]*)
+       case `/bin/uname -X | grep "^Machine"` in
+           *486*)           UNAME_MACHINE=i486 ;;
+           *Pentium)        UNAME_MACHINE=i586 ;;
+           *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+       esac
+       echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
        exit 0 ;;
-    i?86:*:3.2:*)
+    i*86:*:3.2:*)
        if test -f /usr/options/cb.name; then
                UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
                echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
        elif /bin/uname -X 2>/dev/null >/dev/null ; then
-               UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
-               (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
-               (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+               UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+               (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+               (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
                        && UNAME_MACHINE=i586
-               (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+               (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
                        && UNAME_MACHINE=i686
-               (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+               (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
                        && UNAME_MACHINE=i686
                echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
        else
                echo ${UNAME_MACHINE}-pc-sysv32
        fi
        exit 0 ;;
-    i?86:*DOS:*:*)
-       echo ${UNAME_MACHINE}-pc-msdosdjgpp
-       exit 0 ;;
     pc:*:*:*)
        # Left here for compatibility:
         # uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1016,9 +1076,15 @@ EOF
        # "miniframe"
        echo m68010-convergent-sysv
        exit 0 ;;
-    M68*:*:R3V[567]*:*)
+    mc68k:UNIX:SYSTEM5:3.51m)
+       echo m68k-convergent-sysv
+       exit 0 ;;
+    M680?0:D-NIX:5.3:*)
+       echo m68k-diab-dnix
+       exit 0 ;;
+    M68*:*:R3V[5678]*:*)
        test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
-    3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0)
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
        OS_REL=''
        test -r /etc/.relid \
        && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
@@ -1029,22 +1095,19 @@ EOF
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
         /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
           && echo i486-ncr-sysv4 && exit 0 ;;
-    m68*:LynxOS:2.*:*)
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
        echo m68k-unknown-lynxos${UNAME_RELEASE}
        exit 0 ;;
     mc68030:UNIX_System_V:4.*:*)
        echo m68k-atari-sysv4
        exit 0 ;;
-    i?86:LynxOS:2.*:* | i?86:LynxOS:3.[01]*:*)
-       echo i386-unknown-lynxos${UNAME_RELEASE}
-       exit 0 ;;
     TSUNAMI:LynxOS:2.*:*)
        echo sparc-unknown-lynxos${UNAME_RELEASE}
        exit 0 ;;
     rs6000:LynxOS:2.*:*)
        echo rs6000-unknown-lynxos${UNAME_RELEASE}
        exit 0 ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:*)
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
        echo powerpc-unknown-lynxos${UNAME_RELEASE}
        exit 0 ;;
     SM[BE]S:UNIX_SV:*:*)
@@ -1064,8 +1127,8 @@ EOF
                echo ns32k-sni-sysv
        fi
        exit 0 ;;
-    PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                           # says <Richard.M.Bartel@ccMail.Census.GOV>
+    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+                      # says <Richard.M.Bartel@ccMail.Census.GOV>
         echo i586-unisys-sysv4
         exit 0 ;;
     *:UNIX_System_V:4*:FTX*)
@@ -1077,6 +1140,10 @@ EOF
        # From seanf@swdc.stratus.com.
        echo i860-stratus-sysv4
        exit 0 ;;
+    *:VOS:*:*)
+       # From Paul.Green@stratus.com.
+       echo hppa1.1-stratus-vos
+       exit 0 ;;
     mc68*:A/UX:*:*)
        echo m68k-apple-aux${UNAME_RELEASE}
        exit 0 ;;
@@ -1105,6 +1172,9 @@ EOF
     SX-5:SUPER-UX:*:*)
        echo sx5-nec-superux${UNAME_RELEASE}
        exit 0 ;;
+    SX-6:SUPER-UX:*:*)
+       echo sx6-nec-superux${UNAME_RELEASE}
+       exit 0 ;;
     Power*:Rhapsody:*:*)
        echo powerpc-apple-rhapsody${UNAME_RELEASE}
        exit 0 ;;
@@ -1112,18 +1182,28 @@ EOF
        echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
        exit 0 ;;
     *:Darwin:*:*)
-       echo `uname -p`-apple-darwin${UNAME_RELEASE}
+       UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+       case $UNAME_PROCESSOR in
+           *86) UNAME_PROCESSOR=i686 ;;
+           unknown) UNAME_PROCESSOR=powerpc ;;
+       esac
+       echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
        exit 0 ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
-       if test "${UNAME_MACHINE}" = "x86pc"; then
+       UNAME_PROCESSOR=`uname -p`
+       if test "$UNAME_PROCESSOR" = "x86"; then
+               UNAME_PROCESSOR=i386
                UNAME_MACHINE=pc
        fi
-       echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+       echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
        exit 0 ;;
     *:QNX:*:4*)
        echo i386-pc-qnx
        exit 0 ;;
-    NSR-[KW]:NONSTOP_KERNEL:*:*)
+    NSE-?:NONSTOP_KERNEL:*:*)
+       echo nse-tandem-nsk${UNAME_RELEASE}
+       exit 0 ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
        echo nsr-tandem-nsk${UNAME_RELEASE}
        exit 0 ;;
     *:NonStop-UX:*:*)
@@ -1146,11 +1226,6 @@ EOF
        fi
        echo ${UNAME_MACHINE}-unknown-plan9
        exit 0 ;;
-    i?86:OS/2:*:*)
-       # If we were able to find `uname', then EMX Unix compatibility
-       # is probably installed.
-       echo ${UNAME_MACHINE}-pc-os2-emx
-       exit 0 ;;
     *:TOPS-10:*:*)
        echo pdp10-unknown-tops10
        exit 0 ;;
@@ -1169,11 +1244,28 @@ EOF
     *:ITS:*:*)
        echo pdp10-unknown-its
        exit 0 ;;
+    SEI:*:*:SEIUX)
+        echo mips-sei-seiux${UNAME_RELEASE}
+       exit 0 ;;
+    *:DragonFly:*:*)
+       echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+       exit 0 ;;
+    *:*VMS:*:*)
+       UNAME_MACHINE=`(uname -p) 2>/dev/null`
+       case "${UNAME_MACHINE}" in
+           A*) echo alpha-dec-vms && exit 0 ;;
+           I*) echo ia64-dec-vms && exit 0 ;;
+           V*) echo vax-dec-vms && exit 0 ;;
+       esac ;;
+    *:XENIX:*:SysV)
+       echo i386-pc-xenix
+       exit 0 ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
 
+eval $set_cc_for_build
 cat >$dummy.c <<EOF
 #ifdef _SEQUENT_
 # include <sys/types.h>
@@ -1288,8 +1380,7 @@ main ()
 }
 EOF
 
-$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
-rm -f $dummy.c $dummy
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0
 
 # Apollos put the system type in the environment.
 
@@ -1328,7 +1419,9 @@ This script, last modified $timestamp, has failed to recognize
 the operating system you are using. It is advised that you
 download the most up to date version of the config scripts from
 
-    ftp://ftp.gnu.org/pub/gnu/config/
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
+and
+  http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
 
 If the version you run ($0) is already up to date, please
 send the following data and any information you think might be
index 67f3d01382db001a0c046a310835a44c81b53d6e..afbed88265e1894e586d8fa305e3db3237921436 100644 (file)
@@ -33,6 +33,9 @@ MANGROUP      = root
 LIBBSD         = @LIBBSD@
 LIBNSL         = @LIBNSL@
 LIBWRAP                = @LIBWRAP@
+KRBLIB         = @KRBLIB@
+KRBDIR         = @KRBDIR@
+KRB5_VERSION   = @K5VERS@
 
 ################# END OF USER SERVICEABLE PARTS ##################
 ALLTARGETS     = all clean distclean install installman \
@@ -58,6 +61,7 @@ INSTALL               = install
 MAN2PS         = groff -Tps -man
 
 AFLAGS         = -I$(TOP)support/include \
+                 -I$(KRBDIR)/include \
                  -Wall $(ARCHFLAGS) -pipe
 ifdef KERNEL_INCDIR
 AFLAGS        += -I$(KERNEL_INCDIR)
index 44ebcd89a8027dea9b99830bbe0bacda62cddae3..d8fd2f8fa2f58cb9a31d7494d75d7ed8b7135dfe 100755 (executable)
@@ -1,9 +1,9 @@
 #! /bin/sh
 # Configuration validation subroutine script.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-#   Free Software Foundation, Inc.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
-timestamp='2001-03-19'
+timestamp='2005-02-10'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -29,7 +29,8 @@ timestamp='2001-03-19'
 # configuration script generated by Autoconf, you may include it under
 # the same distribution terms that you use for the rest of that program.
 
-# Please send patches to <config-patches@gnu.org>.
+# Please send patches to <config-patches@gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
@@ -69,7 +70,7 @@ Report bugs and patches to <config-patches@gnu.org>."
 version="\
 GNU config.sub ($timestamp)
 
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
@@ -117,7 +118,8 @@ esac
 # Here we must recognize all the valid KERNEL-OS combinations.
 maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
-  nto-qnx* | linux-gnu* | storm-chaos* | os2-emx*)
+  nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \
+  kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
     ;;
@@ -143,7 +145,7 @@ case $os in
        -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
        -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
        -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-       -apple | -axis)
+       -apple | -axis | -knuth | -cray)
                os=
                basic_machine=$1
                ;;
@@ -157,13 +159,17 @@ case $os in
                os=-vxworks
                basic_machine=$1
                ;;
+       -chorusos*)
+               os=-chorusos
+               basic_machine=$1
+               ;;
+       -chorusrdb)
+               os=-chorusrdb
+               basic_machine=$1
+               ;;
        -hiux*)
                os=-hiuxwe2
                ;;
-       -mvs*)
-               os=-mvs
-               basic_machine=i370-ibm
-               ;;
        -sco5)
                os=-sco3.2v5
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
@@ -219,25 +225,50 @@ esac
 case $basic_machine in
        # Recognize the basic CPU types without company name.
        # Some are omitted here because they have special meanings below.
-       tahoe | i860 | ia64 | m32r | m68k | m68000 | m88k | ns32k | arc \
-               | arm | arme[lb] | arm[bl]e | armv[2345] | armv[345][lb] | strongarm | xscale \
-               | pyramid | mn10200 | mn10300 | tron | a29k \
-               | 580 | i960 | h8300 \
-               | x86 | ppcbe | mipsbe | mipsle | shbe | shle \
-               | hppa | hppa1.0 | hppa1.1 | hppa2.0 | hppa2.0w | hppa2.0n \
-               | hppa64 \
-               | alpha | alphaev[4-8] | alphaev56 | alphapca5[67] \
-               | alphaev6[78] \
-               | we32k | ns16k | clipper | i370 | sh | sh[34] \
-               | powerpc | powerpcle \
-               | 1750a | dsp16xx | pdp10 | pdp11 \
-               | mips16 | mips64 | mipsel | mips64el \
-               | mips64orion | mips64orionel | mipstx39 | mipstx39el \
-               | mips64vr4300 | mips64vr4300el | mips64vr4100 | mips64vr4100el \
-               | mips64vr5000 | miprs64vr5000el | mcore | s390 | s390x \
-               | sparc | sparclet | sparclite | sparc64 | sparcv9 | v850 | c4x \
-               | thumb | d10v | d30v | fr30 | avr | openrisc | tic80 \
-               | pj | pjl | h8500)
+       1750a | 580 \
+       | a29k \
+       | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+       | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+       | am33_2.0 \
+       | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
+       | c4x | clipper \
+       | d10v | d30v | dlx | dsp16xx \
+       | fr30 | frv \
+       | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+       | i370 | i860 | i960 | ia64 \
+       | ip2k | iq2000 \
+       | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \
+       | mips | mipsbe | mipseb | mipsel | mipsle \
+       | mips16 \
+       | mips64 | mips64el \
+       | mips64vr | mips64vrel \
+       | mips64orion | mips64orionel \
+       | mips64vr4100 | mips64vr4100el \
+       | mips64vr4300 | mips64vr4300el \
+       | mips64vr5000 | mips64vr5000el \
+       | mipsisa32 | mipsisa32el \
+       | mipsisa32r2 | mipsisa32r2el \
+       | mipsisa64 | mipsisa64el \
+       | mipsisa64r2 | mipsisa64r2el \
+       | mipsisa64sb1 | mipsisa64sb1el \
+       | mipsisa64sr71k | mipsisa64sr71kel \
+       | mipstx39 | mipstx39el \
+       | mn10200 | mn10300 \
+       | msp430 \
+       | ns16k | ns32k \
+       | openrisc | or32 \
+       | pdp10 | pdp11 | pj | pjl \
+       | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+       | pyramid \
+       | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
+       | sh64 | sh64le \
+       | sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv8 | sparcv9 | sparcv9b \
+       | strongarm \
+       | tahoe | thumb | tic4x | tic80 | tron \
+       | v850 | v850e \
+       | we32k \
+       | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \
+       | z8k)
                basic_machine=$basic_machine-unknown
                ;;
        m6811 | m68hc11 | m6812 | m68hc12)
@@ -245,13 +276,13 @@ case $basic_machine in
                basic_machine=$basic_machine-unknown
                os=-none
                ;;
-       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | z8k | v70 | w65)
+       m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
                ;;
 
        # We use `pc' rather than `unknown'
        # because (1) that's what they normally are, and
        # (2) the word "unknown" tends to confuse beginning users.
-       i[234567]86 | x86_64)
+       i*86 | x86_64)
          basic_machine=$basic_machine-pc
          ;;
        # Object if more than one company name word.
@@ -260,30 +291,62 @@ case $basic_machine in
                exit 1
                ;;
        # Recognize the basic CPU types with company name.
-       # FIXME: clean up the formatting here.
-       vax-* | tahoe-* | i[234567]86-* | i860-* | ia64-* | m32r-* | m68k-* | m68000-* \
-             | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | c[123]* \
-             | arm-*  | armbe-* | armle-* | armv*-* | strongarm-* | xscale-* \
-             | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
-             | power-* | none-* | 580-* | cray2-* | h8300-* | h8500-* | i960-* \
-             | xmp-* | ymp-* \
-             | x86-* | ppcbe-* | mipsbe-* | mipsle-* | shbe-* | shle-* \
-             | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* | hppa2.0w-* \
-             | hppa2.0n-* | hppa64-* \
-             | alpha-* | alphaev[4-8]-* | alphaev56-* | alphapca5[67]-* \
-             | alphaev6[78]-* \
-             | we32k-* | cydra-* | ns16k-* | pn-* | np1-* | xps100-* \
-             | clipper-* | orion-* \
-             | sparclite-* | pdp10-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
-             | sparc64-* | sparcv9-* | sparc86x-* | mips16-* | mips64-* | mipsel-* \
-             | mips64el-* | mips64orion-* | mips64orionel-* \
-             | mips64vr4100-* | mips64vr4100el-* | mips64vr4300-* | mips64vr4300el-* \
-             | mipstx39-* | mipstx39el-* | mcore-* \
-             | f30[01]-* | f700-* | s390-* | s390x-* | sv1-* | t3e-* \
-             | [cjt]90-* \
-             | m88110-* | m680[01234]0-* | m683?2-* | m68360-* | z8k-* | d10v-* \
-             | thumb-* | v850-* | d30v-* | tic30-* | tic80-* | c30-* | fr30-* \
-             | bs2000-* | tic54x-* | c54x-* | x86_64-* | pj-* | pjl-*)
+       580-* \
+       | a29k-* \
+       | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+       | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+       | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+       | arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+       | avr-* \
+       | bs2000-* \
+       | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+       | clipper-* | craynv-* | cydra-* \
+       | d10v-* | d30v-* | dlx-* \
+       | elxsi-* \
+       | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \
+       | h8300-* | h8500-* \
+       | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+       | i*86-* | i860-* | i960-* | ia64-* \
+       | ip2k-* | iq2000-* \
+       | m32r-* | m32rle-* \
+       | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+       | m88110-* | m88k-* | maxq-* | mcore-* \
+       | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+       | mips16-* \
+       | mips64-* | mips64el-* \
+       | mips64vr-* | mips64vrel-* \
+       | mips64orion-* | mips64orionel-* \
+       | mips64vr4100-* | mips64vr4100el-* \
+       | mips64vr4300-* | mips64vr4300el-* \
+       | mips64vr5000-* | mips64vr5000el-* \
+       | mipsisa32-* | mipsisa32el-* \
+       | mipsisa32r2-* | mipsisa32r2el-* \
+       | mipsisa64-* | mipsisa64el-* \
+       | mipsisa64r2-* | mipsisa64r2el-* \
+       | mipsisa64sb1-* | mipsisa64sb1el-* \
+       | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+       | mipstx39-* | mipstx39el-* \
+       | mmix-* \
+       | msp430-* \
+       | none-* | np1-* | ns16k-* | ns32k-* \
+       | orion-* \
+       | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+       | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+       | pyramid-* \
+       | romp-* | rs6000-* \
+       | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \
+       | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+       | sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
+       | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \
+       | tahoe-* | thumb-* \
+       | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+       | tron-* \
+       | v850-* | v850e-* | vax-* \
+       | we32k-* \
+       | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \
+       | xstormy16-* | xtensa-* \
+       | ymp-* \
+       | z8k-*)
                ;;
        # Recognize the various machine names and aliases which stand
        # for a CPU type and a company and sometimes even an OS.
@@ -301,6 +364,9 @@ case $basic_machine in
                basic_machine=a29k-amd
                os=-udi
                ;;
+       abacus)
+               basic_machine=abacus-unknown
+               ;;
        adobe68k)
                basic_machine=m68010-adobe
                os=-scout
@@ -315,6 +381,12 @@ case $basic_machine in
                basic_machine=a29k-none
                os=-bsd
                ;;
+       amd64)
+               basic_machine=x86_64-pc
+               ;;
+       amd64-*)
+               basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
        amdahl)
                basic_machine=580-amdahl
                os=-sysv
@@ -346,6 +418,10 @@ case $basic_machine in
                basic_machine=ns32k-sequent
                os=-dynix
                ;;
+       c90)
+               basic_machine=c90-cray
+               os=-unicos
+               ;;
        convex-c1)
                basic_machine=c1-convex
                os=-bsd
@@ -366,30 +442,45 @@ case $basic_machine in
                basic_machine=c38-convex
                os=-bsd
                ;;
-       cray | ymp)
-               basic_machine=ymp-cray
+       cray | j90)
+               basic_machine=j90-cray
                os=-unicos
                ;;
-       cray2)
-               basic_machine=cray2-cray
-               os=-unicos
+       craynv)
+               basic_machine=craynv-cray
+               os=-unicosmp
                ;;
-       [cjt]90)
-               basic_machine=${basic_machine}-cray
-               os=-unicos
+       cr16c)
+               basic_machine=cr16c-unknown
+               os=-elf
                ;;
        crds | unos)
                basic_machine=m68k-crds
                ;;
+       crisv32 | crisv32-* | etraxfs*)
+               basic_machine=crisv32-axis
+               ;;
        cris | cris-* | etrax*)
                basic_machine=cris-axis
                ;;
+       crx)
+               basic_machine=crx-unknown
+               os=-elf
+               ;;
        da30 | da30-*)
                basic_machine=m68k-da30
                ;;
        decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
                basic_machine=mips-dec
                ;;
+       decsystem10* | dec10*)
+               basic_machine=pdp10-dec
+               os=-tops10
+               ;;
+       decsystem20* | dec20*)
+               basic_machine=pdp10-dec
+               os=-tops20
+               ;;
        delta | 3300 | motorola-3300 | motorola-delta \
              | 3300-motorola | delta-motorola)
                basic_machine=m68k-motorola
@@ -398,6 +489,10 @@ case $basic_machine in
                basic_machine=m88k-motorola
                os=-sysv3
                ;;
+       djgpp)
+               basic_machine=i586-pc
+               os=-msdosdjgpp
+               ;;
        dpx20 | dpx20-*)
                basic_machine=rs6000-bull
                os=-bosx
@@ -506,23 +601,23 @@ case $basic_machine in
                basic_machine=hppa1.1-hp
                os=-proelf
                ;;
-       i370*)
+       i370-ibm* | ibm*)
                basic_machine=i370-ibm
                ;;
 # I'm not sure what "Sysv32" means.  Should this be sysv3.2?
-       i[34567]86v32)
+       i*86v32)
                basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
                os=-sysv32
                ;;
-       i[34567]86v4*)
+       i*86v4*)
                basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
                os=-sysv4
                ;;
-       i[34567]86v)
+       i*86v)
                basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
                os=-sysv
                ;;
-       i[34567]86sol2)
+       i*86sol2)
                basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
                os=-solaris2
                ;;
@@ -570,28 +665,20 @@ case $basic_machine in
                basic_machine=m68k-atari
                os=-mint
                ;;
-       mipsel*-linux*)
-               basic_machine=mipsel-unknown
-               os=-linux-gnu
-               ;;
-       mips*-linux*)
-               basic_machine=mips-unknown
-               os=-linux-gnu
-               ;;
        mips3*-*)
                basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
                ;;
        mips3*)
                basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
                ;;
-       mmix*)
-               basic_machine=mmix-knuth
-               os=-mmixware
-               ;;
        monitor)
                basic_machine=m68k-rom68k
                os=-coff
                ;;
+       morphos)
+               basic_machine=powerpc-unknown
+               os=-morphos
+               ;;
        msdos)
                basic_machine=i386-pc
                os=-msdos
@@ -671,6 +758,14 @@ case $basic_machine in
                basic_machine=hppa1.1-oki
                os=-proelf
                ;;
+       or32 | or32-*)
+               basic_machine=or32-unknown
+               os=-coff
+               ;;
+       os400)
+               basic_machine=powerpc-ibm
+               os=-os400
+               ;;
        OSE68000 | ose68000)
                basic_machine=m68000-ericsson
                os=-ose
@@ -693,42 +788,58 @@ case $basic_machine in
        pbb)
                basic_machine=m68k-tti
                ;;
-        pc532 | pc532-*)
+       pc532 | pc532-*)
                basic_machine=ns32k-pc532
                ;;
-       pentium | p5 | k5 | k6 | nexgen)
+       pentium | p5 | k5 | k6 | nexgen | viac3)
                basic_machine=i586-pc
                ;;
-       pentiumpro | p6 | 6x86 | athlon)
+       pentiumpro | p6 | 6x86 | athlon | athlon_*)
                basic_machine=i686-pc
                ;;
-       pentiumii | pentium2)
+       pentiumii | pentium2 | pentiumiii | pentium3)
                basic_machine=i686-pc
                ;;
-       pentium-* | p5-* | k5-* | k6-* | nexgen-*)
+       pentium4)
+               basic_machine=i786-pc
+               ;;
+       pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
                basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
        pentiumpro-* | p6-* | 6x86-* | athlon-*)
                basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
-       pentiumii-* | pentium2-*)
+       pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
                basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
+       pentium4-*)
+               basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
        pn)
                basic_machine=pn-gould
                ;;
        power)  basic_machine=power-ibm
                ;;
        ppc)    basic_machine=powerpc-unknown
-               ;;
+               ;;
        ppc-*)  basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
        ppcle | powerpclittle | ppc-le | powerpc-little)
                basic_machine=powerpcle-unknown
-               ;;
+               ;;
        ppcle-* | powerpclittle-*)
                basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
                ;;
+       ppc64)  basic_machine=powerpc64-unknown
+               ;;
+       ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
+       ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+               basic_machine=powerpc64le-unknown
+               ;;
+       ppc64le-* | powerpc64little-*)
+               basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+               ;;
        ps2)
                basic_machine=i386-ibm
                ;;
@@ -746,10 +857,26 @@ case $basic_machine in
        rtpc | rtpc-*)
                basic_machine=romp-ibm
                ;;
+       s390 | s390-*)
+               basic_machine=s390-ibm
+               ;;
+       s390x | s390x-*)
+               basic_machine=s390x-ibm
+               ;;
        sa29200)
                basic_machine=a29k-amd
                os=-udi
                ;;
+       sb1)
+               basic_machine=mipsisa64sb1-unknown
+               ;;
+       sb1el)
+               basic_machine=mipsisa64sb1el-unknown
+               ;;
+       sei)
+               basic_machine=mips-sei
+               os=-seiux
+               ;;
        sequent)
                basic_machine=i386-sequent
                ;;
@@ -757,7 +884,10 @@ case $basic_machine in
                basic_machine=sh-hitachi
                os=-hms
                ;;
-       sparclite-wrs)
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparclite-wrs | simso-wrs)
                basic_machine=sparclite-wrs
                os=-vxworks
                ;;
@@ -824,22 +954,42 @@ case $basic_machine in
                os=-dynix
                ;;
        t3e)
-               basic_machine=t3e-cray
+               basic_machine=alphaev5-cray
+               os=-unicos
+               ;;
+       t90)
+               basic_machine=t90-cray
                os=-unicos
                ;;
        tic54x | c54x*)
                basic_machine=tic54x-unknown
                os=-coff
                ;;
+       tic55x | c55x*)
+               basic_machine=tic55x-unknown
+               os=-coff
+               ;;
+       tic6x | c6x*)
+               basic_machine=tic6x-unknown
+               os=-coff
+               ;;
        tx39)
                basic_machine=mipstx39-unknown
                ;;
        tx39el)
                basic_machine=mipstx39el-unknown
                ;;
+       toad1)
+               basic_machine=pdp10-xkl
+               os=-tops20
+               ;;
        tower | tower-32)
                basic_machine=m68k-ncr
                ;;
+       tpf)
+               basic_machine=s390x-ibm
+               os=-tpf
+               ;;
        udi29k)
                basic_machine=a29k-amd
                os=-udi
@@ -861,8 +1011,8 @@ case $basic_machine in
                os=-vms
                ;;
        vpp*|vx|vx-*)
-               basic_machine=f301-fujitsu
-               ;;
+               basic_machine=f301-fujitsu
+               ;;
        vxworks960)
                basic_machine=i960-wrs
                os=-vxworks
@@ -883,13 +1033,17 @@ case $basic_machine in
                basic_machine=hppa1.1-winbond
                os=-proelf
                ;;
-       xmp)
-               basic_machine=xmp-cray
-               os=-unicos
+       xbox)
+               basic_machine=i686-pc
+               os=-mingw32
                ;;
-        xps | xps100)
+       xps | xps100)
                basic_machine=xps100-honeywell
                ;;
+       ymp)
+               basic_machine=ymp-cray
+               os=-unicos
+               ;;
        z8k-*-coff)
                basic_machine=z8k-unknown
                os=-sim
@@ -910,16 +1064,12 @@ case $basic_machine in
        op60c)
                basic_machine=hppa1.1-oki
                ;;
-       mips)
-               if [ x$os = x-linux-gnu ]; then
-                       basic_machine=mips-unknown
-               else
-                       basic_machine=mips-mips
-               fi
-               ;;
        romp)
                basic_machine=romp-ibm
                ;;
+       mmix)
+               basic_machine=mmix-knuth
+               ;;
        rs6000)
                basic_machine=rs6000-ibm
                ;;
@@ -936,13 +1086,16 @@ case $basic_machine in
        we32k)
                basic_machine=we32k-att
                ;;
-       sh3 | sh4)
+       sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele)
                basic_machine=sh-unknown
                ;;
-       sparc | sparcv9)
+       sh64)
+               basic_machine=sh64-unknown
+               ;;
+       sparc | sparcv8 | sparcv9 | sparcv9b)
                basic_machine=sparc-sun
                ;;
-        cydra)
+       cydra)
                basic_machine=cydra-cydrome
                ;;
        orion)
@@ -957,9 +1110,8 @@ case $basic_machine in
        pmac | pmac-mpw)
                basic_machine=powerpc-apple
                ;;
-       c4x*)
-               basic_machine=c4x-none
-               os=-coff
+       *-unknown)
+               # Make sure to match an already-canonicalized machine name.
                ;;
        *)
                echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
@@ -1013,28 +1165,35 @@ case $os in
              | -aos* \
              | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
              | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-             | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
-             | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+             | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \
+             | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+             | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
              | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
              | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+             | -chorusos* | -chorusrdb* \
              | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-             | -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
-             | -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
+             | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \
+             | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
              | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
-             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* | -os2*)
+             | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+             | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+             | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+             | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*)
        # Remember, each alternative MUST END IN *, to match a version number.
                ;;
        -qnx*)
                case $basic_machine in
-                   x86-* | i[34567]86-*)
+                   x86-* | i*86-*)
                        ;;
                    *)
                        os=-nto$os
                        ;;
                esac
                ;;
+       -nto-qnx*)
+               ;;
        -nto*)
-               os=-nto-qnx
+               os=`echo $os | sed -e 's|nto|nto-qnx|'`
                ;;
        -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
              | -windows* | -osx | -abug | -netware* | -os9* | -beos* \
@@ -1043,6 +1202,9 @@ case $os in
        -mac*)
                os=`echo $os | sed -e 's|mac|macos|'`
                ;;
+       -linux-dietlibc)
+               os=-linux-dietlibc
+               ;;
        -linux*)
                os=`echo $os | sed -e 's|linux|linux-gnu|'`
                ;;
@@ -1055,6 +1217,9 @@ case $os in
        -opened*)
                os=-openedition
                ;;
+        -os400*)
+               os=-os400
+               ;;
        -wince*)
                os=-wince
                ;;
@@ -1073,14 +1238,23 @@ case $os in
        -acis*)
                os=-aos
                ;;
+       -atheos*)
+               os=-atheos
+               ;;
+       -syllable*)
+               os=-syllable
+               ;;
        -386bsd)
                os=-bsd
                ;;
        -ctix* | -uts*)
                os=-sysv
                ;;
+       -nova*)
+               os=-rtmk-nova
+               ;;
        -ns2 )
-               os=-nextstep2
+               os=-nextstep2
                ;;
        -nsk*)
                os=-nsk
@@ -1092,6 +1266,9 @@ case $os in
        -sinix*)
                os=-sysv4
                ;;
+        -tpf*)
+               os=-tpf
+               ;;
        -triton*)
                os=-sysv3
                ;;
@@ -1119,8 +1296,17 @@ case $os in
        -xenix)
                os=-xenix
                ;;
-        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-               os=-mint
+       -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+               os=-mint
+               ;;
+       -aros*)
+               os=-aros
+               ;;
+       -kaos*)
+               os=-kaos
+               ;;
+       -zvmoe)
+               os=-zvmoe
                ;;
        -none)
                ;;
@@ -1153,10 +1339,14 @@ case $basic_machine in
        arm*-semi)
                os=-aout
                ;;
+    c4x-* | tic4x-*)
+        os=-coff
+        ;;
+       # This must come before the *-dec entry.
        pdp10-*)
                os=-tops20
                ;;
-        pdp11-*)
+       pdp11-*)
                os=-none
                ;;
        *-dec | vax-*)
@@ -1183,6 +1373,9 @@ case $basic_machine in
        mips*-*)
                os=-elf
                ;;
+       or32-*)
+               os=-coff
+               ;;
        *-tti)  # must be before sparc entry or we get the wrong os.
                os=-sysv3
                ;;
@@ -1195,6 +1388,9 @@ case $basic_machine in
        *-ibm)
                os=-aix
                ;;
+       *-knuth)
+               os=-mmixware
+               ;;
        *-wec)
                os=-proelf
                ;;
@@ -1246,19 +1442,19 @@ case $basic_machine in
        *-next)
                os=-nextstep3
                ;;
-        *-gould)
+       *-gould)
                os=-sysv
                ;;
-        *-highlevel)
+       *-highlevel)
                os=-bsd
                ;;
        *-encore)
                os=-bsd
                ;;
-        *-sgi)
+       *-sgi)
                os=-irix
                ;;
-        *-siemens)
+       *-siemens)
                os=-sysv4
                ;;
        *-masscomp)
@@ -1327,10 +1523,16 @@ case $basic_machine in
                        -mvs* | -opened*)
                                vendor=ibm
                                ;;
+                       -os400*)
+                               vendor=ibm
+                               ;;
                        -ptx*)
                                vendor=sequent
                                ;;
-                       -vxsim* | -vxworks*)
+                       -tpf*)
+                               vendor=ibm
+                               ;;
+                       -vxsim* | -vxworks* | -windiss*)
                                vendor=wrs
                                ;;
                        -aux*)
@@ -1345,6 +1547,9 @@ case $basic_machine in
                        -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
                                vendor=atari
                                ;;
+                       -vos*)
+                               vendor=stratus
+                               ;;
                esac
                basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
                ;;
index f8be185520759c2cf4c6b05c0f97a770e5c447d1..9732c28604a876bcc8ae17b2ee57a27d56e6f96d 100755 (executable)
--- a/configure
+++ b/configure
@@ -20,12 +20,18 @@ ac_help="$ac_help
   --with-statduser=rpcuser user for statd to run under [rpcuser or nobody]"
 ac_help="$ac_help
   --enable-nfsv3          enable support for NFSv3"
+ac_help="$ac_help
+  --enable-nfsv4          enable support for NFSv4"
+ac_help="$ac_help
+  --enable-gss           enable support for rpcsec_gss"
 ac_help="$ac_help
   --enable-kprefix       install progs as rpc.knfsd etc"
 ac_help="$ac_help
   --enable-secure-statd  Only lockd can use statd (security)"
 ac_help="$ac_help
   --enable-rquotad          enable rquotad"
+ac_help="$ac_help
+  --with-krb5=DIR         use Kerberos v5 installation in DIR"
 
 # Initialize some variables set by options.
 # The variables have the same names as the options, with
@@ -539,7 +545,7 @@ fi
 
 
 # The nfs-utils version
-VERSION="1.0.6"
+VERSION="1.0.7"
 
 
 # Check whether --with-release or --without-release was given.
@@ -590,6 +596,49 @@ EOF
                enable_nfsv3=
        fi
        
+# Check whether --enable-nfsv4 or --disable-nfsv4 was given.
+if test "${enable_nfsv4+set}" = set; then
+  enableval="$enable_nfsv4"
+  enable_nfsv4=$enableval
+else
+  enable_nfsv4=yes
+fi
+
+       if test "$enable_nfsv4" = yes; then
+               cat >> confdefs.h <<\EOF
+#define NFS4_SUPPORTED 1
+EOF
+
+               IDMAPD=idmapd
+       else
+               enable_nfsv4=
+               IDMAPD=
+       fi
+       
+       
+# Check whether --enable-gss or --disable-gss was given.
+if test "${enable_gss+set}" = set; then
+  enableval="$enable_gss"
+  enable_gss=$enableval
+else
+  enable_gss=yes
+fi
+
+       if test "$enable_gss" = yes; then
+               cat >> confdefs.h <<\EOF
+#define GSS_SUPPORTED 1
+EOF
+
+               GSSD=gssd
+               SVCGSSD=svcgssd
+       else
+               enable_gss=
+               GSSD=
+               SVCGSSD=
+       fi
+       
+       
+       
 # Check whether --enable-kprefix or --disable-kprefix was given.
 if test "${enable_kprefix+set}" = set; then
   enableval="$enable_kprefix"
@@ -633,7 +682,7 @@ fi
 # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:637: checking for $ac_word" >&5
+echo "configure:686: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -663,7 +712,7 @@ if test -z "$CC"; then
   # Extract the first word of "cc", so it can be a program name with args.
 set dummy cc; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:667: checking for $ac_word" >&5
+echo "configure:716: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -714,7 +763,7 @@ fi
       # Extract the first word of "cl", so it can be a program name with args.
 set dummy cl; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:718: checking for $ac_word" >&5
+echo "configure:767: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -746,7 +795,7 @@ fi
 fi
 
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:750: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+echo "configure:799: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -757,12 +806,12 @@ cross_compiling=$ac_cv_prog_cc_cross
 
 cat > conftest.$ac_ext << EOF
 
-#line 761 "configure"
+#line 810 "configure"
 #include "confdefs.h"
 
 main(){return(0);}
 EOF
-if { (eval echo configure:766: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:815: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   ac_cv_prog_cc_works=yes
   # If we can't run a trivial program, we are probably using a cross compiler.
   if (./conftest; exit) 2>/dev/null; then
@@ -788,12 +837,12 @@ if test $ac_cv_prog_cc_works = no; then
   { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
 fi
 echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:792: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "configure:841: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
 echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
 cross_compiling=$ac_cv_prog_cc_cross
 
 echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:797: checking whether we are using GNU C" >&5
+echo "configure:846: checking whether we are using GNU C" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -802,7 +851,7 @@ else
   yes;
 #endif
 EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:806: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:855: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
   ac_cv_prog_gcc=yes
 else
   ac_cv_prog_gcc=no
@@ -821,7 +870,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
 ac_save_CFLAGS="$CFLAGS"
 CFLAGS=
 echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:825: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:874: checking whether ${CC-cc} accepts -g" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -853,7 +902,7 @@ else
 fi
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:857: checking how to run the C preprocessor" >&5
+echo "configure:906: checking how to run the C preprocessor" >&5
 # On Suns, sometimes $CPP names a directory.
 if test -n "$CPP" && test -d "$CPP"; then
   CPP=
@@ -868,13 +917,13 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 872 "configure"
+#line 921 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:878: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:927: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -885,13 +934,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 889 "configure"
+#line 938 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:895: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:944: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -902,13 +951,13 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -nologo -E"
   cat > conftest.$ac_ext <<EOF
-#line 906 "configure"
+#line 955 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:912: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:961: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   :
@@ -963,7 +1012,7 @@ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
 # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
 # ./install, which can be erroneously created by make from ./install.sh.
 echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:967: checking for a BSD compatible install" >&5
+echo "configure:1016: checking for a BSD compatible install" >&5
 if test -z "$INSTALL"; then
 if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1026,7 +1075,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
 fi
 
 echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:1030: checking host system type" >&5
+echo "configure:1079: checking host system type" >&5
 
 host_alias=$host
 case "$host_alias" in
@@ -1047,7 +1096,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
 echo "$ac_t""$host" 1>&6
 
 echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:1051: checking build system type" >&5
+echo "configure:1100: checking build system type" >&5
 
 build_alias=$build
 case "$build_alias" in
@@ -1073,7 +1122,7 @@ fi
 # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1077: checking for $ac_word" >&5
+echo "configure:1126: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1105,7 +1154,7 @@ if test -n "$ac_tool_prefix"; then
   # Extract the first word of "ranlib", so it can be a program name with args.
 set dummy ranlib; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1109: checking for $ac_word" >&5
+echo "configure:1158: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1140,7 +1189,7 @@ fi
 # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ar; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1144: checking for $ac_word" >&5
+echo "configure:1193: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1172,7 +1221,7 @@ fi
 # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ld; ac_word=$2
 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1176: checking for $ac_word" >&5
+echo "configure:1225: checking for $ac_word" >&5
 if eval "test \"`echo '$''{'ac_cv_prog_LD'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1203,12 +1252,12 @@ fi
 
 
 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1207: checking for ANSI C header files" >&5
+echo "configure:1256: checking for ANSI C header files" >&5
 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1212 "configure"
+#line 1261 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1216,7 +1265,7 @@ else
 #include <float.h>
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1220: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1269: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1233,7 +1282,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1237 "configure"
+#line 1286 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1251,7 +1300,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1255 "configure"
+#line 1304 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1272,7 +1321,7 @@ if test "$cross_compiling" = yes; then
   :
 else
   cat > conftest.$ac_ext <<EOF
-#line 1276 "configure"
+#line 1325 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1283,7 +1332,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
 exit (0); }
 
 EOF
-if { (eval echo configure:1287: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1336: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   :
 else
@@ -1307,12 +1356,12 @@ EOF
 fi
 
 echo $ac_n "checking for GNU libc2""... $ac_c" 1>&6
-echo "configure:1311: checking for GNU libc2" >&5
+echo "configure:1360: checking for GNU libc2" >&5
   if eval "test \"`echo '$''{'knfsd_cv_glibc2'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1316 "configure"
+#line 1365 "configure"
 #include "confdefs.h"
 
       #include <features.h>
@@ -1321,7 +1370,7 @@ else
       #endif
 EOF
 ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1325: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:1374: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
 ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
 if test -z "$ac_err"; then
   rm -rf conftest*
@@ -1344,7 +1393,7 @@ fi
 
 
 echo $ac_n "checking for main in -lsocket""... $ac_c" 1>&6
-echo "configure:1348: checking for main in -lsocket" >&5
+echo "configure:1397: checking for main in -lsocket" >&5
 ac_lib_var=`echo socket'_'main | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1352,14 +1401,14 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1356 "configure"
+#line 1405 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:1363: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1412: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1380,7 +1429,7 @@ else
 fi
 
 echo $ac_n "checking for main in -lnsl""... $ac_c" 1>&6
-echo "configure:1384: checking for main in -lnsl" >&5
+echo "configure:1433: checking for main in -lnsl" >&5
 ac_lib_var=`echo nsl'_'main | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1388,14 +1437,14 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lnsl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1392 "configure"
+#line 1441 "configure"
 #include "confdefs.h"
 
 int main() {
 main()
 ; return 0; }
 EOF
-if { (eval echo configure:1399: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1448: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1416,7 +1465,7 @@ else
 fi
 
 echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6
-echo "configure:1420: checking for crypt in -lcrypt" >&5
+echo "configure:1469: checking for crypt in -lcrypt" >&5
 ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1424,7 +1473,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lcrypt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1428 "configure"
+#line 1477 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1435,7 +1484,7 @@ int main() {
 crypt()
 ; return 0; }
 EOF
-if { (eval echo configure:1439: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1488: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1455,9 +1504,189 @@ else
   echo "$ac_t""no" 1>&6
 fi
 
+if test "$enable_nfsv4" = yes; then
+    echo $ac_n "checking for event_dispatch in -levent""... $ac_c" 1>&6
+echo "configure:1510: checking for event_dispatch in -levent" >&5
+ac_lib_var=`echo event'_'event_dispatch | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-levent  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1518 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char event_dispatch();
+
+int main() {
+event_dispatch()
+; return 0; }
+EOF
+if { (eval echo configure:1529: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo event | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-levent $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: libevent needed for nfsv4 support" 1>&2; exit 1; }
+fi
+
+    echo $ac_n "checking for nfs4_init_name_mapping in -lnfsidmap""... $ac_c" 1>&6
+echo "configure:1558: checking for nfs4_init_name_mapping in -lnfsidmap" >&5
+ac_lib_var=`echo nfsidmap'_'nfs4_init_name_mapping | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lnfsidmap  $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1566 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char nfs4_init_name_mapping();
+
+int main() {
+nfs4_init_name_mapping()
+; return 0; }
+EOF
+if { (eval echo configure:1577: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_lib=HAVE_LIB`echo nfsidmap | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+    -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lnfsidmap $LIBS"
+
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: libnfsidmap needed for nfsv4 support" 1>&2; exit 1; }
+fi
+
+    for ac_hdr in event.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1609: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1614 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1619: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: libevent needed for nfsv4 support" 1>&2; exit 1; }
+fi
+done
+
+    for ac_hdr in nfsidmap.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1650: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1655 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1660: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: libnfsidmap needed for nfsv4 support" 1>&2; exit 1; }
+fi
+done
+
+fi
 if test "$knfsd_cv_glibc2" = no; then
     echo $ac_n "checking for daemon in -lbsd""... $ac_c" 1>&6
-echo "configure:1461: checking for daemon in -lbsd" >&5
+echo "configure:1690: checking for daemon in -lbsd" >&5
 ac_lib_var=`echo bsd'_'daemon | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1465,7 +1694,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lbsd  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1469 "configure"
+#line 1698 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1476,7 +1705,7 @@ int main() {
 daemon()
 ; return 0; }
 EOF
-if { (eval echo configure:1480: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1709: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1503,14 +1732,14 @@ fi
 
 
 echo $ac_n "checking for the tcp wrapper library""... $ac_c" 1>&6
-echo "configure:1507: checking for the tcp wrapper library" >&5
+echo "configure:1736: checking for the tcp wrapper library" >&5
   if eval "test \"`echo '$''{'knfsd_cv_tcp_wrapper'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   old_LIBS="$LIBS"
    LIBS="$LIBS -lwrap $LIBNSL"
    cat > conftest.$ac_ext <<EOF
-#line 1514 "configure"
+#line 1743 "configure"
 #include "confdefs.h"
 
       int deny_severity = 0;
@@ -1519,7 +1748,7 @@ int main() {
 return hosts_ctl ("nfsd", "", "")
 ; return 0; }
 EOF
-if { (eval echo configure:1523: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1752: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   knfsd_cv_tcp_wrapper=yes
 else
 
 
 
+if test "$enable_gss" = yes; then
+    for ac_hdr in nfsidmap.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1779: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1784 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1789: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+{ echo "configure: error: libnfsidmap needed for gss support" 1>&2; exit 1; }
+fi
+done
+
+  
+            echo $ac_n "checking for Kerberos v5""... $ac_c" 1>&6
+echo "configure:1818: checking for Kerberos v5" >&5
+  # Check whether --with-krb5 or --without-krb5 was given.
+if test "${with_krb5+set}" = set; then
+  withval="$with_krb5"
+   case "$withval" in
+    yes|no)
+       krb5_with=""
+       ;;
+    *)
+       krb5_with="$withval"
+       ;;
+    esac 
+  
+fi
+
+
+  for dir in $krb5_with /usr/kerberos /usr/local /usr/local/krb5 /usr/krb5 \
+             /usr/heimdal /usr/local/heimdal /usr/athena /usr ; do
+            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
+         cat >> confdefs.h <<\EOF
+#define HAVE_KRB5 1
+EOF
+
+         KRBDIR="$dir"
+         K5VERS=`$K5CONFIG --version | awk '{split($4,v,"."); print v[1]v[2]v[3] }'`
+         cat >> confdefs.h <<EOF
+#define KRB5_VERSION $K5VERS
+EOF
+
+         KRBLIB=`$K5CONFIG --libs gssapi`
+         if test $K5VERS -le 131; then
+           cat >> confdefs.h <<\EOF
+#define USE_PRIVATE_KRB5_FUNCTIONS 1
+EOF
+
+         fi
+         echo $ac_n "checking for gss_krb5_export_lucid_sec_context in -lgssapi_krb5""... $ac_c" 1>&6
+echo "configure:1864: checking for gss_krb5_export_lucid_sec_context in -lgssapi_krb5" >&5
+ac_lib_var=`echo gssapi_krb5'_'gss_krb5_export_lucid_sec_context | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi_krb5 $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1872 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_export_lucid_sec_context();
+
+int main() {
+gss_krb5_export_lucid_sec_context()
+; return 0; }
+EOF
+if { (eval echo configure:1883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LUCID_CONTEXT_SUPPORT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         echo $ac_n "checking for gss_krb5_set_allowable_enctypes in -lgssapi_krb5""... $ac_c" 1>&6
+echo "configure:1907: checking for gss_krb5_set_allowable_enctypes in -lgssapi_krb5" >&5
+ac_lib_var=`echo gssapi_krb5'_'gss_krb5_set_allowable_enctypes | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi_krb5 $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1915 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_set_allowable_enctypes();
+
+int main() {
+gss_krb5_set_allowable_enctypes()
+; return 0; }
+EOF
+if { (eval echo configure:1926: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SET_ALLOWABLE_ENCTYPES 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         echo $ac_n "checking for gss_krb5_ccache_name in -lgssapi_krb5""... $ac_c" 1>&6
+echo "configure:1950: checking for gss_krb5_ccache_name in -lgssapi_krb5" >&5
+ac_lib_var=`echo gssapi_krb5'_'gss_krb5_ccache_name | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi_krb5 $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1958 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_ccache_name();
+
+int main() {
+gss_krb5_ccache_name()
+; return 0; }
+EOF
+if { (eval echo configure:1969: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         break
+                  elif test \( -f $dir/include/heim_err.h -o\
+                -f $dir/include/heimdal/heim_err.h \) -a \
+                -f $dir/lib/libroken.a; then
+         cat >> confdefs.h <<\EOF
+#define HAVE_HEIMDAL 1
+EOF
+
+         KRBDIR="$dir"
+         K5VERS=`$K5CONFIG --version | head -1 | awk '{split($2,v,"."); print v[1]v[2]v[3] }'`
+         cat >> confdefs.h <<EOF
+#define KRB5_VERSION $K5VERS
+EOF
+
+         KRBLIB=`$K5CONFIG --libs gssapi`
+         echo $ac_n "checking for gss_krb5_export_lucid_sec_context in -lgssapi""... $ac_c" 1>&6
+echo "configure:2008: checking for gss_krb5_export_lucid_sec_context in -lgssapi" >&5
+ac_lib_var=`echo gssapi'_'gss_krb5_export_lucid_sec_context | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2016 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_export_lucid_sec_context();
+
+int main() {
+gss_krb5_export_lucid_sec_context()
+; return 0; }
+EOF
+if { (eval echo configure:2027: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_LUCID_CONTEXT_SUPPORT 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         echo $ac_n "checking for gss_krb5_set_allowable_enctypes in -lgssapi""... $ac_c" 1>&6
+echo "configure:2051: checking for gss_krb5_set_allowable_enctypes in -lgssapi" >&5
+ac_lib_var=`echo gssapi'_'gss_krb5_set_allowable_enctypes | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2059 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_set_allowable_enctypes();
+
+int main() {
+gss_krb5_set_allowable_enctypes()
+; return 0; }
+EOF
+if { (eval echo configure:2070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_SET_ALLOWABLE_ENCTYPES 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+         echo $ac_n "checking for gss_krb5_ccache_name in -lgssapi""... $ac_c" 1>&6
+echo "configure:2094: checking for gss_krb5_ccache_name in -lgssapi" >&5
+ac_lib_var=`echo gssapi'_'gss_krb5_ccache_name | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  ac_save_LIBS="$LIBS"
+LIBS="-lgssapi $KRBLIB $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 2102 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error.  */
+/* We use char because int might match the return type of a gcc2
+    builtin and then its argument prototype would still apply.  */
+char gss_krb5_ccache_name();
+
+int main() {
+gss_krb5_ccache_name()
+; return 0; }
+EOF
+if { (eval echo configure:2113: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=yes"
+else
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+  cat >> confdefs.h <<\EOF
+#define HAVE_GSS_KRB5_CCACHE_NAME 1
+EOF
+
+else
+  echo "$ac_t""no" 1>&6
+fi
+
+        break
+      fi
+      CFLAGS=$CFLAGS `$K5CONFIG --cflags`
+    fi
+  done
+    if test "x$KRBDIR" = "x"; then
+    echo "$ac_t"""no"" 1>&6
+    if test "x$krb5_with" = "x"; then
+      { echo "configure: error: Kerberos v5 with GSS support not found: consider --disable-gss or --with-krb5=" 1>&2; exit 1; }
+    else
+      { echo "configure: error: Kerberos v5 with GSS support not found at $krb5_with" 1>&2; exit 1; }
+    fi
+  fi
+  echo "$ac_t""$KRBDIR" 1>&6
+    if test "x$krb5_with" != "x" -a "$krb5_with" != "$KRBDIR"; then
+    echo "configure: warning: Using $KRBDIR instead of requested value of $krb5_with for Kerberos!" 1>&2
+  fi
+
+  
+  
+  
+fi
+
 
 for ac_func in innetgr
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1549: checking for $ac_func" >&5
+echo "configure:2163: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1554 "configure"
+#line 2168 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1573,7 +2187,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1577: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2191: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1707,7 +2321,7 @@ done
 ac_given_srcdir=$srcdir
 ac_given_INSTALL="$INSTALL"
 
-trap 'rm -fr `echo "config.mk nfs-utils.spec utils/Makefile support/include/config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+trap 'rm -fr `echo "config.mk utils/Makefile support/include/config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
 EOF
 cat >> $CONFIG_STATUS <<EOF
 
@@ -1744,6 +2358,11 @@ s%@RELEASE@%$RELEASE%g
 s%@statedir@%$statedir%g
 s%@statduser@%$statduser%g
 s%@enable_nfsv3@%$enable_nfsv3%g
+s%@IDMAPD@%$IDMAPD%g
+s%@enable_nfsv4@%$enable_nfsv4%g
+s%@GSSD@%$GSSD%g
+s%@SVCGSSD@%$SVCGSSD%g
+s%@enable_gss@%$enable_gss%g
 s%@kprefix@%$kprefix%g
 s%@secure_statd@%$secure_statd%g
 s%@RQUOTAD@%$RQUOTAD%g
@@ -1771,6 +2390,9 @@ s%@LIBNSL@%$LIBNSL%g
 s%@LIBCRYPT@%$LIBCRYPT%g
 s%@LIBBSD@%$LIBBSD%g
 s%@LIBWRAP@%$LIBWRAP%g
+s%@KRBDIR@%$KRBDIR%g
+s%@KRBLIB@%$KRBLIB%g
+s%@K5VERS@%$K5VERS%g
 
 CEOF
 EOF
@@ -1812,7 +2434,7 @@ EOF
 
 cat >> $CONFIG_STATUS <<EOF
 
-CONFIG_FILES=\${CONFIG_FILES-"config.mk nfs-utils.spec utils/Makefile"}
+CONFIG_FILES=\${CONFIG_FILES-"config.mk utils/Makefile"}
 EOF
 cat >> $CONFIG_STATUS <<\EOF
 for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
index 2f20cef6174bace71dfbdecc016a0a7ecbf61da1..aaffb2d7f1fc561ec6bde8871e4cdd2f1adc3f21 100644 (file)
@@ -4,7 +4,7 @@ AC_INIT(rules.mk)
 AC_PREFIX_DEFAULT(/usr)
 
 # The nfs-utils version
-VERSION="1.0.6"
+VERSION="1.0.7"
 AC_SUBST(VERSION)
 
 dnl *************************************************************
@@ -39,6 +39,35 @@ AC_ARG_ENABLE(nfsv3,
                enable_nfsv3=
        fi
        AC_SUBST(enable_nfsv3)
+AC_ARG_ENABLE(nfsv4,
+       [  --enable-nfsv4          enable support for NFSv4],
+       enable_nfsv4=$enableval,
+       enable_nfsv4=yes)
+       if test "$enable_nfsv4" = yes; then
+               AC_DEFINE(NFS4_SUPPORTED)
+               IDMAPD=idmapd
+       else
+               enable_nfsv4=
+               IDMAPD=
+       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,
@@ -87,6 +116,12 @@ dnl *************************************************************
 AC_CHECK_LIB(socket, main, [LIBSOCKET="-lnsl"])
 AC_CHECK_LIB(nsl, main,        [LIBNSL="-lnsl"])
 AC_CHECK_LIB(crypt, crypt, [LIBCRYPT="-lcrypt"])
+if test "$enable_nfsv4" = yes; then
+    AC_CHECK_LIB(event, event_dispatch, , [AC_MSG_ERROR(libevent needed for nfsv4 support)])
+    AC_CHECK_LIB(nfsidmap, nfs4_init_name_mapping, ,[AC_MSG_ERROR(libnfsidmap needed for nfsv4 support)])
+    AC_CHECK_HEADERS(event.h, ,[AC_MSG_ERROR(libevent needed for nfsv4 support)])
+    AC_CHECK_HEADERS(nfsidmap.h, ,[AC_MSG_ERROR(libnfsidmap needed for nfsv4 support)])
+fi
 if test "$knfsd_cv_glibc2" = no; then
     AC_CHECK_LIB(bsd, daemon, [LIBBSD="-lbsd"])
 fi
@@ -98,6 +133,98 @@ AC_SUBST(LIBBSD)
 AC_TCP_WRAPPER
 AC_SUBST(LIBWRAP)
 
+if test "$enable_gss" = yes; then
+  dnl 'gss' also depends on nfsidmap.h - at least for svcgssd_proc.c
+  AC_CHECK_HEADERS(nfsidmap.h, ,[AC_MSG_ERROR(libnfsidmap needed for gss support)])
+  
+  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
+    AC_MSG_RESULT("no")
+    if test "x$krb5_with" = "x"; then
+      AC_MSG_ERROR(Kerberos v5 with GSS support not found: consider --disable-gss or --with-krb5=)
+    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 *************************************************************
@@ -116,4 +243,4 @@ AC_DEFINE_UNQUOTED(NFS_STATEDIR, "$statedir")
 AC_SUBST(LDFLAGS)
 AC_SUBST(CXXFLAGS)
 AC_SUBST(CFLAGS)
-AC_OUTPUT(config.mk nfs-utils.spec utils/Makefile)
+AC_OUTPUT(config.mk utils/Makefile)
diff --git a/debian/gssapi_mech.conf b/debian/gssapi_mech.conf
new file mode 100644 (file)
index 0000000..2dd2fc5
--- /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.2     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/debian/idmapd.conf b/debian/idmapd.conf
new file mode 100644 (file)
index 0000000..8325982
--- /dev/null
@@ -0,0 +1,10 @@
+[General]
+
+Verbosity = 0
+Pipefs-Directory = /var/lib/nfs/rpc_pipefs
+Domain = localdomain
+
+[Mapping]
+
+Nobody-User = nobody
+Nobody-Group = nogroup
diff --git a/debian/nfs-common.install b/debian/nfs-common.install
new file mode 100644 (file)
index 0000000..8d81caa
--- /dev/null
@@ -0,0 +1,2 @@
+debian/idmapd.conf etc
+debian/gssapi_mech.conf etc
diff --git a/etc/nodist/nfs-client b/etc/nodist/nfs-client
deleted file mode 100755 (executable)
index d1a0029..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-# nfs   This shell script starts and stops the nfs services in a distribution
-#       independent fashion.
-#
-# description:  starts and stops nfs client services
-# chkconfig: 2345 60 86
-#
-# Copyright (c) 2000-2001 Mission Critical Linux, Inc.
-#
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-export PATH
-
-# Who am I?
-SCRIPT_NAME=`basename $0`
-
-# Grab our daemon functions.
-. `dirname $0`/nfs-functions
-
-# Kernel daemons and options
-PREFIX="rpc."          # Prefix for kernel execs (usually "rpc.")
-LOCKD="lockd"          # Lockd
-
-# User daemons and options
-STATD="rpc.statd"      # NLM Server
-
-# We use "type -path" instead of "which" since it's internal to bash.
-[ -x "`type -path $STATD`" ] || exit 0
-[ -x "`type -path $PREFIX$LOCKD`" ] || exit 0
-
-# Handle how we were called.
-case "$1" in
-start)
-    # Start rpc.statd daemon without options...
-    echo -n "Starting $STATD: "
-    startdaemon $STATD
-
-    echo -n "Starting $LOCKD: "
-    startdaemon $PREFIX$LOCKD
-
-    # if this lock file doesn't exist, init won't even try to run
-    # the shutdown script for this service on RedHat systems!
-    # on non-RedHat systems, /var/lock/subsys may not exist.
-    touch /var/lock/subsys/$SCRIPT_NAME &> /dev/null
-    ;;
-
-stop)
-    echo -n "Stopping $STATD: "
-    stopdaemon $STATD
-
-    echo -n "Stopping $LOCKD: "
-    stopdaemon $LOCKD
-
-    rm -f /var/lock/subsys/$SCRIPT_NAME 
-    ;;
-
-restart)
-    $0 stop
-    $0 start
-    ;;
-
-status)
-    daemonstatus $STATD
-    daemonstatus $LOCKD
-
-    exit 0
-    ;;
-
-*)
-    echo "Usage: $0 {start|stop|status|restart}"
-    exit 1
-esac
-
-exit 0
diff --git a/etc/nodist/nfs-functions b/etc/nodist/nfs-functions
deleted file mode 100755 (executable)
index 1f7b050..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/bin/bash
-#
-# An attempt at a simple, distribution-independent daemon management.
-#
-# Copyright (C) 2000-2001 Mission Critical Linux, Inc.
-#
-
-# daemon functions
-getpid()
-{
-    pid=''
-    if [ -f /var/run/${base}.pid ] 
-    then
-        pid=`head -1 /var/run/${base}.pid`
-    fi
-    if [ "$pid" = "" ]
-    then
-        pid=`pidof $1`
-    fi
-    if [ "$pid" = "" ]
-    then
-        pid=`ps ax | awk 'BEGIN { prog=ARGV[1]; ARGC=1 }
-                   { if ((prog == $5) || (("(" prog ")") == $5) ||
-                     (("[" prog "]") == $5) ||
-                   ((prog ":") == $5)) { print $1 ; exit 0 } }' $1`
-    fi
-
-    echo $pid
-}
-
-startdaemon()
-{
-    base=`basename $1`
-
-    # check if it is already running
-    pid=`getpid $base`
-    [ -n "$pid" ] && ps h $pid >/dev/null 2>&1 && echo " already running." && return
-
-    # don't dump core
-    ulimit -c 0
-
-    $* && echo " done." || echo " failed."
-}
-
-stopdaemon()
-{
-    base=`basename $1`
-    pid=`getpid $base`
-
-    if [ "$pid" != "" ]
-    then
-        if ps h $pid>/dev/null 2>&1
-        then
-            kill -TERM $pid
-            if ps h $pid>/dev/null 2>&1
-            then
-                sleep 1
-                if ps h $pid>/dev/null 2>&1
-                then
-                    sleep 3
-                    if ps h $pid>/dev/null 2>&1
-                    then
-                        kill -KILL $pid
-                       sleep 2
-                    fi
-                fi
-            fi
-        fi
-        ps h $pid >/dev/null 2>&1
-        RC=$?
-        [ $RC -eq 0 ] && echo " failed." || echo " done."
-        [ $RC -eq 0 ] || rm -f /var/run/$base.pid >/dev/null 2>&1
-    else
-        echo " not running."
-    fi
-}
-
-daemonstatus()
-{
-    base=`basename $1`
-    pid=`getpid $base`
-    
-    if [ "$pid" != "" ]
-    then
-        if ps h $pid >/dev/null 2>&1
-        then
-            echo "$base (pid $pid) is running."
-            return 0
-        else
-            if [ -f /var/run/${base}.pid ]
-            then
-                echo "$base dead but pid file exists."
-                return 1
-            else
-                echo "$base is stopped."
-                return 2
-            fi
-        fi
-    else
-        echo "$base is stopped."
-        return 3
-    fi
-}
-
diff --git a/etc/nodist/nfs-server b/etc/nodist/nfs-server
deleted file mode 100755 (executable)
index 8f1d34b..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/bin/sh
-# nfs   This shell script starts and stops the nfs services in a distribution
-#       independent fashion.
-#
-# description:  starts and stops nfs server services
-# chkconfig: 2345 60 20
-#
-# Copyright (c) 2000-2001 Mission Critical Linux, Inc.
-#
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin
-export PATH
-
-# Who am I?
-SCRIPT_NAME=`basename $0`
-
-# Grab our daemon functions.
-. `dirname $0`/nfs-functions
-
-# Kernel daemons and options
-PREFIX="rpc."          # Prefix for kernel execs (usually "rpc.")
-NFSD="nfsd"            # Kernel NFS Server
-RPCNFSDCOUNT="8"       # Number of nfsd threads
-
-# User daemons and options
-RQUOTAD="rpc.rquotad"  # Remote quota server
-MOUNTD="rpc.mountd"    # Mount server
-RPCMOUNTDOPTS=""       # options for rpc.mountd
-EXPORTFS="exportfs"    # Exportfs command
-
-SCRIPT_NAME=`basename $0`
-DESC="NFS kernel daemon"
-
-# We use "type -path" instead of "which" since it's internal to bash.
-[ -x "`type -path $PREFIX$NFSD`" ] || exit 0
-[ -x "`type -path $MOUNTD`" ] || exit 0
-
-# Also make sure we have our exportfs command.
-[ -x "`type -path $EXPORTFS`" ] || exit 0
-[ -s /etc/exports ] || exit 0
-
-# rquotad is not required for NFS to work, however.
-# Unset if it is not present.
-[ -x "`type -path $RQUOTAD`" ] || unset RQUOTAD
-
-# Handle how we were called.
-case "$1" in
-start)
-    echo -n "Exporting directories for $DESC..."
-    $EXPORTFS -r
-    echo "done."
-
-    echo -n "Starting $NFSD: "
-    startdaemon $PREFIX$NFSD $RPCNFSDCOUNT
-
-    # Disable NFSv3 on mountd if we don't have NFSv3
-    ClearAddr=
-    if [ -f /proc/net/rpc/auth.unix.ip/channel ] ; then
-      if   grep -s 127.0.0.1 /proc/net/rpc/auth.unix.ip/content > /dev/null ; then
-            : address already known
-      else
-             echo nfsd 127.0.0.1 2147483647 localhost > /proc/net/rpc/auth.unix.ip/channel
-            ClearAddr=
-      fi
-    fi
-    rpcinfo -u localhost nfs 3 &>/dev/null 
-    if [ "$?" != "0" ]
-    then
-        RPCMOUNTDOPTS="$RPCMOUNTDOPTS --no-nfs-version 3"
-    fi
-    if [ -n "$ClearAddr" ]; then
-          echo nfsd 127.0.0.1 1  > /proc/net/rpc/auth.unix.ip/channel
-    fi
-
-    echo -n "Starting $MOUNTD: "
-    startdaemon $MOUNTD $RPCMOUNTDOPTS
-
-    # Start rquotad if it is set
-    if [ -n "$RQUOTAD" ]
-    then
-        echo -n "Starting $RQUOTAD: "
-        startdaemon $RQUOTAD
-    fi
-
-    # if this lock file doesn't exist, init won't even try to run
-    # the shutdown script for this service on RedHat systems!
-    # on non-RedHat systems, /var/lock/subsys may not exist.
-    touch /var/lock/subsys/$SCRIPT_NAME &> /dev/null
-    ;;
-
-stop)
-    for process in $RQUOTAD $MOUNTD $NFSD
-    do
-        echo -n "Stopping $process: "
-        stopdaemon $process
-    done
-
-    echo "Unexporting directories for $DESC..."
-    $EXPORTFS -au
-    rm -f /var/lock/subsys/$SCRIPT_NAME 
-    echo "done."
-    ;;
-
-restart)
-    $0 stop
-    $0 start
-    ;;
-
-reload)
-    # Update exports
-    echo "Re-exporting directories for $DESC..."
-    $EXPORTFS -r
-    touch /var/lock/subsys/$SCRIPT_NAME &> /dev/null
-    echo "done."
-    ;;
-
-status)
-    # First, check status of userland daemons
-    for process in $RQUOTAD $MOUNTD $NFSD
-    do
-       daemonstatus $process
-    done
-    exit 0
-    ;;
-
-*)
-    echo "Usage: $0 {start|stop|status|restart|reload}"
-    exit 1
-esac
diff --git a/etc/redhat/nfs b/etc/redhat/nfs
deleted file mode 100644 (file)
index 5e21f1f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# For more information on nfs tuning, please see the NFS-HOWTO
-# http://nfs.sourceforge.net/nfs-howto/
-
-# Pass any additional options for mountd.
-# MOUNTD_OPTIONS=
-
-# Pin mountd to a given port rather than random one from portmapper
-# MOUNTD_PORT=
-
-# Don't advertise TCP for mount.
-# MOUNTD_TCP=no
-
-# NFS V3
-# MOUNTD_NFS_V3=auto|yes|no
-
-# NFS V2
-# MOUNTD_NFS_V2=auto|yes|no
-
-# The number of open file descriptors
-# MOUNTD_OPEN_FILES=128
-
-# Pass the number of instances of nfsd (8 is default; 16 or more
-# might be needed to handle heavy client traffic)
-# NFSDCOUNT=8
-
-# Increase the memory limits on the socket input queues for
-# the nfs processes .. NFS  benchmark SPECsfs demonstrate a
-# need for a larger than default size (64kb) .. setting
-# TUNE_QUEUE to yes will set the values to 256kb.
-# TUNE_QUEUE="yes"
-# NFS_QS=262144
diff --git a/etc/redhat/nfs.init b/etc/redhat/nfs.init
deleted file mode 100755 (executable)
index ac45937..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/bin/sh
-#
-# nfs           This shell script takes care of starting and stopping
-#               the NFS services.
-#
-# chkconfig: - 60 20
-# description: NFS is a popular protocol for file sharing across TCP/IP \
-#              networks. This service provides NFS server functionality, \
-#              which is configured via the /etc/exports file.
-# probe: true
-# config: /etc/sysconfig/nfs
-
-# Source function library.
-. /etc/rc.d/init.d/functions
-
-# Source networking configuration.
-if [ ! -f /etc/sysconfig/network ]; then
-    exit 0
-fi
-
-. /etc/sysconfig/network
-
-# Check that networking is up.
-[ ${NETWORKING} = "no" ] && exit 0
-
-[ -x /usr/sbin/rpc.nfsd ] || exit 0
-[ -x /usr/sbin/rpc.mountd ] || exit 0
-[ -x /usr/sbin/exportfs ] || exit 0
-[ -s /etc/exports ] || exit 0
-
-# Check for and source configuration file otherwise set defaults
-# TUNE_QUEUE: controls whether to up the size of input queues
-[ -f /etc/sysconfig/nfs ] && . /etc/sysconfig/nfs
-
-[ -z "$MOUNTD_NFS_V2" ] && MOUNTD_NFS_V2=auto
-[ -z "$MOUNTD_NFS_V3" ] && MOUNTD_NFS_V3=auto
-
-# Number of servers to be started by default
-[ -z "$NFSDCOUNT" ] && NFSDCOUNT=8
-
-# Remote quota server
-[ -z "$RQUOTAD" ] && RQUOTAD=`type -path rpc.rquotad`
-
-# Get the initial values for the input sock queues
-# at the time of running the script.
-if [ "$TUNE_QUEUE" = "yes" ]; then
-    RMEM_DEFAULT=`/sbin/sysctl -n net.core.rmem_default`
-    RMEM_MAX=`/sbin/sysctl -n net.core.rmem_max`
-    # 256kb recommended minimum size based on SPECsfs NFS benchmarks
-    [ -z "$NFS_QS" ] && NFS_QS=262144
-fi
-
-# See how we were called.
-case "$1" in
-  start)
-       # Start daemons.
-       # Apply input queue increase for nfs server
-       if [ "$TUNE_QUEUE" = "yes" ]; then
-           /sbin/sysctl -w net.core.rmem_default=$NFSD_QS >/dev/null 2>&1
-           /sbin/sysctl -w net.core.rmem_max=$NFSD_QS >/dev/null 2>&1
-       fi
-       action "Starting NFS services: " /usr/sbin/exportfs -r
-       if [ -n "$RQUOTAD" -a "$RQUOTAD" != "no" ]; then
-           echo -n "Starting NFS quotas: "
-           daemon rpc.rquotad
-           echo
-       fi
-       echo -n "Starting NFS daemon: "
-       daemon rpc.nfsd $NFSDCOUNT
-       echo
-
-       [ -n "$MOUNTD_PORT" ] \
-       && MOUNTD_OPTIONS="$MOUNTD_OPTIONS -p $MOUNTD_PORT"
-       [ "$MOUNTD_TCP" = "no" -o "$MOUNTD_TCP" = "NO" ] \
-       && MOUNTD_OPTIONS="$MOUNTD_OPTIONS --no-tcp"
-
-       case $MOUNTD_NFS_V2 in
-       auto|AUTO)
-           # Let's see if we support NFS version 2.
-           ClearAddr=
-           if [ -f /proc/net/rpc/auth.unix.ip/channel ] ; then
-              if   grep -s 127.0.0.1 /proc/net/rpc/auth.unix.ip/content > /dev/null ; then
-                   : address already known
-              else
-                    echo nfsd 127.0.0.1 2147483647 localhost > /proc/net/rpc/auth.unix.ip/channel
-                   ClearAddr=yes
-             fi
-           fi
-           /usr/sbin/rpcinfo -u localhost nfs 2 &>/dev/null
-           if [ $? -ne 0 ]; then
-               MOUNTD_OPTIONS="$MOUNTD_OPTIONS --no-nfs-version 2"
-           fi
-           if [ -n "$ClearAddr" ]; then
-                  echo nfsd 127.0.0.1 1  > /proc/net/rpc/auth.unix.ip/channel
-           fi
-           ;;
-       no|NO)
-           MOUNTD_OPTIONS="$MOUNTD_OPTIONS --no-nfs-version 2"
-           ;;
-       yes|YES)
-           MOUNTD_OPTIONS="$MOUNTD_OPTIONS --nfs-version 2"
-           ;;
-       esac
-
-       case $MOUNTD_NFS_V3 in
-       auto|AUTO)
-           # Let's see if we support NFS version 3.
-           /usr/sbin/rpcinfo -u localhost nfs 3 &>/dev/null
-           if [ $? -ne 0 ]; then
-               MOUNTD_OPTIONS="$MOUNTD_OPTIONS --no-nfs-version 3"
-           fi
-           ;;
-       no|NO)
-           MOUNTD_OPTIONS="$MOUNTD_OPTIONS --no-nfs-version 3"
-           ;;
-       yes|YES)
-           MOUNTD_OPTIONS="$MOUNTD_OPTIONS --nfs-version 3"
-           ;;
-       esac
-
-       echo -n "Starting NFS mountd: "
-       daemon rpc.mountd $MOUNTD_OPTIONS
-       echo
-       touch /var/lock/subsys/nfs
-       # reset input queue for rest of network services
-       if [ "$TUNE_QUEUE" = "yes" ]; then
-           /sbin/sysctl -w net.core.rmem_default=$RMEM_DEFAULT >/dev/null 2>&1
-           /sbin/sysctl -w net.core.rmem_max=$RMEM_MAX >/dev/null 2>&1
-       fi
-       ;;
-  stop)
-       # Stop daemons.
-       echo -n "Shutting down NFS mountd: "
-       killproc rpc.mountd
-       echo
-       echo -n "Shutting down NFS daemon: "
-       killproc nfsd
-       echo
-       if [ -n "$RQUOTAD" ]; then
-               echo -n "Shutting down NFS quotas: "
-               killproc rpc.rquotad
-               echo
-       fi
-       # Do it the last so that clients can still access the server
-       # when the server is running.
-       action "Shutting down NFS services: " /usr/sbin/exportfs -au
-       rm -f /var/lock/subsys/nfs
-       ;;
-  status)
-       status rpc.mountd
-       status nfsd
-       if [ -n "$RQUOTAD" ]; then
-               status rpc.rquotad
-       fi
-       ;;
-  restart)
-       $0 stop
-       $0 start
-       ;;
-  reload)
-       /usr/sbin/exportfs -r
-       touch /var/lock/subsys/nfs
-       ;;
-  probe)
-       if [ ! -f /var/lock/subsys/nfs ] ; then
-         echo start; exit 0
-       fi
-       /sbin/pidof rpc.mountd >/dev/null 2>&1; MOUNTD="$?"
-       /sbin/pidof nfsd >/dev/null 2>&1; NFSD="$?"
-       if [ $MOUNTD = 1 -o $NFSD = 1 ] ; then
-         echo restart; exit 0
-       fi
-       if [ /etc/exports -nt /var/lock/subsys/nfs ] ; then
-         echo reload; exit 0
-       fi
-       ;;
-  *)
-       echo "Usage: nfs {start|stop|status|restart|reload}"
-       exit 1
-esac
-
-exit 0
diff --git a/etc/redhat/nfslock.init b/etc/redhat/nfslock.init
deleted file mode 100755 (executable)
index 2f99c45..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh
-#
-# nfslock       This shell script takes care of starting and stopping
-#               the NFS file locking service.
-#
-# chkconfig: 345 60 86
-# description: NFS is a popular protocol for file sharing across \
-#             TCP/IP networks. This service provides NFS file \
-#             locking functionality.
-# probe: true
-
-# Source function library.
-. /etc/rc.d/init.d/functions
-
-# Source networking configuration.
-if [ ! -f /etc/sysconfig/network ]; then
-    exit 0
-fi
-
-. /etc/sysconfig/network
-
-# Check that networking is up.
-[ ${NETWORKING} = "no" ] && exit 0
-
-[ -x /sbin/rpc.lockd ] || exit 0
-[ -x /sbin/rpc.statd ] || exit 0
-
-if [ -n "${STATD_HOSTNAME}" ]; then
-    STATDARG="-n ${STATD_HOSTNAME}"
-else
-    STATDARG=""
-fi
-
-# See how we were called.
-case "$1" in
-  start)
-       # Start daemons.
-       echo "Starting NFS file locking services: "
-       echo -n "Starting NFS lockd: "
-       daemon rpc.lockd
-       echo
-       echo -n "Starting NFS statd: "
-       daemon rpc.statd ${STATDARG}
-       echo
-       touch /var/lock/subsys/nfslock
-       ;;
-  stop)
-       # Stop daemons.
-       echo "Shutting down NFS file locking services: "
-       pidlist=`pidofproc lockd`
-       if [ -n "$pidlist" ]; then
-               pid=
-               for apid in $pidlist ; do
-                       [ -f /proc/$apid/exe ] && pid="$pid $apid"
-               done
-               if [ -n "$pid" ]; then
-                       echo -n "Shutting down NFS lockd: "
-                       killproc lockd
-                       echo
-               fi
-       fi
-       echo -n "Shutting down NFS statd: "
-       killproc rpc.statd
-       echo
-       rm -f /var/lock/subsys/nfslock
-       ;;
-  status)
-       status lockd
-       status rpc.statd
-       ;;
-  restart)
-       $0 stop
-       $0 start
-       ;;
-  probe)
-       if [ ! -f /var/lock/subsys/nfslock ] ; then
-         echo start; exit 0
-       fi
-       /sbin/pidof rpc.statd >/dev/null 2>&1; STATD="$?"
-       /sbin/pidof lockd >/dev/null 2>&1; LOCKD="$?"
-       if [ $STATD = 1 -o $LOCKD = 1 ] ; then
-         echo restart; exit 0
-       fi
-       ;;
-  *)
-       echo "Usage: nfslock {start|stop|status|restart}"
-       exit 1
-esac
-
-exit 0
diff --git a/nfs-utils.spec b/nfs-utils.spec
deleted file mode 100644 (file)
index 81feb54..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-%define rquotad 0
-%{?do_rquotad:%define rquotad 1}
-
-# We don't use libtool. 
-%define __libtoolize :
-
-Summary: NFS utlilities and supporting daemons for the kernel NFS server.
-Name: nfs-utils
-Version: 1.0.6
-Release: 1
-Source0: ftp://nfs.sourceforge.net/pub/nfs/%{name}-%{version}.tar.gz
-Group: System Environment/Daemons
-Obsoletes: nfs-server
-Obsoletes: knfsd
-Obsoletes: knfsd-clients
-Obsoletes: nfs-server-clients 
-Obsoletes: knfsd-lock
-Provides: nfs-server 
-Provides: nfs-server-clients 
-Provides: knfsd-lock 
-Provides: knfsd-clients 
-Provides: knfsd
-Copyright: GPL
-Buildroot: /var/tmp/%{name}-root
-Requires: kernel >= 2.2.7, portmap >= 4.0
-
-%description
-The nfs-utils package provides a daemon for the kernel NFS server and
-related tools, which provides a much higher level of performance than the
-traditional Linux NFS server used by most users.
-
-This package also contains the showmount program.  Showmount queries the
-mount daemon on a remote host for information about the NFS (Network File
-System) server on the remote host.  For example, showmount can display the
-clients which are mounted on that host.
-
-%prep
-%setup -q
-
-%build
-CC=%{__cc}; export CC
-CC_FOR_BUILD=gcc; export CC_FOR_BUILD
-%configure \
-%if !%{rquotad}
-       --disable-rquotad \
-%endif
-       --build=%{_build_alias}
-
-make all
-
-%install
-rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/{/sbin,/usr/sbin}
-mkdir -p $RPM_BUILD_ROOT%{_mandir}/{man5,man8}
-mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
-mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
-mkdir -p $RPM_BUILD_ROOT/var/lib/nfs
-make install_prefix=$RPM_BUILD_ROOT MANDIR=$RPM_BUILD_ROOT%{_mandir} SBINDIR=$RPM_BUILD_ROOT%{_prefix}/sbin install
-install -s -m 755 tools/rpcdebug/rpcdebug $RPM_BUILD_ROOT/sbin
-install -m 755 etc/redhat/nfs.init $RPM_BUILD_ROOT/etc/rc.d/init.d/nfs
-install -m 755 etc/redhat/nfs $RPM_BUILD_ROOT/etc/sysconfig/nfs
-install -m 755 etc/redhat/nfslock.init $RPM_BUILD_ROOT/etc/rc.d/init.d/nfslock
-touch $RPM_BUILD_ROOT/var/lib/nfs/rmtab
-mv $RPM_BUILD_ROOT/usr/sbin/{rpc.lockd,rpc.statd} $RPM_BUILD_ROOT/sbin
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post
-/sbin/chkconfig --add nfs
-/sbin/chkconfig --add nfslock
-
-%preun
-if [ "$1" = "0" ]; then
-    /sbin/chkconfig --del nfs
-    /sbin/chkconfig --del nfslock
-fi
-
-%triggerpostun -- nfs-server
-/sbin/chkconfig --add nfs
-
-%triggerpostun -- knfsd
-/sbin/chkconfig --add nfs
-
-%triggerpostun -- knfsd-clients
-/sbin/chkconfig --add nfslock
-
-%files
-%defattr(-,root,root)
-%config /etc/rc.d/init.d/nfs
-%dir /var/lib/nfs
-%config(noreplace) /etc/sysconfig/nfs
-%config(noreplace) /var/lib/nfs/xtab
-%config(noreplace) /var/lib/nfs/etab
-%config(noreplace) /var/lib/nfs/rmtab
-/sbin/rpcdebug
-/sbin/rpc.lockd
-/sbin/rpc.statd
-/usr/sbin/exportfs
-/usr/sbin/nfsstat
-/usr/sbin/nhfsstone
-/usr/sbin/rpc.mountd
-/usr/sbin/rpc.nfsd
-%if %{rquotad}
-/usr/sbin/rpc.rquotad
-%endif
-/usr/sbin/showmount
-%{_mandir}/man?/*
-%config /etc/rc.d/init.d/nfslock
-%doc README ChangeLog COPYING
diff --git a/nfs-utils.spec.in b/nfs-utils.spec.in
deleted file mode 100644 (file)
index 05a6926..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-%define rquotad 0
-%{?do_rquotad:%define rquotad 1}
-
-# We don't use libtool. 
-%define __libtoolize :
-
-Summary: NFS utlilities and supporting daemons for the kernel NFS server.
-Name: nfs-utils
-Version: @VERSION@
-Release: @RELEASE@
-Source0: ftp://nfs.sourceforge.net/pub/nfs/%{name}-%{version}.tar.gz
-Group: System Environment/Daemons
-Obsoletes: nfs-server
-Obsoletes: knfsd
-Obsoletes: knfsd-clients
-Obsoletes: nfs-server-clients 
-Obsoletes: knfsd-lock
-Provides: nfs-server 
-Provides: nfs-server-clients 
-Provides: knfsd-lock 
-Provides: knfsd-clients 
-Provides: knfsd
-Copyright: GPL
-Buildroot: /var/tmp/%{name}-root
-Requires: kernel >= 2.2.7, portmap >= 4.0
-
-%description
-The nfs-utils package provides a daemon for the kernel NFS server and
-related tools, which provides a much higher level of performance than the
-traditional Linux NFS server used by most users.
-
-This package also contains the showmount program.  Showmount queries the
-mount daemon on a remote host for information about the NFS (Network File
-System) server on the remote host.  For example, showmount can display the
-clients which are mounted on that host.
-
-%prep
-%setup -q
-
-%build
-CC=%{__cc}; export CC
-CC_FOR_BUILD=gcc; export CC_FOR_BUILD
-%configure \
-%if !%{rquotad}
-       --disable-rquotad \
-%endif
-       --build=%{_build_alias}
-
-make all
-
-%install
-rm -rf $RPM_BUILD_ROOT
-mkdir -p $RPM_BUILD_ROOT/{/sbin,/usr/sbin}
-mkdir -p $RPM_BUILD_ROOT%{_mandir}/{man5,man8}
-mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d
-mkdir -p $RPM_BUILD_ROOT/etc/sysconfig
-mkdir -p $RPM_BUILD_ROOT/var/lib/nfs
-make install_prefix=$RPM_BUILD_ROOT MANDIR=$RPM_BUILD_ROOT%{_mandir} SBINDIR=$RPM_BUILD_ROOT%{_prefix}/sbin install
-install -s -m 755 tools/rpcdebug/rpcdebug $RPM_BUILD_ROOT/sbin
-install -m 755 etc/redhat/nfs.init $RPM_BUILD_ROOT/etc/rc.d/init.d/nfs
-install -m 755 etc/redhat/nfs $RPM_BUILD_ROOT/etc/sysconfig/nfs
-install -m 755 etc/redhat/nfslock.init $RPM_BUILD_ROOT/etc/rc.d/init.d/nfslock
-touch $RPM_BUILD_ROOT/var/lib/nfs/rmtab
-mv $RPM_BUILD_ROOT/usr/sbin/{rpc.lockd,rpc.statd} $RPM_BUILD_ROOT/sbin
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post
-/sbin/chkconfig --add nfs
-/sbin/chkconfig --add nfslock
-
-%preun
-if [ "$1" = "0" ]; then
-    /sbin/chkconfig --del nfs
-    /sbin/chkconfig --del nfslock
-fi
-
-%triggerpostun -- nfs-server
-/sbin/chkconfig --add nfs
-
-%triggerpostun -- knfsd
-/sbin/chkconfig --add nfs
-
-%triggerpostun -- knfsd-clients
-/sbin/chkconfig --add nfslock
-
-%files
-%defattr(-,root,root)
-%config /etc/rc.d/init.d/nfs
-%dir /var/lib/nfs
-%config(noreplace) /etc/sysconfig/nfs
-%config(noreplace) /var/lib/nfs/xtab
-%config(noreplace) /var/lib/nfs/etab
-%config(noreplace) /var/lib/nfs/rmtab
-/sbin/rpcdebug
-/sbin/rpc.lockd
-/sbin/rpc.statd
-/usr/sbin/exportfs
-/usr/sbin/nfsstat
-/usr/sbin/nhfsstone
-/usr/sbin/rpc.mountd
-/usr/sbin/rpc.nfsd
-%if %{rquotad}
-/usr/sbin/rpc.rquotad
-%endif
-/usr/sbin/showmount
-%{_mandir}/man?/*
-%config /etc/rc.d/init.d/nfslock
-%doc README ChangeLog COPYING
index 37b6359267dbe1a8cd777186e083d56339fa2367..aa56fa7fc4c66fff18b4d33f3557da61385d3367 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for linux-nfs/support
 #
 
-SUBDIRS        = include nfs export lib misc
+SUBDIRS        = include nfs export lib misc rpc gssapi
 .DEFAULT: all
 
 include $(TOP)rules.mk
index 3db21ae2840419bdfc50bdaa816db55cd4615adc..57176d880077a53e40b0e27532643ecd7b4e2620 100644 (file)
@@ -138,7 +138,9 @@ client_init(nfs_client *clp, const char *hname, struct hostent *hp)
 
        if (clp->m_type == MCL_SUBNETWORK) {
                char    *cp = strchr(clp->m_hostname, '/');
+               static char slash32[] = "/32";
 
+               if(!cp) cp = slash32;
                *cp = '\0';
                clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
                if (strchr(cp + 1, '.')) {
@@ -392,6 +394,8 @@ client_check(nfs_client *clp, struct hostent *hp)
 #endif
        case MCL_ANONYMOUS:
                return 1;
+       case MCL_GSS:
+               return 0;
        default:
                xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
        }
@@ -425,6 +429,8 @@ client_gettype(char *ident)
 
        if (ident[0] == '\0' || strcmp(ident, "*")==0)
                return MCL_ANONYMOUS;
+       if (strncmp(ident, "gss/", 4) == 0)
+               return MCL_GSS;
        if (ident[0] == '@') {
 #ifndef HAVE_INNETGR
                xlog(L_WARNING, "netgroup support not compiled in");
@@ -439,5 +445,12 @@ client_gettype(char *ident)
                if (*sp == '\\' && sp[1])
                        sp++;
        }
-       return MCL_FQDN;
+       /* check for N.N.N.N */
+       sp = ident;
+       if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN;
+       /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */
+       return MCL_SUBNETWORK;
 }
index 5f5acccb96ea340ae697eb980ac1ebae406a3630..e9ffeb5e288ae2355f1c24a85d7a8a7b62c55171 100644 (file)
@@ -27,7 +27,7 @@ export_export(nfs_export *exp)
        struct nfsctl_export    exparg;
        struct nfsctl_client    cltarg;
 
-       if (!clp->m_exported) {
+       if (!clp->m_exported && (clp->m_type != MCL_GSS)) {
                if (!cltsetup(&cltarg, clp))
                        return 0;
                if (nfsaddclient(&cltarg) < 0)
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
+
+/* 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
index bf5bb67a9fd02e378c64225511ada24850e47954..10f38c797d8fe2e2152c77b4a6e586ece12ac2fe 100644 (file)
@@ -19,6 +19,7 @@ enum {
        MCL_WILDCARD,
        MCL_NETGROUP,
        MCL_ANONYMOUS,
+       MCL_GSS,
        MCL_MAXTYPES
 };
 
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_ */
diff --git a/support/include/ha-callout.h b/support/include/ha-callout.h
new file mode 100644 (file)
index 0000000..efb70fb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * support/include/ha-callout.h
+ *
+ * High Availability NFS Callout support routines
+ *
+ * Copyright (c) 2004, Paul Clements, SteelEye Technology
+ *
+ * In order to implement HA NFS, we need several callouts at key
+ * points in statd and mountd. These callouts all come to ha_callout(),
+ * which, in turn, calls out to an ha-callout script (not part of nfs-utils;
+ * defined by -H argument to rpc.statd and rpc.mountd).
+ */
+#ifndef HA_CALLOUT_H
+#define HA_CALLOUT_H
+
+#include <sys/wait.h>
+#include <signal.h>
+
+extern char *ha_callout_prog;
+
+static inline void
+ha_callout(char *event, char *arg1, char *arg2, int arg3)
+{
+       char buf[16]; /* should be plenty */
+       pid_t pid;
+       int ret = -1;
+       struct sigaction oldact, newact;
+
+       if (!ha_callout_prog) /* HA callout is not enabled */
+               return;
+
+       sprintf(buf, "%d", arg3);
+
+       /* many daemons ignore SIGCHLD as tcpwrappers will
+        * fork a child to do logging.  We need to wait
+        * for a child here, so we need to un-ignore
+        * SIGCHLD temporarily
+        */
+       newact.sa_handler = SIG_DFL;
+       newact.sa_flags = 0;
+       sigemptyset(&newact.sa_mask);
+       sigaction(SIGCHLD, &newact, &oldact);
+       pid = fork();
+       switch (pid) {
+               case 0: execl(ha_callout_prog, ha_callout_prog,
+                               event, arg1, arg2, 
+                             arg3 < 0 ? NULL : buf,
+                             NULL);
+                       perror("execl");
+                       exit(2);
+               case -1: perror("fork");
+                       break;
+               default: pid = waitpid(pid, &ret, 0);
+       }
+       sigaction(SIGCHLD, &oldact, &newact);
+#ifdef dprintf
+       dprintf(N_DEBUG, "ha callout returned %d\n", WEXITSTATUS(ret));
+#else
+       xlog(D_GENERAL, "ha callout returned %d\n", WEXITSTATUS(ret));
+#endif
+}
+
+#endif
index e7e9f1db4442018c39079be129e38005794ffd2f..2fbd0f5a1d6ae2cbb606f492cc66edba6403610b 100644 (file)
@@ -23,6 +23,9 @@
 #ifndef _PATH_EXPORTS
 #define _PATH_EXPORTS          "/etc/exports"
 #endif
+#ifndef _PATH_IDMAPDCONF
+#define _PATH_IDMAPDCONF       "/etc/idmapd.conf"
+#endif
 #ifndef _PATH_XTAB
 #define _PATH_XTAB             NFS_STATEDIR "/xtab"
 #endif
index 2a839c7caa69284e2d626a719275aa4db670474a..cf9bc916941ace96fc7e8ca551524215e6bd227e 100644 (file)
@@ -7,12 +7,15 @@
 #ifndef XLOG_H
 #define XLOG_H
 
+/* These are logged always. L_FATAL also does exit(1) */
 #define L_FATAL                0x0100
 #define L_ERROR                0x0200
 #define L_WARNING      0x0400
 #define L_NOTICE       0x0800
 #define L_ALL          0xFF00
 
+/* These are logged if enabled with xlog_[s]config */
+/* NB: code does not expect ORing together D_ and L_ */
 #define D_GENERAL      0x0001          /* general debug info */
 #define D_CALL         0x0002
 #define D_AUTH         0x0004
@@ -31,7 +34,8 @@ struct xlog_debugfac {
 };
 
 void                   xlog_open(char *progname);
-void                   xlog_background(void);
+void                   xlog_stderr(int on);
+void                   xlog_syslog(int on);
 void                   xlog_config(int fac, int on);
 void                   xlog_sconfig(char *, int on);
 int                    xlog_enabled(int fac);
index 2eeb93bba8780235b8cd5612e4088f3678165755..58c84f80632eb3861a1d4f52135e0ef41a9470dd 100644 (file)
@@ -1,7 +1,7 @@
 
 include        $(TOP)rules.mk
 
-LIBS   = libnfs.a libexport.a libmisc.a
+LIBS   = libnfs.a libexport.a libmisc.a librpc.a libgssapi.a
 
 all install::  $(LIBS)
        @:
index 20d195c16ca4b792fbb7b7866688e7993ab87db8..d7ad4293762f4b6dd583fec668cb0ea9df47b733 100644 (file)
@@ -205,16 +205,17 @@ int readline(int fd, char **buf, int *lenp)
         */
                char *new;
                int nl;
-               *lenp += 128;
+               *lenp *= 2;
                new = realloc(*buf, *lenp);
                if (new == NULL)
                        return 0;
-               nl = read(fd, *buf +len, *lenp - len);
-               if (nl <= 0 )
+               *buf = new;
+               nl = read(fd, *buf + len, *lenp - len);
+               if (nl <= 0)
                        return 0;
-               new += nl;
+               len += nl;
        }
-       (*buf)[len-1] = 0;
+       (*buf)[len-1] = '\0';
        return 1;
 }
 
@@ -246,10 +247,16 @@ cache_flush(int force)
        int c;
        char stime[20];
        char path[200];
+       /* Note: the order of these caches is important.
+        * The need to be flushed in dependancy order. So
+        * a cache that references items in another cache,
+        * as nfsd.fh entries reference items in nfsd.export,
+        * must be flushed before the cache that it references.
+        */
        static char *cachelist[] = {
                "auth.unix.ip",
-               "nfsd.export",
                "nfsd.fh",
+               "nfsd.export",
                NULL
        };
        stb.st_mtime = time(0);
index c46c7a99655b921f24855e1bee13f2f306742f77..43e68b147b9a7d6a3b97d2f87453953de5c70c6c 100644 (file)
@@ -185,6 +185,8 @@ putexportent(struct exportent *ep)
                "no_" : "");
        fprintf(fp, "%ssecure_locks,", (ep->e_flags & NFSEXP_NOAUTHNLM)?
                "in" : "");
+       fprintf(fp, "%sacl,", (ep->e_flags & NFSEXP_NOACL)?
+               "no_" : "");
        if (ep->e_flags & NFSEXP_FSID) {
                fprintf(fp, "fsid=%d,", ep->e_fsid);
        }
@@ -374,6 +376,10 @@ parseopts(char *cp, struct exportent *ep, int warn)
                        ep->e_flags &= ~NFSEXP_NOAUTHNLM;
                else if (strcmp(opt, "insecure_locks") == 0)
                        ep->e_flags |= NFSEXP_NOAUTHNLM;
+               else if (strcmp(opt, "acl") == 0)
+                       ep->e_flags &= ~NFSEXP_NOACL;
+               else if (strcmp(opt, "no_acl") == 0)
+                       ep->e_flags |= NFSEXP_NOACL;
                else if (strncmp(opt, "mapping=", 8) == 0)
                        ep->e_maptype = parsemaptype(opt+8);
                else if (strcmp(opt, "map_identity") == 0)      /* old style */
index b06d12eb23edc62f2dc34c2599f7c4007f7a9bcb..e1e4c3f0bf412817ea6e9ca633266b949c72f7ca 100644 (file)
 
 #undef VERBOSE_PRINTF
 
-static int  foreground = 1;            /* not a daemon initially       */
+static int  log_stderr = 1;
+static int  log_syslog = 1;
 static int  logging = 0;               /* enable/disable DEBUG logs    */
 static int  logmask = 0;               /* What will be logged          */
 static char log_name[256];             /* name of this program         */
 static int  log_pid = -1;              /* PID of this program          */
-static FILE *log_fp = (FILE *)NULL;    /* fp for the log file          */
 
 static void    xlog_toggle(int sig);
 static struct xlog_debugfac    debugnames[] = {
@@ -50,11 +50,6 @@ void
 xlog_open(char *progname)
 {
        openlog(progname, LOG_PID, LOG_DAEMON);
-       if (foreground) {
-               log_fp = stderr;
-               if (log_fp != NULL)
-                       setbuf(log_fp, NULL);
-       }
 
        strncpy(log_name, progname, sizeof (log_name) - 1);
        log_name [sizeof (log_name) - 1] = '\0';
@@ -65,9 +60,15 @@ xlog_open(char *progname)
 }
 
 void
-xlog_background(void)
+xlog_stderr(int on)
+{
+       log_stderr = on;
+}
+
+void
+xlog_syslog(int on)
 {
-       foreground = 0;
+       log_syslog = on;
 }
 
 static void
@@ -126,17 +127,13 @@ xlog_enabled(int fac)
 }
 
 
-/* Write something to the system logfile. */
+/* Write something to the system logfile and/or stderr */
 void
 xlog(int kind, const char *fmt, ...)
 {
        char            buff[1024];
        va_list         args;
-       int             logged = 1, n;
-#ifdef VERBOSE_PRINTF
-       time_t          now;
-       struct tm       *tm;
-#endif
+       int             n;
 
        if (!(kind & (L_ALL)) && !(logging && (kind & logmask)))
                return;
@@ -148,40 +145,44 @@ xlog(int kind, const char *fmt, ...)
        if ((n = strlen(buff)) > 0 && buff[n-1] == '\n')
                buff[--n] = '\0';
 
-       switch (kind) {
-       case L_FATAL:
-               syslog(LOG_ERR, "%s", buff);
-               break;
-       case L_ERROR:
-               syslog(LOG_ERR, "%s", buff);
-               break;
-       case L_WARNING:
-               syslog(LOG_WARNING, "%s", buff);
-               break;
-       case L_NOTICE:
-               syslog(LOG_NOTICE, "%s", buff);
-               break;
-       default:
-               logged = 0;
-               break;
+       if (log_syslog) {
+               switch (kind) {
+               case L_FATAL:
+                       syslog(LOG_ERR, "%s", buff);
+                       break;
+               case L_ERROR:
+                       syslog(LOG_ERR, "%s", buff);
+                       break;
+               case L_WARNING:
+                       syslog(LOG_WARNING, "%s", buff);
+                       break;
+               case L_NOTICE:
+                       syslog(LOG_NOTICE, "%s", buff);
+                       break;
+               default:
+                       if (!log_stderr)
+                               syslog(LOG_DEBUG, "%s", buff);
+                       break;
+               }
        }
-       if (!logged || foreground) {
-               if (!logged && log_fp == NULL) {
-                       syslog(LOG_DEBUG, "%s", buff);
-               } else if (log_fp != NULL) {
+
+       if (log_stderr) {
 #ifdef VERBOSE_PRINTF
-                       time(&now);
-                       tm = localtime(&now);
-                       fprintf(log_fp, "%s[%d] %02d/%02d/%02d %02d:%02d %s\n",
-                                       log_name, log_pid,
-                                       tm->tm_mon + 1, tm->tm_mday,
-                                       tm->tm_year, tm->tm_hour, tm->tm_min,
-                                       buff);
+               time_t          now;
+               struct tm       *tm;
+
+               time(&now);
+               tm = localtime(&now);
+               fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d %s\n",
+                               log_name, log_pid,
+                               tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday,
+                               tm->tm_hour, tm->tm_min, tm->tm_sec,
+                               buff);
 #else
-                       fprintf(log_fp, "%s: %s\n", log_name, buff);
+               fprintf(stderr, "%s: %s\n", log_name, buff);
 #endif
-               }
        }
+
        if (kind == L_FATAL)
                exit(1);
 }
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..82b8d01
--- /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;
+               auth->svc_ah_private = (caddr_t)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 af2e530074093aa4e02f18b6aa82fcd9968edaa2..5dce56b2a543360669f6b42c9b0ab534dff96e87 100644 (file)
@@ -2,7 +2,7 @@
 # knfsd tools
 #
 
-TOOL   = rpcdebug
+TOOL   = rpcdebug nfsdebug nfsddebug
 OBJS   = rpcdebug.o
 
 include $(TOP)rules.mk
index b7e751135526816ad8f819a8af02784e5ac610d2..bbe57b1693c73c306700f2cbef81105bb7a96ec7 100644 (file)
@@ -9,6 +9,10 @@
  * allocated via vmalloc.
  *
  * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
+ *           (C) 2004 <frederic.jolly@bull.ext.net>
+ *
+ * 06/15/2004: updated for NFSv4
+ *
  */
 
 #include "config.h"
 #include <string.h>
 #include <fcntl.h>
 #include <ctype.h>
+/* RPC debug flags
+   #include <sunrpc/debug.h> */
+/* NFS debug flags
+   #include <nfs_fs.h> */
+/* NFSD and NLM debug flags
+   #include <nfsd/debug.h> */
 #include <nfs/debug.h>
 
 static int             verbose = 0;
+static char*            cdename;
 
-static int             find_sysname(char *module);
 static unsigned int    find_flag(char **module, char *name);
 static unsigned int    get_flags(char *);
 static unsigned int    set_flags(char *, unsigned int value);
 static void            print_flags(FILE *, char *, unsigned int, int);
 static char *          strtolower(char *str);
-static void            usage(int excode);
+static void            usage(int excode, char *module);
 
 int
 main(int argc, char **argv)
@@ -42,13 +52,27 @@ main(int argc, char **argv)
        char *          module = NULL;
        int             c;
 
+       cdename = malloc(strlen(basename(argv[0])));
+       if (cdename == NULL) {
+         fprintf(stderr, "failed in malloc\n");
+         exit(1);
+        }
+       strcpy(cdename, basename(argv[0]));
+
+       if (!strcmp(cdename, "nfsdebug")) {
+         module = "nfs";
+       }
+       else if (!strcmp(cdename, "nfsddebug")) {
+         module = "nfsd";
+       }
+
        while ((c = getopt(argc, argv, "chm:sv")) != EOF) {
                switch (c) {
                case 'c':
                        opt_c = 1;
                        break;
                case 'h':
-                       usage(0);
+                       usage(0, module);
                case 'm':
                        module = optarg;
                        break;
@@ -59,15 +83,27 @@ main(int argc, char **argv)
                        verbose++;
                        break;
                default:
-                       fprintf(stderr, "rpcdebug: unknown option -%c\n",
-                                               optopt);
-                       usage(1);
+                       fprintf(stderr, "%s: unknown option -%c\n", cdename, optopt);
+                       usage(1, module);
                }
        }
 
        if (opt_c + opt_s > 1) {
                fprintf(stderr, "You can use at most one of -c and -s\n");
-               usage(1);
+               usage(1, module);
+       }
+
+       if (!module) {
+               fprintf(stderr, "%s: no module name specified.\n", cdename);
+               usage(1, module);
+       }
+
+       if (strcmp(module, "nfsd") &&
+           strcmp(module, "nfs") &&
+           strcmp(module, "nlm") &&
+           strcmp(module, "rpc")) {
+               fprintf(stderr, "%s: unknown module: %s\n", cdename, module);
+               usage(1, module);
        }
 
        if (argc == optind) {
@@ -79,12 +115,6 @@ main(int argc, char **argv)
                        opt_s = 1;
        }
 
-       if (!module) {
-               fprintf(stderr, "rpcdebug: no module name specified, and "
-                               "could not be inferred.\n");
-               usage(1);
-       }
-
        oflags = get_flags(module);
 
        if (opt_c) {
@@ -93,14 +123,16 @@ main(int argc, char **argv)
                oflags = set_flags(module, oflags | flags);
        }
        print_flags(stdout, module, oflags, 0);
+       if (verbose) {
+               fprintf(stdout, "\nModule     Valid flags\n");
+               print_flags(stdout, module, ~(unsigned int) 0, 1);
+       }
 
        return 0;
 }
 
 #define FLAG(mname, fname)     \
       { #mname, #fname, mname##DBG_##fname }
-#define SHORTFLAG(mname, fname, dbgname)       \
-      { #mname, #fname, mname##DBG_##dbgname }
 
 static struct flagmap {
        char *          module;
@@ -126,10 +158,11 @@ static struct flagmap {
        FLAG(NFS,       LOOKUPCACHE),
        FLAG(NFS,       PAGECACHE),
        FLAG(NFS,       PROC),
+       FLAG(NFS,       XDR),
+       FLAG(NFS,       FILE),
+       FLAG(NFS,       ROOT),
+       //      FLAG(NFS,       CALLBACK),
        FLAG(NFS,       ALL),
-       SHORTFLAG(NFS,  dir,    DIRCACHE),
-       SHORTFLAG(NFS,  lookup, LOOKUPCACHE),
-       SHORTFLAG(NFS,  page,   PAGECACHE),
 
        /* nfsd */
        FLAG(NFSD,      SOCK),
@@ -152,6 +185,7 @@ static struct flagmap {
        FLAG(NLM,       MONITOR),
        FLAG(NLM,       CLNTSUBS),
        FLAG(NLM,       SVCSUBS),
+       FLAG(NLM,       HOSTCACHE),
        FLAG(NLM,       ALL),
 
       { NULL,          NULL,           0 }
@@ -170,12 +204,12 @@ find_flag(char **module, char *name)
                        continue;
                if (value) {
                        fprintf(stderr,
-                               "rpcdebug: ambiguous symbol name %s.\n"
+                               "%s: ambiguous symbol name %s.\n"
                                "This name is used by more than one module, "
                                "please specify the module name using\n"
                                "the -m option.\n",
-                               name);
-                       usage(1);
+                               cdename, name);
+                       exit(1);
                }
                value = flagmap[i].value;
                if (*module)
@@ -186,12 +220,12 @@ find_flag(char **module, char *name)
        if (!value) {
                if (*module)
                        fprintf(stderr,
-                               "rpcdebug: unknown module or flag %s/%s\n",
-                               *module, name);
+                               "%s: unknown module or flag %s/%s\n",
+                               cdename, *module, name);
                else
                        fprintf(stderr,
-                               "rpcdebug: unknown flag %s\n",
-                               name);
+                               "%s: unknown flag %s\n",
+                               cdename, name);
                exit(1);
        }
 
@@ -202,11 +236,13 @@ find_flag(char **module, char *name)
 static unsigned int
 get_flags(char *module)
 {
-       char    buffer[256], *sp;
-       int     sysfd, len, namelen;
+       char    buffer[256], filename[256];
+       int     sysfd, len;
+
+       snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module);
 
-       if ((sysfd = open("/proc/net/rpc/debug", O_RDONLY)) < 0) {
-               perror("/proc/net/rpc/debug");
+       if ((sysfd = open(filename, O_RDONLY)) < 0) {
+               perror(filename);
                exit(1);
        }
        if ((len = read(sysfd, buffer, sizeof(buffer))) < 0) {
@@ -216,27 +252,20 @@ get_flags(char *module)
        close(sysfd);
        buffer[len - 1] = '\0';
 
-       namelen = strlen(module);
-       for (sp = strtok(buffer, " \t"); sp; sp = strtok(NULL, " \t")) {
-               if (!strncmp(sp, module, namelen) && sp[namelen] == '=') {
-
-                       return strtoul(sp + namelen + 1, NULL, 0);
-               }
-       }
-
-       fprintf(stderr, "Unknown module %s\n", module);
-       exit(1);
+       return strtoul(buffer, NULL, 0);
 }
 
 static unsigned int
 set_flags(char *module, unsigned int value)
 {
-       char    buffer[64];
+       char    buffer[64], filename[256];
        int     sysfd, len, ret;
 
-       len = sprintf(buffer, "%s=%u\n", module, value);
-       if ((sysfd = open("/proc/net/rpc/debug", O_WRONLY)) < 0) {
-               perror("/proc/net/rpc/debug");
+       snprintf(filename, 256, "/proc/sys/sunrpc/%s_debug", module);
+
+       len = sprintf(buffer, "%d", value);
+       if ((sysfd = open(filename, O_WRONLY)) < 0) {
+               perror(filename);
                exit(1);
        }
        if ((ret = write(sysfd, buffer, len)) < 0) {
@@ -251,22 +280,6 @@ set_flags(char *module, unsigned int value)
        return value;
 }
 
-static int
-find_sysname(char *module)
-{
-       char    procname[1024];
-       int     fd;
-
-       module = strtolower(module);
-
-       sprintf(procname, "/proc/sys/sunrpc/%s_debug", module);
-       if ((fd = open(procname, O_RDWR)) < 0) {
-               perror(procname);
-               exit(1);
-       }
-
-       return fd;
-}
 
 static char *
 strtolower(char *str)
@@ -293,7 +306,6 @@ print_flags(FILE *ofp, char *module, unsigned int flags, int show_all)
                        fprintf(ofp, "<no flags set>\n");
                        return;
                }
-               /* printf(" <%x>", flags); */
        }
 
        for (i = 0, shown = 0; flagmap[i].module; i++) {
@@ -319,15 +331,21 @@ print_flags(FILE *ofp, char *module, unsigned int flags, int show_all)
 }
 
 static void
-usage(int excode)
+usage(int excode, char *module)
 {
-       fprintf(stderr, "usage: rpcdebug [-m module] [-cs] flags ...\n");
+        if (module)
+         fprintf(stderr, "usage: %s [-v] [-h] [-s flags...|-c flags...]\n", cdename);
+       else
+         fprintf(stderr, "usage: %s [-v] [-h] [-m module] [-s flags...|-c flags...]\n", cdename);
+       fprintf(stderr, "       set or cancel debug flags.\n");
        if (verbose) {
-               fprintf(stderr, "\nModule     Valid flags\n");
-               print_flags(stderr, NULL, ~(unsigned int) 0, 1);
+         fprintf(stderr, "\nModule     Valid flags\n");
+         print_flags(stderr, module, ~(unsigned int) 0, 1);
        } else {
-               fprintf(stderr,
-                   "       (use rpcdebug -vh to get a list of valid flags)\n");
+         if (module)
+           fprintf(stderr, "       (use %s -vh to get a list of valid flags)\n", cdename);
+         else
+           fprintf(stderr, "       (use %s -vh to get a list of modules and valid flags)\n", cdename);
        }
        exit (excode);
 }
index 8f258796100384c472e80ab57740a001a1325e92..539632fdeef7ea5dff09a7ddc07b509c0be8ba63 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 SUBDIRS        = exportfs mountd nfsd statd nfsstat @RQUOTAD@ showmount \
-         nhfsstone lockd
+         nhfsstone lockd @IDMAPD@ @GSSD@ @SVCGSSD@
 
 include $(TOP)rules.mk
 
index 290d8b25454b7317c3c323bb1f02b9964934bdb8..c7a9a0e94df1800cbd2758f8adb285485d978955 100644 (file)
@@ -130,7 +130,8 @@ main(int argc, char **argv)
                if (!f_export)
                        for (i = optind ; i < argc ; i++)
                                unexportfs(argv[i], f_verbose);
-               rmtab_read();
+               if (!new_cache)
+                       rmtab_read();
        }
        if (!new_cache) {
                xtab_mount_read();
@@ -145,10 +146,43 @@ main(int argc, char **argv)
        return export_errno;
 }
 
+static void
+exports_update_one(nfs_export *exp, int verbose)
+{
+               /* check mountpoint option */
+       if (exp->m_mayexport &&
+           exp->m_export.e_mountpoint &&
+           !is_mountpoint(exp->m_export.e_mountpoint[0]?
+                          exp->m_export.e_mountpoint:
+                          exp->m_export.e_path)) {
+               printf("%s not exported as %s not a mountpoint.\n",
+                      exp->m_export.e_path, exp->m_export.e_mountpoint);
+               exp->m_mayexport = 0;
+       }
+       if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) {
+               if (verbose)
+                       printf("%sexporting %s:%s to kernel\n",
+                              exp->m_exported ?"re":"",
+                              exp->m_client->m_hostname,
+                              exp->m_export.e_path);
+               if (!export_export(exp))
+                       error(exp, errno);
+       }
+       if (exp->m_exported && ! exp->m_mayexport) {
+               if (verbose)
+                       printf("unexporting %s:%s from kernel\n",
+                              exp->m_client->m_hostname,
+                              exp->m_export.e_path);
+               if (!export_unexport(exp))
+                       error(exp, errno);
+       }
+}
+
+
 /* we synchronise intention with reality.
  * entries with m_mayexport get exported
  * entries with m_exported but not m_mayexport get unexported
- * looking at m_client->m_type == MCL_FQDN only
+ * looking at m_client->m_type == MCL_FQDN and m_client->m_type == MCL_GSS only
  */
 static void
 exports_update(int verbose)
@@ -156,33 +190,10 @@ exports_update(int verbose)
        nfs_export      *exp;
 
        for (exp = exportlist[MCL_FQDN]; exp; exp=exp->m_next) {
-               /* check mountpoint option */
-               if (exp->m_mayexport && 
-                   exp->m_export.e_mountpoint &&
-                   !is_mountpoint(exp->m_export.e_mountpoint[0]?
-                                  exp->m_export.e_mountpoint:
-                                  exp->m_export.e_path)) {
-                       printf("%s not exported as %s not a mountpoint.\n",
-                              exp->m_export.e_path, exp->m_export.e_mountpoint);
-                       exp->m_mayexport = 0;
-               }
-               if (exp->m_mayexport && ((exp->m_exported<1) || exp->m_changed)) {
-                       if (verbose)
-                               printf("%sexporting %s:%s to kernel\n",
-                                      exp->m_exported ?"re":"",
-                                      exp->m_client->m_hostname,
-                                      exp->m_export.e_path);
-                       if (!export_export(exp))
-                               error(exp, errno);
-               }
-               if (exp->m_exported && ! exp->m_mayexport) {
-                       if (verbose)
-                               printf("unexporting %s:%s from kernel\n",
-                                      exp->m_client->m_hostname,
-                                      exp->m_export.e_path);
-                       if (!export_unexport(exp))
-                               error(exp, errno);
-               }
+               exports_update_one(exp, verbose);
+       }
+       for (exp = exportlist[MCL_GSS]; exp; exp=exp->m_next) {
+               exports_update_one(exp, verbose);
        }
 }
                        
@@ -387,6 +398,8 @@ dump(int verbose)
                                c = dumpopt(c, "no_subtree_check");
                        if (ep->e_flags & NFSEXP_NOAUTHNLM)
                                c = dumpopt(c, "insecure_locks");
+                       if (ep->e_flags & NFSEXP_NOACL)
+                               c = dumpopt(c, "no_acl");
                        if (ep->e_flags & NFSEXP_FSID)
                                c = dumpopt(c, "fsid=%d", ep->e_fsid);
                        if (ep->e_mountpoint)
index 034a896225e09c84001e9365b941397b54350306..2b316f546bd95187622a4697d750f3410850adf4 100644 (file)
@@ -1,5 +1,4 @@
-.TH EXPORTS 5 "28 October 1999"
-.UC 5
+.TH EXPORTS 5 "4 March 2005" "Linux" "Linux File Formats Manual"
 .SH NAME
 exports \- NFS file systems being exported (for Kernel based NFS)
 .SH SYNOPSIS
@@ -79,6 +78,11 @@ may work by accident when reverse DNS lookups fail.
 '''.B \-\-public\-root
 '''option. Multiple specifications of a public root will be ignored.
 .PP
+.SS RPCSEC_GSS security
+To restrict access to an export using rpcsec_gss security, use the special
+string "gss/krb5" as the client.  It is not possible to simultaneously require
+rpcsec_gss and to make requirements on the IP address of the client.
+.PP
 .SS General Options
 .IR exportfs
 understands the following export options:
@@ -166,7 +170,7 @@ The option can be explicitly disabled with
 .TP
 .IR no_subtree_check
 This option disables subtree checking, which has mild security
-implications, but can improve reliability is some circumstances.
+implications, but can improve reliability in some circumstances.
 
 If a subdirectory of a filesystem is exported, but the whole
 filesystem isn't then whenever a NFS request arrives, the server must
@@ -185,7 +189,7 @@ subtree checking is also used to make sure that files inside
 directories to which only root has access can only be accessed if the
 filesystem is exported with
 .I no_root_squash
-(see below), even the file itself allows more general access.
+(see below), even if the file itself allows more general access.
 
 As a general guide, a home directory filesystem, which is normally
 exported at the root and may see lots of file renames, should be
@@ -218,6 +222,21 @@ be explicitly requested with either of the synonymous
 .IR auth_nlm ,
 or
 .IR secure_locks .
+.TP
+.IR no_acl
+On some specially patched kernels, and when exporting filesystems that
+support ACLs, this option tells nfsd not to reveal ACLs to clients, so
+they will see only a subset of actual permissions on the given file
+system.  This option is safe for filesystems used by NFSv2 clients and
+old NFSv3 clients that perform access decisions locally.  Current
+NFSv3 clients use the ACCESS RPC to perform all access decisions on
+the server.  Note that the
+.I no_acl
+option only has effect on kernels specially patched to support it, and
+when exporting filesystems with ACL support.  The default is to export
+with ACL support (i.e. by default,
+.I no_acl
+is off).
 
 '''.TP
 '''.I noaccess
@@ -482,6 +501,12 @@ don't use a reserved port for NFS.
 '''entry.
 .SH FILES
 /etc/exports
+.SH SEE ALSO
+.BR exportfs (8),
+.BR netgroup (5),
+.BR mountd (8),
+.BR nfsd (8),
+.BR showmount (8).
 '''.SH DIAGNOSTICS
 '''An error parsing the file is reported using syslogd(8) as level NOTICE from
 '''a DAEMON whenever nfsd(8) or mountd(8) is started up.  Any unknown
index d475eb102526db027d6df936e84d0ef7f8ea79e1..cf3639d0eb1b434193704864f898fd7cc774e0fe 100644 (file)
@@ -25,7 +25,7 @@ up to 2.6).  This man page does not apply to 2.4 and earlier.
 As well as this filesystem, there are a collection of files in the
 .B procfs
 filesystem (normally mounted at
-.BE /proc )
+.BR /proc )
 which are used to control the NFS server.
 This manual page describes all of these files.
 .P
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..788ecf1
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+  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)) goto out_err;
+       /* Not setting any timeout for now: */
+       if (WRITE_BYTES(&p, end, timeout)) goto out_err;
+       if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
+       if (write_buffer(&p, end, &pd->pd_ctx_hndl)) goto out_err;
+       if (write_buffer(&p, end, context_token)) goto out_err;
+
+       if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
+       return 0;
+out_err:
+       printerr(0, "Failed to write downcall!\n");
+       return -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;
+
+       printerr(1, "doing error downcall\n");
+
+       if (WRITE_BYTES(&p, end, uid)) goto out_err;
+       if (WRITE_BYTES(&p, end, timeout)) goto out_err;
+       /* use seq_win = 0 to indicate an error: */
+       if (WRITE_BYTES(&p, end, zero)) goto out_err;
+       if (WRITE_BYTES(&p, end, err)) goto out_err;
+
+       if (write(k5_fd, buf, p - buf) < p - buf) goto out_err;
+       return 0;
+out_err:
+       printerr(0, "Failed to write error downcall!\n");
+       return -1;
+}
+
+/*
+ * 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 ((save_uid != -1) && (seteuid(save_uid) != 0)) {
+               printerr(0, "WARNING: Failed to restore euid"
+                           " to uid %d (in error path)\n", save_uid);
+       }
+       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/idmapd/Makefile b/utils/idmapd/Makefile
new file mode 100644 (file)
index 0000000..14f6cc1
--- /dev/null
@@ -0,0 +1,12 @@
+#
+# Makefile for rpc.idmapd
+#
+
+PROGRAM        = idmapd
+PREFIX = rpc.
+OBJS   = atomicio.o cfg.o idmapd.o setproctitle.o strlcat.o strlcpy.o
+LIBS   = -levent -lnfsidmap
+MAN8   = idmapd
+MAN5   = idmapd.conf
+
+include $(TOP)rules.mk
diff --git a/utils/idmapd/atomicio.c b/utils/idmapd/atomicio.c
new file mode 100644 (file)
index 0000000..93171a7
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2002 Marius Aamodt Eriksen <marius@monkey.org>
+ * Copyright (c) 1995,1999 Theo de Raadt.  All rights reserved.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 <unistd.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * ensure all of data on socket comes through. f==read || f==write
+ */
+ssize_t
+atomicio(f, fd, _s, n)
+       ssize_t (*f) ();
+       int fd;
+       void *_s;
+       size_t n;
+{
+       char *s = _s;
+       ssize_t res, pos = 0;
+
+       while (n > pos) {
+               res = (f) (fd, s + pos, n - pos);
+               switch (res) {
+               case -1:
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+               case 0:
+                       if (pos != 0)
+                               return (pos);
+                       return (res);
+               default:
+                       pos += res;
+               }
+       }
+       return (pos);
+}
diff --git a/utils/idmapd/cfg.c b/utils/idmapd/cfg.c
new file mode 100644 (file)
index 0000000..b22a7c9
--- /dev/null
@@ -0,0 +1,889 @@
+/*     $OpenBSD: conf.c,v 1.55 2003/06/03 14:28:16 ho Exp $    */
+/*     $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $   */
+
+/*
+ * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist.  All rights reserved.
+ * Copyright (c) 2000, 2001, 2002 HÃ¥kan Olsson.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+
+#include "cfg.h"
+
+static void conf_load_defaults (int);
+#if 0
+static int conf_find_trans_xf (int, char *);
+#endif
+
+size_t  strlcpy(char *, const char *, size_t);
+
+struct conf_trans {
+  TAILQ_ENTRY (conf_trans) link;
+  int trans;
+  enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op;
+  char *section;
+  char *tag;
+  char *value;
+  int override;
+  int is_default;
+};
+
+TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue;
+
+/*
+ * Radix-64 Encoding.
+ */
+const u_int8_t bin2asc[]
+  = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const u_int8_t asc2bin[] =
+{
+  255, 255, 255, 255, 255, 255, 255, 255,
+  255, 255, 255, 255, 255, 255, 255, 255,
+  255, 255, 255, 255, 255, 255, 255, 255,
+  255, 255, 255, 255, 255, 255, 255, 255,
+  255, 255, 255, 255, 255, 255, 255, 255,
+  255, 255, 255,  62, 255, 255, 255,  63,
+   52,  53,  54,  55,  56,  57,  58,  59,
+   60,  61, 255, 255, 255, 255, 255, 255,
+  255,   0,   1,   2,   3,   4,   5,   6,
+    7,   8,   9,  10,  11,  12,  13,  14,
+   15,  16,  17,  18,  19,  20,  21,  22,
+   23,  24,  25, 255, 255, 255, 255, 255,
+  255,  26,  27,  28,  29,  30,  31,  32,
+   33,  34,  35,  36,  37,  38,  39,  40,
+   41,  42,  43,  44,  45,  46,  47,  48,
+   49,  50,  51, 255, 255, 255, 255, 255
+};
+
+struct conf_binding {
+  LIST_ENTRY (conf_binding) link;
+  char *section;
+  char *tag;
+  char *value;
+  int is_default;
+};
+
+char *conf_path;
+LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
+
+static char *conf_addr;
+
+static __inline__ u_int8_t
+conf_hash (char *s)
+{
+  u_int8_t hash = 0;
+
+  while (*s)
+    {
+      hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s);
+      s++;
+    }
+  return hash;
+}
+
+/*
+ * Insert a tag-value combination from LINE (the equal sign is at POS)
+ */
+static int
+conf_remove_now (char *section, char *tag)
+{
+  struct conf_binding *cb, *next;
+
+  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next)
+    {
+      next = LIST_NEXT (cb, link);
+      if (strcasecmp (cb->section, section) == 0
+         && strcasecmp (cb->tag, tag) == 0)
+       {
+         LIST_REMOVE (cb, link);
+         warnx("[%s]:%s->%s removed", section, tag, cb->value);
+         free (cb->section);
+         free (cb->tag);
+         free (cb->value);
+         free (cb);
+         return 0;
+       }
+    }
+  return 1;
+}
+
+static int
+conf_remove_section_now (char *section)
+{
+  struct conf_binding *cb, *next;
+  int unseen = 1;
+
+  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb; cb = next)
+    {
+      next = LIST_NEXT (cb, link);
+      if (strcasecmp (cb->section, section) == 0)
+       {
+         unseen = 0;
+         LIST_REMOVE (cb, link);
+         warnx("[%s]:%s->%s removed", section, cb->tag, cb->value);
+         free (cb->section);
+         free (cb->tag);
+         free (cb->value);
+         free (cb);
+       }
+    }
+  return unseen;
+}
+
+/*
+ * Insert a tag-value combination from LINE (the equal sign is at POS)
+ * into SECTION of our configuration database.
+ */
+static int
+conf_set_now (char *section, char *tag, char *value, int override,
+             int is_default)
+{
+  struct conf_binding *node = 0;
+
+  if (override)
+    conf_remove_now (section, tag);
+  else if (conf_get_str (section, tag))
+    {
+      if (!is_default)
+       warnx("conf_set: duplicate tag [%s]:%s, ignoring...\n", section, tag);
+      return 1;
+    }
+
+  node = calloc (1, sizeof *node);
+  if (!node)
+    {
+      warnx("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node);
+      return 1;
+    }
+  node->section = strdup (section);
+  node->tag = strdup (tag);
+  node->value = strdup (value);
+  node->is_default = is_default;
+
+  LIST_INSERT_HEAD (&conf_bindings[conf_hash (section)], node, link);
+  return 0;
+}
+
+/*
+ * Parse the line LINE of SZ bytes.  Skip Comments, recognize section
+ * headers and feed tag-value pairs into our configuration database.
+ */
+static void
+conf_parse_line (int trans, char *line, size_t sz)
+{
+  char *val;
+  size_t i;
+  int j;
+  static char *section = 0;
+  static int ln = 0;
+
+  ln++;
+
+  /* Lines starting with '#' or ';' are comments.  */
+  if (*line == '#' || *line == ';')
+    return;
+
+  /* '[section]' parsing...  */
+  if (*line == '[')
+    {
+      for (i = 1; i < sz; i++)
+       if (line[i] == ']')
+         break;
+      if (section)
+       free (section);
+      if (i == sz)
+       {
+         warnx("conf_parse_line: %d:"
+                    "non-matched ']', ignoring until next section", ln);
+         section = 0;
+         return;
+       }
+      section = malloc (i);
+      if (!section)
+       {
+         warnx("conf_parse_line: %d: malloc (%lu) failed", ln,
+               (unsigned long)i);
+         return;
+       }
+      strlcpy (section, line + 1, i);
+      return;
+    }
+
+  /* Deal with assignments.  */
+  for (i = 0; i < sz; i++)
+    if (line[i] == '=')
+      {
+       /* If no section, we are ignoring the lines.  */
+       if (!section)
+         {
+           warnx("conf_parse_line: %d: ignoring line due to no section", ln);
+           return;
+         }
+       line[strcspn (line, " \t=")] = '\0';
+       val = line + i + 1 + strspn (line + i + 1, " \t");
+       /* Skip trailing whitespace, if any */
+       for (j = sz - (val - line) - 1; j > 0 && isspace (val[j]); j--)
+         val[j] = '\0';
+       /* XXX Perhaps should we not ignore errors?  */
+       conf_set (trans, section, line, val, 0, 0);
+       return;
+      }
+
+  /* Other non-empty lines are weird.  */
+  i = strspn (line, " \t");
+  if (line[i])
+    warnx("conf_parse_line: %d: syntax error", ln);
+
+  return;
+}
+
+/* Parse the mapped configuration file.  */
+static void
+conf_parse (int trans, char *buf, size_t sz)
+{
+  char *cp = buf;
+  char *bufend = buf + sz;
+  char *line;
+
+  line = cp;
+  while (cp < bufend)
+    {
+      if (*cp == '\n')
+       {
+         /* Check for escaped newlines.  */
+         if (cp > buf && *(cp - 1) == '\\')
+           *(cp - 1) = *cp = ' ';
+         else
+           {
+             *cp = '\0';
+             conf_parse_line (trans, line, cp - line);
+             line = cp + 1;
+           }
+       }
+      cp++;
+    }
+  if (cp != line)
+    warnx("conf_parse: last line non-terminated, ignored.");
+}
+
+static void
+conf_load_defaults (int tr)
+{
+       /* No defaults */
+       return;
+}
+
+void
+conf_init (void)
+{
+  unsigned int i;
+
+  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+    LIST_INIT (&conf_bindings[i]);
+  TAILQ_INIT (&conf_trans_queue);
+  conf_reinit ();
+}
+
+/* Open the config file and map it into our address space, then parse it.  */
+void
+conf_reinit (void)
+{
+  struct conf_binding *cb = 0;
+  int fd, trans;
+  unsigned int i;
+  size_t sz;
+  char *new_conf_addr = 0;
+  struct stat sb;
+
+  if ((stat (conf_path, &sb) == 0) || (errno != ENOENT))
+    {
+      sz = sb.st_size;
+      fd = open (conf_path, O_RDONLY, 0);
+      if (fd == -1)
+        {
+         warnx("conf_reinit: open (\"%s\", O_RDONLY) failed", conf_path);
+         return;
+       }
+
+      new_conf_addr = malloc (sz);
+      if (!new_conf_addr)
+        {
+         warnx("conf_reinit: malloc (%lu) failed", (unsigned long)sz);
+         goto fail;
+       }
+
+      /* XXX I assume short reads won't happen here.  */
+      if (read (fd, new_conf_addr, sz) != (int)sz)
+        {
+           warnx("conf_reinit: read (%d, %p, %lu) failed",
+                      fd, new_conf_addr, (unsigned long)sz);
+           goto fail;
+       }
+      close (fd);
+
+      trans = conf_begin ();
+
+      /* XXX Should we not care about errors and rollback?  */
+      conf_parse (trans, new_conf_addr, sz);
+    }
+  else
+    trans = conf_begin ();
+
+  /* Load default configuration values.  */
+  conf_load_defaults (trans);
+
+  /* Free potential existing configuration.  */
+  if (conf_addr)
+    {
+      for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+       for (cb = LIST_FIRST (&conf_bindings[i]); cb;
+            cb = LIST_FIRST (&conf_bindings[i]))
+         conf_remove_now (cb->section, cb->tag);
+      free (conf_addr);
+    }
+
+  conf_end (trans, 1);
+  conf_addr = new_conf_addr;
+  return;
+
+ fail:
+  if (new_conf_addr)
+    free (new_conf_addr);
+  close (fd);
+}
+
+/*
+ * Return the numeric value denoted by TAG in section SECTION or DEF
+ * if that tag does not exist.
+ */
+int
+conf_get_num (char *section, char *tag, int def)
+{
+  char *value = conf_get_str (section, tag);
+
+  if (value)
+      return atoi (value);
+  return def;
+}
+
+/* Validate X according to the range denoted by TAG in section SECTION.  */
+int
+conf_match_num (char *section, char *tag, int x)
+{
+  char *value = conf_get_str (section, tag);
+  int val, min, max, n;
+
+  if (!value)
+    return 0;
+  n = sscanf (value, "%d,%d:%d", &val, &min, &max);
+  switch (n)
+    {
+    case 1:
+      warnx("conf_match_num: %s:%s %d==%d?", section, tag, val, x);
+      return x == val;
+    case 3:
+      warnx("conf_match_num: %s:%s %d<=%d<=%d?", section, tag, min, x, max);
+      return min <= x && max >= x;
+    default:
+      warnx("conf_match_num: section %s tag %s: invalid number spec %s",
+                section, tag, value);
+    }
+  return 0;
+}
+
+/* Return the string value denoted by TAG in section SECTION.  */
+char *
+conf_get_str (char *section, char *tag)
+{
+  struct conf_binding *cb;
+
+  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
+       cb = LIST_NEXT (cb, link))
+    if (strcasecmp (section, cb->section) == 0
+       && strcasecmp (tag, cb->tag) == 0)
+      {
+       return cb->value;
+      }
+  return 0;
+}
+
+/*
+ * Build a list of string values out of the comma separated value denoted by
+ * TAG in SECTION.
+ */
+struct conf_list *
+conf_get_list (char *section, char *tag)
+{
+  char *liststr = 0, *p, *field, *t;
+  struct conf_list *list = 0;
+  struct conf_list_node *node;
+
+  list = malloc (sizeof *list);
+  if (!list)
+    goto cleanup;
+  TAILQ_INIT (&list->fields);
+  list->cnt = 0;
+  liststr = conf_get_str (section, tag);
+  if (!liststr)
+    goto cleanup;
+  liststr = strdup (liststr);
+  if (!liststr)
+    goto cleanup;
+  p = liststr;
+  while ((field = strsep (&p, ",")) != NULL)
+    {
+      /* Skip leading whitespace */
+      while (isspace (*field))
+       field++;
+      /* Skip trailing whitespace */
+      if (p)
+       for (t = p - 1; t > field && isspace (*t); t--)
+         *t = '\0';
+      if (*field == '\0')
+       {
+         warnx("conf_get_list: empty field, ignoring...");
+         continue;
+       }
+      list->cnt++;
+      node = calloc (1, sizeof *node);
+      if (!node)
+       goto cleanup;
+      node->field = strdup (field);
+      if (!node->field)
+       goto cleanup;
+      TAILQ_INSERT_TAIL (&list->fields, node, link);
+    }
+  free (liststr);
+  return list;
+
+ cleanup:
+  if (list)
+    conf_free_list (list);
+  if (liststr)
+    free (liststr);
+  return 0;
+}
+
+struct conf_list *
+conf_get_tag_list (char *section)
+{
+  struct conf_list *list = 0;
+  struct conf_list_node *node;
+  struct conf_binding *cb;
+
+  list = malloc (sizeof *list);
+  if (!list)
+    goto cleanup;
+  TAILQ_INIT (&list->fields);
+  list->cnt = 0;
+  for (cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); cb;
+       cb = LIST_NEXT (cb, link))
+    if (strcasecmp (section, cb->section) == 0)
+      {
+       list->cnt++;
+       node = calloc (1, sizeof *node);
+       if (!node)
+         goto cleanup;
+       node->field = strdup (cb->tag);
+       if (!node->field)
+         goto cleanup;
+       TAILQ_INSERT_TAIL (&list->fields, node, link);
+      }
+  return list;
+
+ cleanup:
+  if (list)
+    conf_free_list (list);
+  return 0;
+}
+
+/* Decode a PEM encoded buffer.  */
+int
+conf_decode_base64 (u_int8_t *out, u_int32_t *len, u_char *buf)
+{
+  u_int32_t c = 0;
+  u_int8_t c1, c2, c3, c4;
+
+  while (*buf)
+    {
+      if (*buf > 127 || (c1 = asc2bin[*buf]) == 255)
+       return 0;
+      buf++;
+
+      if (*buf > 127 || (c2 = asc2bin[*buf]) == 255)
+       return 0;
+      buf++;
+
+      if (*buf == '=')
+       {
+         c3 = c4 = 0;
+         c++;
+
+         /* Check last four bit */
+         if (c2 & 0xF)
+           return 0;
+
+         if (strcmp ((char *)buf, "==") == 0)
+           buf++;
+         else
+           return 0;
+       }
+      else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255)
+       return 0;
+      else
+       {
+         if (*++buf == '=')
+           {
+             c4 = 0;
+             c += 2;
+
+             /* Check last two bit */
+             if (c3 & 3)
+               return 0;
+
+             if (strcmp ((char *)buf, "="))
+               return 0;
+
+           }
+         else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255)
+             return 0;
+         else
+             c += 3;
+       }
+
+      buf++;
+      *out++ = (c1 << 2) | (c2 >> 4);
+      *out++ = (c2 << 4) | (c3 >> 2);
+      *out++ = (c3 << 6) | c4;
+    }
+
+  *len = c;
+  return 1;
+
+}
+
+void
+conf_free_list (struct conf_list *list)
+{
+  struct conf_list_node *node = TAILQ_FIRST (&list->fields);
+
+  while (node)
+    {
+      TAILQ_REMOVE (&list->fields, node, link);
+      if (node->field)
+       free (node->field);
+      free (node);
+      node = TAILQ_FIRST (&list->fields);
+    }
+  free (list);
+}
+
+int
+conf_begin (void)
+{
+  static int seq = 0;
+
+  return ++seq;
+}
+
+static struct conf_trans *
+conf_trans_node (int transaction, enum conf_op op)
+{
+  struct conf_trans *node;
+
+  node = calloc (1, sizeof *node);
+  if (!node)
+    {
+      warnx("conf_trans_node: calloc (1, %lu) failed",
+       (unsigned long)sizeof *node);
+      return 0;
+    }
+  node->trans = transaction;
+  node->op = op;
+  TAILQ_INSERT_TAIL (&conf_trans_queue, node, link);
+  return node;
+}
+
+/* Queue a set operation.  */
+int
+conf_set (int transaction, char *section, char *tag, char *value, int override,
+         int is_default)
+{
+  struct conf_trans *node;
+
+  node = conf_trans_node (transaction, CONF_SET);
+  if (!node)
+    return 1;
+  node->section = strdup (section);
+  if (!node->section)
+    {
+      warnx("conf_set: strdup (\"%s\") failed", section);
+      goto fail;
+    }
+  node->tag = strdup (tag);
+  if (!node->tag)
+    {
+      warnx("conf_set: strdup (\"%s\") failed", tag);
+      goto fail;
+    }
+  node->value = strdup (value);
+  if (!node->value)
+    {
+      warnx("conf_set: strdup (\"%s\") failed", value);
+      goto fail;
+    }
+  node->override = override;
+  node->is_default = is_default;
+  return 0;
+
+ fail:
+  if (node->tag)
+    free (node->tag);
+  if (node->section)
+    free (node->section);
+  if (node)
+    free (node);
+  return 1;
+}
+
+/* Queue a remove operation.  */
+int
+conf_remove (int transaction, char *section, char *tag)
+{
+  struct conf_trans *node;
+
+  node = conf_trans_node (transaction, CONF_REMOVE);
+  if (!node)
+    goto fail;
+  node->section = strdup (section);
+  if (!node->section)
+    {
+      warnx("conf_remove: strdup (\"%s\") failed", section);
+      goto fail;
+    }
+  node->tag = strdup (tag);
+  if (!node->tag)
+    {
+      warnx("conf_remove: strdup (\"%s\") failed", tag);
+      goto fail;
+    }
+  return 0;
+
+ fail:
+  if (node->section)
+    free (node->section);
+  if (node)
+    free (node);
+  return 1;
+}
+
+/* Queue a remove section operation.  */
+int
+conf_remove_section (int transaction, char *section)
+{
+  struct conf_trans *node;
+
+  node = conf_trans_node (transaction, CONF_REMOVE_SECTION);
+  if (!node)
+    goto fail;
+  node->section = strdup (section);
+  if (!node->section)
+    {
+      warnx("conf_remove_section: strdup (\"%s\") failed", section);
+      goto fail;
+    }
+  return 0;
+
+ fail:
+  if (node)
+    free (node);
+  return 1;
+}
+
+/* Execute all queued operations for this transaction.  Cleanup.  */
+int
+conf_end (int transaction, int commit)
+{
+  struct conf_trans *node, *next;
+
+  for (node = TAILQ_FIRST (&conf_trans_queue); node; node = next)
+    {
+      next = TAILQ_NEXT (node, link);
+      if (node->trans == transaction)
+       {
+         if (commit)
+           switch (node->op)
+             {
+             case CONF_SET:
+               conf_set_now (node->section, node->tag, node->value,
+                             node->override, node->is_default);
+               break;
+             case CONF_REMOVE:
+               conf_remove_now (node->section, node->tag);
+               break;
+             case CONF_REMOVE_SECTION:
+               conf_remove_section_now (node->section);
+               break;
+             default:
+               warnx("conf_end: unknown operation: %d", node->op);
+             }
+         TAILQ_REMOVE (&conf_trans_queue, node, link);
+         if (node->section)
+           free (node->section);
+         if (node->tag)
+           free (node->tag);
+         if (node->value)
+           free (node->value);
+         free (node);
+       }
+    }
+  return 0;
+}
+
+/*
+ * Dump running configuration upon SIGUSR1.
+ * Configuration is "stored in reverse order", so reverse it again.
+ */
+struct dumper {
+  char *s, *v;
+  struct dumper *next;
+};
+
+static void
+conf_report_dump (struct dumper *node)
+{
+  /* Recursive, cleanup when we're done.  */
+
+  if (node->next)
+    conf_report_dump (node->next);
+
+  if (node->v)
+    warnx("%s=\t%s", node->s, node->v);
+  else if (node->s)
+    {
+      warnx("%s", node->s);
+      if (strlen (node->s) > 0)
+       free (node->s);
+    }
+
+  free (node);
+}
+
+void
+conf_report (void)
+{
+  struct conf_binding *cb, *last = 0;
+  unsigned int i, len;
+  char *current_section = (char *)0;
+  struct dumper *dumper, *dnode;
+
+  dumper = dnode = (struct dumper *)calloc (1, sizeof *dumper);
+  if (!dumper)
+    goto mem_fail;
+
+  warnx("conf_report: dumping running configuration");
+
+  for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++)
+    for (cb = LIST_FIRST (&conf_bindings[i]); cb;
+        cb = LIST_NEXT (cb, link))
+      {
+       if (!cb->is_default)
+         {
+           /* Dump this entry.  */
+           if (!current_section || strcmp (cb->section, current_section))
+             {
+               if (current_section)
+                 {
+                   len = strlen (current_section) + 3;
+                   dnode->s = malloc (len);
+                   if (!dnode->s)
+                     goto mem_fail;
+
+                   snprintf (dnode->s, len, "[%s]", current_section);
+                   dnode->next
+                     = (struct dumper *)calloc (1, sizeof (struct dumper));
+                   dnode = dnode->next;
+                   if (!dnode)
+                     goto mem_fail;
+
+                   dnode->s = "";
+                   dnode->next
+                     = (struct dumper *)calloc (1, sizeof (struct dumper));
+                   dnode = dnode->next;
+                   if (!dnode)
+                     goto mem_fail;
+                 }
+               current_section = cb->section;
+             }
+           dnode->s = cb->tag;
+           dnode->v = cb->value;
+           dnode->next = (struct dumper *)calloc (1, sizeof (struct dumper));
+           dnode = dnode->next;
+           if (!dnode)
+             goto mem_fail;
+           last = cb;
+         }
+      }
+
+  if (last)
+    {
+      len = strlen (last->section) + 3;
+      dnode->s = malloc (len);
+      if (!dnode->s)
+       goto mem_fail;
+      snprintf (dnode->s, len, "[%s]", last->section);
+    }
+
+  conf_report_dump (dumper);
+
+  return;
+
+ mem_fail:
+  warnx("conf_report: malloc/calloc failed");
+  while ((dnode = dumper) != 0)
+    {
+      dumper = dumper->next;
+      if (dnode->s)
+       free (dnode->s);
+      free (dnode);
+    }
+  return;
+}
diff --git a/utils/idmapd/cfg.h b/utils/idmapd/cfg.h
new file mode 100644 (file)
index 0000000..c1ca940
--- /dev/null
@@ -0,0 +1,67 @@
+/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $   */
+/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $     */
+
+/*
+ * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist.  All rights reserved.
+ * Copyright (c) 2000, 2003 HÃ¥kan Olsson.  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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+/*
+ * This code was written under funding by Ericsson Radio Systems.
+ */
+
+#ifndef _CONF_H_
+#define _CONF_H_
+
+#include "queue.h"
+
+struct conf_list_node {
+       TAILQ_ENTRY(conf_list_node) link;
+       char    *field;
+};
+
+struct conf_list {
+       size_t  cnt;
+       TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields;
+};
+
+extern char    *conf_path;
+
+extern int      conf_begin(void);
+extern int      conf_decode_base64(u_int8_t *, u_int32_t *, u_char *);
+extern int      conf_end(int, int);
+extern void     conf_free_list(struct conf_list *);
+extern struct sockaddr *conf_get_address(char *, char *);
+extern struct conf_list *conf_get_list(char *, char *);
+extern struct conf_list *conf_get_tag_list(char *);
+extern int      conf_get_num(char *, char *, int);
+extern char    *conf_get_str(char *, char *);
+extern void     conf_init(void);
+extern int      conf_match_num(char *, char *, int);
+extern void     conf_reinit(void);
+extern int      conf_remove(int, char *, char *);
+extern int      conf_remove_section(int, char *);
+extern int      conf_set(int, char *, char *, char *, int, int);
+extern void     conf_report(void);
+
+#endif                         /* _CONF_H_ */
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
new file mode 100644 (file)
index 0000000..02604df
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ *  idmapd.c
+ *
+ *  Userland daemon for idmap.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@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/types.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <time.h>
+
+#include "nfs_idmap.h"
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <limits.h>
+#include <ctype.h>
+#include <nfsidmap.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "cfg.h"
+#include "queue.h"
+#include "nfslib.h"
+
+#ifndef PIPEFS_DIR
+#define PIPEFS_DIR  "/var/lib/nfs/rpc_pipefs/"
+#endif
+
+#ifndef NFSD_DIR
+#define NFSD_DIR  "/proc/net/rpc"
+#endif
+
+#ifndef NFS4NOBODY_USER
+#define NFS4NOBODY_USER "nobody"
+#endif
+
+#ifndef NFS4NOBODY_GROUP
+#define NFS4NOBODY_GROUP "nobody"
+#endif
+
+/* From Niels */
+#define CONF_SAVE(w, f) do {                   \
+       char *p = f;                            \
+       if (p != NULL)                          \
+               (w) = p;                        \
+} while (0)
+
+#define IC_IDNAME 1
+#define IC_NAMEID 2
+struct idmap_client {
+       int                        ic_fd;
+       int                        ic_dirfd;
+       char                       ic_clid[30];
+       char                       ic_path[PATH_MAX];
+       int                        ic_scanned;
+       struct event               ic_event;
+       char                      *ic_id;
+       short                      ic_which;
+       TAILQ_ENTRY(idmap_client)  ic_next;
+};
+
+TAILQ_HEAD(idmap_clientq, idmap_client);
+
+static void dirscancb(int, short, void *);
+static void clntscancb(int, short, void *);
+static void svrreopen(int, short, void *);
+static int  nfsopen(struct idmap_client *);
+static void nfscb(int, short, void *);
+static void nfsdcb(int, short, void *);
+static int  validateascii(char *, u_int32_t);
+static int  addfield(char **, ssize_t *, char *);
+static int  getfield(char **, char *, size_t);
+
+static void imconv(struct idmap_client *, struct idmap_msg *);
+static void idtonameres(struct idmap_msg *);
+static void nametoidres(struct idmap_msg *);
+
+static int nfsdopen(char *);
+static int nfsdopenone(struct idmap_client *, short, char *);
+static void nfsdreopen(void);
+
+size_t  strlcat(char *, const char *, size_t);
+size_t  strlcpy(char *, const char *, size_t);
+ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
+void    mydaemon(int, int);
+void    release_parent();
+
+static int verbose = 0;
+static char pipefsdir[PATH_MAX];
+static char *nobodyuser, *nobodygroup;
+static uid_t nobodyuid;
+static gid_t nobodygid;
+static struct idmap_client nfsd_ic[2];
+
+/* Used by cfg.c */
+char *conf_path;
+
+int
+main(int argc, char **argv)
+{
+       int fd = 0, opt, fg = 0, nfsdret = -1;
+       struct idmap_clientq icq;
+       struct event rootdirev, clntdirev, svrdirev;
+       struct event initialize;
+       struct passwd *pw;
+       struct group *gr;
+       struct stat sb;
+       char *xpipefsdir = NULL;
+       int serverstart = 1, clientstart = 1;
+
+       conf_path = _PATH_IDMAPDCONF;
+       nobodyuser = NFS4NOBODY_USER;
+       nobodygroup = NFS4NOBODY_GROUP;
+       strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir));
+
+#define GETOPTSTR "vfd:p:U:G:c:CS"
+       opterr=0; /* Turn off error messages */
+       while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) {
+               if (opt == 'c')
+                       conf_path = optarg;
+               if (opt == '?') {
+                       if (strchr(GETOPTSTR, optopt))
+                               errx(1, "'-%c' option requires an argument.", optopt);
+                       else
+                               errx(1, "'-%c' is an invalid argument.", optopt);
+               }
+       }
+       optind = 1;
+
+       if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) {
+               warn("Skipping configuration file \"%s\"", conf_path);
+       } else {
+               conf_init();
+               verbose = conf_get_num("General", "Verbosity", 0);
+               CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory"));
+               if (xpipefsdir != NULL)
+                       strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir));
+               CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User"));
+               CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group"));
+               nfs4_init_name_mapping(conf_path);
+       }
+
+       while ((opt = getopt(argc, argv, GETOPTSTR)) != -1)
+               switch (opt) {
+               case 'v':
+                       verbose++;
+                       break;
+               case 'f':
+                       fg = 1;
+                       break;
+               case 'p':
+                       strlcpy(pipefsdir, optarg, sizeof(pipefsdir));
+                       break;
+               case 'd':
+               case 'U':
+               case 'G':
+                       errx(1, "the -d, -U, and -G options have been removed;"
+                               " please use the configuration file instead.");
+               case 'C':
+                       serverstart = 0;
+                       break;
+               case 'S':
+                       clientstart = 0;
+                       break;
+               default:
+                       break;
+               }
+
+       if (!serverstart && !clientstart)
+               errx(1, "it is illegal to specify both -C and -S");
+
+       strncat(pipefsdir, "/nfs", sizeof(pipefsdir));
+
+       if ((pw = getpwnam(nobodyuser)) == NULL)
+               errx(1, "Could not find user \"%s\"", nobodyuser);
+       nobodyuid = pw->pw_uid;
+
+       if ((gr = getgrnam(nobodygroup)) == NULL)
+               errx(1, "Could not find group \"%s\"", nobodygroup);
+       nobodygid = gr->gr_gid;
+
+       if (!fg)
+               mydaemon(0, 0);
+
+       event_init();
+
+       if (serverstart)
+               nfsdret = nfsdopen(NFSD_DIR);
+
+       if (clientstart) {
+               struct timeval now = {
+                       .tv_sec = 0,
+                       .tv_usec = 0,
+               };
+
+               if ((fd = open(pipefsdir, O_RDONLY)) == -1)
+                       err(1, "open(%s)", pipefsdir);
+
+               if (fcntl(fd, F_SETSIG, SIGUSR1) == -1)
+                       err(1, "fcntl(%s)", pipefsdir);
+               if (fcntl(fd, F_NOTIFY,
+                       DN_CREATE | DN_DELETE | DN_MODIFY | DN_MULTISHOT) == -1)
+                       err(1, "fcntl(%s)", pipefsdir);
+
+               TAILQ_INIT(&icq);
+
+               /* These events are persistent */
+               signal_set(&rootdirev, SIGUSR1, dirscancb, &icq);
+               signal_add(&rootdirev, NULL);
+               signal_set(&clntdirev, SIGUSR2, clntscancb, &icq);
+               signal_add(&clntdirev, NULL);
+               signal_set(&svrdirev, SIGHUP, svrreopen, NULL);
+               signal_add(&svrdirev, NULL);
+
+               /* Fetch current state */
+               /* (Delay till start of event_dispatch to avoid possibly losing
+                * a SIGUSR1 between here and the call to event_dispatch().) */
+               evtimer_set(&initialize, dirscancb, &icq);
+               evtimer_add(&initialize, &now);
+       }
+
+       if (nfsdret != 0 && fd == 0)
+               errx(1, "Neither NFS client nor NFSd found");
+
+       release_parent();
+
+       if (event_dispatch() < 0)
+               errx(1, "event_dispatch: returns errno %d (%s)", errno, strerror(errno));
+       /* NOTREACHED */
+       return 1;
+}
+
+static void
+dirscancb(int fd, short which, void *data)
+{
+       int nent, i;
+       struct dirent **ents;
+       struct idmap_client *ic;
+       char path[PATH_MAX];
+       struct idmap_clientq *icq = data;
+
+       nent = scandir(pipefsdir, &ents, NULL, alphasort);
+       if (nent == -1) {
+               warn("scandir(%s)", pipefsdir);
+               return;
+       }
+
+       for (i = 0;  i < nent; i++) {
+               if (ents[i]->d_reclen > 4 &&
+                   strncmp(ents[i]->d_name, "clnt", 4) == 0) {
+                       TAILQ_FOREACH(ic, icq, ic_next)
+                           if (strcmp(ents[i]->d_name + 4, ic->ic_clid) == 0)
+                                   break;
+                       if (ic != NULL)
+                               goto next;
+
+                       if ((ic = calloc(1, sizeof(*ic))) == NULL)
+                               return;
+                       strlcpy(ic->ic_clid, ents[i]->d_name + 4,
+                           sizeof(ic->ic_clid));
+                       path[0] = '\0';
+                       snprintf(path, sizeof(path), "%s/%s",
+                           pipefsdir, ents[i]->d_name);
+
+                       if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) {
+                               warn("open(%s)", path);
+                               free(ic);
+                               return;
+                       }
+
+                       strlcat(path, "/idmap", sizeof(path));
+                       strlcpy(ic->ic_path, path, sizeof(ic->ic_path));
+
+                       if (verbose > 0)
+                               warnx("New client: %s", ic->ic_clid);
+
+                       if (nfsopen(ic) == -1) {
+                               close(ic->ic_dirfd);
+                               free(ic);
+                               return;
+                       }
+
+                       ic->ic_id = "Client";
+
+                       TAILQ_INSERT_TAIL(icq, ic, ic_next);
+
+               next:
+                       ic->ic_scanned = 1;
+               }
+       }
+
+       TAILQ_FOREACH(ic, icq, ic_next) {
+               if (!ic->ic_scanned) {
+                       event_del(&ic->ic_event);
+                       close(ic->ic_fd);
+                       close(ic->ic_dirfd);
+                       TAILQ_REMOVE(icq, ic, ic_next);
+                       if (verbose > 0) {
+                               warnx("Stale client: %s", ic->ic_clid);
+                               warnx("\t-> closed %s", ic->ic_path);
+                       }
+                       free(ic);
+               } else
+                       ic->ic_scanned = 0;
+       }
+       return;
+}
+
+static void
+svrreopen(int fd, short which, void *data)
+{
+       nfsdreopen();
+}
+
+static void
+clntscancb(int fd, short which, void *data)
+{
+       struct idmap_clientq *icq = data;
+       struct idmap_client *ic;
+
+       TAILQ_FOREACH(ic, icq, ic_next)
+               if (ic->ic_fd == -1 && nfsopen(ic) == -1) {
+                       close(ic->ic_dirfd);
+                       TAILQ_REMOVE(icq, ic, ic_next);
+                       free(ic);
+               }
+}
+
+static void
+nfsdcb(int fd, short which, void *data)
+{
+       struct idmap_client *ic = data;
+       struct idmap_msg im;
+       u_char buf[IDMAP_MAXMSGSZ + 1];
+       size_t len, bsiz;
+       char *bp, typebuf[IDMAP_MAXMSGSZ],
+               buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p;
+
+       if (which != EV_READ)
+               goto out;
+
+       if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) {
+               warnx("nfsdcb: read(%s) failed: errno %d (%s)",
+                       ic->ic_path, errno, strerror(errno));
+               goto out;
+       }
+
+       /* Get rid of newline and terminate buffer*/
+       buf[len - 1] = '\0';
+       bp = buf;
+
+       memset(&im, 0, sizeof(im));
+
+       /* Authentication name -- ignored for now*/
+       if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) {
+               warnx("nfsdcb: bad authentication name in upcall\n");
+               return;
+       }
+       if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) {
+               warnx("nfsdcb: bad type in upcall\n");
+               return;
+       }
+       if (verbose > 0)
+               warnx("nfsdcb: authbuf=%s authtype=%s", authbuf, typebuf);
+
+       im.im_type = strcmp(typebuf, "user") == 0 ?
+               IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
+
+       switch (ic->ic_which) {
+       case IC_NAMEID:
+               im.im_conv = IDMAP_CONV_NAMETOID;
+               if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) {
+                       warnx("nfsdcb: bad name in upcall\n");
+                       return;
+               }
+               break;
+       case IC_IDNAME:
+               im.im_conv = IDMAP_CONV_IDTONAME;
+               if (getfield(&bp, buf1, sizeof(buf1)) == -1) {
+                       warnx("nfsdcb: bad id in upcall\n");
+                       return;
+               }
+               if ((im.im_id = strtoul(buf1, (char **)NULL, 10)) == ULONG_MAX &&
+                   errno == ERANGE) {
+                       warnx("nfsdcb: id '%s' too big!\n", buf1);
+                       return;
+               }
+
+               break;
+       default:
+               warnx("Unknown which type %d", ic->ic_which);
+               return;
+       }
+
+       imconv(ic, &im);
+
+       buf[0] = '\0';
+       bp = buf;
+       bsiz = sizeof(buf);
+
+       /* Authentication name */
+       addfield(&bp, &bsiz, authbuf);
+
+       switch (ic->ic_which) {
+       case IC_NAMEID:
+               /* Type */
+               p = im.im_type == IDMAP_TYPE_USER ? "user" : "group";
+               addfield(&bp, &bsiz, p);
+               /* Name */
+               addfield(&bp, &bsiz, im.im_name);
+#define NFSD_EXPIRY 300 /* seconds */
+               /* expiry */
+               snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY);
+               addfield(&bp, &bsiz, buf1);
+               /* ID */
+               snprintf(buf1, sizeof(buf1), "%u", im.im_id);
+               addfield(&bp, &bsiz, buf1);
+
+               //if (bsiz == sizeof(buf)) /* XXX */
+
+               bp[-1] = '\n';
+
+               break;
+       case IC_IDNAME:
+               /* Type */
+               p = im.im_type == IDMAP_TYPE_USER ? "user" : "group";
+               addfield(&bp, &bsiz, p);
+               /* ID */
+               snprintf(buf1, sizeof(buf1), "%u", im.im_id);
+               addfield(&bp, &bsiz, buf1);
+               /* expiry */
+               snprintf(buf1, sizeof(buf1), "%lu", time(NULL) + NFSD_EXPIRY);
+               addfield(&bp, &bsiz, buf1);
+               /* Name */
+               addfield(&bp, &bsiz, im.im_name);
+
+               bp[-1] = '\n';
+
+               break;
+       default:
+               warnx("Unknown which type %d", ic->ic_which);
+               return;
+       }
+
+       bsiz = sizeof(buf) - bsiz;
+
+       if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz)
+               warnx("nfsdcb: write(%s) failed: errno %d (%s)",
+                       ic->ic_path, errno, strerror(errno));
+
+out:
+       event_add(&ic->ic_event, NULL);
+}
+
+static void
+imconv(struct idmap_client *ic, struct idmap_msg *im)
+{
+       switch (im->im_conv) {
+       case IDMAP_CONV_IDTONAME:
+               idtonameres(im);
+               if (verbose > 1)
+                       warnx("%s %s: (%s) id \"%d\" -> name \"%s\"",
+                           ic->ic_id, ic->ic_clid,
+                           im->im_type == IDMAP_TYPE_USER ? "user" : "group",
+                           im->im_id, im->im_name);
+               break;
+       case IDMAP_CONV_NAMETOID:
+               if (validateascii(im->im_name, sizeof(im->im_name)) == -1) {
+                       im->im_status |= IDMAP_STATUS_INVALIDMSG;
+                       return;
+               }
+               nametoidres(im);
+               if (verbose > 1)
+                       warnx("%s %s: (%s) name \"%s\" -> id \"%d\"",
+                           ic->ic_id, ic->ic_clid,
+                           im->im_type == IDMAP_TYPE_USER ? "user" : "group",
+                           im->im_name, im->im_id);
+               break;
+       default:
+               warnx("Invalid conversion type (%d) in message", im->im_conv);
+               im->im_status |= IDMAP_STATUS_INVALIDMSG;
+               break;
+       }
+}
+
+static void
+nfscb(int fd, short which, void *data)
+{
+       struct idmap_client *ic = data;
+       struct idmap_msg im;
+
+       if (which != EV_READ)
+               goto out;
+
+       if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) {
+               if (verbose > 0)
+                       warn("read(%s)", ic->ic_path);
+               if (errno == EPIPE)
+                       return;
+               goto out;
+       }
+
+       imconv(ic, &im);
+
+       if (atomicio(write, ic->ic_fd, &im, sizeof(im)) != sizeof(im))
+               warn("write(%s)", ic->ic_path);
+out:
+       event_add(&ic->ic_event, NULL);
+}
+
+static void
+nfsdreopen_one(struct idmap_client *ic)
+{
+       int fd;
+
+       if (verbose > 0)
+               warnx("ReOpening %s", ic->ic_path);
+       if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) {
+               if (ic->ic_fd != -1)
+                       close(ic->ic_fd);
+               ic->ic_event.ev_fd = ic->ic_fd = fd;
+               if ((ic->ic_event.ev_flags & EVLIST_INIT) == 0) {
+                       event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
+                       event_add(&ic->ic_event, NULL);
+               }
+       } else {
+               warnx("nfsdreopen: Opening '%s' failed: errno %d (%s)",
+                       ic->ic_path, errno, strerror(errno));
+       }
+}
+
+/*
+ * Note: nfsdreopen assumes nfsdopen has already been called
+ */
+static void
+nfsdreopen()
+{
+       nfsdreopen_one(&nfsd_ic[IC_NAMEID]);
+       nfsdreopen_one(&nfsd_ic[IC_IDNAME]);
+       return;
+}
+
+static int
+nfsdopen(char *path)
+{
+       return ((nfsdopenone(&nfsd_ic[0], IC_NAMEID, path) == 0 &&
+                   nfsdopenone(&nfsd_ic[1], IC_IDNAME, path) == 0) ? 0 : -1);
+}
+
+static int
+nfsdopenone(struct idmap_client *ic, short which, char *path)
+{
+       char *whichstr;
+
+       whichstr = which == IC_IDNAME ? "idtoname" : "nametoid";
+       snprintf(ic->ic_path, sizeof(ic->ic_path),
+               "%s/nfs4.%s/channel", path, whichstr);
+       if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) {
+               if (verbose > 0)
+                       warnx("Opening %s failed: errno %d (%s)",
+                               ic->ic_path, errno, strerror(errno));
+               return (-1);
+       }
+
+       event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
+       event_add(&ic->ic_event, NULL);
+
+       ic->ic_which = which;
+       ic->ic_id = "Server";
+       strlcpy(ic->ic_clid, "Server", strlen("Server"));
+
+       if (verbose > 0)
+               warnx("Opened %s", ic->ic_path);
+
+       return (0);
+}
+
+static int
+nfsopen(struct idmap_client *ic)
+{
+       if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) {
+               switch (errno) {
+               case ENOENT:
+                       fcntl(ic->ic_dirfd, F_SETSIG, SIGUSR2);
+                       fcntl(ic->ic_dirfd, F_NOTIFY,
+                           DN_CREATE | DN_DELETE | DN_MULTISHOT);
+                       break;
+               default:
+                       warn("open(%s)", ic->ic_path);
+                       return (-1);
+               }
+       } else {
+               event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic);
+               event_add(&ic->ic_event, NULL);
+               fcntl(ic->ic_dirfd, F_SETSIG, 0);
+               fcntl(ic->ic_dirfd, F_NOTIFY, 0);
+               if (verbose > 0)
+                       warnx("Opened %s", ic->ic_path);
+       }
+
+       return (0);
+}
+
+static int write_name(char *dest, char *localname, char *domain, size_t len)
+{
+       if (strlen(localname) + 1 + strlen(domain) + 1 > len) {
+               return -ENOMEM; /* XXX: Is there an -ETOOLONG? */
+       }
+       strcpy(dest, localname);
+       strcat(dest, "@");
+       strcat(dest, domain);
+       return 0;
+}
+
+static void
+idtonameres(struct idmap_msg *im)
+{
+       char domain[NFS4_MAX_DOMAIN_LEN];
+       int ret = 0;
+
+       ret = nfs4_get_default_domain(NULL, domain, sizeof(domain));
+       switch (im->im_type) {
+       case IDMAP_TYPE_USER:
+               ret = nfs4_uid_to_name(im->im_id, domain, im->im_name,
+                               sizeof(im->im_name));
+               if (ret)
+                       write_name(im->im_name, nobodyuser, domain,
+                                       sizeof(im->im_name));
+               break;
+       case IDMAP_TYPE_GROUP:
+               ret = nfs4_gid_to_name(im->im_id, domain, im->im_name,
+                               sizeof(im->im_name));
+               if (ret)
+                       write_name(im->im_name, nobodygroup, domain,
+                                       sizeof(im->im_name));
+               break;
+       }
+       /* XXX Hack? would rather return failure instead of writing nobody
+        * as above, but kernel seems not to deal well with that as of
+        * 2.6.8-rc3. */
+       im->im_status = IDMAP_STATUS_SUCCESS;
+}
+
+static void
+nametoidres(struct idmap_msg *im)
+{
+       int ret = 0;
+
+       switch (im->im_type) {
+       case IDMAP_TYPE_USER:
+               ret = nfs4_name_to_uid(im->im_name, &im->im_id);
+               if (ret)
+                       im->im_id = nobodyuid;
+               break;
+       case IDMAP_TYPE_GROUP:
+               ret = nfs4_name_to_gid(im->im_name, &im->im_id);
+               if (ret)
+                       im->im_id = nobodygid;
+               break;
+       }
+       /* XXX Hack? would rather return failure instead of writing nobody
+        * as above, but kernel seems not to deal well with that as of
+        * 2.6.8-rc3. */
+       im->im_status = IDMAP_STATUS_SUCCESS;
+}
+
+static int
+validateascii(char *string, u_int32_t len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               if (string[i] == '\0')
+                       break;
+
+               if (string[i] & 0x80)
+                       return (-1);
+       }
+
+       if (string[i] != '\0')
+               return (-1);
+
+       return (i + 1);
+}
+
+static int
+addfield(char **bpp, ssize_t *bsizp, char *fld)
+{
+       char ch, *bp = *bpp;
+       ssize_t bsiz = *bsizp;
+
+       while ((ch = *fld++) != '\0' && bsiz > 0) {
+               switch(ch) {
+               case ' ':
+               case '\t':
+               case '\n':
+               case '\\':
+                       if (bsiz >= 4) {
+                               bp += snprintf(bp, bsiz, "\\%03o", ch);
+                               bsiz -= 4;
+                       }
+                       break;
+               default:
+                       *bp++ = ch;
+                       bsiz--;
+                       break;
+               }
+       }
+
+       if (bsiz < 1 || ch != '\0')
+               return (-1);
+
+       *bp++ = ' ';
+       bsiz--;
+
+       *bpp = bp;
+       *bsizp = bsiz;
+
+       return (0);
+}
+
+static int
+getfield(char **bpp, char *fld, size_t fldsz)
+{
+       char *bp;
+       u_int val, n;
+
+       while ((bp = strsep(bpp, " ")) != NULL && bp[0] == '\0')
+               ;
+
+       if (bp == NULL || bp[0] == '\0' || bp[0] == '\n')
+               return (-1);
+
+       while (*bp != '\0' && fldsz > 1) {
+               if (*bp == '\\') {
+                       if ((n = sscanf(bp, "\\%03o", &val)) != 1)
+                               return (-1);
+                       if (val > (char)-1)
+                               return (-1);
+                       *fld++ = (char)val;
+                       bp += 4;
+               } else {
+                       *fld++ = *bp;
+                       bp++;
+               }
+               fldsz--;
+       }
+
+       if (*bp != '\0')
+               return (-1);
+       *fld = '\0';
+
+       return (0);
+}
+/*
+ * 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};
+
+void
+mydaemon(int nochdir, int noclose)
+{
+       int pid, status, tempfd, fdmax, filedes;
+
+       if (pipe(pipefds) < 0)
+               err(1, "mydaemon: pipe() failed: errno %d (%s)\n", errno, strerror(errno));
+
+       if ((pid = fork ()) < 0)
+               err(1, "mydaemon: fork() failed: errno %d (%s)\n", errno, strerror(errno));
+
+       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)
+                       err(1, "mydaemon: chdir() failed: errno %d (%s)\n", errno, strerror(errno));
+       }
+
+       while (pipefds[1] <= 2) {
+               pipefds[1] = dup(pipefds[1]);
+               if (pipefds[1] < 0)
+                       err(1, "mydaemon: dup() failed: errno %d (%s)\n", errno, strerror(errno));
+       }
+
+       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;
+}
+void
+release_parent()
+{
+       int status;
+
+       if (pipefds[1] > 0) {
+               write(pipefds[1], &status, 1);
+               close(pipefds[1]);
+               pipefds[1] = -1;
+       }
+}
diff --git a/utils/idmapd/idmapd.conf b/utils/idmapd/idmapd.conf
new file mode 100644 (file)
index 0000000..acafd4b
--- /dev/null
@@ -0,0 +1,10 @@
+[General]
+
+Verbosity = 0
+Pipefs-Directory = /var/lib/nfs/rpc_pipefs
+Domain = localdomain
+
+[Mapping]
+
+Nobody-User = nobody
+Nobody-Group = nobody
diff --git a/utils/idmapd/idmapd.conf.man b/utils/idmapd/idmapd.conf.man
new file mode 100644 (file)
index 0000000..f4ea200
--- /dev/null
@@ -0,0 +1,74 @@
+.\"    $OpenBSD: mdoc.template,v 1.6 2001/02/03 08:22:44 niklas Exp $
+.\"
+.\" The following requests are required for all man pages.
+.Dd July 16, 2003
+.Dt idmapd.conf 5
+.Os
+.Sh NAME
+.Nm idmapd.conf
+.Nd configuration file for idmapd, the NFSv4 ID <-> Name Mapper
+.Sh SYNOPSIS
+Configuration file for idmapd, the NFSv4 ID <-> Name Mapper
+.Sh DESCRIPTION
+The
+.Nm
+configuration file has two sections, initiated by the strings
+[General] and [Mapping].  Each section may contain lines of the form
+
+.Dl variable = value
+
+The variables allowed in the General section are
+.Va Verbosity,
+.Va Pipefs-Directory,
+and
+.Va Domain,
+whose values have the same effect as the arguments to the
+.Fl v,
+.Fl p,
+and
+.Fl d
+commandline options, respectively.  The variables allowed in the
+Mapping section are
+.Va Nobody-User
+and
+.Va Nobody-Group,
+which have the same effect as the
+.Fl U
+and
+.Fl G
+commandline options.
+
+.Sh EXAMPLES
+
+An example
+.Pa /etc/idmapd.conf
+file:
+
+.Bd -literal
+[General]
+
+Verbosity = 0
+Pipefs-Directory = /var/lib/nfs/rpc_pipefs
+Domain = localdomain
+
+[Mapping]
+
+Nobody-User = nobody
+Nobody-Group = nobody
+.Ed
+
+.Sh SEE ALSO
+.Xr idmapd 8
+.\".Sh SEE ALSO
+.\".Xr nylon.conf 4
+.\" .Sh COMPATIBILITY
+.\".Sh STANDARDS
+.\".Sh ACKNOWLEDGEMENTS
+.Sh AUTHORS
+The idmapd software has been developed by Marius Aamodt Eriksen
+.Aq marius@citi.umich.edu .
+.\" .Sh HISTORY
+.\".Sh BUGS
+.\"Please report any bugs to Marius Aamodt Eriksen
+.\".Aq marius@monkey.org .
+.\" .Sh CAVEATS
diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man
new file mode 100644 (file)
index 0000000..58ea9f2
--- /dev/null
@@ -0,0 +1,94 @@
+.\"    $OpenBSD: mdoc.template,v 1.6 2001/02/03 08:22:44 niklas Exp $
+.\"
+.\" The following requests are required for all man pages.
+.Dd February 3, 2003
+.Dt RPC.IDMAPD 8
+.Os
+.Sh NAME
+.Nm rpc.idmapd
+.Nd NFSv4 ID <-> Name Mapper
+.Sh SYNOPSIS
+.\" For a program:  program [-abc] file ...
+.Nm rpc.idmapd
+.Op Fl v
+.Op Fl f
+.Op Fl d Ar domain
+.Op Fl p Ar path
+.Op Fl U Ar username
+.Op Fl G Ar groupname
+.Op Fl c Ar path
+.Sh DESCRIPTION
+.Nm
+is the NFSv4 ID <-> name mapping daemon.  It provides functionality to
+the NFSv4 kernel client and server, to which it communicates via
+upcalls, by translating user and group IDs to names, and vice versa.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds_imagedir
+.It Fl v
+Increases the verbosity level (can be specified multiple times).
+.It Fl f
+Runs
+.Nm
+in the foreground and prints all output to the terminal.
+.It Fl d Ar domain
+Set domain to
+.Ar domain .
+This is used internally by NFSv4 and is typically assigned by the
+system administrator.  By default,
+.Ar domain
+is set to be the FQDN of the host, minus the hostname.
+.It Fl p Ar path
+Specifies the location of the RPC pipefs to be
+.Ar path .
+The default value is \&"/var/lib/nfs/rpc_pipefs\&".
+.It Fl U Ar username
+Specifies the NFSv4 nobody user to be
+.Ar username .
+The default value is \&"nobody\&".
+.It Fl G Ar groupname
+Specifies the NFSv4 nobody group to be
+.Ar groupname .
+The default value is \&"nobody\&".
+.It Fl c Ar path
+Use configuration file
+.Ar path .
+.It Fl C
+Client-only: perform no idmapping for any NFS server, even if one is detected.
+.It Fl S
+Server-only: perform no idmapping for any NFS client, even if one is detected.
+.El
+.Sh EXAMPLES
+.Cm rpc.idmapd -d \&"citi.umich.edu\&" -f -vvv
+.Pp
+Runs
+.Nm
+with the domain \&"citi.umich.edu\&" in the foreground, printing all
+messages to console, and with a verbosity level of 3.
+.\" This next request is for sections 2 and 3 function return values only.
+.\" .Sh RETURN VALUES
+.\" The next request is for sections 2 and 3 error and signal handling only.
+.\" .Sh ERRORS
+.\" This next request is for section 4 only.
+.\" .Sh DIAGNOSTICS
+.\" This next request is for sections 1, 6, 7 & 8 only.
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Pa /etc/idmapd.conf
+.Sh SEE ALSO
+.Xr idmapd.conf 5
+.\".Sh SEE ALSO
+.\".Xr nylon.conf 4
+.\" .Sh COMPATIBILITY
+.\".Sh STANDARDS
+.\".Sh ACKNOWLEDGEMENTS
+.Sh AUTHORS
+The
+.Nm
+software has been developed by Marius Aamodt Eriksen
+.Aq marius@citi.umich.edu .
+.\" .Sh HISTORY
+.\".Sh BUGS
+.\"Please report any bugs to Marius Aamodt Eriksen
+.\".Aq marius@monkey.org .
+.\" .Sh CAVEATS
diff --git a/utils/idmapd/nfs_idmap.h b/utils/idmapd/nfs_idmap.h
new file mode 100644 (file)
index 0000000..5ec7cf1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * include/linux/nfs_idmap.h
+ *
+ *  UID and GID to name mapping for clients.
+ *
+ *  Copyright (c) 2002 The Regents of the University of Michigan.
+ *  All rights reserved.
+ *
+ *  Marius Aamodt Eriksen <marius@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.
+ */
+
+#ifndef NFS_IDMAP_H
+#define NFS_IDMAP_H
+
+/* XXX from bits/utmp.h  */
+#define IDMAP_NAMESZ  128
+
+#define IDMAP_TYPE_USER  0
+#define IDMAP_TYPE_GROUP 1
+
+#define IDMAP_CONV_IDTONAME 0
+#define IDMAP_CONV_NAMETOID 1
+
+#define IDMAP_STATUS_INVALIDMSG 0x01
+#define IDMAP_STATUS_AGAIN      0x02
+#define IDMAP_STATUS_LOOKUPFAIL 0x04
+#define IDMAP_STATUS_SUCCESS    0x08
+
+#define IDMAP_MAXMSGSZ   256
+
+struct idmap_msg {
+       u_int8_t  im_type;
+       u_int8_t  im_conv;
+       char      im_name[IDMAP_NAMESZ];
+       u_int32_t im_id;
+       u_int8_t  im_status;
+};
+
+#ifdef __KERNEL__
+void      *nfs_idmap_new(struct nfs_server *);
+void       nfs_idmap_delete(struct nfs_server *);
+int        nfs_idmap_id(struct nfs_server *, u_int8_t, char *, u_int,  uid_t *);
+int        nfs_idmap_name(struct nfs_server *, u_int8_t, uid_t, char *, u_int *);
+#endif /* __KERNEL__ */
+
+#endif /* NFS_IDMAP_H */
diff --git a/utils/idmapd/queue.h b/utils/idmapd/queue.h
new file mode 100644 (file)
index 0000000..2823fe7
--- /dev/null
@@ -0,0 +1,499 @@
+/*     $OpenBSD: queue.h,v 1.22 2001/06/23 04:39:35 angelos Exp $      */
+/*     $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $       */
+
+/*
+ * Copyright (c) 1991, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)queue.h     8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef        _SYS_QUEUE_H_
+#define        _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *slh_first; /* first element */                     \
+}
+
+#define        SLIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define SLIST_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *sle_next;  /* next element */                      \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define        SLIST_FIRST(head)       ((head)->slh_first)
+#define        SLIST_END(head)         NULL
+#define        SLIST_EMPTY(head)       (SLIST_FIRST(head) == SLIST_END(head))
+#define        SLIST_NEXT(elm, field)  ((elm)->field.sle_next)
+
+#define        SLIST_FOREACH(var, head, field)                                 \
+       for((var) = SLIST_FIRST(head);                                  \
+           (var) != SLIST_END(head);                                   \
+           (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define        SLIST_INIT(head) {                                              \
+       SLIST_FIRST(head) = SLIST_END(head);                            \
+}
+
+#define        SLIST_INSERT_AFTER(slistelm, elm, field) do {                   \
+       (elm)->field.sle_next = (slistelm)->field.sle_next;             \
+       (slistelm)->field.sle_next = (elm);                             \
+} while (0)
+
+#define        SLIST_INSERT_HEAD(head, elm, field) do {                        \
+       (elm)->field.sle_next = (head)->slh_first;                      \
+       (head)->slh_first = (elm);                                      \
+} while (0)
+
+#define        SLIST_REMOVE_HEAD(head, field) do {                             \
+       (head)->slh_first = (head)->slh_first->field.sle_next;          \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do {                      \
+       if ((head)->slh_first == (elm)) {                               \
+               SLIST_REMOVE_HEAD((head), field);                       \
+       }                                                               \
+       else {                                                          \
+               struct type *curelm = (head)->slh_first;                \
+               while( curelm->field.sle_next != (elm) )                \
+                       curelm = curelm->field.sle_next;                \
+               curelm->field.sle_next =                                \
+                   curelm->field.sle_next->field.sle_next;             \
+       }                                                               \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type)                                          \
+struct name {                                                          \
+       struct type *lh_first;  /* first element */                     \
+}
+
+#define LIST_HEAD_INITIALIZER(head)                                    \
+       { NULL }
+
+#define LIST_ENTRY(type)                                               \
+struct {                                                               \
+       struct type *le_next;   /* next element */                      \
+       struct type **le_prev;  /* address of previous next element */  \
+}
+
+/*
+ * List access methods
+ */
+#define        LIST_FIRST(head)                ((head)->lh_first)
+#define        LIST_END(head)                  NULL
+#define        LIST_EMPTY(head)                (LIST_FIRST(head) == LIST_END(head))
+#define        LIST_NEXT(elm, field)           ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field)                                 \
+       for((var) = LIST_FIRST(head);                                   \
+           (var)!= LIST_END(head);                                     \
+           (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define        LIST_INIT(head) do {                                            \
+       LIST_FIRST(head) = LIST_END(head);                              \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do {                    \
+       if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)  \
+               (listelm)->field.le_next->field.le_prev =               \
+                   &(elm)->field.le_next;                              \
+       (listelm)->field.le_next = (elm);                               \
+       (elm)->field.le_prev = &(listelm)->field.le_next;               \
+} while (0)
+
+#define        LIST_INSERT_BEFORE(listelm, elm, field) do {                    \
+       (elm)->field.le_prev = (listelm)->field.le_prev;                \
+       (elm)->field.le_next = (listelm);                               \
+       *(listelm)->field.le_prev = (elm);                              \
+       (listelm)->field.le_prev = &(elm)->field.le_next;               \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do {                                \
+       if (((elm)->field.le_next = (head)->lh_first) != NULL)          \
+               (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+       (head)->lh_first = (elm);                                       \
+       (elm)->field.le_prev = &(head)->lh_first;                       \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do {                                   \
+       if ((elm)->field.le_next != NULL)                               \
+               (elm)->field.le_next->field.le_prev =                   \
+                   (elm)->field.le_prev;                               \
+       *(elm)->field.le_prev = (elm)->field.le_next;                   \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do {                            \
+       if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)     \
+               (elm2)->field.le_next->field.le_prev =                  \
+                   &(elm2)->field.le_next;                             \
+       (elm2)->field.le_prev = (elm)->field.le_prev;                   \
+       *(elm2)->field.le_prev = (elm2);                                \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *sqh_first; /* first element */                     \
+       struct type **sqh_last; /* addr of last next element */         \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head)                                 \
+       { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *sqe_next;  /* next element */                      \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define        SIMPLEQ_FIRST(head)         ((head)->sqh_first)
+#define        SIMPLEQ_END(head)           NULL
+#define        SIMPLEQ_EMPTY(head)         (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define        SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field)                              \
+       for((var) = SIMPLEQ_FIRST(head);                                \
+           (var) != SIMPLEQ_END(head);                                 \
+           (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define        SIMPLEQ_INIT(head) do {                                         \
+       (head)->sqh_first = NULL;                                       \
+       (head)->sqh_last = &(head)->sqh_first;                          \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)        \
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (head)->sqh_first = (elm);                                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.sqe_next = NULL;                                   \
+       *(head)->sqh_last = (elm);                                      \
+       (head)->sqh_last = &(elm)->field.sqe_next;                      \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+               (head)->sqh_last = &(elm)->field.sqe_next;              \
+       (listelm)->field.sqe_next = (elm);                              \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do {                     \
+       if (((head)->sqh_first = (elm)->field.sqe_next) == NULL)        \
+               (head)->sqh_last = &(head)->sqh_first;                  \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type)                                         \
+struct name {                                                          \
+       struct type *tqh_first; /* first element */                     \
+       struct type **tqh_last; /* addr of last next element */         \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head)                                   \
+       { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type)                                              \
+struct {                                                               \
+       struct type *tqe_next;  /* next element */                      \
+       struct type **tqe_prev; /* address of previous next element */  \
+}
+
+/*
+ * tail queue access methods
+ */
+#define        TAILQ_FIRST(head)               ((head)->tqh_first)
+#define        TAILQ_END(head)                 NULL
+#define        TAILQ_NEXT(elm, field)          ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname)                                     \
+       (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field)                               \
+       (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define        TAILQ_EMPTY(head)                                               \
+       (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field)                                        \
+       for((var) = TAILQ_FIRST(head);                                  \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, field, headname)              \
+       for((var) = TAILQ_LAST(head, headname);                         \
+           (var) != TAILQ_END(head);                                   \
+           (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define        TAILQ_INIT(head) do {                                           \
+       (head)->tqh_first = NULL;                                       \
+       (head)->tqh_last = &(head)->tqh_first;                          \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do {                       \
+       if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)        \
+               (head)->tqh_first->field.tqe_prev =                     \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (head)->tqh_first = (elm);                                      \
+       (elm)->field.tqe_prev = &(head)->tqh_first;                     \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do {                       \
+       (elm)->field.tqe_next = NULL;                                   \
+       (elm)->field.tqe_prev = (head)->tqh_last;                       \
+       *(head)->tqh_last = (elm);                                      \
+       (head)->tqh_last = &(elm)->field.tqe_next;                      \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {             \
+       if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   &(elm)->field.tqe_next;                             \
+       else                                                            \
+               (head)->tqh_last = &(elm)->field.tqe_next;              \
+       (listelm)->field.tqe_next = (elm);                              \
+       (elm)->field.tqe_prev = &(listelm)->field.tqe_next;             \
+} while (0)
+
+#define        TAILQ_INSERT_BEFORE(listelm, elm, field) do {                   \
+       (elm)->field.tqe_prev = (listelm)->field.tqe_prev;              \
+       (elm)->field.tqe_next = (listelm);                              \
+       *(listelm)->field.tqe_prev = (elm);                             \
+       (listelm)->field.tqe_prev = &(elm)->field.tqe_next;             \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do {                            \
+       if (((elm)->field.tqe_next) != NULL)                            \
+               (elm)->field.tqe_next->field.tqe_prev =                 \
+                   (elm)->field.tqe_prev;                              \
+       else                                                            \
+               (head)->tqh_last = (elm)->field.tqe_prev;               \
+       *(elm)->field.tqe_prev = (elm)->field.tqe_next;                 \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do {                     \
+       if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)   \
+               (elm2)->field.tqe_next->field.tqe_prev =                \
+                   &(elm2)->field.tqe_next;                            \
+       else                                                            \
+               (head)->tqh_last = &(elm2)->field.tqe_next;             \
+       (elm2)->field.tqe_prev = (elm)->field.tqe_prev;                 \
+       *(elm2)->field.tqe_prev = (elm2);                               \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type)                                       \
+struct name {                                                          \
+       struct type *cqh_first;         /* first element */             \
+       struct type *cqh_last;          /* last element */              \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head)                                 \
+       { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type)                                            \
+struct {                                                               \
+       struct type *cqe_next;          /* next element */              \
+       struct type *cqe_prev;          /* previous element */          \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define        CIRCLEQ_FIRST(head)             ((head)->cqh_first)
+#define        CIRCLEQ_LAST(head)              ((head)->cqh_last)
+#define        CIRCLEQ_END(head)               ((void *)(head))
+#define        CIRCLEQ_NEXT(elm, field)        ((elm)->field.cqe_next)
+#define        CIRCLEQ_PREV(elm, field)        ((elm)->field.cqe_prev)
+#define        CIRCLEQ_EMPTY(head)                                             \
+       (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field)                              \
+       for((var) = CIRCLEQ_FIRST(head);                                \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                      \
+       for((var) = CIRCLEQ_LAST(head);                                 \
+           (var) != CIRCLEQ_END(head);                                 \
+           (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define        CIRCLEQ_INIT(head) do {                                         \
+       (head)->cqh_first = CIRCLEQ_END(head);                          \
+       (head)->cqh_last = CIRCLEQ_END(head);                           \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {           \
+       (elm)->field.cqe_next = (listelm)->field.cqe_next;              \
+       (elm)->field.cqe_prev = (listelm);                              \
+       if ((listelm)->field.cqe_next == CIRCLEQ_END(head))             \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (listelm)->field.cqe_next->field.cqe_prev = (elm);      \
+       (listelm)->field.cqe_next = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {          \
+       (elm)->field.cqe_next = (listelm);                              \
+       (elm)->field.cqe_prev = (listelm)->field.cqe_prev;              \
+       if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))             \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (listelm)->field.cqe_prev->field.cqe_next = (elm);      \
+       (listelm)->field.cqe_prev = (elm);                              \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                     \
+       (elm)->field.cqe_next = (head)->cqh_first;                      \
+       (elm)->field.cqe_prev = CIRCLEQ_END(head);                      \
+       if ((head)->cqh_last == CIRCLEQ_END(head))                      \
+               (head)->cqh_last = (elm);                               \
+       else                                                            \
+               (head)->cqh_first->field.cqe_prev = (elm);              \
+       (head)->cqh_first = (elm);                                      \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                     \
+       (elm)->field.cqe_next = CIRCLEQ_END(head);                      \
+       (elm)->field.cqe_prev = (head)->cqh_last;                       \
+       if ((head)->cqh_first == CIRCLEQ_END(head))                     \
+               (head)->cqh_first = (elm);                              \
+       else                                                            \
+               (head)->cqh_last->field.cqe_next = (elm);               \
+       (head)->cqh_last = (elm);                                       \
+} while (0)
+
+#define        CIRCLEQ_REMOVE(head, elm, field) do {                           \
+       if ((elm)->field.cqe_next == CIRCLEQ_END(head))                 \
+               (head)->cqh_last = (elm)->field.cqe_prev;               \
+       else                                                            \
+               (elm)->field.cqe_next->field.cqe_prev =                 \
+                   (elm)->field.cqe_prev;                              \
+       if ((elm)->field.cqe_prev == CIRCLEQ_END(head))                 \
+               (head)->cqh_first = (elm)->field.cqe_next;              \
+       else                                                            \
+               (elm)->field.cqe_prev->field.cqe_next =                 \
+                   (elm)->field.cqe_next;                              \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {                   \
+       if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_last = (elm2);                               \
+       else                                                            \
+               (elm2)->field.cqe_next->field.cqe_prev = (elm2);        \
+       if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==         \
+           CIRCLEQ_END(head))                                          \
+               (head).cqh_first = (elm2);                              \
+       else                                                            \
+               (elm2)->field.cqe_prev->field.cqe_next = (elm2);        \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/utils/idmapd/setproctitle.c b/utils/idmapd/setproctitle.c
new file mode 100644 (file)
index 0000000..0679f4e
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Modified for OpenSSH by Kevin Steves
+ * October 2000
+ */
+
+/*
+ * Copyright (c) 1994, 1995 Christopher G. Demetriou
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Christopher G. Demetriou
+ *     for the NetBSD Project.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char rcsid[] = "$OpenBSD: setproctitle.c,v 1.8 2001/11/06 19:21:40 art Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_SETPROCTITLE
+
+#define SPT_NONE       0
+#define SPT_PSTAT      1
+
+#ifndef SPT_TYPE
+#define SPT_TYPE       SPT_NONE
+#endif
+
+#if SPT_TYPE == SPT_PSTAT
+#include <sys/param.h>
+#include <sys/pstat.h>
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+#define        MAX_PROCTITLE   2048
+
+extern char *__progname;
+
+/*
+ * Set Process Title (SPT) defines.  Modeled after sendmail's
+ * SPT type definition strategy.
+ *
+ * SPT_TYPE:
+ *
+ * SPT_NONE:   Don't set the process title.  Default.
+ * SPT_PSTAT:  Use pstat(PSTAT_SETCMD).  HP-UX specific.
+ */
+
+void
+setproctitle(const char *fmt, ...)
+{
+#if SPT_TYPE != SPT_NONE
+       va_list ap;
+
+       char buf[MAX_PROCTITLE];
+       size_t used;
+
+#if SPT_TYPE == SPT_PSTAT
+       union pstun pst;
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+       va_start(ap, fmt);
+       if (fmt != NULL) {
+               used = snprintf(buf, MAX_PROCTITLE, "%s: ", __progname);
+               if (used >= MAX_PROCTITLE)
+                       used = MAX_PROCTITLE - 1;
+               (void)vsnprintf(buf + used, MAX_PROCTITLE - used, fmt, ap);
+       } else
+               (void)snprintf(buf, MAX_PROCTITLE, "%s", __progname);
+       va_end(ap);
+       used = strlen(buf);
+
+#if SPT_TYPE == SPT_PSTAT
+       pst.pst_command = buf;
+       pstat(PSTAT_SETCMD, pst, used, 0, 0);
+#endif /* SPT_TYPE == SPT_PSTAT */
+
+#endif /* SPT_TYPE != SPT_NONE */
+}
+#endif /* HAVE_SETPROCTITLE */
diff --git a/utils/idmapd/strlcat.c b/utils/idmapd/strlcat.c
new file mode 100644 (file)
index 0000000..2c8b20a
--- /dev/null
@@ -0,0 +1,77 @@
+/*     $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * Appends src to string dst of size siz (unlike strncat, siz is the
+ * full size of dst, not space left).  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
+ * Returns strlen(src) + MIN(siz, strlen(initial dst)).
+ * If retval >= siz, truncation occurred.
+ */
+size_t
+strlcat(dst, src, siz)
+       char *dst;
+       const char *src;
+       size_t siz;
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
+               }
+               s++;
+       }
+       *d = '\0';
+
+       return(dlen + (s - src));       /* count does not include NUL */
+}
diff --git a/utils/idmapd/strlcpy.c b/utils/idmapd/strlcpy.c
new file mode 100644 (file)
index 0000000..528d4f1
--- /dev/null
@@ -0,0 +1,73 @@
+/*     $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $     */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 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 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(dst, src, siz)
+       char *dst;
+       const char *src;
+       size_t siz;
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
+       }
+
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
+       }
+
+       return(s - src - 1);    /* count does not include NUL */
+}
index 9d244cff4437410be5677b7e7dcfa9f136d8824b..a34dc92224fe5d1640b4e9e32c96ecb06bb74704 100644 (file)
@@ -1,7 +1,7 @@
 .\"
 .\" lockd(8)
 .\"
-.\" Copyright (C) 2000 Chip Salzenberg <chip@valinux.com>
+.\" Copyright (C) 2000 Chip Salzenberg <chip@debian.org>
 .\"
 .TH rpc.lockd 8 "25 Feb 2000"
 .SH NAME
index 6361fcebb13f6f1170c791ba9e65752e8416e5f6..4e1cdbd800527e40825f534781227d0867dfd0c6 100644 (file)
@@ -30,6 +30,8 @@ enum auth_error
 
 static void            auth_fixpath(char *path);
 static char    *export_file = NULL;
+static nfs_export my_exp;
+static nfs_client my_client;
 
 extern int new_cache;
 
@@ -55,6 +57,7 @@ auth_reload()
        last_modified = stb.st_mtime;
 
        export_freeall();
+       memset(&my_client, 0, sizeof(my_client));
        // export_read(export_file);
        xtab_export_read();
 
@@ -69,8 +72,6 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
        nfs_export              *exp;
 
        if (new_cache) {
-               static nfs_export my_exp;
-               static nfs_client my_client;
                int i;
                /* return static nfs_export with details filled in */
                if (my_client.m_naddr != 1 ||
@@ -80,6 +81,7 @@ auth_authenticate_internal(char *what, struct sockaddr_in *caller,
                        my_client.m_naddr = 0;
                        my_client.m_addrlist[0] = caller->sin_addr;
                        n = client_compose(caller->sin_addr);
+                       *error = unknown_host;
                        if (!n)
                                return NULL;
                        strcpy(my_client.m_hostname, *n?n:"DEFAULT");
index 3a166419e4e7892cce9970da192b95e5de9f24ec..77029f446bff8fd33957613bbe116869148583a4 100644 (file)
@@ -315,6 +315,7 @@ int cache_process_req(fd_set *readfds)
                    FD_ISSET(fileno(cachelist[i].f), readfds)) {
                        cnt++;
                        cachelist[i].cache_handle(cachelist[i].f);
+                       FD_CLR(fileno(cachelist[i].f), readfds);
                }
        }
        return cnt;
index 8f6f9cb9d85d8ad69754a9db1bdbda2233feab76..14dac4185c32e9483f108a7faccdc9811ff0f3c1 100644 (file)
@@ -36,6 +36,11 @@ static struct nfs_fh_len *get_rootfh(struct svc_req *, dirpath *, int *, int v3)
 
 int new_cache = 0;
 
+/* PRC: a high-availability callout program can be specified with -H
+ * When this is done, the program will receive callouts whenever clients
+ * send mount or unmount requests -- the callout is not needed for 2.6 kernel */
+char *ha_callout_prog = NULL;
+
 static struct option longopts[] =
 {
        { "foreground", 0, 0, 'F' },
@@ -48,6 +53,7 @@ static struct option longopts[] =
        { "version", 0, 0, 'v' },
        { "port", 1, 0, 'p' },
        { "no-tcp", 0, 0, 'n' },
+       { "ha-callout", 1, 0, 'H' },
        { NULL, 0, 0, 0 }
 };
 
@@ -444,7 +450,7 @@ main(int argc, char **argv)
 
        /* Parse the command line options and arguments. */
        opterr = 0;
-       while ((c = getopt_long(argc, argv, "o:n:Fd:f:p:P:hN:V:v", longopts, NULL)) != EOF)
+       while ((c = getopt_long(argc, argv, "o:n:Fd:f:p:P:hH:N:V:v", longopts, NULL)) != EOF)
                switch (c) {
                case 'o':
                        descriptors = atoi(optarg);
@@ -463,6 +469,9 @@ main(int argc, char **argv)
                case 'f':
                        export_file = optarg;
                        break;
+               case 'H': /* PRC: specify a high-availability callout program */
+                       ha_callout_prog = optarg;
+                       break;
                case 'h':
                        usage(argv [0], 0);
                        break;
@@ -522,7 +531,8 @@ main(int argc, char **argv)
                }
        }
        /* Initialize logging. */
-/*     xlog_open("mountd"); */
+       if (!foreground) xlog_stderr(0);
+       xlog_open("mountd");
 
        sa.sa_handler = SIG_IGN;
        sa.sa_flags = 0;
@@ -580,7 +590,6 @@ main(int argc, char **argv)
                        if (fd > 2) (void) close(fd);
                }
                setsid();
-               xlog_background();
        }
 
        my_svc_run();
@@ -596,6 +605,7 @@ usage(const char *prog, int n)
 "Usage: %s [-F|--foreground] [-h|--help] [-v|--version] [-d kind|--debug kind]\n"
 "      [-o num|--descriptors num] [-f exports-file|--exports-file=file]\n"
 "      [-p|--port port] [-V version|--nfs-version version]\n"
-"      [-N version|--no-nfs-version version] [-n|--no-tcp]\n", prog);
+"      [-N version|--no-nfs-version version] [-n|--no-tcp]\n"
+"      [-H ha-callout-prog]\n", prog);
        exit(n);
 }
index 6e795291e03b40d14e08285c466758cd9ead6a49..64e508a26ea2768ad39ca98e4384b9c36162105f 100644 (file)
@@ -2,7 +2,8 @@
 .\" mountd(8)
 .\"
 .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
-.TH rpc.mountd 8 "25 Aug 2000"
+.\" Modified by Paul Clements, 2004.
+.TH rpc.mountd 8 "31 Aug 2004"
 .SH NAME
 rpc.mountd \- NFS mount daemon
 .SH SYNOPSIS
@@ -44,7 +45,6 @@ For every mount request received from an NFS client,
 adds an entry to the
 .B /var/lib/nfs/rmtab
 file. When receiving an unmount request, that entry is removed.
-user level part of the NFS service.
 .P
 However, this file is mostly ornamental. One, the client can continue
 to use the file handle even after calling
@@ -99,6 +99,26 @@ Force
 to bind to the specified port num, instead of using the random port
 number assigned by the portmapper.
 .TP
+.B \-H " or " \-\-ha-callout prog
+Specify a high availability callout program, which will receive callouts
+for all client mount and unmount requests. This allows 
+.B rpc.mountd
+to be used in a High Availability NFS (HA-NFS) environment. This callout is not
+needed (and should not be used) with 2.6 and later kernels (instead,
+mount the nfsd filesystem on
+.B /proc/fs/nfsd
+).
+The program will be called with 4 arguments.
+The first will be
+.B mount
+or
+.B unmount
+depending on the reason for the callout.
+The second will be the name of the client performing the mount.
+The third will be the path that the client is mounting.
+The last is the number of concurrent mounts that we believe the client
+has of that path.
+.TP
 .B \-V " or " \-\-nfs-version
 This option can be used to request that
 .B rpc.mountd
index 844de511f48b07d76baac5b0b828b9e5520af33f..90fbef4702eede421b96e0e46ebe35aaf3c8037c 100644 (file)
@@ -19,6 +19,7 @@
 #include "exportfs.h"
 #include "xio.h"
 #include "mountd.h"
+#include "ha-callout.h"
 
 #include <limits.h> /* PATH_MAX */
 
@@ -61,6 +62,8 @@ mountlist_add(char *host, const char *path)
                            host) == 0
                    && strcmp(rep->r_path, path) == 0) {
                        rep->r_count++;
+                       /* PRC: do the HA callout: */
+                       ha_callout("mount", rep->r_client, rep->r_path, rep->r_count);
                        putrmtabent(rep, &pos);
                        endrmtabent();
                        xfunlock(lockid);
@@ -75,6 +78,8 @@ mountlist_add(char *host, const char *path)
        xe.r_path [sizeof (xe.r_path) - 1] = '\0';
        xe.r_count = 1;
        if (setrmtabent("a")) {
+               /* PRC: do the HA callout: */
+               ha_callout("mount", xe.r_client, xe.r_path, xe.r_count);
                putrmtabent(&xe, NULL);
                endrmtabent();
        }
@@ -103,8 +108,11 @@ mountlist_del(char *hname, const char *path)
        while ((rep = getrmtabent(1, NULL)) != NULL) {
                match = !strcmp (rep->r_client, hname)
                        && !strcmp(rep->r_path, path);
-               if (match)
+               if (match) {
                        rep->r_count--;
+                       /* PRC: do the HA callout: */
+                       ha_callout("unmount", rep->r_client, rep->r_path, rep->r_count);
+               }
                if (!match || rep->r_count)
                        fputrmtabent(fp, rep, NULL);
        }
index 8c1bb50ef98a076aadb00ecc3dbf2f66882e3a28..88b33db0ab478ac22a4bd33384a4cb204a244665 100644 (file)
@@ -19,6 +19,7 @@
 #include "misc.h"
 #include "statd.h"
 #include "notlist.h"
+#include "ha-callout.h"
 
 notify_list *          rtnl = NULL;    /* Run-time notify list. */
 
@@ -177,6 +178,8 @@ sm_mon_1_svc(struct mon *argp, struct svc_req *rqstp)
                goto failure;
        }
        free(path);
+       /* PRC: do the HA callout: */
+       ha_callout("add-client", mon_name, my_name, -1);
        nlist_insert(&rtnl, clnt);
        close(fd);
 
@@ -207,9 +210,27 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
        char            *mon_name = argp->mon_name,
                        *my_name  = argp->my_id.my_name;
        struct my_id    *id = &argp->my_id;
+#ifdef RESTRICTED_STATD
+       struct in_addr  caller;
+#endif
 
        result.state = MY_STATE;
 
+#ifdef RESTRICTED_STATD
+       /* 1.   Reject anyone not calling from 127.0.0.1.
+        *      Ignore the my_name specified by the caller, and
+        *      use "127.0.0.1" instead.
+        */
+       caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+       if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
+               note(N_WARNING,
+                       "Call to statd from non-local host %s",
+                       inet_ntoa(caller));
+               goto failure;
+       }
+       my_name = "127.0.0.1";
+#endif
+
        /* Check if we're monitoring anyone. */
        if (!(clnt = rtnl)) {
                note(N_WARNING,
@@ -232,6 +253,10 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
                        /* Match! */
                        dprintf(N_DEBUG, "UNMONITORING %s for %s",
                                        mon_name, my_name);
+
+                       /* PRC: do the HA callout: */
+                       ha_callout("del-client", mon_name, my_name, -1);
+
                        nlist_free(&rtnl, clnt);
                        xunlink(SM_DIR, mon_name, 1);
 
@@ -240,6 +265,7 @@ sm_unmon_1_svc(struct mon_id *argp, struct svc_req *rqstp)
                        clnt = NL_NEXT(clnt);
        }
 
+ failure:
        note(N_WARNING, "Received erroneous SM_UNMON request from %s for %s",
                my_name, mon_name);
        return (&result);
@@ -252,16 +278,33 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
        short int       count = 0;
        static sm_stat  result;
        notify_list     *clnt;
+       char            *my_name = argp->my_name;
+#ifdef RESTRICTED_STATD
+       struct in_addr  caller;
+
+       /* 1.   Reject anyone not calling from 127.0.0.1.
+        *      Ignore the my_name specified by the caller, and
+        *      use "127.0.0.1" instead.
+        */
+       caller = svc_getcaller(rqstp->rq_xprt)->sin_addr;
+       if (caller.s_addr != htonl(INADDR_LOOPBACK)) {
+               note(N_WARNING,
+                       "Call to statd from non-local host %s",
+                       inet_ntoa(caller));
+               goto failure;
+       }
+       my_name = "127.0.0.1";
+#endif
 
        result.state = MY_STATE;
 
        if (!(clnt = rtnl)) {
                note(N_WARNING, "Received SM_UNMON_ALL request from %s "
-                       "while not monitoring any hosts", argp->my_name);
+                       "while not monitoring any hosts", my_name);
                return (&result);
        }
 
-       while ((clnt = nlist_gethost(clnt, argp->my_name, 1))) {
+       while ((clnt = nlist_gethost(clnt, my_name, 1))) {
                if (NL_MY_PROC(clnt) == argp->my_proc &&
                        NL_MY_PROG(clnt) == argp->my_prog &&
                        NL_MY_VERS(clnt) == argp->my_vers) {
@@ -276,6 +319,8 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
                                sizeof (mon_name) - 1);
                        mon_name[sizeof (mon_name) - 1] = '\0';
                        temp = NL_NEXT(clnt);
+                       /* PRC: do the HA callout: */
+                       ha_callout("del-client", mon_name, my_name, -1);
                        nlist_free(&rtnl, clnt);
                        xunlink(SM_DIR, mon_name, 1);
                        ++count;
@@ -286,8 +331,8 @@ sm_unmon_all_1_svc(struct my_id *argp, struct svc_req *rqstp)
 
        if (!count) {
                dprintf(N_DEBUG, "SM_UNMON_ALL request from %s with no "
-                       "SM_MON requests from it.", argp->my_name);
+                       "SM_MON requests from it.", my_name);
        }
-
+ failure:
        return (&result);
 }
index 29972545d7389b9ac7ca54defee529c4cfb18b43..474bbb4242b3a254ddb5af426abb53b130b9356c 100644 (file)
@@ -38,6 +38,7 @@
 #include "statd.h"
 #include "notlist.h"
 #include "log.h"
+#include "ha-callout.h"
 
 #define MAXMSGSIZE     (2048 / sizeof(unsigned int))
 
@@ -64,12 +65,29 @@ statd_get_socket(int port)
 
        memset(&sin, 0, sizeof(sin));
        sin.sin_family = AF_INET;
-       sin.sin_port = port;
+       sin.sin_addr.s_addr = INADDR_ANY;
+       /*
+        * If a local hostname is given (-n option to statd), bind to the address
+        * specified. This is required to support clients that ignore the mon_name in
+        * the statd protocol but use the source address from the request packet.
+        */
+       if (MY_NAME) {
+               struct hostent *hp = gethostbyname(MY_NAME);
+               if (hp)
+                       sin.sin_addr = *(struct in_addr *) hp->h_addr;
+       }
+       if (port != 0) {
+               sin.sin_port = htons(port);
+               if (bind(sockfd, &sin, sizeof(sin)) == 0)
+                       goto out_success;
+               note(N_CRIT, "statd: failed to bind to outgoing port, %d\n"
+                               "       falling back on randomly chosen port\n", port);
+       }
        if (bindresvport(sockfd, &sin) < 0) {
                dprintf(N_WARNING,
                        "process_hosts: can't bind to reserved port\n");
        }
-
+out_success:
        return sockfd;
 }
 
@@ -414,6 +432,8 @@ process_notify_list(void)
                        note(N_ERROR,
                                "Can't notify %s, giving up.",
                                        NL_MON_NAME(entry));
+                       /* PRC: do the HA callout */
+                       ha_callout("del-client", NL_MON_NAME(entry), NL_MY_NAME(entry), -1);
                        xunlink(SM_BAK_DIR, NL_MON_NAME(entry), 0);
                        nlist_free(&notify, entry);
                }
index cf30fe46d0a17c3da481346b85f3955dd1165d9f..48362c0104d332c4f4aa7db4f131b07794d48dc6 100644 (file)
@@ -48,6 +48,11 @@ int  run_mode = 0;           /* foreground logging mode */
 char *name_p = NULL;
 char *version_p = NULL;
 
+/* PRC: a high-availability callout program can be specified with -H
+ * When this is done, the program will receive callouts whenever clients
+ * are added or deleted to the notify list */
+char *ha_callout_prog = NULL;
+
 static struct option longopts[] =
 {
        { "foreground", 0, 0, 'F' },
@@ -59,6 +64,7 @@ static struct option longopts[] =
        { "name", 1, 0, 'n' },
        { "state-directory-path", 1, 0, 'P' },
        { "notify-mode", 0, 0, 'N' },
+       { "ha-callout", 1, 0, 'H' },
        { NULL, 0, 0, 0 }
 };
 
@@ -102,6 +108,14 @@ killer (int sig)
        exit (0);
 }
 
+static void
+sigusr (int sig)
+{
+       dprintf (N_DEBUG, "Caught signal %d, re-notifying (state %d).", sig,
+                                                               MY_STATE);
+       re_notify = 1;
+}
+
 /*
  * Startup information.
  */
@@ -148,6 +162,7 @@ usage()
        fprintf(stderr,"      -n, --name           Specify a local hostname.\n");
        fprintf(stderr,"      -P                   State directory path.\n");
        fprintf(stderr,"      -N                   Run in notify only mode.\n");
+       fprintf(stderr,"      -H                   Specify a high-availability callout program.\n");
 }
 
 static const char *pidfile = "/var/run/rpc.statd.pid";
@@ -236,7 +251,7 @@ int main (int argc, char **argv)
        MY_NAME = NULL;
 
        /* Process command line switches */
-       while ((arg = getopt_long(argc, argv, "h?vVFNdn:p:o:P:", longopts, NULL)) != EOF) {
+       while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:", longopts, NULL)) != EOF) {
                switch (arg) {
                case 'V':       /* Version */
                case 'v':
@@ -302,6 +317,13 @@ int main (int argc, char **argv)
                                sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
                        }
                        break;
+               case 'H': /* PRC: specify the ha-callout program */
+                       if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
+                               fprintf(stderr, "%s: xstrdup(%s) failed!\n",
+                                       argv[0], optarg);
+                               exit(1);
+                       }
+                       break;
                case '?':       /* heeeeeelllllllpppp? heh */
                case 'h':
                        usage();
@@ -397,6 +419,8 @@ int main (int argc, char **argv)
        signal (SIGHUP, killer);
        signal (SIGINT, killer);
        signal (SIGTERM, killer);
+       /* PRC: trap SIGUSR1 to re-read notify list from disk */
+       signal(SIGUSR1, sigusr);
        /* WARNING: the following works on Linux and SysV, but not BSD! */
        signal(SIGCHLD, SIG_IGN);
        /*
index ef90bdd48380488afc844e3089cdb4a849da7952..e7829722257d75800517bec1b1d1d565a6d93e1e 100644 (file)
@@ -85,3 +85,5 @@ extern int run_mode;
  */
 extern char *name_p;           /* program basename */
 extern char *version_p;                /* program version */
+
+extern int             re_notify; /* time to re-read notify list */
index f35b6c9c015d8a99233e1144d9a2d80b21372970..a22591538cd77d818b611624ed6de15bcac82e38 100644 (file)
@@ -4,11 +4,12 @@
 .\" Copyright (C) 1999 Olaf Kirch <okir@monad.swb.de>
 .\" Modified by Jeffrey A. Uphoff, 1999, 2002.
 .\" Modified by Lon Hohberger, 2000.
-.TH rpc.statd 8 "16 Sep 2002"
+.\" Modified by Paul Clements, 2004.
+.TH rpc.statd 8 "31 Aug 2004"
 .SH NAME
 rpc.statd \- NSM status monitor
 .SH SYNOPSIS
-.B "/sbin/rpc.statd [-F] [-d] [-?] [-n " name "] [-o " port "] [-p " port "] [-V]"
+.B "/sbin/rpc.statd [-F] [-d] [-?] [-n " name "] [-o " port "] [-p " port "] [-H " prog "] [-V]"
 .SH DESCRIPTION
 The
 .B rpc.statd
@@ -101,6 +102,19 @@ statd program will check its state directory, send notifications to any
 monitored nodes, and exit once the notifications have been sent. This mode is
 used to enable Highly Available NFS implementations (i.e. HA-NFS).
 .TP
+.BI "\-H, " "" " \-\-ha-callout " prog
+Specify a high availability callout program, which will receive callouts
+for all client monitor and unmonitor requests. This allows
+.B rpc.statd
+to be used in a High Availability NFS (HA-NFS) environment. The
+program will be run with 3 arguments:  The first is either
+.B add-client
+or
+.B del-client
+depending on the reason for the callout.
+The second will be the name of the client.
+The third will be the name of the server as known to the client.
+.TP
 .B -?
 Causes
 .B rpc.statd
@@ -135,6 +149,15 @@ and
 .BR hosts_access (5)
 manual pages.
 
+.SH SIGNALS
+.BR SIGUSR1
+causes
+.B rpc.statd
+to re-read the notify list from disk
+and send notifications to clients. This can be used in High Availability NFS
+(HA-NFS) environments to notify clients to reacquire file locks upon takeover
+of an NFS export from another server.
+
 .SH FILES
 .BR /var/lib/nfs/state
 .br
@@ -153,3 +176,5 @@ Olaf Kirch <okir@monad.swb.de>
 H.J. Lu <hjl@gnu.org>
 .br
 Lon Hohberger <hohberger@missioncriticallinux.com>
+.br
+Paul Clements <paul.clements@steeleye.com>
index 393a2fd84803ff5ef57ceffa613f767b1d8cecbd..f6bcbb906df907cd847cbe57d5a042d008c89abe 100644 (file)
@@ -60,6 +60,7 @@ static int    svc_stop = 0;
  * requests are put.
  */
 notify_list *  notify = NULL;
+int    re_notify = 0;
 
 /*
  * Jump-off function.
@@ -86,6 +87,13 @@ my_svc_run(void)
        for (;;) {
                if (svc_stop)
                        return;
+               if (re_notify) {
+                       change_state();
+                       dprintf(N_DEBUG, "Notifying...(new state %d)",
+                                                               MY_STATE);
+                       notify_hosts();
+                       re_notify = 0;
+               }
 
                /* Ah, there are some notifications to be processed */
                while (notify && NL_WHEN(notify) <= time(&now)) {
@@ -102,7 +110,9 @@ my_svc_run(void)
                                                        tv.tv_sec);
                        selret = select(FD_SETSIZE, &readfds,
                                (void *) 0, (void *) 0, &tv);
-               } else {
+               } else if (run_mode & MODE_NOTIFY_ONLY)
+                       return;
+               else {
                        dprintf(N_DEBUG, "Waiting for client connections.");
                        selret = select(FD_SETSIZE, &readfds,
                                (void *) 0, (void *) 0, (struct timeval *) 0);
diff --git a/utils/svcgssd/Makefile b/utils/svcgssd/Makefile
new file mode 100644 (file)
index 0000000..a864de0
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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) -lnfsidmap
+MAN8   = svcgssd
+
+LINKED = err_util.c gss_util.c gss_oids.c context.c context_heimdal.c
+
+predep :: $(LINKED)
+
+$(LINKED) :
+       ln -s ../gssd/$@ .
+
+distclean ::
+       for f in $(LINKED); do \
+           if [ -L "$$f" ]; then \
+               echo "rm -f $$f"; \
+               rm -f "$$f"; \
+           fi; \
+       done
+
+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..8faddc1
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+  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 <nfsidmap.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;
+       int     cr_ngroups;
+       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;
+       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);
+       qword_printint(f, cred->cr_ngroups);
+       for (i=0; i < cred->cr_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
+
+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;
+       uid_t           uid, gid;
+       gss_OID         name_type;
+       char            *secname;
+
+       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);
+
+       res = -EINVAL;
+       if ((secname = mech2file(mech)) == NULL)
+               goto out_free;
+       nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
+       res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid);
+       if (res < 0)
+               goto out_free;
+       cred->cr_uid = uid;
+       cred->cr_gid = gid;
+       /*XXX: want add_supplementary_groups(secname, sname, cred)? */
+       cred->cr_ngroups = 0;
+       res = 0;
+out_free:
+       free(sname);
+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;
+}