diff -Naur --exclude=autom4te.cache openssh-3.4p1/Makefile.in openssh-3.4p1-gsi/Makefile.in
--- openssh-3.4p1/Makefile.in	Tue Jun 25 18:45:42 2002
+++ openssh-3.4p1-gsi/Makefile.in	Mon Sep 30 12:13:26 2002
@@ -55,16 +55,17 @@
 
 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+INSTALL_GSISSH=@INSTALL_GSISSH@
 
 @NO_SFTP@SFTP_PROGS=sftp-server$(EXEEXT) sftp$(EXEEXT)
 
 TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} $(SFTP_PROGS)
 
-LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o
+LIBSSH_OBJS=atomicio.o authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dh.o dispatch.o fatal.o mac.o msg.o hostfile.o key.o kex.o kexdh.o kexgex.o log.o match.o misc.o mpaux.o nchan.o packet.o radix.o rijndael.o entropy.o readpass.o rsa.o scard.o scard-opensc.o ssh-dss.o ssh-rsa.o tildexpand.o ttymodes.o uidswap.o uuencode.o xmalloc.o monitor_wrap.o monitor_fdpass.o kexgss.o gss-genr.o
 
 SSHOBJS= ssh.o sshconnect.o sshconnect1.o sshconnect2.o sshtty.o readconf.o clientloop.o
 
-SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth2-hostbased.o auth2-kbdint.o auth2-none.o auth2-passwd.o auth2-pubkey.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-krb5.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o monitor_mm.o monitor.o
+SSHDOBJS= sshd.o auth.o auth1.o auth2.o auth2-hostbased.o auth2-kbdint.o auth2-none.o auth2-passwd.o auth2-pubkey.o auth-chall.o auth2-chall.o auth-rhosts.o auth-options.o auth-krb4.o auth-krb5.o auth-pam.o auth2-pam.o auth-passwd.o auth-rsa.o auth-rh-rsa.o auth-sia.o sshpty.o sshlogin.o loginrec.o servconf.o serverloop.o md5crypt.o session.o groupaccess.o auth-skey.o auth-bsdauth.o monitor_mm.o monitor.o auth2-gss.o gss-serv.o
 
 MANPAGES	= scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
 MANPAGES_IN	= scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
@@ -251,6 +252,16 @@
 	ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
 	ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+	if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+		rm -f $(DESTDIR)$(bindir)/gsissh; \
+		ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/gsissh; \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+		ln -s ssh.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+		rm -f $(DESTDIR)$(bindir)/gsiscp; \
+		ln -s scp$(EXEEXT) $(DESTDIR)$(bindir)/gsiscp; \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+		ln -s scp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+	fi
 	if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
 		$(srcdir)/mkinstalldirs $(DESTDIR)$(sysconfdir); \
 	fi
@@ -321,6 +332,10 @@
 
 uninstall: 
 	-rm -f $(DESTDIR)$(bindir)/slogin
+	if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+		rm -f $(DESTDIR)$(bindir)/gsiscp; \
+		rm -f $(DESTDIR)$(bindir)/gsissh; \
+	fi
 	-rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
 	-rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
 	-rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
@@ -334,6 +349,10 @@
 	-rm -f $(DESTDIR)$(RAND_HELPER)$(EXEEXT)
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+	if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsissh.1; \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsiscp.1; \
+	fi
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-agent.1
 	-rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
diff -Naur --exclude=autom4te.cache openssh-3.4p1/acconfig.h openssh-3.4p1-gsi/acconfig.h
--- openssh-3.4p1/acconfig.h	Tue Jun 25 17:35:16 2002
+++ openssh-3.4p1-gsi/acconfig.h	Mon Sep 30 12:13:26 2002
@@ -198,6 +198,12 @@
 /* Define if compiler implements __func__ */
 #undef HAVE___func__
 
+/* Define this if you're building with GSSAPI MechGlue */
+#undef MECHGLUE
+
+/* Define this is you want GSSAPI support in the version 2 protocol */
+#undef GSSAPI
+
 /* Define if you want Kerberos 5 support */
 #undef KRB5
 
@@ -210,6 +216,9 @@
 /* Define if you want AFS support */
 #undef AFS
 
+/* Define if you want GSI/Globus authentication support */
+#undef GSI
+
 /* Define if you want S/Key support */
 #undef SKEY
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth-pam.c openssh-3.4p1-gsi/auth-pam.c
--- openssh-3.4p1/auth-pam.c	Tue May  7 21:27:56 2002
+++ openssh-3.4p1-gsi/auth-pam.c	Mon Sep 30 12:13:26 2002
@@ -402,6 +402,26 @@
 #endif /* HAVE_PAM_GETENVLIST */
 }
 
+/* Set a PAM environment string. We need to do this so that the session
+ * modules can handle things like Kerberos/GSI credentials that appear
+ * during the ssh authentication process.
+ */
+
+int do_pam_putenv(char *name, char *value) {
+	char *compound;
+	int ret=1;
+
+#ifdef HAVE_PAM_PUTENV	
+	compound=xmalloc(strlen(name)+strlen(value)+2);
+	if (compound) {
+		sprintf(compound,"%s=%s",name,value);
+		ret=pam_putenv(__pamh,compound);
+		xfree(compound);
+	}
+#endif
+	return(ret);
+}
+
 /* Print any messages that have been generated during authentication */
 /* or account checking to stderr */
 void print_pam_messages(void)
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth-pam.h openssh-3.4p1-gsi/auth-pam.h
--- openssh-3.4p1/auth-pam.h	Thu Apr  4 13:02:28 2002
+++ openssh-3.4p1-gsi/auth-pam.h	Mon Sep 30 12:13:26 2002
@@ -17,6 +17,7 @@
 int is_pam_password_change_required(void);
 void do_pam_chauthtok(void);
 void do_pam_set_conv(struct pam_conv *);
+int do_pam_putenv(char *, char *);
 void message_cat(char **p, const char *a);
 
 #endif /* USE_PAM */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth.c openssh-3.4p1-gsi/auth.c
--- openssh-3.4p1/auth.c	Wed May 22 00:06:28 2002
+++ openssh-3.4p1-gsi/auth.c	Mon Sep 30 12:13:26 2002
@@ -252,7 +252,7 @@
 	    authmsg,
 	    method,
 	    authctxt->valid ? "" : "illegal user ",
-	    authctxt->user,
+	    (authctxt->user[0]) ? authctxt->user : "<implicit>",
 	    get_remote_ipaddr(),
 	    get_remote_port(),
 	    info);
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth.h openssh-3.4p1-gsi/auth.h
--- openssh-3.4p1/auth.h	Thu Jun  6 15:52:37 2002
+++ openssh-3.4p1-gsi/auth.h	Mon Sep 30 12:13:26 2002
@@ -70,6 +70,7 @@
 	krb5_principal	 krb5_user;
 	char		*krb5_ticket_file;
 #endif
+	void *methoddata;
 };
 
 struct Authmethod {
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth1.c openssh-3.4p1-gsi/auth1.c
--- openssh-3.4p1/auth1.c	Fri Jun 21 01:21:11 2002
+++ openssh-3.4p1-gsi/auth1.c	Mon Sep 30 12:13:26 2002
@@ -15,6 +15,7 @@
 #include "xmalloc.h"
 #include "rsa.h"
 #include "ssh1.h"
+#include "dispatch.h"
 #include "packet.h"
 #include "buffer.h"
 #include "mpaux.h"
@@ -29,6 +30,128 @@
 
 /* import */
 extern ServerOptions options;
+extern Authmethod method_gssapi;
+
+
+
+#ifdef GSSAPI
+#ifdef GSI
+#include "globus_gss_assist.h"
+#endif
+
+int     userauth_gssapi(Authctxt *authctxt);
+
+void
+auth1_gss_protocol_error(int type, u_int32_t plen, void *ctxt)
+{
+  Authctxt *authctxt = ctxt;
+  /* Other side told us to abort, dont need to tell him */ 
+  /* maybe we can us some other method. */
+  if (type == SSH_MSG_AUTH_GSSAPI_ABORT) {
+      log("auth1: GSSAPI aborting");
+      dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+      authctxt->success = 1; /* get out of loop*/
+      return;
+  }
+
+  log("auth1: protocol error: type %d plen %d", type, plen);
+  packet_disconnect("Protocol error during GSSAPI authentication: "
+          "Unknown packet type %d", type);
+}
+
+#ifdef GSI
+int
+gsi_gridmap(char *subject_name, char **mapped_name)
+{
+    return(globus_gss_assist_gridmap(subject_name, mapped_name) == 0);
+}
+#endif
+
+/*
+ * SSH1 GSSAPI clients may send us a user name of the form:
+ *
+ *   (1) username:x:SSL Subject Name
+ *     or
+ *   (2) username:i:SSL Subject Name
+ *     or
+ *   (3) username
+ *
+ *  if case 1, then uname is an explicit name (ssh -l uname). Keep this
+ *  name always, rewrite the user parameter to be just uname. We'll pull
+ *  the GSSAPI idenity out and deal with (or skip it) later.
+ *  
+ *  if case 2, then uname is implicit (user didn't use the -l option), so
+ *  use the default gridmap mapping and replace uname with whatever
+ *  the gridmap maps to. If the gridmap mapping fails, drop down
+ *  to just uname
+ *  
+ *  if case 3, then leave it be.
+ *
+ *  This function may return the original pointer to the orginal string,
+ *  the original pointer to a modified string, or a completely new pointer.
+ */
+static char *
+ssh1_gssapi_parse_userstring(char *userstring)
+{
+  char name_type = '\0';	/* explicit 'x' or implicit 'i' */
+  char *ssl_subject_name = NULL;
+  char *delim = NULL;
+
+  debug("Looking at username '%s' for gssapi-ssleay type name", userstring);
+  if((delim = strchr(userstring, ':')) != NULL) {
+      /* Parse and split into components */
+      ssl_subject_name = strchr(delim + 1, ':');
+
+      if (ssl_subject_name) {
+	/* Successful parse, split into components */
+	*delim = '\0';
+	name_type = *(delim + 1);
+	*ssl_subject_name = '\0';
+	ssl_subject_name++;
+
+	debug("Name parsed. type = '%c'. ssl subject name is \"%s\"",
+	      name_type, ssl_subject_name);
+
+      } else {
+
+	debug("Don't understand name format. Letting it pass.");
+      }	
+  }	
+
+#ifdef GSI
+  if(ssl_subject_name) {
+    char *gridmapped_name = NULL;
+    switch (name_type) {
+    case 'x':
+      debug("explicit name given, using %s as username", userstring);
+      break;
+
+    case 'i':
+      /* gridmap check */
+      debug("implicit name given. gridmapping '%s'", ssl_subject_name);
+
+      PRIVSEP(gsi_gridmap(ssl_subject_name, &gridmapped_name));
+      if (gridmapped_name && gridmapped_name[0] != '\0') {
+	userstring = gridmapped_name;
+	debug("I gridmapped and got %s", userstring);
+
+      } else {
+	debug("I gridmapped and got null, reverting to %s", userstring);
+      }
+      break;
+
+    default:
+      debug("Unknown name type '%c'. Ignoring.", name_type);
+      break;
+    }
+  } else {
+    debug("didn't find any :'s so I assume it's just a user name");
+  }
+#endif /* GSI */
+
+  return userstring;
+}
+#endif
 
 /*
  * convert ssh auth msg type into description
@@ -53,6 +176,10 @@
 	case SSH_CMSG_AUTH_KERBEROS:
 		return "kerberos";
 #endif
+#if defined(GSSAPI)
+	case SSH_CMSG_AUTH_GSSAPI:
+	    	return "gssapi";
+#endif
 	}
 	snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
 	return buf;
@@ -150,6 +277,39 @@
 			break;
 #endif /* KRB4 || KRB5 */
 
+#ifdef GSSAPI
+		case SSH_CMSG_AUTH_GSSAPI:
+			if (!options.gss_authentication) {
+				verbose("GSSAPI authentication disabled.");
+				break;
+			}
+			/*
+			* GSSAPI was first added to ssh1 in ssh-1.2.27, and
+			* was added to the SecurtCRT product. In order
+			* to continue operating with these, we will add
+			* the equivelent GSSAPI support to SSH1. 
+			* Will use the gssapi routines from the ssh2 as
+			* they are almost identical. But they use dispatch
+			* so we need to setup the dispatch tables here 
+			* auth1.c for use only by the gssapi code. 
+			* Since we already have the packet, we will call
+			* userauth_gssapi then start the dispatch loop.
+			*/
+			if (!authctxt->valid) {
+			packet_disconnect("Authentication rejected for invalid user");
+			}
+			dispatch_init(&auth1_gss_protocol_error);
+			method_gssapi.userauth(authctxt);
+			dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
+			if (authctxt->postponed) { /* failed, try other methods */
+				authctxt->success = 0;
+				authctxt->postponed = 0;
+				break;
+			}
+			authenticated = 1;
+			break;
+#endif /* GSSAPI */
+			
 #if defined(AFS) || defined(KRB5)
 			/* XXX - punt on backward compatibility here. */
 		case SSH_CMSG_HAVE_KERBEROS_TGT:
@@ -356,6 +516,11 @@
 	user = packet_get_string(&ulen);
 	packet_check_eom();
 
+#ifdef GSSAPI
+	/* Parse GSSAPI identity from userstring */
+	user = ssh1_gssapi_parse_userstring(user);
+#endif /* GSSAPI */
+
 	if ((style = strchr(user, ':')) != NULL)
 		*style++ = '\0';
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth2-gss.c openssh-3.4p1-gsi/auth2-gss.c
--- openssh-3.4p1/auth2-gss.c	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/auth2-gss.c	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2001,2002 Simon Wilkinson. 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 "includes.h"
+
+#ifdef GSSAPI
+#include "auth.h"
+#include "ssh2.h"
+#include "ssh1.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "dispatch.h"
+#include "servconf.h"
+#include "compat.h"
+#include "packet.h"
+#include "monitor_wrap.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+extern unsigned char ssh1_key_digest[16];
+
+static int
+userauth_external(Authctxt *authctxt)
+{
+        packet_check_eom();
+
+        return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
+}
+
+static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+
+/* We only support those mechanisms that we know about (ie ones that we know
+ * how to check local user kuserok and the like
+ */
+static int
+userauth_gssapi(Authctxt *authctxt)
+{
+        gss_OID_desc    oid= {0,NULL};
+        Gssctxt         *ctxt = NULL;
+        int             mechs;
+        gss_OID_set     supported;
+        int             present;
+        OM_uint32       ms;
+        u_int           len;
+        
+        if (!authctxt->valid || authctxt->user == NULL)
+                return 0;
+                
+        if (datafellows & SSH_OLD_GSSAPI) {
+                debug("Early drafts of GSSAPI userauth not supported");
+                return 0;
+        }
+        
+        mechs=packet_get_int();
+        if (mechs==0) {
+                debug("Mechanism negotiation is not supported");
+                return 0;
+        }
+
+        ssh_gssapi_supported_oids(&supported);
+        do {
+                if (oid.elements)
+                        xfree(oid.elements);
+                oid.elements = packet_get_string(&len);
+                oid.length = len;
+                gss_test_oid_set_member(&ms, &oid, supported, &present);
+                mechs--;
+        } while (mechs>0 && !present);
+        
+        if (!present) {
+                xfree(oid.elements);
+                return(0);
+        }
+                
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid))))
+		return(0);
+	
+        authctxt->methoddata=(void *)ctxt;
+
+        /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
+
+	if (!compat20)
+        packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
+	else
+	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
+        packet_put_string(oid.elements,oid.length);
+        packet_send();
+        packet_write_wait();
+        xfree(oid.elements);
+
+ 	if (!compat20)
+ 	dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
+ 				&input_gssapi_token);
+ 	else
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
+		     &input_gssapi_token);
+        authctxt->postponed = 1;
+        
+        return 0;
+}
+
+static void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+        Authctxt *authctxt = ctxt;
+        Gssctxt *gssctxt;
+        gss_buffer_desc send_tok,recv_tok;
+        OM_uint32 maj_status, min_status;
+	int len;
+        
+        if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+                fatal("No authentication or GSSAPI context");
+                
+        gssctxt=authctxt->methoddata;
+        recv_tok.value=packet_get_string(&len);
+	recv_tok.length=len; /* int vs. size_t */
+        
+        maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
+        					 &send_tok, NULL));
+        packet_check_eom();
+        
+        if (send_tok.length != 0) {
+                /* Send a packet back to the client */
+		if (!compat20)
+		packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+		else
+	        packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+                packet_put_string(send_tok.value,send_tok.length);
+                packet_send();
+                packet_write_wait();
+                gss_release_buffer(&min_status, &send_tok);        
+        }
+        
+        if (GSS_ERROR(maj_status)) {
+                /* Failure <sniff> */
+		ssh_gssapi_send_error(gssctxt->oid,maj_status,min_status);
+                authctxt->postponed = 0;
+		dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+                dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+                userauth_finish(authctxt, 0, "gssapi");
+        }
+                        
+        if (maj_status == GSS_S_COMPLETE) {
+		dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
+                dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+		/* ssh1 does not have an extra message here */
+		if (!compat20)
+		input_gssapi_exchange_complete(0, 0, ctxt);
+		else
+  		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+  			     &input_gssapi_exchange_complete);
+        }
+}
+
+/* This is called when the client thinks we've completed authentication.
+ * It should only be enabled in the dispatch handler by the function above,
+ * which only enables it once the GSSAPI exchange is complete.
+ */
+ 
+static void
+input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+{
+        Authctxt *authctxt = ctxt;
+        Gssctxt *gssctxt;
+        int authenticated;
+        
+	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+                fatal("No authentication or GSSAPI context");
+                
+	if ((strcmp(authctxt->user, "") == 0) && (authctxt->pw == NULL)) {
+	    char *lname = NULL;
+	    PRIVSEP(ssh_gssapi_localname(&lname));
+	    if (lname && lname[0] != '\0') {
+		xfree(authctxt->user);
+		authctxt->user = lname;
+		debug("set username to %s from gssapi context", lname);
+		authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
+	    } else {
+		debug("failed to set username from gssapi context");
+	    }
+	}
+	if (authctxt->pw) {
+#ifdef USE_PAM
+	    PRIVSEP(start_pam(authctxt->pw->pw_name));
+#endif
+	} else {
+	    authctxt->valid = 0;
+	    authenticated = 0;
+	    goto finish;
+	}
+
+        gssctxt=authctxt->methoddata;
+
+	/* ssh1 needs to exchange the hash of the keys */
+	if (!compat20) {
+
+		OM_uint32 min_status;
+		gss_buffer_desc dummy, msg_tok;
+
+		/* ssh1 wraps the keys, in the monitor */
+
+		dummy.value=malloc(sizeof(ssh1_key_digest));
+		memcpy(dummy.value,ssh1_key_digest,sizeof(ssh1_key_digest));
+		dummy.length=sizeof(ssh1_key_digest);
+		if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(gssctxt,&dummy,&msg_tok))))
+		    fatal("Couldn't wrap keys");
+ 
+		packet_start(SSH_SMSG_AUTH_GSSAPI_HASH);
+		packet_put_string((char *)msg_tok.value,msg_tok.length);
+		packet_send();
+		packet_write_wait();
+		gss_release_buffer(&min_status,&msg_tok);
+	}
+
+  
+	/* We don't need to check the status, because the stored credentials
+	 * which userok uses are only populated once the context init step
+	 * has returned complete.
+	 */
+
+        authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+
+finish:
+        authctxt->postponed = 0;
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+        userauth_finish(authctxt, authenticated, "gssapi");
+}
+
+Authmethod method_external = {
+	"external-keyx",
+	userauth_external,
+	&options.gss_authentication
+};
+	
+Authmethod method_gssapi = {
+        "gssapi",
+        userauth_gssapi,
+        &options.gss_authentication
+};
+
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/auth2.c openssh-3.4p1-gsi/auth2.c
--- openssh-3.4p1/auth2.c	Fri Jun 21 01:21:11 2002
+++ openssh-3.4p1-gsi/auth2.c	Mon Sep 30 12:13:26 2002
@@ -26,6 +26,7 @@
 RCSID("$OpenBSD: auth2.c,v 1.93 2002/05/31 11:35:15 markus Exp $");
 
 #include "ssh2.h"
+#include "ssh1.h"
 #include "xmalloc.h"
 #include "packet.h"
 #include "log.h"
@@ -36,6 +37,10 @@
 #include "pathnames.h"
 #include "monitor_wrap.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import */
 extern ServerOptions options;
 extern u_char *session_id2;
@@ -46,6 +51,10 @@
 /* methods */
 
 extern Authmethod method_none;
+#ifdef GSSAPI
+extern Authmethod method_external;
+extern Authmethod method_gssapi;
+#endif
 extern Authmethod method_pubkey;
 extern Authmethod method_passwd;
 extern Authmethod method_kbdint;
@@ -53,6 +62,10 @@
 
 Authmethod *authmethods[] = {
 	&method_none,
+#ifdef GSSAPI
+	&method_external,
+	&method_gssapi,
+#endif
 	&method_pubkey,
 	&method_passwd,
 	&method_kbdint,
@@ -144,14 +157,57 @@
 	user = packet_get_string(NULL);
 	service = packet_get_string(NULL);
 	method = packet_get_string(NULL);
-	debug("userauth-request for user %s service %s method %s", user, service, method);
+
+#ifdef GSSAPI
+	if (strcmp(user, "") == 0) {
+	    debug("received empty username for %s", method);
+	    if (strcmp(method, "external-keyx") == 0) {
+		char *lname = NULL;
+		PRIVSEP(ssh_gssapi_localname(&lname));
+		if (lname && lname[0] != '\0') {
+		    xfree(user);
+		    user = lname;
+		    debug("set username to %s from gssapi context", user);
+		} else if (authctxt->valid) {
+		    debug("failed to set username from gssapi context");
+		}
+	    }
+	}
+#endif
+
+	debug("userauth-request for user %s service %s method %s",
+	      (user && user[0]) ? user : "<implicit>", service, method);
 	debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
 
 	if ((style = strchr(user, ':')) != NULL)
 		*style++ = 0;
 
-	if (authctxt->attempt++ == 0) {
+	authctxt->attempt++;
+	if (!authctxt->user ||
+	    strcmp(user, authctxt->user) != 0) {
 		/* setup auth context */
+		if (authctxt->user) {
+		    xfree(authctxt->user);
+		    authctxt->user = NULL;
+		}
+		if (authctxt->service) {
+		    xfree(authctxt->service);
+		    authctxt->service = NULL;
+		}
+		if (authctxt->style) {
+		    xfree(authctxt->style);
+		    authctxt->style = NULL;
+		}
+#ifdef GSSAPI
+		/* We'll verify the username after we set it from the
+		   GSSAPI context. */
+		if ((strcmp(user, "") == 0) &&
+		    ((strcmp(method, "gssapi") == 0) ||
+		     (strcmp(method, "external-keyx") == 0))) {
+		    authctxt->pw = NULL;
+		    authctxt->valid = 1;
+		} else {
+#endif
 		authctxt->pw = PRIVSEP(getpwnamallow(user));
 		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
 			authctxt->valid = 1;
@@ -160,26 +216,31 @@
 			PRIVSEP(start_pam(authctxt->pw->pw_name));
 #endif
 		} else {
+			authctxt->valid = 0;
 			log("input_userauth_request: illegal user %s", user);
 #ifdef USE_PAM
 			PRIVSEP(start_pam("NOUSER"));
 #endif
 		}
+#ifdef GSSAPI
+		}
+#endif
 		setproctitle("%s%s", authctxt->pw ? user : "unknown",
 		    use_privsep ? " [net]" : "");
 		authctxt->user = xstrdup(user);
 		authctxt->service = xstrdup(service);
 		authctxt->style = style ? xstrdup(style) : NULL;
-		if (use_privsep)
+		if (use_privsep && (authctxt->attempt == 1))
 			mm_inform_authserv(service, style);
-	} else if (strcmp(user, authctxt->user) != 0 ||
-	    strcmp(service, authctxt->service) != 0) {
-		packet_disconnect("Change of username or service not allowed: "
-		    "(%s,%s) -> (%s,%s)",
-		    authctxt->user, authctxt->service, user, service);
 	}
 	/* reset state */
 	auth2_challenge_stop(authctxt);
+
+#ifdef GSSAPI
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+#endif
+
 	authctxt->postponed = 0;
 
 	/* try to authenticate user */
@@ -188,6 +249,7 @@
 		debug2("input_userauth_request: try method %s", method);
 		authenticated =	m->userauth(authctxt);
 	}
