]> andersk Git - gssapi-openssh.git/commitdiff
merged OPENSSH_4_2P1_SIMON-20050926-2 to trunk
authorjbasney <jbasney>
Mon, 19 Dec 2005 22:53:37 +0000 (22:53 +0000)
committerjbasney <jbasney>
Mon, 19 Dec 2005 22:53:37 +0000 (22:53 +0000)
29 files changed:
openssh/Makefile.in
openssh/acconfig.h
openssh/auth-krb5.c
openssh/auth.h
openssh/auth2-gss.c
openssh/auth2.c
openssh/configure.ac
openssh/gss-genr.c
openssh/gss-serv-krb5.c
openssh/gss-serv.c
openssh/kex.c
openssh/kex.h
openssh/kexgssc.c
openssh/kexgsss.c
openssh/key.c
openssh/monitor.c
openssh/monitor.h
openssh/monitor_wrap.c
openssh/monitor_wrap.h
openssh/readconf.c
openssh/readconf.h
openssh/servconf.c
openssh/servconf.h
openssh/session.c
openssh/ssh-gss.h
openssh/ssh_config.5
openssh/sshconnect2.c
openssh/sshd.c
openssh/sshd_config.5

index 504672081186beb113e95076938833cedb3b4085..84e2c77b4f3883481eabeb7b4d02af2274555e94 100644 (file)
@@ -72,8 +72,7 @@ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o buffer.o \
        atomicio.o key.o dispatch.o kex.o mac.o uidswap.o uuencode.o misc.o \
        monitor_fdpass.o rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o \
        kexgex.o kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
-       kexgssc.o \
-       entropy.o scard-opensc.o gss-genr.o
+       entropy.o scard-opensc.o gss-genr.o kexgssc.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
        sshconnect.o sshconnect1.o sshconnect2.o
@@ -85,9 +84,8 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
        auth-skey.o auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \
        auth2-none.o auth2-passwd.o auth2-pubkey.o \
        monitor_mm.o monitor.o monitor_wrap.o kexdhs.o kexgexs.o \
-       kexgsss.o gss-serv-gsi.o \
        auth-krb5.o \
-       auth2-gss.o gss-serv.o gss-serv-krb5.o \
+       auth2-gss.o gss-serv.o gss-serv-krb5.o gss-serv-gsi.o kexgsss.o \
        loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
        audit.o audit-bsm.o
 
index b2e21dd1a985c022075817cd750a0c5a34c9ff5f..9adbe8bca37a9cc8bf75e896bd7628f04b002a62 100644 (file)
 /* getaddrinfo is broken (if present) */
 #undef BROKEN_GETADDRINFO
 
+/* platform uses an in-memory credentials cache */
+#undef USE_CCAPI
+
+/* platform has a Security Authorization Session API */
+#undef USE_SECURITY_SESSION_API
+
 /* updwtmpx is broken (if present) */
 #undef BROKEN_UPDWTMPX
 
index c7367b49a2772e4d8aacb14de39165cbdda22af8..5f554a66ba61265d34506326e639893fc0b9ac96 100644 (file)
@@ -159,8 +159,13 @@ auth_krb5_password(Authctxt *authctxt, const char *password)
 
        len = strlen(authctxt->krb5_ticket_file) + 6;
        authctxt->krb5_ccname = xmalloc(len);
+#ifdef USE_CCAPI
+       snprintf(authctxt->krb5_ccname, len, "API:%s",
+           authctxt->krb5_ticket_file);
+#else
        snprintf(authctxt->krb5_ccname, len, "FILE:%s",
            authctxt->krb5_ticket_file);
+#endif
 
 #ifdef USE_PAM
        if (options.use_pam)
@@ -212,15 +217,22 @@ krb5_cleanup_proc(Authctxt *authctxt)
 #ifndef HEIMDAL
 krb5_error_code
 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
-       int tmpfd, ret;
+       int ret;
        char ccname[40];
        mode_t old_umask;
+#ifdef USE_CCAPI
+       char cctemplate[] = "API:krb5cc_%d";
+#else
+       char cctemplate[] = "FILE:/tmp/krb5cc_%d_XXXXXXXXXX";
+       int tmpfd;
+#endif
 
        ret = snprintf(ccname, sizeof(ccname),
-           "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid());
-       if (ret == -1 || ret >= sizeof(ccname))
+           cctemplate, geteuid());
+       if (ret == -1 || ret >= (int) sizeof(ccname))
                return ENOMEM;
 
+#ifndef USE_CCAPI
        old_umask = umask(0177);
        tmpfd = mkstemp(ccname + strlen("FILE:"));
        umask(old_umask);
@@ -235,6 +247,7 @@ ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) {
                return errno;
        }
        close(tmpfd);
+#endif
 
        return (krb5_cc_resolve(ctx, ccname, ccache));
 }
index 5cd4ea37ae25b7b15a0897506e9d28d4186bd235..4114fa38ec9117189b20d493d25b795a5f4159f0 100644 (file)
@@ -56,6 +56,7 @@ struct Authctxt {
        int              valid;         /* user exists and is allowed to login */
        int              attempt;
        int              failures;
+       int              server_caused_failure; 
        int              force_pwchange;
        char            *user;          /* username sent by the client */
        char            *service;
index 1445e4ffccd499b0632de1ca32f559b72ffdcd45..8622002214e8655cb232962d9e68779e9894dd39 100644 (file)
@@ -62,6 +62,52 @@ userauth_external(Authctxt *authctxt)
        return 0;
 }
 
+/* 
+ * The 'gssapi_keyex' userauth mechanism.
+ */
+static int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+       int authenticated = 0;
+       Buffer b, b2;
+       gss_buffer_desc mic, gssbuf, gssbuf2;
+       u_int len;
+
+       mic.value = packet_get_string(&len);
+       mic.length = len;
+
+       packet_check_eom();
+
+       ssh_gssapi_buildmic(&b, authctxt->user, authctxt->service,
+           "gssapi-keyex");
+
+       gssbuf.value = buffer_ptr(&b);
+       gssbuf.length = buffer_len(&b);
+
+       /* client may have used empty username to determine target
+          name from GSSAPI context */
+       ssh_gssapi_buildmic(&b2, "", authctxt->service, "gssapi-keyex");
+
+       gssbuf2.value = buffer_ptr(&b2);
+       gssbuf2.length = buffer_len(&b2);
+
+       /* gss_kex_context is NULL with privsep, so we can't check it here */
+       if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
+                                                  &gssbuf, &mic))) ||
+           !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, 
+                                                  &gssbuf2, &mic)))) {
+           if (authctxt->valid && authctxt->user && authctxt->user[0]) {
+               authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
+           }
+       }
+       
+       buffer_free(&b);
+       buffer_free(&b2);
+       xfree(mic.value);
+
+       return (authenticated);
+}
+
 /*
  * We only support those mechanisms that we know about (ie ones that we know
  * how to check local user kuserok and the like
@@ -115,11 +161,13 @@ userauth_gssapi(Authctxt *authctxt)
 
        if (!present) {
                xfree(doid);
+               authctxt->server_caused_failure = 1;
                return (0);
        }
 
        if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
                xfree(doid);
+               authctxt->server_caused_failure = 1;
                return (0);
        }
 
@@ -383,6 +431,12 @@ Authmethod method_external = {
        &options.gss_authentication
 };
        
+Authmethod method_gsskeyex = {
+       "gssapi-keyex",
+       userauth_gsskeyex,
+       &options.gss_authentication
+};
+
 Authmethod method_gssapi = {
        "gssapi-with-mic",
        userauth_gssapi_with_mic,
index ac0b0d74042858bc6e6f196087cf6a42a12f7516..319303c09c24709a7914f4b339fe6e62ca0b4c66 100644 (file)
@@ -56,6 +56,7 @@ extern Authmethod method_kbdint;
 extern Authmethod method_hostbased;
 #ifdef GSSAPI
 extern Authmethod method_external;
+extern Authmethod method_gsskeyex;
 extern Authmethod method_gssapi;
 extern Authmethod method_gssapi_compat;
 #endif
@@ -64,6 +65,7 @@ Authmethod *authmethods[] = {
        &method_none,
        &method_pubkey,
 #ifdef GSSAPI
+       &method_gsskeyex,
        &method_external,
        &method_gssapi,
        &method_gssapi_compat,
@@ -151,7 +153,8 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 #ifdef GSSAPI
        if (user[0] == '\0') {
            debug("received empty username for %s", method);
-           if (strcmp(method, "external-keyx") == 0) {
+           if (strcmp(method, "external-keyx") == 0 ||
+               strcmp(method, "gssapi-keyex") == 0) {
                char *lname = NULL;
                PRIVSEP(ssh_gssapi_localname(&lname));
                if (lname && lname[0] != '\0') {
@@ -243,6 +246,7 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
 #endif
 
        authctxt->postponed = 0;
+       authctxt->server_caused_failure = 0;
 
        /* try to authenticate user */
        m = authmethod_lookup(method);
