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