Index: auth.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/auth.h,v
retrieving revision 1.47
diff -u -p -r1.47 auth.h
--- auth.h	2 Aug 2003 12:24:49 -0000	1.47
+++ auth.h	22 Aug 2003 13:02:33 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: auth.h,v 1.43 2003/07/22 13:35:22 markus Exp $	*/
+/*	$OpenBSD: auth.h,v 1.44 2003/08/22 10:56:08 markus Exp $	*/
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -67,6 +67,7 @@ struct Authctxt {
 	krb5_principal	 krb5_user;
 	char		*krb5_ticket_file;
 #endif
+	void		*methoddata;
 };
 /*
  * Every authentication method has to handle authentication requests for
Index: auth2-gss.c
===================================================================
RCS file: auth2-gss.c
diff -N auth2-gss.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ auth2-gss.c	22 Aug 2003 12:34:31 -0000
@@ -0,0 +1,243 @@
+/*	$OpenBSD: auth2-gss.c,v 1.1 2003/08/22 10:56:08 markus Exp $	*/
+
+/*
+ * 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 "auth.h"
+#include "ssh2.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "dispatch.h"
+#include "servconf.h"
+#include "compat.h"
+#include "packet.h"
+#include "monitor_wrap.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
+static void input_gssapi_errtok(int, u_int32_t, void *);
+
+/*
+ * We only support those mechanisms that we know about (ie ones that we know
+ * how to check local user kuserok and the like
+ */
+static int
+userauth_gssapi(Authctxt *authctxt)
+{
+	gss_OID_desc oid = {0, NULL};
+	Gssctxt *ctxt = NULL;
+	int mechs;
+	gss_OID_set supported;
+	int present;
+	OM_uint32 ms;
+	u_int len;
+	char *doid = NULL;
+
+	if (!authctxt->valid || authctxt->user == NULL)
+		return (0);
+
+	mechs = packet_get_int();
+	if (mechs == 0) {
+		debug("Mechanism negotiation is not supported");
+		return (0);
+	}
+
+	ssh_gssapi_supported_oids(&supported);
+	do {
+		mechs--;
+
+		if (doid)
+			xfree(doid);
+
+		doid = packet_get_string(&len);
+
+		if (doid[0] != SSH_GSS_OIDTYPE || doid[1] != len-2) {
+			logit("Mechanism OID received using the old encoding form");
+			oid.elements = doid;
+			oid.length = len;
+		} else {
+			oid.elements = doid + 2;
+			oid.length   = len - 2;
+		}
+		gss_test_oid_set_member(&ms, &oid, supported, &present);
+	} while (mechs > 0 && !present);
+
+	gss_release_oid_set(&ms, &supported);
+
+	if (!present) {
+		xfree(doid);
+		return (0);
+	}
+
+	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &oid))))
+		return (0);
+
+	authctxt->methoddata=(void *)ctxt;
+
+	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
+
+	/* Return OID in same format as we received it*/
+	packet_put_string(doid, len);
+
+	packet_send();
+	xfree(doid);
+
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+	authctxt->postponed = 1;
+
+	return (0);
+}
+
+static void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc recv_tok;
+	OM_uint32 maj_status, min_status;
+	u_int len;
+
+	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+		fatal("No authentication or GSSAPI context");
+
+	gssctxt = authctxt->methoddata;
+	recv_tok.value = packet_get_string(&len);
+	recv_tok.length = len; /* u_int vs. size_t */
+
+	packet_check_eom();
+
+	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
+	    &send_tok, NULL));
+
+	xfree(recv_tok.value);
+
+	if (GSS_ERROR(maj_status)) {
+		if (send_tok.length != 0) {
+			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+			packet_put_string(send_tok.value, send_tok.length);
+			packet_send();
+		}
+		authctxt->postponed = 0;
+		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+		userauth_finish(authctxt, 0, "gssapi");
+	} else {
+		if (send_tok.length != 0) {
+			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+			packet_put_string(send_tok.value, send_tok.length);
+			packet_send();
+		}
+		if (maj_status == GSS_S_COMPLETE) {
+			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
+				     &input_gssapi_exchange_complete);
+		}
+	}
+
+	gss_release_buffer(&min_status, &send_tok);
+}
+
+static void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc recv_tok;
+	OM_uint32 maj_status;
+
+	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+		fatal("No authentication or GSSAPI context");
+
+	gssctxt = authctxt->methoddata;
+	recv_tok.value = packet_get_string(&recv_tok.length);
+
+	packet_check_eom();
+
+	/* Push the error token into GSSAPI to see what it says */
+	maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
+	    &send_tok, NULL));
+
+	xfree(recv_tok.value);
+
+	/* We can't return anything to the client, even if we wanted to */
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
+
+	/* The client will have already moved on to the next auth */
+
+	gss_release_buffer(&maj_status, &send_tok);
+}
+
+/*
+ * This is called when the client thinks we've completed authentication.
+ * It should only be enabled in the dispatch handler by the function above,
+ * which only enables it once the GSSAPI exchange is complete.
+ */
+
+static void
+input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	int authenticated;
+
+	if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
+		fatal("No authentication or GSSAPI context");
+
+	gssctxt = authctxt->methoddata;
+
+	/*
+	 * We don't need to check the status, because the stored credentials
+	 * which userok uses are only populated once the context init step
+	 * has returned complete.
+	 */
+
+	packet_check_eom();
+
+	authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+
+	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_EXCHANGE_COMPLETE, NULL);
+	userauth_finish(authctxt, authenticated, "gssapi");
+}
+
+Authmethod method_gssapi = {
+	"gssapi",
+	userauth_gssapi,
+	&options.gss_authentication
+};
+
+#endif /* GSSAPI */
Index: auth2.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/auth2.c,v
retrieving revision 1.120
diff -u -p -r1.120 auth2.c
--- auth2.c	28 Jun 2003 02:38:02 -0000	1.120
+++ auth2.c	22 Aug 2003 13:02:33 -0000
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/24 08:23:46 markus Exp $");
+RCSID("$OpenBSD: auth2.c,v 1.100 2003/08/22 10:56:08 markus Exp $");
 
 #include "ssh2.h"
 #include "xmalloc.h"
