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