]> andersk Git - openssh.git/blobdiff - sshconnect2.c
- markus@cvs.openbsd.org 2003/08/22 13:20:03
[openssh.git] / sshconnect2.c
index 0605e4e5f6a19df308bbe374e62d403d7eafb397..558a0a749036c085c0ea0c50defe1e7d0c0a4a0b 100644 (file)
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: sshconnect2.c,v 1.118 2003/05/14 02:15:47 markus Exp $");
+RCSID("$OpenBSD: sshconnect2.c,v 1.122 2003/08/22 13:20:03 markus Exp $");
 
-#ifdef KRB5
-#include <krb5.h>
-#endif
+#include "openbsd-compat/sys-queue.h"
 
 #include "ssh.h"
 #include "ssh2.h"
@@ -52,6 +50,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.118 2003/05/14 02:15:47 markus Exp $");
 #include "msg.h"
 #include "pathnames.h"
 
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+
 /* import */
 extern char *client_version_string;
 extern char *server_version_string;
@@ -62,7 +64,7 @@ extern Options options;
  */
 
 u_char *session_id2 = NULL;
-int session_id2_len = 0;
+u_int session_id2_len = 0;
 
 char *xxx_host;
 struct sockaddr *xxx_hostaddr;
@@ -173,6 +175,8 @@ struct Authctxt {
        Sensitive *sensitive;
        /* kbd-interactive */
        int info_req_seen;
+       /* generic */
+       void *methoddata;
 };
 struct Authmethod {
        char    *name;          /* string to compare against server's list */
@@ -196,10 +200,18 @@ int       userauth_kbdint(Authctxt *);
 int    userauth_hostbased(Authctxt *);
 int    userauth_kerberos(Authctxt *);
 
+#ifdef GSSAPI
+int    userauth_gssapi(Authctxt *authctxt);
+void   input_gssapi_response(int type, u_int32_t, void *);
+void   input_gssapi_token(int type, u_int32_t, void *);
+void   input_gssapi_hash(int type, u_int32_t, void *);
+void   input_gssapi_error(int, u_int32_t, void *);
+void   input_gssapi_errtok(int, u_int32_t, void *);
+#endif
+
 void   userauth(Authctxt *, char *);
 
 static int sign_and_send_pubkey(Authctxt *, Identity *);
-static void clear_auth_state(Authctxt *);
 static void pubkey_prepare(Authctxt *);
 static void pubkey_cleanup(Authctxt *);
 static Key *load_identity_file(char *);
@@ -209,16 +221,16 @@ static Authmethod *authmethod_lookup(const char *name);
 static char *authmethods_get(void);
 
 Authmethod authmethods[] = {
+#ifdef GSSAPI
+       {"gssapi",
+               userauth_gssapi,
+               &options.gss_authentication,
+               NULL},
+#endif
        {"hostbased",
                userauth_hostbased,
                &options.hostbased_authentication,
                NULL},
-#if KRB5
-       {"kerberos-2@ssh.com",
-               userauth_kerberos,
-               &options.kerberos_authentication,
-               NULL},
-#endif
        {"publickey",
                userauth_pubkey,
                &options.pubkey_authentication,
@@ -279,6 +291,7 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
        authctxt.success = 0;
        authctxt.method = authmethod_lookup("none");
        authctxt.authlist = NULL;
+       authctxt.methoddata = NULL;
        authctxt.sensitive = sensitive;
        authctxt.info_req_seen = 0;
        if (authctxt.method == NULL)
@@ -294,11 +307,18 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host,
        dispatch_run(DISPATCH_BLOCK, &authctxt.success, &authctxt);     /* loop until success */
 
        pubkey_cleanup(&authctxt);
+       dispatch_range(SSH2_MSG_USERAUTH_MIN, SSH2_MSG_USERAUTH_MAX, NULL);
+
        debug("Authentication succeeded (%s).", authctxt.method->name);
 }
+
 void
 userauth(Authctxt *authctxt, char *authlist)
 {
+       if (authctxt->methoddata) {
+               xfree(authctxt->methoddata);
+               authctxt->methoddata = NULL;
+       }
        if (authlist == NULL) {
                authlist = authctxt->authlist;
        } else {
@@ -311,6 +331,12 @@ userauth(Authctxt *authctxt, char *authlist)
                if (method == NULL)
                        fatal("Permission denied (%s).", authlist);
                authctxt->method = method;
+
+               /* reset the per method handler */
+               dispatch_range(SSH2_MSG_USERAUTH_PER_METHOD_MIN,
+                   SSH2_MSG_USERAUTH_PER_METHOD_MAX, NULL);
+
+               /* and try new method */
                if (method->userauth(authctxt) != 0) {
                        debug2("we sent a %s packet, wait for reply", method->name);
                        break;
@@ -348,7 +374,8 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt)
                fatal("input_userauth_success: no authentication context");
        if (authctxt->authlist)
                xfree(authctxt->authlist);
-       clear_auth_state(authctxt);
+       if (authctxt->methoddata)
+               xfree(authctxt->methoddata);
        authctxt->success = 1;                  /* break out */
 }
 
@@ -370,7 +397,6 @@ input_userauth_failure(int type, u_int32_t seq, void *ctxt)
                logit("Authenticated with partial success.");
        debug("Authentications that can continue: %s", authlist);
 
-       clear_auth_state(authctxt);
        userauth(authctxt, authlist);
 }
 void
@@ -433,15 +459,233 @@ done:
        xfree(pkalg);
        xfree(pkblob);
 
-       /* unregister */
-       clear_auth_state(authctxt);
-       dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL);
-
        /* try another method if we did not send a packet */
        if (sent == 0)
                userauth(authctxt, NULL);
 }
 
