diff -Naur --exclude=autom4te.cache openssh-4.1p1/Makefile.in openssh-4.1p1-gssapi/Makefile.in
--- openssh-4.1p1/Makefile.in	Fri Feb 25 17:12:38 2005
+++ openssh-4.1p1-gssapi/Makefile.in	Thu May 26 14:53:11 2005
@@ -59,6 +59,7 @@
 
 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+INSTALL_GSISSH=@INSTALL_GSISSH@
 
 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-server$(EXEEXT) sftp$(EXEEXT)
 
@@ -71,6 +72,7 @@
 	atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
 	kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
+	kexgssc.o \
 	entropy.o scard-opensc.o gss-genr.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
@@ -83,6 +85,7 @@
 	auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
 	auth2-none.o auth2-passwd.o auth2-pubkey.o \
 	monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
+	kexgsss.o gss-serv-gsi.o \
 	auth-krb5.o \
 	auth2-gss.o gss-serv.o gss-serv-krb5.o \
 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
@@ -282,6 +285,20 @@
 	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; \
+		rm -f $(DESTDIR)$(bindir)/gsisftp; \
+		ln -s ./sftp$(EXEEXT) $(DESTDIR)$(bindir)/gsisftp; \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.1; \
+		ln -s ./sftp.1 $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.1; \
+	fi
 
 install-sysconf:
 	if [ ! -d $(DESTDIR)$(sysconfdir) ]; then \
@@ -353,6 +370,11 @@
 
 uninstall:
 	-rm -f $(DESTDIR)$(bindir)/slogin
+	if [ ! -z "$(INSTALL_GSISSH)" ]; then \
+		rm -f $(DESTDIR)$(bindir)/gsiscp; \
+		rm -f $(DESTDIR)$(bindir)/gsissh; \
+		rm -f $(DESTDIR)$(bindir)/gsisftp; \
+	fi
 	-rm -f $(DESTDIR)$(bindir)/ssh$(EXEEXT)
 	-rm -f $(DESTDIR)$(bindir)/scp$(EXEEXT)
 	-rm -f $(DESTDIR)$(bindir)/ssh-add$(EXEEXT)
@@ -366,6 +388,11 @@
 	-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; \
+		rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/gsisftp.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-4.1p1/acconfig.h openssh-4.1p1-gssapi/acconfig.h
--- openssh-4.1p1/acconfig.h	Fri Feb 25 17:07:38 2005
+++ openssh-4.1p1-gssapi/acconfig.h	Thu May 26 14:53:11 2005
@@ -256,6 +256,9 @@
 /* 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
 
@@ -264,6 +267,16 @@
 
 /* Define this if you are using the Heimdal version of Kerberos V5 */
 #undef HEIMDAL
+
+/* Define this if you want to use AFS/Kerberos 5 option, which runs aklog. */
+#undef AFS_KRB5
+#undef AKLOG_PATH
+
+/* Define if you want GSI/Globus authentication support */
+#undef GSI
+
+/* Define this if you want support for startup/shutdown hooks */
+#undef SESSION_HOOKS
 
 /* Define this if you want to use libkafs' AFS support */
 #undef USE_AFS
diff -Naur --exclude=autom4te.cache openssh-4.1p1/auth.c openssh-4.1p1-gssapi/auth.c
--- openssh-4.1p1/auth.c	Mon Mar 14 06:17:27 2005
+++ openssh-4.1p1-gssapi/auth.c	Thu May 26 14:53:11 2005
@@ -240,7 +240,8 @@
 	    authmsg,
 	    method,
 	    authctxt->valid ? "" : "invalid user ",
-	    authctxt->user,
+	    (authctxt->user && authctxt->user[0]) ?
+		authctxt->user : "<implicit>",
 	    get_remote_ipaddr(),
 	    get_remote_port(),
 	    info);
@@ -511,7 +512,8 @@
 	pw = getpwnam(user);
 	if (pw == NULL) {
 		logit("Invalid user %.100s from %.100s",
-		    user, get_remote_ipaddr());
+		      (user && user[0]) ? user : "<implicit>",
+		      get_remote_ipaddr());
 #ifdef CUSTOM_FAILED_LOGIN
 		record_failed_login(user,
 		    get_canonical_hostname(options.use_dns), "ssh");
diff -Naur --exclude=autom4te.cache openssh-4.1p1/auth.h openssh-4.1p1-gssapi/auth.h
--- openssh-4.1p1/auth.h	Thu Mar 31 05:39:25 2005
+++ openssh-4.1p1-gssapi/auth.h	Thu May 26 14:53:11 2005
@@ -42,6 +42,9 @@
 #ifdef KRB5
 #include <krb5.h>
 #endif
+#ifdef AFS_KRB5
+#include <krbafs.h>
+#endif
 
 typedef struct Authctxt Authctxt;
 typedef struct Authmethod Authmethod;
@@ -68,6 +71,9 @@
 	krb5_principal	 krb5_user;
 	char		*krb5_ticket_file;
 	char		*krb5_ccname;
+#endif
+#ifdef SESSION_HOOKS
+        char            *session_env_file;
 #endif
 	Buffer		*loginmsg;
 	void		*methoddata;
diff -Naur --exclude=autom4te.cache openssh-4.1p1/auth2-gss.c openssh-4.1p1-gssapi/auth2-gss.c
--- openssh-4.1p1/auth2-gss.c	Mon Jun 21 21:56:02 2004
+++ openssh-4.1p1-gssapi/auth2-gss.c	Thu May 26 14:53:11 2005
@@ -42,11 +42,26 @@
 
 extern ServerOptions options;
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_errtok(int, u_int32_t, void *);
 
+static int gssapi_with_mic = 1;	/* flag to toggle "gssapi-with-mic" vs.
+				   "gssapi" */
+
+static int
+userauth_external(Authctxt *authctxt)
+{
+        packet_check_eom();
+
+	if (authctxt->valid && authctxt->user && authctxt->user[0]) {
+		return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
+	}
+	return 0;
+}
+
 /*
  * We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like
@@ -63,7 +78,10 @@
 	u_int len;
 	char *doid = NULL;
 
-	if (!authctxt->valid || authctxt->user == NULL)
+	/* authctxt->valid may be 0 if we haven't yet determined
+	   username from gssapi context. */
+
+	if (authctxt->user == NULL)
 		return (0);
 
 	mechs = packet_get_int();
@@ -130,7 +148,7 @@
 	Gssctxt *gssctxt;
 	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
 	gss_buffer_desc recv_tok;
-	OM_uint32 maj_status, min_status, flags;
+	OM_uint32 maj_status, min_status, flags=0;
 	u_int len;
 
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
@@ -148,6 +166,7 @@
 	xfree(recv_tok.value);
 
 	if (GSS_ERROR(maj_status)) {
+        	ssh_gssapi_userauth_error(gssctxt);
 		if (send_tok.length != 0) {
 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
 			packet_put_string(send_tok.value, send_tok.length);
@@ -155,7 +174,9 @@
 		}
 		authctxt->postponed = 0;
 		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-		userauth_finish(authctxt, 0, "gssapi-with-mic");
+		userauth_finish(authctxt, 0,
+				gssapi_with_mic ? "gssapi-with-mic" :
+				                  "gssapi");
 	} else {
 		if (send_tok.length != 0) {
 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
@@ -164,7 +185,7 @@
 		}
 		if (maj_status == GSS_S_COMPLETE) {
 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
-			if (flags & GSS_C_INTEG_FLAG)
+			if (flags & GSS_C_INTEG_FLAG && gssapi_with_mic)
 				dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
 				    &input_gssapi_mic);
 			else
@@ -211,6 +232,32 @@
 	gss_release_buffer(&maj_status, &send_tok);
 }
 
+static void
+gssapi_set_implicit_username(Authctxt *authctxt)
+{
+    if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) {
+	char *lname = NULL;
+	PRIVSEP(ssh_gssapi_localname(&lname));
+	if (lname && lname[0] != '\0') {
+	    if (authctxt->user) xfree(authctxt->user);
+	    authctxt->user = lname;
+	    debug("set username to %s from gssapi context", lname);
+	    authctxt->pw = PRIVSEP(getpwnamallow(authctxt->user));
+	    if (authctxt->pw) {
+		authctxt->valid = 1;
+	    }
+	} else {
+	    debug("failed to set username from gssapi context");
+	}
+    }
+    if (authctxt->pw) {
+#ifdef USE_PAM
+	if (options.use_pam)
+		PRIVSEP(start_pam(authctxt));
+#endif
+    }
+}
+
 /*
  * This is called when the client thinks we've completed authentication.
  * It should only be enabled in the dispatch handler by the function above,
@@ -227,6 +274,8 @@
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
 		fatal("No authentication or GSSAPI context");
 
+	gssapi_set_implicit_username(authctxt);
+
 	gssctxt = authctxt->methoddata;
 
 	/*
@@ -236,14 +285,34 @@
 
 	packet_check_eom();
 
-	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+	/* user should be set if valid but we double-check here */
+	if (authctxt->valid && authctxt->user && authctxt->user[0]) {
+	    authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+	} else {
+	    authenticated = 0;
+	}
 
 	authctxt->postponed = 0;
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
-	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
+	userauth_finish(authctxt, authenticated,
+			gssapi_with_mic ? "gssapi-with-mic" : "gssapi");
+}
+
+static int
+userauth_gssapi_with_mic(Authctxt *authctxt)
+{
+    gssapi_with_mic = 1;
+    return userauth_gssapi(authctxt);
+}
+
+static int
+userauth_gssapi_without_mic(Authctxt *authctxt)
+{
+    gssapi_with_mic = 0;
+    return userauth_gssapi(authctxt);
 }
 
 static void
@@ -259,6 +328,8 @@
 	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
 		fatal("No authentication or GSSAPI context");
 
+	gssapi_set_implicit_username(authctxt);
+
 	gssctxt = authctxt->methoddata;
 
 	mic.value = packet_get_string(&len);
@@ -271,7 +342,11 @@
 	gssbuf.length = buffer_len(&b);
 
 	if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
+	    if (authctxt->valid && authctxt->user && authctxt->user[0]) {
 		authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+	    } else {
+		authenticated = 0;
+	    }
 	else
 		logit("GSSAPI MIC check failed");
 
@@ -286,9 +361,38 @@
 	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
 }
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
+	char *errstr;
+	OM_uint32 maj,min;
+	
+	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+	if (errstr) {
+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
+		packet_put_int(maj);
+		packet_put_int(min);
+		packet_put_cstring(errstr);
+		packet_put_cstring("");
+		packet_send();
+		packet_write_wait();
+		xfree(errstr);
+	}
+}
+
+Authmethod method_external = {
+	"external-keyx",
+	userauth_external,
+	&options.gss_authentication
+};
+	
 Authmethod method_gssapi = {
 	"gssapi-with-mic",
-	userauth_gssapi,
+	userauth_gssapi_with_mic,
+	&options.gss_authentication
+};
+
+Authmethod method_gssapi_compat = {
+	"gssapi",
+	userauth_gssapi_without_mic,
 	&options.gss_authentication
 };
 
diff -Naur --exclude=autom4te.cache openssh-4.1p1/auth2.c openssh-4.1p1-gssapi/auth2.c
--- openssh-4.1p1/auth2.c	Tue Feb  8 04:52:48 2005
+++ openssh-4.1p1-gssapi/auth2.c	Thu May 26 14:53:11 2005
@@ -55,14 +55,18 @@
 extern Authmethod method_kbdint;
 extern Authmethod method_hostbased;
 #ifdef GSSAPI
+extern Authmethod method_external;
 extern Authmethod method_gssapi;
+extern Authmethod method_gssapi_compat;
 #endif
 
 Authmethod *authmethods[] = {
 	&method_none,
 	&method_pubkey,
 #ifdef GSSAPI
+	&method_external,
 	&method_gssapi,
+	&method_gssapi_compat,
 #endif
 	&method_passwd,
 	&method_kbdint,
@@ -143,14 +147,52 @@
 	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 (user[0] == '\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 {
+		    debug("failed to set username from gssapi context");
+		}
+	    }
+	}
+#endif
+
+	debug("userauth-request for user %s service %s method %s",
+	      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) {
-		/* setup auth context */
+	/* If first time or username changed or implicit username,
+	   setup/reset authentication context. */
+	if ((authctxt->attempt++ == 0) ||
+	    (strcmp(user, authctxt->user) != 0) ||
+	    (strcmp(user, "") == 0)) {
+		if (authctxt->user) {
+		    xfree(authctxt->user);
+		    authctxt->user = NULL;
+		}
+		authctxt->valid = 0;
+#ifdef GSSAPI
+		/* If we're going to set the username based on the
+		   GSSAPI context later, then wait until then to
+		   verify it. Just put in placeholders for now. */
+		if ((strcmp(user, "") == 0) &&
+		    ((strcmp(method, "gssapi") == 0) ||
+		     (strcmp(method, "gssapi-with-mic") == 0))) {
+			authctxt->pw = fakepw();
+			authctxt->user = xstrdup(user);
+		} else {
+#endif
 		authctxt->pw = PRIVSEP(getpwnamallow(user));
 		authctxt->user = xstrdup(user);
 		if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
@@ -171,15 +213,24 @@
 			PRIVSEP(audit_event(SSH_INVALID_USER));
 #endif
 		}
+#ifdef GSSAPI
+		} /* endif for setting username based on GSSAPI context */
+#endif
 		setproctitle("%s%s", authctxt->valid ? user : "unknown",
 		    use_privsep ? " [net]" : "");
+#ifdef GSSAPI
+		if (authctxt->attempt == 1) {
+#endif
 		authctxt->service = xstrdup(service);
 		authctxt->style = style ? xstrdup(style) : NULL;
 		if (use_privsep)
 			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: "
+#ifdef GSSAPI
+		} /* if (authctxt->attempt == 1) */
+#endif
+	}
+	if (strcmp(service, authctxt->service) != 0) {
+		packet_disconnect("Change of service not allowed: "
 		    "(%s,%s) -> (%s,%s)",
 		    authctxt->user, authctxt->service, user, service);
 	}
