From 0e7d62771d3786f28687e3db128e85022e5d8767 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 7 Dec 2009 17:11:59 +0000 Subject: [PATCH] Support PKA and SRV DNS lookups under w32 --- AUTHORS | 2 + ChangeLog | 6 + common/ChangeLog | 7 + common/pka.c | 73 ++++++++- common/srv.c | 376 +++++++++++++++++++++++++------------------ configure.ac | 77 +++++---- tools/ChangeLog | 4 + tools/no-libgcrypt.c | 5 +- 8 files changed, 362 insertions(+), 188 deletions(-) diff --git a/AUTHORS b/AUTHORS index de123ab78..85ce58e3c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -93,6 +93,8 @@ Pavel I. Shajdo Translations [ru] Pedro Morais Translations [pt_PT] +Petr Pisar Translations [cs] + RĂ©mi Guyomarch Assigns past and future changes. (g10/compress.c, g10/encr-data.c, g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c) diff --git a/ChangeLog b/ChangeLog index 77e3ec719..021d0f630 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-12-07 Werner Koch + + * configure.ac: Check for ADNS before checking for the BIND + resolver. + (USE_ADNS): Fallback macro for PKA and CERT lookups. + 2009-09-04 Werner Koch Release 2.0.13. diff --git a/common/ChangeLog b/common/ChangeLog index 1e1089a87..31298d1f4 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,10 @@ +2009-12-07 Werner Koch + + * pka.c (get_pka_info): Add support for ADNS. + * src.v (getsrv): Add support for ADNS. + + * srv.c (getsrv): s/xrealloc/xtryrealloc/. + 2009-12-04 Werner Koch * Makefile.am (audit-events.h, status-codes.h): Create files in diff --git a/common/pka.c b/common/pka.c index 79a0bc3f5..3d68802fe 100644 --- a/common/pka.c +++ b/common/pka.c @@ -1,5 +1,5 @@ /* 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. * @@ -33,6 +33,12 @@ #include #endif #endif /* USE_DNS_PKA */ +#ifdef USE_ADNS +# include +# ifndef HAVE_ADNS_FREE +# define adns_free free +# endif +#endif #include "util.h" #include "pka.h" @@ -106,6 +112,67 @@ 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; @@ -197,7 +264,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 @@ -247,6 +316,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: */ diff --git a/common/srv.c b/common/srv.c index 46d84b583..f3831b45e 100644 --- a/common/srv.c +++ b/common/srv.c @@ -30,6 +30,12 @@ #include #include #include +#ifdef USE_ADNS +# include +# ifndef HAVE_ADNS_FREE +# define adns_free free +# endif +#endif #include "util.h" #include "srv.h" @@ -52,172 +58,232 @@ priosort(const void *a,const void *b) return 0; } + int -getsrv(const char *name,struct srventry **list) +getsrv (const char *name,struct srventry **list) { - unsigned char answer[2048]; - int r,srvcount=0; - unsigned char *pt,*emsg; - u16 count,dlen; - HEADER *header=(HEADER *)answer; + int srvcount=0; + u16 count; + int i, rc; - *list=NULL; + *list = NULL; - r=res_query(name,C_IN,T_SRV,answer,2048); - if(r2048) - return -1; +#ifdef USE_ADNS + { + adns_state state; + adns_answer *answer = NULL; + + rc = adns_init (&state, adns_if_noerrprint, NULL); + if (rc) + { + log_error ("error initializing adns: %s\n", strerror (errno)); + return -1; + } - if(header->rcode==NOERROR && (count=ntohs(header->ancount))) + rc = adns_synchronous (state, name, adns_r_srv, adns_qf_quoteok_query, + &answer); + if (rc) + { + log_error ("DNS query failed: %s\n", strerror (errno)); + adns_finish (state); + return -1; + } + if (answer->status != adns_s_ok + || answer->type != adns_r_srv || !answer->nrrs) + { + /* log_error ("DNS query returned an error or no records: %s (%s)\n", */ + /* adns_strerror (answer->status), */ + /* adns_errabbrev (answer->status)); */ + adns_free (answer); + adns_finish (state); + return 0; + } + + for (count = 0; count < answer->nrrs; count++) + { + struct srventry *srv = NULL; + struct srventry *newlist; + + if (strlen (answer->rrs.srvha[count].ha.host) >= MAXDNAME) + { + log_info ("hostname in SRV record too long - skipped\n"); + continue; + } + + newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry)); + if (!newlist) + goto fail; + *list = newlist; + memset (&(*list)[srvcount], 0, sizeof(struct srventry)); + srv = &(*list)[srvcount]; + srvcount++; + + srv->priority = answer->rrs.srvha[count].priority; + srv->weight = answer->rrs.srvha[count].weight; + srv->port = answer->rrs.srvha[count].port; + strcpy (srv->target, answer->rrs.srvha[count].ha.host); + } + + adns_free (answer); + adns_finish (state); + } +#else /*!USE_ADNS*/ + { + unsigned char answer[2048]; + HEADER *header = (HEADER *)answer; + unsigned char *pt, *emsg; + int r; + u16 dlen; + + r = res_query (name, C_IN, T_SRV, answer, sizeof answer); + if (r < sizeof (HEADER) || r > sizeof answer) + return -1; + if (header->rcode != NOERROR || !(count=ntohs (header->ancount))) + return 0; /* Error or no record found. */ + + emsg = &answer[r]; + pt = &answer[sizeof(HEADER)]; + + /* Skip over the query */ + rc = dn_skipname (pt, emsg); + if (rc == -1) + goto fail; + + pt += rc + QFIXEDSZ; + + while (count-- > 0 && pt < emsg) + { + struct srventry *srv=NULL; + u16 type,class; + struct srventry *newlist; + + newlist = xtryrealloc (*list, (srvcount+1)*sizeof(struct srventry)); + if (!newlist) + goto fail; + *list = newlist; + memset(&(*list)[srvcount],0,sizeof(struct srventry)); + srv=&(*list)[srvcount]; + srvcount++; + + rc = dn_skipname(pt,emsg); /* the name we just queried for */ + if (rc == -1) + goto fail; + pt+=rc; + + /* Truncated message? */ + if((emsg-pt)<16) + goto fail; + + type=*pt++ << 8; + type|=*pt++; + /* We asked for SRV and got something else !? */ + if(type!=T_SRV) + goto fail; + + class=*pt++ << 8; + class|=*pt++; + /* We asked for IN and got something else !? */ + if(class!=C_IN) + goto fail; + + pt+=4; /* ttl */ + dlen=*pt++ << 8; + dlen|=*pt++; + srv->priority=*pt++ << 8; + srv->priority|=*pt++; + srv->weight=*pt++ << 8; + srv->weight|=*pt++; + srv->port=*pt++ << 8; + srv->port|=*pt++; + + /* Get the name. 2782 doesn't allow name compression, but + dn_expand still works to pull the name out of the + packet. */ + rc = dn_expand(answer,emsg,pt,srv->target,MAXDNAME); + if (rc == 1 && srv->target[0] == 0) /* "." */ + { + xfree(*list); + *list = NULL; + return 0; + } + if (rc == -1) + goto fail; + pt += rc; + /* Corrupt packet? */ + if (dlen != rc+6) + goto fail; + } + } +#endif /*!USE_ADNS*/ + + /* Now we have an array of all the srv records. */ + + /* Order by priority */ + qsort(*list,srvcount,sizeof(struct srventry),priosort); + + /* For each priority, move the zero-weighted items first. */ + for (i=0; i < srvcount; i++) { - int i,rc; + int j; + + for (j=i;j < srvcount && (*list)[i].priority == (*list)[j].priority; j++) + { + if((*list)[j].weight==0) + { + /* Swap j with i */ + if(j!=i) + { + struct srventry temp; + + memcpy (&temp,&(*list)[j],sizeof(struct srventry)); + memcpy (&(*list)[j],&(*list)[i],sizeof(struct srventry)); + memcpy (&(*list)[i],&temp,sizeof(struct srventry)); + } + + break; + } + } + } - emsg=&answer[r]; - pt=&answer[sizeof(HEADER)]; + /* Run the RFC-2782 weighting algorithm. We don't need very high + quality randomness for this, so regular libc srand/rand is + sufficient. Fixme: It is a bit questionaly to reinitalize srand + - better use a gnupg fucntion for this. */ + srand(time(NULL)*getpid()); - /* Skip over the query */ - - rc=dn_skipname(pt,emsg); - if(rc==-1) - goto fail; - - pt+=rc+QFIXEDSZ; - - while(count-->0 && ptpriority=*pt++ << 8; - srv->priority|=*pt++; - srv->weight=*pt++ << 8; - srv->weight|=*pt++; - srv->port=*pt++ << 8; - srv->port|=*pt++; - - /* Get the name. 2782 doesn't allow name compression, but - dn_expand still works to pull the name out of the - packet. */ - rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME); - if(rc==1 && srv->target[0]==0) /* "." */ - goto noanswer; - if(rc==-1) - goto fail; - pt+=rc; - /* Corrupt packet? */ - if(dlen!=rc+6) - goto fail; - -#if 0 - printf("count=%d\n",srvcount); - printf("priority=%d\n",srv->priority); - printf("weight=%d\n",srv->weight); - printf("port=%d\n",srv->port); - printf("target=%s\n",srv->target); -#endif - } - - /* Now we have an array of all the srv records. */ - - /* Order by priority */ - qsort(*list,srvcount,sizeof(struct srventry),priosort); - - /* For each priority, move the zero-weighted items first. */ - for(i=0;i @@ -795,9 +824,24 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ AC_DEFINE(BIND_8_COMPAT,1,[an Apple OSXism]) fi else - use_dns_srv=no - use_dns_pka=no + # If we have no resolver library but ADNS (e.g. under W32) enable the + # code parts which can be used with ADNS. use_dns_cert=no + if test x"$have_adns" = xyes ; then + DNSLIBS="$ADNSLIBS" + AC_DEFINE(USE_ADNS,1,[Use ADNS as resolver library.]) + + if test x"$use_dns_srv" = xyes ; then + AC_DEFINE(USE_DNS_SRV,1) + fi + + if test x"$use_dns_pka" = xyes ; then + AC_DEFINE(USE_DNS_PKA,1) + fi + else + use_dns_srv=no + use_dns_pka=no + fi fi LIBS=$_dns_save_libs @@ -808,33 +852,6 @@ AC_SUBST(DNSLIBS) AM_CONDITIONAL(USE_DNS_SRV, test x"$use_dns_srv" = xyes) -# -# Check for ADNS. -# -_cppflags="${CPPFLAGS}" -_ldflags="${LDFLAGS}" -AC_ARG_WITH(adns, - AC_HELP_STRING([--with-adns=DIR], - [look for the adns library in DIR]), - [if test -d "$withval"; then - CPPFLAGS="${CPPFLAGS} -I$withval/include" - LDFLAGS="${LDFLAGS} -L$withval/lib" - fi]) -if test "$with_adns" != "no"; then - AC_CHECK_HEADERS(adns.h, - AC_CHECK_LIB(adns, adns_init, - [have_adns=yes], - [CPPFLAGS=${_cppflags} LDFLAGS=${_ldflags}]), - [CPPFLAGS=${_cppflags} LDFLAGS=${_ldflags}]) -fi -if test "$have_adns" = "yes"; then - ADNSLIBS="-ladns" -fi -AC_SUBST(ADNSLIBS) -# Newer adns versions feature a free function to be used under W32. -AC_CHECK_FUNCS(adns_free) - - # # Check for LDAP # diff --git a/tools/ChangeLog b/tools/ChangeLog index 5714daca9..681f977e5 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2009-12-07 Werner Koch + + * no-libgcrypt.c (gcry_strdup): Actually copy the string. + 2009-07-21 Werner Koch * gpgsplit.c (my_strusage): Remove i18n stuff. diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index 3428e57ee..4cfedcc59 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -55,7 +55,10 @@ gcry_xmalloc (size_t n) char * gcry_strdup (const char *string) { - return malloc (strlen (string)+1); + char *p = malloc (strlen (string)+1); + if (p) + strcpy (p, string); + return p; }