build: Improve test for ADNS
[gnupg.git] / common / pka.c
index 3d442d1..d472162 100644 (file)
@@ -1,22 +1,30 @@
 /* pka.c - DNS Public Key Association RR access
 /* 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.
  *
  *
  * 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 2 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.
  *
  * You should have received a copy of the GNU General Public License
  * 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.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
 #ifdef USE_DNS_PKA
 #include <sys/types.h>
 #ifdef _WIN32
 #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 */
 #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"
 
 #include "util.h"
 #include "pka.h"
@@ -43,7 +57,7 @@
 /* Parse the TXT resource record. Format is:
 
    v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string
 /* 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
    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
@@ -66,7 +80,7 @@ parse_txt_record (char *buffer, unsigned char *fpr)
   *pend++ = 0;
   if (strcmp (p, "v=pka1"))
     return -1; /* Wrong or missing version. */
   *pend++ = 0;
   if (strcmp (p, "v=pka1"))
     return -1; /* Wrong or missing version. */
-  
+
   p = pend;
   pend = strchr (p, ';');
   if (pend)
   p = pend;
   pend = strchr (p, ';');
   if (pend)
@@ -78,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. */
     fpr[i] = xtoi_2 (p);
   if (i != 20)
     return -1; /* Fingerprint consists not of exactly 40 hexbytes. */
-    
+
   p = pend;
   if (!p || !*p)
     {
   p = pend;
   if (!p || !*p)
     {
-      *buffer = 0;  
+      *buffer = 0;
       return 0; /* Success (no URI given). */
     }
   if (strncmp (p, "uri=", 4))
       return 0; /* Success (no URI given). */
     }
   if (strncmp (p, "uri=", 4))
@@ -100,7 +114,7 @@ parse_txt_record (char *buffer, unsigned char *fpr)
 
    On success the 20 byte SHA-1 fingerprint is stored at FPR and the
    URI will be returned in an allocated buffer.  Note that the URI
 
    On success the 20 byte SHA-1 fingerprint is stored at FPR and the
    URI will be returned in an allocated buffer.  Note that the URI
-   might be an zero length string as this information is optiobnal.
+   might be an zero length string as this information is optional.
    Caller must xfree the returned string.
 
    On error NULL is returned and the 20 bytes at FPR are not
    Caller must xfree the returned string.
 
    On error NULL is returned and the 20 bytes at FPR are not
@@ -108,20 +122,83 @@ parse_txt_record (char *buffer, unsigned char *fpr)
 char *
 get_pka_info (const char *address, 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;
   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;
   int rc;
   unsigned char *p, *pend;
   const char *domain;
   char *name;
-
+  HEADER header;
 
   domain = strrchr (address, '@');
   if (!domain || domain == address || !domain[1])
     return NULL; /* invalid mail address given. */
 
 
   domain = strrchr (address, '@');
   if (!domain || domain == address || !domain[1])
     return NULL; /* invalid mail address given. */
 
-  name = malloc (strlen (address) + 5 + 1);
+  name = xtrymalloc (strlen (address) + 5 + 1);
+  if (!name)
+    return NULL;
   memcpy (name, address, domain - address);
   strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
 
   memcpy (name, address, domain - address);
   strcpy (stpcpy (name + (domain-address), "._pka."), 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. */
   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
     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 */
 
   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. */
 
   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;
       rc = dn_skipname (p, pend);
       if (rc == -1)
         return NULL;
-      p += rc + QFIXEDSZ; 
+      p += rc + QFIXEDSZ;
     }
 
   if (ancount > 1)
     }
 
   if (ancount > 1)
@@ -197,7 +278,9 @@ get_pka_info (const char *address, unsigned char *fpr)
     }
 
   return NULL;
     }
 
   return NULL;
+#endif /*!USE_ADNS*/
 }
 }
+
 #else /* !USE_DNS_PKA */
 
 /* Dummy version of the function if we can't use the resolver
 #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)
 {
 char *
 get_pka_info (const char *address, unsigned char *fpr)
 {
+  (void)address;
+  (void)fpr;
   return NULL;
 }
 #endif /* !USE_DNS_PKA */
   return NULL;
 }
 #endif /* !USE_DNS_PKA */
@@ -247,6 +332,6 @@ main(int argc,char *argv[])
 
 /*
 Local Variables:
 
 /*
 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:
 */
 End:
 */