summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog10
-rw-r--r--auth.h3
-rw-r--r--auth2-gss.c243
-rw-r--r--auth2.c18
-rw-r--r--compat.c8
-rw-r--r--compat.h3
-rw-r--r--gss-genr.c256
-rw-r--r--gss-serv-krb5.c168
-rw-r--r--gss-serv.c291
-rw-r--r--monitor.c92
-rw-r--r--monitor.h5
-rw-r--r--monitor_wrap.c73
-rw-r--r--monitor_wrap.h10
-rw-r--r--readconf.c26
-rw-r--r--readconf.h4
-rw-r--r--servconf.c24
-rw-r--r--servconf.h4
-rw-r--r--session.c31
-rw-r--r--session.h5
-rw-r--r--ssh-gss.h109
-rw-r--r--ssh_config.514
-rw-r--r--sshconnect2.c252
-rw-r--r--sshd_config6
-rw-r--r--sshd_config.515
24 files changed, 1646 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index e8727e2f..142af1b0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,14 @@
- (djm) Bug #629: Mark ssh_config option "pamauthenticationviakbdint"
as deprecated. Remove mention from README.privsep. Patch from
aet AT cc.hut.fi
+ - (dtucker) OpenBSD CVS Sync
+ - markus@cvs.openbsd.org 2003/08/22 10:56:09
+ [auth2.c auth2-gss.c auth.h compat.c compat.h gss-genr.c gss-serv-krb5.c
+ gss-serv.c monitor.c monitor.h monitor_wrap.c monitor_wrap.h readconf.c
+ readconf.h servconf.c servconf.h session.c session.h ssh-gss.h
+ ssh_config.5 sshconnect2.c sshd_config sshd_config.5]
+ support GSS API user authentication; patches from Simon Wilkinson,
+ stripped down and tested by Jakob and myself.
20030825
- (djm) Bug #621: Select OpenSC keys by usage attributes. Patch from
@@ -874,4 +882,4 @@
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
Report from murple@murple.net, diagnosis from dtucker@zip.com.au
-$Id: ChangeLog,v 1.2906 2003/08/26 00:48:14 djm Exp $
+$Id: ChangeLog,v 1.2907 2003/08/26 01:49:55 dtucker Exp $
diff --git a/auth.h b/auth.h
index 1ed92e01..6beff7cc 100644
--- a/auth.h
+++ b/auth.h
@@ -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
diff --git a/auth2-gss.c b/auth2-gss.c
new file mode 100644
index 00000000..c7651112
--- /dev/null
+++ b/auth2-gss.c
@@ -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 */
diff --git a/auth2.c b/auth2.c
index e6ec8ddc..4a305a41 100644
--- a/auth2.c
+++ b/auth2.c
@@ -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/24 08:23:46 markus Exp $");
#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_t seq, void *ctxt)
}
/* 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 */
diff --git a/compat.c b/compat.c
index 63a5d91f..6bd42a6f 100644
--- a/compat.c
+++ b/compat.c
@@ -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 },
diff --git a/compat.h b/compat.h
index 881e450d..a21e473c 100644
--- a/compat.h
+++ b/compat.h
@@ -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);
diff --git a/gss-genr.c b/gss-genr.c
new file mode 100644
index 00000000..bda12d6f
--- /dev/null
+++ b/gss-genr.c
@@ -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 */
diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c
new file mode 100644
index 00000000..d8687225
--- /dev/null
+++ b/gss-serv-krb5.c
@@ -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 */
diff --git a/gss-serv.c b/gss-serv.c
new file mode 100644
index 00000000..42718177
--- /dev/null
+++ b/gss-serv.c
@@ -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