@@ -36,6 +36,10 @@ RCSID("$OpenBSD: auth2.c,v 1.99 2003/06/
 #include "pathnames.h"
 #include "monitor_wrap.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import */
 extern ServerOptions options;
 extern u_char *session_id2;
@@ -53,10 +57,16 @@ extern Authmethod method_hostbased;
 #ifdef KRB5
 extern Authmethod method_kerberos;
 #endif
+#ifdef GSSAPI
+extern Authmethod method_gssapi;
+#endif
 
 Authmethod *authmethods[] = {
 	&method_none,
 	&method_pubkey,
+#ifdef GSSAPI
+	&method_gssapi,
+#endif
 	&method_passwd,
 	&method_kbdint,
 	&method_hostbased,
@@ -184,6 +194,12 @@ input_userauth_request(int type, u_int32
 	}
 	/* reset state */
 	auth2_challenge_stop(authctxt);
+
+#ifdef GSSAPI
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
+#endif
+
 	authctxt->postponed = 0;
 
 	/* try to authenticate user */
Index: compat.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/compat.c,v
retrieving revision 1.67
diff -u -p -r1.67 compat.c
--- compat.c	14 May 2003 03:40:07 -0000	1.67
+++ compat.c	22 Aug 2003 13:02:33 -0000
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: compat.c,v 1.67 2003/04/08 20:21:28 itojun Exp $");
+RCSID("$OpenBSD: compat.c,v 1.68 2003/08/22 10:56:09 markus Exp $");
 
 #include "buffer.h"
 #include "packet.h"
@@ -79,7 +79,11 @@ compat_datafellows(const char *version)
 		{ "OpenSSH_2.5.3*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
 		{ "OpenSSH_2.*,"
 		  "OpenSSH_3.0*,"
-		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF},
+		  "OpenSSH_3.1*",	SSH_BUG_EXTEOF|SSH_BUG_GSSAPI_BER},
+		{ "OpenSSH_3.2*,"
+		  "OpenSSH_3.3*,"
+		  "OpenSSH_3.4*,"
+		  "OpenSSH_3.5*",	SSH_BUG_GSSAPI_BER},
 		{ "Sun_SSH_1.0*",	SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
 		{ "OpenSSH*",		0 },
 		{ "*MindTerm*",		0 },
Index: compat.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/compat.h,v
retrieving revision 1.32
diff -u -p -r1.32 compat.h
--- compat.h	1 Apr 2003 11:44:37 -0000	1.32
+++ compat.h	22 Aug 2003 13:02:33 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: compat.h,v 1.34 2003/04/01 10:31:26 markus Exp $	*/
+/*	$OpenBSD: compat.h,v 1.35 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000, 2001 Markus Friedl.  All rights reserved.
@@ -56,6 +56,7 @@
 #define SSH_BUG_K5USER		0x00400000
 #define SSH_BUG_PROBE		0x00800000
 #define SSH_BUG_FIRSTKEX	0x01000000
+#define SSH_BUG_GSSAPI_BER	0x02000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
Index: gss-genr.c
===================================================================
RCS file: gss-genr.c
diff -N gss-genr.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gss-genr.c	22 Aug 2003 12:34:31 -0000
@@ -0,0 +1,256 @@
+/*	$OpenBSD: gss-genr.c,v 1.1 2003/08/22 10:56:09 markus Exp $	*/
+
+/*
+ * 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 "xmalloc.h"
+#include "bufaux.h"
+#include "compat.h"
+#include "log.h"
+#include "monitor_wrap.h"
+
+#include "ssh-gss.h"
+
+
+/* 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)
+{
+	return (ctx != NULL && ctx->oid != GSS_C_NO_OID &&
+	    ctx->oid->length == len &&
+	    memcmp(ctx->oid->elements, data, len) == 0);
+}
+
+/* Set the contexts OID from a data stream */
+void
+ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len)
+{
+	if (ctx->oid != GSS_C_NO_OID) {
+		xfree(ctx->oid->elements);
+		xfree(ctx->oid);
+	}
+	ctx->oid = xmalloc(sizeof(gss_OID_desc));
+	ctx->oid->length = len;
+	ctx->oid->elements = xmalloc(len);
+	memcpy(ctx->oid->elements, data, len);
+}
+
+/* Set the contexts OID */
+void
+ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid)
+{
+	ssh_gssapi_set_oid_data(ctx, oid->elements, oid->length);
+}
+
+/* All this effort to report an error ... */
+void
+ssh_gssapi_error(Gssctxt *ctxt)
+{
+	debug("%s", ssh_gssapi_last_error(ctxt, NULL, NULL));
+}
+
+char *
+ssh_gssapi_last_error(Gssctxt *ctxt,
+		      OM_uint32 *major_status, OM_uint32 *minor_status)
+{
+	OM_uint32 lmin;
+	gss_buffer_desc msg = GSS_C_EMPTY_BUFFER;
+	OM_uint32 ctx;
+	Buffer b;
+	char *ret;
+
+	buffer_init(&b);
+
+	if (major_status != NULL)
+		*major_status = ctxt->major;
+	if (minor_status != NULL)
+		*minor_status = ctxt->minor;
+
+	ctx = 0;
+	/* The GSSAPI error */
+	do {
+		gss_display_status(&lmin, ctxt->major,
+		    GSS_C_GSS_CODE, GSS_C_NULL_OID, &ctx, &msg);
+
+		buffer_append(&b, msg.value, msg.length);
+		buffer_put_char(&b, '\n');
+
+		gss_release_buffer(&lmin, &msg);
+	} while (ctx != 0);
+
+	/* The mechanism specific error */
+	do {
+		gss_display_status(&lmin, ctxt->minor,
+		    GSS_C_MECH_CODE, GSS_C_NULL_OID, &ctx, &msg);
+
+		buffer_append(&b, msg.value, msg.length);
+		buffer_put_char(&b, '\n');
+
+		gss_release_buffer(&lmin, &msg);
+	} while (ctx != 0);
+
+	buffer_put_char(&b, '\0');
+	ret = xmalloc(buffer_len(&b));
+	buffer_get(&b, ret, buffer_len(&b));
+	buffer_free(&b);
+	return (ret);
+}
+
+/*
+ * Initialise our GSSAPI context. We use this opaque structure to contain all
+ * of the data which both the client and server need to persist across
+ * {accept,init}_sec_context calls, so that when we do it from the userauth
+ * stuff life is a little easier
+ */
+void
+ssh_gssapi_build_ctx(Gssctxt **ctx)
+{
+	*ctx = xmalloc(sizeof (Gssctxt));
+	(*ctx)->major = 0;
+	(*ctx)->minor = 0;
+	(*ctx)->context = GSS_C_NO_CONTEXT;
+	(*ctx)->name = GSS_C_NO_NAME;
+	(*ctx)->oid = GSS_C_NO_OID;
+	(*ctx)->creds = GSS_C_NO_CREDENTIAL;
+	(*ctx)->client = GSS_C_NO_NAME;
+	(*ctx)->client_creds = GSS_C_NO_CREDENTIAL;
+}
+
+/* Delete our context, providing it has been built correctly */
+void
+ssh_gssapi_delete_ctx(Gssctxt **ctx)
+{
+	OM_uint32 ms;
+
+	if ((*ctx) == NULL)
+		return;
+	if ((*ctx)->context != GSS_C_NO_CONTEXT)
+		gss_delete_sec_context(&ms, &(*ctx)->context, GSS_C_NO_BUFFER);
+	if ((*ctx)->name != GSS_C_NO_NAME)
+		gss_release_name(&ms, &(*ctx)->name);
+	if ((*ctx)->oid != GSS_C_NO_OID) {
+		xfree((*ctx)->oid->elements);
+		xfree((*ctx)->oid);
+		(*ctx)->oid = GSS_C_NO_OID;
+	}
+	if ((*ctx)->creds != GSS_C_NO_CREDENTIAL)
+		gss_release_cred(&ms, &(*ctx)->creds);
+	if ((*ctx)->client != GSS_C_NO_NAME)
+		gss_release_name(&ms, &(*ctx)->client);
+	if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL)
+		gss_release_cred(&ms, &(*ctx)->client_creds);
+
+	xfree(*ctx);
+	*ctx = NULL;
+}
+
+/*
+ * Wrapper to init_sec_context
+ * Requires that the context contains:
+ *	oid
+ *	server name (from ssh_gssapi_import_name)
+ */
+OM_uint32
+ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
+    gss_buffer_desc* send_tok, OM_uint32 *flags)
+{
+	int deleg_flag = 0;
+
+	if (deleg_creds) {
+		deleg_flag = GSS_C_DELEG_FLAG;
+		debug("Delegating credentials");
+	}
+
+	ctx->major = gss_init_sec_context(&ctx->minor,
+	    GSS_C_NO_CREDENTIAL, &ctx->context, ctx->name, ctx->oid,
+	    GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag,
+	    0, NULL, recv_tok, NULL, send_tok, flags, NULL);
+
+	if (GSS_ERROR(ctx->major))
+		ssh_gssapi_error(ctx);
+
+	return (ctx->major);
+}
+
+/* Create a service name for the given host */
+OM_uint32
+ssh_gssapi_import_name(Gssctxt *ctx, const char *host)
+{
+	gss_buffer_desc gssbuf;
+
+	gssbuf.length = sizeof("host@") + strlen(host);
+	gssbuf.value = xmalloc(gssbuf.length);
+	snprintf(gssbuf.value, gssbuf.length, "host@%s", host);
+
+	if ((ctx->major = gss_import_name(&ctx->minor,
+	    &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name)))
+		ssh_gssapi_error(ctx);
+
+	xfree(gssbuf.value);
+	return (ctx->major);
+}
+
+/* Acquire credentials for a server running on the current host.
+ * Requires that the context structure contains a valid OID
+ */
+
+/* Returns a GSSAPI error code */
+OM_uint32
+ssh_gssapi_acquire_cred(Gssctxt *ctx)
+{
+	OM_uint32 status;
+	char lname[MAXHOSTNAMELEN];
+	gss_OID_set oidset;
+
+	gss_create_empty_oid_set(&status, &oidset);
+	gss_add_oid_set_member(&status, ctx->oid, &oidset);
+
+	if (gethostname(lname, MAXHOSTNAMELEN))
+		return (-1);
+
+	if (GSS_ERROR(ssh_gssapi_import_name(ctx, lname)))
+		return (ctx->major);
+
+	if ((ctx->major = gss_acquire_cred(&ctx->minor,
+	    ctx->name, 0, oidset, GSS_C_ACCEPT, &ctx->creds, NULL, NULL)))
+		ssh_gssapi_error(ctx);
+
+	gss_release_oid_set(&status, &oidset);
+	return (ctx->major);
+}
+
+OM_uint32
+ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
+	if (*ctx)
+		ssh_gssapi_delete_ctx(ctx);
+	ssh_gssapi_build_ctx(ctx);
+	ssh_gssapi_set_oid(*ctx, oid);
+	return (ssh_gssapi_acquire_cred(*ctx));
+}
+
+#endif /* GSSAPI */
Index: gss-serv-krb5.c
===================================================================
RCS file: gss-serv-krb5.c
diff -N gss-serv-krb5.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gss-serv-krb5.c	22 Aug 2003 12:34:31 -0000
@@ -0,0 +1,168 @@
+/*	$OpenBSD: gss-serv-krb5.c,v 1.1 2003/08/22 10:56:09 markus Exp $	*/
+
+/*
+ * 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 KRB5
+
+#include "auth.h"
+#include "xmalloc.h"
+#include "log.h"
+#include "servconf.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+#include <krb5.h>
+
+static krb5_context krb_context = NULL;
+
+/* Initialise the krb5 library, for the stuff that GSSAPI won't do */
+
+static int 
+ssh_gssapi_krb5_init()
+{
+	krb5_error_code problem;
+
+	if (krb_context != NULL)
+		return 1;
+
+	problem = krb5_init_context(&krb_context);
+	if (problem) {
+		logit("Cannot initialize krb5 context");
+		return 0;
+	}
+	krb5_init_ets(krb_context);
+
+	return 1;
+}
+
+/* Check if this user is OK to login. This only works with krb5 - other
+ * GSSAPI mechanisms will need their own.
+ * Returns true if the user is OK to log in, otherwise returns 0
+ */
+
+static int
+ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name)
+{
+	krb5_principal princ;
+	int retval;
+
+	if (ssh_gssapi_krb5_init() == 0)
+		return 0;
+
+	if ((retval = krb5_parse_name(krb_context, client->exportedname.value,
+	    &princ))) {
+		logit("krb5_parse_name(): %.100s",
+		    krb5_get_err_text(krb_context, retval));
+		return 0;
+	}
+	if (krb5_kuserok(krb_context, princ, name)) {
+		retval = 1;
+		logit("Authorized to %s, krb5 principal %s (krb5_kuserok)",
+		    name, (char *)client->displayname.value);
+	} else
+		retval = 0;
+
+	krb5_free_principal(krb_context, princ);
+	return retval;
+}
+
+
+/* This writes out any forwarded credentials from the structure populated
+ * during userauth. Called after we have setuid to the user */
+
+static void
+ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client)
+{
+	krb5_ccache ccache;
+	krb5_error_code problem;
+	krb5_principal princ;
+	OM_uint32 maj_status, min_status;
+
+	if (client->creds == NULL) {
+		debug("No credentials stored");
+		return;
+	}
+
+	if (ssh_gssapi_krb5_init() == 0)
+		return;
+
+	if ((problem = krb5_cc_gen_new(krb_context, &krb5_fcc_ops, &ccache))) {
+		logit("krb5_cc_gen_new(): %.100s",
+		    krb5_get_err_text(krb_context, problem));
+		return;
+	}
+
+	if ((problem = krb5_parse_name(krb_context, 
+	    client->exportedname.value, &princ))) {
+		logit("krb5_parse_name(): %.100s",
+		    krb5_get_err_text(krb_context, problem));
+		krb5_cc_destroy(krb_context, ccache);
+		return;
+	}
+
+	if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
+		logit("krb5_cc_initialize(): %.100s",
+		    krb5_get_err_text(krb_context, problem));
+		krb5_free_principal(krb_context, princ);
+		krb5_cc_destroy(krb_context, ccache);
+		return;
+	}
+
+	krb5_free_principal(krb_context, princ);
+
+	if ((maj_status = gss_krb5_copy_ccache(&min_status, 
+	    client->creds, ccache))) {
+		logit("gss_krb5_copy_ccache() failed");
+		krb5_cc_destroy(krb_context, ccache);
+		return;
+	}
+
+	client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache));
+	client->store.envvar = "KRB5CCNAME";
+	client->store.envval = xstrdup(client->store.filename);
+
+	krb5_cc_close(krb_context, ccache);
+
+	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 */
+
+#endif /* GSSAPI */
Index: gss-serv.c
===================================================================
RCS file: gss-serv.c
diff -N gss-serv.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gss-serv.c	22 Aug 2003 12:34:31 -0000
@@ -0,0 +1,291 @@
+/*	$OpenBSD: gss-serv.c,v 1.1 2003/08/22 10:56:09 markus Exp $	*/
+
+/*
+ * 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 "bufaux.h"
+#include "compat.h"
+#include "auth.h"
+#include "log.h"
+#include "channels.h"
+#include "session.h"
+#include "servconf.h"
+#include "monitor_wrap.h"
+#include "xmalloc.h"
+#include "getput.h"
+
+#include "ssh-gss.h"
+
+extern ServerOptions options;
+
+static ssh_gssapi_client gssapi_client =
+    { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
+    GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
+
+ssh_gssapi_mech gssapi_null_mech =
+    { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
+
+#ifdef KRB5
+extern ssh_gssapi_mech gssapi_kerberos_mech;
+#endif
+
+ssh_gssapi_mech* supported_mechs[]= {
+#ifdef KRB5
+	&gssapi_kerberos_mech,
+#endif
+	&gssapi_null_mech,
+};
+
+/* Unpriviledged */
+void
+ssh_gssapi_supported_oids(gss_OID_set *oidset)
+{
+	int i = 0;
+	OM_uint32 min_status;
+	int present;
+	gss_OID_set supported;
+
+	gss_create_empty_oid_set(&min_status, oidset);
+	gss_indicate_mechs(&min_status, &supported);
+
+	while (supported_mechs[i]->name != NULL) {
+		if (GSS_ERROR(gss_test_oid_set_member(&min_status,
+		    &supported_mechs[i]->oid, supported, &present)))
+			present = 0;
+		if (present)
+			gss_add_oid_set_member(&min_status,
+			    &supported_mechs[i]->oid, oidset);
+		i++;
+	}
+}
+
+
+/* Wrapper around accept_sec_context
+ * Requires that the context contains:
+ *    oid
+ *    credentials	(from ssh_gssapi_acquire_cred)
+ */
+/* Priviledged */
+OM_uint32
+ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
+    gss_buffer_desc *send_tok, OM_uint32 *flags)
+{
+	OM_uint32 status;
+	gss_OID mech;
+
+	ctx->major = gss_accept_sec_context(&ctx->minor,
+	    &ctx->context, ctx->creds, recv_tok,
+	    GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
+	    send_tok, flags, NULL, &ctx->client_creds);
+
+	if (GSS_ERROR(ctx->major))
+		ssh_gssapi_error(ctx);
+
+	if (ctx->client_creds)
+		debug("Received some client credentials");
+	else
+		debug("Got no client credentials");
+
+	status = ctx->major;
+
+	/* Now, if we're complete and we have the right flags, then
+	 * we flag the user as also having been authenticated
+	 */
+
+	if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
+	    (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
+		if (ssh_gssapi_getclient(ctx, &gssapi_client))
+			fatal("Couldn't convert client name");
+	}
+
+	return (status);
+}
+
+/*
+ * This parses an exported name, extracting the mechanism specific portion
+ * to use for ACL checking. It verifies that the name belongs the mechanism
+ * originally selected.
+ */
+static OM_uint32
+ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
+{
+	char *tok;
+	OM_uint32 offset;
+	OM_uint32 oidl;
+	
+	tok=ename->value;
+	
+	/* 
+	 * Check that ename is long enough for all of the fixed length 
+	 * header, and that the initial ID bytes are correct
+	 */
+
+	if (ename->length<6 || memcmp(tok,"\x04\x01", 2)!=0) 
+		return GSS_S_FAILURE;
+
+	/*
+	 * Extract the OID, and check it. Here GSSAPI breaks with tradition
+	 * and does use the OID type and length bytes. To confuse things
+	 * there are two lengths - the first including these, and the
+	 * second without.
+	 */
+
+	oidl = GET_16BIT(tok+2); /* length including next two bytes */
+	oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
+
+	/*
+	 * Check the BER encoding for correct type and length, that the
+	 * string is long enough and that the OID matches that in our context
+	 */
+	if (tok[4] != 0x06 || tok[5] != oidl ||
+	    ename->length < oidl+6 ||        
+	   !ssh_gssapi_check_oid(ctx,tok+6,oidl))
+		return GSS_S_FAILURE;
+
+	offset = oidl+6;
+	
+	if (ename->length < offset+4)
+		return GSS_S_FAILURE;
+		
+	name->length = GET_32BIT(tok+offset);
+	offset += 4;
+	
+	if (ename->length < offset+name->length)
+        	return GSS_S_FAILURE;
+	
+	name->value = xmalloc(name->length);
+	memcpy(name->value,tok+offset,name->length);
+	
+	return GSS_S_COMPLETE;
+} 
+
+/* Extract the client details from a given context. This can only reliably
+ * be called once for a context */
+
+/* Priviledged (called from accept_secure_ctx) */
+OM_uint32
+ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
+{
+	int i = 0;
+
+	gss_buffer_desc ename;
+	
+	client->mech = NULL;
+
+	while (supported_mechs[i]->name != NULL) {
+		if (supported_mechs[i]->oid.length == ctx->oid->length &&
+		    (memcmp(supported_mechs[i]->oid.elements,
+		    ctx->oid->elements, ctx->oid->length) == 0))
+			client->mech = supported_mechs[i];
+		i++;
+	}
+
+	if (client->mech == NULL) 
+		return GSS_S_FAILURE;
+	
+	if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, 
+	    &client->displayname, NULL))) {
+	        ssh_gssapi_error(ctx);
+	        return (ctx->major);
+	}
+	
+	if ((ctx->major = gss_export_name(&ctx->minor, ctx->client, 
+	    &ename))) {
+		ssh_gssapi_error(ctx);
+		return (ctx->major);
+	}
+	
+	if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
+	    &client->exportedname))) {
+		return (ctx->major);
+	}
+
+	/* We can't copy this structure, so we just move the pointer to it */
+	client->creds = ctx->client_creds;
+	ctx->client_creds = GSS_C_NO_CREDENTIAL;
+	return (ctx->major);
+}
+
+/* As user - called through fatal cleanup hook */
+void
+ssh_gssapi_cleanup_creds(void *ignored)
+{
+	if (gssapi_client.store.filename != NULL) {
+		/* Unlink probably isn't sufficient */
+		debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename);
+		unlink(gssapi_client.store.filename);
+	}
+}
+
+/* As user */
+void
+ssh_gssapi_storecreds(void)
+{
+	if (gssapi_client.mech && gssapi_client.mech->storecreds) {
+		(*gssapi_client.mech->storecreds)(&gssapi_client);
+		if (options.gss_cleanup_creds)
+			fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
+	} else
+		debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+}
+
+/* This allows GSSAPI methods to do things to the childs environment based
+ * on the passed authentication process and credentials.
+ */
+/* As user */
+void
+ssh_gssapi_do_child(char ***envp, u_int *envsizep)
+{
+
+	if (gssapi_client.store.envvar != NULL &&
+	    gssapi_client.store.envval != NULL) {
+
+		debug("Setting %s to %s", gssapi_client.store.envvar,
+		gssapi_client.store.envval);
+		child_set_env(envp, envsizep, gssapi_client.store.envvar,
+		     gssapi_client.store.envval);
+	}
+}
+
+/* Priviledged */
+int
+ssh_gssapi_userok(char *user)
+{
+	if (gssapi_client.exportedname.length == 0 ||
+	    gssapi_client.exportedname.value == NULL) {
+		debug("No suitable client data");
+		return 0;
+	}
+	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);
+}
+
+#endif
Index: monitor.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/monitor.c,v
retrieving revision 1.51
diff -u -p -r1.51 monitor.c
--- monitor.c	2 Aug 2003 12:24:49 -0000	1.51
+++ monitor.c	22 Aug 2003 13:02:33 -0000
@@ -25,7 +25,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: monitor.c,v 1.45 2003/07/22 13:35:22 markus Exp $");
+RCSID("$OpenBSD: monitor.c,v 1.46 2003/08/22 10:56:09 markus Exp $");
 
 #include <openssl/dh.h>
 
