diff options
author | Werner Koch <wk@gnupg.org> | 2009-12-07 16:52:27 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2009-12-07 16:52:27 +0100 |
commit | 85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21 (patch) | |
tree | 46ac431df3a7970a33bee257b79ea00d35bee2a0 | |
parent | allow for default algorithms in a gpg parameter file (diff) | |
download | gnupg2-85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21.tar.xz gnupg2-85d778b9f6fc37f1fae9c2d0dca6c3d51517dd21.zip |
Use ADNS for PKA and SRV records if no other resolver is available.
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | common/ChangeLog | 7 | ||||
-rw-r--r-- | common/pka.c | 71 | ||||
-rw-r--r-- | common/srv.c | 382 | ||||
-rw-r--r-- | configure.ac | 73 | ||||
-rw-r--r-- | doc/DETAILS | 2 | ||||
-rw-r--r-- | tools/ChangeLog | 4 | ||||
-rw-r--r-- | tools/no-libgcrypt.c | 5 |
9 files changed, 362 insertions, 189 deletions
@@ -1,3 +1,8 @@ +2009-12-07 Werner Koch <wk@g10code.com> + + * configure.ac: Check for ADNS before checking for the BIND + resolver. + 2009-10-20 Marcus Brinkmann <marcus@g10code.com> * configure.ac: Check for fusermount and encfs. @@ -14,6 +14,8 @@ Noteworthy changes in version 2.1.x (under development) * Numerical values may now be used as an alternative to the debug-level keywords. + * Support SRV and PKA records on W32. + Noteworthy changes in version 2.0.13 (2009-09-04) ------------------------------------------------- diff --git a/common/ChangeLog b/common/ChangeLog index e2da8a01a..6ec45823d 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,10 @@ +2009-12-07 Werner Koch <wk@g10code.com> + + * 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 <wk@g10code.com> * Makefile.am (audit-events.h, status-codes.h): Create files in diff --git a/common/pka.c b/common/pka.c index 79a0bc3f5..e78f54367 100644 --- a/common/pka.c +++ b/common/pka.c @@ -33,6 +33,12 @@ #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" @@ -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..79ffc7862 100644 --- a/common/srv.c +++ b/common/srv.c @@ -30,6 +30,12 @@ #include <stdlib.h> #include <string.h> #include <time.h> +#ifdef USE_ADNS +# include <adns.h> +# 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; - - *list=NULL; + int srvcount=0; + u16 count; + int i, rc; + + *list = NULL; + +#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; + } + + 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 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; + } + } + } - r=res_query(name,C_IN,T_SRV,answer,2048); - if(r<sizeof(HEADER) || r>2048) - return -1; + /* 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()); - if(header->rcode==NOERROR && (count=ntohs(header->ancount))) + for (i=0; i < srvcount; i++) { - int i,rc; - - 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; - - *list=xrealloc(*list,(srvcount+1)*sizeof(struct srventry)); - 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) /* "." */ - 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<srvcount;i++) - { - 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; - } - } - } - - /* Run the RFC-2782 weighting algorithm. We don't need very - high quality randomness for this, so regular libc srand/rand - is sufficient. */ - srand(time(NULL)*getpid()); - - for(i=0;i<srvcount;i++) - { - int j; - float prio_count=0,chose; - - for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) - { - prio_count+=(*list)[j].weight; - (*list)[j].run_count=prio_count; - } - - chose=prio_count*rand()/RAND_MAX; - - for(j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) - { - if(chose<=(*list)[j].run_count) - { - /* 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; - } - } - } + int j; + float prio_count=0,chose; + + for (j=i; j < srvcount && (*list)[i].priority == (*list)[j].priority; j++) + { + prio_count+=(*list)[j].weight; + (*list)[j].run_count=prio_count; + } + + chose=prio_count*rand()/RAND_MAX; + + for (j=i;j<srvcount && (*list)[i].priority==(*list)[j].priority;j++) + { + if (chose<=(*list)[j].run_count) + { + /* 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; + } + } } return srvcount; - noanswer: - xfree(*list); - *list=NULL; - return 0; - fail: xfree(*list); *list=NULL; @@ -250,6 +316,6 @@ main(int argc,char *argv[]) /* Local Variables: -compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv libutil.a" +compile-command: "cc -DTEST -I.. -I../include -Wall -g -o srv srv.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a" End: */ diff --git a/configure.ac b/configure.ac index 42f4857da..8797e7954 100644 --- a/configure.ac +++ b/configure.ac @@ -710,6 +710,35 @@ AC_CHECK_FUNC(gethostbyname, , AC_CHECK_LIB(nsl, gethostbyname, AC_CHECK_FUNC(setsockopt, , AC_CHECK_LIB(socket, setsockopt, [NETLIBS="-lsocket $NETLIBS"])) + +# +# 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) + + + # # Now try for the resolver functions so we can use DNS for SRV, PA and CERT. # @@ -747,7 +776,8 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ # Make sure that the BIND 4 resolver interface is workable before # enabling any code that calls it. At some point I'll rewrite the # code to use the BIND 8 resolver API. - # We might also want to use adns instead. + # We might also want to use adns instead. Problem with ADNS is that + # it does not support v6. AC_MSG_CHECKING([whether the resolver is usable]) AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <sys/types.h> @@ -802,6 +832,20 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \ use_dns_srv=no use_dns_pka=no use_dns_cert=no + # If we have no resolver library but ADNS (e.g. under W32) enable the + # code parts which can be used with ADNS. + if test x"$have_adns" = xyes ; then + DNSLIB="$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 + fi fi LIBS=$_dns_save_libs @@ -813,33 +857,6 @@ 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 # if test "$try_ldap" = yes ; then diff --git a/doc/DETAILS b/doc/DETAILS index 829407997..89f9e86a1 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -843,7 +843,7 @@ The format of this file is as follows: given but "default" is used the usage will be "sign". Subkey-Type: <algo-number>|<algo-string> This generates a secondary key. Currently only one subkey - can be handled. + can be handled. "default" is also supported. Subkey-Length: <length-in-bits> Length of the subkey in bits. The default is returned by running the command "gpg --gpgconf-list". diff --git a/tools/ChangeLog b/tools/ChangeLog index eaa60bb99..02e67f922 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2009-12-07 Werner Koch <wk@g10code.com> + + * no-libgcrypt.c (gcry_strdup): Actually copy the string. + 2009-11-23 Werner Koch <wk@g10code.com> * gpgconf-comp.c (gc_options_gpg): Add default_pubkey_algo. 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; } |