Line data Source code
1 : /* dns-stuff.c - DNS related code including CERT RR (rfc-4398)
2 : * Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
3 : * Copyright (C) 2005, 2006, 2009, 2015 Werner Koch
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * This file is free software; you can redistribute it and/or modify
8 : * it under the terms of either
9 : *
10 : * - the GNU Lesser General Public License as published by the Free
11 : * Software Foundation; either version 3 of the License, or (at
12 : * your option) any later version.
13 : *
14 : * or
15 : *
16 : * - the GNU General Public License as published by the Free
17 : * Software Foundation; either version 2 of the License, or (at
18 : * your option) any later version.
19 : *
20 : * or both in parallel, as here.
21 : *
22 : * This file is distributed in the hope that it will be useful,
23 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 : * GNU General Public License for more details.
26 : *
27 : * You should have received a copy of the GNU General Public License
28 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <sys/types.h>
33 : #ifdef HAVE_W32_SYSTEM
34 : # ifdef HAVE_WINSOCK2_H
35 : # include <winsock2.h>
36 : # endif
37 : # include <windows.h>
38 : #else
39 : # include <netinet/in.h>
40 : # include <arpa/nameser.h>
41 : # include <resolv.h>
42 : # include <netdb.h>
43 : #endif
44 : #include <string.h>
45 : #include <unistd.h>
46 : #ifdef USE_ADNS
47 : # include <adns.h>
48 : #endif
49 :
50 : #if !defined(HAVE_GETADDRINFO) && !defined(USE_ADNS)
51 : # error Either getaddrinfo or the ADNS libary is required.
52 : #endif
53 :
54 : #include "util.h"
55 : #include "host2net.h"
56 : #include "dns-stuff.h"
57 :
58 : /* We allow the use of 0 instead of AF_UNSPEC - check this assumption. */
59 : #if AF_UNSPEC != 0
60 : # error AF_UNSPEC does not have the value 0
61 : #endif
62 :
63 : /* Windows does not support the AI_ADDRCONFIG flag - use zero instead. */
64 : #ifndef AI_ADDRCONFIG
65 : # define AI_ADDRCONFIG 0
66 : #endif
67 :
68 : /* Not every installation has gotten around to supporting SRVs or
69 : CERTs yet... */
70 : #ifndef T_SRV
71 : #define T_SRV 33
72 : #endif
73 : #ifndef T_CERT
74 : # define T_CERT 37
75 : #endif
76 :
77 : /* ADNS has no support for CERT yet. */
78 : #define my_adns_r_cert 37
79 :
80 : /* If set Tor mode shall be used. */
81 : static int tor_mode;
82 :
83 : /* Sets the module in Tor mode. Returns 0 is this is possible or an
84 : error code. */
85 : gpg_error_t
86 0 : enable_dns_tormode (void)
87 : {
88 : #if defined(USE_DNS_CERT) && defined(USE_ADNS)
89 : # if HAVE_ADNS_IF_TORMODE
90 : tor_mode = 1;
91 : return 0;
92 : # endif
93 : #endif
94 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
95 : }
96 :
97 : /* Free an addressinfo linked list as returned by resolve_dns_name. */
98 : void
99 0 : free_dns_addrinfo (dns_addrinfo_t ai)
100 : {
101 0 : while (ai)
102 : {
103 0 : dns_addrinfo_t next = ai->next;
104 0 : xfree (ai);
105 0 : ai = next;
106 : }
107 0 : }
108 :
109 :
110 : static gpg_error_t
111 0 : map_eai_to_gpg_error (int ec)
112 : {
113 : gpg_error_t err;
114 :
115 0 : switch (ec)
116 : {
117 0 : case EAI_AGAIN: err = gpg_error (GPG_ERR_EAGAIN); break;
118 0 : case EAI_BADFLAGS: err = gpg_error (GPG_ERR_INV_FLAG); break;
119 0 : case EAI_FAIL: err = gpg_error (GPG_ERR_SERVER_FAILED); break;
120 0 : case EAI_MEMORY: err = gpg_error (GPG_ERR_ENOMEM); break;
121 0 : case EAI_NODATA: err = gpg_error (GPG_ERR_NO_DATA); break;
122 0 : case EAI_NONAME: err = gpg_error (GPG_ERR_NO_NAME); break;
123 0 : case EAI_SERVICE: err = gpg_error (GPG_ERR_NOT_SUPPORTED); break;
124 0 : case EAI_FAMILY: err = gpg_error (GPG_ERR_EAFNOSUPPORT); break;
125 0 : case EAI_SOCKTYPE: err = gpg_error (GPG_ERR_ESOCKTNOSUPPORT); break;
126 : #ifndef HAVE_W32_SYSTEM
127 0 : case EAI_ADDRFAMILY:err = gpg_error (GPG_ERR_EADDRNOTAVAIL); break;
128 0 : case EAI_SYSTEM: err = gpg_error_from_syserror (); break;
129 : #endif
130 0 : default: err = gpg_error (GPG_ERR_UNKNOWN_ERRNO); break;
131 : }
132 0 : return err;
133 : }
134 :
135 :
136 : #ifdef USE_ADNS
137 : /* Init ADNS and store the new state at R_STATE. Returns 0 on
138 : success; prints an error message and returns an error code on
139 : failure. */
140 : static gpg_error_t
141 : my_adns_init (adns_state *r_state)
142 : {
143 : gpg_error_t err;
144 :
145 : if (tor_mode? adns_init_strcfg (r_state,
146 : adns_if_noerrprint|adns_if_tormode,
147 : NULL, "nameserver 8.8.8.8")
148 : /* */: adns_init (r_state, adns_if_noerrprint, NULL))
149 : {
150 : err = gpg_error_from_syserror ();
151 : log_error ("error initializing adns: %s\n", gpg_strerror (err));
152 : return err;
153 : }
154 : return 0;
155 : }
156 : #endif /*USE_ADNS*/
157 :
158 :
159 : #ifdef USE_ADNS
160 : /* Resolve a name using the ADNS library. See resolve_dns_name for
161 : the description. */
162 : static gpg_error_t
163 : resolve_name_adns (const char *name, unsigned short port,
164 : int want_family, int want_socktype,
165 : dns_addrinfo_t *r_dai, char **r_canonname)
166 : {
167 : gpg_error_t err = 0;
168 : dns_addrinfo_t daihead = NULL;
169 : dns_addrinfo_t dai;
170 : adns_state state;
171 : adns_answer *answer = NULL;
172 : int count;
173 :
174 : *r_dai = NULL;
175 : if (r_canonname)
176 : *r_canonname = NULL;
177 :
178 : if (want_socktype != SOCK_STREAM && want_socktype != SOCK_DGRAM)
179 : return gpg_error (GPG_ERR_ESOCKTNOSUPPORT);
180 :
181 : err = my_adns_init (&state);
182 : if (err)
183 : return err;
184 :
185 : if (adns_synchronous (state, name, adns_r_addr,
186 : adns_qf_quoteok_query, &answer))
187 : {
188 : err = gpg_error_from_syserror ();
189 : log_error ("DNS query failed: %s\n", gpg_strerror (err));
190 : goto leave;
191 : }
192 :
193 : err = gpg_error (GPG_ERR_NOT_FOUND);
194 : if (answer->status != adns_s_ok || answer->type != adns_r_addr)
195 : {
196 : log_error ("DNS query returned an error: %s (%s)\n",
197 : adns_strerror (answer->status),
198 : adns_errabbrev (answer->status));
199 : goto leave;
200 : }
201 :
202 : if (r_canonname && answer->cname)
203 : {
204 : *r_canonname = xtrystrdup (answer->cname);
205 : if (!*r_canonname)
206 : {
207 : err = gpg_error_from_syserror ();
208 : goto leave;
209 : }
210 : }
211 :
212 : for (count = 0; count < answer->nrrs; count++)
213 : {
214 : int len;
215 : adns_rr_addr *addr;
216 :
217 : len = answer->rrs.addr[count].len;
218 : addr = &answer->rrs.addr[count];
219 : if (addr->addr.sa.sa_family != AF_INET6
220 : && addr->addr.sa.sa_family != AF_INET)
221 : continue;
222 :
223 : dai = xtrymalloc (sizeof *dai + len - 1);
224 : if (!dai)
225 : {
226 : err = gpg_error_from_syserror ();
227 : goto leave;
228 : }
229 : dai->family = addr->addr.sa.sa_family;
230 : dai->socktype = want_socktype == SOCK_STREAM? SOCK_STREAM : SOCK_DGRAM;
231 : dai->protocol = want_socktype == SOCK_STREAM? IPPROTO_TCP : IPPROTO_UDP;
232 : dai->addrlen = len;
233 : memcpy (dai->addr, &addr->addr.sa, len);
234 : dai->next = daihead;
235 : daihead = dai;
236 : err = 0;
237 : }
238 :
239 : leave:
240 : adns_free (answer);
241 : adns_finish (state);
242 : if (err)
243 : {
244 : if (r_canonname)
245 : {
246 : xfree (*r_canonname);
247 : *r_canonname = NULL;
248 : }
249 : free_dns_addrinfo (daihead);
250 : }
251 : else
252 : *r_dai = daihead;
253 : return err;
254 : }
255 : #endif /*USE_ADNS*/
256 :
257 :
258 : #ifndef USE_ADNS
259 : /* Resolve a name using the standard system function. */
260 : static gpg_error_t
261 0 : resolve_name_standard (const char *name, unsigned short port,
262 : int want_family, int want_socktype,
263 : dns_addrinfo_t *r_dai, char **r_canonname)
264 : {
265 0 : gpg_error_t err = 0;
266 0 : dns_addrinfo_t daihead = NULL;
267 : dns_addrinfo_t dai;
268 0 : struct addrinfo *aibuf = NULL;
269 : struct addrinfo hints, *ai;
270 : char portstr[21];
271 : int ret;
272 :
273 0 : *r_dai = NULL;
274 0 : if (r_canonname)
275 0 : *r_canonname = NULL;
276 :
277 0 : memset (&hints, 0, sizeof hints);
278 0 : hints.ai_family = want_family;
279 0 : hints.ai_socktype = want_socktype;
280 0 : hints.ai_flags = AI_ADDRCONFIG;
281 0 : if (r_canonname)
282 0 : hints.ai_flags |= AI_CANONNAME;
283 :
284 0 : if (port)
285 0 : snprintf (portstr, sizeof portstr, "%hu", port);
286 : else
287 0 : *portstr = 0;
288 :
289 : /* We can't use the the AI_IDN flag because that does the conversion
290 : using the current locale. However, GnuPG always used UTF-8. To
291 : support IDN we would need to make use of the libidn API. */
292 0 : ret = getaddrinfo (name, *portstr? portstr : NULL, &hints, &aibuf);
293 0 : if (ret)
294 : {
295 0 : aibuf = NULL;
296 0 : err = map_eai_to_gpg_error (ret);
297 0 : if (gpg_err_code (err) == GPG_ERR_NO_NAME)
298 : {
299 : /* There seems to be a bug in the glibc getaddrinfo function
300 : if the CNAME points to a long list of A and AAAA records
301 : in which case the function return NO_NAME. Let's do the
302 : CNAME redirection again. */
303 : char *cname;
304 :
305 0 : if (get_dns_cname (name, &cname))
306 0 : goto leave; /* Still no success. */
307 :
308 0 : ret = getaddrinfo (cname, *portstr? portstr : NULL, &hints, &aibuf);
309 0 : xfree (cname);
310 0 : if (ret)
311 : {
312 0 : aibuf = NULL;
313 0 : err = map_eai_to_gpg_error (ret);
314 0 : goto leave;
315 : }
316 0 : err = 0; /* Yep, now it worked. */
317 : }
318 : else
319 0 : goto leave;
320 : }
321 :
322 0 : if (r_canonname && aibuf && aibuf->ai_canonname)
323 : {
324 0 : *r_canonname = xtrystrdup (aibuf->ai_canonname);
325 0 : if (!*r_canonname)
326 : {
327 0 : err = gpg_error_from_syserror ();
328 0 : goto leave;
329 : }
330 : }
331 :
332 0 : for (ai = aibuf; ai; ai = ai->ai_next)
333 : {
334 0 : if (ai->ai_family != AF_INET6 && ai->ai_family != AF_INET)
335 0 : continue;
336 :
337 0 : dai = xtrymalloc (sizeof *dai + ai->ai_addrlen - 1);
338 0 : dai->family = ai->ai_family;
339 0 : dai->socktype = ai->ai_socktype;
340 0 : dai->protocol = ai->ai_protocol;
341 0 : dai->addrlen = ai->ai_addrlen;
342 0 : memcpy (dai->addr, ai->ai_addr, ai->ai_addrlen);
343 0 : dai->next = daihead;
344 0 : daihead = dai;
345 : }
346 :
347 : leave:
348 0 : if (aibuf)
349 0 : freeaddrinfo (aibuf);
350 0 : if (err)
351 : {
352 0 : if (r_canonname)
353 : {
354 0 : xfree (*r_canonname);
355 0 : *r_canonname = NULL;
356 : }
357 0 : free_dns_addrinfo (daihead);
358 : }
359 : else
360 0 : *r_dai = daihead;
361 0 : return err;
362 : }
363 : #endif /*!USE_ADNS*/
364 :
365 :
366 : /* Resolve an address using the standard system function. */
367 : static gpg_error_t
368 0 : resolve_addr_standard (const struct sockaddr *addr, int addrlen,
369 : unsigned int flags, char **r_name)
370 : {
371 : gpg_error_t err;
372 : int ec;
373 : char *buffer, *p;
374 : int buflen;
375 :
376 0 : *r_name = NULL;
377 :
378 0 : buflen = NI_MAXHOST;
379 0 : buffer = xtrymalloc (buflen + 2 + 1);
380 0 : if (!buffer)
381 0 : return gpg_error_from_syserror ();
382 :
383 0 : if ((flags & DNS_NUMERICHOST) || tor_mode)
384 0 : ec = EAI_NONAME;
385 : else
386 0 : ec = getnameinfo (addr, addrlen, buffer, buflen, NULL, 0, NI_NAMEREQD);
387 :
388 0 : if (!ec && *buffer == '[')
389 0 : ec = EAI_FAIL; /* A name may never start with a bracket. */
390 0 : else if (ec == EAI_NONAME)
391 : {
392 0 : p = buffer;
393 0 : if (addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
394 : {
395 0 : *p++ = '[';
396 0 : buflen -= 2;
397 : }
398 0 : ec = getnameinfo (addr, addrlen, p, buflen, NULL, 0, NI_NUMERICHOST);
399 0 : if (!ec && addr->sa_family == AF_INET6 && (flags & DNS_WITHBRACKET))
400 0 : strcat (buffer, "]");
401 : }
402 :
403 0 : if (ec)
404 0 : err = map_eai_to_gpg_error (ec);
405 : else
406 : {
407 0 : p = xtryrealloc (buffer, strlen (buffer)+1);
408 0 : if (!p)
409 0 : err = gpg_error_from_syserror ();
410 : else
411 : {
412 0 : buffer = p;
413 0 : err = 0;
414 : }
415 : }
416 :
417 0 : if (err)
418 0 : xfree (buffer);
419 : else
420 0 : *r_name = buffer;
421 :
422 0 : return err;
423 : }
424 :
425 :
426 : /* This a wrapper around getaddrinfo with slighly different semantics.
427 : NAME is the name to resolve.
428 : PORT is the requested port or 0.
429 : WANT_FAMILY is either 0 (AF_UNSPEC), AF_INET6, or AF_INET4.
430 : WANT_SOCKETTYPE is either SOCK_STREAM or SOCK_DGRAM.
431 :
432 : On success the result is stored in a linked list with the head
433 : stored at the address R_AI; the caller must call gpg_addrinfo_free
434 : on this. If R_CANONNAME is not NULL the official name of the host
435 : is stored there as a malloced string; if that name is not available
436 : NULL is stored. */
437 : gpg_error_t
438 0 : resolve_dns_name (const char *name, unsigned short port,
439 : int want_family, int want_socktype,
440 : dns_addrinfo_t *r_ai, char **r_canonname)
441 : {
442 : #ifdef USE_ADNS
443 : return resolve_name_adns (name, port, want_family, want_socktype,
444 : r_ai, r_canonname);
445 : #else
446 0 : return resolve_name_standard (name, port, want_family, want_socktype,
447 : r_ai, r_canonname);
448 : #endif
449 : }
450 :
451 :
452 : gpg_error_t
453 0 : resolve_dns_addr (const struct sockaddr *addr, int addrlen,
454 : unsigned int flags, char **r_name)
455 : {
456 : #ifdef USE_ADNS_disabled_for_now
457 : return resolve_addr_adns (addr, addrlen, flags, r_name);
458 : #else
459 0 : return resolve_addr_standard (addr, addrlen, flags, r_name);
460 : #endif
461 : }
462 :
463 :
464 : /* Check whether NAME is an IP address. Returns true if it is either
465 : an IPv6 or IPv4 numerical address. */
466 : int
467 0 : is_ip_address (const char *name)
468 : {
469 : const char *s;
470 : int ndots, dblcol, n;
471 :
472 0 : if (*name == '[')
473 0 : return 1; /* yes: A legal DNS name may not contain this character;
474 : this mut be bracketed v6 address. */
475 0 : if (*name == '.')
476 0 : return 0; /* No. A leading dot is not a valid IP address. */
477 :
478 : /* Check whether this is a v6 address. */
479 0 : ndots = n = dblcol = 0;
480 0 : for (s=name; *s; s++)
481 : {
482 0 : if (*s == ':')
483 : {
484 0 : ndots++;
485 0 : if (s[1] == ':')
486 : {
487 0 : ndots++;
488 0 : if (dblcol)
489 0 : return 0; /* No: Only one "::" allowed. */
490 0 : dblcol++;
491 0 : if (s[1])
492 0 : s++;
493 : }
494 0 : n = 0;
495 : }
496 0 : else if (*s == '.')
497 0 : goto legacy;
498 0 : else if (!strchr ("0123456789abcdefABCDEF", *s))
499 0 : return 0; /* No: Not a hex digit. */
500 0 : else if (++n > 4)
501 0 : return 0; /* To many digits in a group. */
502 : }
503 0 : if (ndots > 7)
504 0 : return 0; /* No: Too many colons. */
505 0 : else if (ndots > 1)
506 0 : return 1; /* Yes: At least 2 colons indicate an v6 address. */
507 :
508 : legacy:
509 : /* Check whether it is legacy IP address. */
510 0 : ndots = n = 0;
511 0 : for (s=name; *s; s++)
512 : {
513 0 : if (*s == '.')
514 : {
515 0 : if (s[1] == '.')
516 0 : return 0; /* No: Douple dot. */
517 0 : if (atoi (s+1) > 255)
518 0 : return 0; /* No: Ipv4 byte value too large. */
519 0 : ndots++;
520 0 : n = 0;
521 : }
522 0 : else if (!strchr ("0123456789", *s))
523 0 : return 0; /* No: Not a digit. */
524 0 : else if (++n > 3)
525 0 : return 0; /* No: More than 3 digits. */
526 : }
527 0 : return !!(ndots == 3);
528 : }
529 :
530 :
531 : /* Return true if NAME is an onion address. */
532 : int
533 0 : is_onion_address (const char *name)
534 : {
535 : size_t len;
536 :
537 0 : len = name? strlen (name) : 0;
538 0 : if (len < 8 || strcmp (name + len - 6, ".onion"))
539 0 : return 0;
540 : /* Note that we require at least 2 characters before the suffix. */
541 0 : return 1; /* Yes. */
542 : }
543 :
544 :
545 : /* Returns 0 on success or an error code. If a PGP CERT record was
546 : found, the malloced data is returned at (R_KEY, R_KEYLEN) and
547 : the other return parameters are set to NULL/0. If an IPGP CERT
548 : record was found the fingerprint is stored as an allocated block at
549 : R_FPR and its length at R_FPRLEN; an URL is is allocated as a
550 : string and returned at R_URL. If WANT_CERTTYPE is 0 this function
551 : returns the first CERT found with a supported type; it is expected
552 : that only one CERT record is used. If WANT_CERTTYPE is one of the
553 : supported certtypes only records with this certtype are considered
554 : and the first found is returned. (R_KEY,R_KEYLEN) are optional. */
555 : gpg_error_t
556 1 : get_dns_cert (const char *name, int want_certtype,
557 : void **r_key, size_t *r_keylen,
558 : unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
559 : {
560 : #ifdef USE_DNS_CERT
561 : #ifdef USE_ADNS
562 : gpg_error_t err;
563 : adns_state state;
564 : adns_answer *answer = NULL;
565 : unsigned int ctype;
566 : int count;
567 :
568 : if (r_key)
569 : *r_key = NULL;
570 : if (r_keylen)
571 : *r_keylen = 0;
572 : *r_fpr = NULL;
573 : *r_fprlen = 0;
574 : *r_url = NULL;
575 :
576 : err = my_adns_init (&state);
577 : if (err)
578 : return err;
579 :
580 : if (adns_synchronous (state, name,
581 : (adns_r_unknown
582 : | (want_certtype < DNS_CERTTYPE_RRBASE
583 : ? my_adns_r_cert
584 : : (want_certtype - DNS_CERTTYPE_RRBASE))),
585 : adns_qf_quoteok_query, &answer))
586 : {
587 : err = gpg_error_from_syserror ();
588 : /* log_error ("DNS query failed: %s\n", strerror (errno)); */
589 : adns_finish (state);
590 : return err;
591 : }
592 : if (answer->status != adns_s_ok)
593 : {
594 : /* log_error ("DNS query returned an error: %s (%s)\n", */
595 : /* adns_strerror (answer->status), */
596 : /* adns_errabbrev (answer->status)); */
597 : err = gpg_error (GPG_ERR_NOT_FOUND);
598 : goto leave;
599 : }
600 :
601 : err = gpg_error (GPG_ERR_NOT_FOUND);
602 : for (count = 0; count < answer->nrrs; count++)
603 : {
604 : int datalen = answer->rrs.byteblock[count].len;
605 : const unsigned char *data = answer->rrs.byteblock[count].data;
606 :
607 : /* First check for our generic RR hack. */
608 : if (datalen
609 : && want_certtype >= DNS_CERTTYPE_RRBASE
610 : && ((want_certtype - DNS_CERTTYPE_RRBASE)
611 : == (answer->type & ~adns_r_unknown)))
612 : {
613 : /* Found the requested record - return it. */
614 : *r_key = xtrymalloc (datalen);
615 : if (!*r_key)
616 : err = gpg_error_from_syserror ();
617 : else
618 : {
619 : memcpy (*r_key, data, datalen);
620 : *r_keylen = datalen;
621 : err = 0;
622 : }
623 : goto leave;
624 : }
625 :
626 : if (datalen < 5)
627 : continue; /* Truncated CERT record - skip. */
628 :
629 : ctype = buf16_to_uint (data);
630 : /* (key tag and algorithm fields are not required.) */
631 : data += 5;
632 : datalen -= 5;
633 :
634 : if (want_certtype && want_certtype != ctype)
635 : ; /* Not of the requested certtype. */
636 : else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
637 : {
638 : /* CERT type is PGP. Gpg checks for a minimum length of 11,
639 : thus we do the same. */
640 : *r_key = xtrymalloc (datalen);
641 : if (!*r_key)
642 : err = gpg_error_from_syserror ();
643 : else
644 : {
645 : memcpy (*r_key, data, datalen);
646 : *r_keylen = datalen;
647 : err = 0;
648 : }
649 : goto leave;
650 : }
651 : else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
652 : && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
653 : {
654 : /* CERT type is IPGP. We made sure that the data is
655 : plausible and that the caller requested this
656 : information. */
657 : *r_fprlen = data[0];
658 : if (*r_fprlen)
659 : {
660 : *r_fpr = xtrymalloc (*r_fprlen);
661 : if (!*r_fpr)
662 : {
663 : err = gpg_error_from_syserror ();
664 : goto leave;
665 : }
666 : memcpy (*r_fpr, data + 1, *r_fprlen);
667 : }
668 : else
669 : *r_fpr = NULL;
670 :
671 : if (datalen > *r_fprlen + 1)
672 : {
673 : *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
674 : if (!*r_url)
675 : {
676 : err = gpg_error_from_syserror ();
677 : xfree (*r_fpr);
678 : *r_fpr = NULL;
679 : goto leave;
680 : }
681 : memcpy (*r_url,
682 : data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
683 : (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
684 : }
685 : else
686 : *r_url = NULL;
687 :
688 : err = 0;
689 : goto leave;
690 : }
691 : }
692 :
693 : leave:
694 : adns_free (answer);
695 : adns_finish (state);
696 : return err;
697 :
698 : #else /*!USE_ADNS*/
699 :
700 : gpg_error_t err;
701 : unsigned char *answer;
702 : int r;
703 : u16 count;
704 :
705 1 : if (r_key)
706 1 : *r_key = NULL;
707 1 : if (r_keylen)
708 1 : *r_keylen = 0;
709 1 : *r_fpr = NULL;
710 1 : *r_fprlen = 0;
711 1 : *r_url = NULL;
712 :
713 : /* Allocate a 64k buffer which is the limit for an DNS response. */
714 1 : answer = xtrymalloc (65536);
715 1 : if (!answer)
716 0 : return gpg_error_from_syserror ();
717 :
718 1 : err = gpg_error (GPG_ERR_NOT_FOUND);
719 1 : r = res_query (name, C_IN,
720 : (want_certtype < DNS_CERTTYPE_RRBASE
721 : ? T_CERT
722 : : (want_certtype - DNS_CERTTYPE_RRBASE)),
723 : answer, 65536);
724 : /* Not too big, not too small, no errors and at least 1 answer. */
725 1 : if (r >= sizeof (HEADER) && r <= 65536
726 1 : && (((HEADER *) answer)->rcode) == NOERROR
727 1 : && (count = ntohs (((HEADER *) answer)->ancount)))
728 : {
729 : int rc;
730 : unsigned char *pt, *emsg;
731 :
732 1 : emsg = &answer[r];
733 :
734 1 : pt = &answer[sizeof (HEADER)];
735 :
736 : /* Skip over the query */
737 :
738 1 : rc = dn_skipname (pt, emsg);
739 1 : if (rc == -1)
740 : {
741 0 : err = gpg_error (GPG_ERR_INV_OBJ);
742 0 : goto leave;
743 : }
744 1 : pt += rc + QFIXEDSZ;
745 :
746 : /* There are several possible response types for a CERT request.
747 : We're interested in the PGP (a key) and IPGP (a URI) types.
748 : Skip all others. TODO: A key is better than a URI since
749 : we've gone through all this bother to fetch it, so favor that
750 : if we have both PGP and IPGP? */
751 :
752 2 : while (count-- > 0 && pt < emsg)
753 : {
754 : u16 type, class, dlen, ctype;
755 :
756 1 : rc = dn_skipname (pt, emsg); /* the name we just queried for */
757 1 : if (rc == -1)
758 : {
759 0 : err = gpg_error (GPG_ERR_INV_OBJ);
760 0 : goto leave;
761 : }
762 :
763 1 : pt += rc;
764 :
765 : /* Truncated message? 15 bytes takes us to the point where
766 : we start looking at the ctype. */
767 1 : if ((emsg - pt) < 15)
768 0 : break;
769 :
770 1 : type = buf16_to_u16 (pt);
771 1 : pt += 2;
772 :
773 1 : class = buf16_to_u16 (pt);
774 1 : pt += 2;
775 :
776 1 : if (class != C_IN)
777 0 : break;
778 :
779 : /* ttl */
780 1 : pt += 4;
781 :
782 : /* data length */
783 1 : dlen = buf16_to_u16 (pt);
784 1 : pt += 2;
785 :
786 : /* Check the type and parse. */
787 1 : if (want_certtype >= DNS_CERTTYPE_RRBASE
788 0 : && type == (want_certtype - DNS_CERTTYPE_RRBASE)
789 0 : && r_key)
790 : {
791 0 : *r_key = xtrymalloc (dlen);
792 0 : if (!*r_key)
793 0 : err = gpg_error_from_syserror ();
794 : else
795 : {
796 0 : memcpy (*r_key, pt, dlen);
797 0 : *r_keylen = dlen;
798 0 : err = 0;
799 : }
800 0 : goto leave;
801 : }
802 1 : else if (want_certtype >= DNS_CERTTYPE_RRBASE)
803 : {
804 : /* We did not found the requested RR. */
805 0 : pt += dlen;
806 : }
807 1 : else if (type == T_CERT)
808 : {
809 : /* We got a CERT type. */
810 1 : ctype = buf16_to_u16 (pt);
811 1 : pt += 2;
812 :
813 : /* Skip the CERT key tag and algo which we don't need. */
814 1 : pt += 3;
815 :
816 1 : dlen -= 5;
817 :
818 : /* 15 bytes takes us to here */
819 1 : if (want_certtype && want_certtype != ctype)
820 : ; /* Not of the requested certtype. */
821 1 : else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
822 : {
823 : /* PGP type */
824 1 : *r_key = xtrymalloc (dlen);
825 1 : if (!*r_key)
826 0 : err = gpg_error_from_syserror ();
827 : else
828 : {
829 1 : memcpy (*r_key, pt, dlen);
830 1 : *r_keylen = dlen;
831 1 : err = 0;
832 : }
833 1 : goto leave;
834 : }
835 0 : else if (ctype == DNS_CERTTYPE_IPGP
836 0 : && dlen && dlen < 1023 && dlen >= pt[0] + 1)
837 : {
838 : /* IPGP type */
839 0 : *r_fprlen = pt[0];
840 0 : if (*r_fprlen)
841 : {
842 0 : *r_fpr = xtrymalloc (*r_fprlen);
843 0 : if (!*r_fpr)
844 : {
845 0 : err = gpg_error_from_syserror ();
846 0 : goto leave;
847 : }
848 0 : memcpy (*r_fpr, &pt[1], *r_fprlen);
849 : }
850 : else
851 0 : *r_fpr = NULL;
852 :
853 0 : if (dlen > *r_fprlen + 1)
854 : {
855 0 : *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
856 0 : if (!*r_fpr)
857 : {
858 0 : err = gpg_error_from_syserror ();
859 0 : xfree (*r_fpr);
860 0 : *r_fpr = NULL;
861 0 : goto leave;
862 : }
863 0 : memcpy (*r_url, &pt[*r_fprlen + 1],
864 0 : dlen - (*r_fprlen + 1));
865 0 : (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
866 : }
867 : else
868 0 : *r_url = NULL;
869 :
870 0 : err = 0;
871 0 : goto leave;
872 : }
873 :
874 : /* No subtype matches, so continue with the next answer. */
875 0 : pt += dlen;
876 : }
877 : else
878 : {
879 : /* Not a requested type - might be a CNAME. Try next item. */
880 0 : pt += dlen;
881 : }
882 : }
883 : }
884 :
885 : leave:
886 1 : xfree (answer);
887 1 : return err;
888 :
889 : #endif /*!USE_ADNS */
890 : #else /* !USE_DNS_CERT */
891 : (void)name;
892 : if (r_key)
893 : *r_key = NULL;
894 : if (r_keylen)
895 : *r_keylen = NULL;
896 : *r_fpr = NULL;
897 : *r_fprlen = 0;
898 : *r_url = NULL;
899 :
900 : return gpg_error (GPG_ERR_NOT_SUPPORTED);
901 : #endif
902 : }
903 :
904 : #ifdef USE_DNS_SRV
905 : static int
906 0 : priosort(const void *a,const void *b)
907 : {
908 0 : const struct srventry *sa=a,*sb=b;
909 0 : if(sa->priority>sb->priority)
910 0 : return 1;
911 0 : else if(sa->priority<sb->priority)
912 0 : return -1;
913 : else
914 0 : return 0;
915 : }
916 :
917 :
918 : int
919 0 : getsrv (const char *name,struct srventry **list)
920 : {
921 0 : int srvcount=0;
922 : u16 count;
923 : int i, rc;
924 :
925 0 : *list = NULL;
926 :
927 : #ifdef USE_ADNS
928 : {
929 : adns_state state;
930 : adns_answer *answer = NULL;
931 :
932 : if (my_adns_init (&state))
933 : return -1;
934 :
935 : rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query,
936 : &answer);
937 : if (rc)
938 : {
939 : log_error ("DNS query failed: %s\n", strerror (errno));
940 : adns_finish (state);
941 : return -1;
942 : }
943 : if (answer->status != adns_s_ok
944 : || answer->type != adns_r_srv || !answer->nrrs)
945 : {
946 : log_error ("DNS query returned an error or no records: %s (%s)\n",
947 : adns_strerror (answer->status),
948 : adns_errabbrev (answer->status));
949 : adns_free (answer);
950 : adns_finish (state);
951 : return 0;
952 : }
953 :
954 : for (count = 0; count < answer->nrrs; count++)
955 : {
956 : struct srventry *srv = NULL;
957 : struct srventry *newlist;
958 :
959 : if (strlen (answer->rrs.srvha[count].ha.host) >= sizeof srv->target)
960 : {
961 : log_info ("hostname in SRV record too long - skipped\n");
962 : continue;
963 : }
964 :
965 : newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
966 : if (!newlist)
967 : goto fail;
968 : *list = newlist;
969 : memset (&(*list)[srvcount], 0, sizeof(struct srventry));
970 : srv = &(*list)[srvcount];
971 : srvcount++;
972 :
973 : srv->priority = answer->rrs.srvha[count].priority;
974 : srv->weight = answer->rrs.srvha[count].weight;
975 : srv->port = answer->rrs.srvha[count].port;
976 : strcpy (srv->target, answer->rrs.srvha[count].ha.host);
977 : }
978 :
979 : adns_free (answer);
980 : adns_finish (state);
981 : }
982 : #else /*!USE_ADNS*/
983 : {
984 : unsigned char answer[2048];
985 0 : HEADER *header = (HEADER *)answer;
986 : unsigned char *pt, *emsg;
987 : int r;
988 : u16 dlen;
989 :
990 : /* Do not allow a query using the standard resolver in Tor mode. */
991 0 : if (tor_mode)
992 0 : return -1;
993 :
994 0 : r = res_query (name, C_IN, T_SRV, answer, sizeof answer);
995 0 : if (r < sizeof (HEADER) || r > sizeof answer)
996 0 : return -1;
997 0 : if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
998 0 : return 0; /* Error or no record found. */
999 :
1000 0 : emsg = &answer[r];
1001 0 : pt = &answer[sizeof(HEADER)];
1002 :
1003 : /* Skip over the query */
1004 0 : rc = dn_skipname (pt, emsg);
1005 0 : if (rc == -1)
1006 0 : goto fail;
1007 :
1008 0 : pt += rc + QFIXEDSZ;
1009 :
1010 0 : while (count-- > 0 && pt < emsg)
1011 : {
1012 0 : struct srventry *srv=NULL;
1013 : u16 type,class;
1014 : struct srventry *newlist;
1015 :
1016 0 : newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry));
1017 0 : if (!newlist)
1018 0 : goto fail;
1019 0 : *list = newlist;
1020 0 : memset(&(*list)[srvcount],0,sizeof(struct srventry));
1021 0 : srv=&(*list)[srvcount];
1022 0 : srvcount++;
1023 :
1024 0 : rc = dn_skipname(pt,emsg); /* the name we just queried for */
1025 0 : if (rc == -1)
1026 0 : goto fail;
1027 0 : pt+=rc;
1028 :
1029 : /* Truncated message? */
1030 0 : if((emsg-pt)<16)
1031 0 : goto fail;
1032 :
1033 0 : type = buf16_to_u16 (pt);
1034 0 : pt += 2;
1035 : /* We asked for SRV and got something else !? */
1036 0 : if(type!=T_SRV)
1037 0 : goto fail;
1038 :
1039 0 : class = buf16_to_u16 (pt);
1040 0 : pt += 2;
1041 : /* We asked for IN and got something else !? */
1042 0 : if(class!=C_IN)
1043 0 : goto fail;
1044 :
1045 0 : pt += 4; /* ttl */
1046 0 : dlen = buf16_to_u16 (pt);
1047 0 : pt += 2;
1048 :
1049 0 : srv->priority = buf16_to_ushort (pt);
1050 0 : pt += 2;
1051 0 : srv->weight = buf16_to_ushort (pt);
1052 0 : pt += 2;
1053 0 : srv->port = buf16_to_ushort (pt);
1054 0 : pt += 2;
1055 :
1056 : /* Get the name. 2782 doesn't allow name compression, but
1057 : dn_expand still works to pull the name out of the
1058 : packet. */
1059 0 : rc = dn_expand(answer,emsg,pt,srv->target, sizeof srv->target);
1060 0 : if (rc == 1 && srv->target[0] == 0) /* "." */
1061 : {
1062 0 : xfree(*list);
1063 0 : *list = NULL;
1064 0 : return 0;
1065 : }
1066 0 : if (rc == -1)
1067 0 : goto fail;
1068 0 : pt += rc;
1069 : /* Corrupt packet? */
1070 0 : if (dlen != rc+6)
1071 0 : goto fail;
1072 : }
1073 : }
1074 : #endif /*!USE_ADNS*/
1075 :
1076 : /* Now we have an array of all the srv records. */
1077 :
1078 : /* Order by priority */
1079 0 : qsort(*list,srvcount,sizeof(struct srventry),priosort);
1080 :
1081 : /* For each priority, move the zero-weighted items first. */
1082 0 : for (i=0; i < srvcount; i++)
1083 : {
1084 : int j;
1085 :
1086 0 : for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
1087 : {
1088 0 : if((*list)[j].weight==0)
1089 : {
1090 : /* Swap j with i */
1091 0 : if(j!=i)
1092 : {
1093 : struct srventry temp;
1094 :
1095 0 : memcpy (&temp,&(*list)[j],sizeof(struct srventry));
1096 0 : memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry));
1097 0 : memcpy (&(*list)[i],&temp,sizeof(struct srventry));
1098 : }
1099 :
1100 0 : break;
1101 : }
1102 : }
1103 : }
1104 :
1105 : /* Run the RFC-2782 weighting algorithm. We don't need very high
1106 : quality randomness for this, so regular libc srand/rand is
1107 : sufficient. */
1108 :
1109 : {
1110 : static int done;
1111 0 : if (!done)
1112 : {
1113 0 : done = 1;
1114 0 : srand (time (NULL)*getpid());
1115 : }
1116 : }
1117 :
1118 0 : for (i=0; i < srvcount; i++)
1119 : {
1120 : int j;
1121 0 : float prio_count=0,chose;
1122 :
1123 0 : for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++)
1124 : {
1125 0 : prio_count+=(*list)[j].weight;
1126 0 : (*list)[j].run_count=prio_count;
1127 : }
1128 :
1129 0 : chose=prio_count*rand()/RAND_MAX;
1130 :
1131 0 : for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++)
1132 : {
1133 0 : if (chose<=(*list)[j].run_count)
1134 : {
1135 : /* Swap j with i */
1136 0 : if(j!=i)
1137 : {
1138 : struct srventry temp;
1139 :
1140 0 : memcpy(&temp,&(*list)[j],sizeof(struct srventry));
1141 0 : memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry));
1142 0 : memcpy(&(*list)[i],&temp,sizeof(struct srventry));
1143 : }
1144 0 : break;
1145 : }
1146 : }
1147 : }
1148 :
1149 0 : return srvcount;
1150 :
1151 : fail:
1152 0 : xfree(*list);
1153 0 : *list=NULL;
1154 0 : return -1;
1155 : }
1156 : #endif /*USE_DNS_SRV*/
1157 :
1158 :
1159 : gpg_error_t
1160 0 : get_dns_cname (const char *name, char **r_cname)
1161 : {
1162 : gpg_error_t err;
1163 : int rc;
1164 :
1165 0 : *r_cname = NULL;
1166 :
1167 : #ifdef USE_ADNS
1168 : {
1169 : adns_state state;
1170 : adns_answer *answer = NULL;
1171 :
1172 : if (my_adns_init (&state))
1173 : return gpg_error (GPG_ERR_GENERAL);
1174 :
1175 : rc = adns_synchronous (state, name, adns_r_cname, adns_qf_quoteok_query,
1176 : &answer);
1177 : if (rc)
1178 : {
1179 : err = gpg_error_from_syserror ();
1180 : log_error ("DNS query failed: %s\n", gpg_strerror (err));
1181 : adns_finish (state);
1182 : return err;
1183 : }
1184 : if (answer->status != adns_s_ok
1185 : || answer->type != adns_r_cname || answer->nrrs != 1)
1186 : {
1187 : err = gpg_error (GPG_ERR_GENERAL);
1188 : log_error ("DNS query returned an error or no records: %s (%s)\n",
1189 : adns_strerror (answer->status),
1190 : adns_errabbrev (answer->status));
1191 : adns_free (answer);
1192 : adns_finish (state);
1193 : return err;
1194 : }
1195 : *r_cname = xtrystrdup (answer->rrs.str[0]);
1196 : if (!*r_cname)
1197 : err = gpg_error_from_syserror ();
1198 : else
1199 : err = 0;
1200 :
1201 : adns_free (answer);
1202 : adns_finish (state);
1203 : return err;
1204 : }
1205 : #else /*!USE_ADNS*/
1206 : {
1207 : unsigned char answer[2048];
1208 0 : HEADER *header = (HEADER *)answer;
1209 : unsigned char *pt, *emsg;
1210 : int r;
1211 : char *cname;
1212 0 : int cnamesize = 1025;
1213 : u16 count;
1214 :
1215 : /* Do not allow a query using the standard resolver in Tor mode. */
1216 0 : if (tor_mode)
1217 0 : return -1;
1218 :
1219 0 : r = res_query (name, C_IN, T_CERT, answer, sizeof answer);
1220 0 : if (r < sizeof (HEADER) || r > sizeof answer)
1221 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1222 0 : if (header->rcode != NOERROR || !(count=ntohs (header->ancount)))
1223 0 : return gpg_error (GPG_ERR_NO_NAME); /* Error or no record found. */
1224 0 : if (count != 1)
1225 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1226 :
1227 0 : emsg = &answer[r];
1228 0 : pt = &answer[sizeof(HEADER)];
1229 0 : rc = dn_skipname (pt, emsg);
1230 0 : if (rc == -1)
1231 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1232 :
1233 0 : pt += rc + QFIXEDSZ;
1234 0 : if (pt >= emsg)
1235 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1236 :
1237 0 : rc = dn_skipname (pt, emsg);
1238 0 : if (rc == -1)
1239 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1240 0 : pt += rc + 2 + 2 + 4;
1241 0 : if (pt+2 >= emsg)
1242 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1243 0 : pt += 2; /* Skip rdlen */
1244 :
1245 0 : cname = xtrymalloc (cnamesize);
1246 0 : if (!cname)
1247 0 : return gpg_error_from_syserror ();
1248 :
1249 0 : rc = dn_expand (answer, emsg, pt, cname, cnamesize -1);
1250 0 : if (rc == -1)
1251 : {
1252 0 : xfree (cname);
1253 0 : return gpg_error (GPG_ERR_SERVER_FAILED);
1254 : }
1255 0 : *r_cname = xtryrealloc (cname, strlen (cname)+1);
1256 0 : if (!*r_cname)
1257 : {
1258 0 : err = gpg_error_from_syserror ();
1259 0 : xfree (cname);
1260 0 : return err;
1261 : }
1262 0 : return 0;
1263 : }
1264 : #endif /*!USE_ADNS*/
1265 : }
|