@@ -313,7 +317,9 @@ userauth_finish(Authctxt *authctxt, int authenticated, char *method)
                /* now we can break out */
                authctxt->success = 1;
        } else {
-               if (authctxt->failures++ > options.max_authtries) {
+               /* Dont count server configuration issues against the client */
+               if (!authctxt->server_caused_failure && 
+                   authctxt->failures++ > options.max_authtries) {
 #ifdef SSH_AUDIT_EVENTS
                        PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
 #endif
index 759a0b00adb69ffe4f5106e94e92d89bc202d7b4..a7fc06ed7052c7a440aa4292b9793f4869f70344 100644 (file)
@@ -257,6 +257,28 @@ case "$host" in
        AC_DEFINE(BROKEN_SETREUID)
        AC_DEFINE(BROKEN_SETREGID)
        AC_DEFINE_UNQUOTED(BIND_8_COMPAT, 1)
+       AC_MSG_CHECKING(if we have the Security Authorization Session API)
+       AC_TRY_COMPILE([#include <Security/AuthSession.h>],
+               [SessionCreate(0, 0);],
+               [ac_cv_use_security_session_api="yes"
+                AC_DEFINE(USE_SECURITY_SESSION_API)
+                LIBS="$LIBS -framework Security"
+                AC_MSG_RESULT(yes)],
+               [ac_cv_use_security_session_api="no"
+                AC_MSG_RESULT(no)])
+       AC_MSG_CHECKING(if we have an in-memory credentials cache)
+       AC_TRY_COMPILE(
+               [#include <Kerberos/Kerberos.h>],
+               [cc_context_t c;
+                (void) cc_initialize (&c, 0, NULL, NULL);],
+               [AC_DEFINE(USE_CCAPI)
+                LIBS="$LIBS -framework Security"
+                AC_MSG_RESULT(yes)
+                if test "x$ac_cv_use_security_session_api" = "xno"; then
+                       AC_MSG_ERROR(*** Need a security framework to use the credentials cache API ***)
+               fi],
+               [AC_MSG_RESULT(no)]
+       )
        ;;
 *-*-hpux*)
        # first we define all of the options common to all HP-UX releases
index 3d6a4e2958c9eb15ab8534005d51464d5406521a..26e20b9773ebf7fe5fd0fbe2781dc3dfb81eaa08 100644 (file)
@@ -1,7 +1,7 @@
 /*     $OpenBSD: gss-genr.c,v 1.4 2005/07/17 07:17:55 djm Exp $        */
 
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -38,6 +38,7 @@
 #include "monitor_wrap.h"
 #include "canohost.h"
 #include "ssh2.h"
+#include <openssl/evp.h>
 
 #include "ssh-gss.h"
 
@@ -48,109 +49,139 @@ typedef struct {
        char *encoded;
        gss_OID oid;
 } ssh_gss_kex_mapping;
-       
-static ssh_gss_kex_mapping *gss_enc2oid;
 
-/* Return a list of the gss-group1-sha1-x mechanisms supported by this
- * program.
- *
- * On the client side, we don't need to worry about whether we 'know'
- * about the mechanism or not - we assume that any mechanism that we've been
- * linked against is suitable for inclusion.
+/*
+ * XXX - It would be nice to find a more elegant way of handling the
+ * XXX   passing of the key exchange context to the userauth routines
+ */
+
+Gssctxt *gss_kex_context = NULL;
+
+static ssh_gss_kex_mapping *gss_enc2oid = NULL;
+
+int 
+ssh_gssapi_oid_table_ok() {
+       return (gss_enc2oid != NULL);
+}
+
+/*
+ * Return a list of the gss-group1-sha1 mechanisms supported by this program
  *
- * XXX - We might want to make this configurable in the future, so as to
- * XXX - allow the user control over which mechanisms to use.
+ * We test mechanisms to ensure that we can use them, to avoid starting
+ * a key exchange with a bad mechanism
  */
-char * 
-ssh_gssapi_client_mechanisms(char *host) {
-       gss_OID_set     supported;
-       OM_uint32       min_status;
-       Buffer          buf;
-       size_t          i = 0;
-       char            *mechs;
-       char            *encoded;
-       int             enclen;
-       unsigned char   digest[EVP_MAX_MD_SIZE];
-       char            deroid[2];
-       const EVP_MD    *evp_md = EVP_md5();
-       EVP_MD_CTX      md;
-       int             oidpos=0;
-       
-       gss_indicate_mechs(&min_status,&supported);
-       gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
-                           *(supported->count+1));
-       
-       buffer_init(&buf);
 
-       for (i=0;i<supported->count;i++) {
 
-               gss_enc2oid[oidpos].encoded=NULL;
-               
-               if (supported->elements[i].length<128 &&
-                   ssh_gssapi_check_mechanism(&(supported->elements[i]),host)) {
+char *
+ssh_gssapi_client_mechanisms(const char *host) {
+       gss_OID_set gss_supported;
+       OM_uint32 min_status;
+
+       gss_indicate_mechs(&min_status, &gss_supported);
 
-                       /* Add the required DER encoding octets and MD5 hash */
-                       deroid[0]=0x06; /* Object Identifier */
-                       deroid[1]=supported->elements[i].length;
+       return(ssh_gssapi_kex_mechs(gss_supported, ssh_gssapi_check_mechanism,
+           (void *)host));
+}
+
+char *
+ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check,
+    void *data) {
+       Buffer buf;
+       size_t i;
+       int oidpos, enclen;
+       char *mechs, *encoded;
+       unsigned char digest[EVP_MAX_MD_SIZE];
+       char deroid[2];
+       const EVP_MD *evp_md = EVP_md5();
+       EVP_MD_CTX md;
+
+       if (gss_enc2oid != NULL) {
+               for (i=0;gss_enc2oid[i].encoded!=NULL;i++)
+                       xfree(gss_enc2oid[i].encoded);
+               xfree(gss_enc2oid);
+       }
+
+       gss_enc2oid = xmalloc(sizeof(ssh_gss_kex_mapping)*
+           (gss_supported->count+1));
+
+       buffer_init(&buf);
+
+       oidpos = 0;
+       for (i = 0;i < gss_supported->count;i++) {
+               if (gss_supported->elements[i].length < 128 &&
+                   (*check)(&(gss_supported->elements[i]), data)) {
+
+                       deroid[0] = SSH_GSS_OIDTYPE;
+                       deroid[1] = gss_supported->elements[i].length;
 
                        EVP_DigestInit(&md, evp_md);
-                       EVP_DigestUpdate(&md,deroid,2);
+                       EVP_DigestUpdate(&md, deroid, 2);
                        EVP_DigestUpdate(&md,
-                                        supported->elements[i].elements,
-                                        supported->elements[i].length);
+                           gss_supported->elements[i].elements,
+                           gss_supported->elements[i].length);
                        EVP_DigestFinal(&md, digest, NULL);
-                       
-                       /* Base64 encode it */
-                       encoded=xmalloc(EVP_MD_size(evp_md)*2);
-                       enclen=__b64_ntop(digest, EVP_MD_size(evp_md),
-                                         encoded,EVP_MD_size(evp_md)*2);
-                       if (oidpos!=0) {
-                               buffer_put_char(&buf,',');
-                       }       
-                       buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1);
-                       buffer_append(&buf, encoded, enclen);
 
-                       debug("Mechanism encoded as %s",encoded);
+                       encoded = xmalloc(EVP_MD_size(evp_md)*2);
+                       enclen = __b64_ntop(digest, EVP_MD_size(evp_md),
+                           encoded, EVP_MD_size(evp_md)*2);
 
-                       gss_enc2oid[oidpos].oid=&(supported->elements[i]);
-                       gss_enc2oid[oidpos].encoded=encoded;                    
+                       if (oidpos != 0)
+                           buffer_put_char(&buf, ',');
+
+                       buffer_append(&buf, KEX_GSS_GEX_SHA1_ID,
+                           sizeof(KEX_GSS_GEX_SHA1_ID)-1);
+                       buffer_append(&buf, encoded, enclen);
+                       buffer_put_char(&buf,',');
+                       buffer_append(&buf, KEX_GSS_GRP1_SHA1_ID, 
+                           sizeof(KEX_GSS_GRP1_SHA1_ID)-1);
+                       buffer_append(&buf, encoded, enclen);
+
+                       gss_enc2oid[oidpos].oid = &(gss_supported->elements[i]);
+                       gss_enc2oid[oidpos].encoded = encoded;
                        oidpos++;
                }
        }
-       gss_enc2oid[oidpos].oid=NULL;
-       gss_enc2oid[oidpos].encoded=NULL;
-       
-       buffer_put_char(&buf,'\0');
-       
-       mechs=xmalloc(buffer_len(&buf));
-       buffer_get(&buf,mechs,buffer_len(&buf));
+       gss_enc2oid[oidpos].oid = NULL;
+       gss_enc2oid[oidpos].encoded = NULL;
+
+       buffer_put_char(&buf, '\0');
+
+       mechs = xmalloc(buffer_len(&buf));
+       buffer_get(&buf, mechs, buffer_len(&buf));
        buffer_free(&buf);
-       if (strlen(mechs)==0)
-               return(NULL);
-       else
-               return(mechs);
-}
 
-gss_OID
-ssh_gssapi_client_id_kex(Gssctxt *ctx, char *name) {
-       int i=0;
-       
-       if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
-               return(NULL);
+       if (strlen(mechs) == 0) {
+               xfree(mechs);
+               mechs = NULL;
        }
        
-       name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the ID string */
-       
-       while (gss_enc2oid[i].encoded!=NULL &&
-               strcmp(name,gss_enc2oid[i].encoded)!=0) {
-               i++;
+       return (mechs);
+}
+
+gss_OID
+ssh_gssapi_id_kex(Gssctxt *ctx, char *name, int *gex) {
+       int i = 0;
+
+       if (strncmp(name, KEX_GSS_GRP1_SHA1_ID,
+           sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) {
+               name+=sizeof(KEX_GSS_GRP1_SHA1_ID)-1;
+               *gex = 0;
+       } else if (strncmp(name, KEX_GSS_GEX_SHA1_ID,
+           sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) {
+               name+=sizeof(KEX_GSS_GEX_SHA1_ID)-1;
+               *gex = 1;
+       } else {
+               return NULL;
        }
-       
-       if (gss_enc2oid[i].oid!=NULL) {
-               ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid);
+
+       while (gss_enc2oid[i].encoded != NULL &&
+           strcmp(name, gss_enc2oid[i].encoded) != 0) {
+               i++;
        }
 
+       if (gss_enc2oid[i].oid != NULL && ctx != NULL)
+               ssh_gssapi_set_oid(ctx, gss_enc2oid[i].oid);
+
        return gss_enc2oid[i].oid;
 }
 
@@ -378,6 +409,9 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx)
 OM_uint32
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
 {
+       if (ctx == NULL) 
+               return -1;
+
        if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context,
            GSS_C_QOP_DEFAULT, buffer, hash)))
                ssh_gssapi_error(ctx);
@@ -385,6 +419,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash)
        return (ctx->major);
 }
 
+/* Priviledged when used by server */
+OM_uint32
+ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
+{
+       if (ctx == NULL)
+               return -1;
+
+       ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
+           gssbuf, gssmic, NULL);
+
+       return (ctx->major);
+}
+
 void
 ssh_gssapi_buildmic(Buffer *b, const char *user, const char *service,
     const char *context)
@@ -407,18 +454,18 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
 }
 
 int
