]> andersk Git - gssapi-openssh.git/commitdiff
merge of OPENSSH_3_6_1P1_SIMON_20030411
authorjbasney <jbasney>
Thu, 17 Apr 2003 20:11:01 +0000 (20:11 +0000)
committerjbasney <jbasney>
Thu, 17 Apr 2003 20:11:01 +0000 (20:11 +0000)
24 files changed:
openssh/Makefile.in
openssh/auth-pam.c
openssh/auth1.c
openssh/auth2-gss.c
openssh/auth2.c
openssh/compat.c
openssh/compat.h
openssh/gss-genr.c
openssh/gss-serv.c
openssh/kex.c
openssh/kex.h
openssh/kexgss.c [deleted file]
openssh/kexgssc.c
openssh/kexgsss.c
openssh/makegssname.pl
openssh/monitor.c
openssh/monitor.h
openssh/monitor_wrap.c
openssh/monitor_wrap.h
openssh/ssh-gss.h
openssh/ssh-keyscan.c
openssh/sshconnect1.c
openssh/sshconnect2.c
openssh/sshd.c

index d4637bf0cae0d806b487a2c0efd9d5921fadc2a8..9f722a2b3ae4aa91e2ac9717a567973c6583b5b3 100644 (file)
@@ -68,8 +68,7 @@ LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \
        key.o dispatch.o kex.o mac.o uuencode.o misc.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 \
-       kexgss.o kexgssc.o gss-genr.o \
-       entropy.o
+       entropy.o kexgssc.o gss-genr.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
        sshconnect.o sshconnect1.o sshconnect2.o
@@ -81,9 +80,9 @@ 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 monitor_fdpass.o \
-       kexdhs.o kexgexs.o \
-       auth-krb5.o auth-krb4.o \
-       kexgsss.o auth2-gss.o gss-serv.o \
+       kexdhs.o kexgexs.o kexgsss.o \
+       auth-krb5.o auth-krb4.o auth2-gss.o \
+       gss-serv.o gss-serv-krb5.o gss-serv-gsi.o \
        loginrec.o auth-pam.o auth2-pam.o auth-sia.o md5crypt.o
 
 MANPAGES       = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
index 09fc3d5052f4ff2087e9252b8a864b1a8425b89e..a8ba48652905daee42e9ffc5d807cd3dfb850dd4 100644 (file)
@@ -413,6 +413,16 @@ char **fetch_pam_environment(void)
 #endif /* HAVE_PAM_GETENVLIST */
 }
 
+void free_pam_environment(char **env)
+{
+       int i;
+
+       if (env != NULL) {
+               for (i = 0; env[i] != NULL; i++)
+                       xfree(env[i]);
+       }
+}
+
 /* Set a PAM environment string. We need to do this so that the session
  * modules can handle things like Kerberos/GSI credentials that appear
  * during the ssh authentication process.
@@ -433,16 +443,6 @@ int do_pam_putenv(char *name, char *value) {
        return(ret);
 }
 
-void free_pam_environment(char **env)
-{
-       int i;
-
-       if (env != NULL) {
-               for (i = 0; env[i] != NULL; i++)
-                       xfree(env[i]);
-       }
-}
-
 /* Print any messages that have been generated during authentication */
 /* or account checking to stderr */
 void print_pam_messages(void)
index ccd43941e6fb2d477eb4848ef02251f2e1c4224a..10d74dc3ebc166a47bfbf83e59d8e864f293cc7c 100644 (file)
@@ -30,15 +30,14 @@ RCSID("$OpenBSD: auth1.c,v 1.47 2003/02/06 21:22:42 markus Exp $");
 
 /* import */
 extern ServerOptions options;
-extern Authmethod method_gssapi;
-
-
 
 #ifdef GSSAPI
 #ifdef GSI
 #include "globus_gss_assist.h"
 #endif
 
+extern Authmethod method_gssapi;
+
 int     userauth_gssapi(Authctxt *authctxt);
 
 void
index c20796123a2516bb28fd8084528aa985cb64a176..6d08d80023813df8274a6235673582d8f9b99f4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -39,7 +39,7 @@
 #include "ssh-gss.h"
 
 extern ServerOptions options;
-extern unsigned char ssh1_key_digest[16];
+unsigned char ssh1_key_digest[16];
 
 static int
 userauth_external(Authctxt *authctxt)
@@ -49,6 +49,7 @@ userauth_external(Authctxt *authctxt)
         return(PRIVSEP(ssh_gssapi_userok(authctxt->user)));
 }
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
 static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt);
 
@@ -65,6 +66,7 @@ userauth_gssapi(Authctxt *authctxt)
         int             present;
         OM_uint32       ms;
         u_int           len;
+        char *         doid = NULL;
         
         if (!authctxt->valid || authctxt->user == NULL)
                 return 0;
@@ -82,41 +84,74 @@ userauth_gssapi(Authctxt *authctxt)
 
         ssh_gssapi_supported_oids(&supported);
         do {
-                if (oid.elements)
-                        xfree(oid.elements);
-                oid.elements = packet_get_string(&len);
-                oid.length = len;
-                gss_test_oid_set_member(&ms, &oid, supported, &present);
                 mechs--;
+                
+                if (doid)
+                        xfree(doid);
+                
+                debug("Trying to get OID string");
+                doid = packet_get_string(&len);
+                debug("Got string");
+                
+                if (datafellows & SSH_BUG_GSSAPI_BER) {
+                       oid.elements = doid;
+                       oid.length = len;
+                } else {
+                       if (doid[0]!=0x06 || doid[1]!=len-2) {
+                               debug("Badly encoded mechanism OID received");
+                               oid.elements=NULL;
+                       } else {
+                               oid.elements = doid + 2;
+                               oid.length   = len - 2;
+                               gss_test_oid_set_member(&ms, &oid, supported, &present);
+                       }
+                }
+               if (oid.elements) {
+                       gss_test_oid_set_member(&ms, &oid, supported, &present);
+               }
         } while (mechs>0 && !present);
         
         if (!present) {
-                xfree(oid.elements);
+                xfree(doid);
                 return(0);
         }
                 
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid))))
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,&oid)))) {
+               ssh_gssapi_userauth_error(ctxt);
                return(0);
+       }
        
         authctxt->methoddata=(void *)ctxt;
 
         /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
 
-       if (!compat20)
-        packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
-       else
-       packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
-        packet_put_string(oid.elements,oid.length);
+       if (!compat20) {
+
+       packet_start(SSH_SMSG_AUTH_GSSAPI_RESPONSE);
+       packet_put_string(oid.elements,oid.length);
+
+       } else {
+
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
+
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+                       packet_put_string(oid.elements,oid.length);
+               } else {
+                       packet_put_string(doid,len);
+               }
+
+       } /* !compat20 */
+               
         packet_send();
         packet_write_wait();
-        xfree(oid.elements);
+        xfree(doid);
 
        if (!compat20)
        dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN,
                                &input_gssapi_token);
        else
-       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
-                    &input_gssapi_token);
+        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, 
+                     &input_gssapi_token);
         authctxt->postponed = 1;
         
         return 0;
@@ -136,14 +171,16 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
                 
         gssctxt=authctxt->methoddata;
         recv_tok.value=packet_get_string(&len);
-       recv_tok.length=len; /* int vs. size_t */
+        recv_tok.length=len; /* int vs. size_t */
         
         maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 
-                                                &send_tok, NULL));
+                                               &send_tok, NULL));
         packet_check_eom();
-        
+                        
         if (send_tok.length != 0) {
-                /* Send a packet back to the client */
+                /* Send a packet back to the client, even if there has
+                 * been an error, as this may contain mechanism specific
+                 * error information */
                if (!compat20)
                packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN);
                else
@@ -153,20 +190,15 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
                 packet_write_wait();
                 gss_release_buffer(&min_status, &send_tok);        
         }
-        
+       
         if (GSS_ERROR(maj_status)) {
-                /* Failure <sniff> */
-               if (gssctxt) {  /* may be NULL under privsep */
-                   ssh_gssapi_send_error(gssctxt->oid,maj_status,min_status);
-               } else {
-                   ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
-               }
+                ssh_gssapi_userauth_error(gssctxt);
                 authctxt->postponed = 0;
                dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
                 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
                 userauth_finish(authctxt, 0, "gssapi");
         }
-                        
+
         if (maj_status == GSS_S_COMPLETE) {
                dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
                 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
@@ -217,7 +249,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
        }
 
         gssctxt=authctxt->methoddata;
-
+        
        /* ssh1 needs to exchange the hash of the keys */
        if (!compat20) {
 
@@ -254,6 +286,23 @@ finish:
         userauth_finish(authctxt, authenticated, "gssapi");
 }
 
+static void ssh_gssapi_userauth_error(Gssctxt *ctxt) {
+       char *errstr;
+       OM_uint32 maj,min;
+       
+       errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+       if (errstr) {
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
+               packet_put_int(maj);
+               packet_put_int(min);
+               packet_put_cstring(errstr);
+               packet_put_cstring("");
+               packet_send();
+               packet_write_wait();
+               xfree(errstr);
+       }
+}
+
 Authmethod method_external = {
        "external-keyx",
        userauth_external,
index 5965f1da67d502d40835713a1b13f2ed45f69fde..4c19365b49e90660e3fbd310d4e088fc89633757 100644 (file)
@@ -253,7 +253,6 @@ input_userauth_request(int type, u_int32_t seq, void *ctxt)
                debug2("input_userauth_request: try method %s", method);
                authenticated = m->userauth(authctxt);
        }
-
        userauth_finish(authctxt, authenticated, method);
 
        xfree(service);
index b2e9cde40612a5017005ce2fb7f9abecaeeebfe8..b3960b506fd50e4b3c0ddac8e241750edf088c58 100644 (file)
@@ -81,7 +81,13 @@ compat_datafellows(const char *version)
                { "OpenSSH_2.9p*",      SSH_OLD_GSSAPI },
                { "OpenSSH_2.*,"
                  "OpenSSH_3.0*,"
-                 "OpenSSH_3.1*",       SSH_BUG_EXTEOF|SSH_BUG_GSS_EMPTYUSER},
+                 "OpenSSH_3.1*",       SSH_BUG_EXTEOF|SSH_BUG_GSS_EMPTYUSER|
+                                       SSH_BUG_GSSAPI_BER},
+               { "OpenSSH_3.2*,"
+                 "OpenSSH_3.3*,"
+                 "OpenSSH_3.4*,"
+                 "OpenSSH_3.5*,"
+                 "OpenSSH_3.6.1*",     SSH_BUG_GSSAPI_BER},
                { "Sun_SSH_1.0*",       SSH_BUG_NOREKEY|SSH_BUG_EXTEOF},
                { "OpenSSH*",           0 },
                { "*MindTerm*",         0 },
index 8d7496fd1ff4717e35fd726f145490ec69eb6a95..b982d3e8f945ef9cf96641659dcdd747e900a1c1 100644 (file)
@@ -56,8 +56,9 @@
 #define SSH_BUG_K5USER         0x00400000
 #define SSH_BUG_PROBE          0x00800000
 #define SSH_BUG_FIRSTKEX       0x01000000
-#define SSH_OLD_GSSAPI         0x10000000
-#define SSH_BUG_GSS_EMPTYUSER  0x20000000
+#define SSH_OLD_GSSAPI         0x02000000
+#define SSH_BUG_GSSAPI_BER     0x04000000
+#define SSH_BUG_GSS_EMPTYUSER  0x10000000
 
 void     enable_compat13(void);
 void     enable_compat20(void);
index 159c55e90eb951184e50bb6f6b50dc36af8c1138..e91dc398c4f0371543227e1a61fa57d4038346a3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved. *
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
 
 #include "ssh-gss.h"
 
-/* Assorted globals for tracking the clients identity once they've
- * authenticated */
-gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */
-gss_cred_id_t   gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */
-enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY;
-
-unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */
-
-/* The mechanism name used in the list below is defined in the internet
- * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding 
- * of the underlying GSSAPI mechanism's OID.
- *
- * Also from the draft, before considering adding SPNEGO, bear in mind that
- * "mechanisms ... MUST NOT use SPNEGO as the underlying GSSAPI mechanism"
- */
-
-/* These must be in the same order as ssh_gss_id, in ssh-gss.h */
-
-ssh_gssapi_mech supported_mechs[]= {
-#ifdef KRB5
- /* Official OID - 1.2.850.113554.1.2.2 */
- {"Se3H81ismmOC3OE+FwYCiQ==","Kerberos",
-       {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}},
-#endif
-#ifdef GSI
- /* gssapi_ssleay 1.3.6.1.4.1.3536.1.1 */
- {"N3+k7/4wGxHyuP8Yxi4RhA==",
-  "GSI",
-  {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"}
- },
-#endif /* GSI */
- {NULL,NULL,{0,0}}
-};
-
-char gssprefix[]=KEX_GSS_SHA1;
+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.
  *
- * 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)
+ * 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.
  *
- * 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.
+ * XXX - We might want to make this configurable in the future, so as to
+ * XXX - allow the user control over which mechanisms to use.
  */
  
 char * 
-ssh_gssapi_mechanisms(char *host) {
+ssh_gssapi_client_mechanisms(char *host) {
        gss_OID_set     supported;
-       OM_uint32       maj_status, min_status;
+       OM_uint32       min_status;
        Buffer          buf;
        int             i = 0;
-       int             present;
-       int             mech_count=0;
-       char *          mechs;
-       Gssctxt *       ctx = NULL;     
-
+       char            *mechs;
+       char            *encoded;
+       int             enclen;
+       char            digest[EVP_MAX_MD_SIZE];
+       char            deroid[2];
+       const EVP_MD    *evp_md = EVP_md5();
+       EVP_MD_CTX      md;
+       int             oidpos=0;
+       
        if (datafellows & SSH_OLD_GSSAPI) return NULL;
        
-       gss_indicate_mechs(&min_status, &supported);
+       gss_indicate_mechs(&min_status,&supported);
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
+                                       *((supported->count*2)+1));
+       } else {
+               gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping)
+                                       *(supported->count+1));
+       }
        
