lib/replace: split out GSSAPI from lib/replace/system/kerberos.h into lib/replace...
[sfrench/samba-autobuild/.git] / lib / addns / dnsrecord.c
1 /*
2   Linux DNS client library implementation
3   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
4   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
5
6      ** NOTE! The following LGPL license applies to the libaddns
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9
10   This library is free software; you can redistribute it and/or
11   modify it under the terms of the GNU Lesser General Public
12   License as published by the Free Software Foundation; either
13   version 2.1 of the License, or (at your option) any later version.
14
15   This library is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   Lesser General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public
21   License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "dns.h"
25
26 DNS_ERROR dns_create_query( TALLOC_CTX *mem_ctx, const char *name,
27                             uint16 q_type, uint16 q_class,
28                             struct dns_request **preq )
29 {
30         struct dns_request *req = NULL;
31         struct dns_question *q = NULL;
32         DNS_ERROR err;
33
34         if (!(req = talloc_zero(mem_ctx, struct dns_request)) ||
35             !(req->questions = talloc_array(req, struct dns_question *, 1)) ||
36             !(req->questions[0] = talloc(req->questions,
37                                          struct dns_question))) {
38                 TALLOC_FREE(req);
39                 return ERROR_DNS_NO_MEMORY;
40         }
41
42         req->id = random();
43
44         req->num_questions = 1;
45         q = req->questions[0];
46
47         err = dns_domain_name_from_string(q, name, &q->name);
48         if (!ERR_DNS_IS_OK(err)) {
49                 TALLOC_FREE(req);
50                 return err;
51         }
52
53         q->q_type = q_type;
54         q->q_class = q_class;
55
56         *preq = req;
57         return ERROR_DNS_SUCCESS;
58 }
59
60 DNS_ERROR dns_create_update( TALLOC_CTX *mem_ctx, const char *name,
61                              struct dns_update_request **preq )
62 {
63         struct dns_update_request *req = NULL;
64         struct dns_zone *z = NULL;
65         DNS_ERROR err;
66
67         if (!(req = talloc_zero(mem_ctx, struct dns_update_request)) ||
68             !(req->zones = talloc_array(req, struct dns_zone *, 1)) ||
69             !(req->zones[0] = talloc(req->zones, struct dns_zone))) {
70                 TALLOC_FREE(req);
71                 return ERROR_DNS_NO_MEMORY;
72         }
73
74         req->id = random();
75         req->flags = 0x2800;    /* Dynamic update */
76
77         req->num_zones = 1;
78         z = req->zones[0];
79
80         err = dns_domain_name_from_string(z, name, &z->name);
81         if (!ERR_DNS_IS_OK(err)) {
82                 TALLOC_FREE(req);
83                 return err;
84         }
85
86         z->z_type = QTYPE_SOA;
87         z->z_class = DNS_CLASS_IN;
88
89         *preq = req;
90         return ERROR_DNS_SUCCESS;
91 }
92
93 DNS_ERROR dns_create_rrec(TALLOC_CTX *mem_ctx, const char *name,
94                           uint16 type, uint16 r_class, uint32 ttl,
95                           uint16 data_length, uint8 *data,
96                           struct dns_rrec **prec)
97 {
98         struct dns_rrec *rec = NULL;
99         DNS_ERROR err;
100
101         if (!(rec = talloc(mem_ctx, struct dns_rrec))) {
102                 return ERROR_DNS_NO_MEMORY;
103         }
104
105         err = dns_domain_name_from_string(rec, name, &rec->name);
106         if (!(ERR_DNS_IS_OK(err))) {
107                 TALLOC_FREE(rec);
108                 return err;
109         }
110
111         rec->type = type;
112         rec->r_class = r_class;
113         rec->ttl = ttl;
114         rec->data_length = data_length;
115         rec->data = talloc_move(rec, &data);
116
117         *prec = rec;
118         return ERROR_DNS_SUCCESS;
119 }
120
121 DNS_ERROR dns_create_a_record(TALLOC_CTX *mem_ctx, const char *host,
122                               uint32 ttl, const struct sockaddr_storage *pss,
123                               struct dns_rrec **prec)
124 {
125         uint8 *data;
126         DNS_ERROR err;
127         struct in_addr ip;
128
129         if (pss->ss_family != AF_INET) {
130                 return ERROR_DNS_INVALID_PARAMETER;
131         }
132
133         ip = ((const struct sockaddr_in *)pss)->sin_addr;
134         if (!(data = (uint8 *)talloc_memdup(mem_ctx, (const void *)&ip.s_addr,
135                                             sizeof(ip.s_addr)))) {
136                 return ERROR_DNS_NO_MEMORY;
137         }
138
139         err = dns_create_rrec(mem_ctx, host, QTYPE_A, DNS_CLASS_IN, ttl,
140                               sizeof(ip.s_addr), data, prec);
141
142         if (!ERR_DNS_IS_OK(err)) {
143                 TALLOC_FREE(data);
144         }
145
146         return err;
147 }
148
149 DNS_ERROR dns_create_aaaa_record(TALLOC_CTX *mem_ctx, const char *host,
150                                  uint32 ttl, const struct sockaddr_storage *pss,
151                                  struct dns_rrec **prec)
152 {
153 #ifdef HAVE_IPV6
154         uint8 *data;
155         DNS_ERROR err;
156         struct in6_addr ip6;
157
158         if (pss->ss_family != AF_INET6) {
159                 return ERROR_DNS_INVALID_PARAMETER;
160         }
161
162         ip6 = ((const struct sockaddr_in6 *)pss)->sin6_addr;
163         if (!(data = (uint8 *)talloc_memdup(mem_ctx, (const void *)&ip6.s6_addr,
164                                             sizeof(ip6.s6_addr)))) {
165                 return ERROR_DNS_NO_MEMORY;
166         }
167
168         err = dns_create_rrec(mem_ctx, host, QTYPE_AAAA, DNS_CLASS_IN, ttl,
169                               sizeof(ip6.s6_addr), data, prec);
170
171         if (!ERR_DNS_IS_OK(err)) {
172                 TALLOC_FREE(data);
173         }
174
175         return err;
176 #else
177         return ERROR_DNS_INVALID_PARAMETER;
178 #endif
179 }
180
181 DNS_ERROR dns_create_name_in_use_record(TALLOC_CTX *mem_ctx,
182                                         const char *name,
183                                         const struct sockaddr_storage *ss,
184                                         struct dns_rrec **prec)
185 {
186         if (ss != NULL) {
187                 switch (ss->ss_family) {
188                 case AF_INET:
189                         return dns_create_a_record(mem_ctx, name, 0, ss, prec);
190 #ifdef HAVE_IPV6
191                 case AF_INET6:
192                         return dns_create_aaaa_record(mem_ctx, name, 0, ss, prec);
193 #endif
194                 default:
195                         return ERROR_DNS_INVALID_PARAMETER;
196                 }
197         }
198
199         return dns_create_rrec(mem_ctx, name, QTYPE_ANY, DNS_CLASS_IN, 0, 0,
200                                NULL, prec);
201 }
202
203 DNS_ERROR dns_create_name_not_in_use_record(TALLOC_CTX *mem_ctx,
204                                             const char *name, uint32 type,
205                                             struct dns_rrec **prec)
206 {
207         return dns_create_rrec(mem_ctx, name, type, DNS_CLASS_NONE, 0,
208                                0, NULL, prec);
209 }
210
211 DNS_ERROR dns_create_delete_record(TALLOC_CTX *mem_ctx, const char *name,
212                                    uint16 type, uint16 r_class,
213                                    struct dns_rrec **prec)
214 {
215         return dns_create_rrec(mem_ctx, name, type, r_class, 0, 0, NULL, prec);
216 }
217
218 DNS_ERROR dns_create_tkey_record(TALLOC_CTX *mem_ctx, const char *keyname,
219                                  const char *algorithm_name, time_t inception,
220                                  time_t expiration, uint16 mode, uint16 error,
221                                  uint16 key_length, const uint8 *key,
222                                  struct dns_rrec **prec)
223 {
224         struct dns_buffer *buf = NULL;
225         struct dns_domain_name *algorithm = NULL;
226         DNS_ERROR err;
227
228         if (!(buf = dns_create_buffer(mem_ctx))) {
229                 return ERROR_DNS_NO_MEMORY;
230         }
231
232         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
233         if (!ERR_DNS_IS_OK(err)) goto error;
234
235         dns_marshall_domain_name(buf, algorithm);
236         dns_marshall_uint32(buf, inception);
237         dns_marshall_uint32(buf, expiration);
238         dns_marshall_uint16(buf, mode);
239         dns_marshall_uint16(buf, error);
240         dns_marshall_uint16(buf, key_length);
241         dns_marshall_buffer(buf, key, key_length);
242         dns_marshall_uint16(buf, 0); /* Other Size */
243
244         if (!ERR_DNS_IS_OK(buf->error)) {
245                 err = buf->error;
246                 goto error;
247         }
248
249         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TKEY, DNS_CLASS_ANY, 0,
250                               buf->offset, buf->data, prec);
251
252  error:
253         TALLOC_FREE(buf);
254         return err;
255 }
256
257 DNS_ERROR dns_unmarshall_tkey_record(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
258                                      struct dns_tkey_record **ptkey)
259 {
260         struct dns_tkey_record *tkey;
261         struct dns_buffer buf;
262         uint32 tmp_inception, tmp_expiration;
263         
264         if (!(tkey = talloc(mem_ctx, struct dns_tkey_record))) {
265                 return ERROR_DNS_NO_MEMORY;
266         }
267
268         buf.data = rec->data;
269         buf.size = rec->data_length;
270         buf.offset = 0;
271         buf.error = ERROR_DNS_SUCCESS;
272
273         dns_unmarshall_domain_name(tkey, &buf, &tkey->algorithm);
274         dns_unmarshall_uint32(&buf, &tmp_inception);
275         dns_unmarshall_uint32(&buf, &tmp_expiration);
276         dns_unmarshall_uint16(&buf, &tkey->mode);
277         dns_unmarshall_uint16(&buf, &tkey->error);
278         dns_unmarshall_uint16(&buf, &tkey->key_length);
279
280         if (!ERR_DNS_IS_OK(buf.error)) goto error;
281
282         if (tkey->key_length) {
283                 if (!(tkey->key = talloc_array(tkey, uint8, tkey->key_length))) {
284                         buf.error = ERROR_DNS_NO_MEMORY;
285                         goto error;
286                 }
287         } else {
288                 tkey->key = NULL;
289         }
290
291         dns_unmarshall_buffer(&buf, tkey->key, tkey->key_length);
292         if (!ERR_DNS_IS_OK(buf.error)) goto error;
293
294         tkey->inception = (time_t)tmp_inception;
295         tkey->expiration = (time_t)tmp_expiration;
296
297         *ptkey = tkey;
298         return ERROR_DNS_SUCCESS;
299
300  error:
301         TALLOC_FREE(tkey);
302         return buf.error;
303 }
304
305 DNS_ERROR dns_create_tsig_record(TALLOC_CTX *mem_ctx, const char *keyname,
306                                  const char *algorithm_name,
307                                  time_t time_signed, uint16 fudge,
308                                  uint16 mac_length, const uint8 *mac,
309                                  uint16 original_id, uint16 error,
310                                  struct dns_rrec **prec)
311 {
312         struct dns_buffer *buf = NULL;
313         struct dns_domain_name *algorithm = NULL;
314         DNS_ERROR err;
315
316         if (!(buf = dns_create_buffer(mem_ctx))) {
317                 return ERROR_DNS_NO_MEMORY;
318         }
319
320         err = dns_domain_name_from_string(buf, algorithm_name, &algorithm);
321         if (!ERR_DNS_IS_OK(err)) goto error;
322
323         dns_marshall_domain_name(buf, algorithm);
324         dns_marshall_uint16(buf, 0); /* time prefix */
325         dns_marshall_uint32(buf, time_signed);
326         dns_marshall_uint16(buf, fudge);
327         dns_marshall_uint16(buf, mac_length);
328         dns_marshall_buffer(buf, mac, mac_length);
329         dns_marshall_uint16(buf, original_id);
330         dns_marshall_uint16(buf, error);
331         dns_marshall_uint16(buf, 0); /* Other Size */
332
333         if (!ERR_DNS_IS_OK(buf->error)) {
334                 err = buf->error;
335                 goto error;
336         }
337
338         err = dns_create_rrec(mem_ctx, keyname, QTYPE_TSIG, DNS_CLASS_ANY, 0,
339                               buf->offset, buf->data, prec);
340
341  error:
342         TALLOC_FREE(buf);
343         return err;
344 }
345
346 DNS_ERROR dns_add_rrec(TALLOC_CTX *mem_ctx, struct dns_rrec *rec,
347                        uint16 *num_records, struct dns_rrec ***records)
348 {
349         struct dns_rrec **new_records;
350
351         if (!(new_records = talloc_realloc(mem_ctx, *records,
352                                                  struct dns_rrec *,
353                                                  (*num_records)+1))) {
354                 return ERROR_DNS_NO_MEMORY;
355         }
356
357         new_records[*num_records] = talloc_move(new_records, &rec);
358
359         *num_records += 1;
360         *records = new_records;
361         return ERROR_DNS_SUCCESS;
362 }
363
364 /*
365  * Create a request that probes a server whether the list of IP addresses
366  * provides meets our expectations
367  */
368
369 DNS_ERROR dns_create_probe(TALLOC_CTX *mem_ctx, const char *zone,
370                            const char *host, int num_ips,
371                            const struct sockaddr_storage *sslist,
372                            struct dns_update_request **preq)
373 {
374         struct dns_update_request *req = NULL;
375         struct dns_rrec *rec = NULL;
376         DNS_ERROR err;
377         uint16 i;
378
379         err = dns_create_update(mem_ctx, zone, &req);
380         if (!ERR_DNS_IS_OK(err)) return err;
381
382         err = dns_create_name_not_in_use_record(req, host, QTYPE_CNAME, &rec);
383         if (!ERR_DNS_IS_OK(err)) goto error;
384
385         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
386         if (!ERR_DNS_IS_OK(err)) goto error;
387
388         for (i=0; i<num_ips; i++) {
389                 err = dns_create_name_in_use_record(req, host,
390                                                     &sslist[i], &rec);
391                 if (!ERR_DNS_IS_OK(err)) goto error;
392
393                 err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
394                 if (!ERR_DNS_IS_OK(err)) goto error;
395         }
396
397         *preq = req;
398         return ERROR_DNS_SUCCESS;
399
400  error:
401         TALLOC_FREE(req);
402         return err;
403 }
404                            
405 DNS_ERROR dns_create_update_request(TALLOC_CTX *mem_ctx,
406                                     const char *domainname,
407                                     const char *hostname,
408                                     const struct sockaddr_storage *ss_addrs,
409                                     size_t num_addrs,
410                                     struct dns_update_request **preq)
411 {
412         struct dns_update_request *req = NULL;
413         struct dns_rrec *rec = NULL;
414         DNS_ERROR err;
415         size_t i;
416
417         err = dns_create_update(mem_ctx, domainname, &req);
418         if (!ERR_DNS_IS_OK(err)) return err;
419
420         /*
421          * Use the same prereq as WinXP -- No CNAME records for this host.
422          */
423
424         err = dns_create_rrec(req, hostname, QTYPE_CNAME, DNS_CLASS_NONE,
425                               0, 0, NULL, &rec);
426         if (!ERR_DNS_IS_OK(err)) goto error;
427
428         err = dns_add_rrec(req, rec, &req->num_preqs, &req->preqs);
429         if (!ERR_DNS_IS_OK(err)) goto error;
430
431         /*
432          * Delete any existing A records
433          */
434
435         err = dns_create_delete_record(req, hostname, QTYPE_A, DNS_CLASS_ANY,
436                                        &rec);
437         if (!ERR_DNS_IS_OK(err)) goto error;
438
439         err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
440         if (!ERR_DNS_IS_OK(err)) goto error;
441
442         /*
443          * .. and add our IPs
444          */
445
446         for ( i=0; i<num_addrs; i++ ) {
447
448                 switch(ss_addrs[i].ss_family) {
449                 case AF_INET:
450                         err = dns_create_a_record(req, hostname, 3600, &ss_addrs[i], &rec);
451                         break;
452 #ifdef HAVE_IPV6
453                 case AF_INET6:
454                         err = dns_create_aaaa_record(req, hostname, 3600, &ss_addrs[i], &rec);
455                         break;
456 #endif
457                 default:
458                         continue;
459                 }
460                 if (!ERR_DNS_IS_OK(err))
461                         goto error;
462
463                 err = dns_add_rrec(req, rec, &req->num_updates, &req->updates);
464                 if (!ERR_DNS_IS_OK(err))
465                         goto error;
466         }
467
468         *preq = req;
469         return ERROR_DNS_SUCCESS;
470
471  error:
472         TALLOC_FREE(req);
473         return err;
474 }