diff -Naur --exclude=autom4te.cache openssh-4.1p1/canohost.c openssh-4.1p1-gssapi/canohost.c
--- openssh-4.1p1/canohost.c	Tue May  3 04:05:32 2005
+++ openssh-4.1p1-gssapi/canohost.c	Thu May 26 14:53:11 2005
@@ -401,3 +401,29 @@
 {
 	return get_port(1);
 }
+
+void
+resolve_localhost(char **host)
+{
+    struct hostent *hostinfo;
+
+    hostinfo = gethostbyname(*host);
+    if (hostinfo == NULL || hostinfo->h_name == NULL) {
+	debug("gethostbyname(%s) failed", *host);
+	return;
+    }
+    if (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) {
+		debug("gethostname() failed");
+		return;
+	    }
+	    hostinfo = gethostbyname(buf);
+	    xfree(*host);
+	    *host = xstrdup(hostinfo->h_name);
+	}
+    }
+}
diff -Naur --exclude=autom4te.cache openssh-4.1p1/canohost.h openssh-4.1p1-gssapi/canohost.h
--- openssh-4.1p1/canohost.h	Wed Feb  2 06:30:25 2005
+++ openssh-4.1p1-gssapi/canohost.h	Thu May 26 14:53:11 2005
@@ -24,4 +24,6 @@
 int		 get_remote_port(void);
 int		 get_local_port(void);
 
+void		 resolve_localhost(char **host);
+
 void		 ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *);
diff -Naur --exclude=autom4te.cache openssh-4.1p1/config.h.in openssh-4.1p1-gssapi/config.h.in
--- openssh-4.1p1/config.h.in	Wed May 25 07:26:09 2005
+++ openssh-4.1p1-gssapi/config.h.in	Thu May 26 14:53:29 2005
@@ -256,6 +256,9 @@
 /* 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
 
@@ -264,6 +267,16 @@
 
 /* Define this if you are using the Heimdal version of Kerberos V5 */
 #undef HEIMDAL
+
+/* Define this if you want to use AFS/Kerberos 5 option, which runs aklog. */
+#undef AFS_KRB5
+#undef AKLOG_PATH
+
+/* Define if you want GSI/Globus authentication support */
+#undef GSI
+
+/* Define this if you want support for startup/shutdown hooks */
+#undef SESSION_HOOKS
 
 /* Define this if you want to use libkafs' AFS support */
 #undef USE_AFS
diff -Naur --exclude=autom4te.cache openssh-4.1p1/configure openssh-4.1p1-gssapi/configure
--- openssh-4.1p1/configure	Wed May 25 07:26:12 2005
+++ openssh-4.1p1-gssapi/configure	Thu May 26 14:53:33 2005
@@ -309,7 +309,7 @@
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os AWK CPP RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR CAT KILL PERL SED ENT TEST_MINUS_S_SH SH TEST_SHELL PATH_GROUPADD_PROG PATH_USERADD_PROG MAKE_PACKAGE_SUPPORTED LOGIN_PROGRAM_FALLBACK PATH_PASSWD_PROG LD EGREP LIBWRAP LIBEDIT LIBPAM INSTALL_SSH_RAND_HELPER SSH_PRIVSEP_USER PROG_LS PROG_NETSTAT PROG_ARP PROG_IFCONFIG PROG_JSTAT PROG_PS PROG_SAR PROG_W PROG_WHO PROG_LAST PROG_LASTLOG PROG_DF PROG_VMSTAT PROG_UPTIME PROG_IPCS PROG_TAIL INSTALL_SSH_PRNG_CMDS OPENSC_CONFIG PRIVSEP_PATH xauth_path STRIP_OPT XAUTH_PATH NROFF MANTYPE mansubdir user_path piddir LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT build build_cpu build_vendor build_os host host_cpu host_vendor host_os AWK CPP RANLIB ac_ct_RANLIB INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR CAT KILL PERL SED ENT TEST_MINUS_S_SH SH TEST_SHELL PATH_GROUPADD_PROG PATH_USERADD_PROG MAKE_PACKAGE_SUPPORTED LOGIN_PROGRAM_FALLBACK PATH_PASSWD_PROG LD EGREP INSTALL_GSISSH LIBWRAP LIBEDIT LIBPAM INSTALL_SSH_RAND_HELPER SSH_PRIVSEP_USER PROG_LS PROG_NETSTAT PROG_ARP PROG_IFCONFIG PROG_JSTAT PROG_PS PROG_SAR PROG_W PROG_WHO PROG_LAST PROG_LASTLOG PROG_DF PROG_VMSTAT PROG_UPTIME PROG_IPCS PROG_TAIL INSTALL_SSH_PRNG_CMDS OPENSC_CONFIG PRIVSEP_PATH xauth_path STRIP_OPT XAUTH_PATH NROFF MANTYPE mansubdir user_path piddir LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -869,6 +869,11 @@
   --with-libs             Specify additional libraries to link with
   --with-zlib=PATH        Use zlib in PATH
   --without-zlib-version-check Disable zlib version check
+  --with-mechglue=PATH    Build with GSSAPI mechglue library
+  --with-gsi              Enable Globus GSI authentication support
+  --with-globus           Enable Globus GSI authentication support
+  --with-globus-static    Link statically with Globus GSI libraries
+  --with-globus-flavor=TYPE  Specify Globus flavor type (ex: gcc32dbg)
   --with-skey[=PATH]      Enable S/Key support (optionally in PATH)
   --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
   --with-libedit[=PATH]   Enable libedit support for sftp
@@ -883,6 +888,8 @@
   --with-sectok           Enable smartcard support using libsectok
 --with-opensc[=PFX]       Enable smartcard support using OpenSC (optionally in PATH)
   --with-kerberos5=PATH   Enable Kerberos 5 support
+  --with-afs-krb5[=AKLOG_PATH]  Enable aklog to get token (default=/usr/bin/aklog).
+  --with-session-hooks    Enable hooks for executing external commands                                       before/after a session
   --with-privsep-path=xxx Path for privilege separation chroot (default=/var/empty)
   --with-xauth=PATH       Specify path to xauth program
   --with-mantype=man|cat|doc  Set man page type
@@ -5026,53 +5033,10 @@
 
 	;;
 *-*-darwin*)
-	echo "$as_me:$LINENO: checking if we have working getaddrinfo" >&5
-echo $ECHO_N "checking if we have working getaddrinfo... $ECHO_C" >&6
-	if test "$cross_compiling" = yes; then
-  echo "$as_me:$LINENO: result: assume it is working" >&5
-echo "${ECHO_T}assume it is working" >&6
-else
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#include <mach-o/dyld.h>
-main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
-		exit(0);
-	else
-		exit(1);
-}
-_ACEOF
-rm -f 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='./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
-  echo "$as_me:$LINENO: result: working" >&5
-echo "${ECHO_T}working" >&6
-else
-  echo "$as_me: program exited with status $ac_status" >&5
-echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-( exit $ac_status )
-echo "$as_me:$LINENO: result: buggy" >&5
-echo "${ECHO_T}buggy" >&6
 	cat >>confdefs.h <<\_ACEOF
 #define BROKEN_GETADDRINFO 1
 _ACEOF
 
-fi
-rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
-fi
 	cat >>confdefs.h <<\_ACEOF
 #define SETEUID_BREAKS_SETUID 1
 _ACEOF
@@ -9693,6 +9657,320 @@
 rm -f core *.core gmon.out bb.out 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
