build: Improve test for ADNS
[gnupg.git] / common / pka.c
index 79a0bc3..d472162 100644 (file)
@@ -1,14 +1,24 @@
 /* pka.c - DNS Public Key Association RR access
- * Copyright (C) 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2005, 2009 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
  *
- * GnuPG is distributed in the hope that it will be useful,
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
 #ifdef USE_DNS_PKA
 #include <sys/types.h>
 #ifdef _WIN32
-#include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+#  include <winsock2.h>
+# endif
+# include <windows.h>
 #else
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 #endif
 #endif /* USE_DNS_PKA */
+#ifdef USE_ADNS
+# include <adns.h>
+#endif
 
 #include "util.h"
 #include "pka.h"
@@ -41,7 +57,7 @@
 /* Parse the TXT resource record. Format is:
 
    v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string
-   
+
    For simplicity white spaces are not allowed.  Because we expect to
    use a new RRTYPE for this in the future we define the TXT really
    strict for simplicity: No white spaces, case sensitivity of the
@@ -64,7 +80,7 @@ parse_txt_record (char *buffer, unsigned char *fpr)
   *pend++ = 0;
   if (strcmp (p, "v=pka1"))
     return -1; /* Wrong or missing version. */
-  
+
   p = pend;
   pend = strchr (p, ';');
   if (pend)
@@ -76,11 +92,11 @@ parse_txt_record (char *buffer, unsigned char *fpr)
     fpr[i] = xtoi_2 (p);
   if (i != 20)
     return -1; /* Fingerprint consists not of exactly 40 hexbytes. */
-    
+
   p = pend;
   if (!p || !*p)
     {
-      *buffer = 0;  
+      *buffer = 0;
       return 0; /* Success (no URI given). */
     }
   if (strncmp (p, "uri=", 4))
@@ -106,14 +122,75 @@ parse_txt_record (char *buffer, unsigned char *fpr)
 char *
 get_pka_info (const char *address, unsigned char *fpr)
 {
+#ifdef USE_ADNS
+  int rc;
+  adns_state state;
+  const char *domain;
+  char *name;
+  adns_answer *answer = NULL;
+  char *buffer = NULL;
+
+  domain = strrchr (address, '@');
+  if (!domain || domain == address || !domain[1])
+    return NULL; /* Invalid mail address given.  */
+  name = xtrymalloc (strlen (address) + 5 + 1);
+  if (!name)
+    return NULL;
+  memcpy (name, address, domain - address);
+  strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
+
+  rc = adns_init (&state, adns_if_noerrprint, NULL);
+  if (rc)
+    {
+      log_error ("error initializing adns: %s\n", strerror (errno));
+      xfree (name);
+      return NULL;
+    }
+
+  rc = adns_synchronous (state, name, adns_r_txt, adns_qf_quoteok_query,
+                         &answer);
+  xfree (name);
+  if (rc)
+    {
+      log_error ("DNS query failed: %s\n", strerror (errno));
+      adns_finish (state);
+      return NULL;
+    }
+  if (answer->status != adns_s_ok
+      || answer->type != adns_r_txt || !answer->nrrs)
+    {
+      log_error ("DNS query returned an error: %s (%s)\n",
+                 adns_strerror (answer->status),
+                 adns_errabbrev (answer->status));
+      adns_free (answer);
+      adns_finish (state);
+      return NULL;
+    }
+
+  /* We use a PKA records iff there is exactly one record.  */
+  if (answer->nrrs == 1 && answer->rrs.manyistr[0]->i != -1)
+    {
+      buffer = xtrystrdup (answer->rrs.manyistr[0]->str);
+      if (parse_txt_record (buffer, fpr))
+        {
+          xfree (buffer);
+          buffer = NULL;   /* Not a valid gpg trustdns RR. */
+        }
+    }
+
+  adns_free (answer);
+  adns_finish (state);
+  return buffer;
+
+#else /*!USE_ADNS*/
   unsigned char answer[PACKETSZ];
   int anslen;
-  int qdcount, ancount, nscount, arcount;
+  int qdcount, ancount;
   int rc;
   unsigned char *p, *pend;
   const char *domain;
   char *name;
-
+  HEADER header;
 
   domain = strrchr (address, '@');
   if (!domain || domain == address || !domain[1])
@@ -129,7 +206,13 @@ get_pka_info (const char *address, unsigned char *fpr)
   xfree (name);
   if (anslen < sizeof(HEADER))
     return NULL; /* DNS resolver returned a too short answer. */
-  if ( (rc=((HEADER*)answer)->rcode) != NOERROR )
+
+  /* Don't despair: A good compiler should optimize this away, as
+     header is just 32 byte and constant at compile time.  It's
+     one way to comply with strict aliasing rules.  */
+  memcpy (&header, answer, sizeof (header));
+
+  if ( (rc=header.rcode) != NOERROR )
     return NULL; /* DNS resolver returned an error. */
 
   /* We assume that PACKETSZ is large enough and don't do dynmically
@@ -137,10 +220,8 @@ get_pka_info (const char *address, unsigned char *fpr)
   if (anslen > PACKETSZ)
     return NULL; /* DNS resolver returned a too long answer */
 
-  qdcount = ntohs (((HEADER*)answer)->qdcount);
-  ancount = ntohs (((HEADER*)answer)->ancount);
-  nscount = ntohs (((HEADER*)answer)->nscount);
-  arcount = ntohs (((HEADER*)answer)->arcount);
+  qdcount = ntohs (header.qdcount);
+  ancount = ntohs (header.ancount);
 
   if (!ancount)
     return NULL; /* Got no answer. */
@@ -153,7 +234,7 @@ get_pka_info (const char *address, unsigned char *fpr)
       rc = dn_skipname (p, pend);
       if (rc == -1)
         return NULL;
-      p += rc + QFIXEDSZ; 
+      p += rc + QFIXEDSZ;
     }
 
   if (ancount > 1)
@@ -197,7 +278,9 @@ get_pka_info (const char *address, unsigned char *fpr)
     }
 
   return NULL;
+#endif /*!USE_ADNS*/
 }
+
 #else /* !USE_DNS_PKA */
 
 /* Dummy version of the function if we can't use the resolver
@@ -205,6 +288,8 @@ get_pka_info (const char *address, unsigned char *fpr)
 char *
 get_pka_info (const char *address, unsigned char *fpr)
 {
+  (void)address;
+  (void)fpr;
   return NULL;
 }
 #endif /* !USE_DNS_PKA */
@@ -247,6 +332,6 @@ main(int argc,char *argv[])
 
 /*
 Local Variables:
-compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv libutil.a"
+compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a"
 End:
 */