From d879aa8f3617b256a16889d04a39a25b27f5bb39 Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Thu, 14 Dec 2006 16:27:45 +0000 Subject: [PATCH] r20170: Fix secure DNS updates to work against Wnidows 2000 DNS which expects the TKEY payload to be in the answer section and not in the additional set of records (like Windows 2003 and the RFC). (This used to be commit a3b6734fdad5fd92dbec075ebcd8d7044aac45c2) --- source3/libaddns/dns.h | 11 ++++++----- source3/libaddns/dnsgss.c | 31 +++++++++++++++++++++++-------- source3/libaddns/dnsrecord.c | 18 ++++++++++++------ source3/utils/net_dns.c | 14 ++++++++++++-- 4 files changed, 53 insertions(+), 21 deletions(-) diff --git a/source3/libaddns/dns.h b/source3/libaddns/dns.h index a8673563ae7..e8fa12c492d 100644 --- a/source3/libaddns/dns.h +++ b/source3/libaddns/dns.h @@ -280,6 +280,8 @@ typedef int BOOL; #endif +enum dns_ServerType { DNS_SRV_ANY, DNS_SRV_WIN2000, DNS_SRV_WIN2003 }; + struct dns_domain_label { struct dns_domain_label *next; char *label; @@ -405,9 +407,6 @@ DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx, const char *name, const in_addr_t *ip, struct dns_rrec **prec); -DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx, - const char *name, uint32 type, - struct dns_rrec **prec); DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name, uint16 type, uint16 r_class, struct dns_rrec **prec); @@ -484,7 +483,8 @@ void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat ); DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm, const char *servername, const char *keyname, - gss_ctx_id_t *gss_ctx ); + gss_ctx_id_t *gss_ctx, + enum dns_ServerType srv_type ); DNS_ERROR dns_sign_update(struct dns_update_request *req, gss_ctx_id_t gss_ctx, const char *keyname, @@ -493,7 +493,8 @@ DNS_ERROR dns_sign_update(struct dns_update_request *req, DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx, const char *domainname, const char *hostname, - in_addr_t ip_addr, + const in_addr_t *ip_addr, + size_t num_adds, struct dns_update_request **preq); #endif /* HAVE_GSSAPI_SUPPORT */ diff --git a/source3/libaddns/dnsgss.c b/source3/libaddns/dnsgss.c index 3d1a038363d..5be13a3b771 100644 --- a/source3/libaddns/dnsgss.c +++ b/source3/libaddns/dnsgss.c @@ -45,6 +45,7 @@ static int strupr( char *szDomainName ) return ( 0 ); } +#if 0 /********************************************************************* *********************************************************************/ @@ -76,12 +77,14 @@ void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat ) display_status_1( msg, maj_stat, GSS_C_GSS_CODE ); display_status_1( msg, min_stat, GSS_C_MECH_CODE ); } +#endif static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx, struct dns_connection *conn, const char *keyname, const gss_name_t target_name, - gss_ctx_id_t *ctx ) + gss_ctx_id_t *ctx, + enum dns_ServerType srv_type ) { struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc; OM_uint32 major, minor; @@ -123,11 +126,21 @@ static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx, req, keyname, "gss.microsoft.com", t, t + 86400, DNS_TKEY_MODE_GSSAPI, 0, output_desc.length, (uint8 *)output_desc.value, - &rec); + &rec ); if (!ERR_DNS_IS_OK(err)) goto error; - err = dns_add_rrec(req, rec, &req->num_additionals, - &req->additionals); + /* Windows 2000 DNS is broken and requires the + TKEY payload in the Answer section instead + of the Additional seciton like Windows 2003 */ + + if ( srv_type == DNS_SRV_WIN2000 ) { + err = dns_add_rrec(req, rec, &req->num_answers, + &req->answers); + } else { + err = dns_add_rrec(req, rec, &req->num_additionals, + &req->additionals); + } + if (!ERR_DNS_IS_OK(err)) goto error; err = dns_marshall_request(req, req, &buf); @@ -163,6 +176,7 @@ static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx, */ if ((resp->num_additionals != 1) || + (resp->num_answers == 0) || (resp->answers[0]->type != QTYPE_TKEY)) { err = ERROR_DNS_INVALID_MESSAGE; goto error; @@ -194,7 +208,8 @@ static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx, DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm, const char *servername, const char *keyname, - gss_ctx_id_t *gss_ctx ) + gss_ctx_id_t *gss_ctx, + enum dns_ServerType srv_type ) { OM_uint32 major, minor; @@ -250,12 +265,12 @@ DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm, goto error; } - err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname, targ_name, - gss_ctx); + err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname, + targ_name, gss_ctx, srv_type ); + gss_release_name( &minor, &targ_name ); krb5_free_principal( krb_ctx, host_principal ); krb5_free_context( krb_ctx ); - gss_release_name( &minor, &targ_name ); error: TALLOC_FREE(mem_ctx); diff --git a/source3/libaddns/dnsrecord.c b/source3/libaddns/dnsrecord.c index 6dfb8edf5cf..0cf4793935d 100644 --- a/source3/libaddns/dnsrecord.c +++ b/source3/libaddns/dnsrecord.c @@ -356,12 +356,14 @@ DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone, DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx, const char *domainname, const char *hostname, - in_addr_t ip_addr, + const in_addr_t *ip_addr, + size_t num_addrs, struct dns_update_request **preq) { struct dns_update_request *req; struct dns_rrec *rec; DNS_ERROR err; + size_t i; err = dns_create_update(mem_ctx, domainname, &req); if (!ERR_DNS_IS_OK(err)) return err; @@ -389,14 +391,18 @@ DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx, if (!ERR_DNS_IS_OK(err)) goto error; /* - * .. and add our IP + * .. and add our IPs */ - err = dns_create_a_record(req, hostname, 3600, ip_addr, &rec); - if (!ERR_DNS_IS_OK(err)) goto error; + for ( i=0; inum_updates, &req->updates); - if (!ERR_DNS_IS_OK(err)) goto error; + err = dns_add_rrec(req, rec, &req->num_updates, &req->updates); + if (!ERR_DNS_IS_OK(err)) + goto error; + } *preq = req; return ERROR_DNS_SUCCESS; diff --git a/source3/utils/net_dns.c b/source3/utils/net_dns.c index d372211a5ff..81d7dd596a8 100644 --- a/source3/utils/net_dns.c +++ b/source3/utils/net_dns.c @@ -118,8 +118,18 @@ DNS_ERROR DoDNSUpdate(ADS_STRUCT *ads, char *pszServerName, } err = dns_negotiate_sec_ctx( pszDomainName, pszServerName, - keyname, &gss_context ); - if (!ERR_DNS_IS_OK(err)) goto error; + keyname, &gss_context, DNS_SRV_ANY ); + + /* retry using the Windows 2000 DNS hack */ + if (!ERR_DNS_IS_OK(err)) { + err = dns_negotiate_sec_ctx( pszDomainName, pszServerName, + keyname, &gss_context, + DNS_SRV_WIN2000 ); + } + + if (!ERR_DNS_IS_OK(err)) + goto error; + err = dns_sign_update(req, gss_context, keyname, "gss.microsoft.com", time(NULL), 3600);