-       buffer_init(&buf);      
-
-       do {
-               if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                       &supported_mechs[i].oid,
-                                                       supported,
-                                                       &present))) {
-                       present=0;
-               }
-               if (present) {
-                       if (!GSS_ERROR(ssh_gssapi_client_ctx(&ctx,
-                                                      &supported_mechs[i].oid,
-                                                      host))) {
-                               /* Append gss_group1_sha1_x to our list */
-                               if (++mech_count > 1) {
-                                   buffer_append(&buf, ",", 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)) {
+
+                       /* Earlier versions of this code interpreted the
+                       * spec incorrectly with regard to OID encoding. They
+                       * also mis-encoded the krb5 OID. The following
+                       * _temporary_ code interfaces with these broken
+                       * servers */
+
+                       if (datafellows & SSH_BUG_GSSAPI_BER) {
+                               char *bodge=NULL;
+                               gss_OID_desc krb5oid={9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"};
+                               gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"};
+                               
+                               if (supported->elements[i].length==krb5oid.length &&
+                                   memcmp(supported->elements[i].elements,
+                                          krb5oid.elements, krb5oid.length)==0) {
+                                       bodge="Se3H81ismmOC3OE+FwYCiQ==";
+                               }
+                               
+                               if (supported->elements[i].length==gsioid.length &&
+                                   memcmp(supported->elements[i].elements,
+                                          gsioid.elements, gsioid.length)==0) {
+                                       bodge="N3+k7/4wGxHyuP8Yxi4RhA==";
+                               }
+
+                               if (bodge) {                            
+                                       if (oidpos!=0) {
+                                               buffer_put_char(&buf,',');
+                                       }
+                               
+                                       buffer_append(&buf, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1);
+                                       buffer_append(&buf, bodge, strlen(bodge));
+
+                                       gss_enc2oid[oidpos].oid=&(supported->elements[i]);
+                                       gss_enc2oid[oidpos].encoded=bodge;
+                       
+                                       oidpos++;
                                }
-                               buffer_append(&buf, gssprefix,
-                                             strlen(gssprefix));
-                               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, gssprefix,
-                                     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);
+                       
+                       /* Add the required DER encoding octets and MD5 hash */
+                       deroid[0]=0x06; /* Object Identifier */
+                       deroid[1]=supported->elements[i].length;
+
+                       EVP_DigestInit(&md, evp_md);
+                       EVP_DigestUpdate(&md,deroid,2);
+                       EVP_DigestUpdate(&md,
+                                       supported->elements[i].elements,
+                                       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);
+
+                       gss_enc2oid[oidpos].oid=&(supported->elements[i]);
+                       gss_enc2oid[oidpos].encoded=encoded;                    
+                       oidpos++;
                }
-       } while (supported_mechs[++i].name != NULL);
+       }
+       gss_enc2oid[oidpos].oid=NULL;
+       gss_enc2oid[oidpos].encoded=NULL;
        
        buffer_put_char(&buf,'\0');
        
@@ -153,11 +173,41 @@ ssh_gssapi_mechanisms(char *host) {
        buffer_get(&buf,mechs,buffer_len(&buf));
        buffer_free(&buf);
        if (strlen(mechs)==0)
-          return(NULL);
+               return(NULL);
        else
-          return(mechs);
+               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);
+       }
+       
+       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++;
+       }
+       
+       if (gss_enc2oid[i].oid!=NULL) {
+               ssh_gssapi_set_oid(ctx,gss_enc2oid[i].oid);
+       }
+
+       return gss_enc2oid[i].oid;
 }
 
+/* Check that the OID in a data stream matches that in the context */
+int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) {
+  
+  return (ctx!=NULL && ctx->oid != GSS_C_NO_OID && 
+         ctx->oid->length == len &&
+         memcmp(ctx->oid->elements,data,len)==0);
+}
+       
 /* Set the contexts OID from a data stream */
 void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) { 
   if (ctx->oid != GSS_C_NO_OID) {
@@ -175,80 +225,58 @@ void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) {
   ssh_gssapi_set_oid_data(ctx,oid->elements,oid->length);
 }
 
-/* Find out which GSS type (out of the list we define in ssh-gss.h) a
- * particular connection is using 
- */
-enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) {
-       enum ssh_gss_id i=0;
-       
-       while(supported_mechs[i].name!=NULL) {
-          if (supported_mechs[i].oid.length == ctxt->oid->length &&
-              (memcmp(supported_mechs[i].oid.elements,
-                      ctxt->oid->elements,ctxt->oid->length) == 0))
-              return i;
-          i++;
-       }
-       return(GSS_LAST_ENTRY);
-}
-
-/* Set the GSS context's OID to the oid indicated by the given key exchange
- * name. */
-gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name) {
-  enum ssh_gss_id i=0;
-  
-  if (strncmp(name, gssprefix, strlen(gssprefix)-1) !=0) {
-     return(NULL);
-  }
-  
-  name+=strlen(gssprefix); /* 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);
-
-  if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid);
-
-  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i].name,
-       gssprefix, supported_mechs[i].enc_name);
+/* All this effort to report an error ... */
 
-  return &supported_mechs[i].oid;
+void
+ssh_gssapi_error(Gssctxt *ctxt) {
+       
+       debug(ssh_gssapi_last_error(ctxt,NULL,NULL));
 }
 
-
-/* All this effort to report an error ... */
-void
-ssh_gssapi_error(gss_OID mech, OM_uint32 major_status,
-                OM_uint32 minor_status) {
-       OM_uint32 lmaj, lmin;
-        gss_buffer_desc msg = {0,NULL};
+char *
+ssh_gssapi_last_error(Gssctxt *ctxt, 
+                     OM_uint32 *major_status, OM_uint32 *minor_status) {
+       OM_uint32 lmin;
+        gss_buffer_desc msg;
         OM_uint32 ctx;
+        Buffer b;
+        char *ret;
         
+        buffer_init(&b);
+
+       if (major_status!=NULL) *major_status=ctxt->major;
+       if (minor_status!=NULL) *minor_status=ctxt->minor;
+       
         ctx = 0;
        /* The GSSAPI error */
         do {
-               lmaj = gss_display_status(&lmin, major_status,
-                                         GSS_C_GSS_CODE,
-                                         mech, &ctx, &msg);
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);         
+               gss_display_status(&lmin, ctxt->major,
+                                  GSS_C_GSS_CODE, ctxt->oid,
+                                  &ctx, &msg);
+
+               buffer_append(&b,msg.value,msg.length);
+               buffer_put_char(&b,'\n');
+               
+                       gss_release_buffer(&lmin, &msg);
+        } while (ctx!=0);
 
         /* The mechanism specific error */
         do {
-               lmaj = gss_display_status(&lmin, minor_status,
-                                         GSS_C_MECH_CODE,
-                                         mech, &ctx, &msg);
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
+               gss_display_status(&lmin, ctxt->minor,
+                                  GSS_C_MECH_CODE, ctxt->oid,
+                                  &ctx, &msg);
+               
+               buffer_append(&b,msg.value,msg.length);
+               buffer_put_char(&b,'\n');
+               
+               gss_release_buffer(&lmin, &msg);
         } while (ctx!=0);
+        
+        buffer_put_char(&b,'\0');
+        ret=xmalloc(buffer_len(&b));
+        buffer_get(&b,ret,buffer_len(&b));
+        buffer_free(&b);
+        return(ret);
 }
 
 /* Initialise our GSSAPI context. We use this opaque structure to contain all
@@ -260,6 +288,8 @@ void
 ssh_gssapi_build_ctx(Gssctxt **ctx)
 {
        *ctx=xmalloc(sizeof (Gssctxt));
+       (*ctx)->major=0;
+       (*ctx)->minor=0;
        (*ctx)->context=GSS_C_NO_CONTEXT;
        (*ctx)->name=GSS_C_NO_NAME;
        (*ctx)->oid=GSS_C_NO_OID;
@@ -311,7 +341,6 @@ OM_uint32
 ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                            gss_buffer_desc* send_tok, OM_uint32 *flags) 
 {
-       OM_uint32 maj_status, min_status;
        int deleg_flag = 0;
        
        if (deleg_creds) {
@@ -319,7 +348,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                debug("Delegating credentials");
        }
                
-       maj_status=gss_init_sec_context(&min_status,
+       ctx->major=gss_init_sec_context(&ctx->minor,
                                        GSS_C_NO_CREDENTIAL, /* def. cred */
                                        &ctx->context,
                                        ctx->name,
@@ -334,28 +363,26 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok,
                                        send_tok,
                                        flags,
                                        NULL);
-       ctx->status=maj_status;
-       if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
+       if (GSS_ERROR(ctx->major)) {
+               ssh_gssapi_error(ctx);
        }
-       return(maj_status);
+       return(ctx->major);
 }
 
 /* Create a service name for the given host */
 OM_uint32
 ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
-       gss_buffer_desc gssbuf = {0,NULL};
-       OM_uint32 maj_status, min_status;
+       gss_buffer_desc gssbuf;
        char *xhost;
        
        /* Make a copy of the host name, in case it was returned by a
-        * previous call to gethostbyname(). */ 
+       * previous call to gethostbyname(). */  
        xhost = xstrdup(host);
 
-       /* Make sure we have the FQHN. Some GSSAPI implementations don't do
-        * this for us themselves */
+       /* Make sure we have the FQDN. Some GSSAPI implementations don't do
+       * this for us themselves */
        resolve_localhost(&xhost);
-
+       
         gssbuf.length = sizeof("host@")+strlen(xhost);
 
         gssbuf.value = xmalloc(gssbuf.length);
@@ -364,16 +391,16 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
                return(-1);
         }
         snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost);
