diff -ur samba-4.5.1/librpc/idl/dns.idl samba-4.5.1-patched/librpc/idl/dns.idl --- samba-4.5.1/librpc/idl/dns.idl 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/librpc/idl/dns.idl 2016-10-26 09:53:44.773864679 -0500 @@ -179,7 +179,7 @@ uint8 option_data[option_length]; } dns_opt_record; - typedef [flag(NDR_NO_COMP),public] struct { + typedef [public] struct { dns_string algorithm; uint32 inception; uint32 expiration; @@ -191,7 +191,7 @@ uint8 other_data[other_size]; } dns_tkey_record; - typedef [flag(NDR_NO_COMP),public] struct { + typedef [public] struct { dns_string algorithm_name; uint16 time_prefix; /* 0 until February 2106*/ uint32 time; @@ -204,7 +204,7 @@ uint8 other_data[other_size]; } dns_tsig_record; - typedef [flag(NDR_NO_COMP|NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct { + typedef [flag(NDR_NOALIGN|NDR_BIG_ENDIAN|NDR_PAHEX),public] struct { dns_string name; dns_qclass rr_class; uint32 ttl; @@ -212,6 +212,7 @@ uint16 time_prefix; /* 0 until February 2106*/ uint32 time; uint16 fudge; + uint16 original_id; uint16 error; uint16 other_size; uint8 other_data[other_size]; diff -ur samba-4.5.1/librpc/idl/idl_types.h samba-4.5.1-patched/librpc/idl/idl_types.h --- samba-4.5.1/librpc/idl/idl_types.h 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/librpc/idl/idl_types.h 2016-10-26 09:53:44.771864679 -0500 @@ -40,7 +40,6 @@ #define NDR_ALIGN2 LIBNDR_FLAG_ALIGN2 #define NDR_ALIGN4 LIBNDR_FLAG_ALIGN4 #define NDR_ALIGN8 LIBNDR_FLAG_ALIGN8 -#define NDR_NO_COMP LIBNDR_FLAG_NO_COMPRESSION /* this flag is used to force a section of IDL as little endian. It is needed for the epmapper IDL, which is defined as always being LE */ diff -ur samba-4.5.1/librpc/ndr/libndr.h samba-4.5.1-patched/librpc/ndr/libndr.h --- samba-4.5.1/librpc/ndr/libndr.h 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/librpc/ndr/libndr.h 2016-10-26 09:53:44.776864679 -0500 @@ -126,9 +126,6 @@ #define LIBNDR_FLAG_STR_RAW8 (1<<13) #define LIBNDR_STRING_FLAGS (0x7FFC) -/* Disable string token compression */ -#define LIBNDR_FLAG_NO_COMPRESSION (1<<15) - /* * don't debug NDR_ERR_BUFSIZE failures, * as the available buffer might be incomplete. diff -ur samba-4.5.1/librpc/ndr/ndr_dns.c samba-4.5.1-patched/librpc/ndr/ndr_dns.c --- samba-4.5.1/librpc/ndr/ndr_dns.c 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/librpc/ndr/ndr_dns.c 2016-10-26 09:53:44.774864679 -0500 @@ -169,30 +169,28 @@ size_t complen; uint32_t offset; - if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) { - /* see if we have pushed the remaining string already, - * if so we use a label pointer to this string - */ - ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s, - &offset, - (comparison_fn_t)strcmp, - false); - if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - uint8_t b[2]; - - if (offset > 0x3FFF) { - return ndr_push_error(ndr, NDR_ERR_STRING, - "offset for dns string " \ - "label pointer " \ - "%u[%08X] > 0x00003FFF", - offset, offset); - } - - b[0] = 0xC0 | (offset>>8); - b[1] = (offset & 0xFF); + /* see if we have pushed the remaining string already, + * if so we use a label pointer to this string + */ + ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s, + &offset, + (comparison_fn_t)strcmp, + false); + if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + uint8_t b[2]; - return ndr_push_bytes(ndr, b, 2); + if (offset > 0x3FFF) { + return ndr_push_error(ndr, NDR_ERR_STRING, + "offset for dns string " \ + "label pointer " \ + "%u[%08X] > 0x00003FFF", + offset, offset); } + + b[0] = 0xC0 | (offset>>8); + b[1] = (offset & 0xFF); + + return ndr_push_bytes(ndr, b, 2); } complen = strcspn(s, "."); @@ -215,10 +213,8 @@ /* remember the current component + the rest of the string * so it can be reused later */ - if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) { - NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s, - ndr->offset)); - } + NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s, + ndr->offset)); /* push just this component into the blob */ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, @@ -268,21 +264,8 @@ ndr_set_flags(&ndr->flags, LIBNDR_PRINT_ARRAY_HEX | LIBNDR_FLAG_NOALIGN); if (ndr_flags & NDR_SCALARS) { - uint32_t _flags_save_name = ndr->flags; - NDR_CHECK(ndr_push_align(ndr, 4)); - - switch (r->rr_type) { - case DNS_QTYPE_TKEY: - case DNS_QTYPE_TSIG: - ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NO_COMPRESSION); - break; - default: - break; - } NDR_CHECK(ndr_push_dns_string(ndr, NDR_SCALARS, r->name)); - ndr->flags = _flags_save_name; - NDR_CHECK(ndr_push_dns_qtype(ndr, NDR_SCALARS, r->rr_type)); NDR_CHECK(ndr_push_dns_qclass(ndr, NDR_SCALARS, r->rr_class)); NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->ttl)); Only in samba-4.5.1-patched: .lock-wscript diff -ur samba-4.5.1/source4/dns_server/dns_crypto.c samba-4.5.1-patched/source4/dns_server/dns_crypto.c --- samba-4.5.1/source4/dns_server/dns_crypto.c 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/source4/dns_server/dns_crypto.c 2016-10-26 09:55:58.100863812 -0500 @@ -146,13 +146,6 @@ tkey = dns_find_tkey(dns->tkeys, state->tsig->name); if (tkey == NULL) { - /* - * We must save the name for use in the TSIG error - * response and have no choice here but to save the - * keyname from the TSIG request. - */ - state->key_name = talloc_strdup(state->mem_ctx, - state->tsig->name); if (state->key_name == NULL) { return WERR_NOMEM; } @@ -160,16 +153,6 @@ return DNS_ERR(NOTAUTH); } - /* - * Remember the keyname that found an existing tkey, used - * later to fetch the key with dns_find_tkey() when signing - * and adding a TSIG record with MAC. - */ - state->key_name = talloc_strdup(state->mem_ctx, tkey->name); - if (state->key_name == NULL) { - return WERR_NOMEM; - } - /* FIXME: check TSIG here */ if (check_rec == NULL) { return WERR_NOMEM; @@ -227,6 +210,9 @@ return WERR_NOMEM; } + /*FIXME: Why is there too much padding? */ + buffer_len -= 2; + /* Now we also need to count down the additional record counter */ arcount = RSVAL(buffer, 10); RSSVAL(buffer, 10, arcount-1); @@ -234,8 +220,7 @@ status = gensec_check_packet(tkey->gensec, buffer, buffer_len, buffer, buffer_len, &sig); if (NT_STATUS_EQUAL(NT_STATUS_ACCESS_DENIED, status)) { - state->tsig_error = DNS_RCODE_BADSIG; - return DNS_ERR(NOTAUTH); + return DNS_ERR(BADKEY); } if (!NT_STATUS_IS_OK(status)) { @@ -244,31 +229,47 @@ } state->authenticated = true; + state->key_name = talloc_strdup(state->mem_ctx, tkey->name); + if (state->key_name == NULL) { + return WERR_NOMEM; + } return WERR_OK; } -static WERROR dns_tsig_compute_mac(TALLOC_CTX *mem_ctx, - struct dns_request_state *state, - struct dns_name_packet *packet, - struct dns_server_tkey *tkey, - time_t current_time, - DATA_BLOB *_psig) +WERROR dns_sign_tsig(struct dns_server *dns, + TALLOC_CTX *mem_ctx, + struct dns_request_state *state, + struct dns_name_packet *packet, + uint16_t error) { + WERROR werror; NTSTATUS status; enum ndr_err_code ndr_err; + time_t current_time = time(NULL); DATA_BLOB packet_blob, tsig_blob, sig; uint8_t *buffer = NULL; - uint8_t *p = NULL; size_t buffer_len = 0; + struct dns_server_tkey * tkey = NULL; + struct dns_res_rec *tsig = talloc_zero(mem_ctx, struct dns_res_rec); + struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); - size_t mac_size = 0; + + if (tsig == NULL) { + return WERR_NOMEM; + } if (check_rec == NULL) { return WERR_NOMEM; } + tkey = dns_find_tkey(dns->tkeys, state->key_name); + if (tkey == NULL) { + /* FIXME: read up on what to do when we can't find a key */ + return WERR_OK; + } + /* first build and verify check packet */ check_rec->name = talloc_strdup(check_rec, tkey->name); if (check_rec->name == NULL) { @@ -303,44 +304,15 @@ return DNS_ERR(SERVER_FAILURE); } - if (state->tsig != NULL) { - mac_size = state->tsig->rdata.tsig_record.mac_size; - } - - buffer_len = mac_size; - - buffer_len += packet_blob.length; - if (buffer_len < packet_blob.length) { - return WERR_INVALID_PARAM; - } - buffer_len += tsig_blob.length; - if (buffer_len < tsig_blob.length) { - return WERR_INVALID_PARAM; - } - + buffer_len = packet_blob.length + tsig_blob.length; buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len); if (buffer == NULL) { return WERR_NOMEM; } - p = buffer; - - /* - * RFC 2845 "4.2 TSIG on Answers", how to lay out the buffer - * that we're going to sign: - * 1. MAC of request (if present) - * 2. Outgoing packet - * 3. TSIG record - */ - if (mac_size > 0) { - memcpy(p, state->tsig->rdata.tsig_record.mac, mac_size); - p += mac_size; - } - - memcpy(p, packet_blob.data, packet_blob.length); - p += packet_blob.length; + memcpy(buffer, packet_blob.data, packet_blob.length); + memcpy(buffer+packet_blob.length, tsig_blob.data, tsig_blob.length); - memcpy(p, tsig_blob.data, tsig_blob.length); status = gensec_sign_packet(tkey->gensec, mem_ctx, buffer, buffer_len, buffer, buffer_len, &sig); @@ -348,63 +320,26 @@ return ntstatus_to_werror(status); } - *_psig = sig; - return WERR_OK; -} - -WERROR dns_sign_tsig(struct dns_server *dns, - TALLOC_CTX *mem_ctx, - struct dns_request_state *state, - struct dns_name_packet *packet, - uint16_t error) -{ - WERROR werror; - time_t current_time = time(NULL); - struct dns_res_rec *tsig = NULL; - DATA_BLOB sig = (DATA_BLOB) { - .data = NULL, - .length = 0 - }; - - tsig = talloc_zero(mem_ctx, struct dns_res_rec); - if (tsig == NULL) { - return WERR_NOMEM; - } - - if (state->tsig_error == DNS_RCODE_OK) { - struct dns_server_tkey *tkey = dns_find_tkey( - dns->tkeys, state->key_name); - if (tkey == NULL) { - return DNS_ERR(SERVER_FAILURE); - } - - werror = dns_tsig_compute_mac(mem_ctx, state, packet, - tkey, current_time, &sig); - if (!W_ERROR_IS_OK(werror)) { - return werror; - } - } - - tsig->name = talloc_strdup(tsig, state->key_name); + tsig->name = talloc_strdup(tsig, check_rec->name); if (tsig->name == NULL) { return WERR_NOMEM; } - tsig->rr_class = DNS_QCLASS_ANY; + tsig->rr_class = check_rec->rr_class; tsig->rr_type = DNS_QTYPE_TSIG; tsig->ttl = 0; tsig->length = UINT16_MAX; - tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, "gss-tsig"); - tsig->rdata.tsig_record.time_prefix = 0; - tsig->rdata.tsig_record.time = current_time; - tsig->rdata.tsig_record.fudge = 300; + tsig->rdata.tsig_record.algorithm_name = talloc_strdup(tsig, + check_rec->algorithm_name); + tsig->rdata.tsig_record.time_prefix = check_rec->time_prefix; + tsig->rdata.tsig_record.time = check_rec->time; + tsig->rdata.tsig_record.fudge = check_rec->fudge; tsig->rdata.tsig_record.error = state->tsig_error; tsig->rdata.tsig_record.original_id = packet->id; tsig->rdata.tsig_record.other_size = 0; tsig->rdata.tsig_record.other_data = NULL; - if (sig.length > 0) { - tsig->rdata.tsig_record.mac_size = sig.length; - tsig->rdata.tsig_record.mac = talloc_memdup(tsig, sig.data, sig.length); - } + tsig->rdata.tsig_record.mac_size = sig.length; + tsig->rdata.tsig_record.mac = talloc_memdup(tsig, sig.data, sig.length); + if (packet->arcount == 0) { packet->additional = talloc_zero(mem_ctx, struct dns_res_rec); diff -ur samba-4.5.1/source4/dns_server/dns_server.c samba-4.5.1-patched/source4/dns_server/dns_server.c --- samba-4.5.1/source4/dns_server/dns_server.c 2016-08-11 02:51:04.000000000 -0500 +++ samba-4.5.1-patched/source4/dns_server/dns_server.c 2016-10-26 09:53:44.521864679 -0500 @@ -152,6 +152,14 @@ NDR_PRINT_DEBUGC(DBGC_DNS, dns_name_packet, &state->in_packet); } + ret = dns_verify_tsig(dns, state, &state->state, &state->in_packet, in); + if (!W_ERROR_IS_OK(ret)) { + DEBUG(1, ("Failed to verify TSIG!\n")); + state->dns_err = werr_to_dns_err(ret); + tevent_req_done(req); + return tevent_req_post(req, ev); + } + if (state->in_packet.operation & DNS_FLAG_REPLY) { DEBUG(1, ("Won't reply to replies.\n")); tevent_req_werror(req, WERR_INVALID_PARAM); @@ -168,13 +176,6 @@ state->out_packet = state->in_packet; - ret = dns_verify_tsig(dns, state, &state->state, &state->out_packet, in); - if (!W_ERROR_IS_OK(ret)) { - state->dns_err = werr_to_dns_err(ret); - tevent_req_done(req); - return tevent_req_post(req, ev); - } - switch (state->in_packet.operation & DNS_OPCODE) { case DNS_OPCODE_QUERY: subreq = dns_server_process_query_send( @@ -235,9 +236,7 @@ return ret; } if ((state->dns_err != DNS_RCODE_OK) && - (state->dns_err != DNS_RCODE_NXDOMAIN) && - (state->dns_err != DNS_RCODE_NOTAUTH)) - { + (state->dns_err != DNS_RCODE_NXDOMAIN)) { goto drop; } if (state->dns_err != DNS_RCODE_OK) { diff -ur samba-4.5.1/source4/selftest/tests.py samba-4.5.1-patched/source4/selftest/tests.py --- samba-4.5.1/source4/selftest/tests.py 2016-10-24 14:37:30.000000000 -0500 +++ samba-4.5.1-patched/source4/selftest/tests.py 2016-10-26 09:53:44.493864679 -0500 @@ -361,8 +361,6 @@ plantestsuite_loadlist("samba.tests.dns_forwarder", "fl2003dc:local", [python, os.path.join(srcdir(), "python/samba/tests/dns_forwarder.py"), '$SERVER', '$SERVER_IP', '$DNS_FORWARDER1', '$DNS_FORWARDER2', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) -plantestsuite_loadlist("samba.tests.dns_tkey", "fl2008r2dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_tkey.py"), '$SERVER', '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) - for t in smbtorture4_testsuites("dns_internal."): plansmbtorture4testsuite(t, "ad_dc_ntvfs:local", '//$SERVER/whavever')