+
+
+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
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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 ();
+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>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (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); }; } &&
+	 { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.err 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 --with-globus-static or --without-globus-static was given.
+if test "${with_globus_static+set}" = set; then
+  withval="$with_globus_static"
+
+		gsi_static="-static"
+		if test "x$gsi_path" = "xno" ; then
+			gsi_path="$withval"
+		fi
+
+
+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"
+		if test "x$gsi_path" = "xno" ; then
+			gsi_path="yes"
+		fi
+
+
+fi;
+
+if test "x$gsi_path" != "xno" ; then
+	# Globus GSSAPI configuration
+	echo "$as_me:$LINENO: checking for Globus GSI" >&5
+echo $ECHO_N "checking for Globus GSI... $ECHO_C" >&6
+	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
+
+	if test "x$gsi_path" = "xyes" ; then
+		if test -z "$GLOBUS_LOCATION" ; then
+			{ { echo "$as_me:$LINENO: error: GLOBUS_LOCATION environment variable must be set." >&5
+echo "$as_me: error: GLOBUS_LOCATION environment variable must be set." >&2;}
+   { (exit 1); exit 1; }; }
+		else
+			gsi_path="$GLOBUS_LOCATION"
+		fi
+	fi
+	GLOBUS_LOCATION="$gsi_path"
+	export GLOBUS_LOCATION
+	if test ! -d "$GLOBUS_LOCATION" ; then
+		{ { echo "$as_me:$LINENO: error: Cannot find Globus installation.  Set GLOBUS_LOCATION environment variable." >&5
+echo "$as_me: error: Cannot find Globus installation.  Set GLOBUS_LOCATION environment variable." >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+        if test "x$globus_flavor_type" = "xno" ; then
+                { { echo "$as_me:$LINENO: error: --with-globus-flavor=TYPE must be specified" >&5
+echo "$as_me: error: --with-globus-flavor=TYPE must be specified" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+        if test "x$globus_flavor_type" = "xyes" ; then
+                { { echo "$as_me:$LINENO: error: --with-globus-flavor=TYPE must specify a flavor type" >&5
+echo "$as_me: error: --with-globus-flavor=TYPE must specify a flavor type" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+	GLOBUS_INCLUDE="${gsi_path}/include/${globus_flavor_type}"
+	if test ! -d "$GLOBUS_INCLUDE" ; then
+		{ { echo "$as_me:$LINENO: error: Cannot find Globus flavor-specific include directory: ${GLOBUS_INCLUDE}" >&5
+echo "$as_me: error: Cannot find Globus flavor-specific include directory: ${GLOBUS_INCLUDE}" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	GSI_CPPFLAGS="-I${GLOBUS_INCLUDE}"
+
+	if test -x ${gsi_path}/bin/globus-makefile-header ; then
+		GSI_LIBS=`${gsi_path}/bin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
+	elif test -x ${gsi_path}/sbin/globus-makefile-header ; then
+		GSI_LIBS=`${gsi_path}/sbin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
+	else
+		{ { echo "$as_me:$LINENO: error: Cannot find globus-makefile-header: Globus installation is incomplete" >&5
+echo "$as_me: error: Cannot find globus-makefile-header: Globus installation is incomplete" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	if test -n "${need_dash_r}"; then
+		GSI_LDFLAGS="-L${gsi_path}/lib -R{gsi_path}/lib"
+	else
+		GSI_LDFLAGS="-L${gsi_path}/lib"
+	fi
+	if test -z "$GSI_LIBS" ; then
+		{ { echo "$as_me:$LINENO: error: globus-makefile-header failed" >&5
+echo "$as_me: error: globus-makefile-header failed" >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+
+	cat >>confdefs.h <<\_ACEOF
+#define HAVE_GSSAPI_H 1
+_ACEOF
+
+
+	LIBS="$LIBS $GSI_LIBS"
+	LDFLAGS="$LDFLAGS $GSI_LDFLAGS"
+	CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+
+	# test that we got the libraries OK
+	cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (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); }; } &&
+	 { 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
+
+			echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+			{ { echo "$as_me:$LINENO: error: link with Globus libraries failed" >&5
+echo "$as_me: error: link with Globus libraries failed" >&2;}
+   { (exit 1); exit 1; }; }
+
+
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+	INSTALL_GSISSH="yes"
+else
+	INSTALL_GSISSH=""
+fi
+
+# End Globus/GSI section
+
 echo "$as_me:$LINENO: checking for /proc/pid/fd directory" >&5
 echo $ECHO_N "checking for /proc/pid/fd directory... $ECHO_C" >&6
 if test -d "/proc/$$/fd" ; then
@@ -13825,7 +14103,9 @@
 
 
 fi;
+if test -z "$GSI_LIBS" ; then
 LIBS="-lcrypto $LIBS"
+fi
 cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
@@ -23044,7 +23324,165 @@
 
 
 
-		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
+
+			if test -z "$GSSAPI"; then
+				GSSAPI="KRB5";
+			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
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"
+			 || test ! -s conftest.err'
+  { (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); }; } &&
+	 { 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
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err 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
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end 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=$?
+  grep -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
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_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
+sed 's/^/| /' 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:$ac_c_preproc_warn_flag 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 compiler's result" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  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: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: gssapi_krb5.h:     section \"Present But Cannot Be Compiled\"" >&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;}
+    { echo "$as_me:$LINENO: WARNING: gssapi_krb5.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: gssapi_krb5.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ---------------------------------- ##
+## Report this to the OpenSSH lists.  ##
+## ---------------------------------- ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&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
+
+
+
+                fi
 		if test ! -z "$need_dash_r" ; then
 			LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
 		fi
@@ -23770,6 +24208,57 @@
 
 fi;
 
+# Check whether user wants AFS_KRB5 support
+AFS_KRB5_MSG="no"
+
+# Check whether --with-afs-krb5 or --without-afs-krb5 was given.
+if test "${with_afs_krb5+set}" = set; then
+  withval="$with_afs_krb5"
+
+		if test "x$withval" != "xno" ; then
+
+			if test "x$withval" != "xyes" ; then
+				cat >>confdefs.h <<_ACEOF
+#define AKLOG_PATH "$withval"
+_ACEOF
+
+			else
+				cat >>confdefs.h <<_ACEOF
+#define AKLOG_PATH "/usr/bin/aklog"
+_ACEOF
+
+			fi
+
+			if test -z "$KRB5ROOT" ; then
+				{ echo "$as_me:$LINENO: WARNING: AFS_KRB5 requires Kerberos 5 support, build may fail" >&5
+echo "$as_me: WARNING: AFS_KRB5 requires Kerberos 5 support, build may fail" >&2;}
+			fi
+
+			LIBS="-lkrbafs -lkrb4 $LIBS"
+			if test ! -z "$AFS_LIBS" ; then
+				LIBS="$LIBS $AFS_LIBS"
+			fi
+			cat >>confdefs.h <<\_ACEOF
+#define AFS_KRB5 1
+_ACEOF
+
+			AFS_KRB5_MSG="yes"
+		fi
+
+
+fi;
+
+
+# Check whether --with-session-hooks or --without-session-hooks was given.
+if test "${with_session_hooks+set}" = set; then
+  withval="$with_session_hooks"
+   cat >>confdefs.h <<\_ACEOF
+#define SESSION_HOOKS 1
+_ACEOF
+
+
+fi;
+
 # Looking for programs, paths and files
 
 PRIVSEP_PATH=/var/empty
@@ -25712,6 +26201,7 @@
 s,@PATH_PASSWD_PROG@,$PATH_PASSWD_PROG,;t t
 s,@LD@,$LD,;t t
 s,@EGREP@,$EGREP,;t t
+s,@INSTALL_GSISSH@,$INSTALL_GSISSH,;t t
 s,@LIBWRAP@,$LIBWRAP,;t t
 s,@LIBEDIT@,$LIBEDIT,;t t
 s,@LIBPAM@,$LIBPAM,;t t
diff -Naur --exclude=autom4te.cache openssh-4.1p1/configure.ac openssh-4.1p1-gssapi/configure.ac
--- openssh-4.1p1/configure.ac	Sun Apr 24 02:52:23 2005
+++ openssh-4.1p1-gssapi/configure.ac	Thu May 26 14:53:11 2005
@@ -166,16 +166,7 @@
 	AC_DEFINE(BROKEN_SETREGID)
 	;;
 *-*-darwin*)
-	AC_MSG_CHECKING(if we have working getaddrinfo)
-	AC_TRY_RUN([#include <mach-o/dyld.h>
-main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
-		exit(0);
-	else
-		exit(1);
-}], [AC_MSG_RESULT(working)],
-	[AC_MSG_RESULT(buggy)
-	AC_DEFINE(BROKEN_GETADDRINFO)],
-	[AC_MSG_RESULT(assume it is working)])
+	AC_DEFINE(BROKEN_GETADDRINFO)
 	AC_DEFINE(SETEUID_BREAKS_SETUID)
 	AC_DEFINE(BROKEN_SETREUID)
 	AC_DEFINE(BROKEN_SETREGID)
@@ -752,6 +743,152 @@
 	]
 )
 
+# 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})
+
+		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              Enable Globus GSI authentication support],
+	[
+		gsi_path="$withval"
+	]
+)
+
+AC_ARG_WITH(globus,
+	[  --with-globus           Enable Globus GSI authentication support],
+	[
+		gsi_path="$withval"
+	]
+)
+
+AC_ARG_WITH(globus-static,
+	[  --with-globus-static    Link statically with Globus GSI libraries],
+	[
+		gsi_static="-static"
+		if test "x$gsi_path" = "xno" ; then
+			gsi_path="$withval"
+		fi
+	]
+)
+
+# Check whether the user has a Globus flavor type
+globus_flavor_type="no"
+AC_ARG_WITH(globus-flavor,
+	[  --with-globus-flavor=TYPE  Specify Globus flavor type (ex: gcc32dbg)],
+	[
+		globus_flavor_type="$withval"
+		if test "x$gsi_path" = "xno" ; then
+			gsi_path="yes"
+		fi
+	]
+)
+
+if test "x$gsi_path" != "xno" ; then
+	# Globus GSSAPI configuration
+	AC_MSG_CHECKING(for Globus GSI)
+	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
+
+	if test "x$gsi_path" = "xyes" ; then
+		if test -z "$GLOBUS_LOCATION" ; then
+			AC_MSG_ERROR(GLOBUS_LOCATION environment variable must be set.)
+		else
+			gsi_path="$GLOBUS_LOCATION"
+		fi
+	fi
+	GLOBUS_LOCATION="$gsi_path"
+	export GLOBUS_LOCATION
+	if test ! -d "$GLOBUS_LOCATION" ; then
+		AC_MSG_ERROR(Cannot find Globus installation.  Set GLOBUS_LOCATION environment variable.)
+	fi
+
+        if test "x$globus_flavor_type" = "xno" ; then
+                AC_MSG_ERROR(--with-globus-flavor=TYPE must be specified)
+	fi
+        if test "x$globus_flavor_type" = "xyes" ; then
+                AC_MSG_ERROR(--with-globus-flavor=TYPE must specify a flavor type)
+	fi
+
+	GLOBUS_INCLUDE="${gsi_path}/include/${globus_flavor_type}"
+	if test ! -d "$GLOBUS_INCLUDE" ; then
+		AC_MSG_ERROR(Cannot find Globus flavor-specific include directory: ${GLOBUS_INCLUDE})
+	fi
+	GSI_CPPFLAGS="-I${GLOBUS_INCLUDE}"
+	
+	if test -x ${gsi_path}/bin/globus-makefile-header ; then
+		GSI_LIBS=`${gsi_path}/bin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
+	elif test -x ${gsi_path}/sbin/globus-makefile-header ; then
+		GSI_LIBS=`${gsi_path}/sbin/globus-makefile-header --flavor=${globus_flavor_type} ${gsi_static} globus_gss_assist | perl -n -e 'if (/GLOBUS_PKG_LIBS = (.*)/){print $1;}'`
+	else
+		AC_MSG_ERROR(Cannot find globus-makefile-header: Globus installation is incomplete)
+	fi
+	if test -n "${need_dash_r}"; then
+		GSI_LDFLAGS="-L${gsi_path}/lib -R{gsi_path}/lib"
+	else
+		GSI_LDFLAGS="-L${gsi_path}/lib"
+	fi
+	if test -z "$GSI_LIBS" ; then
+		AC_MSG_ERROR(globus-makefile-header failed)
+	fi
+
+	AC_DEFINE(HAVE_GSSAPI_H)
+
+	LIBS="$LIBS $GSI_LIBS"
+	LDFLAGS="$LDFLAGS $GSI_LDFLAGS"
+	CPPFLAGS="$CPPFLAGS $GSI_CPPFLAGS"
+
+	# test that we got the libraries OK
+	AC_TRY_LINK(
+		[],
+		[],
+		[
+			AC_MSG_RESULT(yes)
+		],
+		[
+			AC_MSG_ERROR(link with Globus libraries failed)
+		]
+	)
+	INSTALL_GSISSH="yes"
+else
+	INSTALL_GSISSH=""
+fi
+AC_SUBST(INSTALL_GSISSH)
+# End Globus/GSI section
+
 AC_MSG_CHECKING([for /proc/pid/fd directory])
 if test -d "/proc/$$/fd" ; then
 	AC_DEFINE(HAVE_PROC_PID)
@@ -1346,7 +1483,9 @@
 		fi
 	]
 )
+if test -z "$GSI_LIBS" ; then
 LIBS="-lcrypto $LIBS"
+fi
 AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL),
 	[
 		dnl Check default openssl install dir
@@ -2490,7 +2629,21 @@
 			AC_CHECK_HEADER(gssapi_krb5.h, ,
 					[ CPPFLAGS="$oldCPP" ])
 
-		fi
+			# 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
+
+			if test -z "$GSSAPI"; then
+				GSSAPI="KRB5";
+			fi
+
+			oldCPP="$CPPFLAGS"
+			CPPFLAGS="$CPPFLAGS -I${KRB5ROOT}/include/gssapi"
+			AC_CHECK_HEADER(gssapi_krb5.h, ,
+					[ CPPFLAGS="$oldCPP" ])
+
+                fi
 		if test ! -z "$need_dash_r" ; then
 			LDFLAGS="$LDFLAGS -R${KRB5ROOT}/lib"
 		fi
@@ -2507,6 +2660,38 @@
 	AC_SEARCH_LIBS(k_hasafs, kafs, AC_DEFINE(USE_AFS))
 	AC_SEARCH_LIBS(krb5_init_ets, $K5LIBS, AC_DEFINE(KRB5_INIT_ETS))
 	]
+)
+
+# Check whether user wants AFS_KRB5 support
+AFS_KRB5_MSG="no"
+AC_ARG_WITH(afs-krb5,
+	[  --with-afs-krb5[[=AKLOG_PATH]]  Enable aklog to get token (default=/usr/bin/aklog).],
+	[
+		if test "x$withval" != "xno" ; then
+
+			if test "x$withval" != "xyes" ; then
+				AC_DEFINE_UNQUOTED(AKLOG_PATH, "$withval")
+			else
+				AC_DEFINE_UNQUOTED(AKLOG_PATH, "/usr/bin/aklog")
+			fi
+
+			if test -z "$KRB5ROOT" ; then
+				AC_MSG_WARN([AFS_KRB5 requires Kerberos 5 support, build may fail])
+			fi
+
+			LIBS="-lkrbafs -lkrb4 $LIBS"
+			if test ! -z "$AFS_LIBS" ; then
+				LIBS="$LIBS $AFS_LIBS"
+			fi
+			AC_DEFINE(AFS_KRB5)
+			AFS_KRB5_MSG="yes"
+		fi
+	]
+)
+
+AC_ARG_WITH(session-hooks,
+        [  --with-session-hooks    Enable hooks for executing external commands                                       before/after a session],
+        [ AC_DEFINE(SESSION_HOOKS) ]
 )
 
 # Looking for programs, paths and files
diff -Naur --exclude=autom4te.cache openssh-4.1p1/gss-genr.c openssh-4.1p1-gssapi/gss-genr.c
--- openssh-4.1p1/gss-genr.c	Fri Nov 21 06:56:47 2003
+++ openssh-4.1p1-gssapi/gss-genr.c	Thu May 26 14:53:11 2005
@@ -29,10 +29,14 @@
 #ifdef GSSAPI
 
 #include "xmalloc.h"
+#include "buffer.h"
 #include "bufaux.h"
 #include "compat.h"
+#include <openssl/evp.h>
+#include "kex.h"
 #include "log.h"
 #include "monitor_wrap.h"
+#include "canohost.h"
 #include "ssh2.h"
 
 #include "ssh-gss.h"
@@ -40,6 +44,116 @@
 extern u_char *session_id2;
 extern u_int session_id2_len;
 
+typedef struct {
+	char *encoded;
+	gss_OID oid;
+} ssh_gss_kex_mapping;
+	
+static ssh_gss_kex_mapping *gss_enc2oid;
+
+/* Return a list of the gss-group1-sha1-x mechanisms supported by this
+ * program.
+ *
+ * On the client side, we don't need to worry about whether we 'know'
+ * about the mechanism or not - we assume that any mechanism that we've been
+ * linked against is suitable for inclusion.
+ *
+ * XXX - We might want to make this configurable in the future, so as to
+ * XXX - allow the user control over which mechanisms to use.
+ */
+ 
+char * 
+ssh_gssapi_client_mechanisms(char *host) {
+	gss_OID_set 	supported;
+	OM_uint32	min_status;
+	Buffer		buf;
+	int 		i = 0;
+	char 		*mechs;
+	char		*encoded;
+	int		enclen;
+	char		digest[EVP_MAX_MD_SIZE];
+	char		deroid[2];
+	const EVP_MD	*evp_md = EVP_md5();
+	EVP_MD_CTX	md;
+	int 		oidpos=0;
+	
+	gss_indicate_mechs(&min_status,&supported);
+	gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
+			    *(supported->count+1));
+	
+	buffer_init(&buf);
+
+	for (i=0;i<supported->count;i++) {
+
+		gss_enc2oid[oidpos].encoded=NULL;
+		
+		if (supported->elements[i].length<128 &&
+		    ssh_gssapi_check_mechanism(&(supported->elements[i]),host)) {
+
+			/* Add the required DER encoding octets and MD5 hash */
+			deroid[0]=0x06; /* Object Identifier */
+			deroid[1]=supported->elements[i].length;
+
+			EVP_DigestInit(&md, evp_md);
+			EVP_DigestUpdate(&md,deroid,2);
+			EVP_DigestUpdate(&md,
+					 supported->elements[i].elements,
+					 supported->elements[i].length);
+			EVP_DigestFinal(&md, digest, NULL);
+			
+			/* Base64 encode it */
+			encoded=xmalloc(EVP_MD_size(evp_md)*2);
+			enclen=__b64_ntop(digest, EVP_MD_size(evp_md),
+				          encoded,EVP_MD_size(evp_md)*2);
+			if (oidpos!=0) {
+				buffer_put_char(&buf,',');
+			}	
+			buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1);
+			buffer_append(&buf, encoded, enclen);
+
+			debug("Mechanism encoded as %s",encoded);
+
+			gss_enc2oid[oidpos].oid=&(supported->elements[i]);
+			gss_enc2oid[oidpos].encoded=encoded;			
+			oidpos++;
+		}
+	}
+	gss_enc2oid[oidpos].oid=NULL;
+	gss_enc2oid[oidpos].encoded=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);
+}
+
+gss_OID
+ssh_gssapi_client_id_kex(Gssctxt *ctx, char *name) {
+	int i=0;
+	
+	if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
+		return(NULL);
+	}
+	
+	name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the ID string */
+	
+	while (gss_enc2oid[i].encoded!=NULL &&
+	       	strcmp(name,gss_enc2oid[i].encoded)!=0) {
+	      	i++;
+	}
+	
+	if (gss_enc2oid[i].oid!=NULL) {
+		ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid);
+	}
+
+	return gss_enc2oid[i].oid;
+}
+
 /* Check that the OID in a data stream matches that in the context */
 int
 ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len)
@@ -98,7 +212,7 @@
 	/* The GSSAPI error */
 	do {
 		gss_display_status(&lmin, ctxt->major,
-		    GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg);
+		    GSS_C_GSS_CODE, ctxt->oid, &ctx, &msg);
 
 		buffer_append(&b, msg.value, msg.length);
 		buffer_put_char(&b, '\n');
@@ -109,7 +223,7 @@
 	/* The mechanism specific error */
 	do {
 		gss_display_status(&lmin, ctxt->minor,
-		    GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg);
+		    GSS_C_MECH_CODE, ctxt->oid, &ctx, &msg);
 
 		buffer_append(&b, msg.value, msg.length);
 		buffer_put_char(&b, '\n');
@@ -148,10 +262,13 @@
 void
 ssh_gssapi_delete_ctx(Gssctxt **ctx)
 {
+#if !defined(MECHGLUE)
 	OM_uint32 ms;
+#endif
 
 	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)
@@ -167,6 +284,7 @@
 		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;
@@ -205,15 +323,25 @@
 ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
 {
 	gss_buffer_desc gssbuf;
+	char *xhost;
 
-	gssbuf.length = sizeof("host@") + strlen(host);
+	/* Make a copy of the host name, in case it was returned by a
+	 * previous call to gethostbyname(). */	
+	xhost = xstrdup(host);
+
+	/* Make sure we have the FQDN. Some GSSAPI implementations don't do
+	 * this for us themselves */
+	resolve_localhost(&xhost);
+	
+	gssbuf.length = sizeof("host@") + strlen(xhost);
 	gssbuf.value = xmalloc(gssbuf.length);
-	snprintf(gssbuf.value, gssbuf.length, "host@%s", host);
+	snprintf(gssbuf.value, gssbuf.length, "host@%s", xhost);
 
 	if ((ctx->major = gss_import_name(&ctx->minor,
 	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
 		ssh_gssapi_error(ctx);
 
+	xfree(xhost);
 	xfree(gssbuf.value);
 	return (ctx->major);
 }
@@ -276,6 +404,21 @@
 	ssh_gssapi_build_ctx(ctx);
 	ssh_gssapi_set_oid(*ctx, oid);
 	return (ssh_gssapi_acquire_cred(*ctx));
+}
+
+int
+ssh_gssapi_check_mechanism(gss_OID oid, const char *host) {
+	Gssctxt * ctx = NULL;
+	gss_buffer_desc token;
+	OM_uint32 major,minor;
+	
+	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);
+	ssh_gssapi_delete_ctx(&ctx);
+	return(!GSS_ERROR(major));
 }
 
 #endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/gss-serv-gsi.c openssh-4.1p1-gssapi/gss-serv-gsi.c
--- openssh-4.1p1/gss-serv-gsi.c	Wed Dec 31 18:00:00 1969
+++ openssh-4.1p1-gssapi/gss-serv-gsi.c	Thu May 26 14:53:11 2005
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2001-2003 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
+#ifdef GSI
+
+#include "auth.h"
+#include "auth-pam.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+#include <globus_gss_assist.h>
+
+static int ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name);
+static int ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user);
+static void ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client);
+
+ssh_gssapi_mech gssapi_gsi_mech = {
+	"dZuIebMjgUqaxvbF7hDbAw==",
+	"GSI",
+	{9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"},
+	NULL,
+	&ssh_gssapi_gsi_userok,
+	&ssh_gssapi_gsi_localname,
+	&ssh_gssapi_gsi_storecreds
+};
+
+/*
+ * 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.
+ */
+static int
+ssh_gssapi_gsi_userok(ssh_gssapi_client *client, char *name)
+{
+    int authorized = 0;
+    
+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+	return 0;
+    }
+#endif
+
+    /* This returns 0 on success */
+    authorized = (globus_gss_assist_userok(client->displayname.value,
+					   name) == 0);
+    
+    logit("GSI user %s is%s authorized as target user %s",
+	(char *) client->displayname.value, (authorized ? "" : " not"), name);
+    
+    return authorized;
+}
+
+/*
+ * Return the local username associated with the GSI credentials.
+ */
+int
+ssh_gssapi_gsi_localname(ssh_gssapi_client *client, char **user)
+{
+#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
+    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
+	return 0;
+    }
+#endif
+    return(globus_gss_assist_gridmap(client->displayname.value, user) == 0);
+}
+
+/*
+ * Export GSI credentials to disk.
+ */
+static void
+ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client)
+{
+	OM_uint32	major_status;
+	OM_uint32	minor_status;
+	gss_buffer_desc	export_cred = GSS_C_EMPTY_BUFFER;
+	char *		p;
+	
+	if (!client || !client->creds) {
+	    return;
+	}
+
+	major_status = gss_export_cred(&minor_status,
+				       client->creds,
+				       GSS_C_NO_OID,
+				       1,
+				       &export_cred);
+	if (GSS_ERROR(major_status) && major_status != GSS_S_UNAVAILABLE) {
+	    Gssctxt *ctx;
+	    ssh_gssapi_build_ctx(&ctx);
+	    ctx->major = major_status;
+	    ctx->minor = minor_status;
+	    ssh_gssapi_set_oid(ctx, &gssapi_gsi_mech.oid);
+	    ssh_gssapi_error(ctx);
+	    ssh_gssapi_delete_ctx(&ctx);
+	    return;
+	}
+	
+	p = strchr((char *) export_cred.value, '=');
+	if (p == NULL) {
+	    logit("Failed to parse exported credentials string '%.100s'",
+		(char *)export_cred.value);
+	    gss_release_buffer(&minor_status, &export_cred);
+	    return;
+	}
+	*p++ = '\0';
+	if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0) {
+	    client->store.envvar = strdup("X509_USER_PROXY");
+	} else {
+	    client->store.envvar = strdup((char *)export_cred.value);
+	}
+	client->store.envval = strdup(p);
+#ifdef USE_PAM
+	if (options.use_pam)
+	    do_pam_putenv(client->store.envvar, client->store.envval);
+#endif
+	if (strncmp(p, "FILE:", 5) == 0) {
+	    p += 5;
+	}
+	if (access(p, R_OK) == 0) {
+	    client->store.filename = strdup(p);
+	}
+	gss_release_buffer(&minor_status, &export_cred);
+}
+
+#endif /* GSI */
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/gss-serv-krb5.c openssh-4.1p1-gssapi/gss-serv-krb5.c
--- openssh-4.1p1/gss-serv-krb5.c	Sat Aug 14 08:55:38 2004
+++ openssh-4.1p1-gssapi/gss-serv-krb5.c	Thu May 26 14:53:11 2005
@@ -49,6 +49,20 @@
 #endif
 
 static krb5_context krb_context = NULL;
+static int ssh_gssapi_krb5_init();
+static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name);
+static int ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user);
+static void ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client);
+
+ssh_gssapi_mech gssapi_kerberos_mech = {
+	"toWM5Slw5Ew8Mqkay+al2g==",
+	"Kerberos",
+	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
+	NULL,
+	&ssh_gssapi_krb5_userok,
+	&ssh_gssapi_krb5_localname,
+	&ssh_gssapi_krb5_storecreds
+};
 
 /* Initialise the krb5 library, for the stuff that GSSAPI won't do */
 
@@ -104,6 +118,35 @@
 }
 
 
+/* Retrieve the local username associated with a set of Kerberos 
+ * credentials. Hopefully we can use this for the 'empty' username
+ * logins discussed in the draft  */
+static int
+ssh_gssapi_krb5_localname(ssh_gssapi_client *client, char **user) {
+	krb5_principal princ;
+	int retval;
+	
+	if (ssh_gssapi_krb5_init() == 0)
+		return 0;
+
+	if ((retval=krb5_parse_name(krb_context, client->displayname.value, 
+				    &princ))) {
+		logit("krb5_parse_name(): %.100s", 
+			krb5_get_err_text(krb_context,retval));
+		return 0;
+	}
+	
+	/* We've got to return a malloc'd string */
+	*user = (char *)xmalloc(256);
+	if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
+		xfree(*user);
+		*user = NULL;
+		return(0);
+	}
+	
+	return(1);
+}
+	
 /* This writes out any forwarded credentials from the structure populated
  * during userauth. Called after we have setuid to the user */
 
@@ -114,6 +157,7 @@
 	krb5_error_code problem;
 	krb5_principal princ;
 	OM_uint32 maj_status, min_status;
+	gss_cred_id_t krb5_cred_handle;
 	int len;
 
 	if (client->creds == NULL) {
@@ -180,8 +224,16 @@
 
 	krb5_free_principal(krb_context, princ);
 
-	if ((maj_status = gss_krb5_copy_ccache(&min_status,
-	    client->creds, ccache))) {
+#ifdef MECHGLUE
+	krb5_cred_handle =
+	    __gss_get_mechanism_cred(client->creds,
+				     &(gssapi_kerberos_mech.oid));
+#else
+	krb5_cred_handle = client->creds;
+#endif
+
+	if ((maj_status = gss_krb5_copy_ccache(&min_status, 
+	    krb5_cred_handle, ccache))) {
 		logit("gss_krb5_copy_ccache() failed");
 		krb5_cc_destroy(krb_context, ccache);
 		return;
@@ -202,16 +254,6 @@
 
 	return;
 }
-
-ssh_gssapi_mech gssapi_kerberos_mech = {
-	"toWM5Slw5Ew8Mqkay+al2g==",
-	"Kerberos",
-	{9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"},
-	NULL,
-	&ssh_gssapi_krb5_userok,
-	NULL,
-	&ssh_gssapi_krb5_storecreds
-};
 
 #endif /* KRB5 */
 
diff -Naur --exclude=autom4te.cache openssh-4.1p1/gss-serv.c openssh-4.1p1-gssapi/gss-serv.c
--- openssh-4.1p1/gss-serv.c	Mon Nov 17 05:18:22 2003
+++ openssh-4.1p1-gssapi/gss-serv.c	Thu May 26 14:53:11 2005
@@ -28,8 +28,11 @@
 
 #ifdef GSSAPI
 
+#include "buffer.h"
 #include "bufaux.h"
 #include "compat.h"
+#include <openssl/evp.h>
+#include "kex.h"
 #include "auth.h"
 #include "log.h"
 #include "channels.h"
@@ -42,6 +45,8 @@
 #include "ssh-gss.h"
 
 extern ServerOptions options;
+extern u_char *session_id2;
+extern int session_id2_len;
 
 static ssh_gssapi_client gssapi_client =
     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
@@ -53,14 +58,24 @@
 #ifdef KRB5
 extern ssh_gssapi_mech gssapi_kerberos_mech;
 #endif
+#ifdef GSI
+extern ssh_gssapi_mech gssapi_gsi_mech;
+#endif
 
 ssh_gssapi_mech* supported_mechs[]= {
 #ifdef KRB5
 	&gssapi_kerberos_mech,
 #endif
+#ifdef GSI
+	&gssapi_gsi_mech,
+#endif
 	&gssapi_null_mech,
 };
 
+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
+static int limited = 0;
+#endif
+
 /* Unpriviledged */
 void
 ssh_gssapi_supported_oids(gss_OID_set *oidset)
@@ -71,7 +86,8 @@
 	gss_OID_set supported;
 
 	gss_create_empty_oid_set(&min_status, oidset);
-	gss_indicate_mechs(&min_status, &supported);
+	/* Ask priviledged process what mechanisms it supports. */
+	PRIVSEP(gss_indicate_mechs(&min_status, &supported));
 
 	while (supported_mechs[i]->name != NULL) {
 		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
@@ -121,6 +137,10 @@
 	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
 		if (ssh_gssapi_getclient(ctx, &gssapi_client))
 			fatal("Couldn't convert client name");
+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
+		if (flags && (*flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG))
+			limited=1;
+#endif
 	}
 
 	return (status);
@@ -140,6 +160,17 @@
 
 	tok=ename->value;
 
+#ifdef GSI /* GSI gss_export_name() is broken. */
+	if ((ctx->oid->length == gssapi_gsi_mech.oid.length) &&
+	    (memcmp(ctx->oid->elements, gssapi_gsi_mech.oid.elements,
+		    gssapi_gsi_mech.oid.length) == 0)) {
+	    name->length = ename->length;
+	    name->value = xmalloc(ename->length+1);
+	    memcpy(name->value, ename->value, ename->length);
+	    return GSS_S_COMPLETE;
+	}
+#endif
+
 	/*
 	 * Check that ename is long enough for all of the fixed length
 	 * header, and that the initial ID bytes are correct
@@ -280,11 +311,141 @@
 		debug("No suitable client data");
 		return 0;
 	}
+#ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
+	if (limited) {
+		debug("limited proxy not acceptable for remote login");
+		return 0;
+	}
+#endif
 	if (gssapi_client.mech && gssapi_client.mech->userok)
 		return ((*gssapi_client.mech->userok)(&gssapi_client, user));
 	else
 		debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
 	return (0);
+}
+
+/* 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.
+ */
+
+/* Unpriviledged */ 
+char * 
+ssh_gssapi_server_mechanisms() {
+	gss_OID_set 	supported;
+	Gssctxt		*ctx = NULL;
+	OM_uint32	maj_status, min_status;
+	Buffer		buf;
+	int 		i = 0;
+	int		first = 0;
+	int		present;
+	char *		mechs;
+
+	ssh_gssapi_supported_oids(&supported);
+	
+	buffer_init(&buf);
+
+	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) {
+		    if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
+					   &supported_mechs[i]->oid)))) {
+			/* Append gss_group1_sha1_x to our list */
+			if (first++!=0)
+				buffer_put_char(&buf,',');
+			buffer_append(&buf, KEX_GSS_SHA1,
+				      sizeof(KEX_GSS_SHA1)-1);
+	        	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, KEX_GSS_SHA1,
+			      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);
+		}
+        	ssh_gssapi_delete_ctx(&ctx);
+        	i++;
+	}
+	
+	buffer_put_char(&buf,'\0');
+	
+	mechs=xmalloc(buffer_len(&buf));
+	buffer_get(&buf,mechs,buffer_len(&buf));
+	buffer_free(&buf);
+	if (strlen(mechs)==0) {
+	    options.gss_authentication = 0; /* no mechs. skip gss auth. */
+	    return(NULL);
+	} else {
+	    return(mechs);
+	}
+}
+
+/* Return the OID that corresponds to the given context name */
+ 
+/* Unpriviledged */
+gss_OID 
+ssh_gssapi_server_id_kex(char *name) {
+  int i=0;
+  
+  if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
+     return(NULL);
+  }
+  
+  name+=sizeof(KEX_GSS_SHA1)-1; /* 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);
+
+  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
+	KEX_GSS_SHA1, supported_mechs[i]->enc_name);
+
+  return &supported_mechs[i]->oid;
+}
+
+/* Priviledged */
+int
+ssh_gssapi_localname(char **user)
+{
+    	*user = NULL;
+	if (gssapi_client.displayname.length==0 || 
+	    gssapi_client.displayname.value==NULL) {
+		debug("No suitable client data");
+		return(0);;
+	}
+	if (gssapi_client.mech && gssapi_client.mech->localname) {
+		return((*gssapi_client.mech->localname)(&gssapi_client,user));
+	} else {
+		debug("Unknown client authentication type");
+	}
+	return(0);
 }
 
 /* Priviledged */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/kex.c openssh-4.1p1-gssapi/kex.c
--- openssh-4.1p1/kex.c	Mon Jun 21 21:56:02 2004
+++ openssh-4.1p1-gssapi/kex.c	Thu May 26 14:53:11 2005
@@ -42,6 +42,10 @@
 #include "dispatch.h"
 #include "monitor.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 #define KEX_COOKIE_LEN	16
 
 /* prototype */
@@ -297,6 +301,10 @@
 		k->kex_type = KEX_DH_GRP14_SHA1;
 	} else if (strcmp(k->name, KEX_DHGEX) == 0) {
 		k->kex_type = KEX_DH_GEX_SHA1;
+#ifdef GSSAPI
+	} else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
+		k->kex_type = KEX_GSS_GRP1_SHA1;
+#endif
 	} else
 		fatal("bad kex alg %s", k->name);
 }
diff -Naur --exclude=autom4te.cache openssh-4.1p1/kex.h openssh-4.1p1-gssapi/kex.h
--- openssh-4.1p1/kex.h	Mon Jun 14 19:30:09 2004
+++ openssh-4.1p1-gssapi/kex.h	Thu May 26 14:53:11 2005
@@ -59,6 +59,7 @@
 	KEX_DH_GRP1_SHA1,
 	KEX_DH_GRP14_SHA1,
 	KEX_DH_GEX_SHA1,
+	KEX_GSS_GRP1_SHA1,
 	KEX_MAX
 };
 
@@ -97,6 +98,11 @@
 	Mac	mac;
 	Comp	comp;
 };
+
+struct KexOptions {
+	int	gss_deleg_creds;
+};
+
 struct Kex {
 	u_char	*session_id;
 	u_int	session_id_len;
@@ -112,6 +118,7 @@
 	int	flags;
 	char	*client_version_string;
 	char	*server_version_string;
+	struct  KexOptions options;
 	int	(*verify_host_key)(Key *);
 	Key	*(*load_host_key)(int);
 	int	(*host_key_index)(Key *);
@@ -131,6 +138,10 @@
 void	 kexdh_server(Kex *);
 void	 kexgex_client(Kex *);
 void	 kexgex_server(Kex *);
+#ifdef GSSAPI
+void     kexgss_client(Kex *);
+void     kexgss_server(Kex *);
+#endif
 
 u_char *
 kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
diff -Naur --exclude=autom4te.cache openssh-4.1p1/kexgssc.c openssh-4.1p1-gssapi/kexgssc.c
--- openssh-4.1p1/kexgssc.c	Wed Dec 31 18:00:00 1969
+++ openssh-4.1p1-gssapi/kexgssc.c	Thu May 26 14:53:11 2005
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2001-2003 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 "canohost.h"
+#include "ssh2.h"
+#include "ssh-gss.h"
+
+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;
+	char *msg;
+	char *lang;
+	int type = 0;
+	int first = 1;
+	int slen = 0;
+	u_int strlen;
+	
+	/* Initialise our GSSAPI world */
+	ssh_gssapi_build_ctx(&ctxt);
+	if (ssh_gssapi_client_id_kex(ctxt,kex->name)==NULL) {
+		fatal("Couldn't identify host exchange");
+	}
+
+	if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1))) {
+		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)) {
+			if (send_tok.length!=0) {
+				packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+				packet_put_string(send_tok.value,
+						  send_tok.length);
+			}			  
+			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(&strlen);
+				recv_tok.length=strlen; /* u_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(&strlen);
+				msg_tok.length=strlen; /* u_int vs. size_t */
+
+				/* Is there a token included? */
+				if (packet_get_char()) {
+					recv_tok.value=
+					    packet_get_string(&strlen);
+					recv_tok.length=strlen; /*u_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;
+			case SSH2_MSG_KEXGSS_ERROR:
+				debug("Received Error");
+				maj_status=packet_get_int();
+				min_status=packet_get_int();
+				msg=packet_get_string(NULL);
+				lang=packet_get_string(NULL);
+				fatal("GSSAPI Key Exchange Error: \n%s",msg);
+			default:
+				packet_disconnect("Protocol error: didn't expect packet type %d",
+		    		type);
+			}
+			token_ptr=&recv_tok;
+		} else {
+			/* No data, and not complete */
+			if (maj_status!=GSS_S_COMPLETE) {
+				fatal("Not complete, and no token output");
+			}
+		}
+    	} 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);
+        
+        /* The GSS hash is identical to the DH one */
+        hash = kex_dh_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);
+}
+
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/kexgsss.c openssh-4.1p1-gssapi/kexgsss.c
--- openssh-4.1p1/kexgsss.c	Wed Dec 31 18:00:00 1969
+++ openssh-4.1p1-gssapi/kexgsss.c	Thu May 26 14:53:11 2005
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2001-2003 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"
+
+static void kex_gss_send_error(Gssctxt *ctxt);
+
+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;
+	u_int slen;
+	gss_OID oid;
+	
+	/* Initialise GSSAPI */
+
+	debug2("%s: Identifying %s",__func__,kex->name);
+	oid=ssh_gssapi_server_id_kex(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)))) {
+		kex_gss_send_error(ctxt);
+        	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)
+        			packet_disconnect("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:
+			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);
+		
+		if (dh_client_pub == NULL)
+			fatal("No client public key");
+		
+		if (maj_status & GSS_S_CONTINUE_NEEDED ||
+		    (maj_status == GSS_S_COMPLETE && send_tok.length > 0)) {
+			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)) {
+		kex_gss_send_error(ctxt);
+		if (send_tok.length>0) {
+			packet_start(SSH2_MSG_KEXGSS_CONTINUE);
+			packet_put_string(send_tok.value,send_tok.length);
+			packet_send();
+			packet_write_wait();
+		}	
+		packet_disconnect("gssapi key exchange handshake failed");
+	}
+	
+	debug("gss_complete");
+	if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+		packet_disconnect("gssapi_mutual authentication failed");
+		
+	if (!(ret_flags & GSS_C_INTEG_FLAG))
+		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);
+	
+	/* The GSSAPI hash is identical to the Diffie Helman one */
+        hash = kex_dh_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)))) {
+		kex_gss_send_error(ctxt);
+		fatal("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);
+}
+
+static void 
+kex_gss_send_error(Gssctxt *ctxt) {
+	char *errstr;
+	OM_uint32 maj,min;
+		
+	errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+	if (errstr) {
+		packet_start(SSH2_MSG_KEXGSS_ERROR);
+		packet_put_int(maj);
+		packet_put_int(min);
+		packet_put_cstring(errstr);
+		packet_put_cstring("");
+		packet_send();
+		packet_write_wait();
+		/* XXX - We should probably log the error locally here */
+		xfree(errstr);
+	}
+}
+#endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/key.c openssh-4.1p1-gssapi/key.c
--- openssh-4.1p1/key.c	Fri Nov  5 03:42:29 2004
+++ openssh-4.1p1-gssapi/key.c	Thu May 26 14:53:11 2005
@@ -650,6 +650,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-4.1p1/key.h openssh-4.1p1-gssapi/key.h
--- openssh-4.1p1/key.h	Mon Nov 17 04:18:23 2003
+++ openssh-4.1p1-gssapi/key.h	Thu May 26 14:53:11 2005
@@ -34,6 +34,7 @@
 	KEY_RSA1,
 	KEY_RSA,
 	KEY_DSA,
+	KEY_NULL,
 	KEY_UNSPEC
 };
 enum fp_type {
diff -Naur --exclude=autom4te.cache openssh-4.1p1/misc.c openssh-4.1p1-gssapi/misc.c
--- openssh-4.1p1/misc.c	Mon Mar 14 06:08:12 2005
+++ openssh-4.1p1-gssapi/misc.c	Thu May 26 14:53:11 2005
@@ -119,11 +119,14 @@
 /* Characters considered whitespace in strsep calls. */
 #define WHITESPACE " \t\r\n"
 
+/* Characters considered as quotations. */
+#define QUOTES "'\""
+
 /* return next token in configuration line */
 char *
 strdelim(char **s)
 {
-	char *old;
+	char *old, *p, *q;
 	int wspace = 0;
 
 	if (*s == NULL)
@@ -131,7 +134,22 @@
 
 	old = *s;
 
-	*s = strpbrk(*s, WHITESPACE "=");
+        if ((q=strchr(QUOTES, (int) *old)) && *q)
+        {
+            /* find next quote character, point old to start of quoted
+             * string */
+            for (p = ++old;*p && *p!=*q; p++)
+                 ;
+            
+            /* find start of next token */
+            *s = (*p) ? p + strspn(p + 1, WHITESPACE) + 1 : NULL;
+            
+            /* terminate 'old' token */
+            *p = '\0';
+            return (old);
+        }
+
+        *s = strpbrk(*s, WHITESPACE "=");
 	if (*s == NULL)
 		return (old);
 
diff -Naur --exclude=autom4te.cache openssh-4.1p1/monitor.c openssh-4.1p1-gssapi/monitor.c
--- openssh-4.1p1/monitor.c	Sat Apr  2 20:44:23 2005
+++ openssh-4.1p1-gssapi/monitor.c	Thu May 26 14:53:11 2005
@@ -143,6 +143,16 @@
 int mm_answer_gss_checkmic(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_sign(int, Buffer *);
+int mm_answer_gss_error(int, Buffer *);
+int mm_answer_gss_indicate_mechs(int, Buffer *);
+int mm_answer_gss_localname(int, Buffer *);
+#endif
+
 #ifdef SSH_AUDIT_EVENTS
 int mm_answer_audit_event(int, Buffer *);
 int mm_answer_audit_command(int, Buffer *);
@@ -179,12 +189,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},
     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
@@ -208,12 +218,23 @@
     {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+    {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
+    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
+    {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+    {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
     {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
 #endif
     {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},
+    {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
+    {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
+#endif
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
     {MONITOR_REQ_PTY, 0, mm_answer_pty},
@@ -243,8 +264,15 @@
     {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_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
+#endif
 #ifdef USE_PAM
-    {MONITOR_REQ_PAM_START, MON_ONCE, mm_answer_pam_start},
+    {MONITOR_REQ_PAM_START, MON_ISAUTH, mm_answer_pam_start},
     {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account},
     {MONITOR_REQ_PAM_INIT_CTX, MON_ISAUTH, mm_answer_pam_init_ctx},
     {MONITOR_REQ_PAM_QUERY, MON_ISAUTH, mm_answer_pam_query},
@@ -318,6 +346,12 @@
 		/* 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_GSSERR, 1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
+#endif
 	} else {
 		mon_dispatch = mon_dispatch_proto15;
 
@@ -391,10 +425,21 @@
 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
+
+#ifdef GSSAPI
+		/* and for the GSSAPI key exchange */
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1);
+#endif
+
 	} else {
 		mon_dispatch = mon_dispatch_postauth15;
 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
 	}
+#ifdef GSSAPI		
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
+#endif
 	if (!no_pty_flag) {
 		monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_PTYCLEANUP, 1);
@@ -579,13 +624,11 @@
 
 	debug3("%s", __func__);
 
-	if (authctxt->attempt++ != 0)
-		fatal("%s: multiple attempts for getpwnam", __func__);
-
 	username = buffer_get_string(m, NULL);
 
 	pwent = getpwnamallow(username);
 
+	if (authctxt->user) xfree(authctxt->user);
 	authctxt->user = xstrdup(username);
 	setproctitle("%s [priv]", pwent ? username : "unknown");
 	xfree(username);
@@ -1623,6 +1666,9 @@
 	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+#ifdef GSSAPI
+	kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+#endif
 	kex->server = 1;
 	kex->hostkey_type = buffer_get_int(m);
 	kex->kex_type = buffer_get_int(m);
@@ -1864,6 +1910,7 @@
 	if (major==GSS_S_COMPLETE) {
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
 	}
 	return (0);
@@ -1914,5 +1961,105 @@
 
 	/* Monitor loop will terminate if authenticated */
 	return (authenticated);
+}
+
+int
+mm_answer_gss_sign(int socket, Buffer *m) {
+        gss_buffer_desc data,hash;
+        OM_uint32 major,minor;
+	u_int len;
+
+        data.value = buffer_get_string(m, &len);
+	data.length = len;
+        if (data.length != 20)
+		fatal("%s: data length incorrect: %d", __func__,
+		      (int)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);
+        }
+        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);
+}
+
+int
+mm_answer_gss_error(int socket, Buffer *m) {
+        OM_uint32 major,minor;
+        char *msg;
+
+	msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
+	buffer_clear(m);
+	buffer_put_int(m,major);
+	buffer_put_int(m,minor);
+	buffer_put_cstring(m,msg);
+
+	mm_request_send(socket,MONITOR_ANS_GSSERR,m);
+
+	xfree(msg);
+	
+        return(0);
+}
+
+int
+mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
+        OM_uint32 major,minor;
+	gss_OID_set mech_set;
+	int i;
+
+	major=gss_indicate_mechs(&minor, &mech_set);
+
+	buffer_clear(m);
+	buffer_put_int(m, major);
+	buffer_put_int(m, mech_set->count);
+	for (i=0; i < mech_set->count; i++) {
+	    buffer_put_string(m, mech_set->elements[i].elements,
+			      mech_set->elements[i].length);
+	}
+
+#if !defined(MECHGLUE) /* mechglue memory management bug ??? */
+	gss_release_oid_set(&minor,&mech_set);
+#endif
+	
+	mm_request_send(socket,MONITOR_ANS_GSSMECHS,m);
+
+	return(0);
+}
+
+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);
 }
 #endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/monitor.h openssh-4.1p1-gssapi/monitor.h
--- openssh-4.1p1/monitor.h	Wed Feb  2 07:20:53 2005
+++ openssh-4.1p1-gssapi/monitor.h	Thu May 26 14:53:11 2005
@@ -52,6 +52,10 @@
 	MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
 	MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
 	MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
+	MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
+	MONITOR_REQ_GSSMECHS, MONITOR_ANS_GSSMECHS,
+	MONITOR_REQ_GSSLOCALNAME, MONITOR_ANS_GSSLOCALNAME,
+	MONITOR_REQ_GSSERR, MONITOR_ANS_GSSERR,
 	MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
 	MONITOR_REQ_PAM_START,
 	MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
diff -Naur --exclude=autom4te.cache openssh-4.1p1/monitor_wrap.c openssh-4.1p1-gssapi/monitor_wrap.c
--- openssh-4.1p1/monitor_wrap.c	Tue Feb  8 04:52:48 2005
+++ openssh-4.1p1-gssapi/monitor_wrap.c	Thu May 26 14:53:11 2005
@@ -1217,4 +1217,102 @@
 	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
 	return (authenticated);
 }
+
+OM_uint32
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
+        Buffer m;
+        OM_uint32 major;
+	u_int len;
+
+        buffer_init(&m);
+        buffer_put_string(&m, data->value, data->length);
+
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+
+        major=buffer_get_int(&m);
+        hash->value = buffer_get_string(&m, &len);
+	hash->length = len;
+
+	buffer_free(&m);
+	
+        return(major);
+}
+
+char *
+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
+	Buffer m;
+	OM_uint32 maj,min;
+	char *errstr;
+	
+	buffer_init(&m);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
+
+	maj = buffer_get_int(&m);
+	min = buffer_get_int(&m);
+
+	if (major) *major=maj;
+	if (minor) *minor=min;
+	
+	errstr=buffer_get_string(&m,NULL);
+
+	buffer_free(&m);
+	
+	return(errstr);
+}	
+
+OM_uint32
+mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
+{
+        Buffer m;
+	OM_uint32 major,minor;
+	int count;
+	gss_OID_desc oid;
+        u_int length;
+
+	buffer_init(&m);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
+        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
+				  &m);
+        major=buffer_get_int(&m);
+	count=buffer_get_int(&m);
+	
+        gss_create_empty_oid_set(&minor,mech_set);
+	while(count-->0) {
+	    oid.elements=buffer_get_string(&m,&length);
+	    oid.length=length;
+	    gss_add_oid_set_member(&minor,&oid,mech_set);
+	}
+
+	buffer_free(&m);
+	
+        return(major);
+}
+
+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);
+}	
 #endif /* GSSAPI */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/monitor_wrap.h openssh-4.1p1-gssapi/monitor_wrap.h
--- openssh-4.1p1/monitor_wrap.h	Tue Feb  8 04:52:48 2005
+++ openssh-4.1p1-gssapi/monitor_wrap.h	Thu May 26 14:53:11 2005
@@ -63,6 +63,12 @@
    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
 int mm_ssh_gssapi_userok(char *user);
 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *ctxt, gss_buffer_desc *buffer,
+			     gss_buffer_desc *hash);
+int mm_ssh_gssapi_localname(char **user);
+OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
+				gss_OID_set *mech_set);
+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
 #endif
 
 #ifdef USE_PAM
diff -Naur --exclude=autom4te.cache openssh-4.1p1/openbsd-compat/port-aix.h openssh-4.1p1-gssapi/openbsd-compat/port-aix.h
--- openssh-4.1p1/openbsd-compat/port-aix.h	Mon Mar 21 05:46:34 2005
+++ openssh-4.1p1-gssapi/openbsd-compat/port-aix.h	Thu May 26 14:53:12 2005
@@ -38,6 +38,7 @@
 # include <login.h>
 # include <userpw.h>
 # if defined(HAVE_SYS_AUDIT_H) && defined(AIX_LOGINFAILED_4ARG)
+#  undef T_NULL
 #  include <sys/audit.h>
 # endif
 # include <usersec.h>
diff -Naur --exclude=autom4te.cache openssh-4.1p1/readconf.c openssh-4.1p1-gssapi/readconf.c
--- openssh-4.1p1/readconf.c	Mon Mar 14 06:08:12 2005
+++ openssh-4.1p1-gssapi/readconf.c	Thu May 26 14:53:11 2005
@@ -104,7 +104,7 @@
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
-	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
+	oAddressFamily, oGssAuthentication, oGssKeyEx, oGssDelegateCreds,
 	oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
 	oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
 	oDeprecated, oUnsupported
@@ -139,9 +139,11 @@
 	{ "afstokenpassing", oUnsupported },
 #if defined(GSSAPI)
 	{ "gssapiauthentication", oGssAuthentication },
+	{ "gssapikeyexchange", oGssKeyEx },
 	{ "gssapidelegatecredentials", oGssDelegateCreds },
 #else
 	{ "gssapiauthentication", oUnsupported },
+	{ "gssapikeyexchange", oUnsupported },
 	{ "gssapidelegatecredentials", oUnsupported },
 #endif
 	{ "fallbacktorsh", oDeprecated },
@@ -406,6 +408,10 @@
 		intptr = &options->gss_authentication;
 		goto parse_flag;
 
+	case oGssKeyEx:
+	    	intptr = &options->gss_keyex;
+		goto parse_flag;
+
 	case oGssDelegateCreds:
 		intptr = &options->gss_deleg_creds;
 		goto parse_flag;
@@ -893,6 +899,7 @@
 	options->pubkey_authentication = -1;
 	options->challenge_response_authentication = -1;
 	options->gss_authentication = -1;
+	options->gss_keyex = -1;
 	options->gss_deleg_creds = -1;
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
@@ -974,9 +981,11 @@
 	if (options->challenge_response_authentication == -1)
 		options->challenge_response_authentication = 1;
 	if (options->gss_authentication == -1)
-		options->gss_authentication = 0;
+		options->gss_authentication = 1;
+	if (options->gss_keyex == -1)
+		options->gss_keyex = 1;
 	if (options->gss_deleg_creds == -1)
-		options->gss_deleg_creds = 0;
+		options->gss_deleg_creds = 1;
 	if (options->password_authentication == -1)
 		options->password_authentication = 1;
 	if (options->kbd_interactive_authentication == -1)
diff -Naur --exclude=autom4te.cache openssh-4.1p1/readconf.h openssh-4.1p1-gssapi/readconf.h
--- openssh-4.1p1/readconf.h	Tue Mar  1 04:47:37 2005
+++ openssh-4.1p1-gssapi/readconf.h	Thu May 26 14:53:11 2005
@@ -45,6 +45,7 @@
 	int     challenge_response_authentication;
 					/* Try S/Key or TIS, authentication. */
 	int     gss_authentication;	/* Try GSS authentication */
+	int	gss_keyex;
 	int     gss_deleg_creds;	/* Delegate GSS credentials */
 	int     password_authentication;	/* Try password
 						 * authentication. */
@@ -76,6 +77,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-4.1p1/servconf.c openssh-4.1p1-gssapi/servconf.c
--- openssh-4.1p1/servconf.c	Mon Mar 14 06:08:12 2005
+++ openssh-4.1p1-gssapi/servconf.c	Thu May 26 14:53:11 2005
@@ -70,8 +70,14 @@
 	options->kerberos_authentication = -1;
 	options->kerberos_or_local_passwd = -1;
 	options->kerberos_ticket_cleanup = -1;
+#ifdef  SESSION_HOOKS
+        options->session_hooks_allow = -1;
+        options->session_hooks_startup_cmd = NULL;
+        options->session_hooks_shutdown_cmd = NULL;
+#endif
 	options->kerberos_get_afs_token = -1;
 	options->gss_authentication=-1;
+	options->gss_keyex=-1;
 	options->gss_cleanup_creds = -1;
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
@@ -185,7 +191,9 @@
 	if (options->kerberos_get_afs_token == -1)
 		options->kerberos_get_afs_token = 0;
 	if (options->gss_authentication == -1)
-		options->gss_authentication = 0;
+		options->gss_authentication = 1;
+	if (options->gss_keyex == -1)
+		options->gss_keyex = 1;
 	if (options->gss_cleanup_creds == -1)
 		options->gss_cleanup_creds = 1;
 	if (options->password_authentication == -1)
@@ -257,6 +265,9 @@
 	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
 	sKerberosGetAFSToken,
 	sKerberosTgtPassing, sChallengeResponseAuthentication,
+#ifdef SESSION_HOOKS
+        sAllowSessionHooks, sSessionHookStartupCmd, sSessionHookShutdownCmd,
+#endif
 	sPasswordAuthentication, sKbdInteractiveAuthentication,
 	sListenAddress, sAddressFamily,
 	sPrintMotd, sPrintLastLog, sIgnoreRhosts,
@@ -271,6 +282,7 @@
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv,
+	sGssKeyEx, 
 	sUsePrivilegeSeparation,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
@@ -324,11 +336,18 @@
 	{ "afstokenpassing", sUnsupported },
 #ifdef GSSAPI
 	{ "gssapiauthentication", sGssAuthentication },
+	{ "gssapikeyexchange", sGssKeyEx },
 	{ "gssapicleanupcredentials", sGssCleanupCreds },
 #else
 	{ "gssapiauthentication", sUnsupported },
+	{ "gssapikeyexchange", sUnsupported },
 	{ "gssapicleanupcredentials", sUnsupported },
 #endif
+#ifdef SESSION_HOOKS
+        { "allowsessionhooks", sAllowSessionHooks },
+        { "sessionhookstartupcmd", sSessionHookStartupCmd },
+        { "sessionhookshutdowncmd", sSessionHookShutdownCmd },
+#endif        
 	{ "passwordauthentication", sPasswordAuthentication },
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication },
@@ -659,9 +678,30 @@
 		intptr = &options->gss_authentication;
 		goto parse_flag;
 
+	case sGssKeyEx:
+		intptr = &options->gss_keyex;
+		goto parse_flag;
+
 	case sGssCleanupCreds:
 		intptr = &options->gss_cleanup_creds;
 		goto parse_flag;
+
+#ifdef SESSION_HOOKS
+        case sAllowSessionHooks:
+                intptr = &options->session_hooks_allow;
+                goto parse_flag;
+        case sSessionHookStartupCmd:
+        case sSessionHookShutdownCmd:
+                arg = strdelim(&cp);
+                if (!arg || *arg == '\0')
+                    fatal("%s line %d: empty session hook command",
+                          filename, linenum);
+                if (opcode==sSessionHookStartupCmd)
+                    options->session_hooks_startup_cmd = strdup(arg);
+                else
+                    options->session_hooks_shutdown_cmd = strdup(arg);
+                break;
+#endif                  
 
 	case sPasswordAuthentication:
 		intptr = &options->password_authentication;
diff -Naur --exclude=autom4te.cache openssh-4.1p1/servconf.h openssh-4.1p1-gssapi/servconf.h
--- openssh-4.1p1/servconf.h	Wed Jan 19 17:57:56 2005
+++ openssh-4.1p1-gssapi/servconf.h	Thu May 26 14:53:11 2005
@@ -85,9 +85,15 @@
 						 * /etc/passwd */
 	int     kerberos_ticket_cleanup;	/* If true, destroy ticket
 						 * file on logout. */
+#ifdef SESSION_HOOKS
+        int     session_hooks_allow;        /* If true, permit user hooks */
+        char*   session_hooks_startup_cmd;  /* cmd to be executed before */
+        char*   session_hooks_shutdown_cmd; /* cmd to be executed after */
+#endif
 	int     kerberos_get_afs_token;		/* If true, try to get AFS token if
 						 * authenticated with Kerberos. */
 	int     gss_authentication;	/* If true, permit GSSAPI authentication */
+	int     gss_keyex;		/* If true, permit GSSAPI key exchange. */
 	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
 	int     password_authentication;	/* If true, permit password
 						 * authentication. */
diff -Naur --exclude=autom4te.cache openssh-4.1p1/session.c openssh-4.1p1-gssapi/session.c
--- openssh-4.1p1/session.c	Thu Apr 21 04:50:55 2005
+++ openssh-4.1p1-gssapi/session.c	Thu May 26 14:53:11 2005
@@ -89,6 +89,11 @@
 
 static int session_pty_req(Session *);
 
+#ifdef SESSION_HOOKS
+static void execute_session_hook(char* prog, Authctxt *authctxt,
+                                 int startup, int save);
+#endif
+
 /* import */
 extern ServerOptions options;
 extern char *__progname;
@@ -226,6 +231,21 @@
 	else
 		do_authenticated1(authctxt);
 
+#ifdef SESSION_HOOKS
+        if (options.session_hooks_allow &&
+            options.session_hooks_shutdown_cmd)
+        {
+            execute_session_hook(options.session_hooks_shutdown_cmd,
+                                 authctxt,
+                                 /* startup = */ 0, /* save = */ 0);
+
+            if (authctxt->session_env_file)
+            {
+                free(authctxt->session_env_file);
+            }
+        }
+#endif
+
 	do_cleanup(authctxt);
 }
 
@@ -665,6 +685,34 @@
 		debug("Forced command '%.900s'", command);
 	}
 
+#if defined(SESSION_HOOKS)
+	if (options.session_hooks_allow &&
+	    (options.session_hooks_startup_cmd ||
+	     options.session_hooks_shutdown_cmd))
+	{
+		char env_file[1000];
+		struct stat st;
+		do
+		{
+			snprintf(env_file,
+				 sizeof(env_file),
+				 "/tmp/ssh_env_%d%d%d",
+				 getuid(),
+				 getpid(),
+				 rand());
+		} while (stat(env_file, &st)==0);
+		s->authctxt->session_env_file = strdup(env_file);
+	}
+#endif
+
+#ifdef GSSAPI
+	if (options.gss_authentication) {
+		temporarily_use_uid(s->pw);
+		ssh_gssapi_storecreds();
+		restore_uid();
+	}
+#endif
+
 #ifdef SSH_AUDIT_EVENTS
 	if (command != NULL)
 		PRIVSEP(audit_run_command(command));
@@ -891,6 +939,117 @@
 	fclose(f);
 }
 
+#ifdef SESSION_HOOKS
+#define SSH_SESSION_ENV_FILE "SSH_SESSION_ENV_FILE"
+
+typedef enum { no_op, execute, clear_env, restore_env,
+               read_env, save_or_rm_env } session_action_t;
+
+static session_action_t action_order[2][5] = {
+    { clear_env, read_env, execute, save_or_rm_env, restore_env }, /*shutdown*/
+    { execute, read_env, save_or_rm_env, no_op, no_op }            /*startup */
+};
+
+static
+void execute_session_hook(char* prog, Authctxt *authctxt,
+                          int startup, int save)
+{
+    extern char **environ;
+
+    struct stat  st;
+    char         **saved_env, **tmpenv;
+    char         *env_file = authctxt->session_env_file;
+    int          i, status = 0;
+
+    for (i=0; i<5; i++)
+    {
+        switch (action_order[startup][i])
+        {
+          case no_op:
+            break;
+
+          case execute:
+            {
+                FILE* fp;
+                char  buf[1000];
+
+                snprintf(buf,
+                         sizeof(buf),
+                         "%s -c '%s'",
+                         authctxt->pw->pw_shell,
+                         prog);
+
+                debug("executing session hook: [%s]", buf);
+                setenv(SSH_SESSION_ENV_FILE, env_file, /* overwrite = */ 1);
+
+                /* flusing is recommended in the popen(3) man page, to avoid
+                   intermingling of output */
+                fflush(stdout);
+                fflush(stderr);
+                if ((fp=popen(buf, "w")) == NULL)
+                {
+                    perror("Unable to run session hook");
+                    return;
+                }
+                status = pclose(fp);
+                debug2("session hook executed, status=%d", status);
+                unsetenv(SSH_SESSION_ENV_FILE);
+            }
+            break;
+
+          case clear_env:
+            saved_env = environ;
+            tmpenv = (char**) malloc(sizeof(char*));
+            tmpenv[0] = NULL;
+            environ = tmpenv;
+            break;
+
+          case restore_env:
+            environ = saved_env;
+            free(tmpenv);
+            break;
+
+          case read_env:
+            if (status==0 && stat(env_file, &st)==0)
+            {
+                int envsize = 0;
+
+                debug("reading environment from %s", env_file);
+                while (environ[envsize++]) ;
+                read_environment_file(&environ, &envsize, env_file);
+            }
+            break;
+
+          case save_or_rm_env:
+            if (status==0 && save)
+            {
+                FILE* fp;
+                int    envcount=0;
+
+                debug2("saving environment to %s", env_file);
+                if ((fp = fopen(env_file, "w")) == NULL) /* hmm: file perms? */
+                {
+                    perror("Unable to save session hook info");
+                }
+                while (environ[envcount])
+                {
+                    fprintf(fp, "%s\n", environ[envcount++]);
+                }
+                fflush(fp);
+                fclose(fp);
+            }
+            else if (stat(env_file, &st)==0)
+            {
+                debug2("removing environment file %s", env_file);
+                remove(env_file);
+            }
+            break;
+        }
+    }
+
+}
+#endif
+
 #ifdef HAVE_ETC_DEFAULT_LOGIN
 /*
  * Return named variable from specified environment, or NULL if not present.
@@ -1050,6 +1209,23 @@
 	if (getenv("TZ"))
 		child_set_env(&env, &envsize, "TZ", getenv("TZ"));
 
+#ifdef GSI /* GSI shared libs typically installed in non-system locations. */
+	{
+		char *cp;
+
+		if ((cp = getenv("LD_LIBRARY_PATH")) != NULL)
+			child_set_env(&env, &envsize, "LD_LIBRARY_PATH", cp);
+		if ((cp = getenv("LIBPATH")) != NULL)
+			child_set_env(&env, &envsize, "LIBPATH", cp);
+		if ((cp = getenv("SHLIB_PATH")) != NULL)
+			child_set_env(&env, &envsize, "SHLIB_PATH", cp);
+		if ((cp = getenv("LD_LIBRARYN32_PATH")) != NULL)
+			child_set_env(&env, &envsize, "LD_LIBRARYN32_PATH",cp);
+		if ((cp = getenv("LD_LIBRARY64_PATH")) != NULL)
+			child_set_env(&env, &envsize, "LD_LIBRARY64_PATH",cp);
+	}
+#endif
+
 	/* Set custom environment options from RSA authentication. */
 	if (!options.use_login) {
 		while (custom_environment) {
@@ -1435,6 +1611,18 @@
 	const char *shell, *shell0, *hostname = NULL;
 	struct passwd *pw = s->pw;
 
+#ifdef AFS_KRB5
+/* Default place to look for aklog. */
+#ifdef AKLOG_PATH
+#define KPROGDIR AKLOG_PATH
+#else
+#define KPROGDIR "/usr/bin/aklog"
+#endif /* AKLOG_PATH */
+
+	struct stat st;
+	char *aklog_path;
+#endif /* AFS_KRB5 */
+
 	/* remove hostkey from the child's memory */
 	destroy_sensitive_data();
 
@@ -1545,6 +1733,41 @@
 	}
 #endif
 
+#ifdef AFS_KRB5
+
+	/* User has authenticated, and if a ticket was going to be
+	 * passed we would have it.  KRB5CCNAME should already be set.
+	 * Now try to get an AFS token using aklog.
+	 */
+	if (k_hasafs()) {  /* Do we have AFS? */
+
+		aklog_path = xstrdup(KPROGDIR);
+
+		/*
+		 * Make sure it exists before we try to run it
+		 */
+		if (stat(aklog_path, &st) == 0) {
+			debug("Running %s to get afs token.",aklog_path);
+			system(aklog_path);
+		} else {
+			debug("%s does not exist.",aklog_path);
+		}
+
+		xfree(aklog_path);
+	}
+#endif /* AFS_KRB5 */
+
+#ifdef SESSION_HOOKS
+        if (options.session_hooks_allow &&
+            options.session_hooks_startup_cmd)
+        {
+            execute_session_hook(options.session_hooks_startup_cmd,
+                                 s->authctxt,
+                                 /* startup = */ 1,
+                                 options.session_hooks_shutdown_cmd != NULL);
+        }
+#endif
+
 	/* Change current directory to the user\'s home directory. */
 	if (chdir(pw->pw_dir) < 0) {
 		fprintf(stderr, "Could not chdir to home directory %s: %s\n",
@@ -1593,7 +1816,7 @@
 		/* Execute the shell. */
 		argv[0] = argv0;
 		argv[1] = NULL;
-		execve(shell, argv, env);
+		execve(shell, argv, environ);
 
 		/* Executing the shell failed. */
 		perror(shell);
@@ -1607,7 +1830,7 @@
 	argv[1] = "-c";
 	argv[2] = (char *) command;
 	argv[3] = NULL;
-	execve(shell, argv, env);
+	execve(shell, argv, environ);
 	perror(shell);
 	exit(1);
 }
diff -Naur --exclude=autom4te.cache openssh-4.1p1/ssh-gss.h openssh-4.1p1-gssapi/ssh-gss.h
--- openssh-4.1p1/ssh-gss.h	Mon Jun 21 21:56:02 2004
+++ openssh-4.1p1-gssapi/ssh-gss.h	Thu May 26 14:53:11 2005
@@ -28,6 +28,7 @@
 
 #ifdef GSSAPI
 
+#include "kex.h"
 #include "buffer.h"
 
 #ifdef HAVE_GSSAPI_H
@@ -36,6 +37,7 @@
 #include <gssapi/gssapi.h>
 #endif
 
+#ifndef MECHGLUE
 #ifdef KRB5
 # ifndef HEIMDAL
 #  ifdef HAVE_GSSAPI_GENERIC_H
@@ -51,8 +53,14 @@
 #endif /* GSS_C_NT_... */
 #endif /* !HEIMDAL */
 #endif /* KRB5 */
+#endif /* !MECHGLUE */
 
 /* draft-ietf-secsh-gsskeyex-06 */
+#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
@@ -62,6 +70,8 @@
 
 #define SSH_GSS_OIDTYPE 0x06
 
+#define KEX_GSS_SHA1					"gss-group1-sha1-"
+
 typedef struct {
 	char *filename;
 	char *envvar;
@@ -92,7 +102,7 @@
 	OM_uint32	minor; /* both */
 	gss_ctx_id_t	context; /* both */
 	gss_name_t	name; /* both */
-	gss_OID		oid; /* client */
+	gss_OID		oid; /* both */
 	gss_cred_id_t	creds; /* server */
 	gss_name_t	client; /* server */
 	gss_cred_id_t	client_creds; /* server */
@@ -100,6 +110,9 @@
 
 extern ssh_gssapi_mech *supported_mechs[];
 
+char *ssh_gssapi_client_mechanisms(char *);
+gss_OID ssh_gssapi_client_id_kex(Gssctxt *, char *);
+
 int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
 void ssh_gssapi_set_oid(Gssctxt *, gss_OID);
@@ -121,12 +134,25 @@
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
 
+int ssh_gssapi_check_mechanism(gss_OID oid, const char *host);
+
 /* In the server */
+char *ssh_gssapi_server_mechanisms();
+gss_OID ssh_gssapi_server_id_kex(char *name);
+int ssh_gssapi_localname(char **name);
+
 int ssh_gssapi_userok(char *name);
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_do_child(char ***, u_int *);
 void ssh_gssapi_cleanup_creds(void);
 void ssh_gssapi_storecreds(void);
+
+#ifdef MECHGLUE
+gss_cred_id_t __gss_get_mechanism_cred
+   (gss_cred_id_t,	/* union_cred */
+    gss_OID		/* mech_type */
+   );
+#endif
 
 #endif /* GSSAPI */
 
diff -Naur --exclude=autom4te.cache openssh-4.1p1/ssh.c openssh-4.1p1-gssapi/ssh.c
--- openssh-4.1p1/ssh.c	Wed May  4 00:33:09 2005
+++ openssh-4.1p1-gssapi/ssh.c	Thu May 26 14:53:11 2005
@@ -572,6 +572,29 @@
 			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, 1);
+#ifdef GSI
+		snprintf(buf, sizeof buf, "%.100s/%.100s.gsi", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options, 1);
+#endif
+#if defined(KRB5)
+		snprintf(buf, sizeof buf, "%.100s/%.100s.krb", pw->pw_dir,
+		    _PATH_SSH_USER_CONFFILE);
+		(void)read_config_file(buf, host, &options, 1);
+#endif
+#endif
 		snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir,
 		    _PATH_SSH_USER_CONFFILE);
 		(void)read_config_file(buf, host, &options, 1);
@@ -591,8 +614,11 @@
 
 	seed_rng();
 
-	if (options.user == NULL)
+	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-4.1p1/ssh_config.5 openssh-4.1p1-gssapi/ssh_config.5
--- openssh-4.1p1/ssh_config.5	Thu Mar 31 05:31:10 2005
+++ openssh-4.1p1-gssapi/ssh_config.5	Thu May 26 14:53:11 2005
@@ -57,6 +57,12 @@
 user's configuration file
 .Pq Pa $HOME/.ssh/config
 .It
+GSSAPI configuration file
+.Pq Pa $HOME/.ssh/config.gssapi
+.It
+Kerberos configuration file
+.Pq Pa $HOME/.ssh/config.krb
+.It
 system-wide configuration file
 .Pq Pa /etc/ssh/ssh_config
 .El
@@ -399,13 +405,19 @@
 .Pa /etc/ssh/ssh_known_hosts .
 .It Cm GSSAPIAuthentication
 Specifies whether user authentication based on GSSAPI is allowed.
+The default is 
+.Dq yes .
+Note that this option applies to protocol version 2 only.
+.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 no .
+.Dq yes .
 Note that this option applies to protocol version 2 only.
 .It Cm GSSAPIDelegateCredentials
 Forward (delegate) credentials to the server.
 The default is
-.Dq no .
+.Dq yes .
 Note that this option applies to protocol version 2 only.
 .It Cm HashKnownHosts
 Indicates that
@@ -572,7 +584,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-with-mic,gssapi,publickey,keyboard-interactive,password .
 .It Cm Protocol
 Specifies the protocol versions
 .Nm ssh
diff -Naur --exclude=autom4te.cache openssh-4.1p1/sshconnect2.c openssh-4.1p1-gssapi/sshconnect2.c
--- openssh-4.1p1/sshconnect2.c	Mon Jun 14 19:30:09 2004
+++ openssh-4.1p1-gssapi/sshconnect2.c	Thu May 26 14:53:11 2005
@@ -83,10 +83,28 @@
 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
+	if (options.gss_keyex) {
+	/* Add the GSSAPI mechanisms currently supported on this client to
+	 * the key exchange algorithm proposal */
+	orig = myproposal[PROPOSAL_KEX_ALGS];
+	gss = ssh_gssapi_client_mechanisms((char *)get_canonical_hostname(1));
+	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) {
 		logit("No valid ciphers for protocol version 2 given, using defaults.");
 		options.ciphers = NULL;
@@ -114,6 +132,17 @@
 		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 (options.gss_keyex && 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
+
 	if (options.rekey_limit)
 		packet_set_rekey_limit(options.rekey_limit);
 
@@ -122,9 +151,15 @@
 	kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
+#ifdef GSSAPI
+	kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
+#endif
 	kex->client_version_string=client_version_string;
 	kex->server_version_string=server_version_string;
 	kex->verify_host_key=&verify_host_key_callback;
+#ifdef GSSAPI
+	kex->options.gss_deleg_creds=options.gss_deleg_creds;
+#endif
 
 	xxx_kex = kex;
 
@@ -210,6 +245,18 @@
 void	input_gssapi_errtok(int, u_int32_t, void *);
 #endif
 
+#ifdef GSSAPI
+int	userauth_external(Authctxt *authctxt);
+int	userauth_gssapi(Authctxt *authctxt);
+int	userauth_gssapi_with_mic(Authctxt *authctxt);
+int	userauth_gssapi_without_mic(Authctxt *authctxt);
+void	input_gssapi_response(int type, u_int32_t, void *);
+void	input_gssapi_token(int type, u_int32_t, void *);
+void	input_gssapi_hash(int type, u_int32_t, void *);
+void	input_gssapi_error(int, u_int32_t, void *);
+void	input_gssapi_errtok(int, u_int32_t, void *);
+#endif
+
 void	userauth(Authctxt *, char *);
 
 static int sign_and_send_pubkey(Authctxt *, Identity *);
@@ -223,10 +270,18 @@
 
 Authmethod authmethods[] = {
 #ifdef GSSAPI
+	{"external-keyx",
+		userauth_external,
+		&options.gss_authentication,
+		NULL},
 	{"gssapi-with-mic",
 		userauth_gssapi,
 		&options.gss_authentication,
 		NULL},
+	{"gssapi",
+		userauth_gssapi,
+		&options.gss_authentication,
+		NULL},
 #endif
 	{"hostbased",
 		userauth_hostbased,
@@ -486,6 +541,11 @@
 	OM_uint32 min;
 	int ok = 0;
 
+	if (!options.gss_authentication) {
+		verbose("GSSAPI authentication disabled.");
+		return 0;
+	}
+
 	/* Try one GSSAPI method at a time, rather than sending them all at
 	 * once. */
 
@@ -501,8 +561,10 @@
 
 		/* My DER encoding requires length<128 */
 		if (gss_supported->elements[mech].length < 128 &&
+		    ssh_gssapi_check_mechanism(&gss_supported->elements[mech],
+					       get_canonical_hostname(1)) &&
 		    !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
-		    authctxt->host))) {
+						get_canonical_hostname(1)))) {
 			ok = 1; /* Mechanism works */
 		} else {
 			mech++;
@@ -564,7 +626,8 @@
 
 	if (status == GSS_S_COMPLETE) {
 		/* send either complete or MIC, depending on mechanism */
-		if (!(flags & GSS_C_INTEG_FLAG)) {
+		if (strcmp(authctxt->method->name,"gssapi")==0 ||
+		    (!(flags & GSS_C_INTEG_FLAG))) {
 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
 			packet_send();
 		} else {
@@ -704,6 +767,40 @@
 	xfree(msg);
 	xfree(lang);
 }
+
+int
+userauth_external(Authctxt *authctxt)
+{
+        static int attempt = 0;
+        
+        if (attempt++ >= 1)
+        	return 0;
+                                
+	/* The client MUST NOT try this method if initial key exchange
+	   was not performed using a GSSAPI-based key exchange
+	   method. */
+	if (xxx_kex->kex_type != KEX_GSS_GRP1_SHA1) {
+		debug2("gsskex not performed, skipping external-keyx");
+		return 0;
+	}
+
+        debug2("userauth_external");
+        packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
+        if(options.implicit) {
+	    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
diff -Naur --exclude=autom4te.cache openssh-4.1p1/sshd.c openssh-4.1p1-gssapi/sshd.c
--- openssh-4.1p1/sshd.c	Thu Mar 31 05:39:25 2005
+++ openssh-4.1p1-gssapi/sshd.c	Thu May 26 14:53:11 2005
@@ -86,6 +86,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>
@@ -1110,10 +1119,13 @@
 		logit("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) {
 		logit("Disabling protocol version 2. Could not load host key");
 		options.protocol &= ~SSH_PROTO_2;
 	}
+#endif
 	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {
 		logit("sshd: no hostkeys available -- exiting.");
 		exit(1);
@@ -1666,6 +1678,13 @@
 		alarm(options.login_grace_time);
 
 	sshd_exchange_identification(sock_in, sock_out);
+#if defined(AFS_KRB5)
+	/* If machine has AFS, set process authentication group. */
+	if (k_hasafs()) {
+		k_setpag();
+		k_unlog();
+	}
+#endif /* AFS || AFS_KRB5 */
 
 	packet_set_nonblocking();
 
@@ -1991,11 +2010,53 @@
 	}
 	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_server_mechanisms();
+        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->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
 	kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+#ifdef GSSAPI
+	kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+#endif
 	kex->server = 1;
 	kex->client_version_string=client_version_string;
 	kex->server_version_string=server_version_string;
diff -Naur --exclude=autom4te.cache openssh-4.1p1/sshd_config openssh-4.1p1-gssapi/sshd_config
--- openssh-4.1p1/sshd_config	Wed Jan 19 17:57:56 2005
+++ openssh-4.1p1-gssapi/sshd_config	Thu May 26 14:53:11 2005
@@ -65,8 +65,13 @@
 #KerberosTicketCleanup yes
 #KerberosGetAFSToken no
 
+# Session hooks: if allowed, specify the commands to execute
+#AllowSessionHooks yes
+#SessionHookStartupCmd /bin/true
+#SessionHookShutdownCmd /bin/true
+
 # GSSAPI options
-#GSSAPIAuthentication no
+#GSSAPIAuthentication yes
 #GSSAPICleanupCredentials yes
 
 # Set this to 'yes' to enable PAM authentication, account processing, 
diff -Naur --exclude=autom4te.cache openssh-4.1p1/sshd_config.5 openssh-4.1p1-gssapi/sshd_config.5
--- openssh-4.1p1/sshd_config.5	Thu Mar 31 05:33:51 2005
+++ openssh-4.1p1-gssapi/sshd_config.5	Thu May 26 14:53:12 2005
@@ -270,11 +270,23 @@
 .It Cm GSSAPIAuthentication
 Specifies whether user authentication based on GSSAPI is allowed.
 The default is
-.Dq no .
+.Dq yes .
 Note that this option applies to protocol version 2 only.
 .It Cm GSSAPICleanupCredentials
 Specifies whether to automatically destroy the user's credentials cache
 on logout.
+The default is
+.Dq yes .
+Note that this option applies to protocol version 2 only.
+.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 .
+Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIUseSessionCredCache
+Specifies whether a unique credentials cache name should be generated per
+session for storing delegated credentials.
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
diff -Naur --exclude=autom4te.cache openssh-4.1p1/version.h openssh-4.1p1-gssapi/version.h
--- openssh-4.1p1/version.h	Thu Mar 31 05:31:55 2005
+++ openssh-4.1p1-gssapi/version.h	Thu May 26 14:53:12 2005
@@ -1,6 +1,26 @@
 /* $OpenBSD: version.h,v 1.44 2005/03/16 21:17:39 markus Exp $ */
 
+#ifdef GSI
+#define GSI_VERSION	" GSI"
+#else
+#define GSI_VERSION	""
+#endif
+
+#ifdef KRB5
+#define KRB5_VERSION	" KRB5"
+#else
+#define KRB5_VERSION	""
+#endif
+
+#ifdef MECHGLUE
+#define MGLUE_VERSION	" MECHGLUE"
+#else
+#define MGLUE_VERSION	""
+#endif
+
 #define SSH_VERSION	"OpenSSH_4.1"
 
 #define SSH_PORTABLE	"p1"
-#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE
+#define SSH_RELEASE	SSH_VERSION SSH_PORTABLE \
+			" NCSA_GSSAPI_20050526" \
+			GSI_VERSION KRB5_VERSION MGLUE_VERSION