-        if ((maj_status=gss_import_name(&min_status,
+        if ((ctx->major=gss_import_name(&ctx->minor,
                                        &gssbuf,
                                         GSS_C_NT_HOSTBASED_SERVICE,
                                         &ctx->name))) {
-               ssh_gssapi_error(ctx->oid, maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
        
        xfree(xhost);
        xfree(gssbuf.value);
-       return(maj_status);
+       return(ctx->major);
 }
 
 /* Acquire credentials for a server running on the current host.
@@ -383,95 +410,81 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) {
 /* Returns a GSSAPI error code */
 OM_uint32
 ssh_gssapi_acquire_cred(Gssctxt *ctx) {
-       OM_uint32 maj_status, min_status;
+       OM_uint32 status;
        char lname[MAXHOSTNAMELEN];
        gss_OID_set oidset;
        
-       gss_create_empty_oid_set(&min_status,&oidset);
-       gss_add_oid_set_member(&min_status,ctx->oid,&oidset);
+       gss_create_empty_oid_set(&status,&oidset);
+       gss_add_oid_set_member(&status,ctx->oid,&oidset);
        
         if (gethostname(lname, MAXHOSTNAMELEN)) {
                 return(-1);
         }
 
-       if ((maj_status=ssh_gssapi_import_name(ctx,lname))) {
-               return(maj_status);
+       if (GSS_ERROR(ssh_gssapi_import_name(ctx,lname))) {
+               return(ctx->major);
        }
-       if ((maj_status=gss_acquire_cred(&min_status,
-                                   ctx->name,
+       
+       if ((ctx->major=gss_acquire_cred(&ctx->minor,
+                                   ctx->name,
                                    0,
                                    oidset,
                                    GSS_C_ACCEPT,
                                    &ctx->creds,
                                    NULL,
                                    NULL))) {
-           ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
                                
-       gss_release_oid_set(&min_status, &oidset);
-       return(maj_status);
-}
-
-/* Extract the client details from a given context. This can only reliably
- * be called once for a context */
-
-OM_uint32 
-ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type,
-                    gss_buffer_desc *name, gss_cred_id_t *creds) {
-
-       OM_uint32 maj_status,min_status;
-       
-       *type=ssh_gssapi_get_ctype(ctx);
-       if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
-       }
-       
-       /* This is icky. There appears to be no way to copy this structure,
-        * rather than the pointer to it, so we simply copy the pointer and
-        * mark the originator as empty so we don't destroy it. 
-        */
-       *creds=ctx->client_creds;
-       ctx->client_creds=GSS_C_NO_CREDENTIAL;
-       return(maj_status);
+       gss_release_oid_set(&status, &oidset);
+       return(ctx->major);
 }
 
 OM_uint32
 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) {
-       OM_uint32 maj_status,min_status;
        
        /* ssh1 needs to exchange the hash of the keys */
        /* will us this hash to return it */
        if (!compat20) {
-               if ((maj_status=gss_wrap(&min_status,ctx->context,
-                                       0,
-                                       GSS_C_QOP_DEFAULT,
-                                       buffer,
-                                       NULL,
-                                       hash)))
-                       ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               if ((ctx->major=gss_wrap(&ctx->minor,ctx->context,
+                                        0,
+                                        GSS_C_QOP_DEFAULT,
+                                        buffer,
+                                        NULL,
+                                        hash)))
+                   ssh_gssapi_error(ctx);
        }
        else
 
-       if ((maj_status=gss_get_mic(&min_status,ctx->context,
+       if ((ctx->major=gss_get_mic(&ctx->minor,ctx->context,
                                    GSS_C_QOP_DEFAULT, buffer, hash))) {
-               ssh_gssapi_error(ctx->oid,maj_status,min_status);
+               ssh_gssapi_error(ctx);
        }
        
-       return(maj_status);
+       return(ctx->major);
 }
 
-OM_uint32 
-ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) {
-       gss_buffer_desc token = {0,NULL};
-       OM_uint32 major,minor;
-       
+OM_uint32
+ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
        if (*ctx) ssh_gssapi_delete_ctx(ctx);
        ssh_gssapi_build_ctx(ctx);
        ssh_gssapi_set_oid(*ctx,oid);
-       ssh_gssapi_import_name(*ctx,host);
-       major=ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL);
+       return(ssh_gssapi_acquire_cred(*ctx));
+}
+
+int
+ssh_gssapi_check_mechanism(gss_OID oid, char *host) {
+       Gssctxt * ctx = NULL;
+       gss_buffer_desc token;
+       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);
-       return(major);
+       ssh_gssapi_delete_ctx(&ctx);
+       return(!GSS_ERROR(major));
 }
 
 #endif /* GSSAPI */
index 0edb918e4fa63ff763df43cd82936d055a920c11..b94472eaf34fae2e286ecd7ea64b50ccd735c874 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -27,7 +27,6 @@
 #ifdef GSSAPI
 
 #include "ssh.h"
-#include "ssh1.h"
 #include "ssh2.h"
 #include "xmalloc.h"
 #include "buffer.h"
@@ -44,7 +43,6 @@
 #include "dispatch.h"
 #include "servconf.h"
 #include "compat.h"
-#include "misc.h"
 #include "monitor_wrap.h"
 
 #include "ssh-gss.h"
@@ -53,652 +51,99 @@ extern ServerOptions options;
 extern u_char *session_id2;
 extern int session_id2_len;
 
-typedef struct ssh_gssapi_cred_cache {
-       char *filename;
-       char *envvar;
-       char *envval;
-       void *data;
-} ssh_gssapi_cred_cache;
+static ssh_gssapi_client gssapi_client =
+       { {0,NULL}, GSS_C_NO_CREDENTIAL, NULL, {NULL,NULL,NULL}};
 
-static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL};
-
-/*
- * Environment variables pointing to delegated credentials
- */
-static char *delegation_env[] = {
-  "X509_USER_PROXY",           /* GSSAPI/SSLeay */
-  "KRB5CCNAME",                        /* Krb5 and possibly SSLeay */
-  NULL
-};
-
-static void gssapi_unsetenv(const char *var);
+ssh_gssapi_mech gssapi_null_mech 
+  = {NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
 
 #ifdef KRB5
-
-#ifdef HEIMDAL
-#include <krb5.h>
-#else
-#include <gssapi_krb5.h>
-#define krb5_get_err_text(context,code) error_message(code)
-#endif
-
-static krb5_context krb_context = NULL;
-
-/* Initialise the krb5 library, so we can use it for those bits that
- * GSSAPI won't do */
-
-int ssh_gssapi_krb5_init() {
-       krb5_error_code problem;
-       
-       if (krb_context !=NULL)
-               return 1;
-               
-       problem = krb5_init_context(&krb_context);
-       if (problem) {
-               log("Cannot initialize krb5 context");
-               return 0;
-       }
-       krb5_init_ets(krb_context);
-
-       return 1;       
-}                      
-
-/* Check if this user is OK to login. This only works with krb5 - other 
- * GSSAPI mechanisms will need their own.
- * Returns true if the user is OK to log in, otherwise returns 0
- */
-
-int
-ssh_gssapi_krb5_userok(char *name) {
-       krb5_principal princ;
-       int retval;
-
-       if (ssh_gssapi_krb5_init() == 0)
-               return 0;
-               
-       if ((retval=krb5_parse_name(krb_context, gssapi_client_name.value, 
-                                   &princ))) {
-               log("krb5_parse_name(): %.100s", 
-                       krb5_get_err_text(krb_context,retval));
-               return 0;
-       }
-       if (krb5_kuserok(krb_context, princ, name)) {
-               retval = 1;
-               log("Authorized to %s, krb5 principal %s (krb5_kuserok)",name,
-                   (char *)gssapi_client_name.value);
-       }
-       else
-               retval = 0;
-       
-       krb5_free_principal(krb_context, princ);
-       return retval;
-}
-
-int
-ssh_gssapi_krb5_localname(char **user)
-{
-    krb5_principal princ;
-
-    if (ssh_gssapi_krb5_init() == 0)
-       return 0;
-
-    if (krb5_parse_name(krb_context, gssapi_client_name.value, &princ)) {
-       return(0);
-    }
-    *user = (char *)xmalloc(256);
-    if (krb5_aname_to_localname(krb_context, princ, 256, *user)) {
-       xfree(*user);
-       *user = NULL;
-       return(0);
-    }
-    return(1);
-}
-       
-/* Make sure that this is called _after_ we've setuid to the user */
-
-/* This writes out any forwarded credentials. Its specific to the Kerberos
- * GSSAPI mechanism
- *
- * We assume that our caller has made sure that the user has selected
- * delegated credentials, and that the client_creds structure is correctly
- * populated.
- */
-
-OM_uint32
-ssh_gssapi_krb5_storecreds(gss_buffer_t export_buffer) {
-       krb5_ccache ccache;
-       krb5_error_code problem;
-       krb5_principal princ;
-       char ccname[35];
-       static char name[40];
-       int tmpfd;
-       OM_uint32 maj_status,min_status;
-       gss_cred_id_t krb5_cred_handle;
-
-
-       if (gssapi_client_creds==NULL) {
-               debug("No credentials stored"); 
-               return GSS_S_NO_CRED;
-       }
-               
-       if (ssh_gssapi_krb5_init() == 0)
-               return GSS_S_FAILURE;
-
-       if (options.gss_use_session_ccache) {
-               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d_XXXXXX",geteuid());
-       
-               if ((tmpfd = mkstemp(ccname))==-1) {
-                       log("mkstemp(): %.100s", strerror(errno));
-                       return GSS_S_FAILURE;
-               }
-               if (fchmod(tmpfd, S_IRUSR | S_IWUSR) == -1) {
-                       log("fchmod(): %.100s", strerror(errno));
-                       close(tmpfd);
-                       return GSS_S_FAILURE;
-               }
-        } else {
-               snprintf(ccname,sizeof(ccname),"/tmp/krb5cc_%d",geteuid());
-               tmpfd = open(ccname, O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
-               if (tmpfd == -1) {
-                       log("open(): %.100s", strerror(errno));
-                       return GSS_S_FAILURE;
-               }
-        }
-
-               close(tmpfd);
-        snprintf(name, sizeof(name), "FILE:%s",ccname);
-        if ((problem = krb5_cc_resolve(krb_context, name, &ccache))) {
-                log("krb5_cc_default(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-                return GSS_S_FAILURE;
-        }
-
-       if ((problem = krb5_parse_name(krb_context, gssapi_client_name.value, 
-                                      &princ))) {
-               log("krb5_parse_name(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) {
-               log("krb5_cc_initialize(): %.100s", 
-                       krb5_get_err_text(krb_context,problem));
-               krb5_free_principal(krb_context,princ);
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       krb5_free_principal(krb_context,princ);
-
-#ifdef MECHGLUE
-       krb5_cred_handle =
-           __gss_get_mechanism_cred(gssapi_client_creds,
-                                    &(supported_mechs[GSS_KERBEROS].oid));
-#else
-       krb5_cred_handle = gssapi_client_creds;
+extern ssh_gssapi_mech gssapi_kerberos_mech;
+extern ssh_gssapi_mech gssapi_kerberos_mech_old;
 #endif
-
-       if ((maj_status = gss_krb5_copy_ccache(&min_status, 
-                                              krb5_cred_handle, 
-                                              ccache))) {
-               log("gss_krb5_copy_ccache() failed");
-               ssh_gssapi_error(&supported_mechs[GSS_KERBEROS].oid,
-                                maj_status,min_status);
-               krb5_cc_destroy(krb_context,ccache);
-               return GSS_S_FAILURE;
-       }
-       
-       krb5_cc_close(krb_context,ccache);
-
-       export_buffer->length = strlen("KRB5CCNAME")+strlen(name)+1;
-       export_buffer->value = xmalloc(export_buffer->length+1);
-       sprintf(export_buffer->value, "%s=%s", "KRB5CCNAME", name);
-
-       return GSS_S_COMPLETE;
-}
-
-#endif /* KRB5 */
-
 #ifdef GSI
-#include <globus_gss_assist.h>
-
-/*
- * Check if this user is OK to login under GSI. User has been authenticated
- * as identity in global 'client_name.value' and is trying to log in as passed
- * username in 'name'.
- *
- * Returns non-zero if user is authorized, 0 otherwise.
- */
-int
-ssh_gssapi_gsi_userok(char *name)
-{
-    int authorized = 0;
-    
-#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-       return 0;
-    }
+extern ssh_gssapi_mech gssapi_gsi_mech;
+extern ssh_gssapi_mech gssapi_gsi_mech_old;
 #endif
 
-    /* globus_gss_assist_userok() returns 0 on success */
-    authorized = (globus_gss_assist_userok(gssapi_client_name.value,
-                                          name) == 0);
-    
-    log("GSI user %s is%s authorized as target user %s",
-       (char *) gssapi_client_name.value, (authorized ? "" : " not"), name);
-    
-    return authorized;
-}
-
-/*
- * Return the local username associated with the GSI credentials.
- */
-int
-ssh_gssapi_gsi_localname(char **user)
-{
-#ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
-    if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
-       return 0;
-    }
-#endif
-    return(globus_gss_assist_gridmap(gssapi_client_name.value, user) == 0);
-}
-
-/*
- * Handle setting up child environment for GSI.
- *
- * Make sure that this is called _after_ we've setuid to the user.
- */
-OM_uint32
-ssh_gssapi_gsi_storecreds(gss_buffer_t export_buffer)
-{
-       OM_uint32       major_status;
-       OM_uint32       minor_status;
-
-       if (gssapi_client_creds != NULL)
-       {
-               char *creds_env = NULL;
-
-               /*
-                * This is the current hack with the GSI gssapi library to
-                * export credentials to disk.
-                */
-
-               debug("Exporting delegated credentials");
-               
-               minor_status = 0xdee0;  /* Magic value */
-               major_status =
-                       gss_inquire_cred(&minor_status,
-                                        gssapi_client_creds,
-                                        (gss_name_t *) &creds_env,
-                                        NULL,
-                                        NULL,
-                                        NULL);
-
-               if ((major_status == GSS_S_COMPLETE) &&
-                   (minor_status == 0xdee1) &&
-                   (creds_env != NULL))
-               {
-                       char            *value;
-                               
-                       /*
-                        * String is of the form:
-                        * X509_USER_DELEG_PROXY=filename
-                        * so we parse out the filename
-                        * and then set X509_USER_PROXY
-                        * to point at it.
-                        */
-                       value = strchr(creds_env, '=');
-                       
-                       if (value != NULL)
-                       {
-                               *value = '\0';
-                               value++;
-                               export_buffer->length=
-                                   strlen("X509_USER_PROXY")+strlen(value)+1;
-                               export_buffer->value =
-                                   xmalloc(export_buffer->length+1);
-                               sprintf(export_buffer->value, "%s=%s",
-                                       "X509_USER_PROXY", value);
-                               
-                               return GSS_S_COMPLETE;
-                       }
-                       else
-                       {
-                           log("Failed to parse delegated credentials string '%s'",
-                               creds_env);
-                       }
-               }
-               else
-               {
-                   log("Failed to export delegated credentials (error %u)",
-                       (unsigned int)major_status);
-               }
-       }
-       return 0;
-}
-
-#endif /* GSI */
-
-void
-ssh_gssapi_cleanup_creds(void *ignored)
-{
-       /* OM_uint32 min_stat; */
-
-       if (gssapi_cred_store.filename!=NULL) {
-               /* Unlink probably isn't sufficient */
-               debug("removing gssapi cred file \"%s\"",gssapi_cred_store.filename);
-               unlink(gssapi_cred_store.filename);
-       }
-       /* DK ?? 
-       if (gssapi_client_creds != GSS_C_NO_CREDENTIAL)
-               gss_release_cred(&min_stat, &gssapi_client_creds);
-       */
-}
-
-OM_uint32
-ssh_gssapi_export_cred(OM_uint32 *            minor_status,
-                      const gss_cred_id_t    cred_handle,
-                      const gss_OID          desired_mech,
-                      OM_uint32              option_req,
-                      gss_buffer_t           export_buffer)
-{
-       OM_uint32 maj_stat = GSS_S_FAILURE;
-
-       if (option_req != 1) return GSS_S_UNAVAILABLE;
-       if (desired_mech != NULL) return GSS_S_BAD_MECH;
-
-       switch (gssapi_client_type) {
+ssh_gssapi_mech* supported_mechs[]= {
 #ifdef KRB5
-       case GSS_KERBEROS:
-               maj_stat = ssh_gssapi_krb5_storecreds(export_buffer);
-               break;
+  &gssapi_kerberos_mech,
+  &gssapi_kerberos_mech_old, /* Support for legacy clients */
 #endif
 #ifdef GSI
-       case GSS_GSI:
-               maj_stat = ssh_gssapi_gsi_storecreds(export_buffer);
-               break;
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               /* GSSAPI not used in this authentication */
-               debug("No GSSAPI credentials stored");
-               break;
-       default:
-               log("ssh_gssapi_do_child: Unknown mechanism");
-       
-       }
-
-       if (GSS_ERROR(maj_stat)) {
-               *minor_status = GSS_S_FAILURE;
-       }
-       return maj_stat;
-}
-
-void 
-ssh_gssapi_storecreds()
-{
-       OM_uint32 maj_stat, min_stat;
-       gss_buffer_desc export_cred = GSS_C_EMPTY_BUFFER;
-       char *p;
-
-       if (gssapi_client_creds == GSS_C_NO_CREDENTIAL)
-               return;
-
-#ifdef HAVE_GSSAPI_EXT
-       maj_stat = gss_export_cred(&min_stat, gssapi_client_creds,
-                                  GSS_C_NO_OID, 1, &export_cred);
-       if (GSS_ERROR(maj_stat) && maj_stat != GSS_S_UNAVAILABLE) {
-               ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
-               return;
-       }
-#endif
-
-       /* If gss_export_cred() is not available, use old methods */
-       if (export_cred.length == 0) {
-           ssh_gssapi_export_cred(&min_stat, gssapi_client_creds,
-                                  GSS_C_NO_OID, 1, &export_cred);
-           if (GSS_ERROR(maj_stat)) {
-               ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
-           }
-       }
-
-       p = strchr((char *) export_cred.value, '=');
-       if (p == NULL) {
-               log("Failed to parse exported credentials string '%.100s'",
-                   (char *)export_cred.value);
-               gss_release_buffer(&min_stat, &export_cred);
-               return;
-       }
-       *p++ = '\0';
-#ifdef GSI
-       if (strcmp((char *)export_cred.value,"X509_USER_DELEG_PROXY") == 0)
-           gssapi_cred_store.envvar = strdup("X509_USER_PROXY");
-       else
+  &gssapi_gsi_mech,
+  &gssapi_gsi_mech_old,        /* Support for legacy clients */
 #endif
-       gssapi_cred_store.envvar = strdup((char *)export_cred.value);
-       gssapi_cred_store.envval = strdup(p);
-#ifdef USE_PAM
-       do_pam_putenv(gssapi_cred_store.envvar, gssapi_cred_store.envval);
-#endif
-       if (strncmp(p, "FILE:", 5) == 0) {
-           p += 5;
-       }
-       if (access(p, R_OK) == 0) {
-           gssapi_cred_store.filename = strdup(p);
-       }
-       gss_release_buffer(&min_stat, &export_cred);
-
-       if (options.gss_cleanup_creds) {
-               fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
-       }
-}
+  &gssapi_null_mech,
+};
 
-/* This allows GSSAPI methods to do things to the childs environment based
- * on the passed authentication process and credentials.
+/* Return a list of the gss-group1-sha1-x mechanisms supported by this
+ * program.
  *
- * Question: If we didn't use userauth_external for some reason, should we
- * still delegate credentials?
- */
-void 
-ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
-{
-
-       if (gssapi_cred_store.envvar!=NULL && 
-           gssapi_cred_store.envval!=NULL) {
-           
-               debug("Setting %s to %s", gssapi_cred_store.envvar,
-                                         gssapi_cred_store.envval);                              
-               child_set_env(envp, envsizep, gssapi_cred_store.envvar, 
-                                             gssapi_cred_store.envval);
-       }
-
-       switch(gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS: break;
-#endif
-#ifdef GSI
-       case GSS_GSI: break;
-#endif
-       case GSS_LAST_ENTRY:
-               debug("No GSSAPI credentials stored");
-               break;
-       default:
-               log("ssh_gssapi_do_child: Unknown mechanism");
-       }
-}
-
-int
-ssh_gssapi_userok(char *user)
-{
-       if (gssapi_client_name.length==0 || 
-           gssapi_client_name.value==NULL) {
-               debug("No suitable client data");
-               return 0;
-       }
-       switch (gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS:
-               return(ssh_gssapi_krb5_userok(user));
-               break; /* Not reached */
-#endif
-#ifdef GSI
-       case GSS_GSI:
-               return(ssh_gssapi_gsi_userok(user));
-               break; /* Not reached */
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               debug("Client not GSSAPI");
-               break;
-       default:
-               debug("Unknown client authentication type");
-       }
-       return(0);
-}
-
-int
-ssh_gssapi_localname(char **user)
-{
-       *user = NULL;
-       if (gssapi_client_name.length==0 || 
-           gssapi_client_name.value==NULL) {
-               debug("No suitable client data");
-               return(0);;
-       }
-       switch (gssapi_client_type) {
-#ifdef KRB5
-       case GSS_KERBEROS:
-               return(ssh_gssapi_krb5_localname(user));
-               break; /* Not reached */
-#endif
-#ifdef GSI
-       case GSS_GSI:
-               return(ssh_gssapi_gsi_localname(user));
-               break; /* Not reached */
-#endif /* GSI */
-       case GSS_LAST_ENTRY:
-               debug("Client not GSSAPI");
-               break;
-       default:
-               debug("Unknown client authentication type");
-       }
-       return(0);
-}
-
-/*
- * Clean our environment on startup. This means removing any environment
- * strings that might inadvertantly been in root's environment and 
- * could cause serious security problems if we think we set them.
- */
-void
-ssh_gssapi_clean_env(void)
-{
-  char *envstr;
-  int envstr_index;
-
-  
-   for (envstr_index = 0;
-       (envstr = delegation_env[envstr_index]) != NULL;
-       envstr_index++) {
-
-     if (getenv(envstr)) {
-       debug("Clearing environment variable %s", envstr);
-       gssapi_unsetenv(envstr);
-     }
-   }
-}
-
-/*
- * Wrapper around unsetenv.
+ * 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.
  */
-static void
-gssapi_unsetenv(const char *var)
-{
-#ifdef HAVE_UNSETENV
-    unsetenv(var);
-
-#else /* !HAVE_UNSETENV */
-    extern char **environ;
-    char **p1 = environ;       /* New array list */
-    char **p2 = environ;       /* Current array list */
-    int len = strlen(var);
-
-    /*
-     * Walk through current environ array (p2) copying each pointer
-     * to new environ array (p1) unless the pointer is to the item
-     * we want to delete. Copy happens in place.
-     */
-    while (*p2) {
-       if ((strncmp(*p2, var, len) == 0) &&
-           ((*p2)[len] == '=')) {
-           /*
-            * *p2 points at item to be deleted, just skip over it
-            */
-           p2++;
-       } else {
-           /*
-            * *p2 points at item we want to save, so copy it
-            */
-           *p1 = *p2;
-           p1++;
-           p2++;
-       }
-    }
-
-    /* And make sure new array is NULL terminated */
-    *p1 = NULL;
-#endif /* HAVE_UNSETENV */
-}
-
 char * 
-ssh_server_gssapi_mechanisms() {
+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;
-       int             mech_count=0;
        char *          mechs;
-       Gssctxt *       ctx = NULL;     
 
        if (datafellows & SSH_OLD_GSSAPI) return NULL;
        
-       PRIVSEP(gss_indicate_mechs(&min_status, &supported));
+       ssh_gssapi_supported_oids(&supported);
        
-       buffer_init(&buf);      
+       buffer_init(&buf);
 
-       do {
+       while(supported_mechs[i]->name != NULL) {
                if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                       &supported_mechs[i].oid,
+                                                       &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 (++mech_count > 1) {
-                                   buffer_append(&buf, ",", 1);
-                               }
-                               buffer_append(&buf, gssprefix,
-                                             strlen(gssprefix));
-                               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, gssprefix,
-                                     supported_mechs[i].enc_name);
-                       } else {
-                           debug("no credentials for GSSAPI mechanism %s",
-                                 supported_mechs[i].name);
-                       }
-               } else {
+                   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);
+                         supported_mechs[i]->name);
                }
-       } while (supported_mechs[++i].name != NULL);
+               ssh_gssapi_delete_ctx(&ctx);
+               i++;
+       }
        
        buffer_put_char(&buf,'\0');
        
@@ -711,16 +156,8 @@ ssh_server_gssapi_mechanisms() {
           return(mechs);
 }
 
-OM_uint32
-ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) {
-       if (*ctx) ssh_gssapi_delete_ctx(ctx);
-       ssh_gssapi_build_ctx(ctx);
-       ssh_gssapi_set_oid(*ctx,oid);
-       return(ssh_gssapi_acquire_cred(*ctx));
-}
-
 void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
-       enum ssh_gss_id i =0;
+       int i =0;
        OM_uint32 maj_status,min_status;
        int present;
        gss_OID_set supported;
@@ -728,22 +165,69 @@ void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
        gss_create_empty_oid_set(&min_status,oidset);
        PRIVSEP(gss_indicate_mechs(&min_status, &supported));
 
-       while (supported_mechs[i].name!=NULL) {
+       while (supported_mechs[i]->name!=NULL) {
                if ((maj_status=gss_test_oid_set_member(&min_status,
-                                                      &supported_mechs[i].oid,
+                                                      &supported_mechs[i]->oid,
                                                       supported,
                                                       &present))) {
                        present=0;
                }
                if (present) {
                        gss_add_oid_set_member(&min_status,
-                                              &supported_mechs[i].oid,
+                                              &supported_mechs[i]->oid,
                                               oidset); 
                }
                i++;
        }
 }      
 
+/* Find out which GSS type (out of the list we define in ssh-gss.h) a
+ * particular connection is using 
+ */
+ssh_gssapi_mech *
+ssh_gssapi_get_ctype(Gssctxt *ctxt) {
+       int i=0;
+       
+       while(supported_mechs[i]->name!=NULL) {
+           if (supported_mechs[i]->oid.length == ctxt->oid->length &&
+               (memcmp(supported_mechs[i]->oid.elements,
+                       ctxt->oid->elements,ctxt->oid->length)==0)) {
+               return supported_mechs[i];
+           }
+           i++;
+       }
+       return NULL;
+}
+
+/* Set the GSS context's OID to the oid indicated by the given key exchange
+ * name. */
+gss_OID 
+ssh_gssapi_id_kex(Gssctxt *ctx, 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);
+
+  if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i]->oid);
+
+  debug("using GSSAPI mechanism %s (%s%s)", supported_mechs[i]->name,
+       KEX_GSS_SHA1, supported_mechs[i]->enc_name);
+
+  return &supported_mechs[i]->oid;
+}
+
 /* Wrapper arround accept_sec_context
  * Requires that the context contains:
  *    oid              
@@ -752,10 +236,10 @@ void ssh_gssapi_supported_oids(gss_OID_set *oidset) {
 OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
                                gss_buffer_desc *send_tok, OM_uint32 *flags) 
 {
-       OM_uint32 maj_status, min_status;
+       OM_uint32 status;
        gss_OID mech;
        
-       maj_status=gss_accept_sec_context(&min_status,
+       ctx->major=gss_accept_sec_context(&ctx->minor,
                                          &ctx->context,
                                          ctx->creds,
                                          recv_tok,
@@ -766,8 +250,8 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
                                          flags,
                                          NULL,
                                          &ctx->client_creds);
-       if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_send_error(ctx->oid,maj_status,min_status);
+       if (GSS_ERROR(ctx->major)) {
+               ssh_gssapi_error(ctx);
        }
        
        if (ctx->client_creds) {
@@ -777,59 +261,122 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok,
        }
 
        /* FIXME: We should check that the me
-        * the one that we asked for (in ctx->oid) */
+       * the one that we asked for (in ctx->oid) */
 
