uint8_t werr_to_dns_err(WERROR werr) { if (W_ERROR_EQUAL(WERR_OK, werr)) { return DNS_RCODE_OK; } else if (W_ERROR_EQUAL(DNS_ERR(FORMAT_ERROR), werr)) { return DNS_RCODE_FORMERR; } else if (W_ERROR_EQUAL(DNS_ERR(SERVER_FAILURE), werr)) { return DNS_RCODE_SERVFAIL; } else if (W_ERROR_EQUAL(DNS_ERR(NAME_ERROR), werr)) { return DNS_RCODE_NXDOMAIN; } else if (W_ERROR_EQUAL(DNS_ERR(NOT_IMPLEMENTED), werr)) { return DNS_RCODE_NOTIMP; } else if (W_ERROR_EQUAL(DNS_ERR(REFUSED), werr)) { return DNS_RCODE_REFUSED; } else if (W_ERROR_EQUAL(DNS_ERR(YXDOMAIN), werr)) { return DNS_RCODE_YXDOMAIN; } else if (W_ERROR_EQUAL(DNS_ERR(YXRRSET), werr)) { return DNS_RCODE_YXRRSET; } else if (W_ERROR_EQUAL(DNS_ERR(NXRRSET), werr)) { return DNS_RCODE_NXRRSET; } else if (W_ERROR_EQUAL(DNS_ERR(NOTAUTH), werr)) { return DNS_RCODE_NOTAUTH; } else if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) { return DNS_RCODE_NOTZONE; } DEBUG(5, ("No mapping exists for %%s\n")); return DNS_RCODE_SERVFAIL; }
WERROR dns_server_process_query(struct dns_server *dns, struct dns_request_state *state, TALLOC_CTX *mem_ctx, struct dns_name_packet *in, struct dns_res_rec **answers, uint16_t *ancount, struct dns_res_rec **nsrecs, uint16_t *nscount, struct dns_res_rec **additional, uint16_t *arcount) { uint16_t num_answers=0, num_nsrecs=0, num_additional=0; struct dns_res_rec *ans=NULL, *ns=NULL, *adds=NULL; WERROR werror; if (in->qdcount != 1) { return DNS_ERR(FORMAT_ERROR); } /* Windows returns NOT_IMPLEMENTED on this as well */ if (in->questions[0].question_class == DNS_QCLASS_NONE) { return DNS_ERR(NOT_IMPLEMENTED); } if (dns_authorative_for_zone(dns, in->questions[0].name)) { state->flags |= DNS_FLAG_AUTHORITATIVE; werror = handle_question(dns, mem_ctx, &in->questions[0], &ans, &num_answers); } else { if (state->flags & DNS_FLAG_RECURSION_DESIRED && state->flags & DNS_FLAG_RECURSION_AVAIL) { DEBUG(2, ("Not authorative for '%s', forwarding\n", in->questions[0].name)); werror = ask_forwarder(dns, mem_ctx, &in->questions[0], &ans, &num_answers, &ns, &num_nsrecs, &adds, &num_additional); } else { werror = DNS_ERR(NAME_ERROR); } } W_ERROR_NOT_OK_GOTO(werror, query_failed); *answers = ans; *ancount = num_answers; /*FIXME: Do something for these */ *nsrecs = ns; *nscount = num_nsrecs; *additional = adds; *arcount = num_additional; return WERR_OK; query_failed: /*FIXME: add our SOA record to nsrecs */ return werror; }
WERROR dns_name2dn(struct dns_server *dns, TALLOC_CTX *mem_ctx, const char *name, struct ldb_dn **_dn) { struct ldb_dn *base; struct ldb_dn *dn; const struct dns_server_zone *z; size_t host_part_len = 0; if (name == NULL) { return DNS_ERR(FORMAT_ERROR); } /*TODO: Check if 'name' is a valid DNS name */ if (strcmp(name, "") == 0) { base = ldb_get_default_basedn(dns->samdb); dn = ldb_dn_copy(mem_ctx, base); ldb_dn_add_child_fmt(dn, "DC=@,DC=RootDNSServers,CN=MicrosoftDNS,CN=System"); *_dn = dn; return WERR_OK; } for (z = dns->zones; z != NULL; z = z->next) { bool match; match = dns_name_match(z->name, name, &host_part_len); if (match) { break; } } if (z == NULL) { return DNS_ERR(NAME_ERROR); } if (host_part_len == 0) { dn = ldb_dn_copy(mem_ctx, z->dn); ldb_dn_add_child_fmt(dn, "DC=@"); *_dn = dn; return WERR_OK; } dn = ldb_dn_copy(mem_ctx, z->dn); ldb_dn_add_child_fmt(dn, "DC=%*.*s", (int)host_part_len, (int)host_part_len, name); *_dn = dn; return WERR_OK; }
WERROR dns_lookup_records(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct dnsp_DnssrvRpcRecord **records, uint16_t *rec_count) { static const char * const attrs[] = { "dnsRecord", NULL}; struct ldb_message_element *el; uint16_t ri; int ret; struct ldb_message *msg = NULL; struct dnsp_DnssrvRpcRecord *recs; ret = dsdb_search_one(dns->samdb, mem_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "%s", "(objectClass=dnsNode)"); if (ret != LDB_SUCCESS) { /* TODO: we need to check if there's a glue record we need to * create a referral to */ return DNS_ERR(NAME_ERROR); } el = ldb_msg_find_element(msg, attrs[0]); if (el == NULL) { *records = NULL; *rec_count = 0; return WERR_OK; } recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord, el->num_values); W_ERROR_HAVE_NO_MEMORY(recs); for (ri = 0; ri < el->num_values; ri++) { struct ldb_val *v = &el->values[ri]; enum ndr_err_code ndr_err; ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri], (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); return DNS_ERR(SERVER_FAILURE); } } *records = recs; *rec_count = el->num_values; return WERR_OK; }
static WERROR create_response_rr(const struct dns_name_question *question, const struct dnsp_DnssrvRpcRecord *rec, struct dns_res_rec **answers, uint16_t *ancount) { struct dns_res_rec *ans = *answers; uint16_t ai = *ancount; ZERO_STRUCT(ans[ai]); switch (rec->wType) { case DNS_QTYPE_CNAME: ans[ai].rdata.cname_record = talloc_strdup(ans, rec->data.cname); break; case DNS_QTYPE_A: ans[ai].rdata.ipv4_record = talloc_strdup(ans, rec->data.ipv4); break; case DNS_QTYPE_AAAA: ans[ai].rdata.ipv6_record = rec->data.ipv6; break; case DNS_TYPE_NS: ans[ai].rdata.ns_record = rec->data.ns; break; case DNS_QTYPE_SRV: ans[ai].rdata.srv_record.priority = rec->data.srv.wPriority; ans[ai].rdata.srv_record.weight = rec->data.srv.wWeight; ans[ai].rdata.srv_record.port = rec->data.srv.wPort; ans[ai].rdata.srv_record.target = rec->data.srv.nameTarget; break; case DNS_QTYPE_SOA: ans[ai].rdata.soa_record.mname = rec->data.soa.mname; ans[ai].rdata.soa_record.rname = rec->data.soa.rname; ans[ai].rdata.soa_record.serial = rec->data.soa.serial; ans[ai].rdata.soa_record.refresh = rec->data.soa.refresh; ans[ai].rdata.soa_record.retry = rec->data.soa.retry; ans[ai].rdata.soa_record.expire = rec->data.soa.expire; ans[ai].rdata.soa_record.minimum = rec->data.soa.minimum; break; default: return DNS_ERR(NOT_IMPLEMENTED); } ans[ai].name = talloc_strdup(ans, question->name); ans[ai].rr_type = rec->wType; ans[ai].rr_class = DNS_QCLASS_IN; ans[ai].ttl = rec->dwTtlSeconds; ans[ai].length = UINT16_MAX; ai++; *answers = ans; *ancount = ai; return WERR_OK; }
WERROR dns_server_process_query(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct dns_name_packet *in, struct dns_res_rec **answers, uint16_t *ancount, struct dns_res_rec **nsrecs, uint16_t *nscount, struct dns_res_rec **additional, uint16_t *arcount) { uint16_t num_answers=0; struct dns_res_rec *ans=NULL; WERROR werror; if (in->qdcount != 1) { return DNS_ERR(FORMAT_ERROR); } /* Windows returns NOT_IMPLEMENTED on this as well */ if (in->questions[0].question_class == DNS_QCLASS_NONE) { return DNS_ERR(NOT_IMPLEMENTED); } werror = handle_question(dns, mem_ctx, &in->questions[0], &ans, &num_answers); W_ERROR_NOT_OK_GOTO(werror, query_failed); *answers = ans; *ancount = num_answers; /*FIXME: Do something for these */ *nsrecs = NULL; *nscount = 0; *additional = NULL; *arcount = 0; return WERR_OK; query_failed: /*FIXME: add our SOA record to nsrecs */ return werror; }
static WERROR handle_question(struct dns_server *dns, TALLOC_CTX *mem_ctx, const struct dns_name_question *question, struct dns_res_rec **answers, uint16_t *ancount) { struct dns_res_rec *ans; WERROR werror; unsigned int ri; struct dnsp_DnssrvRpcRecord *recs; uint16_t rec_count, ai = 0; struct ldb_dn *dn = NULL; werror = dns_name2dn(dns, mem_ctx, question->name, &dn); W_ERROR_NOT_OK_RETURN(werror); werror = dns_lookup_records(dns, mem_ctx, dn, &recs, &rec_count); W_ERROR_NOT_OK_RETURN(werror); ans = talloc_zero_array(mem_ctx, struct dns_res_rec, rec_count); W_ERROR_HAVE_NO_MEMORY(ans); for (ri = 0; ri < rec_count; ri++) { if ((question->question_type != DNS_QTYPE_ALL) && (recs[ri].wType != question->question_type)) { continue; } werror = create_response_rr(question, &recs[ri], &ans, &ai); W_ERROR_NOT_OK_RETURN(werror); } if (ai == 0) { return DNS_ERR(NAME_ERROR); } *ancount = ai; *answers = ans; return WERR_OK; }
static WERROR create_response_rr(const struct dns_name_question *question, const struct dnsp_DnssrvRpcRecord *rec, struct dns_res_rec **answers, uint16_t *ancount) { struct dns_res_rec *ans = *answers; uint16_t ai = *ancount; char *tmp; uint32_t i; ZERO_STRUCT(ans[ai]); switch (rec->wType) { case DNS_QTYPE_CNAME: ans[ai].rdata.cname_record = talloc_strdup(ans, rec->data.cname); break; case DNS_QTYPE_A: ans[ai].rdata.ipv4_record = talloc_strdup(ans, rec->data.ipv4); break; case DNS_QTYPE_AAAA: ans[ai].rdata.ipv6_record = rec->data.ipv6; break; case DNS_TYPE_NS: ans[ai].rdata.ns_record = rec->data.ns; break; case DNS_QTYPE_SRV: ans[ai].rdata.srv_record.priority = rec->data.srv.wPriority; ans[ai].rdata.srv_record.weight = rec->data.srv.wWeight; ans[ai].rdata.srv_record.port = rec->data.srv.wPort; ans[ai].rdata.srv_record.target = rec->data.srv.nameTarget; break; case DNS_QTYPE_SOA: ans[ai].rdata.soa_record.mname = rec->data.soa.mname; ans[ai].rdata.soa_record.rname = rec->data.soa.rname; ans[ai].rdata.soa_record.serial = rec->data.soa.serial; ans[ai].rdata.soa_record.refresh = rec->data.soa.refresh; ans[ai].rdata.soa_record.retry = rec->data.soa.retry; ans[ai].rdata.soa_record.expire = rec->data.soa.expire; ans[ai].rdata.soa_record.minimum = rec->data.soa.minimum; break; case DNS_QTYPE_PTR: ans[ai].rdata.ptr_record = talloc_strdup(ans, rec->data.ptr); break; case DNS_QTYPE_TXT: tmp = talloc_asprintf(ans, "\"%s\"", rec->data.txt.str[0]); for (i=1; i<rec->data.txt.count; i++) { tmp = talloc_asprintf_append(tmp, " \"%s\"", rec->data.txt.str[i]); } ans[ai].rdata.txt_record.txt = tmp; break; default: DEBUG(0, ("Got unhandled type %u query.\n", rec->wType)); return DNS_ERR(NOT_IMPLEMENTED); } ans[ai].name = talloc_strdup(ans, question->name); ans[ai].rr_type = rec->wType; ans[ai].rr_class = DNS_QCLASS_IN; ans[ai].ttl = rec->dwTtlSeconds; ans[ai].length = UINT16_MAX; ai++; *answers = ans; *ancount = ai; return WERR_OK; }
static WERROR ask_forwarder(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct dns_name_question *question, struct dns_res_rec **answers, uint16_t *ancount, struct dns_res_rec **nsrecs, uint16_t *nscount, struct dns_res_rec **additional, uint16_t *arcount) { struct tevent_context *ev = tevent_context_init(mem_ctx); struct dns_name_packet *out_packet, *in_packet; uint16_t id = random(); DATA_BLOB out, in; enum ndr_err_code ndr_err; WERROR werr = WERR_OK; struct tevent_req *req; const char *forwarder = lpcfg_dns_forwarder(dns->task->lp_ctx); if (!is_ipaddress(forwarder)) { DEBUG(0, ("Invalid 'dns forwarder' setting '%s', needs to be " "an IP address\n", forwarder)); return DNS_ERR(NAME_ERROR); } out_packet = talloc_zero(mem_ctx, struct dns_name_packet); W_ERROR_HAVE_NO_MEMORY(out_packet); out_packet->id = id; out_packet->operation |= DNS_OPCODE_QUERY | DNS_FLAG_RECURSION_DESIRED; out_packet->qdcount = 1; out_packet->questions = question; ndr_err = ndr_push_struct_blob(&out, mem_ctx, out_packet, (ndr_push_flags_fn_t)ndr_push_dns_name_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return DNS_ERR(SERVER_FAILURE); } req = dns_udp_request_send(mem_ctx, ev, forwarder, out.data, out.length); W_ERROR_HAVE_NO_MEMORY(req); if(!tevent_req_poll(req, ev)) { return DNS_ERR(SERVER_FAILURE); } werr = dns_udp_request_recv(req, mem_ctx, &in.data, &in.length); W_ERROR_NOT_OK_RETURN(werr); in_packet = talloc_zero(mem_ctx, struct dns_name_packet); W_ERROR_HAVE_NO_MEMORY(in_packet); ndr_err = ndr_pull_struct_blob(&in, in_packet, in_packet, (ndr_pull_flags_fn_t)ndr_pull_dns_name_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { return DNS_ERR(SERVER_FAILURE); } if (in_packet->id != id) { DEBUG(0, ("DNS packet id mismatch: 0x%0x, expected 0x%0x\n", in_packet->id, id)); return DNS_ERR(NAME_ERROR); } *ancount = in_packet->ancount; *answers = talloc_move(mem_ctx, &in_packet->answers); *nscount = in_packet->nscount; *nsrecs = talloc_move(mem_ctx, &in_packet->nsrecs); *arcount = in_packet->arcount; *additional = talloc_move(mem_ctx, &in_packet->additional); return werr; }
WERROR dns_verify_tsig(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct dns_request_state *state, struct dns_name_packet *packet, DATA_BLOB *in) { WERROR werror; NTSTATUS status; enum ndr_err_code ndr_err; bool found_tsig = false; uint16_t i, arcount = 0; DATA_BLOB tsig_blob, fake_tsig_blob, sig; uint8_t *buffer = NULL; size_t buffer_len = 0, packet_len = 0; struct dns_server_tkey *tkey = NULL; struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); /* Find the first TSIG record in the additional records */ for (i=0; i < packet->arcount; i++) { if (packet->additional[i].rr_type == DNS_QTYPE_TSIG) { found_tsig = true; break; } } if (!found_tsig) { return WERR_OK; } /* The TSIG record needs to be the last additional record */ if (found_tsig && i + 1 != packet->arcount) { DEBUG(1, ("TSIG record not the last additional record!\n")); return DNS_ERR(FORMAT_ERROR); } /* We got a TSIG, so we need to sign our reply */ state->sign = true; state->tsig = talloc_zero(state->mem_ctx, struct dns_res_rec); if (state->tsig == NULL) { return WERR_NOT_ENOUGH_MEMORY; } werror = dns_copy_tsig(state->tsig, &packet->additional[i], state->tsig); if (!W_ERROR_IS_OK(werror)) { return werror; } packet->arcount--; 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_NOT_ENOUGH_MEMORY; } state->tsig_error = DNS_RCODE_BADKEY; 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_NOT_ENOUGH_MEMORY; } /* FIXME: check TSIG here */ if (check_rec == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* first build and verify check packet */ check_rec->name = talloc_strdup(check_rec, tkey->name); if (check_rec->name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->rr_class = DNS_QCLASS_ANY; check_rec->ttl = 0; check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm); if (check_rec->algorithm_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->time_prefix = 0; check_rec->time = state->tsig->rdata.tsig_record.time; check_rec->fudge = state->tsig->rdata.tsig_record.fudge; check_rec->error = 0; check_rec->other_size = 0; check_rec->other_data = NULL; ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, state->tsig, (ndr_push_flags_fn_t)ndr_push_dns_res_rec); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); return DNS_ERR(SERVER_FAILURE); } ndr_err = ndr_push_struct_blob(&fake_tsig_blob, mem_ctx, check_rec, (ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); return DNS_ERR(SERVER_FAILURE); } /* we need to work some magic here. we need to keep the input packet * exactly like we got it, but we need to cut off the tsig record */ packet_len = in->length - tsig_blob.length; buffer_len = packet_len + fake_tsig_blob.length; buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len); if (buffer == NULL) { return WERR_NOT_ENOUGH_MEMORY; } memcpy(buffer, in->data, packet_len); memcpy(buffer + packet_len, fake_tsig_blob.data, fake_tsig_blob.length); sig.length = state->tsig->rdata.tsig_record.mac_size; sig.data = talloc_memdup(mem_ctx, state->tsig->rdata.tsig_record.mac, sig.length); if (sig.data == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* Now we also need to count down the additional record counter */ arcount = RSVAL(buffer, 10); RSSVAL(buffer, 10, arcount-1); 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); } if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Verifying tsig failed: %s\n", nt_errstr(status))); return ntstatus_to_werror(status); } state->authenticated = true; 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_NOT_ENOUGH_MEMORY; } 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); if (tsig->name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } tsig->rr_class = DNS_QCLASS_ANY; 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.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); } if (packet->arcount == 0) { packet->additional = talloc_zero(mem_ctx, struct dns_res_rec); if (packet->additional == NULL) { return WERR_NOT_ENOUGH_MEMORY; } } packet->additional = talloc_realloc(mem_ctx, packet->additional, struct dns_res_rec, packet->arcount + 1); if (packet->additional == NULL) { return WERR_NOT_ENOUGH_MEMORY; } werror = dns_copy_tsig(mem_ctx, tsig, &packet->additional[packet->arcount]); if (!W_ERROR_IS_OK(werror)) { return werror; } packet->arcount++; 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) { NTSTATUS status; enum ndr_err_code ndr_err; DATA_BLOB packet_blob, tsig_blob, sig; uint8_t *buffer = NULL; uint8_t *p = NULL; size_t buffer_len = 0; struct dns_fake_tsig_rec *check_rec = talloc_zero(mem_ctx, struct dns_fake_tsig_rec); size_t mac_size = 0; if (check_rec == NULL) { return WERR_NOT_ENOUGH_MEMORY; } /* first build and verify check packet */ check_rec->name = talloc_strdup(check_rec, tkey->name); if (check_rec->name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->rr_class = DNS_QCLASS_ANY; check_rec->ttl = 0; check_rec->algorithm_name = talloc_strdup(check_rec, tkey->algorithm); if (check_rec->algorithm_name == NULL) { return WERR_NOT_ENOUGH_MEMORY; } check_rec->time_prefix = 0; check_rec->time = current_time; check_rec->fudge = 300; check_rec->error = state->tsig_error; check_rec->other_size = 0; check_rec->other_data = NULL; ndr_err = ndr_push_struct_blob(&packet_blob, mem_ctx, packet, (ndr_push_flags_fn_t)ndr_push_dns_name_packet); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); return DNS_ERR(SERVER_FAILURE); } ndr_err = ndr_push_struct_blob(&tsig_blob, mem_ctx, check_rec, (ndr_push_flags_fn_t)ndr_push_dns_fake_tsig_rec); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1, ("Failed to push packet: %s!\n", ndr_errstr(ndr_err))); 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_PARAMETER; } buffer_len += tsig_blob.length; if (buffer_len < tsig_blob.length) { return WERR_INVALID_PARAMETER; } buffer = talloc_zero_array(mem_ctx, uint8_t, buffer_len); if (buffer == NULL) { return WERR_NOT_ENOUGH_MEMORY; } 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(p, tsig_blob.data, tsig_blob.length); status = gensec_sign_packet(tkey->gensec, mem_ctx, buffer, buffer_len, buffer, buffer_len, &sig); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } *_psig = sig; return WERR_OK; }
WERROR dns_replace_records(struct dns_server *dns, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, bool needs_add, const struct dnsp_DnssrvRpcRecord *records, uint16_t rec_count) { struct ldb_message_element *el; uint16_t i; int ret; struct ldb_message *msg = NULL; msg = ldb_msg_new(mem_ctx); W_ERROR_HAVE_NO_MEMORY(msg); msg->dn = dn; ret = ldb_msg_add_empty(msg, "dnsRecord", LDB_FLAG_MOD_REPLACE, &el); if (ret != LDB_SUCCESS) { return DNS_ERR(SERVER_FAILURE); } el->values = talloc_zero_array(el, struct ldb_val, rec_count); if (rec_count > 0) { W_ERROR_HAVE_NO_MEMORY(el->values); } for (i = 0; i < rec_count; i++) { static const struct dnsp_DnssrvRpcRecord zero; struct ldb_val *v = &el->values[el->num_values]; enum ndr_err_code ndr_err; if (memcmp(&records[i], &zero, sizeof(zero)) == 0) { continue; } ndr_err = ndr_push_struct_blob(v, el->values, &records[i], (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n")); return DNS_ERR(SERVER_FAILURE); } el->num_values++; } if (el->num_values == 0) { if (needs_add) { return WERR_OK; } /* TODO: Delete object? */ } if (needs_add) { ret = ldb_msg_add_string(msg, "objectClass", "dnsNode"); if (ret != LDB_SUCCESS) { return DNS_ERR(SERVER_FAILURE); } ret = ldb_add(dns->samdb, msg); if (ret != LDB_SUCCESS) { return DNS_ERR(SERVER_FAILURE); } return WERR_OK; } ret = ldb_modify(dns->samdb, msg); if (ret != LDB_SUCCESS) { return DNS_ERR(SERVER_FAILURE); } return WERR_OK; }