+
 	userauth_finish(authctxt, authenticated, method);
 
 	xfree(service);
@@ -216,6 +278,9 @@
 #endif /* USE_PAM */
 
 	/* Log before sending the reply */
+	if (!compat20)
+	auth_log(authctxt, authenticated, method, " ssh1");
+	else
 	auth_log(authctxt, authenticated, method, " ssh2");
 
 	if (authctxt->postponed)
@@ -225,9 +290,11 @@
 	if (authenticated == 1) {
 		/* turn off userauth */
 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
+		if (compat20) {
 		packet_start(SSH2_MSG_USERAUTH_SUCCESS);
 		packet_send();
 		packet_write_wait();
+		}
 		/* now we can break out */
 		authctxt->success = 1;
 	} else {
@@ -240,6 +307,16 @@
 #endif /* WITH_AIXAUTHENTICATE */
 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
 		}
+		if (!compat20) {
+		/*
+		 * Break out of the dispatch loop now and go back to
+	         * SSH1 code.  We need to set the 'success' flag to
+	         * break out of the loop.  Set the 'postponed' flag to
+	         * tell the SSH1 code that authentication failed.  The
+	         * SSH1 code will handle sending SSH_SMSG_FAILURE.
+		*/
+		authctxt->success = authctxt->postponed = 1;
+		} else {
 		methods = authmethods_get();
 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
 		packet_put_cstring(methods);
@@ -247,6 +324,7 @@
 		packet_send();
 		packet_write_wait();
 		xfree(methods);
+		}
 	}
 }
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/canohost.c openssh-3.4p1-gsi/canohost.c
--- openssh-3.4p1/canohost.c	Tue Jun 11 11:47:22 2002
+++ openssh-3.4p1-gsi/canohost.c	Mon Sep 30 12:13:26 2002
@@ -355,3 +355,75 @@
 {
 	return get_port(1);
 }
+
+/* If *host is a name for the loopback interface, try to change
+   it to local hostname (not necessarily fully-qualified). */
+void
+resolve_localhost(char **host)
+{
+    struct hostent *hostinfo;
+
+    hostinfo = gethostbyname(*host);
+    if (hostinfo &&
+	hostinfo->h_addrtype == AF_INET) {
+	struct in_addr addr;
+	addr = *(struct in_addr *)(hostinfo->h_addr);
+	if (ntohl(addr.s_addr) == INADDR_LOOPBACK) {
+	    char buf[MAXHOSTNAMELEN];
+	    if (gethostname(buf, sizeof(buf)) == 0) {
+		xfree(*host);
+		*host = xstrdup(buf);
+	    }
+	}
+    }
+}
+
+/* A (hopefully) portable way to make a fully-qualified hostname for
+   GSSAPI authentication without relying on a potentially remote,
+   untrusted resolver.
+   Note: getdomainname() is not portable.
+*/
+void
+make_fqhn(char **host)
+{
+    char *domainname = NULL, *fqhn = NULL, myhn[MAXHOSTNAMELEN];
+    struct hostent *hent = NULL;
+    int i;
+
+    if (strchr(*host, '.')) {
+	return;			/* already fully qualified */
+    }
+
+    /* Otherwise, figure out our local domainname without using
+       getdomainname(). */
+    if (gethostname(myhn, sizeof(myhn)) < 0) {
+	debug("gethostname() failed, can't convert %s to fqhn", *host);
+	return;
+    }
+    if ((domainname = strchr(myhn, '.')) == NULL) {
+	
+	/* Resolving our local hostname should be secure
+	   (unlike resolving a remote hostname). */
+	if ((hent = gethostbyname(myhn)) != NULL) {
+	    if ((domainname = strchr(hent->h_name, '.')) == NULL) {
+		for (i=0;
+		     hent->h_aliases[i] &&
+			 (domainname =
+			  strchr(hent->h_aliases[i], '.')) == NULL;
+		     i++);
+	    }
+	}
+    }
+
+    if (domainname) {
+	domainname++;
+	fqhn = xmalloc(strlen(*host)+strlen(domainname)+2);
+	sprintf(fqhn, "%s.%s", *host, domainname);
+	xfree(*host);
+	*host = fqhn;
+	return;
+    }
+
+    debug("unable to determine fully-qualified local hostname");
+    return;
+}
diff -Naur --exclude=autom4te.cache openssh-3.4p1/canohost.h openssh-3.4p1-gsi/canohost.h
--- openssh-3.4p1/canohost.h	Tue Jul  3 23:46:57 2001
+++ openssh-3.4p1-gsi/canohost.h	Mon Sep 30 12:13:26 2002
@@ -23,3 +23,6 @@
 
 int		 get_remote_port(void);
 int		 get_local_port(void);
+
+void		 resolve_localhost(char **host);
+void		 make_fqhn(char **host);
diff -Naur --exclude=autom4te.cache openssh-3.4p1/compat.c openssh-3.4p1-gsi/compat.c
--- openssh-3.4p1/compat.c	Wed Apr 10 11:22:10 2002
+++ openssh-3.4p1-gsi/compat.c	Mon Sep 30 12:13:26 2002
@@ -71,15 +71,17 @@
 		{ "OpenSSH_2.5.0p1*,"
 		  "OpenSSH_2.5.1p1*",
 					SSH_BUG_BIGENDIANAES|SSH_OLD_DHGEX|
-					SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+					SSH_BUG_NOREKEY|SSH_BUG_EXTEOF|
+					SSH_OLD_GSSAPI},
 		{ "OpenSSH_2.5.0*,"
 		  "OpenSSH_2.5.1*,"
 		  "OpenSSH_2.5.2*",	SSH_OLD_DHGEX|SSH_BUG_NOREKEY|
 					SSH_BUG_EXTEOF},
 		{ "OpenSSH_2.5.3*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
+		{ "OpenSSH_2.9p*",	SSH_OLD_GSSAPI },
 		{ "OpenSSH_2.*,"
 		  "OpenSSH_3.0*,"
-		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF},
+		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF|SSH_BUG_GSS_EMPTYUSER},
 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
 		{ "OpenSSH*",		0 },
 		{ "*MindTerm*",		0 },
diff -Naur --exclude=autom4te.cache openssh-3.4p1/compat.h openssh-3.4p1-gsi/compat.h
--- openssh-3.4p1/compat.h	Wed Apr 10 11:22:10 2002
+++ openssh-3.4p1-gsi/compat.h	Mon Sep 30 12:13:26 2002
@@ -54,6 +54,8 @@
 #define SSH_BUG_DUMMYCHAN	0x00100000
 #define SSH_BUG_EXTEOF		0x00200000
 #define SSH_BUG_K5USER		0x00400000
+#define SSH_OLD_GSSAPI		0x00800000
+#define SSH_BUG_GSS_EMPTYUSER	0x01000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
diff -Naur --exclude=autom4te.cache openssh-3.4p1/config.h.in openssh-3.4p1-gsi/config.h.in
--- openssh-3.4p1/config.h.in	Wed Jun 26 09:08:19 2002
+++ openssh-3.4p1-gsi/config.h.in	Mon Sep 30 12:13:36 2002
@@ -198,6 +198,12 @@
 /* Define if compiler implements __func__ */
 #undef HAVE___func__
 
+/* Define this if you're building with GSSAPI MechGlue */
+#undef MECHGLUE
+
+/* Define this is you want GSSAPI support in the version 2 protocol */
+#undef GSSAPI
+
 /* Define if you want Kerberos 5 support */
 #undef KRB5
 
@@ -210,6 +216,9 @@
 /* Define if you want AFS support */
 #undef AFS
 
+/* Define if you want GSI/Globus authentication support */
+#undef GSI
+
 /* Define if you want S/Key support */
 #undef SKEY
 
@@ -476,6 +485,9 @@
 /* Define to 1 if you have the <glob.h> header file. */
 #undef HAVE_GLOB_H
 
+/* Define to 1 if you have the <gssapi.h> header file. */
+#undef HAVE_GSSAPI_H
+
 /* Define to 1 if you have the `inet_aton' function. */
 #undef HAVE_INET_ATON
 
@@ -593,6 +605,9 @@
 /* Define to 1 if you have the `pam_getenvlist' function. */
 #undef HAVE_PAM_GETENVLIST
 
+/* Define to 1 if you have the `pam_putenv' function. */
+#undef HAVE_PAM_PUTENV
+
 /* Define to 1 if you have the <paths.h> header file. */
 #undef HAVE_PATHS_H
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/configure openssh-3.4p1-gsi/configure
--- openssh-3.4p1/configure	Wed Jun 26 09:08:18 2002
+++ openssh-3.4p1-gsi/configure	Mon Sep 30 12:13:38 2002
@@ -846,6 +846,10 @@
   --with-libs             Specify additional libraries to link with
   --without-rpath         Disable auto-added -R linker paths
   --with-zlib=PATH        Use zlib in PATH
+  --with-mechglue=PATH    Build with GSSAPI mechglue library
+  --with-gsi=PATH         Enable GSI/Globus authentication support
+  --with-globus=PATH      Enable GSI/Globus authentication support
+  --with-globus-flavor=TYPE         Describe Globus flavor type (ex: gcc32dbg, etc.)
   --with-skey[=PATH]      Enable S/Key support
                             (optionally in PATH)
   --with-tcp-wrappers[=PATH]      Enable tcpwrappers support
@@ -6210,6 +6214,274 @@
 rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
 fi
 
+# Check whether the user wants GSSAPI mechglue support
+
+# Check whether --with-mechglue or --without-mechglue was given.
+if test "${with_mechglue+set}" = set; then
+  withval="$with_mechglue"
+
+		echo "$as_me:$LINENO: checking for mechglue library" >&5
+echo $ECHO_N "checking for mechglue library... $ECHO_C" >&6
+
+		if test -e ${withval}/libgssapi.a ; then
+		    mechglue_lib=${withval}/libgssapi.a
+		elif test -e ${withval}/lib/libgssapi.a ; then
+		    mechglue_lib=${withval}/lib/libgssapi.a
+		else
+		    { { echo "$as_me:$LINENO: error: \"Can't find libgssapi in ${withval}\"" >&5
+echo "$as_me: error: \"Can't find libgssapi in ${withval}\"" >&2;}
+   { (exit 1); exit 1; }; };
+		fi
+		LIBS="$LIBS ${mechglue_lib}"
+		echo "$as_me:$LINENO: result: ${mechglue_lib}" >&5
+echo "${ECHO_T}${mechglue_lib}" >&6
+
+#		if test -e ${withval}/gssapi.h ; then
+#		    CPPFLAGS="$CPPFLAGS -I${withval}"
+#		elif test -e ${withval}/include/gssapi.h ; then
+#		    CPPFLAGS="$CPPFLAGS -I${withval}/include"
+#		else
+#		    AC_MSG_ERROR("Can't find gssapi.h in ${withval}");
+#		fi
+
+
+echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char dlopen ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_dl_dlopen=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBDL 1
+_ACEOF
+
+  LIBS="-ldl $LIBS"
+
+fi
+
+		if test $ac_cv_lib_dl_dlopen = yes; then
+		   LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic"
+		fi
+
+		cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+		cat >>confdefs.h <<\_ACEOF
+#define MECHGLUE 1
+_ACEOF
+
+		GSSAPI="mechglue"
+
+
+
+fi;
+
+
+# Check whether the user wants GSI (Globus) support
+gsi_path="no"
+
+# Check whether --with-gsi or --without-gsi was given.
+if test "${with_gsi+set}" = set; then
+  withval="$with_gsi"
+
+		gsi_path="$withval"
+
+
+fi;
+
+
+# Check whether --with-globus or --without-globus was given.
+if test "${with_globus+set}" = set; then
+  withval="$with_globus"
+
+		gsi_path="$withval"
+
+
+fi;
+
+# Check whether the user has a Globus flavor type
+globus_flavor_type="no"
+
+# Check whether --with-globus-flavor or --without-globus-flavor was given.
+if test "${with_globus_flavor+set}" = set; then
+  withval="$with_globus_flavor"
+
+		globus_flavor_type="$withval"
+
+
+fi;
+
+if test "x$gsi_path" != "xno" ; then
+	# Globus GSSAPI configuration
+	cat >>confdefs.h <<\_ACEOF
+#define GSI 1
+_ACEOF
+
+
+	if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+		{ { echo "$as_me:$LINENO: error: Previously configured GSSAPI library conflicts with Globus/GSI." >&5
+echo "$as_me: error: Previously configured GSSAPI library conflicts with Globus/GSI." >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	if test -z "$GSSAPI"; then
+		cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+		GSSAPI="GSI"
+	fi
+
+	# Find GLOBUS/GSI installation Directory
+	echo "$as_me:$LINENO: checking for Globus/GSI installation directory" >&5
+echo $ECHO_N "checking for Globus/GSI installation directory... $ECHO_C" >&6
+
+	globus_install_dir=$gsi_path
+
+	if test "x$globus_install_dir" = "xyes" ; then
+                { { echo "$as_me:$LINENO: error: Cannot find Globus/GSI installation directory -- a path must be specified!" >&5
+echo "$as_me: error: Cannot find Globus/GSI installation directory -- a path must be specified!" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	echo "$as_me:$LINENO: result: $globus_install_dir" >&5
+echo "${ECHO_T}$globus_install_dir" >&6
+
+	# Find GLOBUS/GSI development directory
+	echo "$as_me:$LINENO: checking for Globus/GSI development directory" >&5
+echo $ECHO_N "checking for Globus/GSI development directory... $ECHO_C" >&6
+
+	if test -d ${globus_install_dir}/lib ; then
+		# Looks like a flat directory structure from configure/make
+		# and not globus-install or gsi-install
+		globus_dev_dir=$globus_install_dir
+
+	else
+		# Assume a true globus installation with architecture
+		# directories and run globus-development-path to find
+		# the development directory
+
+		# Set GLOBUS_INSTALL_PATH
+		GLOBUS_INSTALL_PATH=$globus_install_dir
+		export GLOBUS_INSTALL_PATH
+
+		dev_path_program=${globus_install_dir}/bin/globus-development-path
+
+		if test ! -x ${dev_path_program} ; then
+			{ { echo "$as_me:$LINENO: error: Cannot find Globus/GSI installation directory: program ${dev_path_program} does not exist or is not executable" >&5
+echo "$as_me: error: Cannot find Globus/GSI installation directory: program ${dev_path_program} does not exist or is not executable" >&2;}
+   { (exit 1); exit 1; }; }
+		fi
+
+		globus_dev_dir=`${dev_path_program}`
+
+		if test -z "$globus_dev_dir" -o "X$globus_dev_dir" = "X<not found>" ; then
+			{ { echo "$as_me:$LINENO: error: Cannot find Globus/GSI development directory" >&5
+echo "$as_me: error: Cannot find Globus/GSI development directory" >&2;}
+   { (exit 1); exit 1; }; }
+		fi
+
+		if test ! -d "$globus_dev_dir" ; then
+			{ { echo "$as_me:$LINENO: error: Cannot find Globus/GSI development directory: $globus_dev_dir does not exist" >&5
+echo "$as_me: error: Cannot find Globus/GSI development directory: $globus_dev_dir does not exist" >&2;}
+   { (exit 1); exit 1; }; }
+		fi
+	fi
+	echo "$as_me:$LINENO: result: $globus_dev_dir" >&5
+echo "${ECHO_T}$globus_dev_dir" >&6
+
+	# Find GLOBUS/GSI flavor Directory
+	echo "$as_me:$LINENO: checking for Globus flavor type" >&5
+echo $ECHO_N "checking for Globus flavor type... $ECHO_C" >&6
+
+        if test "x$globus_flavor_type" = "xno" ; then
+		if test "$GSSAPI" = "mechglue"; then
+			GSI_LIBS="-lglobus_gss_assist -lglobus_gaa"
+		else
+			GSI_LIBS="-lglobus_gss_assist -lglobus_gss -lglobus_gaa"
+		fi
+		GSI_LDFLAGS="-L${globus_dev_dir}/lib"
+		GSI_CPPFLAGS="-I${globus_dev_dir}/include"
+		echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6
+	else
+                GLOBUS_FLAVOR_TYPE_INCL_DIR="${globus_dev_dir}/include/${globus_flavor_type}"
+
+		if test ! -d "$GLOBUS_FLAVOR_TYPE_INCL_DIR" ; then
+			{ { echo "$as_me:$LINENO: error: Cannot find Globus flavor-specific include directory: ${GLOBUS_FLAVOR_TYPE_INCL_DIR}" >&5
+echo "$as_me: error: Cannot find Globus flavor-specific include directory: ${GLOBUS_FLAVOR_TYPE_INCL_DIR}" >&2;}
+   { (exit 1); exit 1; }; }
+                fi
+
+		echo "$as_me:$LINENO: result: $globus_flavor_type" >&5
+echo "${ECHO_T}$globus_flavor_type" >&6
+		if test "$GSSAPI" = "mechglue"; then
+			GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a"
+		else
+			GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a ${gsi_path}/lib/libglobus_gssapi_gsi_${globus_flavor_type}.a"
+		fi
+		GSI_CPPFLAGS="-I${GLOBUS_FLAVOR_TYPE_INCL_DIR}"
+	fi
+
+	LIBS="$LIBS $GSI_LIBS"
+	LDFLAGS="$LDFLAGS $GSI_LDFLAGS"
+	CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+	INSTALL_GSISSH="yes"
+else
+	INSTALL_GSISSH=""
+fi
+
+# End Globus/GSI section
+
 # Check whether user wants S/Key support
 SKEY_MSG="no"
 
@@ -8015,6 +8287,82 @@
 done
 
 
+for ac_func in pam_putenv
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.  */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
 			disable_shadow=yes
 			PAM_MSG="yes"
 
@@ -8121,7 +8469,81 @@
 
 
 fi;
-LIBS="$LIBS -lcrypto"
+
+# Patch up SSL libraries for GSI authentication as needed
+if test "x$globus_flavor_type" != "xno" ; then
+	#
+	# For Globus 2, always link with the static libraries
+	#
+
+	libssl_utils="${gsi_path}/lib/libglobus_ssl_utils_${globus_flavor_type}.a"
+
+	#
+	# Trouble arrives at GT 2.1.3+ with the reorg of globus_ssl_utils.  Compensating for
+	# the new library linking required here through file tests to see which libraries to
+	# link against.
+	#
+
+	libgsi_proxy_core="${gsi_path}/lib/libglobus_gsi_proxy_core_${globus_flavor_type}.a"
+	libgsi_credential="${gsi_path}/lib/libglobus_gsi_credential_${globus_flavor_type}.a"
+	libgsi_callback="${gsi_path}/lib/libglobus_gsi_callback_${globus_flavor_type}.a"
+	liboldgaa="${gsi_path}/lib/libglobus_oldgaa_${globus_flavor_type}.a"
+	libgsi_sysconfig="${gsi_path}/lib/libglobus_gsi_sysconfig_${globus_flavor_type}.a"
+	libproxy_ssl="${gsi_path}/lib/libglobus_proxy_ssl_${globus_flavor_type}.a"
+	libgsi_cert_utils="${gsi_path}/lib/libglobus_gsi_cert_utils_${globus_flavor_type}.a"
+	libopenssl_error="${gsi_path}/lib/libglobus_openssl_error_${globus_flavor_type}.a"
+	libopenssl="${gsi_path}/lib/libglobus_openssl_${globus_flavor_type}.a"
+
+	if test -r ${libgsi_proxy_core} \
+	     -a -r ${libgsi_credential} \
+	     -a -r ${libgsi_callback} \
+	     -a -r ${liboldgaa} \
+	     -a -r ${libgsi_sysconfig} \
+	     -a -r ${libproxy_ssl} \
+	     -a -r ${libgsi_cert_utils} \
+	     -a -r ${libopenssl_error} \
+	     -a -r ${libopenssl} ; then
+		LIBS="$LIBS ${libgsi_proxy_core}"
+		LIBS="$LIBS ${libgsi_credential}"
+		LIBS="$LIBS ${libgsi_callback}"
+		LIBS="$LIBS ${liboldgaa}"
+		LIBS="$LIBS ${libgsi_sysconfig}"
+		LIBS="$LIBS ${libproxy_ssl}"
+		LIBS="$LIBS ${libgsi_cert_utils}"
+		LIBS="$LIBS ${libopenssl_error}"
+		LIBS="$LIBS ${libopenssl}"
+	elif test -r ${libssl_utils}; then
+		LIBS="$LIBS ${libssl_utils}"
+	else
+		{ { echo "$as_me:$LINENO: error: All of the required Globus Toolkit libraries are not present/configured correctly" >&5
+echo "$as_me: error: All of the required Globus Toolkit libraries are not present/configured correctly" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+	#
+	# Standard openssl libraries.  They need to appear near the end of the link line.
+	#
+
+	LIBS="$LIBS ${gsi_path}/lib/libssl_${globus_flavor_type}.a"
+	LIBS="$LIBS ${gsi_path}/lib/libcrypto_${globus_flavor_type}.a"
+
+	#
+	# Another "GT 2.1.3+"ism.
+	#
+
+	libcommon_path="${gsi_path}/lib/libglobus_common_${globus_flavor_type}.a"
+	if test -r ${libcommon_path}; then
+		LIBS="$LIBS ${libcommon_path}"
+	fi
+else
+	if test "x$gsi_path" != "xno" ; then
+		# Older GSI needs -lssl too
+		LIBS="$LIBS -lssl -lcrypto"
+	else # if no GSI authentication (i.e., OpenSSL default)
+		LIBS="$LIBS -lcrypto"
+	fi
+fi # globus_flavor_type
+
 cat >conftest.$ac_ext <<_ACEOF
 #line $LINENO "configure"
 #include "confdefs.h"
@@ -14783,6 +15205,614 @@
 fi
 
 
+			# If we're using some other GSSAPI
+			if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+				{ { echo "$as_me:$LINENO: error: $GSSAPI GSSAPI library conflicts with Kerberos support.  Use mechglue instead." >&5
+echo "$as_me: error: $GSSAPI GSSAPI library conflicts with Kerberos support.  Use mechglue instead." >&2;}
+   { (exit 1); exit 1; }; }
+			fi
+			echo "$as_me:$LINENO: checking for gss_init_sec_context in -lgssapi" >&5
+echo $ECHO_N "checking for gss_init_sec_context in -lgssapi... $ECHO_C" >&6
+if test "${ac_cv_lib_gssapi_gss_init_sec_context+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char gss_init_sec_context ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+gss_init_sec_context ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_gssapi_gss_init_sec_context=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_gssapi_gss_init_sec_context=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_gss_init_sec_context" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_gss_init_sec_context" >&6
+if test $ac_cv_lib_gssapi_gss_init_sec_context = yes; then
+   cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+				  K5LIBS="-lgssapi $K5LIBS"
+else
+   echo "$as_me:$LINENO: checking for gss_init_sec_context in -lgssapi_krb5" >&5
+echo $ECHO_N "checking for gss_init_sec_context in -lgssapi_krb5... $ECHO_C" >&6
+if test "${ac_cv_lib_gssapi_krb5_gss_init_sec_context+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi_krb5 $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char gss_init_sec_context ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+gss_init_sec_context ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_gssapi_krb5_gss_init_sec_context=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_gssapi_krb5_gss_init_sec_context=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_krb5_gss_init_sec_context" >&6
+if test $ac_cv_lib_gssapi_krb5_gss_init_sec_context = yes; then
+   cat >>confdefs.h <<\_ACEOF
+#define GSSAPI 1
+_ACEOF
+
+				  	  K5LIBS="-lgssapi_krb5 $K5LIBS"
+else
+  { echo "$as_me:$LINENO: WARNING: Cannot find any suitable gss-api library - build may fail" >&5
+echo "$as_me: WARNING: Cannot find any suitable gss-api library - build may fail" >&2;}
+fi
+
+
+fi
+
+
+			if test "${ac_cv_header_gssapi_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for gssapi.h" >&5
+echo $ECHO_N "checking for gssapi.h... $ECHO_C" >&6
+if test "${ac_cv_header_gssapi_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking gssapi.h usability" >&5
+echo $ECHO_N "checking gssapi.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <gssapi.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking gssapi.h presence" >&5
+echo $ECHO_N "checking gssapi.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <gssapi.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  egrep -v '^ *\+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+  yes:no )
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: gssapi.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi.h: proceeding with the preprocessor's result" >&2;};;
+  no:yes )
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: gssapi.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: gssapi.h: check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi.h: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for gssapi.h" >&5
+echo $ECHO_N "checking for gssapi.h... $ECHO_C" >&6
+if test "${ac_cv_header_gssapi_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_gssapi_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_h" >&6
+
+fi
+if test $ac_cv_header_gssapi_h = yes; then
+  :
+else
+   unset ac_cv_header_gssapi_h
+				  CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+
+for ac_header in gssapi.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  egrep -v '^ *\+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+  yes:no )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+  no:yes )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+else
+  { echo "$as_me:$LINENO: WARNING: Cannot find any suitable gss-api header - build may fail" >&5
+echo "$as_me: WARNING: Cannot find any suitable gss-api header - build may fail" >&2;}
+
+fi
+
+done
+
+
+
+fi
+
+
+
+			echo "$as_me:$LINENO: checking for gss_krb5_copy_ccache in -lgssapi" >&5
+echo $ECHO_N "checking for gss_krb5_copy_ccache in -lgssapi... $ECHO_C" >&6
+if test "${ac_cv_lib_gssapi_gss_krb5_copy_ccache+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* 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_copy_ccache ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+gss_krb5_copy_ccache ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_gssapi_gss_krb5_copy_ccache=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_gssapi_gss_krb5_copy_ccache=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_gss_krb5_copy_ccache" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_gss_krb5_copy_ccache" >&6
+if test $ac_cv_lib_gssapi_gss_krb5_copy_ccache = yes; then
+  /bin/true
+else
+   K5LIBS="-lgssapi_krb5 $K5LIBS"
+				  echo "$as_me:$LINENO: checking for gss_krb5_copy_ccache in -lgssapi_krb5" >&5
+echo $ECHO_N "checking for gss_krb5_copy_ccache in -lgssapi_krb5... $ECHO_C" >&6
+if test "${ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lgssapi_krb5 $K5LIBS $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* 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_copy_ccache ();
+#ifdef F77_DUMMY_MAIN
+#  ifdef __cplusplus
+     extern "C"
+#  endif
+   int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+gss_krb5_copy_ccache ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache" >&5
+echo "${ECHO_T}$ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache" >&6
+if test $ac_cv_lib_gssapi_krb5_gss_krb5_copy_ccache = yes; then
+  /bin/true
+else
+  { echo "$as_me:$LINENO: WARNING: Cannot find gss_krb5_copy_ccache -- build may fail" >&5
+echo "$as_me: WARNING: Cannot find gss_krb5_copy_ccache -- build may fail" >&2;}
+fi
+
+
+fi
+
+
+			oldCPP="$CPPFLAGS"
+			CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+			if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for gssapi_krb5.h" >&5
+echo $ECHO_N "checking for gssapi_krb5.h... $ECHO_C" >&6
+if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_krb5_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_krb5_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking gssapi_krb5.h usability" >&5
+echo $ECHO_N "checking gssapi_krb5.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <gssapi_krb5.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+         { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking gssapi_krb5.h presence" >&5
+echo $ECHO_N "checking gssapi_krb5.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <gssapi_krb5.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  egrep -v '^ *\+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+  yes:no )
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&2;};;
+  no:yes )
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for gssapi_krb5.h" >&5
+echo $ECHO_N "checking for gssapi_krb5.h... $ECHO_C" >&6
+if test "${ac_cv_header_gssapi_krb5_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_gssapi_krb5_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_gssapi_krb5_h" >&5
+echo "${ECHO_T}$ac_cv_header_gssapi_krb5_h" >&6
+
+fi
+if test $ac_cv_header_gssapi_krb5_h = yes; then
+  :
+else
+   CPPFLAGS="$oldCPP"
+fi
+
+
+
+			if test -z "$GSSAPI"; then
+				GSSAPI="KRB5";
+			fi
+
                         KRB5=yes
                 fi
 
@@ -17002,6 +18032,7 @@
 s,@SH@,$SH,;t t
 s,@LOGIN_PROGRAM_FALLBACK@,$LOGIN_PROGRAM_FALLBACK,;t t
 s,@LD@,$LD,;t t
+s,@INSTALL_GSISSH@,$INSTALL_GSISSH,;t t
 s,@LIBWRAP@,$LIBWRAP,;t t
 s,@LIBPAM@,$LIBPAM,;t t
 s,@INSTALL_SSH_RAND_HELPER@,$INSTALL_SSH_RAND_HELPER,;t t
diff -Naur --exclude=autom4te.cache openssh-3.4p1/configure.ac openssh-3.4p1-gsi/configure.ac
--- openssh-3.4p1/configure.ac	Tue Jun 25 17:35:16 2002
+++ openssh-3.4p1-gsi/configure.ac	Mon Sep 30 12:13:26 2002
@@ -477,6 +477,163 @@
 	]
 )
 
+# Check whether the user wants GSSAPI mechglue support
+AC_ARG_WITH(mechglue,
+	[  --with-mechglue=PATH    Build with GSSAPI mechglue library],
+	[
+		AC_MSG_CHECKING(for mechglue library)
+
+		if test -e ${withval}/libgssapi.a ; then
+		    mechglue_lib=${withval}/libgssapi.a
+		elif test -e ${withval}/lib/libgssapi.a ; then
+		    mechglue_lib=${withval}/lib/libgssapi.a
+		else
+		    AC_MSG_ERROR("Can't find libgssapi in ${withval}");
+		fi
+		LIBS="$LIBS ${mechglue_lib}"
+		AC_MSG_RESULT(${mechglue_lib})
+
+#		if test -e ${withval}/gssapi.h ; then
+#		    CPPFLAGS="$CPPFLAGS -I${withval}"
+#		elif test -e ${withval}/include/gssapi.h ; then
+#		    CPPFLAGS="$CPPFLAGS -I${withval}/include"
+#		else
+#		    AC_MSG_ERROR("Can't find gssapi.h in ${withval}");
+#		fi
+		
+		AC_CHECK_LIB(dl, dlopen, , )
+		if test $ac_cv_lib_dl_dlopen = yes; then
+		   LDFLAGS="$LDFLAGS -ldl -Wl,-Bsymbolic"
+		fi
+
+		AC_DEFINE(GSSAPI)
+		AC_DEFINE(MECHGLUE)
+		GSSAPI="mechglue"
+
+	]
+)
+
+
+# Check whether the user wants GSI (Globus) support
+gsi_path="no"
+AC_ARG_WITH(gsi,
+	[  --with-gsi=PATH         Enable GSI/Globus authentication support],
+	[
+		gsi_path="$withval"
+	]
+)
+
+AC_ARG_WITH(globus,
+	[  --with-globus=PATH      Enable GSI/Globus authentication support],
+	[
+		gsi_path="$withval"
+	]
+)
+
+# Check whether the user has a Globus flavor type
+globus_flavor_type="no"
+AC_ARG_WITH(globus-flavor,
+	[  --with-globus-flavor=TYPE         Describe Globus flavor type (ex: gcc32dbg, etc.)],
+	[
+		globus_flavor_type="$withval"
+	]
+)
+
+if test "x$gsi_path" != "xno" ; then
+	# Globus GSSAPI configuration
+	AC_DEFINE(GSI)
+
+	if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+		AC_MSG_ERROR([Previously configured GSSAPI library conflicts with Globus/GSI.])
+	fi
+	if test -z "$GSSAPI"; then
+		AC_DEFINE(GSSAPI)
+		GSSAPI="GSI"
+	fi
+
+	# Find GLOBUS/GSI installation Directory
+	AC_MSG_CHECKING(for Globus/GSI installation directory)
+
+	globus_install_dir=$gsi_path
+
+	if test "x$globus_install_dir" = "xyes" ; then
+                AC_MSG_ERROR(Cannot find Globus/GSI installation directory -- a path must be specified!)
+	fi
+	AC_MSG_RESULT($globus_install_dir)
+
+	# Find GLOBUS/GSI development directory
+	AC_MSG_CHECKING(for Globus/GSI development directory)
+
+	if test -d ${globus_install_dir}/lib ; then
+		# Looks like a flat directory structure from configure/make
+		# and not globus-install or gsi-install
+		globus_dev_dir=$globus_install_dir
+
+	else
+		# Assume a true globus installation with architecture
+		# directories and run globus-development-path to find
+		# the development directory
+
+		# Set GLOBUS_INSTALL_PATH
+		GLOBUS_INSTALL_PATH=$globus_install_dir
+		export GLOBUS_INSTALL_PATH
+
+		dev_path_program=${globus_install_dir}/bin/globus-development-path
+
+		if test ! -x ${dev_path_program} ; then
+			AC_MSG_ERROR(Cannot find Globus/GSI installation directory: program ${dev_path_program} does not exist or is not executable)
+		fi
+
+		globus_dev_dir=`${dev_path_program}`
+
+		if test -z "$globus_dev_dir" -o "X$globus_dev_dir" = "X<not found>" ; then
+			AC_MSG_ERROR(Cannot find Globus/GSI development directory)
+		fi
+
+		if test ! -d "$globus_dev_dir" ; then
+			AC_MSG_ERROR(Cannot find Globus/GSI development directory: $globus_dev_dir does not exist)
+		fi
+	fi
+	AC_MSG_RESULT($globus_dev_dir)
+
+	# Find GLOBUS/GSI flavor Directory
+	AC_MSG_CHECKING(for Globus flavor type)
+
+        if test "x$globus_flavor_type" = "xno" ; then
+		if test "$GSSAPI" = "mechglue"; then
+			GSI_LIBS="-lglobus_gss_assist -lglobus_gaa"
+		else
+			GSI_LIBS="-lglobus_gss_assist -lglobus_gss -lglobus_gaa"
+		fi
+		GSI_LDFLAGS="-L${globus_dev_dir}/lib"
+		GSI_CPPFLAGS="-I${globus_dev_dir}/include"
+		AC_MSG_RESULT(none)
+	else
+                GLOBUS_FLAVOR_TYPE_INCL_DIR="${globus_dev_dir}/include/${globus_flavor_type}"
+
+		if test ! -d "$GLOBUS_FLAVOR_TYPE_INCL_DIR" ; then
+			AC_MSG_ERROR(Cannot find Globus flavor-specific include directory: ${GLOBUS_FLAVOR_TYPE_INCL_DIR})
+                fi
+
+		AC_MSG_RESULT($globus_flavor_type)
+		if test "$GSSAPI" = "mechglue"; then
+			GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a"
+		else
+			GSI_LIBS="${gsi_path}/lib/libglobus_gss_assist_${globus_flavor_type}.a ${gsi_path}/lib/libglobus_gssapi_gsi_${globus_flavor_type}.a"
+		fi
+		GSI_CPPFLAGS="-I${GLOBUS_FLAVOR_TYPE_INCL_DIR}"
+	fi
+
+	LIBS="$LIBS $GSI_LIBS"
+	LDFLAGS="$LDFLAGS $GSI_LDFLAGS"
+	CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+	INSTALL_GSISSH="yes"
+else
+	INSTALL_GSISSH=""
+fi
+AC_SUBST(INSTALL_GSISSH)
+# End Globus/GSI section
+
 # Check whether user wants S/Key support
 SKEY_MSG="no" 
 AC_ARG_WITH(skey,
@@ -689,6 +846,7 @@
 			AC_CHECK_LIB(dl, dlopen, , )
 			AC_CHECK_LIB(pam, pam_set_item, , AC_MSG_ERROR([*** libpam missing]))
 			AC_CHECK_FUNCS(pam_getenvlist)
+			AC_CHECK_FUNCS(pam_putenv)
 
 			disable_shadow=yes
 			PAM_MSG="yes"
@@ -751,7 +909,79 @@
 		fi
 	]
 )