-       ctx->status=maj_status;
+       status=ctx->major;
        
        /* Now, if we're complete and we have the right flags, then
-        * we flag the user as also having been authenticated
-        */
+       * we flag the user as also having been authenticated
+       */
        
        if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && 
                               (*flags & GSS_C_INTEG_FLAG))) &&
-           (maj_status == GSS_S_COMPLETE)) {
-               if (ssh_gssapi_getclient(ctx,&gssapi_client_type,
-                                        &gssapi_client_name,
-                                        &gssapi_client_creds))
+           (ctx->major == GSS_S_COMPLETE)) {
+               if (ssh_gssapi_getclient(ctx,&gssapi_client.mech,
+                                        &gssapi_client.name,
+                                        &gssapi_client.creds))
                        fatal("Couldn't convert client name");
        }
 
-       return(maj_status);
+       /* Make sure that the getclient call hasn't stamped on this */
+       return(status);
+}
+
+/* Extract the client details from a given context. This can only reliably
+ * be called once for a context */
+
+OM_uint32 
+ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type,
+                    gss_buffer_desc *name, gss_cred_id_t *creds) {
+
+       *type=ssh_gssapi_get_ctype(ctx);
+       if ((ctx->major=gss_display_name(&ctx->minor,ctx->client,name,NULL))) {
+               ssh_gssapi_error(ctx);
+               return(ctx->major);
+       }
+       
+       /* This is icky. There appears to be no way to copy this structure,
+       * rather than the pointer to it, so we simply copy the pointer and
+       * mark the originator as empty so we don't destroy it. 
+       */
+       *creds=ctx->client_creds;
+       ctx->client_creds=GSS_C_NO_CREDENTIAL;
+       return(ctx->major);
 }
 
 void
-ssh_gssapi_send_error(gss_OID mech, OM_uint32 major_status,
-                     OM_uint32 minor_status) {
-       OM_uint32 lmaj, lmin;
-        gss_buffer_desc msg = {0,NULL};
-        OM_uint32 ctx;
-        
-        ctx = 0;
-       /* The GSSAPI error */
-        do {
-               lmaj = PRIVSEP(gss_display_status(&lmin, major_status,
-                                                 GSS_C_GSS_CODE,
-                                                 mech,
-                                                 &ctx, &msg));
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       packet_send_debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);         
-
-        /* The mechanism specific error */
-        do {
-               lmaj = PRIVSEP(gss_display_status(&lmin, minor_status,
-                                                 GSS_C_MECH_CODE,
-                                                 mech,
-                                                 &ctx, &msg));
-               if (lmaj == GSS_S_COMPLETE) {
-                       debug((char *)msg.value);
-                       packet_send_debug((char *)msg.value);
-                       (void) gss_release_buffer(&lmin, &msg);
-               }
-        } while (ctx!=0);
+ssh_gssapi_cleanup_creds(void *ignored)
+{
+       if (gssapi_client.store.filename!=NULL) {
+               /* Unlink probably isn't sufficient */
+               debug("removing gssapi cred file\"%s\"",gssapi_client.store.filename);
+               unlink(gssapi_client.store.filename);
+       }
+}
+
+void 
+ssh_gssapi_storecreds()
+{
+       if (gssapi_client.mech && gssapi_client.mech->storecreds) {
+               (*gssapi_client.mech->storecreds)(&gssapi_client);
+               if (options.gss_cleanup_creds) {
+                       fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
+               }
+       } else {
+               debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
+       }
 }
 
-#endif /* GSSAPI */
+/* This allows GSSAPI methods to do things to the childs environment based
+ * on the passed authentication process and credentials.
+ *
+ * Question: If we didn't use userauth_external for some reason, should we
+ * still delegate credentials?
+ */
+void 
+ssh_gssapi_do_child(char ***envp, u_int *envsizep) 
+{
+
+       if (gssapi_client.store.envvar!=NULL && 
+           gssapi_client.store.envval!=NULL) {
+           
+               debug("Setting %s to %s", gssapi_client.store.envvar,
+                                         gssapi_client.store.envval);                            
+               child_set_env(envp, envsizep, gssapi_client.store.envvar, 
+                                             gssapi_client.store.envval);
+       }
+}
+
+int
+ssh_gssapi_userok(char *user)
+{
+       if (gssapi_client.name.length==0 || 
+           gssapi_client.name.value==NULL) {
+               debug("No suitable client data");
+               return 0;
+       }
+       if (gssapi_client.mech && gssapi_client.mech->userok) {
+               return((*gssapi_client.mech->userok)(&gssapi_client,user));
+       } else {
+               debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
+       }
+       return(0);
+}
+
+int
+ssh_gssapi_localname(char **user)
+{
+       *user = NULL;
+       if (gssapi_client.name.length==0 || 
+           gssapi_client.name.value==NULL) {
+               debug("No suitable client data");
+               return(0);;
+       }
+       if (gssapi_client.mech && gssapi_client.mech->localname) {
+               return((*gssapi_client.mech->localname)(&gssapi_client,user));
+       } else {
+               debug("Unknown client authentication type");
+       }
+       return(0);
+}
+#endif
index 3269d264ce0e54a0d3a500ebd92dcd9b81d6a187..612b02f04e0e204e300c47cd0bc111e3f2d5b224 100644 (file)
@@ -300,8 +300,7 @@ 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_SHA1, sizeof(KEX_GSS_SHA1)-1) == 0) {
                k->kex_type = KEX_GSS_GRP1_SHA1;
 #endif
        } else