+#ifdef GSSAPI
+int 
+userauth_gssapi(Authctxt *authctxt)
+{
+       Gssctxt *gssctxt = NULL;
+       static gss_OID_set supported = NULL;
+       static int mech = 0;
+       OM_uint32 min;
+       int ok = 0;
+
+       /* Try one GSSAPI method at a time, rather than sending them all at
+        * once. */
+
+       if (supported == NULL)
+               gss_indicate_mechs(&min, &supported);
+
+       /* Check to see if the mechanism is usable before we offer it */
+       while (mech<supported->count && !ok) {
+               if (gssctxt)
+                       ssh_gssapi_delete_ctx(&gssctxt);
+               ssh_gssapi_build_ctx(&gssctxt);
+               ssh_gssapi_set_oid(gssctxt, &supported->elements[mech]);
+
+               /* My DER encoding requires length<128 */
+               if (supported->elements[mech].length < 128 &&
+                   !GSS_ERROR(ssh_gssapi_import_name(gssctxt,
+                   authctxt->host))) {
+                       ok = 1; /* Mechanism works */
+               } else {
+                       mech++;
+               }
+       }
+
+       if (!ok) return 0;
+
+       authctxt->methoddata=(void *)gssctxt;
+
+       packet_start(SSH2_MSG_USERAUTH_REQUEST);
+       packet_put_cstring(authctxt->server_user);
+       packet_put_cstring(authctxt->service);
+       packet_put_cstring(authctxt->method->name);
+
+       packet_put_int(1);
+
+       /* Some servers encode the OID incorrectly (as we used to) */
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               packet_put_string(supported->elements[mech].elements,
+                   supported->elements[mech].length);
+       } else {
+               packet_put_int((supported->elements[mech].length)+2);
+               packet_put_char(SSH_GSS_OIDTYPE);
+               packet_put_char(supported->elements[mech].length);
+               packet_put_raw(supported->elements[mech].elements,
+                   supported->elements[mech].length);
+       }
+
+       packet_send();
+
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE, &input_gssapi_response);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERROR, &input_gssapi_error);
+       dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
+
+       mech++; /* Move along to next candidate */
+
+       return 1;
+}
+
+void
+input_gssapi_response(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       OM_uint32 status, ms;
+       int oidlen;
+       char *oidv;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+
+       /* Setup our OID */
+       oidv = packet_get_string(&oidlen);
+
+       if (datafellows & SSH_BUG_GSSAPI_BER) {
+               if (!ssh_gssapi_check_oid(gssctxt, oidv, oidlen))
+                       fatal("Server returned different OID than expected");
+       } else {
+               if(oidv[0] != SSH_GSS_OIDTYPE || oidv[1] != oidlen-2) {
+                       debug("Badly encoded mechanism OID received");
+                       userauth(authctxt, NULL);
+                       xfree(oidv);
+                       return;
+               }
+               if (!ssh_gssapi_check_oid(gssctxt, oidv+2, oidlen-2))
+                       fatal("Server returned different OID than expected");
+       }
+
+       packet_check_eom();
+
+       xfree(oidv);
+
+       status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+           GSS_C_NO_BUFFER, &send_tok, NULL);
+       if (GSS_ERROR(status)) {
+               if (send_tok.length > 0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value, send_tok.length);
+                       packet_send();
+                       gss_release_buffer(&ms, &send_tok);
+               }
+               /* Start again with next method on list */
+               debug("Trying to start again");
+               userauth(authctxt, NULL);
+               return;
+       }
+
+       /* We must have data to send */
+       packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+       packet_put_string(send_tok.value, send_tok.length);
+       packet_send();
+       gss_release_buffer(&ms, &send_tok);
+}
+
+void
+input_gssapi_token(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc recv_tok;
+       OM_uint32 status, ms;
+       u_int slen;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+
+       recv_tok.value = packet_get_string(&slen);
+       recv_tok.length = slen; /* safe typecast */
+
+       packet_check_eom();
+
+       status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+           &recv_tok, &send_tok, NULL);
+
+       xfree(recv_tok.value);
+
+       if (GSS_ERROR(status)) {
+               if (send_tok.length > 0) {
+                       packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
+                       packet_put_string(send_tok.value, send_tok.length);
+                       packet_send();
+                       gss_release_buffer(&ms, &send_tok);
+               }
+               /* Start again with the next method in the list */
+               userauth(authctxt, NULL);
+               return;
+       }
+
+       if (send_tok.length > 0) {
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
+               packet_put_string(send_tok.value, send_tok.length);
+               packet_send();
+               gss_release_buffer(&ms, &send_tok);
+       }
+
+       if (status == GSS_S_COMPLETE) {
+               /* If that succeeded, send a exchange complete message */
+               packet_start(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE);
+               packet_send();
+       }
+}
+
+void
+input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
+{
+       Authctxt *authctxt = ctxt;
+       Gssctxt *gssctxt;
+       gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+       gss_buffer_desc recv_tok;
+       OM_uint32 status, ms;
+
+       if (authctxt == NULL)
+               fatal("input_gssapi_response: no authentication context");
+       gssctxt = authctxt->methoddata;
+
+       recv_tok.value = packet_get_string(&recv_tok.length);
+
+       packet_check_eom();
+
+       /* Stick it into GSSAPI and see what it says */
+       status = ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds,
+                                    &recv_tok, &send_tok, NULL);
+
+       xfree(recv_tok.value);
+       gss_release_buffer(&ms, &send_tok);
+
+       /* Server will be returning a failed packet after this one */
+}
+
+void
+input_gssapi_error(int type, u_int32_t plen, void *ctxt)
+{
+       OM_uint32 maj, min;
+       char *msg;
+       char *lang;
+
+       maj=packet_get_int();
+       min=packet_get_int();
+       msg=packet_get_string(NULL);
+       lang=packet_get_string(NULL);
+
+       packet_check_eom();
+
+       debug("Server GSSAPI Error:\n%s\n", msg);
+       xfree(msg);
+       xfree(lang);
+}
+#endif /* GSSAPI */
+
 int
 userauth_none(Authctxt *authctxt)
 {
@@ -553,13 +797,6 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
            &input_userauth_passwd_changereq);
 }
 