@@ -59,6 +59,11 @@ RCSID("$OpenBSD: monitor.c,v 1.45 2003/0
 #include "ssh2.h"
 #include "mpaux.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+static Gssctxt *gsscontext = NULL;
+#endif
+
 /* Imports */
 extern ServerOptions options;
 extern u_int utmp_len;
@@ -127,6 +132,11 @@ int mm_answer_pam_free_ctx(int, Buffer *
 #ifdef KRB5
 int mm_answer_krb5(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 *);
+#endif
 
 static Authctxt *authctxt;
 static BIGNUM *ssh1_challenge = NULL;	/* used for ssh1 rsa auth */
@@ -183,6 +193,11 @@ struct mon_table mon_dispatch_proto20[] 
 #ifdef KRB5
     {MONITOR_REQ_KRB5, MON_ONCE|MON_AUTH, mm_answer_krb5},
 #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_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+#endif
     {0, 0, NULL}
 };
 
@@ -342,7 +357,6 @@ monitor_child_postauth(struct monitor *p
 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
-
 	} else {
 		mon_dispatch = mon_dispatch_postauth15;
 		monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
@@ -1735,3 +1749,77 @@ monitor_reinit(struct monitor *mon)
 	mon->m_recvfd = pair[0];
 	mon->m_sendfd = pair[1];
 }
+
+#ifdef GSSAPI
+int
+mm_answer_gss_setup_ctx(int socket, Buffer *m)
+{
+	gss_OID_desc oid;
+	OM_uint32 major;
+	u_int len;
+
+	oid.elements = buffer_get_string(m, &len);
+	oid.length = len;
+
+	major = ssh_gssapi_server_ctx(&gsscontext, &oid);
+
+	xfree(oid.elements);
+
+	buffer_clear(m);
+	buffer_put_int(m, major);
+
+	mm_request_send(socket,MONITOR_ANS_GSSSETUP, m);
+
+	/* Now we have a context, enable the step */
+	monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
+
+	return (0);
+}
+
+int
+mm_answer_gss_accept_ctx(int socket, Buffer *m)
+{
+	gss_buffer_desc in;
+	gss_buffer_desc out = GSS_C_EMPTY_BUFFER;
+	OM_uint32 major,minor;
+	OM_uint32 flags = 0; /* GSI needs this */
+
+	in.value = buffer_get_string(m, &in.length);
+	major = ssh_gssapi_accept_ctx(gsscontext, &in, &out, &flags);
+	xfree(in.value);
+
+	buffer_clear(m);
+	buffer_put_int(m, major);
+	buffer_put_string(m, out.value, out.length);
+	buffer_put_int(m, flags);
+	mm_request_send(socket, MONITOR_ANS_GSSSTEP, m);
+
+	gss_release_buffer(&minor, &out);
+
+	/* Complete - now we can do signing */
+	if (major==GSS_S_COMPLETE) {
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0);
+		monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
+	}
+	return (0);
+}
+
+int
+mm_answer_gss_userok(int socket, Buffer *m)
+{
+	int authenticated;
+
+	authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user);
+
+	buffer_clear(m);
+	buffer_put_int(m, authenticated);
+
+	debug3("%s: sending result %d", __func__, authenticated);
+	mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m);
+
+	auth_method="gssapi";
+
+	/* Monitor loop will terminate if authenticated */
+	return (authenticated);
+}
+#endif /* GSSAPI */
Index: monitor.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/monitor.h,v
retrieving revision 1.14
diff -u -p -r1.14 monitor.h
--- monitor.h	2 Aug 2003 14:17:30 -0000	1.14
+++ monitor.h	22 Aug 2003 13:03:13 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: monitor.h,v 1.9 2003/07/22 13:35:22 markus Exp $	*/
+/*	$OpenBSD: monitor.h,v 1.10 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -50,6 +50,9 @@ enum monitor_reqtype {
 	MONITOR_REQ_RSACHALLENGE, MONITOR_ANS_RSACHALLENGE,
 	MONITOR_REQ_RSARESPONSE, MONITOR_ANS_RSARESPONSE,
  	MONITOR_REQ_KRB5, MONITOR_ANS_KRB5,
+	MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
+	MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
+	MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
 	MONITOR_REQ_PAM_START,
 	MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
 	MONITOR_REQ_PAM_QUERY, MONITOR_ANS_PAM_QUERY,
Index: monitor_wrap.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/monitor_wrap.c,v
retrieving revision 1.30
diff -u -p -r1.30 monitor_wrap.c
--- monitor_wrap.c	2 Aug 2003 12:24:49 -0000	1.30
+++ monitor_wrap.c	22 Aug 2003 13:02:34 -0000
@@ -25,7 +25,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2003/07/22 13:35:22 markus Exp $");
+RCSID("$OpenBSD: monitor_wrap.c,v 1.29 2003/08/22 10:56:09 markus Exp $");
 
 #include <openssl/bn.h>
 #include <openssl/dh.h>
@@ -53,6 +53,10 @@ RCSID("$OpenBSD: monitor_wrap.c,v 1.28 2
 #include "channels.h"
 #include "session.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* Imports */
 extern int compat20;
 extern Newkeys *newkeys[];
