]> andersk Git - gssapi-openssh.git/blobdiff - openssh/sshconnect2.c
merged OpenSSH 5.3p1 to trunk
[gssapi-openssh.git] / openssh / sshconnect2.c
index a762eec3bdb4775e77f29f8902033f7e275d7cac..4744e377dc891ff54d5133b31d64e75fe4aef846 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.170 2008/11/04 08:22:13 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.171 2009/03/05 07:18:19 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -68,6 +68,7 @@
 #include "msg.h"
 #include "pathnames.h"
 #include "uidswap.h"
+#include "schnorr.h"
 #include "jpake.h"
 
 #ifdef GSSAPI
 extern char *client_version_string;
 extern char *server_version_string;
 extern Options options;
+extern Kex *xxx_kex;
+
+/* tty_flag is set in ssh.c. use this in ssh_userauth2 */
+/* if it is set then prevent the switch to the null cipher */
+
+extern int tty_flag;
+
+/* tty_flag is set in ssh.c. use this in ssh_userauth2 */
+/* if it is set then prevent the switch to the null cipher */
+
+extern int tty_flag;
+
+/* tty_flag is set in ssh.c. use this in ssh_userauth2 */
+/* if it is set then prevent the switch to the null cipher */
+
+extern int tty_flag;
 
 /*
  * SSH2 key exchange
@@ -104,9 +121,34 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
 {
        Kex *kex;
 
+#ifdef GSSAPI
+       char *orig = NULL, *gss = NULL;
+       char *gss_host = NULL;
+#endif
+
        xxx_host = host;
        xxx_hostaddr = hostaddr;
 
+#ifdef GSSAPI
+       if (options.gss_keyex) {
+               /* Add the GSSAPI mechanisms currently supported on this 
+                * client to the key exchange algorithm proposal */
+               orig = myproposal[PROPOSAL_KEX_ALGS];
+
+               if (options.gss_trust_dns)
+                       gss_host = (char *)get_canonical_hostname(1);
+               else
+                       gss_host = host;
+
+               gss = ssh_gssapi_client_mechanisms(gss_host, options.gss_client_identity);
+               if (gss) {
+                       debug("Offering GSSAPI proposal: %s", gss);
+                       xasprintf(&myproposal[PROPOSAL_KEX_ALGS],
+                           "%s,%s", gss, orig);
+               }
+       }
+#endif
+
        if (options.ciphers == (char *)-1) {
                logit("No valid ciphers for protocol version 2 given, using defaults.");
                options.ciphers = NULL;
@@ -134,6 +176,17 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
                myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
                    options.hostkeyalgorithms;
 
+#ifdef GSSAPI
+       /* If we've got GSSAPI algorithms, then we also support the
+        * 'null' hostkey, as a last resort */
+       if (options.gss_keyex && gss) {
+               orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS];
+               xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], 
+                   "%s,null", orig);
+               xfree(gss);
+       }
+#endif
+
        if (options.rekey_limit)
                packet_set_rekey_limit((u_int32_t)options.rekey_limit);
 
@@ -143,10 +196,26 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client;
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
        kex->kex[KEX_DH_GEX_SHA256] = kexgex_client;