index 74a86fbed4b63e68be6d22b114d71b3b2f01096e..d907e5ab10f86535dcacb1df7403a3e0de27f34f 100644 (file)
@@ -114,13 +114,13 @@ struct Kex {
        Buffer  peer;
        int     done;
        int     flags;
-       char    *host;
+       char    *host;
        char    *client_version_string;
        char    *server_version_string;
+       struct  KexOptions options;
        int     (*verify_host_key)(Key *);
        Key     *(*load_host_key)(int);
        int     (*host_key_index)(Key *);
-       struct  KexOptions options;
        void    (*kex[KEX_MAX])(Kex *);
 };
 
@@ -137,11 +137,9 @@ void        kexdh_client(Kex *);
 void    kexdh_server(Kex *);
 void    kexgex_client(Kex *);
 void    kexgex_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 *
@@ -150,11 +148,6 @@ kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
 u_char *
 kexgex_hash(char *, char *, char *, int, char *, int, u_char *, int,
     int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *);
-#ifdef GSSAPI
-u_char *
-kex_gssapi_hash(char *, char *, char *, int, char *, int, u_char *, int,
-    BIGNUM *, BIGNUM *, BIGNUM *);
-#endif
 
 #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
 void   dump_digest(char *, u_char *, int);
diff --git a/openssh/kexgss.c b/openssh/kexgss.c
deleted file mode 100644 (file)
index f2d5425..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "includes.h"
-
-#ifdef GSSAPI
-
-#include <openssl/crypto.h>
-#include <openssl/bn.h>
-
-#include "buffer.h"
-#include "bufaux.h"
-#include "ssh2.h"
-#include "kex.h"
-
-/* This is now the same as the DH hash ... */
-
-u_char *
-kex_gssapi_hash(
-    char *client_version_string,
-    char *server_version_string,
-    char *ckexinit, int ckexinitlen,
-    char *skexinit, int skexinitlen,
-    u_char *serverhostkeyblob, int sbloblen,
-    BIGNUM *client_dh_pub,
-    BIGNUM *server_dh_pub,
-    BIGNUM *shared_secret)
-{
-       Buffer b;
-       static u_char digest[EVP_MAX_MD_SIZE];
-       EVP_MD *evp_md = EVP_sha1();
-       EVP_MD_CTX md;
-
-       buffer_init(&b);
-       buffer_put_string(&b, client_version_string, strlen(client_version_string));
-       buffer_put_string(&b, server_version_string, strlen(server_version_string));
-
-       /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
-       buffer_put_int(&b, ckexinitlen+1);
-       buffer_put_char(&b, SSH2_MSG_KEXINIT);
-       buffer_append(&b, ckexinit, ckexinitlen);
-       buffer_put_int(&b, skexinitlen+1);
-       buffer_put_char(&b, SSH2_MSG_KEXINIT);
-       buffer_append(&b, skexinit, skexinitlen);
-
-       buffer_put_string(&b, serverhostkeyblob, sbloblen);
-       buffer_put_bignum2(&b, client_dh_pub);
-       buffer_put_bignum2(&b, server_dh_pub);
-       buffer_put_bignum2(&b, shared_secret);
-
-#ifdef DEBUG_KEX
-       buffer_dump(&b);
-#endif
-       EVP_DigestInit(&md, evp_md);
-       EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
-       EVP_DigestFinal(&md, digest, NULL);
-
-       buffer_free(&b);
-
-#ifdef DEBUG_KEX
-       dump_digest("hash", digest, evp_md->md_size);
-#endif
-       return digest;
-}
-
-#endif /* GSSAPI */
index 8cf27306fdbed1bd2d02b7ca111e67eb2e2ffde7..7e3729eea6edf2b6a934cde34cd9a232d5713e86 100644 (file)
@@ -38,7 +38,6 @@
 #include "dh.h"
 #include "ssh2.h"
 #include "ssh-gss.h"
-#include "monitor_wrap.h"
 #include "canohost.h"
 
 
@@ -55,13 +54,15 @@ kexgss_client(Kex *kex)
        unsigned char *kbuf;
        unsigned char *hash;
        unsigned char *serverhostkey;
+       char *msg;
+       char *lang;
        int type = 0;
        int first = 1;
-       int slen = 0;
+       int slen = 0, strlen;
        
        /* Initialise our GSSAPI world */
        ssh_gssapi_build_ctx(&ctxt);
-       if (ssh_gssapi_id_kex(ctxt,kex->name)==NULL) {
+       if (ssh_gssapi_client_id_kex(ctxt,kex->name)==NULL) {
                fatal("Couldn't identify host exchange");
        }
        if (ssh_gssapi_import_name(ctxt,get_canonical_hostname(1))) {
@@ -81,7 +82,7 @@ kexgss_client(Kex *kex)
        }
                
        token_ptr = GSS_C_NO_BUFFER;
-                        
+                       
        do {
                debug("Calling gss_init_sec_context");
                
@@ -141,20 +142,20 @@ kexgss_client(Kex *kex)
                                debug("Received GSSAPI_CONTINUE");
                                if (maj_status == GSS_S_COMPLETE) 
                                        fatal("GSSAPI Continue received from server when complete");
-                               recv_tok.value=packet_get_string(&slen);
-                               recv_tok.length=slen; /* int vs. size_t */
+                               recv_tok.value=packet_get_string(&strlen);
+                               recv_tok.length=strlen; /* int vs. size_t */
                                break;
                        case SSH2_MSG_KEXGSS_COMPLETE:
                                debug("Received GSSAPI_COMPLETE");
                                packet_get_bignum2(dh_server_pub);
-                               msg_tok.value=packet_get_string(&slen);
-                               msg_tok.length=slen; /* int vs. size_t */
+                               msg_tok.value=packet_get_string(&strlen);
+                               msg_tok.length=strlen; /* int vs. size_t */
 
                                /* Is there a token included? */
                                if (packet_get_char()) {
                                        recv_tok.value=
-                                           packet_get_string(&slen);
-                                       recv_tok.length=slen; /* int/size_t */
+                                           packet_get_string(&strlen);
+                                       recv_tok.length=strlen; /*int/size_t*/
                                        /* If we're already complete - protocol error */
                                        if (maj_status == GSS_S_COMPLETE)
                                                packet_disconnect("Protocol error: received token when complete");
@@ -164,6 +165,13 @@ kexgss_client(Kex *kex)
                                                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);
+                               fatal(msg);
                        default:
                                packet_disconnect("Protocol error: didn't expect packet type %d",
                                type);
@@ -193,8 +201,8 @@ kexgss_client(Kex *kex)
         memset(kbuf, 0, klen);
         xfree(kbuf);
         
-       slen=0;
-        hash = kex_gssapi_hash(
+        /* 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),
index ea17b2d15fbb93cb43cb8a7013d474fe69399eb8..7cb068da008721aedc1c2c5b70cd1be003c39395 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "ssh2.h"
 #include "ssh-gss.h"
 #include "monitor_wrap.h"
-#include "canohost.h"
+
+static void kex_gss_send_error(Gssctxt *ctxt);
 
 void
 kexgss_server(Kex *kex)
 {
-
        OM_uint32 maj_status, min_status;
        
        /* 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.*/
+       * output variable) as a means of triggering mechanism specific 
+       * features. Initializing it to zero avoids inadvertently 
+       * activating this non-standard behaviour.*/
 
        OM_uint32 ret_flags = 0;
        gss_buffer_desc gssbuf,send_tok,recv_tok,msg_tok;
@@ -62,8 +62,8 @@ kexgss_server(Kex *kex)
         BIGNUM *shared_secret = NULL;
         BIGNUM *dh_client_pub = NULL;
        int type =0;
-       gss_OID oid;
        u_int slen;
+       gss_OID oid;
        
        /* Initialise GSSAPI */
 
@@ -75,9 +75,11 @@ kexgss_server(Kex *kex)
        
        debug2("%s: Acquiring credentials",__func__);
        
-       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid))))
-          packet_disconnect("Unable to acquire credentials for the server");
-
+       if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt,oid)))) {
+               kex_gss_send_error(ctxt);
+               packet_disconnect("Unable to acquire credentials for the server");
+        }
+                                                                                                                                
        do {
                debug("Wait SSH2_MSG_GSSAPI_INIT");
                type = packet_read();
@@ -91,7 +93,7 @@ kexgss_server(Kex *kex)
                        dh_client_pub = BN_new();
                        
                        if (dh_client_pub == NULL)
-                               fatal("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 */
@@ -108,17 +110,18 @@ kexgss_server(Kex *kex)
                }
                
                maj_status=PRIVSEP(ssh_gssapi_accept_ctx(ctxt,&recv_tok, 
-                                                        &send_tok, &ret_flags));
+                                                       &send_tok, &ret_flags));
 
                gss_release_buffer(&min_status,&recv_tok);
-
+               
 #ifdef GSS_C_GLOBUS_LIMITED_PROXY_FLAG
                 if (ret_flags & GSS_C_GLOBUS_LIMITED_PROXY_FLAG) {
                         packet_disconnect("Limited proxy is not allowed in gssapi key exchange.");
                 }
 #endif
-               
-               if (maj_status & GSS_S_CONTINUE_NEEDED) {
+
+               if ((maj_status & GSS_S_CONTINUE_NEEDED) ||
+                   (GSS_ERROR(maj_status) && send_tok.length>0)) {
                        debug("Sending GSSAPI_CONTINUE");
                        packet_start(SSH2_MSG_KEXGSS_CONTINUE);
                        packet_put_string(send_tok.value,send_tok.length);
@@ -129,21 +132,17 @@ kexgss_server(Kex *kex)
        } while (maj_status & GSS_S_CONTINUE_NEEDED);
 
        if (GSS_ERROR(maj_status)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
+               kex_gss_send_error(ctxt);
                packet_disconnect("gssapi key exchange handshake failed");
        }
-
+       
        debug("gss_complete");
-       if (!(ret_flags & GSS_C_MUTUAL_FLAG)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
-               packet_disconnect("gssapi mutual authentication failed");
-       }
+       if (!(ret_flags & GSS_C_MUTUAL_FLAG))
+               packet_disconnect("gssapi_mutual authentication failed");
                
-       if (!(ret_flags & GSS_C_INTEG_FLAG)) {
-               ssh_gssapi_send_error(oid,maj_status,min_status);
+       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);
        
@@ -159,7 +158,8 @@ kexgss_server(Kex *kex)
        memset(kbuf, 0, klen);
        xfree(kbuf);
        
-        hash = kex_gssapi_hash(
+       /* 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),
@@ -181,12 +181,8 @@ kexgss_server(Kex *kex)
        gssbuf.length = 20; /* Hashlen appears to always be 20 */
        
        if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt,&gssbuf,&msg_tok)))) {
-               if (ctxt) { /* may be NULL under privsep */
-                   ssh_gssapi_send_error(ctxt->oid,maj_status,min_status);
-               } else {
-                   ssh_gssapi_send_error(GSS_C_NO_OID,maj_status,min_status);
-               }
-               packet_disconnect("Couldn't get MIC");
+               kex_gss_send_error(ctxt);
+               fatal("Couldn't get MIC");
        }
        
        packet_start(SSH2_MSG_KEXGSS_COMPLETE);
@@ -210,7 +206,7 @@ kexgss_server(Kex *kex)
        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 */
+       * using privsep */
        ssh_gssapi_delete_ctx(&ctxt);
        
        DH_free(dh);
@@ -220,4 +216,22 @@ kexgss_server(Kex *kex)
        kex_finish(kex);
 }
 
+static void 
+kex_gss_send_error(Gssctxt *ctxt) {
+       char *errstr;
+       OM_uint32 maj,min;
+               
+       errstr=PRIVSEP(ssh_gssapi_last_error(ctxt,&maj,&min));
+       if (errstr) {
+               packet_start(SSH2_MSG_KEXGSS_ERROR);
+               packet_put_int(maj);
+               packet_put_int(min);
+               packet_put_cstring(errstr);
+               packet_put_cstring("");
+               packet_send();
+               packet_write_wait();
+               /* XXX - We should probably log the error locally here */
+               xfree(errstr);
+       }
+}
 #endif /* GSSAPI */
index b91f30b22f6b3e44a9e5cf225f95cb6d322c2813..1350cddb1d5fc847c4606b71236f26fa89df94c0 100644 (file)
@@ -3,12 +3,16 @@
 use Convert::ASN1 qw(:tag);
 use Digest::MD5 qw(md5);
 use MIME::Base64;
+use Data::Dumper;
  
 $oid=shift;
-$encoded=encode_object_id($oid);
+my $asn=Convert::ASN1->new;
+$asn->prepare("oid OBJECT IDENTIFIER");
+$encoded=$asn->encode(oid => $oid);
+Convert::ASN1::asn_dump($encoded);
+print Dumper($asn->decode($encoded));
 
 @entries=unpack("C*",$encoded);