-ssh_gssapi_check_mechanism(gss_OID oid, const char *host) {
+ssh_gssapi_check_mechanism(gss_OID oid, void *host) {
        Gssctxt * ctx = NULL;
-       gss_buffer_desc token;
-       OM_uint32 major,minor;
+       gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+       OM_uint32 major, minor;
        
        ssh_gssapi_build_ctx(&ctx);
-       ssh_gssapi_set_oid(ctx,oid);
-       ssh_gssapi_import_name(ctx,host);
-       major=ssh_gssapi_init_ctx(ctx,0, GSS_C_NO_BUFFER, &token, NULL);
-       gss_release_buffer(&minor,&token);
+       ssh_gssapi_set_oid(ctx, oid);
+       ssh_gssapi_import_name(ctx, host);
+       major = ssh_gssapi_init_ctx(ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
+       gss_release_buffer(&minor, &token);
        ssh_gssapi_delete_ctx(&ctx);
-       return(!GSS_ERROR(major));
+       return (!GSS_ERROR(major));
 }
 
 #endif /* GSSAPI */
index 8b3a4a7142398f3f9f10b16be11a23a4d97a884b..a1e87aca2530a0dfddf979d5bd0d5ce7245cfa26 100644 (file)
@@ -40,10 +40,10 @@ extern ServerOptions options;
 
 #ifdef HEIMDAL
 # include <krb5.h>
-#else
-# ifdef HAVE_GSSAPI_KRB5
+#elsif !defined(MECHGLUE)
+# ifdef HAVE_GSSAPI_KRB5_H
 #  include <gssapi_krb5.h>
-# elif HAVE_GSSAPI_GSSAPI_KRB5
+# elif HAVE_GSSAPI_GSSAPI_KRB5_H
 #  include <gssapi/gssapi_krb5.h>
 # endif
 #endif
index 9b6b4c290c1f377271d656993b1b52931ba287eb..0c73250906c34787404ab988680bae18085056a1 100644 (file)
@@ -45,8 +45,6 @@
 #include "ssh-gss.h"
 
 extern ServerOptions options;
-extern u_char *session_id2;
-extern int session_id2_len;
 
 static ssh_gssapi_client gssapi_client =
     { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
@@ -76,6 +74,28 @@ ssh_gssapi_mech* supported_mechs[]= {
 static int limited = 0;
 #endif
 
+/* Unpriviledged */
+char *
+ssh_gssapi_server_mechanisms() {
+       gss_OID_set     supported;
+
+       ssh_gssapi_supported_oids(&supported);
+       return (ssh_gssapi_kex_mechs(supported, &ssh_gssapi_server_check_mech,
+           NULL));
+}
+
+/* Unpriviledged */
+int
+ssh_gssapi_server_check_mech(gss_OID oid, void *data) {
+        Gssctxt * ctx = NULL;
+       int res;
+
+       res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid)));
+       ssh_gssapi_delete_ctx(&ctx);
+
+       return (res);
+}
+
 /* Unpriviledged */
 void
 ssh_gssapi_supported_oids(gss_OID_set *oidset)
@@ -335,112 +355,6 @@ ssh_gssapi_userok(char *user)
        return (0);
 }
 
-/* Return a list of the gss-group1-sha1-x mechanisms supported by this
- * program.
- *
- * We only support the mechanisms that we've indicated in the list above,
- * but we check that they're supported by the GSSAPI mechanism on the 
- * machine. We also check, before including them in the list, that
- * we have the necesary information in order to carry out the key exchange
- * (that is, that the user has credentials, the server's creds are accessible,
- * etc)
- *
- * The way that this is done is fairly nasty, as we do a lot of work that
- * is then thrown away. This should possibly be implemented with a cache
- * that stores the results (in an expanded Gssctxt structure), which are
- * then used by the first calls if that key exchange mechanism is chosen.
- */
-
-/* Unpriviledged */ 
-char * 
-ssh_gssapi_server_mechanisms() {
-       gss_OID_set     supported;
-       Gssctxt         *ctx = NULL;
-       OM_uint32       maj_status, min_status;
-       Buffer          buf;
-       int             i = 0;
-       int             first = 0;
-       int             present;
-       char *          mechs;
-
-       ssh_gssapi_supported_oids(&supported);
-       
-       buffer_init(&buf);
-
-       while(supported_mechs[i]->name != NULL) {
-               if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                       &supported_mechs[i]->oid,
-                                                       supported,
-                                                       &present))) {
-                       present=0;
-               }
-
-               if (present) {
-                   if (!GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx,
-                                          &supported_mechs[i]->oid)))) {
-                       /* Append gss_group1_sha1_x to our list */
-                       if (first++!=0)
-                               buffer_put_char(&buf,',');
-                       buffer_append(&buf, KEX_GSS_SHA1,
-                                     sizeof(KEX_GSS_SHA1)-1);
-                       buffer_append(&buf, 
-                                     supported_mechs[i]->enc_name,
-                                     strlen(supported_mechs[i]->enc_name));
-                       debug("GSSAPI mechanism %s (%s%s) supported",
-                             supported_mechs[i]->name, KEX_GSS_SHA1,
-                             supported_mechs[i]->enc_name);
-                   } else {
-                       debug("no credentials for GSSAPI mechanism %s",
-                             supported_mechs[i]->name);
-                   }
-               } else {
-                   debug("GSSAPI mechanism %s not supported",
-                         supported_mechs[i]->name);
-               }
-               ssh_gssapi_delete_ctx(&ctx);
-               i++;
-       }
-       
-       buffer_put_char(&buf,'\0');
-       
-       mechs=xmalloc(buffer_len(&buf));
-       buffer_get(&buf,mechs,buffer_len(&buf));
-       buffer_free(&buf);
-       if (strlen(mechs)==0) {
-           options.gss_authentication = 0; /* no mechs. skip gss auth. */
-           return(NULL);
-       } else {
-           return(mechs);
-       }
-}
-
-/* Return the OID that corresponds to the given context name */
-/* Unpriviledged */
-gss_OID 
-ssh_gssapi_server_id_kex(char *name) {
-  int i=0;
-  
-  if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) {
-     return(NULL);
-  }
-  
-  name+=sizeof(KEX_GSS_SHA1)-1; /* Move to the start of the MIME string */
-  
-  while (supported_mechs[i]->name!=NULL &&
-        strcmp(name,supported_mechs[i]->enc_name)!=0) {
-       i++;
-  }
-
-  if (supported_mechs[i]->name==NULL)
-     return (NULL);
-
-  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
-       KEX_GSS_SHA1, supported_mechs[i]->enc_name);
-
-  return &supported_mechs[i]->oid;
-}
-
 /* Priviledged */
 int
 ssh_gssapi_localname(char **user)
@@ -459,14 +373,4 @@ ssh_gssapi_localname(char **user)
        return(0);
 }
 
-/* Priviledged */
-OM_uint32
-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
-{
-       ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
-           gssbuf, gssmic, NULL);
-
-       return (ctx->major);
-}
-
 #endif
index 7d814217a9c89d9e9e927c2cc5e77d2a73797e49..8cd851d232af2873578b85334528f293fa8c711c 100644 (file)
@@ -303,7 +303,11 @@ choose_kex(Kex *k, char *client, char *server)
        } else if (strcmp(k->name, KEX_DHGEX) == 0) {
                k->kex_type = KEX_DH_GEX_SHA1;
 #ifdef GSSAPI
-       } else if (strncmp(k->name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
+       } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID,
+           sizeof(KEX_GSS_GEX_SHA1_ID)-1) == 0) {
+               k->kex_type = KEX_GSS_GEX_SHA1;
+       } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, 
+           sizeof(KEX_GSS_GRP1_SHA1_ID)-1) == 0) {
                k->kex_type = KEX_GSS_GRP1_SHA1;
 #endif
        } else
index 1cedd9963e60b331903daf911c54484eb232e22a..ce9d334c4889c83b4f67c239737db4d44f838067 100644 (file)
@@ -64,6 +64,7 @@ enum kex_exchange {
        KEX_DH_GRP14_SHA1,
        KEX_DH_GEX_SHA1,
        KEX_GSS_GRP1_SHA1,
+       KEX_GSS_GEX_SHA1,
        KEX_MAX
 };
 
@@ -120,6 +121,11 @@ struct Kex {
        Buffer  peer;
        int     done;
        int     flags;
+#ifdef GSSAPI
+       int     gss_deleg_creds;
+       int     gss_trust_dns;
+       char    *gss_host;
+#endif
        char    *client_version_string;
        char    *server_version_string;
        struct  KexOptions options;
@@ -142,9 +148,10 @@ void        kexdh_client(Kex *);
 void    kexdh_server(Kex *);
 void    kexgex_client(Kex *);
 void    kexgex_server(Kex *);
+
 #ifdef GSSAPI
-void     kexgss_client(Kex *);
-void     kexgss_server(Kex *);
+void   kexgss_client(Kex *);
+void   kexgss_server(Kex *);
 #endif
 
 u_char *
index 627f14e09dc296407a8f0e3bc1fbcb924fefc37f..acd20458ef592b79978176400dfade13aae78290 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "ssh-gss.h"
 
 void
-kexgss_client(Kex *kex)
-{
-       gss_buffer_desc gssbuf,send_tok,recv_tok, msg_tok, *token_ptr;
+kexgss_client(Kex *kex) {
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+        gss_buffer_desc recv_tok, gssbuf, msg_tok, *token_ptr;
        Gssctxt *ctxt;
        OM_uint32 maj_status, min_status, ret_flags;
        unsigned int klen, kout;
        DH *dh; 
-       BIGNUM *dh_server_pub = 0;
-       BIGNUM *shared_secret = 0;      
+       BIGNUM *dh_server_pub = NULL;
+       BIGNUM *shared_secret = NULL;
+       BIGNUM *p = NULL;
+       BIGNUM *g = NULL;       
        unsigned char *kbuf;
        unsigned char *hash;
-       unsigned char *serverhostkey = 0;
+       unsigned char *serverhostkey = NULL;
        char *msg;
        char *lang;
        int type = 0;
        int first = 1;
-       u_int slen = 0;
+       unsigned int slen = 0;
+       int gex = 0;
+       int nbits = -1, min = -1, max = -1;
        u_int strlen;
-       
-       /* Initialise our GSSAPI world */
+
+       /* Initialise our GSSAPI world */       
        ssh_gssapi_build_ctx(&ctxt);
-       if (ssh_gssapi_client_id_kex(ctxt,kex->name)==NULL) {
+       if (ssh_gssapi_id_kex(ctxt, kex->name, &gex) == NULL)
                fatal("Couldn't identify host exchange");
-       }
 
-       if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1))) {
-               fatal("Couldn't import hostname ");
+       if (ssh_gssapi_import_name(ctxt, kex->gss_host))
+               fatal("Couldn't import hostname");
+       
+       if (gex) {
+               debug("Doing group exchange\n");
+               nbits = dh_estimate(kex->we_need * 8);
+               min = DH_GRP_MIN;
+               max = DH_GRP_MAX;
+               packet_start(SSH2_MSG_KEXGSS_GROUPREQ);
+               packet_put_int(min);
+               packet_put_int(nbits);
+               packet_put_int(max);
+
+               packet_send();
+
+               packet_read_expect(SSH2_MSG_KEXGSS_GROUP);
+
+               if ((p = BN_new()) == NULL)
+                       fatal("BN_new() failed");
+               packet_get_bignum2(p);
+               if ((g = BN_new()) == NULL)
+                       fatal("BN_new() failed");
+               packet_get_bignum2(g);
+               packet_check_eom();
+
+               if (BN_num_bits(p) < min || BN_num_bits(p) > max)
+                       fatal("GSSGRP_GEX group out of range: %d !< %d !< %d",
+                           min, BN_num_bits(p), max);
+
+               dh = dh_new_group(g, p);
+       } else {
+               dh = dh_new_group1();
        }
        
-       /* This code should match that in ssh_dh1_client */
-               
        /* Step 1 - e is dh->pub_key */
-       dh = dh_new_group1();
        dh_gen_key(dh, kex->we_need * 8);
 
        /* This is f, we initialise it now to make life easier */
-       dh_server_pub = BN_new();
-       if (dh_server_pub == NULL) {
-               fatal("dh_server_pub == NULL");
-       }
-               
+       dh_server_pub = BN_new();
+       if (dh_server_pub == NULL)
+               fatal("dh_server_pub == NULL");
+
        token_ptr = GSS_C_NO_BUFFER;
                         
        do {
                debug("Calling gss_init_sec_context");
                
-               maj_status=ssh_gssapi_init_ctx(ctxt,
-                                              kex->options.gss_deleg_creds,
-                                              token_ptr,&send_tok,
-                                              &ret_flags);
+               maj_status = ssh_gssapi_init_ctx(ctxt,
+                   kex->gss_deleg_creds, token_ptr, &send_tok,
+                   &ret_flags);
 
                if (GSS_ERROR(maj_status)) {
-                       if (send_tok.length!=0) {
+                       if (send_tok.length != 0) {
                                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
                                packet_put_string(send_tok.value,
-                                                 send_tok.length);
-                       }                         
+                                   send_tok.length);
+                       }
                        fatal("gss_init_context failed");
                }
 
                /* If we've got an old receive buffer get rid of it */
                if (token_ptr != GSS_C_NO_BUFFER)
-                       (void) gss_release_buffer(&min_status, &recv_tok);
-       
-               
+                       xfree(recv_tok.value);
+
                if (maj_status == GSS_S_COMPLETE) {
                        /* If mutual state flag is not true, kex fails */
-                       if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
+                       if (!(ret_flags & GSS_C_MUTUAL_FLAG))
                                fatal("Mutual authentication failed");
-                       }
+
                        /* If integ avail flag is not true kex fails */
-                       if (!(ret_flags & GSS_C_INTEG_FLAG)) {
+                       if (!(ret_flags & GSS_C_INTEG_FLAG))
                                fatal("Integrity check failed");
-                       }
                }