@@ -1076,4 +1080,69 @@ mm_auth_krb5(void *ctx, void *argp, char
 	buffer_free(&m);
 	return (success);
 }
-#endif
+#endif /* KRB5 */
+
+#ifdef GSSAPI
+OM_uint32
+mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid)
+{
+	Buffer m;
+	OM_uint32 major;
+
+	/* Client doesn't get to see the context */
+	*ctx = NULL;
+
+	buffer_init(&m);
+	buffer_put_string(&m, oid->elements, oid->length);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
+
+	major = buffer_get_int(&m);
+
+	buffer_free(&m);
+	return (major);
+}
+
+OM_uint32
+mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
+    gss_buffer_desc *out, OM_uint32 *flags)
+{
+	Buffer m;
+	OM_uint32 major;
+
+	buffer_init(&m);
+	buffer_put_string(&m, in->value, in->length);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
+
+	major = buffer_get_int(&m);
+	out->value = buffer_get_string(&m, &out->length);
+	if (flags)
+		*flags = buffer_get_int(&m);
+
+	buffer_free(&m);
+
+	return (major);
+}
+
+int
+mm_ssh_gssapi_userok(char *user)
+{
+	Buffer m;
+	int authenticated = 0;
+
+	buffer_init(&m);
+
+	mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
+	mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
+				  &m);
+
+	authenticated = buffer_get_int(&m);
+
+	buffer_free(&m);
+	debug3("%s: user %sauthenticated",__func__, authenticated ? "" : "not ");
+	return (authenticated);
+}
+#endif /* GSSAPI */
Index: monitor_wrap.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/monitor_wrap.h,v
retrieving revision 1.12
diff -u -p -r1.12 monitor_wrap.h
--- monitor_wrap.h	2 Aug 2003 12:24:49 -0000	1.12
+++ monitor_wrap.h	22 Aug 2003 13:02:34 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: monitor_wrap.h,v 1.9 2003/07/22 13:35:22 markus Exp $	*/
+/*	$OpenBSD: monitor_wrap.h,v 1.10 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -54,6 +54,14 @@ int mm_key_verify(Key *, u_char *, u_int
 int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **);
 int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *);
 BIGNUM *mm_auth_rsa_generate_challenge(Key *);
+
+#ifdef GSSAPI
+#include "ssh-gss.h"
+OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **ctxt, gss_OID oid);
+OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *ctxt,
+   gss_buffer_desc *recv, gss_buffer_desc *send, OM_uint32 *flags);
+int mm_ssh_gssapi_userok(char *user);
+#endif
 
 #ifdef USE_PAM
 void mm_start_pam(char *);
Index: readconf.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/readconf.c,v
retrieving revision 1.92
diff -u -p -r1.92 readconf.c
--- readconf.c	13 Aug 2003 10:38:36 -0000	1.92
+++ readconf.c	22 Aug 2003 13:02:34 -0000
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.117 2003/08/13 09:07:09 markus Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.118 2003/08/22 10:56:09 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -105,7 +105,7 @@ typedef enum {
 	oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
 	oClearAllForwardings, oNoHostAuthenticationForLocalhost,
 	oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
-	oAddressFamily,
+	oAddressFamily, oGssAuthentication, oGssDelegateCreds,
 	oDeprecated, oUnsupported
 } OpCodes;
 
@@ -140,6 +140,14 @@ static struct {
 	{ "kerberostgtpassing", oUnsupported },
 #endif
 	{ "afstokenpassing", oUnsupported },
+#if defined(GSSAPI)
+	{ "gssapiauthentication", oGssAuthentication },
+	{ "gssapidelegatecreds", oGssDelegateCreds },
+	{ "gssapidelegatecredentials", oGssDelegateCreds },
+#else
+	{ "gssapiauthentication", oUnsupported },
+	{ "gssapidelegatecredentials", oUnsupported },
+#endif
 	{ "fallbacktorsh", oDeprecated },
 	{ "usersh", oDeprecated },
 	{ "identityfile", oIdentityFile },
@@ -389,6 +397,14 @@ parse_flag:
 		intptr = &options->kerberos_tgt_passing;
 		goto parse_flag;
 
+	case oGssAuthentication:
+		intptr = &options->gss_authentication;
+		goto parse_flag;
+
+	case oGssDelegateCreds:
+		intptr = &options->gss_deleg_creds;
+		goto parse_flag;
+
 	case oBatchMode:
 		intptr = &options->batch_mode;
 		goto parse_flag;
@@ -813,6 +829,8 @@ initialize_options(Options * options)
 	options->challenge_response_authentication = -1;
 	options->kerberos_authentication = -1;
 	options->kerberos_tgt_passing = -1;
+	options->gss_authentication = -1;
+	options->gss_deleg_creds = -1;
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
 	options->kbd_interactive_devices = NULL;
@@ -887,6 +905,10 @@ fill_default_options(Options * options)
 		options->kerberos_authentication = 1;
 	if (options->kerberos_tgt_passing == -1)
 		options->kerberos_tgt_passing = 1;
+	if (options->gss_authentication == -1)
+		options->gss_authentication = 1;
+	if (options->gss_deleg_creds == -1)
+		options->gss_deleg_creds = 0;
 	if (options->password_authentication == -1)
 		options->password_authentication = 1;
 	if (options->kbd_interactive_authentication == -1)
Index: readconf.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/readconf.h,v
retrieving revision 1.45
diff -u -p -r1.45 readconf.h
--- readconf.h	13 Aug 2003 10:37:05 -0000	1.45
+++ readconf.h	22 Aug 2003 13:02:34 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: readconf.h,v 1.53 2003/08/13 08:46:30 markus Exp $	*/
+/*	$OpenBSD: readconf.h,v 1.54 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -42,6 +42,8 @@ typedef struct {
 					/* Try S/Key or TIS, authentication. */
 	int     kerberos_authentication;	/* Try Kerberos authentication. */
 	int     kerberos_tgt_passing;	/* Try Kerberos TGT passing. */
