s4 dns: Add a prerequisites check for updates
[kai/samba.git] / source4 / dns_server / dns_update.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    DNS server handler for update requests
5
6    Copyright (C) 2010 Kai Blin  <kai@samba.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "libcli/util/ntstatus.h"
24 #include "librpc/ndr/libndr.h"
25 #include "librpc/gen_ndr/ndr_dns.h"
26 #include "librpc/gen_ndr/ndr_dnsp.h"
27 #include <ldb.h>
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/util.h"
30 #include "dns_server/dns_server.h"
31
32 static WERROR check_prerequsites(struct dns_server *dns,
33                                  TALLOC_CTX *mem_ctx,
34                                  const struct dns_name_packet *in,
35                                  const struct dns_res_rec *prereqs, uint16_t count)
36 {
37         const struct dns_name_question *zone;
38         size_t host_part_len = 0;
39         uint16_t i;
40
41         zone = in->questions;
42
43         for (i = 0; i < count; i++) {
44                 const struct dns_res_rec *r = &prereqs[i];
45                 bool match;
46
47                 if (r->ttl != 0) {
48                         return DNS_ERR(FORMAT_ERROR);
49                 }
50                 match = dns_name_match(zone->name, r->name, &host_part_len);
51                 if (!match) {
52                         /* TODO: check if we need to echo all prereqs if the
53                          * first fails */
54                         return DNS_ERR(NOTZONE);
55                 }
56                 if (r->rr_class == DNS_QCLASS_ANY) {
57                         if (r->length != 0) {
58                                 return DNS_ERR(FORMAT_ERROR);
59                         }
60                         if (r->rr_type == DNS_QTYPE_ALL) {
61                                 /* TODO: Check if zone has at least one RR */
62                                 return DNS_ERR(NAME_ERROR);
63                         } else {
64                                 /* TODO: Check if RR exists of the specified type */
65                                 return DNS_ERR(NXRRSET);
66                         }
67                         continue;
68                 }
69                 if (r->rr_class == DNS_QCLASS_NONE) {
70                         if (r->length != 0) {
71                                 return DNS_ERR(FORMAT_ERROR);
72                         }
73                         if (r->rr_type == DNS_QTYPE_ALL) {
74                                 /* TODO: Return this error if the given name exits in this zone */
75                                 return DNS_ERR(YXDOMAIN);
76                         } else {
77                                 /* TODO: Return error if there's an RRset of this type in the zone */
78                                 return DNS_ERR(YXRRSET);
79                         }
80                         continue;
81                 }
82                 if (r->rr_class == zone->question_class) {
83                         /* Check if there's a RR with this */
84                         return DNS_ERR(NOT_IMPLEMENTED);
85                 } else {
86                         return DNS_ERR(FORMAT_ERROR);
87                 }
88         }
89
90
91         return WERR_OK;
92 }
93
94 WERROR dns_server_process_update(struct dns_server *dns,
95                                  TALLOC_CTX *mem_ctx,
96                                  struct dns_name_packet *in,
97                                  const struct dns_res_rec *prereqs, uint16_t prereq_count,
98                                  struct dns_res_rec **updates,      uint16_t *update_count,
99                                  struct dns_res_rec **additional,   uint16_t *arcount)
100 {
101         struct dns_name_question *zone;
102         const struct dns_server_zone *z;
103         size_t host_part_len = 0;
104         WERROR werror = WERR_DNS_ERROR_RCODE_NOT_IMPLEMENTED;
105
106         if (in->qdcount != 1) {
107                 return DNS_ERR(FORMAT_ERROR);
108         }
109
110         zone = in->questions;
111
112         if (zone->question_type != DNS_QTYPE_SOA) {
113                 return DNS_ERR(FORMAT_ERROR);
114         }
115
116         DEBUG(0, ("Got a dns update request.\n"));
117
118         for (z = dns->zones; z != NULL; z = z->next) {
119                 bool match;
120
121                 match = dns_name_match(z->name, zone->name, &host_part_len);
122                 if (match) {
123                         break;
124                 }
125         }
126
127         if (z == NULL) {
128                 return DNS_ERR(NOTAUTH);
129         }
130
131         if (host_part_len != 0) {
132                 /* TODO: We need to delegate this one */
133                 return DNS_ERR(NOT_IMPLEMENTED);
134         }
135
136         werror = check_prerequsites(dns, mem_ctx, in, prereqs, prereq_count);
137         W_ERROR_NOT_OK_RETURN(werror);
138
139         return werror;
140 }