-               
-               /* If we have data to send, then the last message that we
-                * received cannot have been a 'complete'. */
-               if (send_tok.length !=0) {
+
+               /* 
+                * If we have data to send, then the last message that we
+                * received cannot have been a 'complete'. 
+                */
+               if (send_tok.length != 0) {
                        if (first) {
                                packet_start(SSH2_MSG_KEXGSS_INIT);
                                packet_put_string(send_tok.value,
-                                                 send_tok.length);
+                                   send_tok.length);
                                packet_put_bignum2(dh->pub_key);
-                               first=0;
+                               first = 0;
                        } else {
                                packet_start(SSH2_MSG_KEXGSS_CONTINUE);
                                packet_put_string(send_tok.value,
-                                                 send_tok.length);
+                                   send_tok.length);
                        }
                        packet_send();
-                       packet_write_wait();
+                       gss_release_buffer(&min_status, &send_tok);
+
+                       /* If we've sent them data, they should reply */
+                       do {    
+                               type = packet_read();
+                               if (type == SSH2_MSG_KEXGSS_HOSTKEY) {
+                                       debug("Received KEXGSS_HOSTKEY");
+                                       if (serverhostkey)
+                                               fatal("Server host key received more than once");
+                                       serverhostkey = 
+                                           packet_get_string(&slen);
+                               }
+                       } while (type == SSH2_MSG_KEXGSS_HOSTKEY);
 
-                       
-                       /* If we've sent them data, they'd better be polite
-                        * and reply. */
-               
-                       type = packet_read();
                        switch (type) {
-                       case SSH2_MSG_KEXGSS_HOSTKEY:
-                               debug("Received KEXGSS_HOSTKEY");
-                               serverhostkey=packet_get_string(&slen);
-                               break;
                        case SSH2_MSG_KEXGSS_CONTINUE:
                                debug("Received GSSAPI_CONTINUE");
                                if (maj_status == GSS_S_COMPLETE) 
                                        fatal("GSSAPI Continue received from server when complete");
-                               recv_tok.value=packet_get_string(&strlen);
-                               recv_tok.length=strlen; /* u_int vs. size_t */
+                               recv_tok.value = packet_get_string(&strlen);
+                               recv_tok.length = strlen; 
                                break;
                        case SSH2_MSG_KEXGSS_COMPLETE:
                                debug("Received GSSAPI_COMPLETE");
-                               packet_get_bignum2(dh_server_pub);
-                               msg_tok.value=packet_get_string(&strlen);
-                               msg_tok.length=strlen; /* u_int vs. size_t */
+                               packet_get_bignum2(dh_server_pub);
+                               msg_tok.value =  packet_get_string(&strlen);
+                               msg_tok.length = strlen; 
 
                                /* Is there a token included? */
                                if (packet_get_char()) {
                                        recv_tok.value=
                                            packet_get_string(&strlen);
-                                       recv_tok.length=strlen; /*u_int/size_t*/
+                                       recv_tok.length = strlen;
                                        /* If we're already complete - protocol error */
                                        if (maj_status == GSS_S_COMPLETE)
                                                packet_disconnect("Protocol error: received token when complete");
-                               } else {
-                                       /* No token included */
-                                       if (maj_status != GSS_S_COMPLETE)
-                                               packet_disconnect("Protocol error: did not receive final token");
+                                       } else {
+                                               /* No token included */
+                                               if (maj_status != GSS_S_COMPLETE)
+                                                       packet_disconnect("Protocol error: did not receive final token");
                                }
                                break;
                        case SSH2_MSG_KEXGSS_ERROR:
                                debug("Received Error");
-                               maj_status=packet_get_int();
-                               min_status=packet_get_int();
-                               msg=packet_get_string(NULL);
-                               lang=packet_get_string(NULL);
+                               maj_status = packet_get_int();
+                               min_status = packet_get_int();
+                               msg = packet_get_string(NULL);
+                               lang = packet_get_string(NULL);
                                fatal("GSSAPI Key Exchange Error: \n%s",msg);
                        default:
                                packet_disconnect("Protocol error: didn't expect packet type %d",
                                type);
                        }
-                       token_ptr=&recv_tok;
+                       token_ptr = &recv_tok;
                } else {
                        /* No data, and not complete */
-                       if (maj_status!=GSS_S_COMPLETE) {
+                       if (maj_status != GSS_S_COMPLETE)
                                fatal("Not complete, and no token output");
-                       }
                }
-       } while (maj_status & GSS_S_CONTINUE_NEEDED);
-       
-       /* We _must_ have received a COMPLETE message in reply from the 
-        * server, which will have set dh_server_pub and msg_tok */
-        
-       if (type!=SSH2_MSG_KEXGSS_COMPLETE)
-          fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
-                       
+       } while (maj_status & GSS_S_CONTINUE_NEEDED);
+
+       /* 
+        * We _must_ have received a COMPLETE message in reply from the 
+        * server, which will have set dh_server_pub and msg_tok 
+        */
+
+       if (type != SSH2_MSG_KEXGSS_COMPLETE)
+               fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it");
+
        /* Check f in range [1, p-1] */
-        if (!dh_pub_is_valid(dh, dh_server_pub))
-                        packet_disconnect("bad server public DH value");
-                        
-        /* compute K=f^x mod p */
-        klen = DH_size(dh);
-        kbuf = xmalloc(klen);
-        kout = DH_compute_key(kbuf, dh_server_pub, dh);
-        
-        shared_secret = BN_new();
-        BN_bin2bn(kbuf,kout, shared_secret);
-        memset(kbuf, 0, klen);
-        xfree(kbuf);
-        
-        /* The GSS hash is identical to the DH one */
-        hash = kex_dh_hash(
-           kex->client_version_string,
-            kex->server_version_string,
-            buffer_ptr(&kex->my), buffer_len(&kex->my),
-            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
-            serverhostkey, slen, /* server host key */
-            dh->pub_key,       /* e */
-            dh_server_pub,     /* f */
-            shared_secret      /* K */
-        );
-        
-        gssbuf.value=hash;
-        gssbuf.length=20;
-        
-        /* Verify that H matches the token we just got. */
-                if ((maj_status = gss_verify_mic(&min_status,
-                                        ctxt->context,
-                                        &gssbuf,
-                                        &msg_tok,
-                                        NULL))) {
+       if (!dh_pub_is_valid(dh, dh_server_pub))
+               packet_disconnect("bad server public DH value");
 
-               packet_disconnect("Hash's MIC didn't verify");
-       }       
-        
-        DH_free(dh);
-               ssh_gssapi_delete_ctx(&ctxt);
-        /* save session id */
-        if (kex->session_id == NULL) {
-               kex->session_id_len = 20;
-               kex->session_id = xmalloc(kex->session_id_len);
-               memcpy(kex->session_id, hash, kex->session_id_len);
+       /* compute K=f^x mod p */
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen);
+       kout = DH_compute_key(kbuf, dh_server_pub, dh);
+
+       shared_secret = BN_new();
+       BN_bin2bn(kbuf,kout, shared_secret);
+       memset(kbuf, 0, klen);
+       xfree(kbuf);
+
+       if (gex) {
+               hash = kexgex_hash( kex->client_version_string,
+                   kex->server_version_string,
+                   buffer_ptr(&kex->my), buffer_len(&kex->my),
+                   buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+                   serverhostkey, slen,
+                   min, nbits, max,
+                   dh->p, dh->g,
+                   dh->pub_key,
+                   dh_server_pub,
+                   shared_secret
+               );
+       } else {
+               /* The GSS hash is identical to the DH one */
+               hash = kex_dh_hash( kex->client_version_string, 
+                   kex->server_version_string,
+                   buffer_ptr(&kex->my), buffer_len(&kex->my),
+                   buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+                   serverhostkey, slen, /* server host key */
+                   dh->pub_key,        /* e */
+                   dh_server_pub,      /* f */
+                   shared_secret       /* K */
+               );
         }
-        
+
+       gssbuf.value = hash;
+       gssbuf.length = 20;
+
+        /* Verify that the hash matches the MIC we just got. */
+       if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok)))
+               packet_disconnect("Hash's MIC didn't verify");
+
+       xfree(msg_tok.value);
+
+       DH_free(dh);
+       if (serverhostkey)
+               xfree(serverhostkey);
+       BN_clear_free(dh_server_pub);
+
+       /* save session id */
+       if (kex->session_id == NULL) {
+               kex->session_id_len = 20;
+               kex->session_id = xmalloc(kex->session_id_len);
+               memcpy(kex->session_id, hash, kex->session_id_len);
+       }
+
+       if (gss_kex_context == NULL)
+               gss_kex_context = ctxt;
+       else
+               ssh_gssapi_delete_ctx(&ctxt);
+
        kex_derive_keys(kex, hash, shared_secret);
        BN_clear_free(shared_secret);