-static void
-clear_auth_state(Authctxt *authctxt)
-{
-       /* XXX clear authentication state */
-       dispatch_set(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, NULL);
-}
-
 static int
 identity_sign(Identity *id, u_char **sigp, u_int *lenp,
     u_char *data, u_int datalen)
@@ -591,7 +828,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
        Buffer b;
        u_char *blob, *signature;
        u_int bloblen, slen;
-       int skip = 0;
+       u_int skip = 0;
        int ret = -1;
        int have_sig = 1;
 
@@ -1123,94 +1360,6 @@ userauth_hostbased(Authctxt *authctxt)
        return 1;
 }
 
-#if KRB5
-static int
-ssh_krb5_helper(krb5_data *ap)
-{
-       krb5_context xcontext = NULL;   /* XXX share with ssh1 */
-       krb5_auth_context xauth_context = NULL;
-
-       krb5_context *context;
-       krb5_auth_context *auth_context;
-       krb5_error_code problem;
-       const char *tkfile;
-       struct stat buf;
-       krb5_ccache ccache = NULL;
-       const char *remotehost;
-       int ret;
-
-       memset(ap, 0, sizeof(*ap));
-
-       context = &xcontext;
-       auth_context = &xauth_context;
-
-       problem = krb5_init_context(context);
-       if (problem) {
-               debug("Kerberos v5: krb5_init_context failed");
-               ret = 0;
-               goto out;
-       }
-
-       tkfile = krb5_cc_default_name(*context);
-       if (strncmp(tkfile, "FILE:", 5) == 0)
-               tkfile += 5;
-
-       if (stat(tkfile, &buf) == 0 && getuid() != buf.st_uid) {
-               debug("Kerberos v5: could not get default ccache (permission denied).");
-               ret = 0;
-               goto out;
-       }
-
-       problem = krb5_cc_default(*context, &ccache);
-       if (problem) {
-               debug("Kerberos v5: krb5_cc_default failed: %s",
-                   krb5_get_err_text(*context, problem));
-               ret = 0;
-               goto out;
-       }
-
-       remotehost = get_canonical_hostname(1);
-
-       problem = krb5_mk_req(*context, auth_context, AP_OPTS_MUTUAL_REQUIRED,
-           "host", remotehost, NULL, ccache, ap);
-       if (problem) {
-               debug("Kerberos v5: krb5_mk_req failed: %s",
-                   krb5_get_err_text(*context, problem));
-               ret = 0;
-               goto out;
-       }
-       ret = 1;
-
- out:
-       if (ccache != NULL)
-               krb5_cc_close(*context, ccache);
-       if (*auth_context)
-               krb5_auth_con_free(*context, *auth_context);
-       if (*context)
-               krb5_free_context(*context);
-       return (ret);
-}
-
-int
-userauth_kerberos(Authctxt *authctxt)
-{
-       krb5_data ap;
-
-       if (ssh_krb5_helper(&ap) == 0)
-               return (0);
-
-       packet_start(SSH2_MSG_USERAUTH_REQUEST);
-       packet_put_cstring(authctxt->server_user);
-       packet_put_cstring(authctxt->service);
-       packet_put_cstring(authctxt->method->name);
-       packet_put_string(ap.data, ap.length);
-       packet_send();
-
-       krb5_data_free(&ap);
-       return (1);
-}
-#endif
-
 /* find auth method */
 
 /*
This page took 0.050766 seconds and 4 git commands to generate.