-LIBS="$LIBS -lcrypto"
+
+# Patch up SSL libraries for GSI authentication as needed
+if test "x$globus_flavor_type" != "xno" ; then
+	#
+	# For Globus 2, always link with the static libraries
+	#
+
+	libssl_utils="${gsi_path}/lib/libglobus_ssl_utils_${globus_flavor_type}.a"
+
+	#
+	# Trouble arrives at GT 2.1.3+ with the reorg of globus_ssl_utils.  Compensating for
+	# the new library linking required here through file tests to see which libraries to 
+	# link against.
+	#
+
+	libgsi_proxy_core="${gsi_path}/lib/libglobus_gsi_proxy_core_${globus_flavor_type}.a"
+	libgsi_credential="${gsi_path}/lib/libglobus_gsi_credential_${globus_flavor_type}.a"
+	libgsi_callback="${gsi_path}/lib/libglobus_gsi_callback_${globus_flavor_type}.a"
+	liboldgaa="${gsi_path}/lib/libglobus_oldgaa_${globus_flavor_type}.a"
+	libgsi_sysconfig="${gsi_path}/lib/libglobus_gsi_sysconfig_${globus_flavor_type}.a"
+	libproxy_ssl="${gsi_path}/lib/libglobus_proxy_ssl_${globus_flavor_type}.a"
+	libgsi_cert_utils="${gsi_path}/lib/libglobus_gsi_cert_utils_${globus_flavor_type}.a"
+	libopenssl_error="${gsi_path}/lib/libglobus_openssl_error_${globus_flavor_type}.a"
+	libopenssl="${gsi_path}/lib/libglobus_openssl_${globus_flavor_type}.a"
+
+	if test -r ${libgsi_proxy_core} \
+	     -a -r ${libgsi_credential} \
+	     -a -r ${libgsi_callback} \
+	     -a -r ${liboldgaa} \
+	     -a -r ${libgsi_sysconfig} \
+	     -a -r ${libproxy_ssl} \
+	     -a -r ${libgsi_cert_utils} \
+	     -a -r ${libopenssl_error} \
+	     -a -r ${libopenssl} ; then
+		LIBS="$LIBS ${libgsi_proxy_core}"
+		LIBS="$LIBS ${libgsi_credential}"
+		LIBS="$LIBS ${libgsi_callback}"
+		LIBS="$LIBS ${liboldgaa}"
+		LIBS="$LIBS ${libgsi_sysconfig}"
+		LIBS="$LIBS ${libproxy_ssl}"
+		LIBS="$LIBS ${libgsi_cert_utils}"
+		LIBS="$LIBS ${libopenssl_error}"
+		LIBS="$LIBS ${libopenssl}"
+	elif test -r ${libssl_utils}; then
+		LIBS="$LIBS ${libssl_utils}"
+	else
+		AC_MSG_ERROR(All of the required Globus Toolkit libraries are not present/configured correctly)
+	fi
+
+	#
+	# Standard openssl libraries.  They need to appear near the end of the link line.
+	#
+
+	LIBS="$LIBS ${gsi_path}/lib/libssl_${globus_flavor_type}.a"
+	LIBS="$LIBS ${gsi_path}/lib/libcrypto_${globus_flavor_type}.a"
+
+	#
+	# Another "GT 2.1.3+"ism.
+	#
+
+	libcommon_path="${gsi_path}/lib/libglobus_common_${globus_flavor_type}.a"
+	if test -r ${libcommon_path}; then
+		LIBS="$LIBS ${libcommon_path}"
+	fi
+else
+	if test "x$gsi_path" != "xno" ; then
+		# Older GSI needs -lssl too
+		LIBS="$LIBS -lssl -lcrypto"
+	else # if no GSI authentication (i.e., OpenSSL default)
+		LIBS="$LIBS -lcrypto"
+	fi
+fi # globus_flavor_type
+
 AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL),
 	[
 		dnl Check default openssl install dir
@@ -1729,6 +1959,47 @@
                         fi
                         AC_CHECK_LIB(resolv, dn_expand, , )
 
+			# If we're using some other GSSAPI
+			if test "$GSSAPI" -a "$GSSAPI" != "mechglue"; then
+				AC_MSG_ERROR([$GSSAPI GSSAPI library conflicts with Kerberos support.  Use mechglue instead.])
+			fi
+			AC_CHECK_LIB(gssapi,gss_init_sec_context,
+				[ AC_DEFINE(GSSAPI)
+				  K5LIBS="-lgssapi $K5LIBS" ],
+				[ AC_CHECK_LIB(gssapi_krb5,gss_init_sec_context,
+					[ AC_DEFINE(GSSAPI)
+				  	  K5LIBS="-lgssapi_krb5 $K5LIBS" ],
+					AC_MSG_WARN([Cannot find any suitable gss-api library - build may fail]),
+					$K5LIBS)
+				],
+				$K5LIBS)
+		
+			AC_CHECK_HEADER(gssapi.h, ,
+				[ unset ac_cv_header_gssapi_h
+				  CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi" 
+				  AC_CHECK_HEADERS(gssapi.h, ,
+					AC_MSG_WARN([Cannot find any suitable gss-api header - build may fail])
+				  ) 
+				]
+			)
+
+			AC_CHECK_LIB(gssapi, gss_krb5_copy_ccache, /bin/true,
+				[ K5LIBS="-lgssapi_krb5 $K5LIBS"
+				  AC_CHECK_LIB(gssapi_krb5, gss_krb5_copy_ccache, /bin/true,
+					AC_MSG_WARN([Cannot find gss_krb5_copy_ccache -- build may fail]),
+					$K5LIBS)
+				],
+				$K5LIBS)
+
+			oldCPP="$CPPFLAGS"
+			CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+			AC_CHECK_HEADER(gssapi_krb5.h, ,
+					[ CPPFLAGS="$oldCPP" ])
+
+			if test -z "$GSSAPI"; then
+				GSSAPI="KRB5";
+			fi
+
                         KRB5=yes
                 fi
         ]