-        kex_finish(kex);
+       kex_finish(kex);
 }
 
 #endif /* GSSAPI */
index c4e0e9d225efbb333b92e0505281eb3ae5219bb3..52e46e8e25b835a62cb37586e59eba842605c31b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2005 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -47,168 +47,209 @@ kexgss_server(Kex *kex)
 {
        OM_uint32 maj_status, min_status;
        
-       /* Some GSSAPI implementations use the input value of ret_flags (an
+       /* 
+        * Some GSSAPI implementations use the input value of ret_flags (an
         * output variable) as a means of triggering mechanism specific 
         * features. Initializing it to zero avoids inadvertently 
-        * activating this non-standard behaviour.*/
+        * activating this non-standard behaviour.
+        */
 
        OM_uint32 ret_flags = 0;
-       gss_buffer_desc gssbuf,send_tok,recv_tok,msg_tok;
+       gss_buffer_desc gssbuf, recv_tok, msg_tok;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
        Gssctxt *ctxt = NULL;
-        unsigned int klen, kout;
-        unsigned char *kbuf;
-        unsigned char *hash;
-        DH *dh;
-        BIGNUM *shared_secret = NULL;
-        BIGNUM *dh_client_pub = NULL;
-       int type =0;
+       unsigned int klen, kout;
+       unsigned char *kbuf, *hash;
+       DH *dh;
+       int min = -1, max = -1, nbits = -1;
+       BIGNUM *shared_secret = NULL;
+       BIGNUM *dh_client_pub = NULL;
+       int type = 0;
+       int gex;
        u_int slen;
        gss_OID oid;
        
        /* Initialise GSSAPI */
 
-       debug2("%s: Identifying %s",__func__,kex->name);
-       oid=ssh_gssapi_server_id_kex(kex->name);
-       if (oid==NULL) {
-          packet_disconnect("Unknown gssapi mechanism");
-       }
-       
-       debug2("%s: Acquiring credentials",__func__);
-       
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid)))) {
+       /* If we're rekeying, privsep means that some of the private structures
+        * in the GSSAPI code are no longer available. This kludges them back
+         * into life
+        */
+       if (!ssh_gssapi_oid_table_ok()) 
+               ssh_gssapi_server_mechanisms();
+
+       debug2("%s: Identifying %s", __func__, kex->name);
+       oid = ssh_gssapi_id_kex(NULL, kex->name, &gex);
+       if (oid == NULL)
+          fatal("Unknown gssapi mechanism");
+
+       debug2("%s: Acquiring credentials", __func__);
+
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) {
                kex_gss_send_error(ctxt);
-               packet_disconnect("Unable to acquire credentials for the server");
-        }
-                                                                                                                                
+               fatal("Unable to acquire credentials for the server");
+       }
+
+       if (gex) {
+               debug("Doing group exchange");
+               packet_read_expect(SSH2_MSG_KEXGSS_GROUPREQ);
+               min = packet_get_int();
+               nbits = packet_get_int();
+               max = packet_get_int();
+               min = MAX(DH_GRP_MIN, min);
+               max = MIN(DH_GRP_MAX, max);
+               packet_check_eom();
+               if (max < min || nbits < min || max < nbits)
+                       fatal("GSS_GEX, bad parameters: %d !< %d !< %d",
+                           min, nbits, max);
+               dh = PRIVSEP(choose_dh(min, nbits, max));
+               if (dh == NULL)
+                       packet_disconnect("Protocol error: no matching group found");
+
+               packet_start(SSH2_MSG_KEXGSS_GROUP);
+               packet_put_bignum2(dh->p);
+               packet_put_bignum2(dh->g);
+               packet_send();
+
+               packet_write_wait();
+               
+       } else {
+               dh = dh_new_group1();
+       }
+       dh_gen_key(dh, kex->we_need * 8);
+
        do {
                debug("Wait SSH2_MSG_GSSAPI_INIT");
                type = packet_read();
                switch(type) {
                case SSH2_MSG_KEXGSS_INIT:
-                       if (dh_client_pub!=NULL) 
-                               packet_disconnect("Received KEXGSS_INIT after initialising");
-                       recv_tok.value=packet_get_string(&slen);
-                       recv_tok.length=slen; /* int vs. size_t */
-
-                       dh_client_pub = BN_new();
-                       
-                       if (dh_client_pub == NULL)
-                               packet_disconnect("dh_client_pub == NULL");
-                       packet_get_bignum2(dh_client_pub);
-                       
-                       /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
+                       if (dh_client_pub != NULL) 
+                               fatal("Received KEXGSS_INIT after initialising");
+                       recv_tok.value = packet_get_string(&slen);
+                       recv_tok.length = slen; 
+
+                       if ((dh_client_pub = BN_new()) == NULL)
+                               fatal("dh_client_pub == NULL");
+
+                       packet_get_bignum2(dh_client_pub);
+
+                       /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */
                        break;
                case SSH2_MSG_KEXGSS_CONTINUE:
-                       recv_tok.value=packet_get_string(&slen);
-                       recv_tok.length=slen; /* int vs. size_t */
+                       recv_tok.value = packet_get_string(&slen);
+                       recv_tok.length = slen; 
                        break;
                default:
-                       packet_disconnect("Protocol error: didn't expect packet type %d",
-                                          type);
+                       packet_disconnect(
+                           "Protocol error: didn't expect packet type %d",
+                           type);
                }
-               
-               maj_status=PRIVSEP(ssh_gssapi_accept_ctx(ctxt,&recv_tok, 
-                                                        &send_tok, &ret_flags));
 
-               gss_release_buffer(&min_status,&recv_tok);
-               
+               maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, 
+                   &send_tok, &ret_flags));
+
+               xfree(recv_tok.value);
+
+               if (maj_status != GSS_S_COMPLETE && send_tok.length == 0)
+                       fatal("Zero length token output when incomplete");
+
                if (dh_client_pub == NULL)
                        fatal("No client public key");
                
                if (maj_status & GSS_S_CONTINUE_NEEDED) {
                        debug("Sending GSSAPI_CONTINUE");
                        packet_start(SSH2_MSG_KEXGSS_CONTINUE);
-                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_put_string(send_tok.value, send_tok.length);
                        packet_send();
-                       packet_write_wait();
                        gss_release_buffer(&min_status, &send_tok);
                }
        } while (maj_status & GSS_S_CONTINUE_NEEDED);
 
        if (GSS_ERROR(maj_status)) {
                kex_gss_send_error(ctxt);
-               if (send_tok.length>0) {
+               if (send_tok.length > 0) {
                        packet_start(SSH2_MSG_KEXGSS_CONTINUE);
-                       packet_put_string(send_tok.value,send_tok.length);
+                       packet_put_string(send_tok.value, send_tok.length);
                        packet_send();
-                       packet_write_wait();
-               }       
-               packet_disconnect("gssapi key exchange handshake failed");
+               }
+               packet_disconnect("GSSAPI Key Exchange handshake failed");
        }
-       
-       debug("gss_complete");
+
        if (!(ret_flags & GSS_C_MUTUAL_FLAG))
-               packet_disconnect("gssapi_mutual authentication failed");
-               
+               fatal("Mutual Authentication flag wasn't set");
+
        if (!(ret_flags & GSS_C_INTEG_FLAG))
-               packet_disconnect("gssapi channel integrity not established");
-                       
-       dh = dh_new_group1();
-       dh_gen_key(dh, kex->we_need * 8);
+               fatal("Integrity flag wasn't set");
        
-        if (!dh_pub_is_valid(dh, dh_client_pub))
-                packet_disconnect("bad client public DH value");
+       if (!dh_pub_is_valid(dh, dh_client_pub))
+               packet_disconnect("bad client public DH value");
 
-        klen = DH_size(dh);
-        kbuf = xmalloc(klen); 
-        kout = DH_compute_key(kbuf, dh_client_pub, dh);
+       klen = DH_size(dh);
+       kbuf = xmalloc(klen); 
+       kout = DH_compute_key(kbuf, dh_client_pub, dh);
 
        shared_secret = BN_new();
        BN_bin2bn(kbuf, kout, shared_secret);
        memset(kbuf, 0, klen);
        xfree(kbuf);
-       
-       /* The GSSAPI hash is identical to the Diffie Helman one */
-        hash = kex_dh_hash(
-            kex->client_version_string,
-            kex->server_version_string,
-            buffer_ptr(&kex->peer), buffer_len(&kex->peer),
-            buffer_ptr(&kex->my), buffer_len(&kex->my),
-            NULL, 0, /* Change this if we start sending host keys */
-            dh_client_pub,
-            dh->pub_key,
-            shared_secret
-       );
+
+       if (gex) {
+               hash = kexgex_hash(
+                   kex->client_version_string, kex->server_version_string,
+                   buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+                   buffer_ptr(&kex->my), buffer_len(&kex->my),
+                   NULL, 0,
+                   min, nbits, max,
+                   dh->p, dh->g,
+                   dh_client_pub,
+                   dh->pub_key,
+                   shared_secret
+               );
+       }
+       else {  
+               /* The GSSAPI hash is identical to the Diffie Helman one */
+               hash = kex_dh_hash(
+                   kex->client_version_string, kex->server_version_string,
+                   buffer_ptr(&kex->peer), buffer_len(&kex->peer),
+                   buffer_ptr(&kex->my), buffer_len(&kex->my),
+                   NULL, 0, /* Change this if we start sending host keys */
+                   dh_client_pub, dh->pub_key, shared_secret
+               );
+       }
        BN_free(dh_client_pub);
-               
+
        if (kex->session_id == NULL) {
                kex->session_id_len = 20;
                kex->session_id = xmalloc(kex->session_id_len);
                memcpy(kex->session_id, hash, kex->session_id_len);
        }
-                               
+
        gssbuf.value = hash;
        gssbuf.length = 20; /* Hashlen appears to always be 20 */
-       
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
-               kex_gss_send_error(ctxt);
+
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok))))
                fatal("Couldn't get MIC");
-       }
-       
+
        packet_start(SSH2_MSG_KEXGSS_COMPLETE);
        packet_put_bignum2(dh->pub_key);
        packet_put_string((char *)msg_tok.value,msg_tok.length);
 