+	int     gss_authentication;	/* Try GSS authentication */
+	int     gss_deleg_creds;	/* Delegate GSS credentials */
 	int     password_authentication;	/* Try password
 						 * authentication. */
 	int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
Index: servconf.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/servconf.c,v
retrieving revision 1.110
diff -u -p -r1.110 servconf.c
--- servconf.c	13 Aug 2003 10:37:05 -0000	1.110
+++ servconf.c	22 Aug 2003 13:02:34 -0000
@@ -10,7 +10,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: servconf.c,v 1.124 2003/08/13 08:46:30 markus Exp $");
+RCSID("$OpenBSD: servconf.c,v 1.125 2003/08/22 10:56:09 markus Exp $");
 
 #include "ssh.h"
 #include "log.h"
@@ -73,6 +73,8 @@ initialize_server_options(ServerOptions 
 	options->kerberos_or_local_passwd = -1;
 	options->kerberos_ticket_cleanup = -1;
 	options->kerberos_tgt_passing = -1;
+	options->gss_authentication=-1;
+	options->gss_cleanup_creds = -1;
 	options->password_authentication = -1;
 	options->kbd_interactive_authentication = -1;
 	options->challenge_response_authentication = -1;
@@ -182,6 +184,10 @@ fill_default_server_options(ServerOption
 		options->kerberos_ticket_cleanup = 1;
 	if (options->kerberos_tgt_passing == -1)
 		options->kerberos_tgt_passing = 0;
+	if (options->gss_authentication == -1)
+		options->gss_authentication = 0;
+	if (options->gss_cleanup_creds == -1)
+		options->gss_cleanup_creds = 1;
 	if (options->password_authentication == -1)
 		options->password_authentication = 1;
 	if (options->kbd_interactive_authentication == -1)
@@ -259,6 +265,7 @@ typedef enum {
 	sBanner, sUseDNS, sHostbasedAuthentication,
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
 	sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+	sGssAuthentication, sGssCleanupCreds,
 	sUsePrivilegeSeparation,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
@@ -304,6 +311,13 @@ static struct {
 	{ "kerberostgtpassing", sUnsupported },
 #endif
 	{ "afstokenpassing", sUnsupported },
+#ifdef GSSAPI
+	{ "gssapiauthentication", sGssAuthentication },
+	{ "gssapicleanupcreds", sGssCleanupCreds },
+#else
+	{ "gssapiauthentication", sUnsupported },
+	{ "gssapicleanupcreds", sUnsupported },
+#endif
 	{ "passwordauthentication", sPasswordAuthentication },
 	{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
 	{ "challengeresponseauthentication", sChallengeResponseAuthentication },
@@ -620,6 +634,14 @@ parse_flag:
 
 	case sKerberosTgtPassing:
 		intptr = &options->kerberos_tgt_passing;
+		goto parse_flag;
+
+	case sGssAuthentication:
+		intptr = &options->gss_authentication;
+		goto parse_flag;
+
+	case sGssCleanupCreds:
+		intptr = &options->gss_cleanup_creds;
 		goto parse_flag;
 
 	case sPasswordAuthentication:
Index: servconf.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/servconf.h,v
retrieving revision 1.55
diff -u -p -r1.55 servconf.h
--- servconf.h	13 Aug 2003 10:37:05 -0000	1.55
+++ servconf.h	22 Aug 2003 13:02:34 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: servconf.h,v 1.63 2003/08/13 08:46:30 markus Exp $	*/
+/*	$OpenBSD: servconf.h,v 1.64 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -82,6 +82,8 @@ typedef struct {
 						 * file on logout. */
 	int     kerberos_tgt_passing;	/* If true, permit Kerberos TGT
 					 * passing. */
+	int     gss_authentication;	/* If true, permit GSSAPI authentication */
+	int     gss_cleanup_creds;	/* If true, destroy cred cache on logout */
 	int     password_authentication;	/* If true, permit password
 						 * authentication. */
 	int     kbd_interactive_authentication;	/* If true, permit */
Index: session.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/session.c,v
retrieving revision 1.246
diff -u -p -r1.246 session.c
--- session.c	13 Aug 2003 10:31:05 -0000	1.246
+++ session.c	22 Aug 2003 13:02:34 -0000
@@ -33,7 +33,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.160 2003/08/13 08:33:02 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.161 2003/08/22 10:56:09 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -58,6 +58,10 @@ RCSID("$OpenBSD: session.c,v 1.160 2003/
 #include "session.h"
 #include "monitor_wrap.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* func */
 
 Session *session_new(void);
@@ -424,6 +428,12 @@ do_exec_no_pty(Session *s, const char *c
 	}
 #endif /* USE_PAM */
 
+#ifdef GSSAPI
+	temporarily_use_uid(s->pw);
+	ssh_gssapi_storecreds();
+	restore_uid();
+#endif
+
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
 		fatal_remove_all_cleanups();
@@ -550,6 +560,12 @@ do_exec_pty(Session *s, const char *comm
 	}
 #endif
 
+#ifdef GSSAPI
+	temporarily_use_uid(s->pw);
+	ssh_gssapi_storecreds();
+	restore_uid();
+#endif
+
 	/* Fork the child. */
 	if ((pid = fork()) == 0) {
 		fatal_remove_all_cleanups();
@@ -806,7 +822,7 @@ check_quietlogin(Session *s, const char 
  * Sets the value of the given variable in the environment.  If the variable
  * already exists, its value is overriden.
  */
-static void
+void
 child_set_env(char ***envp, u_int *envsizep, const char *name,
 	const char *value)
 {
@@ -933,6 +949,13 @@ do_setup_env(Session *s, const char *she
 	copy_environment(environ, &env, &envsize);
 #endif
 
+#ifdef GSSAPI
+	/* Allow any GSSAPI methods that we've used to alter 
+	 * the childs environment as they see fit
+	 */
+	ssh_gssapi_do_child(&env, &envsize);
+#endif
+
 	if (!options.use_login) {
 		/* Set basic environment. */
 		child_set_env(&env, &envsize, "USER", pw->pw_name);
@@ -2087,4 +2110,8 @@ static void
 do_authenticated2(Authctxt *authctxt)
 {
 	server_loop2(authctxt);
+#if defined(GSSAPI)
+	if (options.gss_cleanup_creds)
+		ssh_gssapi_cleanup_creds(NULL);
+#endif
 }
Index: session.h
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/session.h,v
retrieving revision 1.23
diff -u -p -r1.23 session.h
--- session.h	4 Jul 2002 00:14:18 -0000	1.23
+++ session.h	22 Aug 2003 13:02:34 -0000
@@ -1,4 +1,4 @@
-/*	$OpenBSD: session.h,v 1.19 2002/06/30 21:59:45 deraadt Exp $	*/
+/*	$OpenBSD: session.h,v 1.20 2003/08/22 10:56:09 markus Exp $	*/
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -68,4 +68,7 @@ Session	*session_new(void);
 Session	*session_by_tty(char *);
 void	 session_close(Session *);
 void	 do_setusercontext(struct passwd *);
+void	 child_set_env(char ***envp, u_int *envsizep, const char *name,
+		       const char *value);
+
 #endif
Index: ssh-gss.h
===================================================================
RCS file: ssh-gss.h
diff -N ssh-gss.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ssh-gss.h	22 Aug 2003 12:34:31 -0000
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+#ifndef _SSH_GSS_H
+#define _SSH_GSS_H
+
+#ifdef GSSAPI
+
+#include "buffer.h"
+
+#include <gssapi.h>
+
+/* draft-ietf-secsh-gsskeyex-06 */
+#define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE		60
+#define SSH2_MSG_USERAUTH_GSSAPI_TOKEN			61
+#define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE	63
+#define SSH2_MSG_USERAUTH_GSSAPI_ERROR			64
+#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK			65
+
+#define SSH_GSS_OIDTYPE 0x06
+
+typedef struct {
+	char *filename;
+	char *envvar;
+	char *envval;
+	void *data;
+} ssh_gssapi_ccache;
+
+typedef struct {
+	gss_buffer_desc displayname;
+	gss_buffer_desc exportedname;
+	gss_cred_id_t creds;
+	struct ssh_gssapi_mech_struct *mech;
+	ssh_gssapi_ccache store;
+} ssh_gssapi_client;
+
+typedef struct ssh_gssapi_mech_struct {
+	char *enc_name;
+	char *name;
+	gss_OID_desc oid;
+	int (*dochild) (ssh_gssapi_client *);
+	int (*userok) (ssh_gssapi_client *, char *);
+	int (*localname) (ssh_gssapi_client *, char **);
+	void (*storecreds) (ssh_gssapi_client *);
+} ssh_gssapi_mech;
+
+typedef struct {
+	OM_uint32	major; /* both */
+	OM_uint32	minor; /* both */
+	gss_ctx_id_t	context; /* both */
+	gss_name_t	name; /* both */
+	gss_OID		oid; /* client */
+	gss_cred_id_t	creds; /* server */
+	gss_name_t	client; /* server */
+	gss_cred_id_t	client_creds; /* server */
+} Gssctxt;
+
+extern ssh_gssapi_mech *supported_mechs[];
+
+int  ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len);
+void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
+void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
+void ssh_gssapi_supported_oids(gss_OID_set *oidset);
+ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *ctxt);
+
+OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host);
+OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx);
+OM_uint32 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds,
+    gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags);
+OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,
+    gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags);
+OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *);
+void ssh_gssapi_error(Gssctxt *ctx);
+char *ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
+void ssh_gssapi_build_ctx(Gssctxt **ctx);
+void ssh_gssapi_delete_ctx(Gssctxt **ctx);
+OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid);
+
+/* In the server */
+int ssh_gssapi_userok(char *name);
+
+void ssh_gssapi_do_child(char ***envp, u_int *envsizep);
+void ssh_gssapi_cleanup_creds(void *ignored);
+void ssh_gssapi_storecreds(void);
+
+#endif /* GSSAPI */
+
+#endif /* _SSH_GSS_H */
Index: ssh_config.5
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/ssh_config.5,v
retrieving revision 1.17
diff -u -p -r1.17 ssh_config.5
--- ssh_config.5	13 Aug 2003 10:37:05 -0000	1.17
+++ ssh_config.5	22 Aug 2003 13:02:34 -0000
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh_config.5,v 1.17 2003/08/13 08:46:31 markus Exp $
+.\" $OpenBSD: ssh_config.5,v 1.18 2003/08/22 10:56:09 markus Exp $
 .Dd September 25, 1999
 .Dt SSH_CONFIG 5
 .Os
@@ -331,6 +331,18 @@ The default is
 Specifies a file to use for the global
 host key database instead of
 .Pa /etc/ssh/ssh_known_hosts .
+.It Cm GSSAPIAuthentication
+Specifies whether authentication based on GSSAPI may be used, either using
+the result of a successful key exchange, or using GSSAPI user
+authentication.
+The default is 
+.Dq yes .
+Note that this option applies to protocol version 2 only.
+.It Cm GSSAPIDelegateCredentials
+Forward (delegate) credentials to the server.
+The default is
+.Dq no .
+Note that this option applies to protocol version 2 only.
 .It Cm HostbasedAuthentication
 Specifies whether to try rhosts based authentication with public key
 authentication.
Index: sshconnect2.c
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/sshconnect2.c,v
retrieving revision 1.107
diff -u -p -r1.107 sshconnect2.c
--- sshconnect2.c	28 Jun 2003 02:38:02 -0000	1.107
+++ sshconnect2.c	22 Aug 2003 13:02:34 -0000
@@ -23,7 +23,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.121 2003/08/22 10:56:09 markus Exp $");
 
 #ifdef KRB5
 #include <krb5.h>
@@ -57,6 +57,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.120 2
 #include "msg.h"
 #include "pathnames.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import */
 extern char *client_version_string;
 extern char *server_version_string;
@@ -178,6 +182,8 @@ struct Authctxt {
 	Sensitive *sensitive;
 	/* kbd-interactive */
 	int info_req_seen;
+	/* generic */
+	void *methoddata;
 };
 struct Authmethod {
 	char	*name;		/* string to compare against server's list */
@@ -201,6 +207,15 @@ int	userauth_kbdint(Authctxt *);
 int	userauth_hostbased(Authctxt *);
 int	userauth_kerberos(Authctxt *);
 
+#ifdef GSSAPI
+int	userauth_gssapi(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 *);
@@ -213,6 +228,12 @@ static Authmethod *authmethod_lookup(con
 static char *authmethods_get(void);
 
 Authmethod authmethods[] = {
+#ifdef GSSAPI
+	{"gssapi",
+		userauth_gssapi,
+		&options.gss_authentication,
+		NULL},
+#endif
 	{"hostbased",
 		userauth_hostbased,
 		&options.hostbased_authentication,
@@ -283,6 +304,7 @@ ssh_userauth2(const char *local_user, co
 	authctxt.success = 0;
 	authctxt.method = authmethod_lookup("none");
 	authctxt.authlist = NULL;
+	authctxt.methoddata = NULL;
 	authctxt.sensitive = sensitive;
 	authctxt.info_req_seen = 0;
 	if (authctxt.method == NULL)
@@ -306,6 +328,10 @@ ssh_userauth2(const char *local_user, co
 void
 userauth(Authctxt *authctxt, char *authlist)
 {
+	if (authctxt->methoddata) {
+		xfree(authctxt->methoddata);
+		authctxt->methoddata = NULL;
+	}
 	if (authlist == NULL) {
 		authlist = authctxt->authlist;
 	} else {
@@ -361,6 +387,8 @@ input_userauth_success(int type, u_int32
 		fatal("input_userauth_success: no authentication context");
 	if (authctxt->authlist)
 		xfree(authctxt->authlist);
+	if (authctxt->methoddata)
+		xfree(authctxt->methoddata);
 	authctxt->success = 1;			/* break out */
 }
 
@@ -448,6 +476,228 @@ done:
 	if (sent == 0)
 		userauth(authctxt, NULL);
 }
+
+#ifdef GSSAPI
+int 
+userauth_gssapi(Authctxt *authctxt)
+{
+	Gssctxt *gssctxt = NULL;
+	static gss_OID_set supported = NULL;
+	static int mech = 0;
+	OM_uint32 min;
+	int ok = 0;
+
+	/* Try one GSSAPI method at a time, rather than sending them all at
+	 * once. */
+
+	if (supported == NULL)
+		gss_indicate_mechs(&min, &supported);
+
+	/* Check to see if the mechanism is usable before we offer it */
+	while (mech<supported->count && !ok) {
+		if (gssctxt)
+			ssh_gssapi_delete_ctx(&gssctxt);
+		ssh_gssapi_build_ctx(&gssctxt);
+		ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]);
+
+		/* My DER encoding requires length<128 */
+		if (supported->elements[mech].length < 128 &&
+		    !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
+		    authctxt->host))) {
+			ok = 1; /* Mechanism works */
+		} else {
+			mech++;
+		}
+	}
+
+	if (!ok) return 0;
+
+	authctxt->methoddata=(void *)gssctxt;
+
+	packet_start(SSH2_MSG_USERAUTH_REQUEST);
+	packet_put_cstring(authctxt->server_user);
+	packet_put_cstring(authctxt->service);
+	packet_put_cstring(authctxt->method->name);
+
+	packet_put_int(1);
+
+	/* Some servers encode the OID incorrectly (as we used to) */
+	if (datafellows & SSH_BUG_GSSAPI_BER) {
+		packet_put_string(supported->elements[mech].elements,
+		    supported->elements[mech].length);
+	} else {
+		packet_put_int((supported->elements[mech].length)+2);
+		packet_put_char(SSH_GSS_OIDTYPE);
+		packet_put_char(supported->elements[mech].length);
+		packet_put_raw(supported->elements[mech].elements,
+		    supported->elements[mech].length);
+	}
+
+	packet_send();
+
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
+	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+
+	mech++; /* Move along to next candidate */
+
+	return 1;
+}
+
+void
+input_gssapi_response(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	OM_uint32 status, ms;
+	int oidlen;
+	char *oidv;
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+
+	if (authctxt == NULL)
+		fatal("input_gssapi_response: no authentication context");
+	gssctxt = authctxt->methoddata;
+
+	/* Setup our OID */
+	oidv = packet_get_string(&oidlen);
+
+	if (datafellows & SSH_BUG_GSSAPI_BER) {
+		if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen))
+			fatal("Server returned different OID than expected");
+	} else {
+		if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) {
+			debug("Badly encoded mechanism OID received");
+			userauth(authctxt, NULL);
+			xfree(oidv);
+			return;
+		}
+		if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2))
+			fatal("Server returned different OID than expected");
+	}
+
+	packet_check_eom();
+
+	xfree(oidv);
+
+	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+	    GSS_C_NO_BUFFER, &send_tok, NULL);
+	if (GSS_ERROR(status)) {
+		if (send_tok.length > 0) {
+			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+			packet_put_string(send_tok.value, send_tok.length);
+			packet_send();
+			gss_release_buffer(&ms, &send_tok);
+		}
+		/* Start again with next method on list */
+		debug("Trying to start again");
+		userauth(authctxt, NULL);
+		return;
+	}
+
+	/* We must have data to send */
+	packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+	packet_put_string(send_tok.value, send_tok.length);
+	packet_send();
+	gss_release_buffer(&ms, &send_tok);
+}
+
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc recv_tok;
+	OM_uint32 status, ms;
+	u_int slen;
+
+	if (authctxt == NULL)
+		fatal("input_gssapi_response: no authentication context");
+	gssctxt = authctxt->methoddata;
+
+	recv_tok.value = packet_get_string(&slen);
+	recv_tok.length = slen;	/* safe typecast */
+
+	packet_check_eom();
+
+	status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+	    &recv_tok, &send_tok, NULL);
+
+	xfree(recv_tok.value);
+
+	if (GSS_ERROR(status)) {
+		if (send_tok.length > 0) {
+			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+			packet_put_string(send_tok.value, send_tok.length);
+			packet_send();
+			gss_release_buffer(&ms, &send_tok);
+		}
+		/* Start again with the next method in the list */
+		userauth(authctxt, NULL);
+		return;
+	}
+
+	if (send_tok.length > 0) {
+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+		packet_put_string(send_tok.value, send_tok.length);
+		packet_send();
+		gss_release_buffer(&ms, &send_tok);
+	}
+
+	if (status == GSS_S_COMPLETE) {
+		/* If that succeeded, send a exchange complete message */
+		packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+		packet_send();
+	}
+}
+
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+	Authctxt *authctxt = ctxt;
+	Gssctxt *gssctxt;
+	gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+	gss_buffer_desc recv_tok;
+	OM_uint32 status, ms;
+
+	if (authctxt == NULL)
+		fatal("input_gssapi_response: no authentication context");
+	gssctxt = authctxt->methoddata;
+
+	recv_tok.value = packet_get_string(&recv_tok.length);
+
+	packet_check_eom();
+
+	/* Stick it into GSSAPI and see what it says */
+	status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+				     &recv_tok, &send_tok, NULL);
+
+	xfree(recv_tok.value);
+	gss_release_buffer(&ms, &send_tok);
+
+	/* Server will be returning a failed packet after this one */
+}
+
+void
+input_gssapi_error(int type, u_int32_t plen, void *ctxt)
+{
+	OM_uint32 maj, min;
+	char *msg;
+	char *lang;
+
+	maj=packet_get_int();
+	min=packet_get_int();
+	msg=packet_get_string(NULL);
+	lang=packet_get_string(NULL);
+
+	packet_check_eom();
+
+	debug("Server GSSAPI Error:\n%s\n", msg);
+	xfree(msg);
+	xfree(lang);
+}
+#endif /* GSSAPI */
 
 int
 userauth_none(Authctxt *authctxt)