+#ifdef GSSAPI
+       if (options.gss_keyex) {
+               kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
+               kex->kex[KEX_GSS_GRP14_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;
        kex->verify_host_key=&verify_host_key_callback;
 
+#ifdef GSSAPI
+       if (options.gss_keyex) {
+               kex->gss_deleg_creds = options.gss_deleg_creds;
+               kex->gss_trust_dns = options.gss_trust_dns;
+               kex->gss_client = options.gss_client_identity;
+               kex->gss_host = gss_host;
+       }
+#endif
+
        xxx_kex = kex;
 
        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -229,12 +298,16 @@ int       userauth_jpake(Authctxt *);
 void   userauth_jpake_cleanup(Authctxt *);
 
 #ifdef GSSAPI
+int    userauth_external(Authctxt *authctxt);
 int    userauth_gssapi(Authctxt *authctxt);
+int    userauth_gssapi_with_mic(Authctxt *authctxt);
+int    userauth_gssapi_without_mic(Authctxt *authctxt);
 void   input_gssapi_response(int type, u_int32_t, void *);
 void   input_gssapi_token(int type, u_int32_t, void *);
 void   input_gssapi_hash(int type, u_int32_t, void *);
 void   input_gssapi_error(int, u_int32_t, void *);
 void   input_gssapi_errtok(int, u_int32_t, void *);
+int    userauth_gsskeyex(Authctxt *authctxt);
 #endif
 
 void   userauth(Authctxt *, char *);
@@ -250,11 +323,26 @@ static char *authmethods_get(void);
 
 Authmethod authmethods[] = {
 #ifdef GSSAPI
+       {"gssapi-keyex",
+               userauth_gsskeyex,
+               NULL,
+               &options.gss_authentication,
+               NULL},
+       {"external-keyx",
+               userauth_external,
+               NULL,
+               &options.gss_authentication,
+               NULL},
        {"gssapi-with-mic",
                userauth_gssapi,
                NULL,
                &options.gss_authentication,
                NULL},
+       {"gssapi",
+               userauth_gssapi,
+               NULL,
+               &options.gss_authentication,
+               NULL},
 #endif
        {"hostbased",
                userauth_hostbased,
@@ -350,6 +438,28 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
        pubkey_cleanup(&authctxt);
        dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
 
+       /* if the user wants to use the none cipher do it */
+       /* post authentication and only if the right conditions are met */
+       /* both of the NONE commands must be true and there must be no */
+       /* tty allocated */
+       if ((options.none_switch == 1) && (options.none_enabled == 1)) 
+       {
+               if (!tty_flag) /* no null on tty sessions */
+               {
+                       debug("Requesting none rekeying...");
+                       myproposal[PROPOSAL_ENC_ALGS_STOC] = "none";
+                       myproposal[PROPOSAL_ENC_ALGS_CTOS] = "none";
+                       kex_prop2buf(&xxx_kex->my,myproposal);
+                       packet_request_rekeying();
+                       fprintf(stderr, "WARNING: ENABLED NONE CIPHER\n");
+               }
+               else
+               {
+                       /* requested NONE cipher when in a tty */
+                       debug("Cannot switch to NONE cipher with tty allocated");
+                       fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n");
+               }
+       }
        debug("Authentication succeeded (%s).", authctxt.method->name);
 }
 
@@ -541,19 +651,34 @@ 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. */
 
        if (gss_supported == NULL)
-               gss_indicate_mechs(&min, &gss_supported);
+               if (GSS_ERROR(gss_indicate_mechs(&min, &gss_supported))) {
+                       gss_supported = NULL;
+                       return 0;
+               }
 
        /* Check to see if the mechanism is usable before we offer it */
        while (mech < gss_supported->count && !ok) {
                /* My DER encoding requires length<128 */
                if (gss_supported->elements[mech].length < 128 &&
                    ssh_gssapi_check_mechanism(&gssctxt, 
-                   &gss_supported->elements[mech], authctxt->host)) {
+                   &gss_supported->elements[mech], gss_host, 
+                    options.gss_client_identity)) {
                        ok = 1; /* Mechanism works */
                } else {
                        mech++;
@@ -617,7 +742,8 @@ process_gssapi_token(void *ctxt, gss_buffer_t recv_tok)
 
        if (status == GSS_S_COMPLETE) {
                /* send either complete or MIC, depending on mechanism */
-               if (!(flags & GSS_C_INTEG_FLAG)) {
+               if (strcmp(authctxt->method->name,"gssapi")==0 ||
+                   (!(flags & GSS_C_INTEG_FLAG))) {
                        packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
                        packet_send();
                } else {
@@ -650,8 +776,8 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
 {
        Authctxt *authctxt = ctxt;
        Gssctxt *gssctxt;
-       int oidlen;
-       char *oidv;
+       u_int oidlen;
+       u_char *oidv;
 
        if (authctxt == NULL)
                fatal("input_gssapi_response: no authentication context");
@@ -761,6 +887,106 @@ input_gssapi_error(int type, u_int32_t plen, void *ctxt)
        xfree(msg);
        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)
+{
+    static int attempt = 0;
+        
+    if (attempt++ >= 1)
+        return 0;
+                                
+       /* The client MUST NOT try this method if initial key exchange
+          was not performed using a GSSAPI-based key exchange
+          method. */
+       if (gss_kex_context == NULL) {
+               debug2("gsskex not performed, skipping external-keyx");
+               return 0;
+       }
+
+    debug2("userauth_external");
+    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_send();
+    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
This page took 0.043055 seconds and 4 git commands to generate.