diff options
author | Markus Friedl <markus@cvs.openbsd.org> | 2003-08-22 10:56:10 +0000 |
---|---|---|
committer | Markus Friedl <markus@cvs.openbsd.org> | 2003-08-22 10:56:10 +0000 |
commit | b3e8a9a0da9a4fbe3a84d9d3113851474129d460 (patch) | |
tree | e9178b4b7b0d42fddee0adfb2912da00660f13bb /usr.bin/ssh/sshconnect2.c | |
parent | 49f5a4b688e110da4d5e2d9a08bff2979053472e (diff) |
support GSS API user authentication; patches from Simon Wilkinson,
stripped down and tested by Jakob and myself.
Diffstat (limited to 'usr.bin/ssh/sshconnect2.c')
-rw-r--r-- | usr.bin/ssh/sshconnect2.c | 252 |
1 files changed, 251 insertions, 1 deletions
diff --git a/usr.bin/ssh/sshconnect2.c b/usr.bin/ssh/sshconnect2.c index e18ad4af640..6cf43ac1a00 100644 --- a/usr.bin/ssh/sshconnect2.c +++ b/usr.bin/ssh/sshconnect2.c @@ -23,7 +23,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 markus Exp $"); +RCSID("$OpenBSD: sshconnect2.c,v 1.121 2003/08/22 10:56:09 markus Exp $"); #ifdef KRB5 #include <krb5.h> @@ -52,6 +52,10 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.120 2003/06/24 08:23:46 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; @@ -173,6 +177,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,6 +202,15 @@ 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 *); @@ -208,6 +223,12 @@ 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, @@ -278,6 +299,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) @@ -301,6 +323,10 @@ ssh_userauth2(const char *local_user, const char *server_user, char *host, void userauth(Authctxt *authctxt, char *authlist) { + if (authctxt->methoddata) { + xfree(authctxt->methoddata); + authctxt->methoddata = NULL; + } if (authlist == NULL) { authlist = authctxt->authlist; } else { @@ -356,6 +382,8 @@ input_userauth_success(int type, u_int32_t seq, void *ctxt) fatal("input_userauth_success: no authentication context"); if (authctxt->authlist) xfree(authctxt->authlist); + if (authctxt->methoddata) + xfree(authctxt->methoddata); authctxt->success = 1; /* break out */ } @@ -444,6 +472,228 @@ done: 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) { |