From 3e19642522f29167667cb7fc45ea6426e871ed4c Mon Sep 17 00:00:00 2001 From: jbasney Date: Thu, 17 Apr 2003 20:25:21 +0000 Subject: [PATCH] openssh-3.6.1p1-gssapi-20030416.diff from Simon --- openssh/auth2-gss.c | 110 +++++++++++++++++++++++++---------------- openssh/gss-genr.c | 22 ++++----- openssh/gss-serv-gsi.c | 30 +++++------ openssh/gss-serv.c | 42 +++++++++------- openssh/kexgssc.c | 30 +++++++---- openssh/kexgsss.c | 30 +++++++---- openssh/monitor.c | 71 ++++++++++++++++++++++++-- openssh/monitor.h | 2 + openssh/monitor_wrap.c | 49 ++++++++++++++++++ openssh/monitor_wrap.h | 1 + openssh/session.c | 4 +- openssh/session.h | 2 +- openssh/ssh-gss.h | 4 +- openssh/sshconnect2.c | 73 +++++++++++++++++++++------ openssh/sshd.c | 2 +- 15 files changed, 342 insertions(+), 130 deletions(-) diff --git a/openssh/auth2-gss.c b/openssh/auth2-gss.c index ac1bc8c..bba5c10 100644 --- a/openssh/auth2-gss.c +++ b/openssh/auth2-gss.c @@ -50,6 +50,7 @@ userauth_external(Authctxt *authctxt) 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); +static void input_gssapi_errtok(int, u_int32_t, void *); /* We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like @@ -91,22 +92,15 @@ userauth_gssapi(Authctxt *authctxt) 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); - } + if (doid[0]!=0x06 || doid[1]!=len-2) { + log("Mechanism OID received using the old encoding form"); + oid.elements = doid; + oid.length = len; + } else { + oid.elements = doid + 2; + oid.length = len - 2; + } + gss_test_oid_set_member(&ms, &oid, supported, &present); } while (mechs>0 && !present); if (!present) { @@ -125,11 +119,8 @@ userauth_gssapi(Authctxt *authctxt) 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); - } + /* Just return whatever they sent */ + packet_put_string(doid,len); packet_send(); packet_write_wait(); @@ -137,6 +128,8 @@ userauth_gssapi(Authctxt *authctxt) dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, + &input_gssapi_errtok); authctxt->postponed = 1; return 0; @@ -157,32 +150,62 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) recv_tok.value=packet_get_string(&recv_tok.length); 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, even if there has - * been an error, as this may contain mechanism specific - * error information */ - 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); - } - + if (GSS_ERROR(maj_status)) { - ssh_gssapi_userauth_error(gssctxt); + ssh_gssapi_userauth_error(gssctxt); + if (send_tok.length != 0) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); + packet_put_string(send_tok.value,send_tok.length); + packet_send(); + packet_write_wait(); + } authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); userauth_finish(authctxt, 0, "gssapi"); + } else { + if (send_tok.length != 0) { + packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); + packet_put_string(send_tok.value,send_tok.length); + packet_send(); + packet_write_wait(); + } + 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); + } } + + 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); - } +static void +input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + gss_buffer_desc send_tok,recv_tok; + OM_uint32 maj_status; + + if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + fatal("No authentication or GSSAPI context"); + + gssctxt=authctxt->methoddata; + recv_tok.value=packet_get_string(&recv_tok.length); + + /* Push the error token into GSSAPI to see what it says */ + maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, + &send_tok, NULL)); + packet_check_eom(); + + /* We can't return anything to the client, even if we wanted to */ + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL); + + /* The client will have already moved on to the next auth */ + } /* This is called when the client thinks we've completed authentication. @@ -203,14 +226,15 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) gssctxt=authctxt->methoddata; /* We don't need to check the status, because the stored credentials - * which userok uses are only populated once the context init step - * has returned complete. - */ + * which userok uses are only populated once the context init step + * has returned complete. + */ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); authctxt->postponed = 0; dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); + dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); userauth_finish(authctxt, authenticated, "gssapi"); } diff --git a/openssh/gss-genr.c b/openssh/gss-genr.c index 25cab87..6090717 100644 --- a/openssh/gss-genr.c +++ b/openssh/gss-genr.c @@ -81,10 +81,10 @@ ssh_gssapi_client_mechanisms(char *host) { gss_indicate_mechs(&min_status,&supported); if (datafellows & SSH_BUG_GSSAPI_BER) { gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping) - *(supported->count+1)); + *((supported->count*2)+1)); } else { gss_enc2oid=xmalloc(sizeof(ssh_gss_kex_mapping) - *((supported->count*2)+1)); + *(supported->count*2+1)); } buffer_init(&buf); @@ -98,10 +98,10 @@ ssh_gssapi_client_mechanisms(char *host) { 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 */ + * 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; @@ -142,8 +142,8 @@ ssh_gssapi_client_mechanisms(char *host) { EVP_DigestInit(&md, evp_md); EVP_DigestUpdate(&md,deroid,2); EVP_DigestUpdate(&md, - supported->elements[i].elements, - supported->elements[i].length); + supported->elements[i].elements, + supported->elements[i].length); EVP_DigestFinal(&md, digest, NULL); /* Base64 encode it */ @@ -372,11 +372,11 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { 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 FQDN. Some GSSAPI implementations don't do - * this for us themselves */ + * this for us themselves */ hostinfo = gethostbyname(xhost); @@ -430,7 +430,7 @@ ssh_gssapi_acquire_cred(Gssctxt *ctx) { } if ((ctx->major=gss_acquire_cred(&ctx->minor, - ctx->name, + ctx->name, 0, oidset, GSS_C_ACCEPT, diff --git a/openssh/gss-serv-gsi.c b/openssh/gss-serv-gsi.c index d8714e3..a1dc646 100644 --- a/openssh/gss-serv-gsi.c +++ b/openssh/gss-serv-gsi.c @@ -78,20 +78,20 @@ ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) char *creds_env = NULL; /* - * This is the current hack with the GSI gssapi library to - * export credentials to disk. - */ + * 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, - client->creds, - (gss_name_t *) &creds_env, - NULL, - NULL, - NULL); + client->creds, + (gss_name_t *) &creds_env, + NULL, + NULL, + NULL); if ((major_status == GSS_S_COMPLETE) && (minor_status == 0xdee1) && @@ -100,12 +100,12 @@ ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) 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. - */ + * 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) @@ -115,7 +115,7 @@ ssh_gssapi_gsi_storecreds(ssh_gssapi_client *client) #ifdef USE_PAM do_pam_putenv("X509_USER_PROXY",value); #endif - client->store.filename=NULL; + client->store.filename=NULL; client->store.envvar="X509_USER_PROXY"; client->store.envval=strdup(value); diff --git a/openssh/gss-serv.c b/openssh/gss-serv.c index aa86a45..95c35f5 100644 --- a/openssh/gss-serv.c +++ b/openssh/gss-serv.c @@ -89,7 +89,8 @@ ssh_gssapi_mech* supported_mechs[]= { * that stores the results (in an expanded Gssctxt structure), which are * then used by the first calls if that key exchange mechanism is chosen. */ - + +/* Unpriviledged */ char * ssh_gssapi_server_mechanisms() { gss_OID_set supported; @@ -142,6 +143,7 @@ ssh_gssapi_server_mechanisms() { return(mechs); } +/* Unpriviledged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) { int i =0; OM_uint32 maj_status,min_status; @@ -149,7 +151,7 @@ void ssh_gssapi_supported_oids(gss_OID_set *oidset) { gss_OID_set supported; gss_create_empty_oid_set(&min_status,oidset); - gss_indicate_mechs(&min_status, &supported); + PRIVSEP(gss_indicate_mechs(&min_status, &supported)); while (supported_mechs[i]->name!=NULL) { if ((maj_status=gss_test_oid_set_member(&min_status, @@ -170,6 +172,8 @@ void ssh_gssapi_supported_oids(gss_OID_set *oidset) { /* Find out which GSS type (out of the list we define in ssh-gss.h) a * particular connection is using */ + +/* Priviledged (called ssh_gssapi_accept_ctx -> ssh_gssapi_getclient ->) */ ssh_gssapi_mech * ssh_gssapi_get_ctype(Gssctxt *ctxt) { int i=0; @@ -183,11 +187,11 @@ ssh_gssapi_get_ctype(Gssctxt *ctxt) { return ((supported_mechs[i]->name!=NULL)?supported_mechs[i]:NULL); } -/* Set the GSS context's OID to the oid indicated by the given key exchange - * name. */ +/* Return the OID that corresponds to the given context name */ +/* Unpriviledged */ gss_OID -ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { +ssh_gssapi_server_id_kex(char *name) { int i=0; if (strncmp(name, KEX_GSS_SHA1, sizeof(KEX_GSS_SHA1)-1) !=0) { @@ -197,23 +201,22 @@ ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { 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) { + 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); - return &supported_mechs[i]->oid; } -/* Wrapper arround accept_sec_context +/* Wrapper around accept_sec_context * Requires that the context contains: * oid * credentials (from ssh_gssapi_acquire_cred) */ +/* Priviledged */ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, gss_buffer_desc *send_tok, OM_uint32 *flags) { @@ -242,13 +245,13 @@ 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) */ 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))) && @@ -266,6 +269,7 @@ OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, /* Extract the client details from a given context. This can only reliably * be called once for a context */ +/* Priviledged (called from accept_secure_ctx) */ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type, gss_buffer_desc *name, gss_cred_id_t *creds) { @@ -277,14 +281,15 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_mech **type, } /* 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. - */ + * 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); } +/* As user - called through fatal cleanup hook */ void ssh_gssapi_cleanup_creds(void *ignored) { @@ -295,6 +300,7 @@ ssh_gssapi_cleanup_creds(void *ignored) } } +/* As user */ void ssh_gssapi_storecreds() { @@ -310,10 +316,8 @@ ssh_gssapi_storecreds() /* 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? */ +/* As user */ void ssh_gssapi_do_child(char ***envp, u_int *envsizep) { @@ -328,6 +332,7 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) } } +/* Priviledged */ int ssh_gssapi_userok(char *user) { @@ -344,6 +349,7 @@ ssh_gssapi_userok(char *user) return(0); } +/* Priviledged */ int ssh_gssapi_localname(char **user) { diff --git a/openssh/kexgssc.c b/openssh/kexgssc.c index 7230944..d244580 100644 --- a/openssh/kexgssc.c +++ b/openssh/kexgssc.c @@ -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 @@ -81,7 +81,7 @@ kexgss_client(Kex *kex) } token_ptr = GSS_C_NO_BUFFER; - + do { debug("Calling gss_init_sec_context"); @@ -91,8 +91,14 @@ kexgss_client(Kex *kex) &ret_flags); if (GSS_ERROR(maj_status)) { + if (send_tok.length!=0) { + /* Hmmm - not sure about this */ + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value, + send_tok.length); + } fatal("gss_init_context failed"); - } + } /* If we've got an old receive buffer get rid of it */ if (token_ptr != GSS_C_NO_BUFFER) @@ -111,7 +117,7 @@ kexgss_client(Kex *kex) } /* If we have data to send, then the last message that we - * received cannot have been a 'complete'. */ + * received cannot have been a 'complete'. */ if (send_tok.length !=0) { if (first) { packet_start(SSH2_MSG_KEXGSS_INIT); @@ -129,7 +135,7 @@ kexgss_client(Kex *kex) /* If we've sent them data, they'd better be polite - * and reply. */ + * and reply. */ type = packet_read(); switch (type) { @@ -168,22 +174,26 @@ kexgss_client(Kex *kex) min_status=packet_get_int(); msg=packet_get_string(NULL); lang=packet_get_string(NULL); - fatal(msg); + fprintf(stderr,"GSSAPI Error: \n%s",msg); default: packet_disconnect("Protocol error: didn't expect packet type %d", type); } token_ptr=&recv_tok; + } else { + /* No data, and not complete */ + if (maj_status!=GSS_S_COMPLETE) { + fatal("Not complete, and no token output"); + } } - } while (maj_status & GSS_S_CONTINUE_NEEDED); /* We _must_ have received a COMPLETE message in reply from the - * server, which will have set dh_server_pub and msg_tok */ - + * server, which will have set dh_server_pub and msg_tok */ + if (type!=SSH2_MSG_KEXGSS_COMPLETE) fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); - + /* Check f in range [1, p-1] */ if (!dh_pub_is_valid(dh, dh_server_pub)) packet_disconnect("bad server public DH value"); diff --git a/openssh/kexgsss.c b/openssh/kexgsss.c index 5044540..6f6cb34 100644 --- a/openssh/kexgsss.c +++ b/openssh/kexgsss.c @@ -48,9 +48,9 @@ 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; @@ -67,7 +67,7 @@ kexgss_server(Kex *kex) /* Initialise GSSAPI */ debug2("%s: Identifying %s",__func__,kex->name); - oid=ssh_gssapi_id_kex(ctxt,kex->name); + oid=ssh_gssapi_server_id_kex(kex->name); if (oid==NULL) { fatal("Unknown gssapi mechanism"); } @@ -97,8 +97,6 @@ kexgss_server(Kex *kex) /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ break; case SSH2_MSG_KEXGSS_CONTINUE: - if (dh_client_pub == NULL) - fatal("Received KEXGSS_CONTINUE without initialising"); recv_tok.value=packet_get_string(&recv_tok.length); break; default: @@ -107,12 +105,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); - if ((maj_status & GSS_S_CONTINUE_NEEDED) || - (GSS_ERROR(maj_status) && send_tok.length>0)) { + if (maj_status!=GSS_S_COMPLETE && send_tok.length==0) { + fatal("Zero length token output when incomplete"); + } + + if (dh_client_pub == NULL) + fatal("No client public key"); + + if (maj_status & GSS_S_CONTINUE_NEEDED) { debug("Sending GSSAPI_CONTINUE"); packet_start(SSH2_MSG_KEXGSS_CONTINUE); packet_put_string(send_tok.value,send_tok.length); @@ -124,6 +128,12 @@ kexgss_server(Kex *kex) if (GSS_ERROR(maj_status)) { kex_gss_send_error(ctxt); + if (send_tok.length>0) { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); + packet_put_string(send_tok.value,send_tok.length); + packet_send(); + packet_write_wait(); + } fatal("accept_ctx died"); } @@ -197,7 +207,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); diff --git a/openssh/monitor.c b/openssh/monitor.c index 32bc424..9c6b197 100644 --- a/openssh/monitor.c +++ b/openssh/monitor.c @@ -138,6 +138,8 @@ int mm_answer_gss_accept_ctx(int, Buffer *); int mm_answer_gss_userok(int, Buffer *); int mm_answer_gss_sign(int, Buffer *); int mm_answer_gss_error(int, Buffer *); +int mm_answer_gss_indicate_mechs(int, Buffer *); +int mm_answer_gss_localname(int, Buffer *); #endif static Authctxt *authctxt; @@ -189,8 +191,13 @@ struct mon_table mon_dispatch_proto20[] = { {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, {MONITOR_REQ_GSSSTEP, MON_ISAUTH, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSSIGN, MON_ONCE, mm_answer_gss_sign}, - {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, {MONITOR_REQ_GSSERR, MON_ISAUTH | MON_ONCE, mm_answer_gss_error}, + {MONITOR_REQ_GSSMECHS, MON_ISAUTH, mm_answer_gss_indicate_mechs}, + {MONITOR_REQ_GSSUSEROK, MON_AUTH, mm_answer_gss_userok}, +/* Turn this off until we use it */ +#if 0 + {MONITOR_REQ_GSSLOCALNAME, MON_ISAUTH, mm_answer_gss_localname}, +#endif #endif {MONITOR_REQ_KEYALLOWED, MON_ISAUTH, mm_answer_keyallowed}, {MONITOR_REQ_KEYVERIFY, MON_AUTH, mm_answer_keyverify}, @@ -203,6 +210,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_GSSERR, 0, mm_answer_gss_error}, + {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, #endif {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, {MONITOR_REQ_SIGN, 0, mm_answer_sign}, @@ -296,9 +304,8 @@ monitor_child_preauth(struct monitor *pmonitor) #ifdef GSSAPI /* and for the GSSAPI key exchange */ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 1); - monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR, 1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS, 1); #endif } else { mon_dispatch = mon_dispatch_proto15; @@ -354,6 +361,13 @@ monitor_child_postauth(struct monitor *pmonitor) monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); +#ifdef GSSAPI + /* and for the GSSAPI key exchange */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSMECHS,1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP,1); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSERR,1); +#endif + } else { mon_dispatch = mon_dispatch_postauth15; monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -1703,6 +1717,9 @@ mm_answer_gss_setup_ctx(int socket, Buffer *m) { mm_request_send(socket,MONITOR_ANS_GSSSETUP,m); + /* Now we have a context, enable the step and sign */ + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,1); + return(0); } @@ -1724,8 +1741,14 @@ mm_answer_gss_accept_ctx(int socket, Buffer *m) { gss_release_buffer(&minor, &out); + /* Complete - now we can do signing */ + if (major==GSS_S_COMPLETE) { + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP,0); + monitor_permit(mon_dispatch, MONITOR_REQ_GSSSIGN,1); + } return(0); } + int mm_answer_gss_userok(int socket, Buffer *m) { int authenticated; @@ -1796,5 +1819,47 @@ mm_answer_gss_error(int socket, Buffer *m) { return(0); } +int +mm_answer_gss_indicate_mechs(int socket, Buffer *m) { + OM_uint32 major,minor; + gss_OID_set mech_set; + int i; + + major=gss_indicate_mechs(&minor, &mech_set); + buffer_clear(m); + buffer_put_int(m, major); + buffer_put_int(m, mech_set->count); + for (i=0; i < mech_set->count; i++) { + buffer_put_string(m, mech_set->elements[i].elements, + mech_set->elements[i].length); + } + + gss_release_oid_set(&minor,&mech_set); + + mm_request_send(socket,MONITOR_ANS_GSSMECHS,m); + + return(0); +} + +int +mm_answer_gss_localname(int socket, Buffer *m) { + char *name; + + ssh_gssapi_localname(&name); + + buffer_clear(m); + if (name) { + buffer_put_cstring(m, name); + debug3("%s: sending result %s", __func__, name); + xfree(name); + } else { + buffer_put_cstring(m, ""); + debug3("%s: sending result \"\"", __func__); + } + + mm_request_send(socket, MONITOR_ANS_GSSLOCALNAME, m); + + return(0); +} #endif /* GSSAPI */ diff --git a/openssh/monitor.h b/openssh/monitor.h index 1bdddfc..086bab6 100644 --- a/openssh/monitor.h +++ b/openssh/monitor.h @@ -44,6 +44,8 @@ enum monitor_reqtype { MONITOR_REQ_GSSSTEP,MONITOR_ANS_GSSSTEP, MONITOR_REQ_GSSSIGN,MONITOR_ANS_GSSSIGN, MONITOR_REQ_GSSUSEROK,MONITOR_ANS_GSSUSEROK, + MONITOR_REQ_GSSMECHS,MONITOR_ANS_GSSMECHS, + MONITOR_REQ_GSSLOCALNAME,MONITOR_ANS_GSSLOCALNAME, MONITOR_REQ_GSSERR,MONITOR_ANS_GSSERR, #endif MONITOR_REQ_KEYALLOWED, MONITOR_ANS_KEYALLOWED, diff --git a/openssh/monitor_wrap.c b/openssh/monitor_wrap.c index a0c4d2a..e23f72d 100644 --- a/openssh/monitor_wrap.c +++ b/openssh/monitor_wrap.c @@ -1126,5 +1126,54 @@ mm_ssh_gssapi_last_error(Gssctxt *ctx, OM_uint32 *major, OM_uint32 *minor) { return(errstr); } + +OM_uint32 +mm_gss_indicate_mechs(OM_uint32 *minor_status, gss_OID_set *mech_set) +{ + Buffer m; + OM_uint32 major,minor; + int count; + gss_OID_desc oid; + buffer_init(&m); + + mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSMECHS, &m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_GSSMECHS, + &m); + major=buffer_get_int(&m); + count=buffer_get_int(&m); + + gss_create_empty_oid_set(&minor,mech_set); + while(count-->0) { + oid.elements=buffer_get_string(&m,&oid.length); + gss_add_oid_set_member(&minor,&oid,mech_set); + } + + buffer_free(&m); + + return(major); +} + +int +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); + + *lname = buffer_get_string(&m, NULL); + + buffer_free(&m); + if (lname[0] == '\0') { + debug3("%s: gssapi identity mapping failed", __func__); + } else { + debug3("%s: gssapi identity mapped to %s", __func__, *lname); + } + return(0); +} #endif /* GSSAPI */ diff --git a/openssh/monitor_wrap.h b/openssh/monitor_wrap.h index 85173e1..ffd2f28 100644 --- a/openssh/monitor_wrap.h +++ b/openssh/monitor_wrap.h @@ -68,6 +68,7 @@ OM_uint32 mm_ssh_gssapi_sign(Gssctxt *ctxt, gss_buffer_desc *buffer, gss_buffer_desc *hash); int mm_ssh_gssapi_userok(char *user); char *mm_ssh_gssapi_last_error(Gssctxt *ctxt, OM_uint32 *maj, OM_uint32 *min); + #endif void mm_terminate(void); diff --git a/openssh/session.c b/openssh/session.c index 7bab890..e85bc9e 100644 --- a/openssh/session.c +++ b/openssh/session.c @@ -985,8 +985,8 @@ do_setup_env(Session *s, const char *shell) #ifdef GSSAPI /* Allow any GSSAPI methods that we've used to alter - * the childs environment as they see fit - */ + * the childs environment as they see fit + */ ssh_gssapi_do_child(&env,&envsize); #endif diff --git a/openssh/session.h b/openssh/session.h index 012f0ff..7fc3653 100644 --- a/openssh/session.h +++ b/openssh/session.h @@ -69,6 +69,6 @@ Session *session_by_tty(char *); void session_close(Session *); void do_setusercontext(struct passwd *); -void child_set_env(char ***envp, u_int *envsizep, const char *name, +void child_set_env(char ***envp, u_int *envsizep, const char *name, const char *value); #endif diff --git a/openssh/ssh-gss.h b/openssh/ssh-gss.h index 1d2ec36..2260232 100644 --- a/openssh/ssh-gss.h +++ b/openssh/ssh-gss.h @@ -53,6 +53,7 @@ #define SSH2_MSG_USERAUTH_GSSAPI_TOKEN 61 #define SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE 63 #define SSH2_MSG_USERAUTH_GSSAPI_ERROR 64 +#define SSH2_MSG_USERAUTH_GSSAPI_ERRTOK 65 #define KEX_GSS_SHA1 "gss-group1-sha1-" @@ -126,8 +127,9 @@ 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); +gss_OID ssh_gssapi_server_id_kex(char *name); int ssh_gssapi_userok(char *name); +int ssh_gssapi_localname(char **name); void ssh_gssapi_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit); diff --git a/openssh/sshconnect2.c b/openssh/sshconnect2.c index cf19388..39cffd9 100644 --- a/openssh/sshconnect2.c +++ b/openssh/sshconnect2.c @@ -91,7 +91,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) #ifdef GSSAPI /* Add the GSSAPI mechanisms currently supported on this client to - * the key exchange algorithm proposal */ + * the key exchange algorithm proposal */ orig = myproposal[PROPOSAL_KEX_ALGS]; gss = ssh_gssapi_client_mechanisms(host); if (gss) { @@ -223,10 +223,11 @@ int userauth_hostbased(Authctxt *); #ifdef GSSAPI int userauth_external(Authctxt *authctxt); 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_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 *); @@ -504,16 +505,16 @@ userauth_gssapi(Authctxt *authctxt) 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. */ + * 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; /* 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. - */ + * bother trying to get credentials - as the standard fallback will + * deal with that kind of failure. + */ if (supported==NULL) gss_indicate_mechs(&min, &supported); @@ -523,12 +524,12 @@ userauth_gssapi(Authctxt *authctxt) ssh_gssapi_set_oid(gssctxt,&supported->elements[mech]); /* The DER encoding below only works for lengths<128, - * so check this here - */ + * so check this here + */ if (supported->elements[mech].length<128 && !GSS_ERROR(ssh_gssapi_import_name(gssctxt, authctxt->host))) { - ok = 1; /* Mechanism works */ + ok = 1; /* Mechanism works */ } else { mech++; } @@ -546,8 +547,8 @@ userauth_gssapi(Authctxt *authctxt) packet_put_int(1); /* The newest gsskeyex draft stipulates that OIDs should - * be DER encoded, so we need to add the object type and - * length information back on */ + * 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); @@ -565,6 +566,7 @@ userauth_gssapi(Authctxt *authctxt) 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 */ @@ -612,6 +614,12 @@ input_gssapi_response(int type, u_int32_t plen, void *ctxt) 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(); + packet_write_wait(); + } /* Start again with next method on list */ debug("Trying to start again"); clear_auth_state(authctxt); @@ -647,6 +655,12 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) packet_check_eom(); 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(); + packet_write_wait(); + } /* Start again with the next method in the list */ clear_auth_state(authctxt); userauth(authctxt,NULL); @@ -668,6 +682,35 @@ input_gssapi_token(int type, u_int32_t plen, void *ctxt) } } +void +input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) +{ + Authctxt *authctxt = ctxt; + Gssctxt *gssctxt; + gss_buffer_desc send_tok,recv_tok; + OM_uint32 status; + + if (authctxt == NULL) + fatal("input_gssapi_response: no authentication context"); + gssctxt = authctxt->methoddata; + + recv_tok.value=packet_get_string(&recv_tok.length); + + /* Stick it into GSSAPI and see what it says */ + status=ssh_gssapi_init_ctx(gssctxt, options.gss_deleg_creds, + &recv_tok, &send_tok, NULL); + + packet_check_eom(); + + /* We can't send a packet to the server */ + + /* The draft says that we should wait for the server to fail + * before starting the next authentication. So, we clear the + * state, but don't do anything else */ + clear_auth_state(authctxt); + return; +} + void input_gssapi_error(int type, u_int32_t plen, void *ctxt) { diff --git a/openssh/sshd.c b/openssh/sshd.c index c595b28..2e0fee5 100644 --- a/openssh/sshd.c +++ b/openssh/sshd.c @@ -1831,7 +1831,7 @@ do_ssh2_kex(void) orig = myproposal[PROPOSAL_KEX_ALGS]; /* If we don't have a host key, then all of the algorithms - * currently in myproposal are useless */ + * currently in myproposal are useless */ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])==0) orig= NULL; -- 2.45.2