-shift @entries; # Get rid of the NULL
 
 print "DER representation: ";
 foreach $entry (@entries) {
index 65acd443407cb8cbb61cb7bd4b864e6ff5cf2dea..e36cc23571dea8a25306d206865ce073ca6d3e94 100644 (file)
@@ -125,6 +125,13 @@ int mm_answer_sessid(int, Buffer *);
 int mm_answer_pam_start(int, Buffer *);
 #endif
 
+#ifdef KRB4
+int mm_answer_krb4(int, Buffer *);
+#endif
+#ifdef KRB5
+int mm_answer_krb5(int, Buffer *);
+#endif
+
 #ifdef GSSAPI
 int mm_answer_gss_setup_ctx(int, Buffer *);
 int mm_answer_gss_accept_ctx(int, Buffer *);
@@ -132,20 +139,13 @@ int mm_answer_gss_userok(int, Buffer *);
 int mm_answer_gss_localname(int, Buffer *);
 int mm_answer_gss_sign(int, Buffer *);
 int mm_answer_gss_indicate_mechs(int, Buffer *);
-int mm_answer_gss_display_status(int, Buffer *);
+int mm_answer_gss_error(int, Buffer *);
 #endif
 
 #ifdef GSI
 int mm_answer_gsi_gridmap(int, Buffer *);
 #endif
 
-#ifdef KRB4
-int mm_answer_krb4(int, Buffer *);
-#endif
-#ifdef KRB5
-int mm_answer_krb5(int, Buffer *);
-#endif
-
 static Authctxt *authctxt;
 static BIGNUM *ssh1_challenge = NULL;  /* used for ssh1 rsa auth */
 
@@ -196,9 +196,9 @@ struct mon_table mon_dispatch_proto20[] = {
     {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
     {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
     {MONITOR_REQ_GSSLOCALNAME, MON_AUTH, mm_answer_gss_localname},
+    {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error},
 #endif
     {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed},
     {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify},
@@ -211,7 +211,7 @@ struct mon_table mon_dispatch_postauth20[] = {
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
     {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
+    {MONITOR_REQ_GSSERR, 0, mm_answer_gss_error},
 #endif
     {MONITOR_REQ_MODULI, 0, mm_answer_moduli},
     {MONITOR_REQ_SIGN, 0, mm_answer_sign},
@@ -244,7 +244,6 @@ struct mon_table mon_dispatch_proto15[] = {
     {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign},
     {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok},
     {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, MON_ISAUTH, mm_answer_gss_display_status},
 #endif
 #ifdef GSI
     {MONITOR_REQ_GSIGRIDMAP, MON_PERMIT, mm_answer_gsi_gridmap},
@@ -267,7 +266,6 @@ struct mon_table mon_dispatch_postauth15[] = {
     {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx},
     {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign},
     {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs},
-    {MONITOR_REQ_GSSSTAT, 0, mm_answer_gss_display_status},
 #endif
     {MONITOR_REQ_PTY, MON_ONCE, mm_answer_pty},
     {MONITOR_REQ_PTYCLEANUP, MON_ONCE, mm_answer_pty_cleanup},
@@ -326,7 +324,7 @@ monitor_child_preauth(struct monitor *pmonitor)
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
 #endif
        } else {
                mon_dispatch = mon_dispatch_proto15;
@@ -335,7 +333,7 @@ monitor_child_preauth(struct monitor *pmonitor)
 #ifdef GSSAPI          
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1);
                monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1);
-               monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+               monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
 #endif
 #ifdef GSI
                monitor_permit(mon_dispatch, MONITOR_REQ_GSIGRIDMAP, 1);
@@ -395,7 +393,7 @@ monitor_child_postauth(struct monitor *pmonitor)
                monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1);
        }
 #ifdef GSSAPI          
-       monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTAT, 1);
+       monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1);
 #endif
        if (!no_pty_flag) {
                monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1);
@@ -1538,6 +1536,9 @@ mm_get_kex(Buffer *m)
        kex->we_need = buffer_get_int(m);
        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
        kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
+#ifdef GSSAPI
+       kex->kex[KEX_GSS_GRP1_SHA1] =kexgss_server;
+#endif
        kex->server = 1;
        kex->hostkey_type = buffer_get_int(m);
        kex->kex_type = buffer_get_int(m);
@@ -1774,11 +1775,13 @@ mm_answer_gss_userok(int socket, Buffer *m) {
         debug3("%s: sending result %d", __func__, authenticated);
         mm_request_send(socket, MONITOR_ANS_GSSUSEROK, m);
 
+       /* XXX - auth method could also be 'external' */
        auth_method="gssapi";
        
         /* Monitor loop will terminate if authenticated */
         return(authenticated);
 }
+
 int
 mm_answer_gss_localname(int socket, Buffer *m) {
        char *name;
@@ -1857,41 +1860,21 @@ mm_answer_gss_indicate_mechs(int socket, Buffer *m) {
 }
 
 int
-mm_answer_gss_display_status(int socket, Buffer *m) {
-        OM_uint32 major,minor,status_value,message_context;
-       int status_type;
-       gss_OID_desc mech_type_desc;
-       gss_OID mech_type;
-       gss_buffer_desc status_string;
-       u_int length;
-
-       status_value = buffer_get_int(m);
-       status_type = buffer_get_int(m);
-       mech_type_desc.elements = buffer_get_string(m, &length);
-       mech_type_desc.length = length;
-       if (length != 0) {
-           mech_type = &mech_type_desc;
-       } else if (gsscontext) {
-           mech_type = gsscontext->oid;
-       } else {
-           mech_type = GSS_C_NO_OID;
-       }
-       message_context = buffer_get_int(m);
-
-       major=gss_display_status(&minor, status_value, status_type, mech_type,
-                                &message_context, &status_string);
+mm_answer_gss_error(int socket, Buffer *m) {
+        OM_uint32 major,minor;
+        char *msg;
 
+       msg=ssh_gssapi_last_error(gsscontext,&major,&minor);
        buffer_clear(m);
-       buffer_put_int(m, message_context);
-       buffer_put_string(m, status_string.value, status_string.length);
-
-       mm_request_send(socket,MONITOR_ANS_GSSSTAT,m);
+       buffer_put_int(m,major);
+       buffer_put_int(m,minor);
+       buffer_put_cstring(m,msg);
 
-       if (mech_type_desc.elements) {
-           xfree(mech_type_desc.elements);
-       }
+       mm_request_send(socket,MONITOR_ANS_GSSERR,m);
 
-       return 0;
+       xfree(msg);
+       
+        return(0);
 }
 
 #endif /* GSSAPI */
index 80261a543b0ea3764f2527c1c9c119074b4c293e..2b722fa4f51be4cf49c9b8222603151b518a1db8 100644 (file)
@@ -39,14 +39,16 @@ enum monitor_reqtype {
        MONITOR_REQ_BSDAUTHRESPOND, MONITOR_ANS_BSDAUTHRESPOND,
        MONITOR_REQ_SKEYQUERY, MONITOR_ANS_SKEYQUERY,
        MONITOR_REQ_SKEYRESPOND, MONITOR_ANS_SKEYRESPOND,
+#ifdef GSSAPI
        MONITOR_REQ_GSSSETUP,MONITOR_ANS_GSSSETUP,
        MONITOR_REQ_GSSSTEP,MONITOR_ANS_GSSSTEP,
        MONITOR_REQ_GSSSIGN,MONITOR_ANS_GSSSIGN,
        MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS,
-       MONITOR_REQ_GSSSTAT,MONITOR_ANS_GSSSTAT,
        MONITOR_REQ_GSSUSEROK,MONITOR_ANS_GSSUSEROK,
        MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME,
        MONITOR_REQ_GSIGRIDMAP,MONITOR_ANS_GSIGRIDMAP,
+       MONITOR_REQ_GSSERR,MONITOR_ANS_GSSERR,
+#endif
        MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED,
        MONITOR_REQ_KEYVERIFY, MONITOR_ANS_KEYVERIFY,
        MONITOR_REQ_KEYEXPORT,
index 705fc1677226b9091edc0a3343782b1ade91d175..b1552fd7ef0f47dc41309f0be83000bf1c4367f4 100644 (file)
@@ -952,6 +952,77 @@ mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16])
 
        return (success);
 }
+
+#ifdef KRB4
+int
+mm_auth_krb4(Authctxt *authctxt, void *_auth, char **client, void *_reply)
+{
+       KTEXT auth, reply;
+       Buffer m;
+       u_int rlen;
+       int success = 0;
+       char *p;
+
+       debug3("%s entering", __func__);
+       auth = _auth;
+       reply = _reply;
+
+       buffer_init(&m);
+       buffer_put_string(&m, auth->dat, auth->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB4, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB4, &m);
+
+       success = buffer_get_int(&m);
+       if (success) {
+               *client = buffer_get_string(&m, NULL);
+               p = buffer_get_string(&m, &rlen);
+               if (rlen >= MAX_KTXT_LEN)
+                       fatal("%s: reply from monitor too large", __func__);
+               reply->length = rlen;
+               memcpy(reply->dat, p, rlen);
+               memset(p, 0, rlen);
+               xfree(p);
+       }
+       buffer_free(&m);
+       return (success);
+}
+#endif
+
+#ifdef KRB5
+int
+mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
+{
+       krb5_data *tkt, *reply;
+       Buffer m;
+       int success;
+
+       debug3("%s entering", __func__);
+       tkt = (krb5_data *) argp;
+       reply = (krb5_data *) resp;
+
+       buffer_init(&m);
+       buffer_put_string(&m, tkt->data, tkt->length);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB5, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB5, &m);
+
+       success = buffer_get_int(&m);
+       if (success) {
+               u_int len;
+
+               *userp = buffer_get_string(&m, NULL);
+               reply->data = buffer_get_string(&m, &len);
+               reply->length = len;
+       } else {
+               memset(reply, 0, sizeof(*reply));
+               *userp = NULL;
+       }
+
+       buffer_free(&m);
+       return (success);
+}
+#endif
 #ifdef GSSAPI
 OM_uint32
 mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
@@ -965,32 +1036,33 @@ mm_ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) {
         buffer_put_string(&m,oid->elements,oid->length);
 
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSETUP, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSSETUP",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSETUP, &m);
+
         major=buffer_get_int(&m);
 
+       buffer_free(&m);
         return(major);
 }
 
 OM_uint32
 mm_ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *in,
                          gss_buffer_desc *out, OM_uint32 *flags) {
-
         Buffer m;
         OM_uint32 major;
 
         buffer_init(&m);
         buffer_put_string(&m, in->value, in->length);
-        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSSTEP", __func__);
+        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTEP, &m);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTEP, &m);
 
         major=buffer_get_int(&m);
         out->value=buffer_get_string(&m,&out->length);
         if (flags) *flags=buffer_get_int(&m);
 
+       buffer_free(&m);
+       
         return(major);
 }
 
@@ -1002,7 +1074,6 @@ mm_ssh_gssapi_userok(char *user) {
         buffer_init(&m);
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSUSEROK", __func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSUSEROK,
                                   &m);
 
@@ -1019,9 +1090,9 @@ mm_ssh_gssapi_localname(char **lname)
         Buffer m;
 
        buffer_init(&m);
+
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSLOCALNAME, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSLOCALNAME", __func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSLOCALNAME,
                                   &m);
 
@@ -1046,15 +1117,40 @@ mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) {
         buffer_put_string(&m, data->value, data->length);
 
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSIGN, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSSIGN",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSIGN, &m);
+
         major=buffer_get_int(&m);
         hash->value = buffer_get_string(&m, &hash->length);
 
+       buffer_free(&m);
+       
         return(major);
 }
 
+char *
+mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) {
+       Buffer m;
+       OM_uint32 maj,min;
+       char *errstr;
+       
+       buffer_init(&m);
+
+       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSERR, &m);
+       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSERR, &m);
+
+       maj = buffer_get_int(&m);
+       min = buffer_get_int(&m);
+
+       if (major) *major=maj;
+       if (minor) *minor=min;
+       
+       errstr=buffer_get_string(&m,NULL);
+
+       buffer_free(&m);
+       
+       return(errstr);
+}      
+       
 OM_uint32
 mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
 {
@@ -1066,7 +1162,6 @@ mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
 
        mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS,
                                  &m);
         major=buffer_get_int(&m);
@@ -1080,46 +1175,9 @@ mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set)
            lmajor=gss_add_oid_set_member(&lminor, &member_oid, mech_set);
        }
 
-        return(major);
-}
-
-OM_uint32
-mm_gss_display_status(OM_uint32 *minor_status, OM_uint32 status_value,
-                     int status_type, const gss_OID mech_type,
-                     OM_uint32 *message_context, gss_buffer_t status_string)
-{
-        Buffer m;
-       OM_uint32 major;
-
-       buffer_init(&m);
-
-       buffer_put_int(&m, status_value);
-       buffer_put_int(&m, status_type);
-       if (mech_type) {
-           buffer_put_string(&m, mech_type->elements, mech_type->length);
-       } else {
-           buffer_put_string(&m, "", 0);
-       }
-       if (message_context) {
-           buffer_put_int(&m, *message_context);
-       } else {
-           buffer_put_int(&m, 0);
-       }
-
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSSTAT, &m);
-
-        debug3("%s: waiting for MONITOR_ANS_GSSMECHS",__func__);
-        mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSSTAT,
-                                 &m);
+       buffer_free(&m);
        
-       if (message_context) {
-           *message_context = buffer_get_int(&m);
-       } else {
-           buffer_get_int(&m);
-       }
-       status_string->value = buffer_get_string(&m, &status_string->length);
-
-       return major;
+        return(major);
 }
 #endif /* GSSAPI */
 
@@ -1133,7 +1191,6 @@ int mm_gsi_gridmap(char *subject_name, char **lname)
        buffer_put_cstring(&m, subject_name);
         mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSIGRIDMAP, &m);
 
-        debug3("%s: waiting for MONITOR_ANS_GSIGRIDMAP", __func__);
         mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSIGRIDMAP,
                                   &m);
 
@@ -1153,74 +1210,3 @@ int mm_gsi_gridmap(char *subject_name, char **lname)
 }
 
 #endif /* GSI */