diff -Naur --exclude=autom4te.cache openssh-3.4p1/gss-genr.c openssh-3.4p1-gsi/gss-genr.c
--- openssh-3.4p1/gss-genr.c	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/gss-genr.c	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2001,2002 Simon Wilkinson. 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 "includes.h"
+
+#ifdef GSSAPI
+
+#include "ssh.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "packet.h"
+#include "compat.h"
+#include <openssl/evp.h>
+#include "cipher.h"
+#include "kex.h"
+#include "log.h"
+#include "compat.h"
+#include "monitor_wrap.h"
+#include "canohost.h"
+
+#include <netdb.h>
+
+#include "ssh-gss.h"
+
+/* Assorted globals for tracking the clients identity once they've
+ * authenticated */
+ 
+gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */
+gss_cred_id_t   gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */
+enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY;
+
+unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */
+
+/* The mechanism name used in the list below is defined in the internet
+ * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding 
+ * of the underlying GSSAPI mechanism's OID.
+ *
+ * Also from the draft, before considering adding SPNEGO, bear in mind that
+ * "mechanisms ... MUST NOT use SPNEGO as the underlying GSSAPI mechanism"
+ */
+
+/* These must be in the same order as ssh_gss_id, in ssh-gss.h */
+
+ssh_gssapi_mech supported_mechs[]= {
+#ifdef KRB5
+ /* Official OID - 1.2.850.113554.1.2.2 */
+ {"Se3H81ismmOC3OE+FwYCiQ==","Kerberos",
+ 	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}},
+#endif
+#ifdef GSI
+ /* gssapi_ssleay 1.3.6.1.4.1.3536.1.1 */
+ {"N3+k7/4wGxHyuP8Yxi4RhA==",
+  "GSI",
+  {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}
+ },
+#endif /* GSI */
+ {NULL,NULL,{0,0}}
+};
+
+char gssprefix[]=KEX_GSS_SHA1;
+
+/* Return a list of the gss-group1-sha1-x mechanisms supported by this
+ * program.
+ *
+ * We only support the mechanisms that we've indicated in the list above,
+ * but we check that they're supported by the GSSAPI mechanism on the 
+ * machine. We also check, before including them in the list, that
+ * we have the necesary information in order to carry out the key exchange
+ * (that is, that the user has credentials, the server's creds are accessible,
+ * etc)
+ *
+ * The way that this is done is fairly nasty, as we do a lot of work that
+ * is then thrown away. This should possibly be implemented with a cache
+ * that stores the results (in an expanded Gssctxt structure), which are
+ * then used by the first calls if that key exchange mechanism is chosen.
+ */
+ 
+char * 
+ssh_gssapi_mechanisms(int server,char *host) {
+	gss_OID_set 	supported;
+	OM_uint32	maj_status, min_status;
+	Buffer		buf;
+	int 		i = 0;
+	int		present;
+	int		mech_count=0;
+	char *		mechs;
+	Gssctxt *	ctx = NULL;	
+
+	if (datafellows & SSH_OLD_GSSAPI) return NULL;
+	
+	gss_indicate_mechs(&min_status, &supported);
+	
+	buffer_init(&buf);	
+
+	do {
+		if ((maj_status=gss_test_oid_set_member(&min_status,
+						   	&supported_mechs[i].oid,
+						   	supported,
+						   	&present))) {
+			present=0;
+		}
+		if (present) {
+		    	if ((server && 
+		    	     !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
+		    	  			            &supported_mechs[i].oid)))) 
+		    	    || (!server &&
+		    	        !GSS_ERROR(ssh_gssapi_client_ctx(&ctx,
+		    	 			       &supported_mechs[i].oid,
+		    	 			       host)))) {
+				/* Append gss_group1_sha1_x to our list */
+				if (++mech_count > 1) {
+				    buffer_append(&buf, ",", 1);
+				}
+				buffer_append(&buf, gssprefix,
+					      strlen(gssprefix));
+		        	buffer_append(&buf, 
+		        		      supported_mechs[i].enc_name,
+	        	      		      strlen(supported_mechs[i].enc_name));
+				debug("GSSAPI mechanism %s (%s%s) supported",
+				      supported_mechs[i].name, gssprefix,
+				      supported_mechs[i].enc_name);
+			} else {
+			    debug("no credentials for GSSAPI mechanism %s",
+				  supported_mechs[i].name);
+			}
+ 		} else {
+		    debug("GSSAPI mechanism %s not supported",
+			  supported_mechs[i].name);
+		}
+	} while (supported_mechs[++i].name != NULL);
+	
+	buffer_put_char(&buf,'\0');
+	
+	mechs=xmalloc(buffer_len(&buf));
+	buffer_get(&buf,mechs,buffer_len(&buf));
+	buffer_free(&buf);
+	if (strlen(mechs)==0)
+	   return(NULL);
+	else
+	   return(mechs);
+}
+
+void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
+	enum ssh_gss_id i =0;
+	OM_uint32 maj_status,min_status;
+	int present;
+	gss_OID_set supported;
+	
+	gss_create_empty_oid_set(&min_status,oidset);
+	gss_indicate_mechs(&min_status, &supported);
+
+	while (supported_mechs[i].name!=NULL) {
+		if ((maj_status=gss_test_oid_set_member(&min_status,
+						       &supported_mechs[i].oid,
+						       supported,
+						       &present))) {
+			present=0;
+		}
+		if (present) {
+			gss_add_oid_set_member(&min_status,
+					       &supported_mechs[i].oid,
+				       	       oidset);	
+		}
+		i++;
+	}
+}	
+
+/* Set the contexts OID from a data stream */
+void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) { 
+  if (ctx->oid != GSS_C_NO_OID) {
+	xfree(ctx->oid->elements);
+   	xfree(ctx->oid);
+  }
+  ctx->oid=xmalloc(sizeof(gss_OID_desc));
+  ctx->oid->length=len;
+  ctx->oid->elements=xmalloc(len);
+  memcpy(ctx->oid->elements,data,len);
+}
+
+/* Set the contexts OID */
+void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) {  
+  ssh_gssapi_set_oid_data(ctx,oid->elements,oid->length);
+}
+
+/* Find out which GSS type (out of the list we define in ssh-gss.h) a
+ * particular connection is using 
+ */
+enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) {
+	enum ssh_gss_id i=0;
+	
+	while(supported_mechs[i].name!=NULL) {
+	   if (supported_mechs[i].oid.length == ctxt->oid->length &&
+	       (memcmp(supported_mechs[i].oid.elements,
+		       ctxt->oid->elements,ctxt->oid->length) == 0))
+	       return i;
+	   i++;
+	}
+	return(GSS_LAST_ENTRY);
+}
+
+/* Set the GSS context's OID to the oid indicated by the given key exchange
+ * name. */
+gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
+  enum ssh_gss_id i=0;
+  
+  if (strncmp(name, gssprefix, strlen(gssprefix)-1) !=0) {
+     return(NULL);
+  }
+  
+  name+=strlen(gssprefix); /* Move to the start of the MIME string */
+  
+  while (supported_mechs[i].name!=NULL &&
+  	 strcmp(name,supported_mechs[i].enc_name)!=0) {
+  	i++;
+  }
+
+  if (supported_mechs[i].name==NULL)
+     return (NULL);
+
+  if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid);
+
+  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i].name,
+	gssprefix, supported_mechs[i].enc_name);
+
+  return &supported_mechs[i].oid;
+}
+
+
+/* All this effort to report an error ... */
+static void
+ssh_gssapi_error_ex(gss_OID mech, OM_uint32 major_status,
+		    OM_uint32 minor_status,
+		    int send_packet) {
+	OM_uint32 lmaj, lmin;
+        gss_buffer_desc msg = {0,NULL};
+        OM_uint32 ctx;
+        
+        ctx = 0;
+	/* The GSSAPI error */
+        do {
+        	lmaj = gss_display_status(&lmin, major_status,
+        				  GSS_C_GSS_CODE,
+        				  mech,
+        				  &ctx, &msg);
+        	if (lmaj == GSS_S_COMPLETE) {
+        	    	debug((char *)msg.value);
+			if (send_packet) packet_send_debug((char *)msg.value);
+        	    	(void) gss_release_buffer(&lmin, &msg);
+        	}
+        } while (ctx!=0);	   
+
+        /* The mechanism specific error */
+        do {
+        	lmaj = gss_display_status(&lmin, minor_status,
+        				  GSS_C_MECH_CODE,
+        				  mech,
+        				  &ctx, &msg);
+        	if (lmaj == GSS_S_COMPLETE) {
+        	    	debug((char *)msg.value);
+			if (send_packet) packet_send_debug((char *)msg.value);
+        	    	(void) gss_release_buffer(&lmin, &msg);
+        	}
+        } while (ctx!=0);
+}
+
+void
+ssh_gssapi_error(gss_OID mech,OM_uint32 major_status,OM_uint32 minor_status) {
+    ssh_gssapi_error_ex(mech, major_status, minor_status, 0);
+}
+
+void
+ssh_gssapi_send_error(gss_OID mech,
+		      OM_uint32 major_status,OM_uint32 minor_status) {
+    ssh_gssapi_error_ex(mech, major_status, minor_status, 1);
+}
+
+
+
+
+/* Initialise our GSSAPI context. We use this opaque structure to contain all
+ * of the data which both the client and server need to persist across
+ * {accept,init}_sec_context calls, so that when we do it from the userauth
+ * stuff life is a little easier
+ */
+void
+ssh_gssapi_build_ctx(Gssctxt **ctx)
+{
+	*ctx=xmalloc(sizeof (Gssctxt));
+	(*ctx)->context=GSS_C_NO_CONTEXT;
+	(*ctx)->name=GSS_C_NO_NAME;
+	(*ctx)->oid=GSS_C_NO_OID;
+	(*ctx)->creds=GSS_C_NO_CREDENTIAL;
+	(*ctx)->client=GSS_C_NO_NAME;
+	(*ctx)->client_creds=GSS_C_NO_CREDENTIAL;
+}
+
+/* Delete our context, providing it has been built correctly */
+void
+ssh_gssapi_delete_ctx(Gssctxt **ctx)
+{
+	OM_uint32 ms;
+	
+	/* Return if there's no context */
+	if ((*ctx)==NULL)
+		return;
+		
+#if !defined(MECHGLUE) /* mechglue has some memory management issues */
+	if ((*ctx)->context != GSS_C_NO_CONTEXT) 
+		gss_delete_sec_context(&ms,&(*ctx)->context,GSS_C_NO_BUFFER);
+	if ((*ctx)->name != GSS_C_NO_NAME)
+		gss_release_name(&ms,&(*ctx)->name);
+	if ((*ctx)->oid != GSS_C_NO_OID) {
+		xfree((*ctx)->oid->elements);
+		xfree((*ctx)->oid);
+		(*ctx)->oid = GSS_C_NO_OID;
+	}
+	if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
+		gss_release_cred(&ms,&(*ctx)->creds);
+	if ((*ctx)->client != GSS_C_NO_NAME)
+		gss_release_name(&ms,&(*ctx)->client);	
+	if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
+		gss_release_cred(&ms,&(*ctx)->client_creds);
+#endif
+	
+	xfree(*ctx);
+	*ctx=NULL; 
+}
+
+/* Wrapper to init_sec_context 
+ * Requires that the context contains:
+ *	oid
+ * 	server name (from ssh_gssapi_import_name)
+ */
+OM_uint32 
+ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
+       	      	    gss_buffer_desc* send_tok, OM_uint32 *flags) 
+{
+      	OM_uint32 maj_status, min_status;
+	int deleg_flag = 0;
+	
+	if (deleg_creds) {
+		deleg_flag=GSS_C_DELEG_FLAG;
+		debug("Delegating credentials");
+	}
+	      	
+      	maj_status=gss_init_sec_context(&min_status,
+      					GSS_C_NO_CREDENTIAL, /* def. cred */
+      					&ctx->context,
+      					ctx->name,
+      					ctx->oid,
+      					GSS_C_MUTUAL_FLAG |
+      					GSS_C_INTEG_FLAG |
+      					deleg_flag,
+      					0, /* default lifetime */
+      					NULL, /* no channel bindings */
+      					recv_tok,
+      					NULL,
+      					send_tok,
+      					flags,
+      					NULL);
+	ctx->status=maj_status;
+      	if (GSS_ERROR(maj_status)) {
+      		ssh_gssapi_error(ctx->oid,maj_status,min_status);
+      	}
+      	return(maj_status);
+}
+
+/* Wrapper arround accept_sec_context
+ * Requires that the context contains:
+ *    oid		
+ *    credentials	(from ssh_gssapi_acquire_cred)
+ */
+OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
+				gss_buffer_desc *send_tok, OM_uint32 *flags) 
+{
+	OM_uint32 maj_status, min_status;
+	
+	maj_status=gss_accept_sec_context(&min_status,
+					  &ctx->context,
+					  ctx->creds,
+					  recv_tok,
+					  GSS_C_NO_CHANNEL_BINDINGS,
+					  &ctx->client,
+					  &ctx->oid,
+					  send_tok,
+					  flags,
+					  NULL,
+					  &ctx->client_creds);
+	if (GSS_ERROR(maj_status)) {
+		ssh_gssapi_send_error(ctx->oid,maj_status,min_status);
+	}
+	
+	if (ctx->client_creds) {
+		debug("Received some client credentials");
+	} else {
+		debug("Got no client credentials");
+	}
+
+	/* FIXME: We should check that the me
+	 * the one that we asked for (in ctx->oid) */
+
+	ctx->status=maj_status;
+	
+	/* Now, if we're complete and we have the right flags, then
+	 * we flag the user as also having been authenticated
+	 */
+	
+	if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && 
+	                       (*flags & GSS_C_INTEG_FLAG))) &&
+	    (maj_status == GSS_S_COMPLETE)) {
+		if (ssh_gssapi_getclient(ctx,&gssapi_client_type,
+	  			         &gssapi_client_name,
+	  			         &gssapi_client_creds))
+	  		fatal("Couldn't convert client name");
+	}
+
+	return(maj_status);
+}
+
+/* Create a service name for the given host */
+OM_uint32
+ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
+	gss_buffer_desc gssbuf = {0,NULL};
+	OM_uint32 maj_status, min_status;
+	char *xhost;
+	
+	/* Make a copy of the host name, in case it was returned by a
+	 * previous call to gethostbyname(). */	
+	xhost = xstrdup(host);
+
+	/* If xhost is the loopback interface, switch it to our
+	   true local hostname. */
+	resolve_localhost(&xhost);
+
+	/* Make sure we have the FQHN. Some GSSAPI implementations don't do
+	 * this for us themselves */
+	make_fqhn(&xhost);
+
+        gssbuf.length = sizeof("host@")+strlen(xhost);
+
+        gssbuf.value = xmalloc(gssbuf.length);
+        if (gssbuf.value == NULL) {
+		xfree(xhost);
+		return(-1);
+        }
+        snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost);
+        if ((maj_status=gss_import_name(&min_status,
+                                   	&gssbuf,
+                                        GSS_C_NT_HOSTBASED_SERVICE,
+                                        &ctx->name))) {
+		ssh_gssapi_error(ctx->oid, maj_status,min_status);
+	}
+	
+	xfree(xhost);
+	xfree(gssbuf.value);
+	return(maj_status);
+}
+
+/* Acquire credentials for a server running on the current host.
+ * Requires that the context structure contains a valid OID
+ */
+ 
+/* Returns a GSSAPI error code */
+OM_uint32
+ssh_gssapi_acquire_cred(Gssctxt *ctx) {
+	OM_uint32 maj_status, min_status;
+	char lname[MAXHOSTNAMELEN];
+	gss_OID_set oidset;
+	
+	gss_create_empty_oid_set(&min_status,&oidset);
+	gss_add_oid_set_member(&min_status,ctx->oid,&oidset);
+	
+        if (gethostname(lname, MAXHOSTNAMELEN)) {
+                return(-1);
+        }
+
+	if ((maj_status=ssh_gssapi_import_name(ctx,lname))) {
+		return(maj_status);
+	}
+	if ((maj_status=gss_acquire_cred(&min_status,
+			 	    ctx->name,
+				    0,
+				    oidset,
+				    GSS_C_ACCEPT,
+				    &ctx->creds,
+				    NULL,
+				    NULL))) {
+		ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status);
+	}
+				
+	gss_release_oid_set(&min_status, &oidset);
+	return(maj_status);
+}
+
+/* Extract the client details from a given context. This can only reliably
+ * be called once for a context */
+
+OM_uint32 
+ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type,
+		     gss_buffer_desc *name, gss_cred_id_t *creds) {
+
+	OM_uint32 maj_status,min_status;
+	
+	*type=ssh_gssapi_get_ctype(ctx);
+	if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) {
+		ssh_gssapi_error(GSS_C_NO_OID,maj_status,min_status);
+	}
+	
+	/* This is icky. There appears to be no way to copy this structure,
+	 * rather than the pointer to it, so we simply copy the pointer and
+	 * mark the originator as empty so we don't destroy it. 
+	 */
+	*creds=ctx->client_creds;
+	ctx->client_creds=GSS_C_NO_CREDENTIAL;
+	return(maj_status);
+}
+
+OM_uint32
+ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) {
+	OM_uint32 maj_status,min_status;
+	
+	/* ssh1 needs to exchange the hash of the keys */
+	/* will us this hash to return it */
+	if (!compat20) {
+		if ((maj_status=gss_wrap(&min_status,ctx->context,
+					0,
+					GSS_C_QOP_DEFAULT,
+					buffer,
+					NULL,
+					hash)))
+			ssh_gssapi_error(ctx->oid,maj_status,min_status);
+	}
+	else
+
+	if ((maj_status=gss_get_mic(&min_status,ctx->context,
+				    GSS_C_QOP_DEFAULT, buffer, hash))) {
+		ssh_gssapi_error(ctx->oid,maj_status,min_status);
+	}
+	
+	return(maj_status);
+}
+
+OM_uint32
+ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
+	if (*ctx) ssh_gssapi_delete_ctx(ctx);
+	ssh_gssapi_build_ctx(ctx);
+	ssh_gssapi_set_oid(*ctx,oid);
+	return(ssh_gssapi_acquire_cred(*ctx));
+}
+
+OM_uint32 
+ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) {
+	gss_buffer_desc token = {0,NULL};
+	OM_uint32 major,minor;
+	
+	if (*ctx) ssh_gssapi_delete_ctx(ctx);
+	ssh_gssapi_build_ctx(ctx);
+	ssh_gssapi_set_oid(*ctx,oid);
+	ssh_gssapi_import_name(*ctx,host);
+	major=ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
+	gss_release_buffer(&minor,&token);
+	return(major);
+}
+                                                                                        
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/gss-serv.c openssh-3.4p1-gsi/gss-serv.c
--- openssh-3.4p1/gss-serv.c	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/gss-serv.c	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,643 @@
+/*
+ * Copyright (c) 2001,2002 Simon Wilkinson. 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 "includes.h"
+
+#ifdef GSSAPI
+
+#include "ssh.h"
+#include "ssh1.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "packet.h"
+#include "compat.h"
+#include <openssl/evp.h>
+#include "cipher.h"
+#include "kex.h"
+#include "auth.h"
+#include "log.h"
+#include "channels.h"
+#include "session.h"
+#include "dispatch.h"
+#include "servconf.h"
+#include "compat.h"
+#include "misc.h"
+#include "monitor_wrap.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+extern u_char *session_id2;
+extern int session_id2_len;
+
+typedef struct ssh_gssapi_cred_cache {
+	char *filename;
+	char *envvar;
+	char *envval;
+	void *data;
+} ssh_gssapi_cred_cache;
+
+static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL};
+
+/*
+ * Environment variables pointing to delegated credentials
+ */
+static char *delegation_env[] = {
+  "X509_USER_PROXY",		/* GSSAPI/SSLeay */
+  "KRB5CCNAME",			/* Krb5 and possibly SSLeay */
+  NULL
+};
+
+static void gssapi_unsetenv(const char *var);
+
+#ifdef KRB5
+
+#ifdef HEIMDAL
+#include <krb5.h>
+#else
+#include <gssapi_krb5.h>
+#define krb5_get_err_text(context,code) error_message(code)
+#endif
+
+static krb5_context krb_context = NULL;
+
+/* Initialise the krb5 library, so we can use it for those bits that
+ * GSSAPI won't do */
+
+int ssh_gssapi_krb5_init() {
+	krb5_error_code problem;
+	
+	if (krb_context !=NULL)
+		return 1;
+		
+	problem = krb5_init_context(&krb_context);
+	if (problem) {
+		log("Cannot initialize krb5 context");
+		return 0;
+	}
+	krb5_init_ets(krb_context);
+
+	return 1;	
+}			
+
+/* Check if this user is OK to login. This only works with krb5 - other 
+ * GSSAPI mechanisms will need their own.
+ * Returns true if the user is OK to log in, otherwise returns 0
+ */
+
+int
+ssh_gssapi_krb5_userok(char *name) {
+	krb5_principal princ;
+	int retval;
+
+	if (ssh_gssapi_krb5_init() == 0)
+		return 0;
+		
+	if ((retval=krb5_parse_name(krb_context, gssapi_client_name.value, 
+				    &princ))) {
+		log("krb5_parse_name(): %.100s", 
+			krb5_get_err_text(krb_context,retval));
+		return 0;
+	}
+	if (krb5_kuserok(krb_context, princ, name)) {
+		retval = 1;
+		log("Authorized to %s, krb5 principal %s (krb5_kuserok)",name,
+		    (char *)gssapi_client_name.value);
+	}
+	else
+		retval = 0;
+	
+	krb5_free_principal(krb_context, princ);
+	return retval;
+}
+
+int
+ssh_gssapi_krb5_localname(char **user)
+{
+    krb5_principal princ;
+
+    if (ssh_gssapi_krb5_init() == 0)
+	return 0;
+
+    if (krb5_parse_name(krb_context, gssapi_client_name.value, &princ)) {
+	return(0);
+    }
+    *user = (char *)xmalloc(256);
+    if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
+	xfree(*user);
+	*user = NULL;
+	return(0);
+    }
+    return(1);
+}
+	
+/* Make sure that this is called _after_ we've setuid to the user */
+
+/* This writes out any forwarded credentials. Its specific to the Kerberos
+ * GSSAPI mechanism
+ *
+ * We assume that our caller has made sure that the user has selected
+ * delegated credentials, and that the client_creds structure is correctly
+ * populated.
+ */
+
+OM_uint32
+ssh_gssapi_krb5_storecreds(gss_buffer_t export_buffer) {
+	krb5_ccache ccache;
+	krb5_error_code problem;
+	krb5_principal princ;
+	char ccname[35];
+	static char name[40];
+	int tmpfd;
+	OM_uint32 maj_status,min_status;
+	gss_cred_id_t krb5_cred_handle;
+
+
+	if (gssapi_client_creds==NULL) {
+		debug("No credentials stored"); 
+		return GSS_S_NO_CRED;
+	}
+		
+	if (ssh_gssapi_krb5_init() == 0)
+		return GSS_S_FAILURE;
+
+	if (options.gss_use_session_ccache) {
+        	snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
+       
+        	if ((tmpfd = mkstemp(ccname))==-1) {
+                	log("mkstemp(): %.100s", strerror(errno));
+                  	return GSS_S_FAILURE;
+        	}
+	        if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
+	               	log("fchmod(): %.100s", strerror(errno));
+	               	close(tmpfd);
+	               	return GSS_S_FAILURE;
+	        }
+        } else {
+        	snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
+        	tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+        	if (tmpfd == -1) {
+        		log("open(): %.100s", strerror(errno));
+        		return GSS_S_FAILURE;
+        	}
+        }
+
+       	close(tmpfd);
+        snprintf(name, sizeof(name), "FILE:%s",ccname);
+ 
+        if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
+                log("krb5_cc_default(): %.100s", 
+                	krb5_get_err_text(krb_context,problem));
+                return GSS_S_FAILURE;
+        }
+
+	if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value, 
+				       &princ))) {
+		log("krb5_parse_name(): %.100s", 
+			krb5_get_err_text(krb_context,problem));
+		krb5_cc_destroy(krb_context,ccache);
+		return GSS_S_FAILURE;
+	}
+	
+	if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
+		log("krb5_cc_initialize(): %.100s", 
+			krb5_get_err_text(krb_context,problem));
+		krb5_free_principal(krb_context,princ);
+		krb5_cc_destroy(krb_context,ccache);
+		return GSS_S_FAILURE;
+	}
+	
+	krb5_free_principal(krb_context,princ);
+
+#ifdef MECHGLUE
+	krb5_cred_handle =
+	    __gss_get_mechanism_cred(gssapi_client_creds,
+				     &(supported_mechs[GSS_KERBEROS].oid));
+#else
+	krb5_cred_handle = gssapi_client_creds;
+#endif
+
+	if ((maj_status = gss_krb5_copy_ccache(&min_status, 
+					       krb5_cred_handle, 
+					       ccache))) {
+		log("gss_krb5_copy_ccache() failed");
+		ssh_gssapi_error(&supported_mechs[GSS_KERBEROS].oid,
+				 maj_status,min_status);
+		krb5_cc_destroy(krb_context,ccache);
+		return GSS_S_FAILURE;
+	}
+	
+	krb5_cc_close(krb_context,ccache);
+
+	export_buffer->length = strlen("KRB5CCNAME")+strlen(name)+1;
+	export_buffer->value = xmalloc(export_buffer->length+1);
+	sprintf(export_buffer->value, "%s=%s", "KRB5CCNAME", name);
+
+	return GSS_S_COMPLETE;
+}
+
+#endif /* KRB5 */
+
+#ifdef GSI
+#include <globus_gss_assist.h>
+
+/*
+ * Check if this user is OK to login under GSI. User has been authenticated
+ * as identity in global 'client_name.value' and is trying to log in as passed
+ * username in 'name'.
+ *
+ * Returns non-zero if user is authorized, 0 otherwise.
+ */
+int
+ssh_gssapi_gsi_userok(char *name)
+{
+    int authorized = 0;
+    
+    /* This returns 0 on success */
+    authorized = (globus_gss_assist_userok(gssapi_client_name.value,
+					   name) == 0);
+    
+    log("GSI user %s is%s authorized as target user %s",
+	(char *) gssapi_client_name.value, (authorized ? "" : " not"), name);
+    
+    return authorized;
+}
+
+/*
+ * Return the local username associated with the GSI credentials.
+ */
+int
+ssh_gssapi_gsi_localname(char **user)
+{
+    return(globus_gss_assist_gridmap(gssapi_client_name.value, user) == 0);
+}
+
+/*
+ * Handle setting up child environment for GSI.
+ *
+ * Make sure that this is called _after_ we've setuid to the user.
+ */
+OM_uint32
+ssh_gssapi_gsi_storecreds(gss_buffer_t export_buffer)
+{
+	OM_uint32	major_status;
+	OM_uint32	minor_status;
+
+	if (gssapi_client_creds != NULL)
+	{
+		char *creds_env = NULL;
+
+		/*
+ 		 * This is the current hack with the GSI gssapi library to
+		 * export credentials to disk.
+		 */
+
+		debug("Exporting delegated credentials");
+		
+		minor_status = 0xdee0;	/* Magic value */
+		major_status =
+			gss_inquire_cred(&minor_status,
+					 gssapi_client_creds,
+					 (gss_name_t *) &creds_env,
+					 NULL,
+					 NULL,
+					 NULL);
+
+		if ((major_status == GSS_S_COMPLETE) &&
+		    (minor_status == 0xdee1) &&
+		    (creds_env != NULL))
+		{
+			char		*value;
+				
+			/*
+			 * String is of the form:
+			 * X509_USER_DELEG_PROXY=filename
+			 * so we parse out the filename
+			 * and then set X509_USER_PROXY
+			 * to point at it.
+			 */
+			value = strchr(creds_env, '=');
+			
+			if (value != NULL)
+			{
+				*value = '\0';
+				value++;
+				export_buffer->length=
+				    strlen("X509_USER_PROXY")+strlen(value)+1;
+				export_buffer->value =
+				    xmalloc(export_buffer->length+1);
+				sprintf(export_buffer->value, "%s=%s",
+					"X509_USER_PROXY", value);
+				
+				return GSS_S_COMPLETE;
+			}
+			else
+			{
+				log("Failed to parse delegated credentials string '%s'",
+				    creds_env);
+			}
+		}
+		else
+		{
+			log("Failed to export delegated credentials (error %ld)",
+			    major_status);
+		}
+	}
+	return 0;
+}
+
+#endif /* GSI */
+
+void
+ssh_gssapi_cleanup_creds(void *ignored)
+{
+	/* OM_uint32 min_stat; */
+
+	if (gssapi_cred_store.filename!=NULL) {
+		/* Unlink probably isn't sufficient */
+		debug("removing gssapi cred file \"%s\"",gssapi_cred_store.filename);
+		unlink(gssapi_cred_store.filename);
+	}
+	/* DK ?? 
+	if (gssapi_client_creds != GSS_C_NO_CREDENTIAL)
+		gss_release_cred(&min_stat, &gssapi_client_creds);
+	*/
+}
+
+OM_uint32
+ssh_gssapi_export_cred(OM_uint32 *            minor_status,
+		       const gss_cred_id_t    cred_handle,
+		       const gss_OID          desired_mech,
+		       OM_uint32              option_req,
+		       gss_buffer_t           export_buffer)
+{
+	OM_uint32 maj_stat = GSS_S_FAILURE;
+
+	if (option_req != 1) return GSS_S_UNAVAILABLE;
+	if (desired_mech != NULL) return GSS_S_BAD_MECH;
+
+	switch (gssapi_client_type) {
+#ifdef KRB5
+	case GSS_KERBEROS:
+		maj_stat = ssh_gssapi_krb5_storecreds(export_buffer);
+		break;
+#endif
+#ifdef GSI
+	case GSS_GSI:
+		maj_stat = ssh_gssapi_gsi_storecreds(export_buffer);
+		break;
+#endif /* GSI */
+	case GSS_LAST_ENTRY:
+		/* GSSAPI not used in this authentication */
+		debug("No GSSAPI credentials stored");
+		break;
+	default:
+		log("ssh_gssapi_do_child: Unknown mechanism");
+	
+	}
+
+	if (GSS_ERROR(maj_stat)) {
+		*minor_status = GSS_S_FAILURE;
+	}
+	return maj_stat;
+}
+
+void 
+ssh_gssapi_storecreds()
+{
+   	OM_uint32 maj_stat, min_stat;
+	gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
+	char *p;
+
+	if (gssapi_client_creds == GSS_C_NO_CREDENTIAL)
+		return;
+
+#ifdef HAVE_GSSAPI_EXT
+	maj_stat = gss_export_cred(&min_stat, gssapi_client_creds,
+				   GSS_C_NO_OID, 1, &export_cred);
+	if (GSS_ERROR(maj_stat) && maj_stat != GSS_S_UNAVAILABLE) {
+		ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+		return;
+	}
+#endif
+
+	/* If gss_export_cred() is not available, use old methods */
+	if (export_cred.length == 0) {
+	    ssh_gssapi_export_cred(&min_stat, gssapi_client_creds,
+				   GSS_C_NO_OID, 1, &export_cred);
+	    if (GSS_ERROR(maj_stat)) {
+		ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+	    }
+	}
+
+	p = strchr((char *) export_cred.value, '=');
+	if (p == NULL) {
+		log("Failed to parse exported credentials string '%.100s'",
+		    (char *)export_cred.value);
+		gss_release_buffer(&min_stat, &export_cred);
+		return;
+	}
+	*p++ = '\0';
+#ifdef GSI
+	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0)
+	    gssapi_cred_store.envvar = strdup("X509_USER_PROXY");
+	else
+#endif
+	gssapi_cred_store.envvar = strdup((char *)export_cred.value);
+	gssapi_cred_store.envval = strdup(p);
+#ifdef USE_PAM
+	do_pam_putenv(gssapi_cred_store.envvar, gssapi_cred_store.envval);
+#endif
+	if (strncmp(p, "FILE:", 5) == 0) {
+	    p += 5;
+	}
+	if (access(p, R_OK) == 0) {
+	    gssapi_cred_store.filename = strdup(p);
+	}
+	gss_release_buffer(&min_stat, &export_cred);
+
+	if (options.gss_cleanup_creds) {
+		fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
+	}
+}
+
+/* This allows GSSAPI methods to do things to the childs environment based
+ * on the passed authentication process and credentials.
+ *
+ * Question: If we didn't use userauth_external for some reason, should we
+ * still delegate credentials?
+ */
+void 
+ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
+{
+
+	if (gssapi_cred_store.envvar!=NULL && 
+	    gssapi_cred_store.envval!=NULL) {
+	    
+		debug("Setting %s to %s", gssapi_cred_store.envvar,
+					  gssapi_cred_store.envval);				  
+		child_set_env(envp, envsizep, gssapi_cred_store.envvar, 
+					      gssapi_cred_store.envval);
+	}
+
+	switch(gssapi_client_type) {
+#ifdef KRB5
+	case GSS_KERBEROS: break;
+#endif
+#ifdef GSI
+	case GSS_GSI: break;
+#endif
+	case GSS_LAST_ENTRY:
+		debug("No GSSAPI credentials stored");
+		break;
+	default:
+		log("ssh_gssapi_do_child: Unknown mechanism");
+	}
+}
+
+int
+ssh_gssapi_userok(char *user)
+{
+	if (gssapi_client_name.length==0 || 
+	    gssapi_client_name.value==NULL) {
+		debug("No suitable client data");
+		return 0;
+	}
+	switch (gssapi_client_type) {
+#ifdef KRB5
+	case GSS_KERBEROS:
+		return(ssh_gssapi_krb5_userok(user));
+		break; /* Not reached */
+#endif
+#ifdef GSI
+	case GSS_GSI:
+		return(ssh_gssapi_gsi_userok(user));
+		break; /* Not reached */
+#endif /* GSI */
+	case GSS_LAST_ENTRY:
+		debug("Client not GSSAPI");
+		break;
+	default:
+		debug("Unknown client authentication type");
+	}
+	return(0);
+}
+
+int
+ssh_gssapi_localname(char **user)
+{
+    	*user = NULL;
+	if (gssapi_client_name.length==0 || 
+	    gssapi_client_name.value==NULL) {
+		debug("No suitable client data");
+		return(0);;
+	}
+	switch (gssapi_client_type) {
+#ifdef KRB5
+	case GSS_KERBEROS:
+		return(ssh_gssapi_krb5_localname(user));
+		break; /* Not reached */
+#endif
+#ifdef GSI
+	case GSS_GSI:
+		return(ssh_gssapi_gsi_localname(user));
+		break; /* Not reached */
+#endif /* GSI */
+	case GSS_LAST_ENTRY:
+		debug("Client not GSSAPI");
+		break;
+	default:
+		debug("Unknown client authentication type");
+	}
+	return(0);
+}
+
+/*
+ * Clean our environment on startup. This means removing any environment
+ * strings that might inadvertantly been in root's environment and 
+ * could cause serious security problems if we think we set them.
+ */
+void
+ssh_gssapi_clean_env(void)
+{
+  char *envstr;
+  int envstr_index;
+
+  
+   for (envstr_index = 0;
+       (envstr = delegation_env[envstr_index]) != NULL;
+       envstr_index++) {
+
+     if (getenv(envstr)) {
+       debug("Clearing environment variable %s", envstr);
+       gssapi_unsetenv(envstr);
+     }
+   }
+}
+
+/*
+ * Wrapper around unsetenv.
+ */
+static void
+gssapi_unsetenv(const char *var)
+{
+#ifdef HAVE_UNSETENV
+    unsetenv(var);
+
+#else /* !HAVE_UNSETENV */
+    extern char **environ;
+    char **p1 = environ;	/* New array list */
+    char **p2 = environ;	/* Current array list */
+    int len = strlen(var);
+
+    /*
+     * Walk through current environ array (p2) copying each pointer
+     * to new environ array (p1) unless the pointer is to the item
+     * we want to delete. Copy happens in place.
+     */
+    while (*p2) {
+	if ((strncmp(*p2, var, len) == 0) &&
+	    ((*p2)[len] == '=')) {
+	    /*
+	     * *p2 points at item to be deleted, just skip over it
+	     */
+	    p2++;
+	} else {
+	    /*
+	     * *p2 points at item we want to save, so copy it
+	     */
+	    *p1 = *p2;
+	    p1++;
+	    p2++;
+	}
+    }
+
+    /* And make sure new array is NULL terminated */
+    *p1 = NULL;
+#endif /* HAVE_UNSETENV */
+}
+
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/kex.c openssh-3.4p1-gsi/kex.c
--- openssh-3.4p1/kex.c	Tue Jun 25 18:19:13 2002
+++ openssh-3.4p1-gsi/kex.c	Mon Sep 30 12:13:26 2002
@@ -42,6 +42,10 @@
 #include "dispatch.h"
 #include "monitor.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 #define KEX_COOKIE_LEN	16
 
 /* Use privilege separation for sshd */
