this is the proposed gssapi diff against OpenSSH-current (non-portable).
note: if this goes in, the old krb5 auth (ssh.com compatible) will be
removed.
please comment.
jakob
Index: auth.h
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/auth.h,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- auth.h 10 Aug 2003 14:06:43 -0000 1.1.1.2
+++ auth.h 10 Aug 2003 14:25:01 -0000 1.3
@@ -67,6 +67,7 @@
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 18 May 2003 16:51:43 -0000 1.13
@@ -0,0 +1,243 @@
+/* $OpenBSD$ */
+
+/*
+ * 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:
/home/hack/jakob/mycvs/sshgss/auth2.c,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- auth2.c 10 Aug 2003 14:06:43 -0000 1.1.1.2
+++ auth2.c 10 Aug 2003 14:25:01 -0000 1.5
@@ -36,6 +36,10 @@
#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 @@
#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,
@@ -176,6 +186,12 @@
}
/* 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:
/home/hack/jakob/mycvs/sshgss/compat.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- compat.c 17 May 2003 03:34:10 -0000 1.1.1.1
+++ compat.c 17 May 2003 03:49:36 -0000 1.2
@@ -79,7 +79,11 @@
{ "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:
/home/hack/jakob/mycvs/sshgss/compat.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- compat.h 17 May 2003 03:34:10 -0000 1.1.1.1
+++ compat.h 17 May 2003 03:49:36 -0000 1.2
@@ -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 18 May 2003 16:56:30 -0000 1.8
@@ -0,0 +1,255 @@
+/* $OpenBSD$ */
+
+/*
+ * 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 2 Jun 2003 18:23:49 -0000 1.9
@@ -0,0 +1,168 @@
+/* $OpenBSD$ */
+
+/*
+ * 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 2 Jun 2003 18:23:49 -0000 1.11
@@ -0,0 +1,292 @@
+/* $OpenBSD$ */
+
+/*
+ * 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 "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.
+ */
+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 = (tok[2] << 8) + tok[3]; /* 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 = (tok[offset] << 24) + (tok[offset+1] << 16) +
+ (tok[offset+2]<<8) + (tok[offset+3]);
+
+ 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:
/home/hack/jakob/mycvs/sshgss/monitor.c,v
retrieving revision 1.1.1.2
retrieving revision 1.10
diff -u -r1.1.1.2 -r1.10
--- monitor.c 10 Aug 2003 14:06:48 -0000 1.1.1.2
+++ monitor.c 10 Aug 2003 14:25:01 -0000 1.10
@@ -59,6 +59,11 @@
#include "ssh2.h"
#include "mpaux.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+static Gssctxt *gsscontext = NULL;
+#endif
+
/* Imports */
extern ServerOptions options;
extern u_int utmp_len;
@@ -119,6 +124,11 @@
#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 */
@@ -168,6 +178,11 @@
#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}
};
@@ -320,7 +335,6 @@
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);
@@ -1586,3 +1600,77 @@
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:
/home/hack/jakob/mycvs/sshgss/monitor.h,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- monitor.h 10 Aug 2003 14:06:48 -0000 1.1.1.2
+++ monitor.h 10 Aug 2003 14:25:01 -0000 1.5
@@ -50,6 +50,9 @@
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_TERM
};
Index: monitor_wrap.c
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/monitor_wrap.c,v
retrieving revision 1.1.1.2
retrieving revision 1.7
diff -u -r1.1.1.2 -r1.7
--- monitor_wrap.c 10 Aug 2003 14:06:49 -0000 1.1.1.2
+++ monitor_wrap.c 10 Aug 2003 14:25:01 -0000 1.7
@@ -52,6 +52,10 @@
#include "channels.h"
#include "session.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
/* Imports */
extern int compat20;
extern Newkeys *newkeys[];
@@ -971,4 +975,69 @@
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:
/home/hack/jakob/mycvs/sshgss/monitor_wrap.h,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- monitor_wrap.h 10 Aug 2003 14:06:49 -0000 1.1.1.2
+++ monitor_wrap.h 10 Aug 2003 14:25:01 -0000 1.5
@@ -55,6 +55,14 @@
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
+
void mm_terminate(void);
int mm_pty_allocate(int *, int *, char *, int);
void mm_session_pty_cleanup2(void *);
Index: readconf.c
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/readconf.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- readconf.c 10 Aug 2003 14:06:50 -0000 1.1.1.2
+++ readconf.c 10 Aug 2003 14:25:01 -0000 1.3
@@ -107,7 +107,7 @@
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
- oAddressFamily,
+ oAddressFamily, oGssAuthentication, oGssDelegateCreds,
oDeprecated, oUnsupported
} OpCodes;
@@ -142,6 +142,13 @@
{ "kerberostgtpassing", oUnsupported },
#endif
{ "afstokenpassing", oUnsupported },
+#if defined(GSSAPI)
+ { "gssapiauthentication", oGssAuthentication },
+ { "gssapidelegatecredentials", oGssDelegateCreds },
+#else
+ { "gssapiauthentication", oUnsupported },
+ { "gssapidelegatecredentials", oUnsupported },
+#endif
{ "fallbacktorsh", oDeprecated },
{ "usersh", oDeprecated },
{ "identityfile", oIdentityFile },
@@ -393,6 +400,14 @@
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;
@@ -818,6 +833,8 @@
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;
@@ -894,6 +911,10 @@
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:
/home/hack/jakob/mycvs/sshgss/readconf.h,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- readconf.h 10 Aug 2003 14:06:50 -0000 1.1.1.2
+++ readconf.h 10 Aug 2003 14:25:01 -0000 1.3
@@ -43,6 +43,9 @@
/* Try S/Key or TIS, authentication. */
int kerberos_authentication; /* Try Kerberos authentication. */
int kerberos_tgt_passing; /* Try Kerberos TGT passing. */
+ int afs_token_passing; /* Try AFS token 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:
/home/hack/jakob/mycvs/sshgss/servconf.c,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- servconf.c 10 Aug 2003 14:06:52 -0000 1.1.1.2
+++ servconf.c 10 Aug 2003 14:25:01 -0000 1.5
@@ -69,6 +69,9 @@
options->kerberos_or_local_passwd = -1;
options->kerberos_ticket_cleanup = -1;
options->kerberos_tgt_passing = -1;
+ options->afs_token_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;
@@ -175,6 +178,12 @@
options->kerberos_ticket_cleanup = 1;
if (options->kerberos_tgt_passing == -1)
options->kerberos_tgt_passing = 0;
+ if (options->afs_token_passing == -1)
+ options->afs_token_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)
@@ -239,6 +248,7 @@
sBanner, sUseDNS, sHostbasedAuthentication,
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
+ sGssAuthentication, sGssCleanupCreds,
sUsePrivilegeSeparation,
sDeprecated, sUnsupported
} ServerOpCodes;
@@ -277,6 +287,13 @@
{ "kerberostgtpassing", sUnsupported },
#endif
{ "afstokenpassing", sUnsupported },
+#ifdef GSSAPI
+ { "gssapiauthentication", sGssAuthentication },
+ { "gssapicleanupcreds", sGssCleanupCreds },
+#else
+ { "gssapiauthentication", sUnsupported },
+ { "gssapicleanupcreds", sUnsupported },
+#endif
{ "passwordauthentication", sPasswordAuthentication },
{ "kbdinteractiveauthentication", sKbdInteractiveAuthentication },
{ "challengeresponseauthentication",
sChallengeResponseAuthentication },
@@ -591,6 +608,14 @@
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:
/home/hack/jakob/mycvs/sshgss/servconf.h,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- servconf.h 10 Aug 2003 14:06:52 -0000 1.1.1.2
+++ servconf.h 10 Aug 2003 14:25:01 -0000 1.4
@@ -84,6 +84,9 @@
* file on logout. */
int kerberos_tgt_passing; /* If true, permit Kerberos TGT
* passing. */
+ int afs_token_passing; /* If true, permit AFS token 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:
/home/hack/jakob/mycvs/sshgss/session.c,v
retrieving revision 1.1.1.2
retrieving revision 1.4
diff -u -r1.1.1.2 -r1.4
--- session.c 10 Aug 2003 14:06:53 -0000 1.1.1.2
+++ session.c 10 Aug 2003 14:25:01 -0000 1.4
@@ -58,6 +58,10 @@
#include "session.h"
#include "monitor_wrap.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
/* func */
Session *session_new(void);
@@ -409,6 +413,12 @@
session_proctitle(s);
+#ifdef GSSAPI
+ temporarily_use_uid(s->pw);
+ ssh_gssapi_storecreds();
+ restore_uid();
+#endif
+
/* Fork the child. */
if ((pid = fork()) == 0) {
fatal_remove_all_cleanups();
@@ -517,6 +527,12 @@
ptyfd = s->ptyfd;
ttyfd = s->ttyfd;
+#ifdef GSSAPI
+ temporarily_use_uid(s->pw);
+ ssh_gssapi_storecreds();
+ restore_uid();
+#endif
+
/* Fork the child. */
if ((pid = fork()) == 0) {
fatal_remove_all_cleanups();
@@ -703,7 +719,7 @@
* Sets the value of the given variable in the environment. If the variable
* already exists, its value is overriden.
*/
-static void
+void
child_set_env(char ***envp, u_int *envsizep, const char *name,
const char *value)
{
@@ -799,6 +815,13 @@
env = xmalloc(envsize * sizeof(char *));
env[0] = NULL;
+#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);
@@ -1832,4 +1855,7 @@
do_authenticated2(Authctxt *authctxt)
{
server_loop2(authctxt);
+#if defined(GSSAPI)
+ ssh_gssapi_cleanup_creds(NULL);
+#endif
}
Index: session.h
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/session.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- session.h 17 May 2003 03:34:18 -0000 1.1.1.1
+++ session.h 17 May 2003 03:43:28 -0000 1.2
@@ -68,4 +68,7 @@
Session *session_by_tty(char *);
void session_close(Session *);
void do_setusercontext(struct passwd *);
+void child_set_env(char ***envp, u_int *envsizep, const char *name,
+ const char *value);
+
#endif
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 2 Jun 2003 18:23:49 -0000 1.8
@@ -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:
/home/hack/jakob/mycvs/sshgss/ssh_config.5,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- ssh_config.5 10 Aug 2003 14:06:57 -0000 1.1.1.2
+++ ssh_config.5 10 Aug 2003 14:25:01 -0000 1.3
@@ -331,6 +331,18 @@
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:
/home/hack/jakob/mycvs/sshgss/sshconnect2.c,v
retrieving revision 1.1.1.2
retrieving revision 1.10
diff -u -r1.1.1.2 -r1.10
--- sshconnect2.c 10 Aug 2003 14:06:59 -0000 1.1.1.2
+++ sshconnect2.c 10 Aug 2003 14:25:01 -0000 1.10
@@ -52,6 +52,10 @@
#include "msg.h"
#include "pathnames.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
/* import */
extern char *client_version_string;
extern char *server_version_string;
@@ -173,6 +177,8 @@
Sensitive *sensitive;
/* kbd-interactive */
int info_req_seen;
+ /* generic */
+ void *methoddata;
};
struct Authmethod {
char *name; /* string to compare against server's list */
@@ -196,6 +202,15 @@
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 *);
@@ -208,6 +223,12 @@
static char *authmethods_get(void);
Authmethod authmethods[] = {
+#ifdef GSSAPI
+ {"gssapi",
+ userauth_gssapi,
+ &options.gss_authentication,
+ NULL},
+#endif
{"hostbased",
userauth_hostbased,
&options.hostbased_authentication,
@@ -278,6 +299,7 @@
authctxt.success = 0;
authctxt.method = authmethod_lookup("none");
authctxt.authlist = NULL;
+ authctxt.methoddata = NULL;
authctxt.sensitive = sensitive;
authctxt.info_req_seen = 0;
if (authctxt.method == NULL)
@@ -301,6 +323,10 @@
void
userauth(Authctxt *authctxt, char *authlist)
{
+ if (authctxt->methoddata) {
+ xfree(authctxt->methoddata);
+ authctxt->methoddata = NULL;
+ }
if (authlist == NULL) {
authlist = authctxt->authlist;
} else {
@@ -356,6 +382,8 @@
fatal("input_userauth_success: no authentication context");
if (authctxt->authlist)
xfree(authctxt->authlist);
+ if (authctxt->methoddata)
+ xfree(authctxt->methoddata);
authctxt->success = 1; /* break out */
}
@@ -444,6 +472,229 @@
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();
+
+ fprintf(stderr, "Server GSSAPI Error:\n%s\n", msg);
+ xfree(msg);
+ xfree(lang);
+}
+
+#endif /* GSSAPI */
+
int
userauth_none(Authctxt *authctxt)
{
@@ -454,6 +705,7 @@
packet_put_cstring(authctxt->method->name);
packet_send();
return 1;
+
}
int
Index: sshd_config
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/sshd_config,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- sshd_config 10 Aug 2003 14:07:00 -0000 1.1.1.2
+++ sshd_config 10 Aug 2003 14:40:31 -0000 1.5
@@ -63,6 +63,10 @@
#KerberosTicketCleanup yes
#KerberosTgtPassing no
+# GSSAPI options
+#GSSAPIAuthentication no
+#GSSAPICleanupCreds yes
+
#AllowTcpForwarding yes
#GatewayPorts no
#X11Forwarding no
Index: sshd_config.5
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/sshd_config.5,v
retrieving revision 1.1.1.2
retrieving revision 1.7
diff -u -r1.1.1.2 -r1.7
--- sshd_config.5 10 Aug 2003 14:07:00 -0000 1.1.1.2
+++ sshd_config.5 10 Aug 2003 14:25:01 -0000 1.7
@@ -225,6 +225,19 @@
.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
Index: lib/Makefile
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/lib/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- lib/Makefile 10 Aug 2003 14:07:00 -0000 1.1.1.2
+++ lib/Makefile 10 Aug 2003 14:25:02 -0000 1.3
@@ -23,6 +23,9 @@
.if (${KERBEROS5:L} == "yes")
CFLAGS+= -DKRB5 -I${DESTDIR}/usr/include/kerberosV
+
+SRCS+= gss-genr.c
+CFLAGS+= -DGSSAPI
.endif # KERBEROS5
.include <bsd.lib.mk>
Index: ssh/Makefile
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/ssh/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- ssh/Makefile 10 Aug 2003 14:07:00 -0000 1.1.1.2
+++ ssh/Makefile 10 Aug 2003 14:25:02 -0000 1.3
@@ -19,8 +19,13 @@
.if (${KERBEROS5:L} == "yes")
CFLAGS+= -DKRB5 -I${DESTDIR}/usr/include/kerberosV
-DPADD+= ${LIBKRB5} ${LIBASN1}
-LDADD+= -lkrb5 -lasn1
+
+LDADD+= -lkrb5
+DPADD+= ${LIBKRB5}
+
+CFLAGS+= -DGSSAPI
+LDADD+= -lgssapi
+DPADD+= ${LIBGSSAPI}
.endif # KERBEROS5
.include <bsd.prog.mk>
Index: sshd/Makefile
==================================================================RCS file:
/home/hack/jakob/mycvs/sshgss/sshd/Makefile,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sshd/Makefile 10 Aug 2003 14:07:01 -0000 1.1.1.2
+++ sshd/Makefile 10 Aug 2003 14:25:02 -0000 1.3
@@ -23,8 +23,14 @@
.if (${KERBEROS5:L} == "yes")
CFLAGS+=-DKRB5 -I${DESTDIR}/usr/include/kerberosV
SRCS+= auth-krb5.c auth2-krb5.c
-DPADD+= ${LIBKRB5} ${LIBASN1}
-LDADD+= -lkrb5 -lasn1
+
+LDADD+= -lkrb5
+DPADD+= ${LIBKRB5}
+
+SRCS+= auth2-gss.c gss-serv.c gss-serv-krb5.c
+CFLAGS+= -DGSSAPI
+LDADD+= -lgssapi
+DPADD+= ${LIBGSSAPI}
.endif # KERBEROS5
.include <bsd.prog.mk>