-
-#ifdef KRB4
-int
-mm_auth_krb4(Authctxt *authctxt, void *_auth, char **client, void *_reply)
-{
-       KTEXT auth, reply;
-       Buffer m;
-       u_int rlen;
-       int success = 0;
-       char *p;
-
-       debug3("%s entering", __func__);
-       auth = _auth;
-       reply = _reply;
-
-       buffer_init(&m);
-       buffer_put_string(&m, auth->dat, auth->length);
-
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB4, &m);
-       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB4, &m);
-
-       success = buffer_get_int(&m);
-       if (success) {
-               *client = buffer_get_string(&m, NULL);
-               p = buffer_get_string(&m, &rlen);
-               if (rlen >= MAX_KTXT_LEN)
-                       fatal("%s: reply from monitor too large", __func__);
-               reply->length = rlen;
-               memcpy(reply->dat, p, rlen);
-               memset(p, 0, rlen);
-               xfree(p);
-       }
-       buffer_free(&m);
-       return (success);
-}
-#endif
-
-#ifdef KRB5
-int
-mm_auth_krb5(void *ctx, void *argp, char **userp, void *resp)
-{
-       krb5_data *tkt, *reply;
-       Buffer m;
-       int success;
-
-       debug3("%s entering", __func__);
-       tkt = (krb5_data *) argp;
-       reply = (krb5_data *) resp;
-
-       buffer_init(&m);
-       buffer_put_string(&m, tkt->data, tkt->length);
-
-       mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KRB5, &m);
-       mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KRB5, &m);
-
-       success = buffer_get_int(&m);
-       if (success) {
-               u_int len;
-
-               *userp = buffer_get_string(&m, NULL);
-               reply->data = buffer_get_string(&m, &len);
-               reply->length = len;
-       } else {
-               memset(reply, 0, sizeof(*reply));
-               *userp = NULL;
-       }
-
-       buffer_free(&m);
-       return (success);
-}
-#endif
index 09766e73210d3cb22719815d7536a3b9fbb0acd5..f265f3400ac9dbdb20323494b2e700c9393af0b1 100644 (file)
@@ -70,11 +70,7 @@ int mm_ssh_gssapi_userok(char *user);
 int mm_ssh_gssapi_localname(char **user);
 OM_uint32 mm_gss_indicate_mechs(OM_uint32 *minor_status,
                                gss_OID_set *mech_set);
-OM_uint32 mm_gss_display_status(OM_uint32 *minor_status,
-                               OM_uint32 status_value,
-                               int status_type, const gss_OID mech_type,
-                               OM_uint32 *message_context,
-                               gss_buffer_t status_string);
+char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
 #endif
 
 #ifdef GSI
index 3f5f028ecd11aa2bd7c3cac3fdd618653f537665..71b3819af72fa5ef01c21648fb06f865540a6af2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved.
+ * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #define KEX_GSS_SHA1                                   "gss-group1-sha1-"
 
-enum ssh_gss_id {
-#ifdef KRB5
-       GSS_KERBEROS,
-#endif
-#ifdef GSI
-       GSS_GSI,
-#endif /* GSI */
-       GSS_LAST_ENTRY
-};
+typedef struct {
+        char *filename;
+        char *envvar;
+        char *envval;
+        void *data;
+} ssh_gssapi_ccache;
+
+typedef struct {
+       gss_buffer_desc name;
+       gss_cred_id_t   creds;
+       struct ssh_gssapi_mech_struct *mech;
+       ssh_gssapi_ccache store;
+} ssh_gssapi_client;
 
-typedef struct ssh_gss_mech_struct {
+typedef struct ssh_gssapi_mech_struct {
         char *enc_name;
         char *name;
         gss_OID_desc oid;
+       int (*dochild) (ssh_gssapi_client *);
+       int (*userok) (ssh_gssapi_client *, char *);
+       int (*localname) (ssh_gssapi_client *, char **);
+       void (*storecreds) (ssh_gssapi_client *);
 } ssh_gssapi_mech;
 
+
+
 typedef struct {
-       OM_uint32       status; /* both */
+       OM_uint32       major; /* both */
+       OM_uint32       minor; /* both */
        gss_ctx_id_t    context; /* both */
        gss_name_t      name; /* both */
        gss_OID         oid; /* both */
@@ -85,19 +96,17 @@ typedef struct {
        gss_cred_id_t   client_creds; /* server */
 } Gssctxt;
 
-extern ssh_gssapi_mech supported_mechs[];
-extern char gssprefix[];
-extern gss_buffer_desc gssapi_client_name;
-extern gss_cred_id_t   gssapi_client_creds;
-extern enum ssh_gss_id gssapi_client_type;
+extern ssh_gssapi_mech *supported_mechs[];
 
 char *ssh_gssapi_mechanisms(char *host);
-char *ssh_server_gssapi_mechanisms();
-gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
+char *ssh_gssapi_client_mechanisms(char *host);
+gss_OID ssh_gssapi_client_id_kex(Gssctxt *ctx, char *name);
+int  ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len);
 void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len);
 void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid);
 void ssh_gssapi_supported_oids(gss_OID_set *oidset);
-enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt);
+ssh_gssapi_mech *ssh_gssapi_get_ctype(Gssctxt *ctxt);
+gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name);
 
 OM_uint32 ssh_gssapi_import_name(Gssctxt *ctx, const char *host);
 OM_uint32 ssh_gssapi_acquire_cred(Gssctxt *ctx);
@@ -109,21 +118,21 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,
                                gss_buffer_desc *send_tok,
                                OM_uint32 *flags);
 OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx,
-                               enum ssh_gss_id *type,
+                               ssh_gssapi_mech **mech,
                                gss_buffer_desc *name,
                                gss_cred_id_t *creds);
-void ssh_gssapi_error(gss_OID mech,
-                     OM_uint32 major_status, OM_uint32 minor_status);
-void ssh_gssapi_send_error(gss_OID mech,
-                          OM_uint32 major_status,OM_uint32 minor_status);
+void ssh_gssapi_error(Gssctxt *ctx);
+char *ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min);
 void ssh_gssapi_build_ctx(Gssctxt **ctx);
 void ssh_gssapi_delete_ctx(Gssctxt **ctx);
-OM_uint32 ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid,char *host);
 OM_uint32 ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid);
 
+int ssh_gssapi_check_mechanism(gss_OID oid, char *host);
+
 /* In the server */
+gss_OID ssh_gssapi_server_id_kex(Gssctxt *ctx, char *name);
 int ssh_gssapi_userok(char *name);
-int ssh_gssapi_localname(char **lname);
+int ssh_gssapi_localname(char **user);
 void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit, 
                       Buffer *server_kexinit);
 
@@ -133,7 +142,7 @@ OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer,
 void ssh_gssapi_do_child(char ***envp, u_int *envsizep);                 
 void ssh_gssapi_cleanup_creds(void *ignored);
 void ssh_gssapi_storecreds();
-void ssh_gssapi_clean_env();
+char *ssh_gssapi_server_mechanisms();
 
 #ifdef GSI
 int gsi_gridmap(char *subject_name, char **mapped_name);
index 415304b36e918bfa299a1bd2970f42c229bfbea2..5b4eb82d1fc058011731af658be12ec504d832e1 100644 (file)
@@ -356,9 +356,6 @@ keygrab_ssh2(con *c)
        c->c_kex = kex_setup(myproposal);
        c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
        c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