@@ -242,6 +246,11 @@
 	case DH_GEX_SHA1:
 		kexgex(kex);
 		break;
+#ifdef GSSAPI
+	case GSS_GRP1_SHA1:
+		kexgss(kex);
+		break;
+#endif
 	default:
 		fatal("Unsupported key exchange %d", kex->kex_type);
 	}
@@ -297,11 +306,15 @@
 {
 	k->name = match_list(client, server, NULL);
 	if (k->name == NULL)
-		fatal("no kex alg");
+		fatal("No key exchange algorithm");
 	if (strcmp(k->name, KEX_DH1) == 0) {
 		k->kex_type = DH_GRP1_SHA1;
 	} else if (strcmp(k->name, KEX_DHGEX) == 0) {
 		k->kex_type = DH_GEX_SHA1;
+#ifdef GSSAPI
+	} else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
+		k->kex_type = GSS_GRP1_SHA1;
+#endif
 	} else
 		fatal("bad kex alg %s", k->name);
 }
diff -Naur --exclude=autom4te.cache openssh-3.4p1/kex.h openssh-3.4p1-gsi/kex.h
--- openssh-3.4p1/kex.h	Thu Jun  6 14:48:16 2002
+++ openssh-3.4p1-gsi/kex.h	Mon Sep 30 12:13:26 2002
@@ -56,7 +56,8 @@
 
 enum kex_exchange {
 	DH_GRP1_SHA1,
-	DH_GEX_SHA1
+	DH_GEX_SHA1,
+	GSS_GRP1_SHA1
 };
 
 #define KEX_INIT_SENT	0x0001
@@ -94,6 +95,11 @@
 	Mac	mac;
 	Comp	comp;
 };
+
+struct KexOptions {
+	int	gss_deleg_creds;
+};
+
 struct Kex {
 	u_char	*session_id;
 	int	session_id_len;
@@ -107,11 +113,13 @@
 	Buffer	peer;
 	int	done;
 	int	flags;
+	char 	*host;
 	char	*client_version_string;
 	char	*server_version_string;
 	int	(*verify_host_key)(Key *);
 	Key	*(*load_host_key)(int);
 	int	(*host_key_index)(Key *);
+	struct  KexOptions options;
 };
 
 Kex	*kex_setup(char *[PROPOSAL_MAX]);
@@ -123,6 +131,9 @@
 
 void	 kexdh(Kex *);
 void	 kexgex(Kex *);
+#ifdef GSSAPI
+void	 kexgss(Kex *);
+#endif
 
 Newkeys *kex_get_newkeys(int);
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/kexgss.c openssh-3.4p1-gsi/kexgss.c
--- openssh-3.4p1/kexgss.c	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/kexgss.c	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2001,2002 Simon Wilkinson. 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 "includes.h"
+
+#ifdef GSSAPI
+
+#include <openssl/crypto.h>
+#include <openssl/bn.h>
+
+#include "xmalloc.h"
+#include "buffer.h"
+#include "bufaux.h"
+#include "kex.h"
+#include "log.h"
+#include "packet.h"
+#include "dh.h"
+#include "ssh2.h"
+#include "ssh-gss.h"
+#include "monitor_wrap.h"
+
+/* This is now the same as the DH hash ... */
+
+u_char *
+kex_gssapi_hash(
+    char *client_version_string,
+    char *server_version_string,
+    char *ckexinit, int ckexinitlen,
+    char *skexinit, int skexinitlen,
+    u_char *serverhostkeyblob, int sbloblen,
+    BIGNUM *client_dh_pub,
+    BIGNUM *server_dh_pub,
+    BIGNUM *shared_secret)
+{
+	Buffer b;
+	static u_char digest[EVP_MAX_MD_SIZE];
+	EVP_MD *evp_md = EVP_sha1();
+	EVP_MD_CTX md;
+
+	buffer_init(&b);
+	buffer_put_string(&b, client_version_string, strlen(client_version_string));
+	buffer_put_string(&b, server_version_string, strlen(server_version_string));
+
+	/* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
+	buffer_put_int(&b, ckexinitlen+1);
+	buffer_put_char(&b, SSH2_MSG_KEXINIT);
+	buffer_append(&b, ckexinit, ckexinitlen);
+	buffer_put_int(&b, skexinitlen+1);
+	buffer_put_char(&b, SSH2_MSG_KEXINIT);
+	buffer_append(&b, skexinit, skexinitlen);
+
+	buffer_put_string(&b, serverhostkeyblob, sbloblen);
+	buffer_put_bignum2(&b, client_dh_pub);
+	buffer_put_bignum2(&b, server_dh_pub);
+	buffer_put_bignum2(&b, shared_secret);
+
+#ifdef DEBUG_KEX
+	buffer_dump(&b);
+#endif
+	EVP_DigestInit(&md, evp_md);
+	EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
+	EVP_DigestFinal(&md, digest, NULL);
+
+	buffer_free(&b);
+
+#ifdef DEBUG_KEX
+	dump_digest("hash", digest, evp_md->md_size);
+#endif
+	return digest;
+}
+
+void
+kexgss_client(Kex *kex)
+{
+	gss_buffer_desc gssbuf,send_tok,recv_tok, msg_tok, *token_ptr;
+	Gssctxt *ctxt;
+	OM_uint32 maj_status, min_status, ret_flags;
+	unsigned int klen, kout;
+	DH *dh; 
+	BIGNUM *dh_server_pub = 0;
+	BIGNUM *shared_secret = 0;	
+	unsigned char *kbuf;
+	unsigned char *hash;
+	unsigned char *serverhostkey;
+	int type = 0;
+	int first = 1;
+	int slen = 0;
+	
+	/* Initialise our GSSAPI world */
+	ssh_gssapi_build_ctx(&ctxt);
+	if (ssh_gssapi_id_kex(ctxt,kex->name)==NULL) {
+		fatal("Couldn't identify host exchange");
+	}
+	if (ssh_gssapi_import_name(ctxt,kex->host)) {
+		fatal("Couldn't import hostname ");
+	}
+	
+	/* This code should match that in ssh_dh1_client */
+		
+	/* Step 1 - e is dh->pub_key */
+	dh = dh_new_group1();
+	dh_gen_key(dh, kex->we_need * 8);
+
+	/* This is f, we initialise it now to make life easier */
+    	dh_server_pub = BN_new();
+    	if (dh_server_pub == NULL) {
+    		fatal("dh_server_pub == NULL");
+    	}
+    		
+	token_ptr = GSS_C_NO_BUFFER;
+			 
+	do {
+		debug("Calling gss_init_sec_context");
+		
+		maj_status=ssh_gssapi_init_ctx(ctxt,
+					       kex->options.gss_deleg_creds,
+					       token_ptr,&send_tok,
+					       &ret_flags);
+
+		if (GSS_ERROR(maj_status)) {
+			fatal("gss_init_context failed");
+		} 
+
+		/* If we've got an old receive buffer get rid of it */
+		if (token_ptr != GSS_C_NO_BUFFER)
+	  		(void) gss_release_buffer(&min_status, &recv_tok);
+ 	
+		
+		if (maj_status == GSS_S_COMPLETE) {
+			/* If mutual state flag is not true, kex fails */
+			if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
+				fatal("Mutual authentication failed");
+			}
+			/* If integ avail flag is not true kex fails */
+			if (!(ret_flags & GSS_C_INTEG_FLAG)) {
+				fatal("Integrity check failed");
+			}
+		}
+		
+		/* If we have data to send, then the last message that we
+		 * received cannot have been a 'complete'. */
+		if (send_tok.length !=0) {
+			if (first) {
+				packet_start(SSH2_MSG_KEXGSS_INIT);
+				packet_put_string(send_tok.value,
+					  	  send_tok.length);
+				packet_put_bignum2(dh->pub_key);
+				first=0;
+			} else {
+				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+				packet_put_string(send_tok.value,
+						  send_tok.length);
+			}
+			packet_send();
+			packet_write_wait();
+
+			
+			/* If we've sent them data, they'd better be polite
+			 * and reply. */
+		
+			type = packet_read();
+			switch (type) {
+			case SSH2_MSG_KEXGSS_HOSTKEY:
+				debug("Received KEXGSS_HOSTKEY");
+				serverhostkey=packet_get_string(&slen);
+				break;
+			case SSH2_MSG_KEXGSS_CONTINUE:
+				debug("Received GSSAPI_CONTINUE");
+				if (maj_status == GSS_S_COMPLETE) 
+					fatal("GSSAPI Continue received from server when complete");
+				recv_tok.value=packet_get_string(&slen);
+				recv_tok.length=slen; /* int vs. size_t */
+				break;
+			case SSH2_MSG_KEXGSS_COMPLETE:
+				debug("Received GSSAPI_COMPLETE");
+			        packet_get_bignum2(dh_server_pub);
+			    	msg_tok.value=packet_get_string(&slen);
+				msg_tok.length=slen; /* int vs. size_t */
+
+				/* Is there a token included? */
+				if (packet_get_char()) {
+					recv_tok.value=
+					    packet_get_string(&slen);
+					recv_tok.length=slen; /* int/size_t */
+					/* If we're already complete - protocol error */
+					if (maj_status == GSS_S_COMPLETE)
+						packet_disconnect("Protocol error: received token when complete");
+				} else {
+				   	/* No token included */
+				   	if (maj_status != GSS_S_COMPLETE)
+				   		packet_disconnect("Protocol error: did not receive final token");
+				}
+				break;
+			default:
+				packet_disconnect("Protocol error: didn't expect packet type %d",
+		    		type);
+			}
+			token_ptr=&recv_tok;
+		}
+
+    	} while (maj_status & GSS_S_CONTINUE_NEEDED);
+    	
+    	/* We _must_ have received a COMPLETE message in reply from the 
+    	 * server, which will have set dh_server_pub and msg_tok */
+    	 
+    	if (type!=SSH2_MSG_KEXGSS_COMPLETE)
+    	   fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
+    	 	    	
+	/* Check f in range [1, p-1] */
+        if (!dh_pub_is_valid(dh, dh_server_pub))
+                        packet_disconnect("bad server public DH value");
+                        
+        /* compute K=f^x mod p */
+        klen = DH_size(dh);
+        kbuf = xmalloc(klen);
+        kout = DH_compute_key(kbuf, dh_server_pub, dh);
+        
+        shared_secret = BN_new();
+        BN_bin2bn(kbuf,kout, shared_secret);
+        memset(kbuf, 0, klen);
+        xfree(kbuf);
+        
+	slen=0;
+        hash = kex_gssapi_hash(
+ 	    kex->client_version_string,
+            kex->server_version_string,
+            buffer_ptr(&kex->my), buffer_len(&kex->my),
+            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+            serverhostkey, slen, /* server host key */
+            dh->pub_key,	/* e */
+            dh_server_pub,	/* f */
+            shared_secret	/* K */
+        );
+        
+        gssbuf.value=hash;
+        gssbuf.length=20;
+        
+        /* Verify that H matches the token we just got. */
+                if ((maj_status = gss_verify_mic(&min_status,
+        	       		         ctxt->context,
+        	                         &gssbuf,
+        	                         &msg_tok,
+        	                         NULL))) {
+
+		packet_disconnect("Hash's MIC didn't verify");
+      	}	
+        
+        DH_free(dh);
+       	ssh_gssapi_delete_ctx(&ctxt);
+        /* save session id */
+        if (kex->session_id == NULL) {
+        	kex->session_id_len = 20;
+        	kex->session_id = xmalloc(kex->session_id_len);
+        	memcpy(kex->session_id, hash, kex->session_id_len);
+        }
+        
+	kex_derive_keys(kex, hash, shared_secret);
+	BN_clear_free(shared_secret);
+        kex_finish(kex);
+}
+
+
+
+
+void
+kexgss_server(Kex *kex)
+{
+
+	OM_uint32 maj_status, min_status;
+	
+	/* Some GSSAPI implementations use the input value of ret_flags (an
+ 	 * output variable) as a means of triggering mechanism specific 
+ 	 * features. Initializing it to zero avoids inadvertently 
+ 	 * activating this non-standard behaviour.*/
+
+	OM_uint32 ret_flags = 0;
+	gss_buffer_desc gssbuf,send_tok,recv_tok,msg_tok;
+	Gssctxt *ctxt = NULL;
+        unsigned int klen, kout;
+        unsigned char *kbuf;
+        unsigned char *hash;
+        DH *dh;
+        BIGNUM *shared_secret = NULL;
+        BIGNUM *dh_client_pub = NULL;
+	int type =0;
+	gss_OID oid;
+	u_int slen;
+	
+	/* Initialise GSSAPI */
+
+	debug2("%s: Identifying %s",__func__,kex->name);
+	oid=ssh_gssapi_id_kex(ctxt,kex->name);
+	if (oid==NULL) {
+	   packet_disconnect("Unknown gssapi mechanism");
+	}
+	
+	debug2("%s: Acquiring credentials",__func__);
+	
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid))))
+	   packet_disconnect("Unable to acquire credentials for the server");
+
+	do {
+		debug("Wait SSH2_MSG_GSSAPI_INIT");
+		type = packet_read();
+		switch(type) {
+		case SSH2_MSG_KEXGSS_INIT:
+			if (dh_client_pub!=NULL) 
+				packet_disconnect("Received KEXGSS_INIT after initialising");
+			recv_tok.value=packet_get_string(&slen);
+			recv_tok.length=slen; /* int vs. size_t */
+
+		        dh_client_pub = BN_new();
+		        
+		        if (dh_client_pub == NULL)
+        			fatal("dh_client_pub == NULL");
+		  	packet_get_bignum2(dh_client_pub);
+		  	
+		  	/* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
+			break;
+		case SSH2_MSG_KEXGSS_CONTINUE:
+			if (dh_client_pub == NULL)
+				packet_disconnect("Received KEXGSS_CONTINUE without initialising");
+			recv_tok.value=packet_get_string(&slen);
+			recv_tok.length=slen; /* int vs. size_t */
+			break;
+		default:
+			packet_disconnect("Protocol error: didn't expect packet type %d",
+					   type);
+		}
+		
+		maj_status=PRIVSEP(ssh_gssapi_accept_ctx(ctxt,&recv_tok, 
+							 &send_tok, &ret_flags));
+
+		gss_release_buffer(&min_status,&recv_tok);
+
+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
+                if (ret_flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG) {
+                        packet_disconnect("Limited proxy is not allowed in gssapi key exchange.");
+                }
+#endif
+		
+		if (maj_status & GSS_S_CONTINUE_NEEDED) {
+			debug("Sending GSSAPI_CONTINUE");
+			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+			packet_put_string(send_tok.value,send_tok.length);
+			packet_send();
+			packet_write_wait();
+			gss_release_buffer(&min_status, &send_tok);
+		}
+	} while (maj_status & GSS_S_CONTINUE_NEEDED);
+
+	if (GSS_ERROR(maj_status)) {
+		ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+		packet_disconnect("gssapi key exchange handshake failed");
+	}
+
+	debug("gss_complete");
+	if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
+		ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+		packet_disconnect("gssapi mutual authentication failed");
+	}
+		
+	if (!(ret_flags & GSS_C_INTEG_FLAG)) {
+		ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+		packet_disconnect("gssapi channel integrity not established");
+	}		
+	
+	dh = dh_new_group1();
+	dh_gen_key(dh, kex->we_need * 8);
+	
+        if (!dh_pub_is_valid(dh, dh_client_pub))
+                packet_disconnect("bad client public DH value");
+
+        klen = DH_size(dh);
+        kbuf = xmalloc(klen); 
+        kout = DH_compute_key(kbuf, dh_client_pub, dh);
+
+	shared_secret = BN_new();
+	BN_bin2bn(kbuf, kout, shared_secret);
+	memset(kbuf, 0, klen);
+	xfree(kbuf);
+	
+        hash = kex_gssapi_hash(
+            kex->client_version_string,
+            kex->server_version_string,
+            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+            buffer_ptr(&kex->my), buffer_len(&kex->my),
+            NULL, 0, /* Change this if we start sending host keys */
+            dh_client_pub,
+            dh->pub_key,
+            shared_secret
+	);
+	BN_free(dh_client_pub);
+		
+	if (kex->session_id == NULL) {
+		kex->session_id_len = 20;
+		kex->session_id = xmalloc(kex->session_id_len);
+		memcpy(kex->session_id, hash, kex->session_id_len);
+	}
+	                        
+	gssbuf.value = hash;
+	gssbuf.length = 20; /* Hashlen appears to always be 20 */
+	
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
+		ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
+		packet_disconnect("Couldn't get MIC");
+	}
+	
+	packet_start(SSH2_MSG_KEXGSS_COMPLETE);
+	packet_put_bignum2(dh->pub_key);
+	packet_put_string((char *)msg_tok.value,msg_tok.length);
+
+	if (send_tok.length!=0) {
+		packet_put_char(1); /* true */
+		packet_put_string((char *)send_tok.value,send_tok.length);
+	} else {
+		packet_put_char(0); /* false */
+	}
+ 	packet_send();
+	packet_write_wait();
+
+        /* We used to store the client name and credentials here for later
+         * use. With privsep, its easier to do this as a by product of the
+         * call to accept_context, which stores delegated information when
+         * the context is complete */
+         
+	gss_release_buffer(&min_status, &send_tok);	
+
+	/* If we've got a context, delete it. It may be NULL if we've been
+	 * using privsep */
+	ssh_gssapi_delete_ctx(&ctxt);
+	
+	DH_free(dh);
+
+	kex_derive_keys(kex, hash, shared_secret);
+	BN_clear_free(shared_secret);
+	kex_finish(kex);
+}
+
+void 
+kexgss(Kex *kex)
+{
+	if (kex->server)
+		kexgss_server(kex);
+	else
+		kexgss_client(kex);
+}
+
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/key.c openssh-3.4p1-gsi/key.c
--- openssh-3.4p1/key.c	Sun Jun 23 16:21:31 2002
+++ openssh-3.4p1-gsi/key.c	Mon Sep 30 12:13:26 2002
@@ -647,6 +647,8 @@
 		return KEY_RSA;
 	} else if (strcmp(name, "ssh-dss") == 0) {
 		return KEY_DSA;
+	} else if (strcmp(name, "null") == 0){
+		return KEY_NULL;
 	}
 	debug2("key_type_from_name: unknown key type '%s'", name);
 	return KEY_UNSPEC;
diff -Naur --exclude=autom4te.cache openssh-3.4p1/key.h openssh-3.4p1-gsi/key.h
--- openssh-3.4p1/key.h	Thu Mar 21 19:45:55 2002
+++ openssh-3.4p1-gsi/key.h	Mon Sep 30 12:13:26 2002
@@ -34,6 +34,7 @@
 	KEY_RSA1,
 	KEY_RSA,
 	KEY_DSA,
