From 63e58ad048e479dc3d5179b3b01fbb6450253ddf Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 14 Jul 2016 15:06:28 +1000 Subject: [PATCH] 4413. [bug] GSSAPI negotiation could fail if GSS_S_CONTINUE_NEEDED was returned. [RT #42733] --- CHANGES | 3 ++ bin/nsupdate/nsupdate.c | 10 ++++--- lib/dns/gssapictx.c | 6 ++-- lib/dns/include/dst/gssapi.h | 1 + lib/dns/spnego.c | 4 +-- lib/dns/tkey.c | 58 ++++++++++++++++++++++++++++-------- 6 files changed, 60 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index dfda273cef..cf4356d188 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4413. [bug] GSSAPI negotiation could fail if GSS_S_CONTINUE_NEEDED + was returned. [RT #42733] + 4412. [cleanup] Make fixes for GCC 6. ISC_OFFSET_MAXIMUM macro was removed. [RT #42721] diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c index 96fb76b119..894bddbee8 100644 --- a/bin/nsupdate/nsupdate.c +++ b/bin/nsupdate/nsupdate.c @@ -2976,13 +2976,15 @@ recvgss(isc_task_t *task, isc_event_t *event) { tsigkey = NULL; result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, &context, &tsigkey, gssring, - use_win2k_gsstsig, - &err_message); + use_win2k_gsstsig, &err_message); switch (result) { case DNS_R_CONTINUE: + dns_message_destroy(&rcvmsg); + dns_request_destroy(&request); send_gssrequest(kserver, tsigquery, &request, context); - break; + ddebug("Out of recvgss"); + return; case ISC_R_SUCCESS: /* @@ -3019,7 +3021,7 @@ recvgss(isc_task_t *task, isc_event_t *event) { break; default: - fatal("dns_tkey_negotiategss: %s %s", + fatal("dns_tkey_gssnegotiate: %s %s", isc_result_totext(result), err_message != NULL ? err_message : ""); } diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c index bbcaf7c073..3b92805cb1 100644 --- a/lib/dns/gssapictx.c +++ b/lib/dns/gssapictx.c @@ -712,10 +712,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, switch (gret) { case GSS_S_COMPLETE: - result = ISC_R_SUCCESS; - break; case GSS_S_CONTINUE_NEEDED: - result = DNS_R_CONTINUE; break; case GSS_S_DEFECTIVE_TOKEN: case GSS_S_DEFECTIVE_CREDENTIAL: @@ -780,7 +777,8 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, gss_error_tostring(gret, minor, buf, sizeof(buf))); } - } + } else + result = DNS_R_CONTINUE; *ctxout = context; diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h index aa2a183c33..c22e8290d3 100644 --- a/lib/dns/include/dst/gssapi.h +++ b/lib/dns/include/dst/gssapi.h @@ -136,6 +136,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred, * Returns: * ISC_R_SUCCESS msg was successfully updated to include the * query to be sent + * DNS_R_CONTINUE transaction still in progress * other an error occurred while building the message */ diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c index aa4714e94b..9e367f9593 100644 --- a/lib/dns/spnego.c +++ b/lib/dns/spnego.c @@ -561,7 +561,7 @@ gss_accept_sec_context_spnego(OM_uint32 *minor_status, gss_cred_id_t *delegated_cred_handle) { NegTokenInit init_token; - OM_uint32 major_status; + OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 minor_status2; gss_buffer_desc ibuf, obuf; gss_buffer_t ot = NULL; @@ -677,7 +677,7 @@ gss_accept_sec_context_spnego(OM_uint32 *minor_status, if (ot != NULL && ot->length != 0U) gss_release_buffer(&minor_status2, ot); - return (ret); + return (ret != GSS_S_COMPLETE ? ret : major_status); } /* decapsulate.c */ diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c index d5b866e5d4..9e1c6a191e 100644 --- a/lib/dns/tkey.c +++ b/lib/dns/tkey.c @@ -444,7 +444,8 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, isc_result_t result = ISC_R_SUCCESS; dst_key_t *dstkey = NULL; dns_tsigkey_t *tsigkey = NULL; - dns_fixedname_t principal; + dns_fixedname_t fixed; + dns_name_t *principal; isc_stdtime_t now; isc_region_t intoken; isc_buffer_t *outtoken = NULL; @@ -481,16 +482,15 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, if (result == ISC_R_SUCCESS) gss_ctx = dst_key_getgssctx(tsigkey->key); - dns_fixedname_init(&principal); + dns_fixedname_init(&fixed); + principal = dns_fixedname_name(&fixed); /* * Note that tctx->gsscred may be NULL if tctx->gssapi_keytab is set */ result = dst_gssapi_acceptctx(tctx->gsscred, tctx->gssapi_keytab, - &intoken, - &outtoken, &gss_ctx, - dns_fixedname_name(&principal), - tctx->mctx); + &intoken, &outtoken, &gss_ctx, + principal, tctx->mctx); if (result == DNS_R_INVALIDTKEY) { if (tsigkey != NULL) dns_tsigkey_detach(&tsigkey); @@ -506,7 +506,10 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, isc_stdtime_get(&now); - if (tsigkey == NULL) { + if (dns_name_countlabels(principal) == 0U) { + if (tsigkey != NULL) + dns_tsigkey_detach(&tsigkey); + } else if (tsigkey == NULL) { #ifdef GSSAPI OM_uint32 gret, minor, lifetime; #endif @@ -525,8 +528,7 @@ process_gsstkey(dns_name_t *name, dns_rdata_tkey_t *tkeyin, expire = now + lifetime; #endif RETERR(dns_tsigkey_createfromkey(name, &tkeyin->algorithm, - dstkey, ISC_TRUE, - dns_fixedname_name(&principal), + dstkey, ISC_TRUE, principal, now, expire, ring->mctx, ring, NULL)); dst_key_free(&dstkey); @@ -1262,7 +1264,7 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, dst_key_t *dstkey = NULL; isc_buffer_t intoken; isc_result_t result; - unsigned char array[1024]; + unsigned char array[TEMP_BUFFER_SZ]; REQUIRE(outtoken != NULL); REQUIRE(qmsg != NULL); @@ -1391,11 +1393,11 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, { dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; dns_name_t *tkeyname; - dns_rdata_tkey_t rtkey, qtkey; + dns_rdata_tkey_t rtkey, qtkey, tkey; isc_buffer_t intoken, outtoken; dst_key_t *dstkey = NULL; isc_result_t result; - unsigned char array[1024]; + unsigned char array[TEMP_BUFFER_SZ]; isc_boolean_t freertkey = ISC_FALSE; REQUIRE(qmsg != NULL); @@ -1438,6 +1440,38 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) return (result); + if (result == DNS_R_CONTINUE) { + dns_fixedname_t fixed; + + dns_fixedname_init(&fixed); + dns_name_copy(tkeyname, dns_fixedname_name(&fixed), NULL); + tkeyname = dns_fixedname_name(&fixed); + + tkey.common.rdclass = dns_rdataclass_any; + tkey.common.rdtype = dns_rdatatype_tkey; + ISC_LINK_INIT(&tkey.common, link); + tkey.mctx = NULL; + dns_name_init(&tkey.algorithm, NULL); + + if (win2k) + dns_name_clone(DNS_TSIG_GSSAPIMS_NAME, &tkey.algorithm); + else + dns_name_clone(DNS_TSIG_GSSAPI_NAME, &tkey.algorithm); + + tkey.inception = qtkey.inception; + tkey.expire = qtkey.expire; + tkey.mode = DNS_TKEYMODE_GSSAPI; + tkey.error = 0; + tkey.key = isc_buffer_base(&outtoken); + tkey.keylen = isc_buffer_usedlength(&outtoken); + tkey.other = NULL; + tkey.otherlen = 0; + + dns_message_reset(qmsg, DNS_MESSAGE_INTENTRENDER); + RETERR(buildquery(qmsg, tkeyname, &tkey, win2k)); + return (DNS_R_CONTINUE); + } + RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, &dstkey, NULL));