X-Git-Url: http://andersk.mit.edu/gitweb/gssapi-openssh.git/blobdiff_plain/5598e598f2b9714c3b08a211d401c780e74dabe2..c7221eeea765e474a69b7c537e56045c83d7ce78:/openssh/gss-serv.c diff --git a/openssh/gss-serv.c b/openssh/gss-serv.c index 762c210..dfca41d 100644 --- a/openssh/gss-serv.c +++ b/openssh/gss-serv.c @@ -27,6 +27,7 @@ #ifdef GSSAPI #include "ssh.h" +#include "ssh1.h" #include "ssh2.h" #include "xmalloc.h" #include "buffer.h" @@ -38,9 +39,11 @@ #include "kex.h" #include "auth.h" #include "log.h" +#include "channels.h" #include "session.h" #include "dispatch.h" #include "servconf.h" +#include "compat.h" #include "ssh-gss.h" @@ -48,6 +51,8 @@ extern ServerOptions options; extern u_char *session_id2; extern int session_id2_len; +void userauth_reply(Authctxt *authctxt, int authenticated); +static void gssapi_unsetenv(const char *var); typedef struct ssh_gssapi_cred_cache { char *filename; @@ -57,6 +62,16 @@ typedef struct ssh_gssapi_cred_cache { } ssh_gssapi_cred_cache; static struct ssh_gssapi_cred_cache gssapi_cred_store = {NULL,NULL,NULL}; +unsigned char ssh1_key_digest[16]; /* used for ssh1 gssapi */ + +/* + * Environment variables pointing to delegated credentials + */ +static char *delegation_env[] = { + "X509_USER_PROXY", /* GSSAPI/SSLeay */ + "KRB5CCNAME", /* Krb5 and possibly SSLeay */ + NULL +}; #ifdef KRB5 @@ -402,7 +417,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) #endif case GSS_LAST_ENTRY: debug("No GSSAPI credentials stored"); - + break; default: log("ssh_gssapi_do_child: Unknown mechanism"); } @@ -439,13 +454,13 @@ ssh_gssapi_userok(char *user) int userauth_external(Authctxt *authctxt) { - packet_done(); + packet_check_eom(); return(ssh_gssapi_userok(authctxt->user)); } -void input_gssapi_token(int type, int plen, void *ctxt); -void input_gssapi_exchange_complete(int type, int plen, void *ctxt); +void input_gssapi_token(int type, u_int32_t plen, void *ctxt); +void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); /* We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like @@ -459,9 +474,16 @@ userauth_gssapi(Authctxt *authctxt) gss_OID_set supported; int present; OM_uint32 ms; + u_int len; if (!authctxt->valid || authctxt->user == NULL) return 0; + + if (datafellows & SSH_OLD_GSSAPI) { + debug("Early drafts of GSSAPI userauth not supported"); + return 0; + } + mechs=packet_get_int(); if (mechs==0) { debug("Mechanism negotiation is not supported"); @@ -472,7 +494,8 @@ userauth_gssapi(Authctxt *authctxt) do { if (oid.elements) xfree(oid.elements); - oid.elements = packet_get_string(&oid.length); + oid.elements = packet_get_string(&len); + oid.length = len; gss_test_oid_set_member(&ms, &oid, supported, &present); mechs--; } while (mechs>0 && !present); @@ -493,12 +516,19 @@ userauth_gssapi(Authctxt *authctxt) /* 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); packet_send(); packet_write_wait(); xfree(oid.elements); + if (!compat20) + dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, + &input_gssapi_token); + else dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); authctxt->postponed = 1; @@ -507,7 +537,7 @@ userauth_gssapi(Authctxt *authctxt) } void -input_gssapi_token(int type, int plen, void *ctxt) +input_gssapi_token(int type, u_int32_t plen, void *ctxt) { Authctxt *authctxt = ctxt; Gssctxt *gssctxt; @@ -522,28 +552,37 @@ input_gssapi_token(int type, int plen, void *ctxt) recv_tok.value=packet_get_string(&recv_tok.length); maj_status=ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok, NULL); - packet_done(); + packet_check_eom(); if (GSS_ERROR(maj_status)) { /* Failure */ 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 (send_tok.length != 0) { /* Send a packet back to the client */ + if (!compat20) + packet_start(SSH_MSG_AUTH_GSSAPI_TOKEN); + else packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); packet_put_string(send_tok.value,send_tok.length); packet_send(); packet_write_wait(); - gss_release_buffer(&min_status, &send_tok); + gss_release_buffer(&min_status, &send_tok); } if (maj_status == GSS_S_COMPLETE) { - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); - dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, - &input_gssapi_exchange_complete); + dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); + /* ssh1 does not have an extra message here */ + if (!compat20) + input_gssapi_exchange_complete(0, 0, ctxt); + else + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, + &input_gssapi_exchange_complete); } } @@ -553,7 +592,7 @@ input_gssapi_token(int type, int plen, void *ctxt) */ void -input_gssapi_exchange_complete(int type, int plen, void *ctxt) +input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) { Authctxt *authctxt = ctxt; Gssctxt *gssctxt; @@ -577,10 +616,103 @@ input_gssapi_exchange_complete(int type, int plen, void *ctxt) authenticated = ssh_gssapi_userok(authctxt->user); + /* ssh1 needs to exchange the hash of the keys */ + if (!compat20) { + if (authenticated) { + + OM_uint32 maj_status, min_status; + gss_buffer_desc gssbuf,msg_tok; + + /* ssh1 uses wrap */ + gssbuf.value=ssh1_key_digest; + gssbuf.length=sizeof(ssh1_key_digest); + if ((maj_status=gss_wrap(&min_status, + gssctxt->context, + 0, + GSS_C_QOP_DEFAULT, + &gssbuf, + NULL, + &msg_tok))) { + ssh_gssapi_error(maj_status,min_status); + fatal("Couldn't wrap keys"); + } + packet_start(SSH_SMSG_AUTH_GSSAPI_HASH); + packet_put_string((char *)msg_tok.value,msg_tok.length); + packet_send(); + packet_write_wait(); + gss_release_buffer(&min_status,&msg_tok); + } + } + authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); userauth_finish(authctxt, authenticated, "gssapi"); } +/* + * 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. + */ +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 */ +} + #endif /* GSSAPI */