+	KEY_NULL,
 	KEY_UNSPEC
 };
 enum fp_type {
diff -Naur --exclude=autom4te.cache openssh-3.4p1/log.c openssh-3.4p1-gsi/log.c
--- openssh-3.4p1/log.c	Tue Feb 26 11:52:15 2002
+++ openssh-3.4p1-gsi/log.c	Mon Sep 30 12:13:26 2002
@@ -367,7 +367,7 @@
 		vsnprintf(msgbuf, sizeof(msgbuf), fmt, args);
 	}
 	if (log_on_stderr) {
-		fprintf(stderr, "%s\r\n", msgbuf);
+		fprintf(stderr, "%d: %s\r\n", getpid(), msgbuf);
 	} else {
 		openlog(argv0 ? argv0 : __progname, LOG_PID, log_facility);
 		syslog(pri, "%.500s", msgbuf);
diff -Naur --exclude=autom4te.cache openssh-3.4p1/makegssname.pl openssh-3.4p1-gsi/makegssname.pl
--- openssh-3.4p1/makegssname.pl	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/makegssname.pl	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,46 @@
+#!/usr/bin/perl
+
+use Convert::ASN1 qw(:tag);
+use Digest::MD5 qw(md5);
+use MIME::Base64;
+ 
+$oid=shift;
+$encoded=encode_object_id($oid);
+
+@entries=unpack("C*",$encoded);
+shift @entries; # Get rid of the NULL
+
+print "DER representation: ";
+foreach $entry (@entries) {
+  print "\\x";
+  printf "%02X",$entry;
+}
+print "\n";
+
+$digest = md5($encoded);
+# We only want the first 10 characters;
+# Conversations with the authors suggest that we want to use all of the
+# characters of the digest.
+#$digest = substr($digest,0,10);
+print "gsskeyex representation: ",encode_base64($digest),"\n";
+
+sub encode_object_id {
+  $string="";
+
+  my @data = ($_[0] =~ /(\d+)/g);
+
+  if(@data < 2) {
+      @data = (0);
+  }
+  else {
+      my $first = $data[1] + ($data[0] * 40);
+      splice(@data,0,2,$first);
+  }
+
+#  my $l = length $string;
+  $string .= pack("cw*", 0, @data);
+#  substr($string,$l,1) = asn_encode_length(length($string) - $l - 1);
+  return $string;
+}
+
+
diff -Naur --exclude=autom4te.cache openssh-3.4p1/monitor.c openssh-3.4p1-gsi/monitor.c
--- openssh-3.4p1/monitor.c	Wed Jun 26 08:27:11 2002
+++ openssh-3.4p1-gsi/monitor.c	Mon Sep 30 12:13:26 2002
@@ -59,6 +59,11 @@
 #include "ssh2.h"
 #include "mpaux.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+static Gssctxt *gsscontext = NULL;
+#endif
+
 /* Imports */
 extern ServerOptions options;
 extern u_int utmp_len;
@@ -120,6 +125,18 @@
 int mm_answer_pam_start(int, Buffer *);
 #endif
 
+#ifdef GSSAPI
+int mm_answer_gss_setup_ctx(int, Buffer *);
+int mm_answer_gss_accept_ctx(int, Buffer *);
+int mm_answer_gss_userok(int, Buffer *);
+int mm_answer_gss_localname(int, Buffer *);
+int mm_answer_gss_sign(int, Buffer *);
+#endif
+
+#ifdef GSI
+int mm_answer_gsi_gridmap(int, Buffer *);
+#endif
+
 static Authctxt *authctxt;
 static BIGNUM *ssh1_challenge = NULL;	/* used for ssh1 rsa auth */
 
@@ -150,12 +167,12 @@
 struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli},
     {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign},
-    {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow},
+    {MONITOR_REQ_PWNAM, MON_AUTH, mm_answer_pwnamallow},
     {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv},
     {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner},
     {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword},
 #ifdef USE_PAM
-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
 #endif
 #ifdef BSD_AUTH
     {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
@@ -165,12 +182,24 @@
     {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
     {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
 #endif
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+    {MONITOR_REQ_GSSLOCALNAME, MON_AUTH, mm_answer_gss_localname},
+#endif
     {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
     {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
     {0, 0, NULL}
 };
 
 struct mon_table mon_dispatch_postauth20[] = {
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+#endif
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
     {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -196,13 +225,27 @@
     {MONITOR_REQ_SKEYQUERY, MON_ISAUTH, mm_answer_skeyquery},
     {MONITOR_REQ_SKEYRESPOND, MON_AUTH, mm_answer_skeyrespond},
 #endif
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+#endif
+#ifdef GSI
+    {MONITOR_REQ_GSIGRIDMAP, MON_PERMIT, mm_answer_gsi_gridmap},
+#endif
 #ifdef USE_PAM
-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
 #endif
     {0, 0, NULL}
 };
 
 struct mon_table mon_dispatch_postauth15[] = {
+#ifdef GSSAPI
+    {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx},
+    {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
+    {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
+#endif
     {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
     {MONITOR_REQ_TERM, 0, mm_answer_term},
@@ -254,10 +297,22 @@
 		/* Permit requests for moduli and signatures */
 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
+#ifdef GSSAPI		
+		/* and for the GSSAPI key exchange */
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+#endif
 	} else {
 		mon_dispatch = mon_dispatch_proto15;
 
 		monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
+#ifdef GSSAPI		
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
+#endif
+#ifdef GSI
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSIGRIDMAP, 1);
+#endif
 	}
 
 	authctxt = authctxt_new();
@@ -496,13 +551,11 @@
 
 	debug3("%s", __func__);
 
-	if (authctxt->attempt++ != 0)
-		fatal("%s: multiple attempts for getpwnam", __func__);
-
 	login = buffer_get_string(m, NULL);
 
 	pwent = getpwnamallow(login);
 
+	if (authctxt->user) xfree(authctxt->user);
 	authctxt->user = xstrdup(login);
 	setproctitle("%s [priv]", pwent ? login : "unknown");
 	xfree(login);
@@ -1540,3 +1593,148 @@
 	mon->m_recvfd = pair[0];
 	mon->m_sendfd = pair[1];
 }
+
+#ifdef GSSAPI
+
+int
+mm_answer_gss_setup_ctx(int socket, Buffer *m) {
+        gss_OID_desc oid;
+        OM_uint32 major;
+	int len;
+
+        oid.elements=buffer_get_string(m,&len);
+	oid.length=len;
+                
+        major=ssh_gssapi_server_ctx(&gsscontext,&oid);
+
+        xfree(oid.elements);
+
+        buffer_clear(m);
+        buffer_put_int(m,major);
+
+        mm_request_send(socket,MONITOR_ANS_GSSSETUP,m);
+
+        return(0);
+}
+
+int
+mm_answer_gss_accept_ctx(int socket, Buffer *m) {
+        gss_buffer_desc in,out;
+        OM_uint32 major,minor;
+        OM_uint32 flags = 0; /* GSI needs this */
+
+        in.value = buffer_get_string(m,&in.length);
+        major=ssh_gssapi_accept_ctx(gsscontext,&in,&out,&flags);
+        xfree(in.value);
+
+        buffer_clear(m);
+        buffer_put_int(m, major);
+        buffer_put_string(m, out.value, out.length);
+        buffer_put_int(m, flags);
+        mm_request_send(socket,MONITOR_ANS_GSSSTEP,m);
+
+        gss_release_buffer(&minor, &out);
+
+        return(0);
+}
+int
+mm_answer_gss_userok(int socket, Buffer *m) {
+	int authenticated;
+
+        authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
+
+        buffer_clear(m);
+        buffer_put_int(m, authenticated);
+
+        debug3("%s: sending result %d", __func__, authenticated);
+        mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m);
+
+	auth_method="gssapi";
+	
+        /* Monitor loop will terminate if authenticated */
+        return(authenticated);
+}
+int
+mm_answer_gss_localname(int socket, Buffer *m) {
+	char *name;
+
+	ssh_gssapi_localname(&name);
+
+        buffer_clear(m);
+	if (name) {
+	    buffer_put_cstring(m, name);
+	    debug3("%s: sending result %s", __func__, name);
+	    xfree(name);
+	} else {
+	    buffer_put_cstring(m, "");
+	    debug3("%s: sending result \"\"", __func__);
+	}
+
+        mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m);
+
+        return(0);
+}
+
+int
+mm_answer_gss_sign(int socket, Buffer *m) {
+        gss_buffer_desc data,hash;
+        OM_uint32 major,minor;
+
+        data.value = buffer_get_string(m,&data.length);
+        if (data.length != 16) {  /* HACK - i.e. we are using SSHv1 */
+        if (data.length != 20)
+                fatal("%s: data length incorrect: %d", __func__, data.length);
+
+        /* Save the session ID - only first time round */
+        if (session_id2_len == 0) {
+                session_id2_len=data.length;
+                session_id2 = xmalloc(session_id2_len);
+                memcpy(session_id2, data.value, session_id2_len);
+        }
+        } /* HACK - end */
+        major=ssh_gssapi_sign(gsscontext, &data, &hash);
+
+        xfree(data.value);
+
+        buffer_clear(m);
+        buffer_put_int(m, major);
+        buffer_put_string(m, hash.value, hash.length);
+
+        mm_request_send(socket,MONITOR_ANS_GSSSIGN,m);
+
+        gss_release_buffer(&minor,&hash);
+
+	/* Turn on permissions for getpwnam */
+	monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
+	
+        return(0);
+}
+
+#endif /* GSSAPI */
+
+#ifdef GSI
+
+int
+mm_answer_gsi_gridmap(int socket, Buffer *m) {
+    char *subject, *name;
+
+    subject = buffer_get_string(m, NULL);
+    
+    gsi_gridmap(subject, &name);
+
+    buffer_clear(m);
+    if (name) {
+	buffer_put_cstring(m, name);
+	debug3("%s: sending result %s", __func__, name);
+	xfree(name);
+    } else {
+	buffer_put_cstring(m, "");
+	debug3("%s: sending result \"\"", __func__);
+    }
+
+    mm_request_send(socket, MONITOR_ANS_GSIGRIDMAP, m);
+
+    return(0);
+}
+
+#endif /* GSI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/monitor.h openssh-3.4p1-gsi/monitor.h
--- openssh-3.4p1/monitor.h	Tue Jun 11 11:42:49 2002
+++ openssh-3.4p1-gsi/monitor.h	Mon Sep 30 12:13:26 2002
@@ -39,6 +39,12 @@
 	MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
 	MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
 	MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+	MONITOR_REQ_GSSSETUP,MONITOR_ANS_GSSSETUP,
+	MONITOR_REQ_GSSSTEP,MONITOR_ANS_GSSSTEP,
+	MONITOR_REQ_GSSSIGN,MONITOR_ANS_GSSSIGN,
+	MONITOR_REQ_GSSUSEROK,MONITOR_ANS_GSSUSEROK,
+	MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME,
+	MONITOR_REQ_GSIGRIDMAP,MONITOR_ANS_GSIGRIDMAP,
 	MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
 	MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
 	MONITOR_REQ_KEYEXPORT,
diff -Naur --exclude=autom4te.cache openssh-3.4p1/monitor_wrap.c openssh-3.4p1-gsi/monitor_wrap.c
--- openssh-3.4p1/monitor_wrap.c	Thu Jun 20 19:43:43 2002
+++ openssh-3.4p1-gsi/monitor_wrap.c	Mon Sep 30 12:13:26 2002
@@ -51,6 +51,10 @@
 #include "channels.h"
 #include "session.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* Imports */
 extern int compat20;
 extern Newkeys *newkeys[];
@@ -937,3 +941,137 @@
 
 	return (success);
 }
+#ifdef GSSAPI
+OM_uint32
+mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
+        Buffer m;
+        OM_uint32 major;
+                
+        /* Client doesn't get to see the context */
+        *ctx=NULL;
+
+        buffer_init(&m);
+        buffer_put_string(&m,oid->elements,oid->length);
+
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSSSETUP",__func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
+        major=buffer_get_int(&m);
+
+        return(major);
+}
+
+OM_uint32
+mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
+                         gss_buffer_desc *out, OM_uint32 *flags) {
+
+        Buffer m;
+        OM_uint32 major;
+
+        buffer_init(&m);
+        buffer_put_string(&m, in->value, in->length);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSSSTEP", __func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
+
+        major=buffer_get_int(&m);
+        out->value=buffer_get_string(&m,&out->length);
+        if (flags) *flags=buffer_get_int(&m);
+
+        return(major);
+}
+
+int
+mm_ssh_gssapi_userok(char *user) {
+        Buffer m;
+        int authenticated = 0;
+
+        buffer_init(&m);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSSUSEROK", __func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
+                                  &m);
+
+        authenticated = buffer_get_int(&m);
+
+        buffer_free(&m);
+        debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
+        return(authenticated);
+}
+
+int
+mm_ssh_gssapi_localname(char **lname)
+{
+        Buffer m;
+
+	buffer_init(&m);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
+                                  &m);
+
+	*lname = buffer_get_string(&m, NULL);
+
+        buffer_free(&m);
+	if (lname[0] == '\0') {
+	    debug3("%s: gssapi identity mapping failed", __func__);
+	} else {
+	    debug3("%s: gssapi identity mapped to %s", __func__, *lname);
+	}
+	
+        return(0);
+}
+
+OM_uint32
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
+        Buffer m;
+        OM_uint32 major;
+
+        buffer_init(&m);
+        buffer_put_string(&m, data->value, data->length);
+
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSSSIGN",__func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+        major=buffer_get_int(&m);
+        hash->value = buffer_get_string(&m, &hash->length);
+
+        return(major);
+}
+#endif /* GSSAPI */
+
+#ifdef GSI
+
+int mm_gsi_gridmap(char *subject_name, char **lname)
+{
+        Buffer m;
+
+	buffer_init(&m);
+	buffer_put_cstring(&m, subject_name);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSIGRIDMAP, &m);
+
+        debug3("%s: waiting for MONITOR_ANS_GSIGRIDMAP", __func__);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSIGRIDMAP,
+                                  &m);
+
+	*lname = buffer_get_string(&m, NULL);
+
+        buffer_free(&m);
+	if (lname[0] == '\0') {
+	    debug3("%s: gssapi identity %s mapping failed", __func__,
+		   subject_name);
+	} else {
+	    debug3("%s: gssapi identity %s mapped to %s", __func__,
+		   subject_name, *lname);
+	}
+	
+        return(0);
+    
+}
+
+#endif /* GSI */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/monitor_wrap.h openssh-3.4p1-gsi/monitor_wrap.h
--- openssh-3.4p1/monitor_wrap.h	Sun May 12 20:07:42 2002
+++ openssh-3.4p1-gsi/monitor_wrap.h	Mon Sep 30 12:13:26 2002
@@ -59,6 +59,21 @@
 void mm_start_pam(char *);
 #endif
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **ctxt, gss_OID oid);
+OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *ctxt, gss_buffer_desc *recv,
+				   gss_buffer_desc *send, OM_uint32 *flags);
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *ctxt, gss_buffer_desc *buffer,
+			     gss_buffer_desc *hash);
+int mm_ssh_gssapi_userok(char *user);
+int mm_ssh_gssapi_localname(char **user);
+#endif
+
+#ifdef GSI
+int mm_gsi_gridmap(char *subject_name, char **mapped_name);
+#endif
+
 void mm_terminate(void);
 int mm_pty_allocate(int *, int *, char *, int);
 void mm_session_pty_cleanup2(void *);
diff -Naur --exclude=autom4te.cache openssh-3.4p1/openbsd-compat/bsd-misc.h openssh-3.4p1-gsi/openbsd-compat/bsd-misc.h
--- openssh-3.4p1/openbsd-compat/bsd-misc.h	Thu Jun 13 16:34:58 2002
+++ openssh-3.4p1-gsi/openbsd-compat/bsd-misc.h	Mon Sep 30 12:13:26 2002
@@ -29,6 +29,7 @@
 
 #include "config.h"
 
+#define get_progname bsd_get_progname
 char *get_progname(char *argv0);
 
 #ifndef HAVE_SETSID
diff -Naur --exclude=autom4te.cache openssh-3.4p1/packet.c openssh-3.4p1-gsi/packet.c
--- openssh-3.4p1/packet.c	Sun Jun 23 16:49:25 2002
+++ openssh-3.4p1-gsi/packet.c	Mon Sep 30 12:13:26 2002
@@ -1159,6 +1159,13 @@
 	return buffer_get_string(&incoming_packet, length_ptr);
 }
 
+/* Clears incoming data buffer */
+
+void packet_get_all(void)
+{
+  buffer_clear(&incoming_packet);
+}
+
 /*
  * Sends a diagnostic message from the server to the client.  This message
  * can be sent at any time (but not while constructing another message). The
diff -Naur --exclude=autom4te.cache openssh-3.4p1/packet.h openssh-3.4p1-gsi/packet.h
--- openssh-3.4p1/packet.h	Thu Jun 20 19:43:43 2002
+++ openssh-3.4p1-gsi/packet.h	Mon Sep 30 12:13:26 2002
@@ -54,6 +54,7 @@
 void     packet_get_bignum2(BIGNUM * value);
 void	*packet_get_raw(int *length_ptr);
 void	*packet_get_string(u_int *length_ptr);
+void	packet_get_all(void);
 void     packet_disconnect(const char *fmt,...) __attribute__((format(printf, 1, 2)));
 void     packet_send_debug(const char *fmt,...) __attribute__((format(printf, 1, 2)));
 
diff -Naur --exclude=autom4te.cache openssh-3.4p1/readconf.c openssh-3.4p1-gsi/readconf.c
--- openssh-3.4p1/readconf.c	Thu Jun 20 19:41:52 2002
+++ openssh-3.4p1-gsi/readconf.c	Mon Sep 30 12:13:26 2002
@@ -97,6 +97,12 @@
 #if defined(KRB4) || defined(KRB5)
 	oKerberosAuthentication,
 #endif
+#ifdef GSSAPI
+	oGssAuthentication, oGssDelegateCreds,
+#ifdef GSI
+	oGssGlobusDelegateLimitedCreds,
+#endif /* GSI */
+#endif /* GSSAPI */
 #if defined(AFS) || defined(KRB5)
 	oKerberosTgtPassing,
 #endif
@@ -143,6 +149,15 @@
 #if defined(KRB4) || defined(KRB5)
 	{ "kerberosauthentication", oKerberosAuthentication },
 #endif
+#ifdef GSSAPI
+	{ "gssapiauthentication", oGssAuthentication },
+	{ "gssapidelegatecredentials", oGssDelegateCreds },
+#ifdef GSI
+	/* For backwards compatability with old 1.2.27 client code */
+	{ "forwardgssapiglobusproxy", oGssDelegateCreds }, /* alias */
+	{ "forwardgssapiglobuslimitedproxy", oGssGlobusDelegateLimitedCreds },
+#endif /* GSI */
+#endif /* GSSAPI */
 #if defined(AFS) || defined(KRB5)
 	{ "kerberostgtpassing", oKerberosTgtPassing },
 #endif
@@ -362,6 +377,23 @@
 		intptr = &options->kerberos_authentication;
 		goto parse_flag;
 #endif
+#ifdef GSSAPI
+	case oGssAuthentication:
+		intptr = &options->gss_authentication;
+		goto parse_flag;
+      
+	case oGssDelegateCreds:
+		intptr = &options->gss_deleg_creds;
+		goto parse_flag;
+ 
+#ifdef GSI
+	case oGssGlobusDelegateLimitedCreds:
+		intptr = &options->gss_globus_deleg_limited_proxy;
+		goto parse_flag;
+#endif /* GSI */
+
+#endif /* GSSAPI */
+
 #if defined(AFS) || defined(KRB5)
 	case oKerberosTgtPassing:
 		intptr = &options->kerberos_tgt_passing;
@@ -747,6 +779,14 @@
 	options->rsa_authentication = -1;
 	options->pubkey_authentication = -1;
 	options->challenge_response_authentication = -1;
+#ifdef GSSAPI
+        options->gss_authentication = -1;
+        options->gss_deleg_creds = -1;
+#ifdef GSI
+        options->gss_globus_deleg_limited_proxy = -1;
+#endif /* GSI */
+#endif /* GSSAPI */
+
 #if defined(KRB4) || defined(KRB5)
 	options->kerberos_authentication = -1;
 #endif
@@ -823,6 +863,16 @@
 		options->pubkey_authentication = 1;
 	if (options->challenge_response_authentication == -1)
 		options->challenge_response_authentication = 1;
+#ifdef GSSAPI
+	if (options->gss_authentication == -1)
+		options->gss_authentication = 1;
+	if (options->gss_deleg_creds == -1)
+		options->gss_deleg_creds = 1;
+#ifdef GSI
+	if (options->gss_globus_deleg_limited_proxy == -1)
+		options->gss_globus_deleg_limited_proxy = 0;
+#endif /* GSI */
+#endif /* GSSAPI */
 #if defined(KRB4) || defined(KRB5)
 	if (options->kerberos_authentication == -1)
 		options->kerberos_authentication = 1;
diff -Naur --exclude=autom4te.cache openssh-3.4p1/readconf.h openssh-3.4p1-gsi/readconf.h
--- openssh-3.4p1/readconf.h	Sun Jun  9 15:04:03 2002
+++ openssh-3.4p1-gsi/readconf.h	Mon Sep 30 12:13:26 2002
@@ -47,6 +47,15 @@
 #if defined(AFS) || defined(KRB5)
 	int     kerberos_tgt_passing;	/* Try Kerberos TGT passing. */
 #endif
+
+#ifdef GSSAPI
+	int 	gss_authentication;
+	int	gss_deleg_creds;
+#ifdef GSI
+	int	gss_globus_deleg_limited_proxy;
+#endif /* GSI */
+#endif /* GSSAPI */
+
 #ifdef AFS
 	int     afs_token_passing;	/* Try AFS token passing. */
 #endif
@@ -77,6 +86,8 @@
 	char   *host_key_alias;	/* hostname alias for .ssh/known_hosts */
 	char   *proxy_command;	/* Proxy command for connecting the host. */
 	char   *user;		/* User to log in as. */
+	int    implicit;	/* Login user was not specified.
+				   Server may choose based on authctxt. */
 	int     escape_char;	/* Escape character; -2 = none */
 
 	char   *system_hostfile;/* Path for /etc/ssh/ssh_known_hosts. */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/servconf.c openssh-3.4p1-gsi/servconf.c
--- openssh-3.4p1/servconf.c	Mon Jun 24 22:22:04 2002
+++ openssh-3.4p1-gsi/servconf.c	Mon Sep 30 12:13:26 2002
@@ -17,7 +17,6 @@
 #endif
 #if defined(KRB5)
 #ifdef HEIMDAL
-#include <krb.h>
 #else
 /* Bodge - but then, so is using the kerberos IV KEYFILE to get a Kerberos V
  * keytab */
@@ -86,6 +85,12 @@
 	options->hostbased_uses_name_from_packet_only = -1;
 	options->rsa_authentication = -1;
 	options->pubkey_authentication = -1;
+#ifdef GSSAPI
+	options->gss_authentication=-1;
+	options->gss_keyex=-1;
+	options->gss_use_session_ccache = -1;
+	options->gss_cleanup_creds = -1;
+#endif
 #if defined(KRB4) || defined(KRB5)
 	options->kerberos_authentication = -1;
 	options->kerberos_or_local_passwd = -1;
@@ -199,6 +204,16 @@
 		options->rsa_authentication = 1;
 	if (options->pubkey_authentication == -1)
 		options->pubkey_authentication = 1;
+#ifdef GSSAPI
+	if (options->gss_authentication == -1)
+		options->gss_authentication = 1;
+	if (options->gss_keyex == -1)
+		options->gss_keyex =1;
+	if (options->gss_use_session_ccache == -1)
+		options->gss_use_session_ccache = 1;
+	if (options->gss_cleanup_creds == -1)
+		options->gss_cleanup_creds = 1;
+#endif
 #if defined(KRB4) || defined(KRB5)
 	if (options->kerberos_authentication == -1)
 		options->kerberos_authentication = 0;
@@ -277,6 +292,9 @@
 	sPort, sHostKeyFile, sServerKeyBits, sLoginGraceTime, sKeyRegenerationTime,
 	sPermitRootLogin, sLogFacility, sLogLevel,
 	sRhostsAuthentication, sRhostsRSAAuthentication, sRSAAuthentication,
+#ifdef GSSAPI
+	sGssAuthentication, sGssKeyEx, sGssUseSessionCredCache, sGssCleanupCreds,
+#endif
 #if defined(KRB4) || defined(KRB5)
 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
 #endif
@@ -327,6 +345,13 @@
 	{ "rsaauthentication", sRSAAuthentication },
 	{ "pubkeyauthentication", sPubkeyAuthentication },
 	{ "dsaauthentication", sPubkeyAuthentication },			/* alias */
+#ifdef GSSAPI
+	{ "gssapiauthentication", sGssAuthentication },
+	{ "gssapikeyexchange", sGssKeyEx },
+	{ "gssusesessionccache", sGssUseSessionCredCache },
+	{ "gssapiusesessioncredcache", sGssUseSessionCredCache },
+	{ "gssapicleanupcreds", sGssCleanupCreds },
+#endif
 #if defined(KRB4) || defined(KRB5)
 	{ "kerberosauthentication", sKerberosAuthentication },
 	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
@@ -641,6 +666,20 @@
 	case sPubkeyAuthentication:
 		intptr = &options->pubkey_authentication;
 		goto parse_flag;