Index: sshd_config
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/sshd_config,v
retrieving revision 1.61
diff -u -p -r1.61 sshd_config
--- sshd_config	13 Aug 2003 10:37:05 -0000	1.61
+++ sshd_config	22 Aug 2003 13:02:34 -0000
@@ -1,4 +1,4 @@
-#	$OpenBSD: sshd_config,v 1.63 2003/08/13 08:46:31 markus Exp $
+#	$OpenBSD: sshd_config,v 1.64 2003/08/22 10:56:09 markus Exp $
 
 # This is the sshd server system-wide configuration file.  See
 # sshd_config(5) for more information.
@@ -62,6 +62,10 @@
 #KerberosOrLocalPasswd yes
 #KerberosTicketCleanup yes
 #KerberosTgtPassing no
+
+# GSSAPI options
+#GSSAPIAuthentication no
+#GSSAPICleanupCreds yes
 
 # Set this to 'yes' to enable PAM authentication (via challenge-response)
 # and session processing. Depending on your PAM configuration, this may
Index: sshd_config.5
===================================================================
RCS file: /usr/local/src/security/openssh/cvs/openssh_cvs/sshd_config.5,v
retrieving revision 1.23
diff -u -p -r1.23 sshd_config.5
--- sshd_config.5	13 Aug 2003 10:37:05 -0000	1.23
+++ sshd_config.5	22 Aug 2003 13:02:34 -0000
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.22 2003/08/13 08:46:31 markus Exp $
+.\" $OpenBSD: sshd_config.5,v 1.23 2003/08/22 10:56:09 markus Exp $
 .Dd September 25, 1999
 .Dt SSHD_CONFIG 5
 .Os
@@ -225,6 +225,19 @@ or
 .Dq no .
 The default is
 .Dq no .
+.It Cm GSSAPIAuthentication
+Specifies whether authentication based on GSSAPI may be used, either using
+the result of a successful key exchange, or using GSSAPI user
+authentication.
+The default is 
+.Dq no .
+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 HostbasedAuthentication
 Specifies whether rhosts or /etc/hosts.equiv authentication together
 with successful public key client host authentication is allowed