-       if (send_tok.length!=0) {
+       if (send_tok.length != 0) {
                packet_put_char(1); /* true */
-               packet_put_string((char *)send_tok.value,send_tok.length);
+               packet_put_string((char *)send_tok.value, send_tok.length);
        } else {
                packet_put_char(0); /* false */
        }
-       packet_send();
-       packet_write_wait();
-
-        /* We used to store the client name and credentials here for later
-         * use. With privsep, its easier to do this as a by product of the
-         * call to accept_context, which stores delegated information when
-         * the context is complete */
-         
-       gss_release_buffer(&min_status, &send_tok);     
-
-       /* If we've got a context, delete it. It may be NULL if we've been
-        * using privsep */
-       ssh_gssapi_delete_ctx(&ctxt);
-       
+       packet_send();
+
+       gss_release_buffer(&min_status, &send_tok);
+       gss_release_buffer(&min_status, &msg_tok);
+
+       if (gss_kex_context == NULL)
+               gss_kex_context = ctxt;
+       else 
+               ssh_gssapi_delete_ctx(&ctxt);
+
        DH_free(dh);
 
        kex_derive_keys(kex, hash, shared_secret);
index ea871129fa93a510b09671d3f79a5a94c8ce7fd3..239a35919536d8234fbd98d03e056f5e99efc39a 100644 (file)
@@ -650,7 +650,7 @@ key_type_from_name(char *name)
                return KEY_RSA;
        } else if (strcmp(name, "ssh-dss") == 0) {
                return KEY_DSA;
-       } else if (strcmp(name, "null") == 0){
+       } else if (strcmp(name, "null") == 0) {
                return KEY_NULL;
        }
        debug2("key_type_from_name: unknown key type '%s'", name);
index 7a6e4632d08429cadb761fa37a300191d1cf5f76..346bbd23047d7dc13307277090554f16b8a72c6d 100644 (file)
@@ -141,12 +141,6 @@ int mm_answer_gss_setup_ctx(int, Buffer *);
 int mm_answer_gss_accept_ctx(int, Buffer *);
 int mm_answer_gss_userok(int, Buffer *);
 int mm_answer_gss_checkmic(int, Buffer *);
-#endif
-
-#ifdef GSSAPI
-int mm_answer_gss_setup_ctx(int, Buffer *);
-int mm_answer_gss_accept_ctx(int, Buffer *);
-int mm_answer_gss_userok(int, Buffer *);
 int mm_answer_gss_sign(int, Buffer *);
 int mm_answer_gss_error(int, Buffer *);
 int mm_answer_gss_indicate_mechs(int, Buffer *);
@@ -218,11 +212,11 @@ struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx},
     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
+    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
     {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
     {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
     {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname},
-    {MONITOR_REQ_GSSCHECKMIC, MON_ISAUTH, mm_answer_gss_checkmic},
 #endif
     {0, 0, NULL}
 };
@@ -1668,6 +1662,7 @@ mm_get_kex(Buffer *m)
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
 #ifdef GSSAPI
        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+       kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
 #endif
        kex->server = 1;
        kex->hostkey_type = buffer_get_int(m);
@@ -1912,6 +1907,7 @@ mm_answer_gss_accept_ctx(int sock, Buffer *m)
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
        }
        return (0);
 }
@@ -1963,40 +1959,41 @@ mm_answer_gss_userok(int sock, Buffer *m)
        return (authenticated);
 }
 
-int
-mm_answer_gss_sign(int socket, Buffer *m) {
-        gss_buffer_desc data,hash;
-        OM_uint32 major,minor;
+int 
+mm_answer_gss_sign(int socket, Buffer *m)
+{
+       gss_buffer_desc data;
+       gss_buffer_desc hash = GSS_C_EMPTY_BUFFER;
+       OM_uint32 major, minor;
        u_int len;
 
-        data.value = buffer_get_string(m, &len);
+       data.value = buffer_get_string(m, &len);
        data.length = len;
-        if (data.length != 20)
-               fatal("%s: data length incorrect: %d", __func__,
-                     (int)data.length);
+       if (data.length != 20) 
+               fatal("%s: data length incorrect: %d", __func__, data.length);
 
-        /* Save the session ID - only first time round */
-        if (session_id2_len == 0) {
-                session_id2_len=data.length;
-                session_id2 = xmalloc(session_id2_len);
-                memcpy(session_id2, data.value, session_id2_len);
-        }
-        major=ssh_gssapi_sign(gsscontext, &data, &hash);
+       /* Save the session ID on the first time around */
+       if (session_id2_len == 0) {
+               session_id2_len = data.length;
+               session_id2 = xmalloc(session_id2_len);
+               memcpy(session_id2, data.value, session_id2_len);
+       }
+       major = ssh_gssapi_sign(gsscontext, &data, &hash);
 
-        xfree(data.value);
+       xfree(data.value);
 
-        buffer_clear(m);
-        buffer_put_int(m, major);
-        buffer_put_string(m, hash.value, hash.length);
+       buffer_clear(m);
+       buffer_put_int(m, major);
+       buffer_put_string(m, hash.value, hash.length);
 
-        mm_request_send(socket,MONITOR_ANS_GSSSIGN,m);
+       mm_request_send(socket, MONITOR_ANS_GSSSIGN, m);
 
-        gss_release_buffer(&minor,&hash);
+       gss_release_buffer(&minor, &hash);
 
-       /* Turn on permissions for getpwnam */
+       /* Turn on getpwnam permissions */
        monitor_permit(mon_dispatch, MONITOR_REQ_PWNAM, 1);
-       
-        return(0);
+
+       return (0);
 }
 
 int
@@ -2062,4 +2059,5 @@ mm_answer_gss_localname(int socket, Buffer *m) {
 
         return(0);
 }
+
 #endif /* GSSAPI */
index cfce700aae617ad653bc01036a42d1e35207b064..cb92f141fd78bb7b3b445bc1e6474750cac7d15d 100644 (file)
@@ -52,11 +52,11 @@ enum monitor_reqtype {
        MONITOR_REQ_GSSSETUP, MONITOR_ANS_GSSSETUP,
        MONITOR_REQ_GSSSTEP, MONITOR_ANS_GSSSTEP,
        MONITOR_REQ_GSSUSEROK, MONITOR_ANS_GSSUSEROK,
-       MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
        MONITOR_REQ_GSSMECHS, MONITOR_ANS_GSSMECHS,
        MONITOR_REQ_GSSLOCALNAME, MONITOR_ANS_GSSLOCALNAME,
        MONITOR_REQ_GSSERR, MONITOR_ANS_GSSERR,
        MONITOR_REQ_GSSCHECKMIC, MONITOR_ANS_GSSCHECKMIC,
+       MONITOR_REQ_GSSSIGN, MONITOR_ANS_GSSSIGN,
        MONITOR_REQ_PAM_START,
        MONITOR_REQ_PAM_ACCOUNT, MONITOR_ANS_PAM_ACCOUNT,
        MONITOR_REQ_PAM_INIT_CTX, MONITOR_ANS_PAM_INIT_CTX,
index 6768a67cbaf417836c57d3f97145282ec3493cd7..83f7b2cd0c6f4e8a83f8d4d40eaf24678227f358 100644 (file)
@@ -1218,24 +1218,25 @@ mm_ssh_gssapi_userok(char *user)
 }
 
 OM_uint32
-mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
-        Buffer m;
-        OM_uint32 major;
+mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash)
+{
+       Buffer m;
+       OM_uint32 major;
        u_int len;
 
-        buffer_init(&m);
-        buffer_put_string(&m, data->value, data->length);
+       buffer_init(&m);
+       buffer_put_string(&m, data->value, data->length);
 
-        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
-        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
 
-        major=buffer_get_int(&m);
-        hash->value = buffer_get_string(&m, &len);
+       major = buffer_get_int(&m);
+       hash->value = buffer_get_string(&m, &len);
        hash->length = len;
 
        buffer_free(&m);
-       
-        return(major);
+
+       return(major);
 }
 
 char *
@@ -1314,4 +1315,5 @@ mm_ssh_gssapi_localname(char **lname)
        
         return(0);
 }      
+
 #endif /* GSSAPI */
index dfc995faeb983f347cc06f70813e88fc5dba10dd..ab05333c9549cc345c4f954e1a8b429ccd14c64e 100644 (file)
@@ -63,8 +63,7 @@ OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *,
    gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *);
 int mm_ssh_gssapi_userok(char *user);
 OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
-OM_uint32 mm_ssh_gssapi_sign(Gssctxt *ctxt, gss_buffer_desc *buffer,
-                            gss_buffer_desc *hash);
+OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
 int mm_ssh_gssapi_localname(char **user);
 OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
                                gss_OID_set *mech_set);