+#ifdef GSSAPI
+	case sGssAuthentication:
+		intptr = &options->gss_authentication;
+		goto parse_flag;
+	case sGssKeyEx:
+		intptr = &options->gss_keyex;
+		goto parse_flag;
+	case sGssUseSessionCredCache:
+		intptr = &options->gss_use_session_ccache;
+		goto parse_flag;
+	case sGssCleanupCreds:
+		intptr = &options->gss_cleanup_creds;
+		goto parse_flag;
+#endif
 #if defined(KRB4) || defined(KRB5)
 	case sKerberosAuthentication:
 		intptr = &options->kerberos_authentication;
diff -Naur --exclude=autom4te.cache openssh-3.4p1/servconf.h openssh-3.4p1-gsi/servconf.h
--- openssh-3.4p1/servconf.h	Thu Jun 20 20:09:47 2002
+++ openssh-3.4p1-gsi/servconf.h	Mon Sep 30 12:13:26 2002
@@ -73,6 +73,13 @@
 	int     hostbased_uses_name_from_packet_only; /* experimental */
 	int     rsa_authentication;	/* If true, permit RSA authentication. */
 	int     pubkey_authentication;	/* If true, permit ssh2 pubkey authentication. */
+	#ifdef GSSAPI
+	int     gss_authentication;
+	int     gss_keyex;
+	int     gss_use_session_ccache;        /* If true, delegated credentials are
+	                                        * stored in a session specific cache */
+	int 	gss_cleanup_creds;	       /* If true, destroy cred cache on logout */
+#endif	
 #if defined(KRB4) || defined(KRB5)
 	int     kerberos_authentication;	/* If true, permit Kerberos
 						 * authentication. */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/session.c openssh-3.4p1-gsi/session.c
--- openssh-3.4p1/session.c	Wed Jun 26 08:51:06 2002
+++ openssh-3.4p1-gsi/session.c	Mon Sep 30 12:13:26 2002
@@ -58,6 +58,10 @@
 #include "session.h"
 #include "monitor_wrap.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 #ifdef HAVE_CYGWIN
 #include <windows.h>
 #include <sys/cygwin.h>
@@ -460,6 +464,12 @@
 
 	session_proctitle(s);
 
+#if defined(GSSAPI)
+	temporarily_use_uid(s->pw);
+	ssh_gssapi_storecreds();
+	restore_uid();
+#endif
+
 #if defined(USE_PAM)
 	do_pam_session(s->pw->pw_name, NULL);
 	do_pam_setcred(1);
@@ -578,6 +588,12 @@
 	ptyfd = s->ptyfd;
 	ttyfd = s->ttyfd;
 
+#if defined(GSSAPI)
+	temporarily_use_uid(s->pw);
+	ssh_gssapi_storecreds();
+	restore_uid();
+#endif
+
 #if defined(USE_PAM)
 	do_pam_session(s->pw->pw_name, s->tty);
 	do_pam_setcred(1);
@@ -826,7 +842,7 @@
  * Sets the value of the given variable in the environment.  If the variable
  * already exists, its value is overriden.
  */
-static void
+void
 child_set_env(char ***envp, u_int *envsizep, const char *name,
 	const char *value)
 {
@@ -953,6 +969,13 @@
 	copy_environment(environ, &env, &envsize);
 #endif
 
+#ifdef GSSAPI
+	/* Allow any GSSAPI methods that we've used to alter 
+	 * the childs environment as they see fit
+	 */
+	ssh_gssapi_do_child(&env,&envsize);
+#endif
+
 	if (!options.use_login) {
 		/* Set basic environment. */
 		child_set_env(&env, &envsize, "USER", pw->pw_name);
@@ -2034,4 +2057,7 @@
 do_authenticated2(Authctxt *authctxt)
 {
 	server_loop2(authctxt);
+#if defined(GSSAPI)
+	ssh_gssapi_cleanup_creds(NULL);
+#endif
 }
diff -Naur --exclude=autom4te.cache openssh-3.4p1/session.h openssh-3.4p1-gsi/session.h
--- openssh-3.4p1/session.h	Sun Jun 23 16:48:29 2002
+++ openssh-3.4p1-gsi/session.h	Mon Sep 30 12:13:26 2002
@@ -68,4 +68,7 @@
 Session	*session_by_tty(char *);
 void	 session_close(Session *);
 void	 do_setusercontext(struct passwd *);
+
+void	 child_set_env(char ***envp, u_int *envsizep, const char *name,
+		       const char *value);
 #endif
diff -Naur --exclude=autom4te.cache openssh-3.4p1/ssh-gss.h openssh-3.4p1-gsi/ssh-gss.h
--- openssh-3.4p1/ssh-gss.h	Wed Dec 31 18:00:00 1969
+++ openssh-3.4p1-gsi/ssh-gss.h	Mon Sep 30 12:13:26 2002
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2001,2002 Simon Wilkinson. 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.
+ */
+
+#ifndef _SSH_GSS_H
+#define _SSH_GSS_H
+
+#ifdef GSSAPI
+
+#include "kex.h"
+#include "buffer.h"
+
+#include <gssapi.h>
+
+#ifndef MECHGLUE
+#ifdef KRB5
+#ifndef HEIMDAL
+#include <gssapi_generic.h>
+
+/* MIT Kerberos doesn't seem to define GSS_NT_HOSTBASED_SERVICE */
+
+#ifndef GSS_C_NT_HOSTBASED_SERVICE
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif /* GSS_C_NT_... */
+#endif /* !HEIMDAL */
+#endif /* KRB5 */
+#endif /* !MECHGLUE */
+
+/* draft-ietf-secsh-gsskeyex-03 */
+#define SSH2_MSG_KEXGSS_INIT				30
+#define SSH2_MSG_KEXGSS_CONTINUE 			31
+#define SSH2_MSG_KEXGSS_COMPLETE 			32
+#define SSH2_MSG_KEXGSS_HOSTKEY				33
+#define SSH2_MSG_KEXGSS_ERROR				34
+#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE     		60
+#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN        		61
+#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE	63    
+#define SSH2_MSG_USERAUTH_GSSAPI_ERROR			64  
+
+#define KEX_GSS_SHA1					"gss-group1-sha1-"
+
+enum ssh_gss_id {
+#ifdef KRB5
+	GSS_KERBEROS,
+#endif
+#ifdef GSI
+	GSS_GSI,
+#endif /* GSI */
+	GSS_LAST_ENTRY
+};
+
+typedef struct ssh_gss_mech_struct {
+        char *enc_name;
+        char *name;
+        gss_OID_desc oid;
+} ssh_gssapi_mech;
+
+typedef struct {
+	OM_uint32	status; /* both */
+	gss_ctx_id_t	context; /* both */
+	gss_name_t	name; /* both */
+	gss_OID		oid; /* both */
+	gss_cred_id_t	creds; /* server */
+	gss_name_t	client; /* server */
+	gss_cred_id_t	client_creds; /* server */
+} Gssctxt;
+
+extern ssh_gssapi_mech supported_mechs[];
+extern gss_buffer_desc gssapi_client_name;
+extern gss_cred_id_t   gssapi_client_creds;
+extern enum ssh_gss_id gssapi_client_type;
+
+char *ssh_gssapi_mechanisms(int server, char *host);
+gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
+void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
+void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
+void ssh_gssapi_supported_oids(gss_OID_set *oidset);
+enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt);
+
+OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host);
+OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx);
+OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds,
+			      gss_buffer_desc *recv_tok, 
+			      gss_buffer_desc *send_tok, OM_uint32 *flags);
+OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,
+				gss_buffer_desc *recv_tok,
+				gss_buffer_desc *send_tok,
+				OM_uint32 *flags);
+OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx,
+				enum ssh_gss_id *type,
+				gss_buffer_desc *name,
+				gss_cred_id_t *creds);
+void ssh_gssapi_error(gss_OID mech,
+		      OM_uint32 major_status, OM_uint32 minor_status);
+void ssh_gssapi_send_error(gss_OID mech,
+			   OM_uint32 major_status,OM_uint32 minor_status);
+void ssh_gssapi_build_ctx(Gssctxt **ctx);
+void ssh_gssapi_delete_ctx(Gssctxt **ctx);
+OM_uint32 ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid,char *host);
+OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid);
+
+/* In the client */
+void ssh_gssapi_client(Kex *kex, char *host, struct sockaddr *hostaddr,
+                       Buffer *client_kexinit, Buffer *server_kexinit);
+
+/* In the server */
+int ssh_gssapi_userok(char *name);
+int ssh_gssapi_localname(char **lname);
+void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit, 
+		       Buffer *server_kexinit);
+
+OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, 
+					gss_buffer_desc *hash);
+
+void ssh_gssapi_do_child(char ***envp, u_int *envsizep);                 
+void ssh_gssapi_cleanup_creds(void *ignored);
+void ssh_gssapi_storecreds();
+void ssh_gssapi_clean_env();
+
+#ifdef GSI
+int gsi_gridmap(char *subject_name, char **mapped_name);
+#ifdef _HAVE_GSI_EXTENDED_GSSAPI
+#define HAVE_GSSAPI_EXT
+#endif
+#endif
+
+#ifdef MECHGLUE
+gss_cred_id_t __gss_get_mechanism_cred
+   (gss_cred_id_t,	/* union_cred */
+    gss_OID		/* mech_type */
+   );
+#ifndef _HAVE_GSI_EXTENDED_GSSAPI
+#define HAVE_GSSAPI_EXT
+OM_uint32 gss_export_cred
+    (OM_uint32 *,        /* minor_status */
+     const gss_cred_id_t,/* cred_handle */
+     const gss_OID,      /* desired mech */
+     OM_uint32,          /* option req */
+     gss_buffer_t);      /* output buffer */
+#endif
+#endif
+#endif /* GSSAPI */
+
+#endif /* _SSH_GSS_H */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/ssh.c openssh-3.4p1-gsi/ssh.c
--- openssh-3.4p1/ssh.c	Wed Jun 12 11:11:13 2002
+++ openssh-3.4p1-gsi/ssh.c	Mon Sep 30 12:13:26 2002
@@ -578,6 +578,34 @@
 			fatal("Can't open user config file %.100s: "
 			    "%.100s", config, strerror(errno));
 	} else  {
+	    /*
+	     * Since the config file parsing code aborts if it sees
+	     * options it doesn't recognize, allow users to put
+	     * options specific to compile-time add-ons in alternate
+	     * config files so their primary config file will
+	     * interoperate SSH versions that don't support those
+	     * options.
+	     */
+#ifdef GSSAPI
+		snprintf(buf, sizeof buf, "%.100s/%.100s.gssapi", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options);
+#ifdef GSI
+		snprintf(buf, sizeof buf, "%.100s/%.100s.gsi", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options);
+#endif
+#if defined(KRB4) || defined(KRB5)
+		snprintf(buf, sizeof buf, "%.100s/%.100s.krb", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options);
+#endif
+#ifdef AFS
+		snprintf(buf, sizeof buf, "%.100s/%.100s.afs", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options);
+#endif
+#endif
 		snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
 		    _PATH_SSH_USER_CONFFILE);
 		(void)read_config_file(buf, host, &options);
@@ -594,8 +622,11 @@
 
 	seed_rng();
 
-	if (options.user == NULL)
-		options.user = xstrdup(pw->pw_name);
+        if (options.user == NULL) {
+                options.user = xstrdup(pw->pw_name);
+                options.implicit = 1;
+        }
+        else options.implicit = 0;
 
 	if (options.hostname != NULL)
 		host = options.hostname;
diff -Naur --exclude=autom4te.cache openssh-3.4p1/ssh1.h openssh-3.4p1-gsi/ssh1.h
--- openssh-3.4p1/ssh1.h	Fri Jun  8 19:17:12 2001
+++ openssh-3.4p1-gsi/ssh1.h	Mon Sep 30 12:13:26 2002
@@ -70,6 +70,13 @@
 #define SSH_MSG_CHANNEL_INPUT_EOF	SSH_MSG_CHANNEL_CLOSE
 #define SSH_MSG_CHANNEL_OUTPUT_CLOSE	SSH_MSG_CHANNEL_CLOSE_CONFIRMATION
 
+/* GSS-API authentication */
+#define SSH_CMSG_AUTH_GSSAPI                    88      /* int, strings... */
+#define SSH_SMSG_AUTH_GSSAPI_RESPONSE           89      /* string */
+#define SSH_MSG_AUTH_GSSAPI_TOKEN               90      /* string */
+#define SSH_SMSG_AUTH_GSSAPI_HASH               91      /* string */
+#define SSH_MSG_AUTH_GSSAPI_ABORT               92      /* */
+
 /*
  * Authentication methods.  New types can be added, but old types should not
  * be removed for compatibility.  The maximum allowed value is 31.
@@ -84,6 +91,8 @@
 				/* 8 to 15 are reserved */
 #define SSH_PASS_AFS_TOKEN	21
 
+#define SSH_AUTH_GSSAPI		24
+
 /* Protocol flags.  These are bit masks. */
 #define SSH_PROTOFLAG_SCREEN_NUMBER	1	/* X11 forwarding includes screen */
 #define SSH_PROTOFLAG_HOST_IN_FWD_OPEN	2	/* forwarding opens contain host */
diff -Naur --exclude=autom4te.cache openssh-3.4p1/ssh_config.5 openssh-3.4p1-gsi/ssh_config.5
--- openssh-3.4p1/ssh_config.5	Thu Jun 20 19:59:06 2002
+++ openssh-3.4p1-gsi/ssh_config.5	Mon Sep 30 12:13:26 2002
@@ -50,10 +50,30 @@
 .Nm ssh
 obtains configuration data from the following sources in
 the following order:
-command line options, user's configuration file
+command line options, 
+feature-specific user configuration file(s) (see below),
+user's configuration file
 .Pq Pa $HOME/.ssh/config ,
 and system-wide configuration file
 .Pq Pa /etc/ssh/ssh_config .
+For compatibility with other
+.Nm
+versions, the following feature-specific user configuration files
+will be processed after the command line options but before the user's 
+main configuration file, so options that other
+.Nm
+versions may not support don't need to go in the main configuration file:
+.Bl -tag -width Ds
+.It Pa $HOME/.ssh/config.gssapi
+Read if GSSAPI authentication is supported.  This is a good place for
+the GssapiAuthentication and GssapiDelegateCredentials options.
+.It Pa $HOME/.ssh/config.krb
+Read if Kerberos authentication is supported.  This is a good place
+for the KerberosAuthentication and KerberosTgtPassing options.
+.It Pa $HOME/.ssh/config.afs
+Read if AFS token passing is supported.  This is a good place for the
+AfsTokenPassing option.
+.El
 .Pp
 For each parameter, the first obtained value
 will be used.
@@ -285,6 +305,17 @@
 Specifies a file to use for the global
 host key database instead of
 .Pa /etc/ssh/ssh_known_hosts .
+.It Cm GssapiAuthentication
+Specifies whether authentication based on GSSAPI may be used, either using
+the result of a successful key exchange, or using GSSAPI user
+authentication.
+The default is 
+.Dq yes .
+.It Cm GssapiDelegateCredentials
+Specifies whether GSSAPI credentials will be delegated (forwarded) to
+the server.
+The default is
+.Dq yes .
 .It Cm HostbasedAuthentication
 Specifies whether to try rhosts based authentication with public key
 authentication.
@@ -418,7 +449,7 @@
 over another method (e.g.
 .Cm password )
 The default for this option is:
-.Dq hostbased,publickey,keyboard-interactive,password .
+.Dq hostbased,external-keyx,gssapi,publickey,keyboard-interactive,password .
 .It Cm Protocol
 Specifies the protocol versions
 .Nm ssh
diff -Naur --exclude=autom4te.cache openssh-3.4p1/sshconnect1.c openssh-3.4p1-gsi/sshconnect1.c
--- openssh-3.4p1/sshconnect1.c	Thu Jun  6 14:57:34 2002
+++ openssh-3.4p1-gsi/sshconnect1.c	Mon Sep 30 12:13:26 2002
@@ -51,6 +51,17 @@
 #include "canohost.h"
 #include "auth.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#include "bufaux.h"
+
+/*
+ * MD5 hash of host and session keys for verification. This is filled
+ * in in ssh_login() and then checked in try_gssapi_authentication().
+ */
+unsigned char ssh_key_digest[16];
+#endif /* GSSAPI */
+
 /* Session id for the current session. */
 u_char session_id[16];
 u_int supported_authentications = 0;
@@ -947,6 +958,409 @@
 	return 0;
 }
 
+#ifdef GSSAPI
+#ifdef GSI
+char * get_gsi_name()
+{
+  OM_uint32 maj_stat;
+  OM_uint32 min_stat;
+  gss_name_t pname = GSS_C_NO_NAME;
+  gss_buffer_desc tmpname;
+  gss_buffer_t tmpnamed = &tmpname;
+  char *retname;
+  gss_OID_set oidset;
+  gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
+
+  gss_create_empty_oid_set(&min_stat,&oidset);
+  gss_add_oid_set_member(&min_stat,&supported_mechs[GSS_GSI].oid,&oidset);
+  maj_stat = gss_acquire_cred(&min_stat,
+                              GSS_C_NO_NAME,
+                              GSS_C_INDEFINITE,
+                              oidset,
+                              GSS_C_INITIATE,
+                              &gss_cred,
+                              NULL,
+                              NULL);
+
+  if (maj_stat != GSS_S_COMPLETE) {
+      goto error;
+  }
+
+  debug("calling gss_inquire_cred");
+  maj_stat = gss_inquire_cred(&min_stat,
+                              gss_cred,
+                              &pname,
+                              NULL,
+                              NULL,
+                              NULL);
+  if (maj_stat != GSS_S_COMPLETE) {
+      goto error;
+  }
+
+  maj_stat = gss_display_name(&min_stat,
+	                      pname,
+			      tmpnamed,
+			      NULL);
+  if (maj_stat != GSS_S_COMPLETE) {
+      goto error;
+  }
+  debug("gss_display_name finsished");
+  retname = (char *)malloc(tmpname.length + 1);
+  if (!retname) {
+      goto error;
+  }
+  memcpy(retname, tmpname.value, tmpname.length);
+  retname[tmpname.length] = '\0';
+
+  gss_release_name(&min_stat, &pname);
+  gss_release_buffer(&min_stat, tmpnamed);
+
+  return retname;
+
+ error:
+  debug("Failed to set GSI username from credentials");
+  ssh_gssapi_error(&supported_mechs[GSS_GSI].oid, maj_stat, min_stat);
+  return NULL;
+}
+#endif /* GSI */
+
+int try_gssapi_authentication(char *host, Options *options)
+{
+  char *service_name = NULL;
+  gss_buffer_desc name_tok;
+  gss_buffer_desc send_tok;
+  gss_buffer_desc recv_tok;
+  gss_buffer_desc *token_ptr;
+  gss_name_t target_name = NULL;
+  gss_ctx_id_t gss_context;
+  gss_OID_desc mech_oid;
+  gss_OID name_type;
+  gss_OID_set gss_mechs, my_mechs;
+  int my_mech_num, i, present;
+  OM_uint32 maj_stat;
+  OM_uint32 min_stat;
+  int ret_stat = 0;                             /* 1 == success */
+  OM_uint32 req_flags = 0;
+  OM_uint32 ret_flags;
+  int type;
+  char *xhost;
+  unsigned int slen;
+  Gssctxt *ctx = NULL;
+
+  /* Make a copy of the host name, in case it was returned by a
+   * previous call to gethostbyname(). */	
+  xhost = xstrdup(host);
+
+  /* If xhost is the loopback interface, switch it to our
+     true local hostname. */
+  resolve_localhost(&xhost);
+
+  /* Make sure we have the FQHN. Some GSSAPI implementations don't do
+   * this for us themselves */
+  make_fqhn(&xhost);
+
+  /*
+   * Default flags
+   */
+  req_flags |= GSS_C_REPLAY_FLAG;
+
+  /* Do mutual authentication */
+  req_flags |= GSS_C_MUTUAL_FLAG;
+
+  service_name = (char *) xmalloc(strlen("host") +
+				  strlen(xhost) +
+				  2 /* 1 for '@', 1 for NUL */);
+
+  sprintf(service_name, "host@%s", xhost);
+
+  xfree(xhost);
+  xhost = NULL;
+
+  name_type = GSS_C_NT_HOSTBASED_SERVICE;
+
+  debug("Service name is %s", service_name);
+
+  /* Forward credentials? */
+
+#ifdef GSSAPI
+  if(options->gss_deleg_creds) {
+    debug("Delegating GSSAPI credentials");
+    req_flags |= GSS_C_DELEG_FLAG;
+  }
+#endif /* GSSAPI */
+
+  debug("req_flags = %u", (unsigned int)req_flags);
+
+  name_tok.value = service_name;
+  name_tok.length = strlen(service_name) + 1;
+  maj_stat = gss_import_name(&min_stat, &name_tok,
+                             name_type, &target_name);
+
+  free(service_name);
+  service_name = NULL;
+
+  if (maj_stat != GSS_S_COMPLETE) {
+    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+    goto cleanup;
+  }
+
+  maj_stat = gss_indicate_mechs(&min_stat, &gss_mechs);
+
+  if (maj_stat != GSS_S_COMPLETE) {
+    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+    goto cleanup;
+  }
+
+  /* The GSSAPI supports the mechs in gss_mechs, but which ones do
+     we have credentials for?  We only get one try, so we don't want
+     to propose a mechanism we know is going to fail. */
+  maj_stat = gss_create_empty_oid_set(&min_stat, &my_mechs);
+  for (i=0; supported_mechs[i].name != NULL; i++) {
+      maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[i].oid,
+					 gss_mechs, &present);
+      if (present) {
+	  if (!GSS_ERROR(ssh_gssapi_client_ctx(&ctx, &supported_mechs[i].oid,
+					       host))) {
+	      maj_stat = gss_add_oid_set_member(&min_stat,
+						&supported_mechs[i].oid,
+						&my_mechs);
+	      debug("GSSAPI mechanism %s supported", supported_mechs[i].name);
+	  } else {
+	      debug("no credentials for GSSAPI mechanism %s",
+		    supported_mechs[i].name);
+	  }
+      } else {
+	  debug("GSSAPI mechanism %s not supported", supported_mechs[i].name);
+      }
+  }
+
+  /*
+   * Send over a packet to the daemon, letting it know we're doing
+   * GSSAPI and our mech_oid(s).
+   */
+  debug("Sending mech oid(s) to server");
+  packet_start(SSH_CMSG_AUTH_GSSAPI);
+  packet_put_int(my_mechs->count); /* Number of mechs we're sending */
+#ifdef GSI
+  /* Send GSI before Kerberos, because if GSI fails, we can always fall
+     back and try regular Kerberos authentication with our Kerberos cred. */
+  maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[GSS_GSI].oid,
+				     my_mechs, &present);
+  if (present) {
+      packet_put_string(supported_mechs[GSS_GSI].oid.elements,
+                        supported_mechs[GSS_GSI].oid.length);
+  }
+#endif
+  for (my_mech_num = 0; my_mech_num < my_mechs->count; my_mech_num++) {
+#ifdef GSI
+      /* Skip GSI.  We already sent it above. */
+      if ((my_mechs->elements[my_mech_num].length ==
+	   supported_mechs[GSS_GSI].oid.length) &&
+	  memcmp(my_mechs->elements[my_mech_num].elements,
+		 supported_mechs[GSS_GSI].oid.elements,
+		 my_mechs->elements[my_mech_num].length) == 0) {
+	  continue;
+      }
+#endif
+      packet_put_string(my_mechs->elements[my_mech_num].elements,
+                        my_mechs->elements[my_mech_num].length);
+  }
+  packet_send();
+  packet_write_wait();
+
+  /*
+   * Get reply from the daemon to see if our mech was acceptable
+   */
+  type = packet_read();
+
+  switch (type) {
+  case SSH_SMSG_AUTH_GSSAPI_RESPONSE:
+      debug("Server accepted mechanism");
+      /* Successful negotiation */
+      break;
+
+  case SSH_MSG_AUTH_GSSAPI_ABORT:
+      debug("Unable to negotiate GSSAPI mechanism type with server");
+      packet_get_all();
+      goto cleanup;
+
+  default:
+      packet_disconnect("Protocol error during GSSAPI authentication:"
+                        " packet type %d received",
+                        type);
+      /* Does not return */
+  }
+
+  /* Read the mechanism the server returned */
+  mech_oid.elements = packet_get_string(&slen);
+  mech_oid.length = slen;	/* safe typecast */
+  packet_get_all();
+
+  /*
+   * Perform the context-establishement loop.
+   *
+   * On each pass through the loop, token_ptr points to the token
+   * to send to the server (or GSS_C_NO_BUFFER on the first pass).
+   * Every generated token is stored in send_tok which is then
+   * transmitted to the server; every received token is stored in
+   * recv_tok, which token_ptr is then set to, to be processed by
+   * the next call to gss_init_sec_context.
+   *
+   * GSS-API guarantees that send_tok's length will be non-zero
+   * if and only if the server is expecting another token from us,
+   * and that gss_init_sec_context returns GSS_S_CONTINUE_NEEDED if
+   * and only if the server has another token to send us.
+   */
+
+  token_ptr = GSS_C_NO_BUFFER;
+  gss_context = GSS_C_NO_CONTEXT;
+
+  do {
+    maj_stat =
+      gss_init_sec_context(&min_stat,
+                           GSS_C_NO_CREDENTIAL,
+                           &gss_context,
+                           target_name,
+                           &mech_oid,
+                           req_flags,
+                           0,
+                           NULL,        /* no channel bindings */
+                           token_ptr,
+                           NULL,        /* ignore mech type */
+                           &send_tok,
+                           &ret_flags,
+                           NULL);       /* ignore time_rec */
+
+    if (token_ptr != GSS_C_NO_BUFFER)
+      (void) gss_release_buffer(&min_stat, &recv_tok);
+
+    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
+      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+
+      /* Send an abort message */
+      packet_start(SSH_MSG_AUTH_GSSAPI_ABORT);
+      packet_send();
+      packet_write_wait();
+
+      goto cleanup;
+    }
+
+    if (send_tok.length != 0) {
+      debug("Sending authenticaton token...");
+      packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
+      packet_put_string((char *) send_tok.value, send_tok.length);
+      packet_send();
+      packet_write_wait();
+
+      (void) gss_release_buffer(&min_stat, &send_tok);
+    }
+
+    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+
+      debug("Continue needed. Reading response...");
+
+      type = packet_read();
+
+      switch(type) {
+
+      case SSH_MSG_AUTH_GSSAPI_TOKEN:
+        /* This is what we expected */
+        break;
+
+      case SSH_MSG_AUTH_GSSAPI_ABORT:
+        debug("Server aborted GSSAPI authentication.");
+        packet_get_all();
+        goto cleanup;
+
+      default:
+        packet_disconnect("Protocol error during GSSAPI authentication:"
+                          " packet type %d received",
+                          type);
+        /* Does not return */
+      }
+
+      recv_tok.value = packet_get_string(&slen);
+      recv_tok.length=slen;	/* safe typecast */
+      packet_get_all();
+      token_ptr = &recv_tok;
+    }
+  } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+
+  /* Success */
+  ret_stat = 1;
+
+  debug("GSSAPI authentication successful");
+
+  /*
+   * Read hash of host and server keys and make sure it
+   * matches what we got earlier.
+   */
+  debug("Reading hash of server and host keys...");
+  type = packet_read();
+
+  if (type == SSH_MSG_AUTH_GSSAPI_ABORT) {
+    debug("Server aborted GSSAPI authentication.");
+    packet_get_all();
+    ret_stat = 0;
+    goto cleanup;
+
+  } else if (type == SSH_SMSG_AUTH_GSSAPI_HASH) {
+    gss_buffer_desc wrapped_buf;
+    gss_buffer_desc unwrapped_buf;
+    int conf_state;
+    gss_qop_t qop_state;
+
+
+    wrapped_buf.value = packet_get_string(&slen);
+    wrapped_buf.length=slen;	/* safe typecast */
+    packet_get_all();
+
+    maj_stat = gss_unwrap(&min_stat,
+                          gss_context,
+                          &wrapped_buf,
+                          &unwrapped_buf,
+                          &conf_state,
+                          &qop_state);
+
+    if (maj_stat != GSS_S_COMPLETE) {
+      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+      packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
+                        "Unwrapping of hash failed.");
+    }
+
+    if (unwrapped_buf.length != sizeof(ssh_key_digest)) {
+      packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
+                        "Size of key hashes do not match (%d != %d)!",
+                        (int)unwrapped_buf.length,
+			(int)sizeof(ssh_key_digest));
+    }
+
+    if (memcmp(ssh_key_digest, unwrapped_buf.value, sizeof(ssh_key_digest)) != 0) {
+      packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
+                        "Hashes don't match!");
+    }
+
+    debug("Verified SSHD keys through GSSAPI-secured channel.");
+
+    gss_release_buffer(&min_stat, &unwrapped_buf);
+
+  } else {
+      packet_disconnect("Protocol error during GSSAPI authentication:"
+                        "packet type %d received", type);
+      /* Does not return */
+  }
+
+
+ cleanup:
+  if (target_name != NULL)
+      (void) gss_release_name(&min_stat, &target_name);
+
+  return ret_stat;
+}
+
+#endif /* GSSAPI */
+
+
 /*
  * SSH1 key exchange
  */
