Actually increase buffer size of t-dns-cert.c.
[gnupg.git] / common / pka.c
index e8cdee6..89761f5 100644 (file)
@@ -1,5 +1,5 @@
 /* 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.
  *
 #include <resolv.h>
 #endif
 #endif /* USE_DNS_PKA */
 #include <resolv.h>
 #endif
 #endif /* USE_DNS_PKA */
+#ifdef USE_ADNS
+# include <adns.h>
+# ifndef HAVE_ADNS_FREE
+#  define adns_free free
+# endif
+#endif
 
 #include "util.h"
 #include "pka.h"
 
 #include "util.h"
 #include "pka.h"
@@ -41,7 +47,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
@@ -64,7 +70,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)
@@ -76,11 +82,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))
@@ -98,7 +104,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
@@ -106,20 +112,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);
 
@@ -127,7 +196,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
@@ -135,10 +210,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. */
@@ -151,7 +224,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)
@@ -195,7 +268,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
@@ -203,6 +278,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 */
@@ -245,6 +322,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:
 */