index c4b542da72f7b702fac819bf0648990956d58366..a9265616e82e8b09e9729cdfc0c5676c5996d11c 100644 (file)
@@ -105,6 +105,7 @@ typedef enum {
        oClearAllForwardings, oNoHostAuthenticationForLocalhost,
        oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
        oAddressFamily, oGssAuthentication, oGssKeyEx, oGssDelegateCreds,
+       oGssTrustDns,
        oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
        oSendEnv, oControlPath, oControlMaster, oHashKnownHosts,
        oDeprecated, oUnsupported
@@ -141,10 +142,12 @@ static struct {
        { "gssapiauthentication", oGssAuthentication },
        { "gssapikeyexchange", oGssKeyEx },
        { "gssapidelegatecredentials", oGssDelegateCreds },
+       { "gssapitrustdns", oGssTrustDns },
 #else
        { "gssapiauthentication", oUnsupported },
        { "gssapikeyexchange", oUnsupported },
        { "gssapidelegatecredentials", oUnsupported },
+       { "gssapitrustdns", oUnsupported },
 #endif
        { "fallbacktorsh", oDeprecated },
        { "usersh", oDeprecated },
@@ -416,6 +419,10 @@ parse_flag:
                intptr = &options->gss_deleg_creds;
                goto parse_flag;
 
+       case oGssTrustDns:
+               intptr = &options->gss_trust_dns;
+               goto parse_flag;
+
        case oBatchMode:
                intptr = &options->batch_mode;
                goto parse_flag;
@@ -924,6 +931,7 @@ initialize_options(Options * options)
        options->gss_authentication = -1;
        options->gss_keyex = -1;
        options->gss_deleg_creds = -1;
+       options->gss_trust_dns = -1;
        options->password_authentication = -1;
        options->kbd_interactive_authentication = -1;
        options->kbd_interactive_devices = NULL;
@@ -1009,6 +1017,8 @@ fill_default_options(Options * options)
                options->gss_keyex = 1;
        if (options->gss_deleg_creds == -1)
                options->gss_deleg_creds = 1;
+       if (options->gss_trust_dns == -1)
+               options->gss_trust_dns = 1;
        if (options->password_authentication == -1)
                options->password_authentication = 1;
        if (options->kbd_interactive_authentication == -1)
index ee981ab1549b24fccb90aa6dc05ef82a36ac5c32..991e9b5e59ffc42362a60652cf3fb4c111174f62 100644 (file)
@@ -47,6 +47,7 @@ typedef struct {
        int     gss_authentication;     /* Try GSS authentication */
        int     gss_keyex;
        int     gss_deleg_creds;        /* Delegate GSS credentials */
+       int     gss_trust_dns;          /* Trust DNS for GSS canonicalization */
        int     password_authentication;        /* Try password
                                                 * authentication. */
        int     kbd_interactive_authentication; /* Try keyboard-interactive auth. */
index 59bb58b49ca43415048929fde58153a8c01d731c..ece97dc8c24f3e4a8709c08310c6f318a360e621 100644 (file)
@@ -77,7 +77,7 @@ initialize_server_options(ServerOptions *options)
 #endif
        options->kerberos_get_afs_token = -1;
        options->gss_authentication=-1;
-       options->gss_keyex=-1;
+       options->gss_keyex = -1;
        options->gss_cleanup_creds = -1;
        options->password_authentication = -1;
        options->kbd_interactive_authentication = -1;
@@ -281,8 +281,7 @@ typedef enum {
        sBanner, sUseDNS, sHostbasedAuthentication,
        sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
        sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
-       sGssAuthentication, sGssCleanupCreds, sAcceptEnv,
-       sGssKeyEx, 
+       sGssAuthentication, sGssKeyEx, sGssCleanupCreds, sAcceptEnv,
        sUsePrivilegeSeparation,
        sDeprecated, sUnsupported
 } ServerOpCodes;
index 0a57e1cc039eb9dcc312a7ef0e5b19c573ccdda4..1750622a84672865219b42e846f8c1a369e0ec26 100644 (file)
@@ -93,7 +93,7 @@ typedef struct {
        int     kerberos_get_afs_token;         /* If true, try to get AFS token if
                                                 * authenticated with Kerberos. */
        int     gss_authentication;     /* If true, permit GSSAPI authentication */
-       int     gss_keyex;              /* If true, permit GSSAPI key exchange. */
+       int     gss_keyex;              /* If true, permit GSSAPI key exchange */
        int     gss_cleanup_creds;      /* If true, destroy cred cache on logout */
        int     password_authentication;        /* If true, permit password
                                                 * authentication. */
index 7ae4a8eccd9aabbbb2beb9b5a2d9c06ad5a08b5c..9de20974ba9e42456fe6115d4ba7d01e7f54a4a8 100644 (file)
@@ -706,14 +706,6 @@ do_exec(Session *s, const char *command)
        }
 #endif
 
-#ifdef GSSAPI
-       if (options.gss_authentication) {
-               temporarily_use_uid(s->pw);
-               ssh_gssapi_storecreds();
-               restore_uid();
-       }
-#endif
-
 #ifdef SSH_AUDIT_EVENTS
        if (command != NULL)
                PRIVSEP(audit_run_command(command));
index 165e733e810fa1671218c481c184e11ca5bba202..12f40c5666c9652ea2f7f04b0630f3fb4605bfa4 100644 (file)
 #endif /* !MECHGLUE */
 
 /* draft-ietf-secsh-gsskeyex-06 */
-#define SSH2_MSG_KEXGSS_INIT                           30
-#define SSH2_MSG_KEXGSS_CONTINUE                       31
-#define SSH2_MSG_KEXGSS_COMPLETE                       32
-#define SSH2_MSG_KEXGSS_HOSTKEY                                33
-#define SSH2_MSG_KEXGSS_ERROR                          34
 #define SSH2_MSG_USERAUTH_GSSAPI_RESPONSE              60
 #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN                 61
 #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE     63
 
 #define SSH_GSS_OIDTYPE 0x06
 
-#define KEX_GSS_SHA1                                   "gss-group1-sha1-"
+#define SSH2_MSG_KEXGSS_INIT                           30
+#define SSH2_MSG_KEXGSS_CONTINUE                       31
+#define SSH2_MSG_KEXGSS_COMPLETE                       32
+#define SSH2_MSG_KEXGSS_HOSTKEY                                33
+#define SSH2_MSG_KEXGSS_ERROR                          34
+#define SSH2_MSG_KEXGSS_GROUPREQ                       40
+#define SSH2_MSG_KEXGSS_GROUP                          41
+#define KEX_GSS_GRP1_SHA1_ID                           "gss-group1-sha1-"
+#define KEX_GSS_GEX_SHA1_ID                            "gss-gex-sha1-"
 
 typedef struct {
        char *filename;
@@ -109,9 +112,7 @@ typedef struct {
 } Gssctxt;
 
 extern ssh_gssapi_mech *supported_mechs[];
-
-char *ssh_gssapi_client_mechanisms(char *);
-gss_OID ssh_gssapi_client_id_kex(Gssctxt *, char *);
+extern Gssctxt *gss_kex_context;
 
 int  ssh_gssapi_check_oid(Gssctxt *, void *, size_t);
 void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t);
@@ -134,18 +135,22 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t);
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID);
 void ssh_gssapi_buildmic(Buffer *, const char *, const char *, const char *);
 
-int ssh_gssapi_check_mechanism(gss_OID oid, const char *host);
-
-/* In the server */
-char *ssh_gssapi_server_mechanisms();
-gss_OID ssh_gssapi_server_id_kex(char *name);
 int ssh_gssapi_localname(char **name);
 
+typedef int ssh_gssapi_check_fn(gss_OID, void *);
+char *ssh_gssapi_client_mechanisms(const char *host);
+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, void *);
+int ssh_gssapi_check_mechanism(gss_OID, void *);
+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int *);
+
+int ssh_gssapi_server_check_mech(gss_OID, void *);
 int ssh_gssapi_userok(char *name);
 OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t);
 void ssh_gssapi_do_child(char ***, u_int *);
 void ssh_gssapi_cleanup_creds(void);
 void ssh_gssapi_storecreds(void);
+char * ssh_gssapi_server_mechanisms(void);
+int ssh_gssapi_oid_table_ok();
 
 #ifdef MECHGLUE
 gss_cred_id_t __gss_get_mechanism_cred
index 571987329094233b565b12e6b11b30ccbb978fa7..9d37d584c465aedc32fcf6e0d5521be5a9ceaba5 100644 (file)
@@ -459,6 +459,16 @@ Forward (delegate) credentials to the server.
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
+.It Cm GSSAPITrustDns
+Set to 
+.Dq yes to indicate that the DNS is trusted to securely canonicalize
+the name of the host being connected to. If 
+.Dq no, the hostname entered on the
+command line will be passed untouched to the GSSAPI library.
+The default is
+.Dq yes .
+This option only applies to protocol version 2 connections using GSSAPI 
+key exchange.
 .It Cm HashKnownHosts
 Indicates that
 .Nm ssh
@@ -624,7 +634,7 @@ This allows a client to prefer one method (e.g.\&
 over another method (e.g.\&
 .Cm password )
 The default for this option is:
-.Dq hostbased,external-keyx,gssapi-with-mic,gssapi,publickey,keyboard-interactive,password .
+.Dq publickey,gssapi-keyex,external-keyx,gssapi-with-mic,gssapi,password,keyboard-interactive .
 .It Cm Protocol
 Specifies the protocol versions
 .Nm ssh
index 22685062c78fc16c7de3330954ba8b8a2876937f..a0d88eb2b77c3a1e6cd0cd5c1a92c594b6b6b904 100644 (file)
@@ -83,9 +83,11 @@ void
 ssh_kex2(char *host, struct sockaddr *hostaddr)
 {
        Kex *kex;
+
 #ifdef GSSAPI
-       char *orig=NULL, *gss=NULL;
+       char *orig = NULL, *gss = NULL;
        int len;
+        char *gss_host = NULL;
 #endif
 
        xxx_host = host;
@@ -96,11 +98,18 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        /* Add the GSSAPI mechanisms currently supported on this client to
         * the key exchange algorithm proposal */
        orig = myproposal[PROPOSAL_KEX_ALGS];
-       gss = ssh_gssapi_client_mechanisms((char *)get_canonical_hostname(1));
+       if (options.gss_trust_dns)
+               gss_host = (char *)get_canonical_hostname(1);
+       else
+               gss_host = host;
+
+       gss = ssh_gssapi_client_mechanisms(gss_host);
        if (gss) {
-          len = strlen(orig)+strlen(gss)+2;
-          myproposal[PROPOSAL_KEX_ALGS]=xmalloc(len);
-          snprintf(myproposal[PROPOSAL_KEX_ALGS],len,"%s,%s",gss,orig);
+               debug("Offering GSSAPI proposal: %s", gss);
+               len = strlen(orig) + strlen(gss) + 2;
+               myproposal[PROPOSAL_KEX_ALGS] = xmalloc(len);
+               snprintf(myproposal[PROPOSAL_KEX_ALGS], len, "%s,%s", gss, 
+                   orig);
        }
        }
 #endif
@@ -133,13 +142,14 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
                    options.hostkeyalgorithms;
 
 #ifdef GSSAPI
-        /* If we've got GSSAPI algorithms, then we also support the
-         * 'null' hostkey, as a last resort */
+       /* If we've got GSSAPI algorithms, then we also support the
+        * 'null' hostkey, as a last resort */
        if (options.gss_keyex && gss) {
-                orig=myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
-                len = strlen(orig)+sizeof(",null");
-                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]=xmalloc(len);
-                snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS],len,"%s,null",orig);
+               orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+               len = strlen(orig) + sizeof(",null");
+               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xmalloc(len);
+               snprintf(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], len, 
+                   "%s,null", orig);
        }
 #endif
 
@@ -153,6 +163,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
 #ifdef GSSAPI
        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
+       kex->kex[KEX_GSS_GEX_SHA1] = kexgss_client;
 #endif
        kex->client_version_string=client_version_string;
        kex->server_version_string=server_version_string;
@@ -161,6 +172,12 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        kex->options.gss_deleg_creds=options.gss_deleg_creds;
 #endif
 
+#ifdef GSSAPI
+       kex->gss_deleg_creds = options.gss_deleg_creds;
+       kex->gss_trust_dns = options.gss_trust_dns;
+       kex->gss_host = gss_host;
+#endif
+
        xxx_kex = kex;
 
        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -236,15 +253,6 @@ 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
-
 #ifdef GSSAPI
 int    userauth_external(Authctxt *authctxt);
 int    userauth_gssapi(Authctxt *authctxt);
@@ -255,6 +263,7 @@ 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 *);
+int    userauth_gsskeyex(Authctxt *authctxt);
 #endif
 
 void   userauth(Authctxt *, char *);