@@ -998,6 +1412,45 @@
 		log("Warning: This may be due to an old implementation of ssh.");
 	}
 
+#ifdef GSSAPI
+  {
+    MD5_CTX md5context;
+    Buffer buf;
+    unsigned char *data;
+    unsigned int data_len;
+
+    /*
+     * Hash the server and host keys. Later we will check them against
+     * a hash sent over a secure channel to make sure they are legit.
+     */
+    debug("Calculating MD5 hash of server and host keys...");
+
+    /* Write all the keys to a temporary buffer */
+    buffer_init(&buf);
+
+    /* Server key */
+    buffer_put_bignum(&buf, server_key->rsa->e);
+    buffer_put_bignum(&buf, server_key->rsa->n);
+
+    /* Host key */
+    buffer_put_bignum(&buf, host_key->rsa->e);
+    buffer_put_bignum(&buf, host_key->rsa->n);
+
+    /* Get the resulting data */
+    data = (unsigned char *) buffer_ptr(&buf);
+    data_len = buffer_len(&buf);
+
+    /* And hash it */
+    MD5_Init(&md5context);
+    MD5_Update(&md5context, data, data_len);
+    MD5_Final(ssh_key_digest, &md5context);
+
+    /* Clean up */
+    buffer_clear(&buf);
+    buffer_free(&buf);
+  }
+#endif /* GSSAPI */
+
 	/* Get protocol flags. */
 	server_flags = packet_get_int();
 	packet_set_protocol_flags(server_flags);
@@ -1140,6 +1593,12 @@
 ssh_userauth1(const char *local_user, const char *server_user, char *host,
     Sensitive *sensitive)
 {
+#ifdef GSSAPI
+#ifdef GSI
+  	const char *save_server_user = NULL;
+#endif /* GSI */
+#endif /* GSSAPI */
+
 #ifdef KRB5
 	krb5_context context = NULL;
 	krb5_auth_context auth_context = NULL;
@@ -1149,12 +1608,56 @@
 	if (supported_authentications == 0)
 		fatal("ssh_userauth1: server supports no auth methods");
 
+#ifdef GSSAPI
+#ifdef GSI
+  /* if no user given, tack on the subject name after the server_user.
+   * This will allow us to run gridmap early to get real user
+   * This name will start with /C=
+   */
+  if ((supported_authentications & (1 << SSH_AUTH_GSSAPI)) &&
+      options.gss_authentication) {
+      char * retname;
+      char * newname;
+
+
+      save_server_user = server_user;
+
+      retname = get_gsi_name();
+
+      if (retname) {
+        debug("passing gssapi name '%s'", retname);
+        if (server_user) {
+          newname = (char *) malloc(strlen(retname) + strlen(server_user) + 4);
+          if (newname) {
+            strcpy(newname, server_user);
+            if(options.implicit) {
+                strcat(newname,":i:");
+	    } else {
+                strcat(newname,":x:");
+	    }
+            strcat(newname, retname);
+            server_user = newname;
+            free(retname);
+          }
+        }
+      }
+      debug("server_user %s", server_user);
+  }
+#endif /* GSI */
+#endif /* GSSAPI */
+
 	/* Send the name of the user to log in as on the server. */
 	packet_start(SSH_CMSG_USER);
 	packet_put_cstring(server_user);
 	packet_send();
 	packet_write_wait();
 
+#if defined(GSI)
+  if(save_server_user)
+    {
+      server_user = save_server_user;
+    }
+#endif
 	/*
 	 * The server should respond with success if no authentication is
 	 * needed (the user has no password).  Otherwise the server responds
@@ -1168,6 +1671,31 @@
 	if (type != SSH_SMSG_FAILURE)
 		packet_disconnect("Protocol error: got %d in response to SSH_CMSG_USER", type);
 
+#ifdef GSSAPI
+  /* Try GSSAPI authentication */
+  if ((supported_authentications & (1 << SSH_AUTH_GSSAPI)) &&
+      options.gss_authentication)
+    {
+      debug("Trying GSSAPI authentication...");
+      try_gssapi_authentication(host, &options);
+
+      /*
+       * XXX Hmmm. Kerberos authentication only reads a packet if it thinks
+       * the authentication went OK, but the server seems to always send
+       * a packet back. So I'm not sure if I'm missing something or
+       * the Kerberos code is broken. - vwelch 1/27/99
+       */
+
+      type = packet_read();
+      if (type == SSH_SMSG_SUCCESS)
+        return; /* Successful connection. */
+      if (type != SSH_SMSG_FAILURE)
+        packet_disconnect("Protocol error: got %d in response to Kerberos auth", type);
+
+      debug("GSSAPI authentication failed");
+    }
+#endif /* GSSAPI */
+	
 #ifdef KRB5
 	if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
 	    options.kerberos_authentication) {
diff -Naur --exclude=autom4te.cache openssh-3.4p1/sshconnect2.c openssh-3.4p1-gsi/sshconnect2.c
--- openssh-3.4p1/sshconnect2.c	Sun Jun 23 16:23:21 2002
+++ openssh-3.4p1-gsi/sshconnect2.c	Mon Sep 30 12:13:26 2002
@@ -48,6 +48,10 @@
 #include "msg.h"
 #include "pathnames.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import */
 extern char *client_version_string;
 extern char *server_version_string;
@@ -77,10 +81,26 @@
 ssh_kex2(char *host, struct sockaddr *hostaddr)
 {
 	Kex *kex;
+#ifdef GSSAPI
+	char *orig, *gss;
+	int len;
+#endif
 
 	xxx_host = host;
 	xxx_hostaddr = hostaddr;
 
+#ifdef GSSAPI
+	/* Add the GSSAPI mechanisms currently supported on this client to
+	 * the key exchange algorithm proposal */
+	orig = myproposal[PROPOSAL_KEX_ALGS];
+	gss = ssh_gssapi_mechanisms(0,host);
+	if (gss) {
+	   len = strlen(orig)+strlen(gss)+2;
+	   myproposal[PROPOSAL_KEX_ALGS]=xmalloc(len);
+	   snprintf(myproposal[PROPOSAL_KEX_ALGS],len,"%s,%s",gss,orig);
+	}
+#endif
+
 	if (options.ciphers == (char *)-1) {
 		log("No valid ciphers for protocol version 2 given, using defaults.");
 		options.ciphers = NULL;
@@ -108,11 +128,27 @@
 		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
 		    options.hostkeyalgorithms;
 
+#ifdef GSSAPI
+        /* If we've got GSSAPI algorithms, then we also support the
+         * 'null' hostkey, as a last resort */
+	if (gss) {
+		orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+		len = strlen(orig)+sizeof(",null");
+		myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
+		snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig);  
+	}
+#endif
+
 	/* start key exchange */
 	kex = kex_setup(myproposal);
 	kex->client_version_string=client_version_string;
 	kex->server_version_string=server_version_string;
 	kex->verify_host_key=&verify_host_key_callback;
+	kex->host=host;
+
+#ifdef GSSAPI
+	kex->options.gss_deleg_creds=options.gss_deleg_creds;
+#endif
 
 	xxx_kex = kex;
 
@@ -159,6 +195,8 @@
 	Sensitive *sensitive;
 	/* kbd-interactive */
 	int info_req_seen;
+	/* generic */
+	void *methoddata;
 };
 struct Authmethod {
 	char	*name;		/* string to compare against server's list */
@@ -181,6 +219,14 @@
 int	userauth_kbdint(Authctxt *);
 int	userauth_hostbased(Authctxt *);
 
+#ifdef GSSAPI
+int	userauth_external(Authctxt *authctxt);
+int	userauth_gssapi(Authctxt *authctxt);
+void	input_gssapi_response(int type, u_int32_t plen, void *ctxt);
+void	input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+void	input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
+#endif
+
 void	userauth(Authctxt *, char *);
 
 static int sign_and_send_pubkey(Authctxt *, Key *, sign_cb_fn *);
@@ -191,6 +237,16 @@
 static char *authmethods_get(void);
 
 Authmethod authmethods[] = {
+#ifdef GSSAPI
+	{"external-keyx",
+		userauth_external,
+		&options.gss_authentication,
+		NULL},
+	{"gssapi",
+		userauth_gssapi,
+		&options.gss_authentication,
+		NULL},
+#endif
 	{"hostbased",
 		userauth_hostbased,
 		&options.hostbased_authentication,
@@ -256,6 +312,7 @@
 	authctxt.success = 0;
 	authctxt.method = authmethod_lookup("none");
 	authctxt.authlist = NULL;
+	authctxt.methoddata = NULL;
 	authctxt.sensitive = sensitive;
 	authctxt.info_req_seen = 0;
 	if (authctxt.method == NULL)
@@ -278,6 +335,11 @@
 void
 userauth(Authctxt *authctxt, char *authlist)
 {
+	if (authctxt->methoddata!=NULL) {
+		xfree(authctxt->methoddata);
+		authctxt->methoddata=NULL;
+	}
+           
 	if (authlist == NULL) {
 		authlist = authctxt->authlist;
 	} else {
@@ -327,6 +389,8 @@
 		fatal("input_userauth_success: no authentication context");
 	if (authctxt->authlist)
 		xfree(authctxt->authlist);
+	if (authctxt->methoddata)
+		xfree(authctxt->methoddata);
 	clear_auth_state(authctxt);
 	authctxt->success = 1;			/* break out */
 }
@@ -428,6 +492,172 @@
 
 }
 
+#ifdef GSSAPI
+int 
+userauth_gssapi(Authctxt *authctxt)
+{
+	Gssctxt *gssctxt;
+	static int mech=0;
+
+	if (datafellows & SSH_OLD_GSSAPI) return 0;
+	
+	/* Try each mechanism in turn.  Give up if we've tried all
+	   supported mechanisms.
+	 */
+	if (mech==GSS_LAST_ENTRY) return 0;
+	
+	/* Initialise as much of our context as we can, so failures can be
+	 * trapped before sending any packets.
+	 */
+	ssh_gssapi_build_ctx(&gssctxt);
+
+	if (ssh_gssapi_import_name(gssctxt,authctxt->host)) {
+		return(0);
+	}
+	
+	authctxt->methoddata=(void *)gssctxt;
+		
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
+        if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
+	    packet_put_cstring("");
+	} else {
+#endif
+	    packet_put_cstring(authctxt->server_user);
+#ifdef GSI
+	}
+#endif
+	packet_put_cstring(authctxt->service);
+        packet_put_cstring(authctxt->method->name);
+
+	/* FIXME: This assumes that our current GSSAPI implementation
+	 * supports all of the mechanisms listed in supported_mechs.
+	 * This may not be the case - we should use something along
+	 * the lines of the code in gss_genr to remove the ones that
+	 * aren't supported */
+
+	/* Try one GSSAPI mechanism at a time. */
+	packet_put_int(1);
+	packet_put_string(supported_mechs[mech].oid.elements,
+			  supported_mechs[mech].oid.length);
+        packet_send();
+        packet_write_wait();
+
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
+	
+	mech++;			/* Move to next mechanism for next time. */
+
+        return 1;
+}
+
+void
+input_gssapi_response(int type, u_int32_t plen, void *ctxt) 
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	OM_uint32 status,ms;
+	int oidlen;
+	char *oidv;
+	gss_buffer_desc send_tok;
+	
+	if (authctxt == NULL)
+		fatal("input_gssapi_response: no authentication context");
+	gssctxt = authctxt->methoddata;
+	
+	/* Setup our OID */
+	oidv=packet_get_string(&oidlen);
+	ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
+	
+	packet_check_eom();
+	
+	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+				     GSS_C_NO_BUFFER, &send_tok, 
+				     NULL);
+	if (GSS_ERROR(status)) {
+		/* Start again with next method on list */
+		debug("Trying to start again");
+		userauth(authctxt,NULL);
+		return;
+	}
+
+	/* We must have data to send */					
+	packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+	packet_put_string(send_tok.value,send_tok.length);
+	packet_send();
+	packet_write_wait();
+	gss_release_buffer(&ms, &send_tok);
+}
+
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	gss_buffer_desc send_tok,recv_tok;
+	OM_uint32 status;
+	u_int slen;
+	
+	if (authctxt == NULL)
+		fatal("input_gssapi_token: no authentication context");
+	gssctxt = authctxt->methoddata;
+	
+	recv_tok.value=packet_get_string(&slen);
+	recv_tok.length=slen;	/* safe typecast */
+
+	status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+				   &recv_tok, &send_tok, NULL);
+
+	packet_check_eom();
+	
+	if (GSS_ERROR(status)) {
+		/* Start again with the next method in the list */
+		userauth(authctxt,NULL);
+		return;
+	}
+	
+	if (send_tok.length>0) {
+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+		packet_put_string(send_tok.value,send_tok.length);
+		packet_send();
+		packet_write_wait();
+	}
+	
+	if (status == GSS_S_COMPLETE) {
+		/* If that succeeded, send a exchange complete message */
+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+		packet_send();
+		packet_write_wait();
+	}
+}
+
+int
+userauth_external(Authctxt *authctxt)
+{
+        static int attempt =0;
+        
+        if (attempt++ >= 1)
+        	return 0;
+                                
+        debug2("userauth_external");
+        packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
+        if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
+	    packet_put_cstring("");
+	} else {
+#endif
+	    packet_put_cstring(authctxt->server_user);
+#ifdef GSI
+	}
+#endif
+        packet_put_cstring(authctxt->service);
+        packet_put_cstring(authctxt->method->name);
+        packet_send();
+        packet_write_wait();
+        return 1;
+}                                                                                                
+#endif /* GSSAPI */
+
 int
 userauth_none(Authctxt *authctxt)
 {
@@ -438,6 +668,7 @@
 	packet_put_cstring(authctxt->method->name);
 	packet_send();
 	return 1;
+
 }
 
 int
diff -Naur --exclude=autom4te.cache openssh-3.4p1/sshd.c openssh-3.4p1-gsi/sshd.c
--- openssh-3.4p1/sshd.c	Tue Jun 25 18:24:19 2002
+++ openssh-3.4p1-gsi/sshd.c	Mon Sep 30 12:13:26 2002
@@ -85,6 +85,15 @@
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
+#ifdef GSSAPI
+#include <openssl/md5.h>
+#include "bufaux.h"
+#endif /* GSSAPI */
+
 #ifdef LIBWRAP
 #include <tcpd.h>
 #include <syslog.h>
@@ -990,10 +999,13 @@
 		log("Disabling protocol version 1. Could not load host key");
 		options.protocol &= ~SSH_PROTO_1;
 	}
+#ifndef GSSAPI
+	/* The GSSAPI key exchange can run without a host key */
 	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {
 		log("Disabling protocol version 2. Could not load host key");
 		options.protocol &= ~SSH_PROTO_2;
 	}
+#endif
 	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
 		log("sshd: no hostkeys available -- exiting.");
 		exit(1);
@@ -1044,6 +1056,10 @@
 	if (test_flag)
 		exit(0);
 
+#ifdef GSSAPI
+	ssh_gssapi_clean_env();
+#endif /* GSSAPI */
+
 	/*
 	 * Clear out any supplemental groups we may have inherited.  This
 	 * prevents inadvertent creation of files with bad modes (in the
@@ -1654,6 +1670,10 @@
 	if (options.afs_token_passing)
 		auth_mask |= 1 << SSH_PASS_AFS_TOKEN;
 #endif
+#ifdef GSSAPI
+	if (options.gss_authentication)
+		auth_mask |= 1 << SSH_AUTH_GSSAPI;
+#endif
 	if (options.challenge_response_authentication == 1)
 		auth_mask |= 1 << SSH_AUTH_TIS;
 	if (options.password_authentication)
@@ -1747,6 +1767,49 @@
 		for (i = 0; i < 16; i++)
 			session_id[i] = session_key[i] ^ session_key[i + 16];
 	}
+
+#ifdef GSSAPI
+  /*
+   * Before we destroy the host and server keys, hash them so we can
+   * send the hash over to the client via a secure channel so that it
+   * can verify them.
+   */
+  {
+    MD5_CTX md5context;
+    Buffer buf;
+    unsigned char *data;
+    unsigned int data_len;
+    extern unsigned char ssh1_key_digest[16];   /* in gss-genr.c */
+
+
+    debug("Calculating MD5 hash of server and host keys...");
+
+    /* Write all the keys to a temporary buffer */
+    buffer_init(&buf);
+
+    /* Server key */
+    buffer_put_bignum(&buf, sensitive_data.server_key->rsa->e);
+    buffer_put_bignum(&buf, sensitive_data.server_key->rsa->n);
+
+    /* Host key */
+    buffer_put_bignum(&buf, sensitive_data.ssh1_host_key->rsa->e);
+    buffer_put_bignum(&buf, sensitive_data.ssh1_host_key->rsa->n);
+
+    /* Get the resulting data */
+    data = (unsigned char *) buffer_ptr(&buf);
+    data_len = buffer_len(&buf);
+
+    /* And hash it */
+    MD5_Init(&md5context);
+    MD5_Update(&md5context, data, data_len);
+    MD5_Final(ssh1_key_digest, &md5context);
+
+    /* Clean up */
+    buffer_clear(&buf);
+    buffer_free(&buf);
+  }
+#endif /* GSSAPI */
+
 	/* Destroy the private and public keys. No longer. */
 	destroy_sensitive_data();
 
@@ -1797,6 +1860,45 @@
 	}
 	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
 
+#ifdef GSSAPI
+	{ 
+	char *orig;
+	char *gss = NULL;
+	char *newstr = NULL;
+       	orig = myproposal[PROPOSAL_KEX_ALGS];
+
+	/* If we don't have a host key, then all of the algorithms
+	 * currently in myproposal are useless */
+	if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])==0)
+		orig= NULL;
+		
+        if (options.gss_keyex)
+        	gss = ssh_gssapi_mechanisms(1,NULL);
+        else
+        	gss = NULL;
+        
+	if (gss && orig) {
+		int len = strlen(orig) + strlen(gss) +2;
+		newstr=xmalloc(len);
+		snprintf(newstr,len,"%s,%s",gss,orig);
+	} else if (gss) {
+		newstr=gss;
+	} else if (orig) {
+		newstr=orig;
+	}
+        /* If we've got GSSAPI mechanisms, then we've also got the 'null'
+	   host key algorithm, but we're not allowed to advertise it, unless
+	   its the only host key algorithm we're supporting */
+	if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) {
+	  	myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]="null";
+	}
+	if (newstr)
+		myproposal[PROPOSAL_KEX_ALGS]=newstr;
+	else
+		fatal("No supported key exchange algorithms");
+        }
+#endif
+
 	/* start key exchange */
 	kex = kex_setup(myproposal);
 	kex->server = 1;
diff -Naur --exclude=autom4te.cache openssh-3.4p1/sshd_config.5 openssh-3.4p1-gsi/sshd_config.5
--- openssh-3.4p1/sshd_config.5	Wed Jun 26 08:05:16 2002
+++ openssh-3.4p1-gsi/sshd_config.5	Mon Sep 30 12:13:26 2002
@@ -233,6 +233,27 @@
 and applies to protocol version 2 only.
 The default is
 .Dq no .
+.It Cm GssapiAuthentication
+Specifies whether authentication based on GSSAPI may be used, either using
+the result of a successful key exchange, or using GSSAPI user
+authentication.
+The default is 
+.Dq yes .
+.It Cm GssapiKeyExchange
+Specifies whether key exchange based on GSSAPI may be used. When using
+GSSAPI key exchange the server need not have a host key.
+The default is
+.Dq yes .
+.It Cm GssapiUseSessionCredCache
+Specifies whether a unique credentials cache name should be generated per
+session for storing delegated credentials.
+The default is
+.Dq yes .
+.It Cm GssapiCleanupCreds
+Specifies whether the credentials cache should be removed at the end
+of the session.
+The default is
+.Dq yes .
 .It Cm HostKey
 Specifies a file containing a private host key
 used by SSH.