-#ifdef GSSAPI
-       c->c_kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client;
-#endif
        c->c_kex->verify_host_key = hostjump;
 
        if (!(j = setjmp(kexjmp))) {
index 37b4c70b444858301854934e514a55a2334473a9..9838cc3b0d42ec2cb723c871081ed5fe02c0e2e8 100644 (file)
@@ -960,67 +960,68 @@ try_password_authentication(char *prompt)
 
 #ifdef GSSAPI
 #ifdef GSI
+static gss_OID_desc gsioid={9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"};
 char * get_gsi_name()
 {
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
   gss_name_t pname = GSS_C_NO_NAME;
   gss_buffer_desc tmpname;
   gss_buffer_t tmpnamed = &tmpname;
-  char *retname;
+  char *retname=NULL;
   gss_OID_set oidset;
   gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL;
+  Gssctxt *ctx = NULL;
 
-  gss_create_empty_oid_set(&min_stat,&oidset);
-  gss_add_oid_set_member(&min_stat,&supported_mechs[GSS_GSI].oid,&oidset);
-  maj_stat = gss_acquire_cred(&min_stat,
-                              GSS_C_NO_NAME,
-                              GSS_C_INDEFINITE,
-                              oidset,
-                              GSS_C_INITIATE,
-                              &gss_cred,
-                              NULL,
-                              NULL);
-
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ssh_gssapi_build_ctx(&ctx);
+
+  gss_create_empty_oid_set(&ctx->minor,&oidset);
+  gss_add_oid_set_member(&ctx->minor,&gsioid,&oidset);
+  ssh_gssapi_set_oid(ctx,&gsioid);
+  ctx->major = gss_acquire_cred(&ctx->minor,
+                               GSS_C_NO_NAME,
+                               GSS_C_INDEFINITE,
+                               oidset,
+                               GSS_C_INITIATE,
+                               &gss_cred,
+                               NULL,
+                               NULL);
+
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
 
   debug("calling gss_inquire_cred");
-  maj_stat = gss_inquire_cred(&min_stat,
-                              gss_cred,
-                              &pname,
-                              NULL,
-                              NULL,
-                              NULL);
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ctx->major = gss_inquire_cred(&ctx->minor,
+                               gss_cred,
+                               &pname,
+                               NULL,
+                               NULL,
+                               NULL);
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
 
-  maj_stat = gss_display_name(&min_stat,
-                             pname,
-                             tmpnamed,
-                             NULL);
-  if (maj_stat != GSS_S_COMPLETE) {
-      goto error;
+  ctx->major = gss_display_name(&ctx->minor,
+                               pname,
+                               tmpnamed,
+                               NULL);
+  if (ctx->major != GSS_S_COMPLETE) {
+      goto cleanup;
   }
   debug("gss_display_name finsished");
-  retname = (char *)malloc(tmpname.length + 1);
-  if (!retname) {
-      goto error;
-  }
+  retname = xmalloc(tmpname.length + 1);
   memcpy(retname, tmpname.value, tmpname.length);
   retname[tmpname.length] = '\0';
 
-  gss_release_name(&min_stat, &pname);
-  gss_release_buffer(&min_stat, tmpnamed);
+  gss_release_name(&ctx->minor, &pname);
+  gss_release_buffer(&ctx->minor, tmpnamed);
 
+ cleanup:
+  if (!retname) {
+      debug("Failed to set GSI username from credentials");
+      ssh_gssapi_error(ctx);
+  }
+  if (ctx) ssh_gssapi_delete_ctx(&ctx);
   return retname;
-
- error:
-  debug("Failed to set GSI username from credentials");
-  ssh_gssapi_error(&supported_mechs[GSS_GSI].oid, maj_stat, min_stat);
-  return NULL;
 }
 #endif /* GSI */
 
@@ -1037,8 +1038,6 @@ int try_gssapi_authentication(char *host, Options *options)
   gss_OID name_type;
   gss_OID_set gss_mechs, my_mechs;
   int my_mech_num, i, present;
-  OM_uint32 maj_stat;
-  OM_uint32 min_stat;
   int ret_stat = 0;                             /* 1 == success */
   OM_uint32 req_flags = 0;
   OM_uint32 ret_flags;
@@ -1047,6 +1046,8 @@ int try_gssapi_authentication(char *host, Options *options)
   unsigned int slen;
   Gssctxt *ctx = NULL;
 
+  ssh_gssapi_build_ctx(&ctx);
+
   xhost = xstrdup(get_canonical_hostname(1));
   resolve_localhost(&xhost);
 
@@ -1081,44 +1082,33 @@ int try_gssapi_authentication(char *host, Options *options)
 
   name_tok.value = service_name;
   name_tok.length = strlen(service_name) + 1;
-  maj_stat = gss_import_name(&min_stat, &name_tok,
-                             name_type, &target_name);
+  ctx->major = gss_import_name(&ctx->minor, &name_tok,
+                              name_type, &target_name);
 
   free(service_name);
   service_name = NULL;
 
-  if (maj_stat != GSS_S_COMPLETE) {
-    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+  if (ctx->major != GSS_S_COMPLETE) {
+    ssh_gssapi_error(ctx);
     goto cleanup;
   }
 
-  maj_stat = gss_indicate_mechs(&min_stat, &gss_mechs);
+  ctx->major = gss_indicate_mechs(&ctx->minor, &gss_mechs);
 
-  if (maj_stat != GSS_S_COMPLETE) {
-    ssh_gssapi_error(GSS_C_NO_OID, maj_stat, min_stat);
+  if (ctx->major != GSS_S_COMPLETE) {
+    ssh_gssapi_error(ctx);
     goto cleanup;
   }
 
   /* The GSSAPI supports the mechs in gss_mechs, but which ones do
      we have credentials for?  We only get one try, so we don't want
      to propose a mechanism we know is going to fail. */
-  maj_stat = gss_create_empty_oid_set(&min_stat, &my_mechs);
-  for (i=0; supported_mechs[i].name != NULL; i++) {
-      maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[i].oid,
-                                        gss_mechs, &present);
-      if (present) {
-         if (!GSS_ERROR(ssh_gssapi_client_ctx(&ctx, &supported_mechs[i].oid,
-                                              host))) {
-             maj_stat = gss_add_oid_set_member(&min_stat,
-                                               &supported_mechs[i].oid,
-                                               &my_mechs);
-             debug("GSSAPI mechanism %s supported", supported_mechs[i].name);
-         } else {
-             debug("no credentials for GSSAPI mechanism %s",
-                   supported_mechs[i].name);
-         }
-      } else {
-         debug("GSSAPI mechanism %s not supported", supported_mechs[i].name);
+  ctx->major = gss_create_empty_oid_set(&ctx->minor, &my_mechs);
+  for (i=0; i<gss_mechs->count; i++) {
+      if (ssh_gssapi_check_mechanism(&(gss_mechs->elements[i]), host)) {
+         ctx->major = gss_add_oid_set_member(&ctx->minor,
+                                             &(gss_mechs->elements[i]),
+                                             &my_mechs);
       }
   }
 
@@ -1137,20 +1127,19 @@ int try_gssapi_authentication(char *host, Options *options)
 #ifdef GSI
   /* Send GSI before Kerberos, because if GSI fails, we can always fall
      back and try regular Kerberos authentication with our Kerberos cred. */
-  maj_stat = gss_test_oid_set_member(&min_stat, &supported_mechs[GSS_GSI].oid,
-                                    my_mechs, &present);
+  ctx->major = gss_test_oid_set_member(&ctx->minor, &gsioid,
+                                      my_mechs, &present);
   if (present) {
-      packet_put_string(supported_mechs[GSS_GSI].oid.elements,
-                        supported_mechs[GSS_GSI].oid.length);
+      packet_put_string(gsioid.elements,gsioid.length);
   }
 #endif
   for (my_mech_num = 0; my_mech_num < my_mechs->count; my_mech_num++) {
 #ifdef GSI
       /* Skip GSI.  We already sent it above. */
       if ((my_mechs->elements[my_mech_num].length ==
-          supported_mechs[GSS_GSI].oid.length) &&
+          gsioid.length) &&
          memcmp(my_mechs->elements[my_mech_num].elements,
-                supported_mechs[GSS_GSI].oid.elements,
+                gsioid.elements,
                 my_mechs->elements[my_mech_num].length) == 0) {
          continue;
       }
@@ -1190,6 +1179,8 @@ int try_gssapi_authentication(char *host, Options *options)
   mech_oid.length = slen;      /* safe typecast */
   packet_get_all();
 
+  ssh_gssapi_set_oid(ctx, &mech_oid);
+
   /*
    * Perform the context-establishement loop.
    *
@@ -1210,12 +1201,12 @@ int try_gssapi_authentication(char *host, Options *options)
   gss_context = GSS_C_NO_CONTEXT;
 
   do {
-    maj_stat =
-      gss_init_sec_context(&min_stat,
+    ctx->major =
+      gss_init_sec_context(&ctx->minor,
                            GSS_C_NO_CREDENTIAL,
                            &gss_context,
                            target_name,
-                           &mech_oid,
+                           ctx->oid,
                            req_flags,
                            0,
                            NULL,        /* no channel bindings */
@@ -1226,10 +1217,10 @@ int try_gssapi_authentication(char *host, Options *options)
                            NULL);       /* ignore time_rec */
 
     if (token_ptr != GSS_C_NO_BUFFER)
-      (void) gss_release_buffer(&min_stat, &recv_tok);
+      (void) gss_release_buffer(&ctx->minor, &recv_tok);
 
-    if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
-      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+    if (ctx->major != GSS_S_COMPLETE && ctx->major != GSS_S_CONTINUE_NEEDED) {
+      ssh_gssapi_error(ctx);
 
       /* Send an abort message */
       packet_start(SSH_MSG_AUTH_GSSAPI_ABORT);
@@ -1246,10 +1237,10 @@ int try_gssapi_authentication(char *host, Options *options)
       packet_send();
       packet_write_wait();
 
-      (void) gss_release_buffer(&min_stat, &send_tok);
+      (void) gss_release_buffer(&ctx->minor, &send_tok);
     }
 
-    if (maj_stat == GSS_S_CONTINUE_NEEDED) {
+    if (ctx->major == GSS_S_CONTINUE_NEEDED) {
 
       debug("Continue needed. Reading response...");
 
@@ -1279,7 +1270,7 @@ int try_gssapi_authentication(char *host, Options *options)
       packet_get_all();
       token_ptr = &recv_tok;
     }
-  } while (maj_stat == GSS_S_CONTINUE_NEEDED);
+  } while (ctx->major == GSS_S_CONTINUE_NEEDED);
 
   /* Success */
   ret_stat = 1;
@@ -1310,15 +1301,15 @@ int try_gssapi_authentication(char *host, Options *options)
     wrapped_buf.length=slen;   /* safe typecast */
     packet_get_all();
 
-    maj_stat = gss_unwrap(&min_stat,
+    ctx->major = gss_unwrap(&ctx->minor,
                           gss_context,
                           &wrapped_buf,
                           &unwrapped_buf,
                           &conf_state,
                           &qop_state);
 
-    if (maj_stat != GSS_S_COMPLETE) {
-      ssh_gssapi_error(&mech_oid, maj_stat, min_stat);
+    if (ctx->major != GSS_S_COMPLETE) {
+      ssh_gssapi_error(ctx);
       packet_disconnect("Verification of SSHD keys through GSSAPI-secured channel failed: "
                         "Unwrapping of hash failed.");
     }
@@ -1337,7 +1328,7 @@ int try_gssapi_authentication(char *host, Options *options)
 
     debug("Verified SSHD keys through GSSAPI-secured channel.");
 
-    gss_release_buffer(&min_stat, &unwrapped_buf);
+    gss_release_buffer(&ctx->minor, &unwrapped_buf);
 
   } else {
       packet_disconnect("Protocol error during GSSAPI authentication:"
@@ -1348,7 +1339,9 @@ int try_gssapi_authentication(char *host, Options *options)
 
  cleanup:
   if (target_name != NULL)
-      (void) gss_release_name(&min_stat, &target_name);
+      (void) gss_release_name(&ctx->minor, &target_name);
+  if (ctx)
+      ssh_gssapi_delete_ctx(&ctx);
 
   return ret_stat;
 }
index 9b7b61aacec15f11c08ed09d6d0ca1cce2557295..7b45c17367662155e177c33da8d3234c52f2be34 100644 (file)
@@ -97,7 +97,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        orig = myproposal[PROPOSAL_KEX_ALGS];
        canonhost = xstrdup(get_canonical_hostname(1));
        resolve_localhost(&canonhost);
-       gss = ssh_gssapi_mechanisms(canonhost);
+       gss = ssh_gssapi_client_mechanisms(canonhost);
        xfree(canonhost);
        canonhost=NULL;
        if (gss) {
@@ -139,13 +139,12 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
         /* 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
-
        /* start key exchange */
        kex = kex_setup(myproposal);
        kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
@@ -157,11 +156,9 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
        kex->server_version_string=server_version_string;
        kex->verify_host_key=&verify_host_key_callback;
        kex->host=host;
-
 #ifdef GSSAPI
        kex->options.gss_deleg_creds=options.gss_deleg_creds;
 #endif
-
        xxx_kex = kex;
 
        dispatch_run(DISPATCH_BLOCK, &kex->done, kex);
@@ -236,6 +233,7 @@ int userauth_gssapi(Authctxt *authctxt);
 void   input_gssapi_response(int type, u_int32_t plen, void *ctxt);
 void   input_gssapi_token(int type, u_int32_t plen, void *ctxt);
 void   input_gssapi_hash(int type, u_int32_t plen, void *ctxt);
+void   input_gssapi_error(int, u_int32_t, void *);
 #endif
 
 void   userauth(Authctxt *, char *);
@@ -506,57 +504,76 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
 int 
 userauth_gssapi(Authctxt *authctxt)
 {
-       Gssctxt *gssctxt;
+       Gssctxt *gssctxt = NULL;
+       static gss_OID_set supported = NULL;
        static int mech=0;
+       OM_uint32 min;
+       int ok=0;
+
+       /* Things work better if we send one mechanism at a time, rather
+       * than them all at once. This means that if we fail at some point
+       * in the middle of a negotiation, we can come back and try something
+       * different. */
 
        if (datafellows & SSH_OLD_GSSAPI) return 0;
        
-       /* Try each mechanism in turn.  Give up if we've tried all
-          supported mechanisms.
-        */
-       if (mech==GSS_LAST_ENTRY) return 0;
-       
-       /* Initialise as much of our context as we can, so failures can be
-        * trapped before sending any packets.
-        */
-       ssh_gssapi_build_ctx(&gssctxt);
+       /* Before we offer a mechanism, check that we can support it. Don't
+       * bother trying to get credentials - as the standard fallback will
+       * deal with that kind of failure.
+       */
 
-       if (ssh_gssapi_import_name(gssctxt,get_canonical_hostname(1))) {
-               return(0);
+       if (supported==NULL) gss_indicate_mechs(&min, &supported);
+       
+       while (mech<supported->count && !ok) {
+               if (gssctxt) ssh_gssapi_delete_ctx(&gssctxt);
+               ssh_gssapi_build_ctx(&gssctxt);
+               ssh_gssapi_set_oid(gssctxt,&supported->elements[mech]);
+
+               /* The DER encoding below only works for lengths<128,
+               * so check this here 
+               */
+               if (supported->elements[mech].length<128 &&
+                   !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
+                                                     authctxt->host))) {
+                       ok = 1; /* Mechanism works */
+               } else {
+                       mech++;
+               }
        }
        
+       if (!ok) return 0;
+       
        authctxt->methoddata=(void *)gssctxt;
                
        packet_start(SSH2_MSG_USERAUTH_REQUEST);
-#ifdef GSI
-        if(options.implicit && !(datafellows & SSH_BUG_GSS_EMPTYUSER)) {
-           packet_put_cstring("");
-       } else {
-#endif
-           packet_put_cstring(authctxt->server_user);
-#ifdef GSI
-       }
-#endif
+       packet_put_cstring(authctxt->server_user);
        packet_put_cstring(authctxt->service);
         packet_put_cstring(authctxt->method->name);
+       
+       packet_put_int(1);
 
-       /* FIXME: This assumes that our current GSSAPI implementation
-        * supports all of the mechanisms listed in supported_mechs.
-        * This may not be the case - we should use something along
-        * the lines of the code in gss_genr to remove the ones that
-        * aren't supported */
+       /* The newest gsskeyex draft stipulates that OIDs should
+       * be DER encoded, so we need to add the object type and
+       * length information back on */
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               packet_put_string(supported->elements[mech].elements,
+                                 supported->elements[mech].length);
+       } else {
+               packet_put_int((supported->elements[mech].length)+2);
+               packet_put_char(0x06);
+               packet_put_char(supported->elements[mech].length);
+               packet_put_raw(supported->elements[mech].elements,
+                              supported->elements[mech].length);
+       }
 
-       /* Try one GSSAPI mechanism at a time. */
-       packet_put_int(1);
-       packet_put_string(supported_mechs[mech].oid.elements,
-                         supported_mechs[mech].oid.length);
         packet_send();
         packet_write_wait();
 
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,&input_gssapi_response);
         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,&input_gssapi_token);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,&input_gssapi_error);
        
-       mech++;                 /* Move to next mechanism for next time. */
+       mech++; /* Move along to next candidate */
 
         return 1;
 }
@@ -577,8 +594,25 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
        
        /* Setup our OID */
        oidv=packet_get_string(&oidlen);
-       ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
        
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               if (!ssh_gssapi_check_oid(gssctxt,oidv,oidlen)) {
+                       fatal("Server returned different OID than expected");
+               }
+               ssh_gssapi_set_oid_data(gssctxt,oidv,oidlen);
+       } else {
+               if(oidv[0]!=0x06 || oidv[1]!=oidlen-2) {
+                       debug("Badly encoded mechanism OID received");
+                       clear_auth_state(authctxt);
+                       userauth(authctxt,NULL);
+                       return;
+               }
+               if (!ssh_gssapi_check_oid(gssctxt,oidv+2,oidlen-2)) {
+                       fatal("Server returned different OID than expected");
+               }
+               ssh_gssapi_set_oid_data(gssctxt,oidv+2,oidlen-2);
+       }
+               
        packet_check_eom();
        
        status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
@@ -587,6 +621,7 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt)
        if (GSS_ERROR(status)) {
                /* Start again with next method on list */
                debug("Trying to start again");
+               clear_auth_state(authctxt);
                userauth(authctxt,NULL);
                return;
        }
@@ -622,6 +657,7 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
        
        if (GSS_ERROR(status)) {
                /* Start again with the next method in the list */
+               clear_auth_state(authctxt);
                userauth(authctxt,NULL);
                return;
        }
@@ -641,6 +677,25 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt)
        }
 }
 
+void
+input_gssapi_error(int type, u_int32_t plen, void *ctxt)
+{
+       OM_uint32 maj,min;
+       char *msg;
+       char *lang;
+       
+       maj=packet_get_int();
+       min=packet_get_int();
+       msg=packet_get_string(NULL);
+       lang=packet_get_string(NULL);
+
+       packet_check_eom();
+       
+       fprintf(stderr, "Server GSSAPI Error:\n%s\n", msg);
+       xfree(msg);
+       xfree(lang);
+}
+
 int
 userauth_external(Authctxt *authctxt)
 {
@@ -785,7 +840,12 @@ clear_auth_state(Authctxt *authctxt)
 {
        /* XXX clear authentication state */
        dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
-
+#ifdef GSSAPI
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE,NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR,NULL);
+#endif
+       
        if (authctxt->last_key != NULL && authctxt->last_key_hint == -1) {
                debug3("clear_auth_state: key_free %p", authctxt->last_key);
                key_free(authctxt->last_key);
index 24f1ce471bfb9b4099ab49bf42869149895f56f9..baf31fd4cfdc869a6aaf0d4f9ecb485461010643 100644 (file)
@@ -1086,10 +1086,6 @@ main(int ac, char **av)
        if (test_flag)
                exit(0);
 
-#ifdef GSSAPI
-       ssh_gssapi_clean_env();
-#endif /* GSSAPI */
-
        /*
         * Clear out any supplemental groups we may have inherited.  This
         * prevents inadvertent creation of files with bad modes (in the
@@ -1798,7 +1794,7 @@ do_ssh1_kex(void)
     Buffer buf;
     unsigned char *data;
     unsigned int data_len;
-    extern unsigned char ssh1_key_digest[16];   /* in gss-genr.c */
+    extern unsigned char ssh1_key_digest[16];   /* in auth2-gss.c */
 
 
     debug("Calculating MD5 hash of server and host keys...");
@@ -1892,7 +1888,7 @@ do_ssh2_kex(void)
                orig= NULL;
                
         if (options.gss_keyex)
-               gss = ssh_server_gssapi_mechanisms();
+               gss = ssh_gssapi_server_mechanisms();
         else
                gss = NULL;
         
This page took 0.209308 seconds and 5 git commands to generate.