@@ -270,6 +279,10 @@ static char *authmethods_get(void);
 
 Authmethod authmethods[] = {
 #ifdef GSSAPI
+       {"gssapi-keyex",
+               userauth_gsskeyex,
+               &options.gss_authentication,
+               NULL},
        {"external-keyx",
                userauth_external,
                &options.gss_authentication,
@@ -540,12 +553,18 @@ userauth_gssapi(Authctxt *authctxt)
        static u_int mech = 0;
        OM_uint32 min;
        int ok = 0;
+       char *gss_host = NULL;
 
        if (!options.gss_authentication) {
                verbose("GSSAPI authentication disabled.");
                return 0;
        }
 
+       if (options.gss_trust_dns)
+               gss_host = (char *)get_canonical_hostname(1);
+       else
+               gss_host = (char *)authctxt->host;
+
        /* Try one GSSAPI method at a time, rather than sending them all at
         * once. */
 
@@ -562,9 +581,9 @@ userauth_gssapi(Authctxt *authctxt)
                /* My DER encoding requires length<128 */
                if (gss_supported->elements[mech].length < 128 &&
                    ssh_gssapi_check_mechanism(&gss_supported->elements[mech],
-                                              get_canonical_hostname(1)) &&
+                                              gss_host) &&
                    !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
-                                               get_canonical_hostname(1)))) {
+                                                     gss_host))) {
                        ok = 1; /* Mechanism works */
                } else {
                        mech++;
@@ -661,8 +680,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
 {
        Authctxt *authctxt = ctxt;
        Gssctxt *gssctxt;
-       int oidlen;
-       char *oidv;
+       unsigned int oidlen;
+       unsigned char *oidv;
 
        if (authctxt == NULL)
                fatal("input_gssapi_response: no authentication context");
@@ -770,6 +789,15 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
        xfree(lang);
 }
 
+#ifdef GSI
+extern
+const gss_OID_desc * const              gss_mech_globus_gssapi_openssl;
+#define is_gsi_oid(oid) \
+  (oid->length == gss_mech_globus_gssapi_openssl->length && \
+   (memcmp(oid->elements, gss_mech_globus_gssapi_openssl->elements, \
+          oid->length) == 0))
+#endif
+
 int
 userauth_external(Authctxt *authctxt)
 {
@@ -781,7 +809,7 @@ userauth_external(Authctxt *authctxt)
        /* The client MUST NOT try this method if initial key exchange
           was not performed using a GSSAPI-based key exchange
           method. */
-       if (xxx_kex->kex_type != KEX_GSS_GRP1_SHA1) {
+       if (gss_kex_context == NULL) {
                debug2("gsskex not performed, skipping external-keyx");
                return 0;
        }
@@ -789,11 +817,11 @@ userauth_external(Authctxt *authctxt)
         debug2("userauth_external");
         packet_start(SSH2_MSG_USERAUTH_REQUEST);
 #ifdef GSI
-        if(options.implicit) {
-           packet_put_cstring("");
+        if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
+       packet_put_cstring("");
        } else {
 #endif
-           packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->server_user);
 #ifdef GSI
        }
 #endif
@@ -803,6 +831,63 @@ userauth_external(Authctxt *authctxt)
         packet_write_wait();
         return 1;
 }                                                                                                
+int
+userauth_gsskeyex(Authctxt *authctxt)
+{
+       Buffer b;
+       gss_buffer_desc gssbuf;
+       gss_buffer_desc mic = GSS_C_EMPTY_BUFFER;
+       OM_uint32 ms;
+
+       static int attempt = 0;
+       if (attempt++ >= 1)
+               return (0);
+
+       if (gss_kex_context == NULL) {
+               debug("No valid Key exchange context"); 
+               return (0);
+       }
+
+#ifdef GSI
+        if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
+       ssh_gssapi_buildmic(&b, "", authctxt->service, "gssapi-keyex");
+       } else {
+#endif
+       ssh_gssapi_buildmic(&b, authctxt->server_user, authctxt->service,
+           "gssapi-keyex");
+#ifdef GSI
+       }
+#endif
+
+       gssbuf.value = buffer_ptr(&b);
+       gssbuf.length = buffer_len(&b);
+
+       if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) {
+               buffer_free(&b);
+               return (0);
+       }
+
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+#ifdef GSI
+        if (options.implicit && is_gsi_oid(gss_kex_context->oid)) {
+       packet_put_cstring("");
+       } else {
+#endif
+       packet_put_cstring(authctxt->server_user);
+#ifdef GSI
+       }
+#endif
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+       packet_put_string(mic.value, mic.length);
+       packet_send();
+
+       buffer_free(&b);
+       gss_release_buffer(&ms, &mic);
+
+       return (1);
+}
+
 #endif /* GSSAPI */
 
 int
index 9003c315a823e5884d3eb5baef80a9d535c6ff1c..5fd4b20b3898404a4efae35511c34d475f660d24 100644 (file)
@@ -86,15 +86,10 @@ RCSID("$OpenBSD: sshd.c,v 1.312 2005/07/25 11:59:40 markus Exp $");
 #include "monitor_wrap.h"
 #include "monitor_fdpass.h"
 
-#ifdef GSSAPI
-#include "ssh-gss.h"
+#ifdef USE_SECURITY_SESSION_API
+#include <Security/AuthSession.h>
 #endif
 
-#ifdef GSSAPI
-#include <openssl/md5.h>
-#include "bufaux.h"
-#endif /* GSSAPI */
-
 #ifdef LIBWRAP
 #include <tcpd.h>
 #include <syslog.h>
@@ -1675,6 +1670,62 @@ main(int ac, char **av)
        /* Log the connection. */
        verbose("Connection from %.500s port %d", remote_ip, remote_port);
 
+#ifdef USE_SECURITY_SESSION_API
+       /*
+        * Create a new security session for use by the new user login if
+        * the current session is the root session or we are not launched
+        * by inetd (eg: debugging mode or server mode).  We do not
+        * necessarily need to create a session if we are launched from
+        * inetd because Panther xinetd will create a session for us.
+        *
+        * The only case where this logic will fail is if there is an
+        * inetd running in a non-root session which is not creating
+        * new sessions for us.  Then all the users will end up in the
+        * same session (bad).
+        *
+        * When the client exits, the session will be destroyed for us
+        * automatically.
+        *
+        * We must create the session before any credentials are stored
+        * (including AFS pags, which happens a few lines below).
+        */
+       {
+               OSStatus err = 0;
+               SecuritySessionId sid = 0;
+               SessionAttributeBits sattrs = 0;
+
+               err = SessionGetInfo(callerSecuritySession, &sid, &sattrs);
+               if (err)
+                       error("SessionGetInfo() failed with error %.8X",
+                           (unsigned) err);
+               else
+                       debug("Current Session ID is %.8X / Session Attributes a
+re %.8X",
+                           (unsigned) sid, (unsigned) sattrs);
+
+               if (inetd_flag && !(sattrs & sessionIsRoot))
+                       debug("Running in inetd mode in a non-root session... "
+                           "assuming inetd created the session for us.");
+               else {
+                       debug("Creating new security session...");
+                       err = SessionCreate(0, sessionHasTTY | sessionIsRemote);
+                       if (err)
+                               error("SessionCreate() failed with error %.8X",
+                                   (unsigned) err);
+
+                       err = SessionGetInfo(callerSecuritySession, &sid, 
+                           &sattrs);
+                       if (err)
+                               error("SessionGetInfo() failed with error %.8X",
+                                   (unsigned) err);
+                       else
+                               debug("New Session ID is %.8X / Session Attribut
+es are %.8X",
+                                   (unsigned) sid, (unsigned) sattrs);
+               }
+       }
+#endif
+
        /*
         * We don\'t want to listen forever unless the other side
         * successfully authenticates itself.  So we set up an alarm which is
@@ -2024,56 +2075,64 @@ do_ssh2_kex(void)
        
        myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types();
 
+       /* start key exchange */
+  
 #ifdef GSSAPI
-       { 
+       {
        char *orig;
        char *gss = NULL;
        char *newstr = NULL;
-               orig = myproposal[PROPOSAL_KEX_ALGS];
-
-       /* If we don't have a host key, then all of the algorithms
-        * currently in myproposal are useless */
-       if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])==0)
-               orig= NULL;
-               
-        if (options.gss_keyex)
-               gss = ssh_gssapi_server_mechanisms();
-        else
-               gss = NULL;
-        
+       orig = myproposal[PROPOSAL_KEX_ALGS];
+
+       /* 
+        * If we don't have a host key, then there's no point advertising
+         * the other key exchange algorithms
+        */
+
+       if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0)
+               orig = NULL;
+
+       if (options.gss_keyex)
+               gss = ssh_gssapi_server_mechanisms();
+       else
+               gss = NULL;
+
        if (gss && orig) {
-               int len = strlen(orig) + strlen(gss) +2;
-               newstr=xmalloc(len);
-               snprintf(newstr,len,"%s,%s",gss,orig);
+               int len = strlen(orig) + strlen(gss) + 2;
+               newstr = xmalloc(len);
+               snprintf(newstr, len, "%s,%s", gss, orig);
        } else if (gss) {
-               newstr=gss;
+               newstr = gss;
        } else if (orig) {
-               newstr=orig;
-       }
-        /* If we've got GSSAPI mechanisms, then we've also got the 'null'
-          host key algorithm, but we're not allowed to advertise it, unless
-          its the only host key algorithm we're supporting */
-       if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) {
-               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]="null";
+               newstr = orig;
        }
+       /* 
+        * If we've got GSSAPI mechanisms, then we've got the 'null' host
+        * key alg, but we can't tell people about it unless its the only
+        * host key algorithm we support
+        */
+       if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0)
+               myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null";
+
        if (newstr)
-               myproposal[PROPOSAL_KEX_ALGS]=newstr;
+               myproposal[PROPOSAL_KEX_ALGS] = newstr;
        else
                fatal("No supported key exchange algorithms");
-        }
+       }
 #endif
 
-       /* start key exchange */
-       kex = kex_setup(myproposal);
-       kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
+       /* start key exchange */
+       kex = kex_setup(myproposal);
+       kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
        kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server;
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
 #ifdef GSSAPI
        kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server;
+       kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server;
 #endif
-       kex->server = 1;
-       kex->client_version_string=client_version_string;
-       kex->server_version_string=server_version_string;
+       kex->server = 1;
+       kex->client_version_string=client_version_string;
+       kex->server_version_string=server_version_string;
        kex->load_host_key=&get_hostkey_by_type;
        kex->host_key_index=&get_hostkey_index;
 
index da0da2d06f68dea66fe40bbd33b3b2c16b49c440..a9c59f440c98c75d47dcbe7d5ffef0e5ba57bead 100644 (file)
@@ -277,21 +277,15 @@ Specifies whether user authentication based on GSSAPI is allowed.
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
-.It Cm GSSAPICleanupCredentials
-Specifies whether to automatically destroy the user's credentials cache
-on logout.
-The default is
-.Dq yes .
-Note that this option applies to protocol version 2 only.
 .It Cm GSSAPIKeyExchange
-Specifies whether key exchange based on GSSAPI may be used. When using
-GSSAPI key exchange the server need not have a host key.
+Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange 
+doesn't rely on ssh keys to verify host identity.
 The default is
 .Dq yes .
 Note that this option applies to protocol version 2 only.
-.It Cm GSSAPIUseSessionCredCache
-Specifies whether a unique credentials cache name should be generated per
-session for storing delegated credentials.
+.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.
This page took 0.167194 seconds and 5 git commands to generate.