dirmngr: Do not use brackets around legacy IP addresses.
[gnupg.git] / dirmngr / ks-engine-hkp.c
1 /* ks-engine-hkp.c - HKP keyserver engine
2  * Copyright (C) 2011, 2012 Free Software Foundation, Inc.
3  * Copyright (C) 2011, 2012, 2014 Werner Koch
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27 #ifdef HAVE_W32_SYSTEM
28 # ifdef HAVE_WINSOCK2_H
29 #  include <winsock2.h>
30 # endif
31 # include <windows.h>
32 #else /*!HAVE_W32_SYSTEM*/
33 # include <sys/types.h>
34 # include <sys/socket.h>
35 # include <netdb.h>
36 #endif /*!HAVE_W32_SYSTEM*/
37
38 #include "dirmngr.h"
39 #include "misc.h"
40 #include "userids.h"
41 #include "ks-engine.h"
42
43 /* Substitute a missing Mingw macro.  */
44 #ifndef EAI_OVERFLOW
45 # define EAI_OVERFLOW EAI_FAIL
46 #endif
47
48
49 /* To match the behaviour of our old gpgkeys helper code we escape
50    more characters than actually needed. */
51 #define EXTRA_ESCAPE_CHARS "@!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
52
53 /* How many redirections do we allow.  */
54 #define MAX_REDIRECTS 2
55
56 /* Number of retries done for a dead host etc.  */
57 #define SEND_REQUEST_RETRIES 3
58
59 /* Objects used to maintain information about hosts.  */
60 struct hostinfo_s;
61 typedef struct hostinfo_s *hostinfo_t;
62 struct hostinfo_s
63 {
64   time_t lastfail;   /* Time we tried to connect and failed.  */
65   time_t lastused;   /* Time of last use.  */
66   int *pool;         /* A -1 terminated array with indices into
67                         HOSTTABLE or NULL if NAME is not a pool
68                         name.  */
69   int poolidx;       /* Index into POOL with the used host.  */
70   unsigned int v4:1; /* Host supports AF_INET.  */
71   unsigned int v6:1; /* Host supports AF_INET6.  */
72   unsigned int dead:1; /* Host is currently unresponsive.  */
73   char name[1];      /* The hostname.  */
74 };
75
76
77 /* An array of hostinfo_t for all hosts requested by the caller or
78    resolved from a pool name and its allocated size.*/
79 static hostinfo_t *hosttable;
80 static int hosttable_size;
81
82 /* The number of host slots we initally allocate for HOSTTABLE.  */
83 #define INITIAL_HOSTTABLE_SIZE 10
84
85
86 /* Create a new hostinfo object, fill in NAME and put it into
87    HOSTTABLE.  Return the index into hosttable on success or -1 on
88    error. */
89 static int
90 create_new_hostinfo (const char *name)
91 {
92   hostinfo_t hi, *newtable;
93   int newsize;
94   int idx, rc;
95
96   hi = xtrymalloc (sizeof *hi + strlen (name));
97   if (!hi)
98     return -1;
99   strcpy (hi->name, name);
100   hi->pool = NULL;
101   hi->poolidx = -1;
102   hi->lastused = (time_t)(-1);
103   hi->lastfail = (time_t)(-1);
104   hi->v4 = 0;
105   hi->v6 = 0;
106   hi->dead = 0;
107
108   /* Add it to the hosttable. */
109   for (idx=0; idx < hosttable_size; idx++)
110     if (!hosttable[idx])
111       {
112         hosttable[idx] = hi;
113         return idx;
114       }
115   /* Need to extend the hosttable.  */
116   newsize = hosttable_size + INITIAL_HOSTTABLE_SIZE;
117   newtable = xtryrealloc (hosttable, newsize * sizeof *hosttable);
118   if (!newtable)
119     {
120       xfree (hi);
121       return -1;
122     }
123   hosttable = newtable;
124   idx = hosttable_size;
125   hosttable_size = newsize;
126   rc = idx;
127   hosttable[idx++] = hi;
128   while (idx < hosttable_size)
129     hosttable[idx++] = NULL;
130
131   return rc;
132 }
133
134
135 /* Find the host NAME in our table.  Return the index into the
136    hosttable or -1 if not found.  */
137 static int
138 find_hostinfo (const char *name)
139 {
140   int idx;
141
142   for (idx=0; idx < hosttable_size; idx++)
143     if (hosttable[idx] && !ascii_strcasecmp (hosttable[idx]->name, name))
144       return idx;
145   return -1;
146 }
147
148
149 static int
150 sort_hostpool (const void *xa, const void *xb)
151 {
152   int a = *(int *)xa;
153   int b = *(int *)xb;
154
155   assert (a >= 0 && a < hosttable_size);
156   assert (b >= 0 && b < hosttable_size);
157   assert (hosttable[a]);
158   assert (hosttable[b]);
159
160   return ascii_strcasecmp (hosttable[a]->name, hosttable[b]->name);
161 }
162
163
164 /* Return true if the host with the hosttable index TBLIDX is in POOL.  */
165 static int
166 host_in_pool_p (int *pool, int tblidx)
167 {
168   int i, pidx;
169
170   for (i=0; (pidx = pool[i]) != -1; i++)
171     if (pidx == tblidx && hosttable[pidx])
172       return 1;
173   return 0;
174 }
175
176
177 /* Select a random host.  Consult TABLE which indices into the global
178    hosttable.  Returns index into TABLE or -1 if no host could be
179    selected.  */
180 static int
181 select_random_host (int *table)
182 {
183   int *tbl;
184   size_t tblsize;
185   int pidx, idx;
186
187   /* We create a new table so that we randomly select only from
188      currently alive hosts.  */
189   for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
190     if (hosttable[pidx] && !hosttable[pidx]->dead)
191       tblsize++;
192   if (!tblsize)
193     return -1; /* No hosts.  */
194
195   tbl = xtrymalloc (tblsize * sizeof *tbl);
196   if (!tbl)
197     return -1;
198   for (idx=0, tblsize=0; (pidx = table[idx]) != -1; idx++)
199     if (hosttable[pidx] && !hosttable[pidx]->dead)
200       tbl[tblsize++] = pidx;
201
202   if (tblsize == 1)  /* Save a get_uint_nonce.  */
203     pidx = tbl[0];
204   else
205     pidx = tbl[get_uint_nonce () % tblsize];
206
207   xfree (tbl);
208   return pidx;
209 }
210
211
212 /* Simplified version of getnameinfo which also returns a numeric
213    hostname inside of brackets.  The caller should provide a buffer
214    for TMPHOST which is 2 bytes larger than the the largest hostname.
215    returns 0 on success or an EAI error code.  */
216 static int
217 my_getnameinfo (struct addrinfo *ai, char *host, size_t hostlen)
218 {
219   int ec;
220   char *p;
221
222   if (hostlen < 5)
223     return EAI_OVERFLOW;
224
225   ec = getnameinfo (ai->ai_addr, ai->ai_addrlen,
226                     host, hostlen, NULL, 0, NI_NAMEREQD);
227   if (!ec && *host == '[')
228     ec = EAI_FAIL;  /* A name may never start with a bracket.  */
229   else if (ec == EAI_NONAME)
230     {
231       p = host;
232       if (ai->ai_family == AF_INET6)
233         {
234           *p++ = '[';
235           hostlen -= 2;
236         }
237       ec = getnameinfo (ai->ai_addr, ai->ai_addrlen,
238                         p, hostlen, NULL, 0, NI_NUMERICHOST);
239       if (!ec && ai->ai_family == AF_INET6)
240         strcat (host, "]");
241     }
242
243   return ec;
244 }
245
246
247 /* Map the host name NAME to the actual to be used host name.  This
248    allows us to manage round robin DNS names.  We use our own strategy
249    to choose one of the hosts.  For example we skip those hosts which
250    failed for some time and we stick to one host for a time
251    independent of DNS retry times.  If FORCE_RESELECT is true a new
252    host is always selected. */
253 static char *
254 map_host (ctrl_t ctrl, const char *name, int force_reselect)
255 {
256   hostinfo_t hi;
257   int idx;
258
259   /* No hostname means localhost.  */
260   if (!name || !*name)
261     return xtrystrdup ("localhost");
262
263   /* See whether the host is in our table.  */
264   idx = find_hostinfo (name);
265   if (idx == -1)
266     {
267       /* We never saw this host.  Allocate a new entry.  */
268       struct addrinfo hints, *aibuf, *ai;
269       int *reftbl;
270       size_t reftblsize;
271       int refidx;
272
273       reftblsize = 100;
274       reftbl = xtrymalloc (reftblsize * sizeof *reftbl);
275       if (!reftbl)
276         return NULL;
277       refidx = 0;
278
279       idx = create_new_hostinfo (name);
280       if (idx == -1)
281         {
282           xfree (reftbl);
283           return NULL;
284         }
285       hi = hosttable[idx];
286
287       /* Find all A records for this entry and put them into the pool
288          list - if any.  */
289       memset (&hints, 0, sizeof (hints));
290       hints.ai_socktype = SOCK_STREAM;
291       if (!getaddrinfo (name, NULL, &hints, &aibuf))
292         {
293           for (ai = aibuf; ai; ai = ai->ai_next)
294             {
295               char tmphost[NI_MAXHOST];
296               int tmpidx;
297               int ec;
298               int i;
299
300               if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
301                 continue;
302
303               dirmngr_tick (ctrl);
304               if ((ec = my_getnameinfo (ai, tmphost, sizeof tmphost)))
305                 {
306                   log_info ("getnameinfo failed while checking '%s': %s\n",
307                             name, gai_strerror (ec));
308                 }
309               else if (refidx+1 >= reftblsize)
310                 {
311                   log_error ("getnameinfo returned for '%s': '%s'"
312                             " [index table full - ignored]\n", name, tmphost);
313                 }
314               else
315                 {
316
317                   if ((tmpidx = find_hostinfo (tmphost)) != -1)
318                     {
319                       log_info ("getnameinfo returned for '%s': '%s'"
320                                 " [already known]\n", name, tmphost);
321                       if (ai->ai_family == AF_INET)
322                         hosttable[tmpidx]->v4 = 1;
323                       if (ai->ai_family == AF_INET6)
324                         hosttable[tmpidx]->v6 = 1;
325
326                       for (i=0; i < refidx; i++)
327                         if (reftbl[i] == tmpidx)
328                           break;
329                       if (!(i < refidx) && tmpidx != idx)
330                         reftbl[refidx++] = tmpidx;
331                     }
332                   else
333                     {
334                       log_info ("getnameinfo returned for '%s': '%s'\n",
335                                 name, tmphost);
336                       /* Create a new entry.  */
337                       tmpidx = create_new_hostinfo (tmphost);
338                       if (tmpidx == -1)
339                         log_error ("map_host for '%s' problem: %s - '%s'"
340                                    " [ignored]\n",
341                                    name, strerror (errno), tmphost);
342                       else
343                         {
344                           if (ai->ai_family == AF_INET)
345                             hosttable[tmpidx]->v4 = 1;
346                           if (ai->ai_family == AF_INET6)
347                             hosttable[tmpidx]->v6 = 1;
348
349                           for (i=0; i < refidx; i++)
350                             if (reftbl[i] == tmpidx)
351                               break;
352                           if (!(i < refidx) && tmpidx != idx)
353                             reftbl[refidx++] = tmpidx;
354                         }
355                     }
356                 }
357             }
358         }
359       reftbl[refidx] = -1;
360       if (refidx)
361         {
362           assert (!hi->pool);
363           hi->pool = xtryrealloc (reftbl, (refidx+1) * sizeof *reftbl);
364           if (!hi->pool)
365             {
366               log_error ("shrinking index table in map_host failed: %s\n",
367                          strerror (errno));
368               xfree (reftbl);
369             }
370           qsort (reftbl, refidx, sizeof *reftbl, sort_hostpool);
371         }
372       else
373         xfree (reftbl);
374     }
375
376   hi = hosttable[idx];
377   if (hi->pool)
378     {
379       /* If the currently selected host is now marked dead, force a
380          re-selection .  */
381       if (force_reselect)
382         hi->poolidx = -1;
383       else if (hi->poolidx >= 0 && hi->poolidx < hosttable_size
384                && hosttable[hi->poolidx] && hosttable[hi->poolidx]->dead)
385         hi->poolidx = -1;
386
387       /* Select a host if needed.  */
388       if (hi->poolidx == -1)
389         {
390           hi->poolidx = select_random_host (hi->pool);
391           if (hi->poolidx == -1)
392             {
393               log_error ("no alive host found in pool '%s'\n", name);
394               return NULL;
395             }
396         }
397
398       assert (hi->poolidx >= 0 && hi->poolidx < hosttable_size);
399       hi = hosttable[hi->poolidx];
400       assert (hi);
401     }
402
403   if (hi->dead)
404     {
405       log_error ("host '%s' marked as dead\n", hi->name);
406       return NULL;
407     }
408
409   return xtrystrdup (hi->name);
410 }
411
412
413 /* Mark the host NAME as dead.  NAME may be given as an URL.  Returns
414    true if a host was really marked as dead or was already marked dead
415    (e.g. by a concurrent session).  */
416 static int
417 mark_host_dead (const char *name)
418 {
419   const char *host;
420   char *host_buffer = NULL;
421   parsed_uri_t parsed_uri = NULL;
422   int done = 0;
423
424   if (name && *name && !http_parse_uri (&parsed_uri, name, 1))
425     {
426       if (parsed_uri->v6lit)
427         {
428           host_buffer = strconcat ("[", parsed_uri->host, "]", NULL);
429           if (!host_buffer)
430             log_error ("out of core in mark_host_dead");
431           host = host_buffer;
432         }
433       else
434         host = parsed_uri->host;
435     }
436   else
437     host = name;
438
439   if (host && *host && strcmp (host, "localhost"))
440     {
441       hostinfo_t hi;
442       int idx;
443
444       idx = find_hostinfo (host);
445       if (idx != -1)
446         {
447           hi = hosttable[idx];
448           log_info ("marking host '%s' as dead%s\n",
449                     hi->name, hi->dead? " (again)":"");
450           hi->dead = 1;
451           done = 1;
452         }
453     }
454
455   http_release_parsed_uri (parsed_uri);
456   xfree (host_buffer);
457   return done;
458 }
459
460
461 /* Mark a host in the hosttable as dead or - if ALIVE is true - as
462    alive.  */
463 gpg_error_t
464 ks_hkp_mark_host (ctrl_t ctrl, const char *name, int alive)
465 {
466   gpg_error_t err = 0;
467   hostinfo_t hi, hi2;
468   int idx, idx2, idx3, n;
469
470   if (!name || !*name || !strcmp (name, "localhost"))
471     return 0;
472
473   idx = find_hostinfo (name);
474   if (idx == -1)
475     return gpg_error (GPG_ERR_NOT_FOUND);
476
477   hi = hosttable[idx];
478   if (alive && hi->dead)
479     {
480       hi->dead = 0;
481       err = ks_printf_help (ctrl, "marking '%s' as alive", name);
482     }
483   else if (!alive && !hi->dead)
484     {
485       hi->dead = 1;
486       err = ks_printf_help (ctrl, "marking '%s' as dead", name);
487     }
488
489   /* If the host is a pool mark all member hosts. */
490   if (!err && hi->pool)
491     {
492       for (idx2=0; !err && (n=hi->pool[idx2]) != -1; idx2++)
493         {
494           assert (n >= 0 && n < hosttable_size);
495
496           if (!alive)
497             {
498               /* Do not mark a host from a pool dead if it is also a
499                  member in another pool.  */
500               for (idx3=0; idx3 < hosttable_size; idx3++)
501                 {
502                   if (hosttable[idx3] && hosttable[idx3]
503                       && hosttable[idx3]->pool
504                       && idx3 != idx
505                       && host_in_pool_p (hosttable[idx3]->pool, n))
506                     break;
507                 }
508               if (idx3 < hosttable_size)
509                 continue;  /* Host is also a member of another pool.  */
510             }
511
512           hi2 = hosttable[n];
513           if (!hi2)
514             ;
515           else if (alive && hi2->dead)
516             {
517               hi2->dead = 0;
518               err = ks_printf_help (ctrl, "marking '%s' as alive",
519                                     hi2->name);
520             }
521           else if (!alive && !hi2->dead)
522             {
523               hi2->dead = 1;
524               err = ks_printf_help (ctrl, "marking '%s' as dead",
525                                     hi2->name);
526             }
527         }
528     }
529
530   return err;
531 }
532
533
534 /* Debug function to print the entire hosttable.  */
535 gpg_error_t
536 ks_hkp_print_hosttable (ctrl_t ctrl)
537 {
538   gpg_error_t err;
539   int idx, idx2;
540   hostinfo_t hi;
541   membuf_t mb;
542   char *p;
543
544   err = ks_print_help (ctrl, "hosttable (idx, ipv4, ipv6, dead, name):");
545   if (err)
546     return err;
547
548   for (idx=0; idx < hosttable_size; idx++)
549     if ((hi=hosttable[idx]))
550       {
551         err = ks_printf_help (ctrl, "%3d %s %s %s %s\n",
552                               idx, hi->v4? "4":" ", hi->v6? "6":" ",
553                               hi->dead? "d":" ", hi->name);
554         if (err)
555           return err;
556         if (hi->pool)
557           {
558             init_membuf (&mb, 256);
559             put_membuf_printf (&mb, "  .   -->");
560             for (idx2=0; hi->pool[idx2] != -1; idx2++)
561               {
562                 put_membuf_printf (&mb, " %d", hi->pool[idx2]);
563                 if (hi->poolidx == hi->pool[idx2])
564                   put_membuf_printf (&mb, "*");
565               }
566             put_membuf( &mb, "", 1);
567             p = get_membuf (&mb, NULL);
568             if (!p)
569               return gpg_error_from_syserror ();
570             err = ks_print_help (ctrl, p);
571             xfree (p);
572             if (err)
573               return err;
574           }
575       }
576   return 0;
577 }
578
579
580
581 /* Print a help output for the schemata supported by this module. */
582 gpg_error_t
583 ks_hkp_help (ctrl_t ctrl, parsed_uri_t uri)
584 {
585   const char const data[] =
586     "Handler for HKP URLs:\n"
587     "  hkp://\n"
588     "Supported methods: search, get, put\n";
589   gpg_error_t err;
590
591   if (!uri)
592     err = ks_print_help (ctrl, "  hkp");
593   else if (uri->is_http && !strcmp (uri->scheme, "hkp"))
594     err = ks_print_help (ctrl, data);
595   else
596     err = 0;
597
598   return err;
599 }
600
601
602 /* Build the remote part or the URL from SCHEME, HOST and an optional
603    PORT.  Returns an allocated string or NULL on failure and sets
604    ERRNO.  */
605 static char *
606 make_host_part (ctrl_t ctrl,
607                 const char *scheme, const char *host, unsigned short port,
608                 int force_reselect)
609 {
610   char portstr[10];
611   char *hostname;
612   char *hostport;
613
614   /* Map scheme and port.  */
615   if (!strcmp (scheme, "hkps") || !strcmp (scheme,"https"))
616     {
617       scheme = "https";
618       strcpy (portstr, "443");
619     }
620   else /* HKP or HTTP.  */
621     {
622       scheme = "http";
623       strcpy (portstr, "11371");
624     }
625   if (port)
626     snprintf (portstr, sizeof portstr, "%hu", port);
627   else
628     {
629       /*fixme_do_srv_lookup ()*/
630     }
631
632   hostname = map_host (ctrl, host, force_reselect);
633   if (!hostname)
634     return NULL;
635
636   hostport = strconcat (scheme, "://", hostname, ":", portstr, NULL);
637   xfree (hostname);
638   return hostport;
639 }
640
641
642 /* Resolve all known keyserver names and update the hosttable.  This
643    is mainly useful for debugging because the resolving is anyway done
644    on demand.  */
645 gpg_error_t
646 ks_hkp_resolve (ctrl_t ctrl, parsed_uri_t uri)
647 {
648   gpg_error_t err;
649   char *hostport = NULL;
650
651   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, 1);
652   if (!hostport)
653     {
654       err = gpg_error_from_syserror ();
655       err = ks_printf_help (ctrl, "%s://%s:%hu: resolve failed: %s",
656                             uri->scheme, uri->host, uri->port,
657                             gpg_strerror (err));
658     }
659   else
660     {
661       err = ks_printf_help (ctrl, "%s", hostport);
662       xfree (hostport);
663     }
664   return err;
665 }
666
667
668 /* Send an HTTP request.  On success returns an estream object at
669    R_FP.  HOSTPORTSTR is only used for diagnostics.  If POST_CB is not
670    NULL a post request is used and that callback is called to allow
671    writing the post data.  */
672 static gpg_error_t
673 send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
674               gpg_error_t (*post_cb)(void *, http_t), void *post_cb_value,
675               estream_t *r_fp)
676 {
677   gpg_error_t err;
678   http_t http = NULL;
679   int redirects_left = MAX_REDIRECTS;
680   estream_t fp = NULL;
681   char *request_buffer = NULL;
682
683   *r_fp = NULL;
684
685  once_more:
686   err = http_open (&http,
687                    post_cb? HTTP_REQ_POST : HTTP_REQ_GET,
688                    request,
689                    /* fixme: AUTH */ NULL,
690                    0,
691                    /* fixme: proxy*/ NULL,
692                    NULL, NULL,
693                    /*FIXME curl->srvtag*/NULL);
694   if (!err)
695     {
696       fp = http_get_write_ptr (http);
697       /* Avoid caches to get the most recent copy of the key.  We set
698          both the Pragma and Cache-Control versions of the header, so
699          we're good with both HTTP 1.0 and 1.1.  */
700       es_fputs ("Pragma: no-cache\r\n"
701                 "Cache-Control: no-cache\r\n", fp);
702       if (post_cb)
703         err = post_cb (post_cb_value, http);
704       if (!err)
705         {
706           http_start_data (http);
707           if (es_ferror (fp))
708             err = gpg_error_from_syserror ();
709         }
710     }
711   if (err)
712     {
713       /* Fixme: After a redirection we show the old host name.  */
714       log_error (_("error connecting to '%s': %s\n"),
715                  hostportstr, gpg_strerror (err));
716       goto leave;
717     }
718
719   /* Wait for the response.  */
720   dirmngr_tick (ctrl);
721   err = http_wait_response (http);
722   if (err)
723     {
724       log_error (_("error reading HTTP response for '%s': %s\n"),
725                  hostportstr, gpg_strerror (err));
726       goto leave;
727     }
728
729   switch (http_get_status_code (http))
730     {
731     case 200:
732       err = 0;
733       break; /* Success.  */
734
735     case 301:
736     case 302:
737       {
738         const char *s = http_get_header (http, "Location");
739
740         log_info (_("URL '%s' redirected to '%s' (%u)\n"),
741                   request, s?s:"[none]", http_get_status_code (http));
742         if (s && *s && redirects_left-- )
743           {
744             xfree (request_buffer);
745             request_buffer = xtrystrdup (s);
746             if (request_buffer)
747               {
748                 request = request_buffer;
749                 http_close (http, 0);
750                 http = NULL;
751                 goto once_more;
752               }
753             err = gpg_error_from_syserror ();
754           }
755         else
756           err = gpg_error (GPG_ERR_NO_DATA);
757         log_error (_("too many redirections\n"));
758       }
759       goto leave;
760
761     default:
762       log_error (_("error accessing '%s': http status %u\n"),
763                  request, http_get_status_code (http));
764       err = gpg_error (GPG_ERR_NO_DATA);
765       goto leave;
766     }
767
768   fp = http_get_read_ptr (http);
769   if (!fp)
770     {
771       err = gpg_error (GPG_ERR_BUG);
772       goto leave;
773     }
774
775   /* Return the read stream and close the HTTP context.  */
776   *r_fp = fp;
777   http_close (http, 1);
778   http = NULL;
779
780  leave:
781   http_close (http, 0);
782   xfree (request_buffer);
783   return err;
784 }
785
786
787 /* Helper to evaluate the error code ERR form a send_request() call
788    with REQUEST.  The function returns true if the caller shall try
789    again.  TRIES_LEFT points to a variable to track the number of
790    retries; this function decrements it and won't return true if it is
791    down to zero. */
792 static int
793 handle_send_request_error (gpg_error_t err, const char *request,
794                            unsigned int *tries_left)
795 {
796   int retry = 0;
797
798   switch (gpg_err_code (err))
799     {
800     case GPG_ERR_ECONNREFUSED:
801     case GPG_ERR_ENETUNREACH:
802       if (mark_host_dead (request) && *tries_left)
803         retry = 1;
804       break;
805
806     case GPG_ERR_ETIMEDOUT:
807       if (*tries_left)
808         {
809           log_info ("selecting a different host due to a timeout\n");
810           retry = 1;
811         }
812
813     default:
814       break;
815     }
816
817   if (*tries_left)
818     --*tries_left;
819
820   return retry;
821 }
822
823 static gpg_error_t
824 armor_data (char **r_string, const void *data, size_t datalen)
825 {
826   gpg_error_t err;
827   struct b64state b64state;
828   estream_t fp;
829   long length;
830   char *buffer;
831   size_t nread;
832
833   *r_string = NULL;
834
835   fp = es_fopenmem (0, "rw");
836   if (!fp)
837     return gpg_error_from_syserror ();
838
839   if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
840       || (err=b64enc_write (&b64state, data, datalen))
841       || (err = b64enc_finish (&b64state)))
842     {
843       es_fclose (fp);
844       return err;
845     }
846
847   /* FIXME: To avoid the extra buffer allocation estream should
848      provide a function to snatch the internal allocated memory from
849      such a memory stream.  */
850   length = es_ftell (fp);
851   if (length < 0)
852     {
853       err = gpg_error_from_syserror ();
854       es_fclose (fp);
855       return err;
856     }
857
858   buffer = xtrymalloc (length+1);
859   if (!buffer)
860     {
861       err = gpg_error_from_syserror ();
862       es_fclose (fp);
863       return err;
864     }
865
866   es_rewind (fp);
867   if (es_read (fp, buffer, length, &nread))
868     {
869       err = gpg_error_from_syserror ();
870       es_fclose (fp);
871       return err;
872     }
873   buffer[nread] = 0;
874   es_fclose (fp);
875
876   *r_string = buffer;
877   return 0;
878 }
879
880
881 \f
882 /* Search the keyserver identified by URI for keys matching PATTERN.
883    On success R_FP has an open stream to read the data.  */
884 gpg_error_t
885 ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
886                estream_t *r_fp)
887 {
888   gpg_error_t err;
889   KEYDB_SEARCH_DESC desc;
890   char fprbuf[2+40+1];
891   char *hostport = NULL;
892   char *request = NULL;
893   estream_t fp = NULL;
894   int reselect;
895   unsigned int tries = SEND_REQUEST_RETRIES;
896
897   *r_fp = NULL;
898
899   /* Remove search type indicator and adjust PATTERN accordingly.
900      Note that HKP keyservers like the 0x to be present when searching
901      by keyid.  We need to re-format the fingerprint and keyids so to
902      remove the gpg specific force-use-of-this-key flag ("!").  */
903   err = classify_user_id (pattern, &desc, 1);
904   if (err)
905     return err;
906   switch (desc.mode)
907     {
908     case KEYDB_SEARCH_MODE_EXACT:
909     case KEYDB_SEARCH_MODE_SUBSTR:
910     case KEYDB_SEARCH_MODE_MAIL:
911     case KEYDB_SEARCH_MODE_MAILSUB:
912       pattern = desc.u.name;
913       break;
914     case KEYDB_SEARCH_MODE_SHORT_KID:
915       snprintf (fprbuf, sizeof fprbuf, "0x%08lX", (ulong)desc.u.kid[1]);
916       pattern = fprbuf;
917       break;
918     case KEYDB_SEARCH_MODE_LONG_KID:
919       snprintf (fprbuf, sizeof fprbuf, "0x%08lX%08lX",
920                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
921       pattern = fprbuf;
922       break;
923     case KEYDB_SEARCH_MODE_FPR16:
924       bin2hex (desc.u.fpr, 16, fprbuf);
925       pattern = fprbuf;
926       break;
927     case KEYDB_SEARCH_MODE_FPR20:
928     case KEYDB_SEARCH_MODE_FPR:
929       bin2hex (desc.u.fpr, 20, fprbuf);
930       pattern = fprbuf;
931       break;
932     default:
933       return gpg_error (GPG_ERR_INV_USER_ID);
934     }
935
936   /* Build the request string.  */
937   reselect = 0;
938  again:
939   {
940     char *searchkey;
941
942     xfree (hostport);
943     hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port,
944                                reselect);
945     if (!hostport)
946       {
947         err = gpg_error_from_syserror ();
948         goto leave;
949       }
950
951     searchkey = http_escape_string (pattern, EXTRA_ESCAPE_CHARS);
952     if (!searchkey)
953       {
954         err = gpg_error_from_syserror ();
955         goto leave;
956       }
957
958     xfree (request);
959     request = strconcat (hostport,
960                          "/pks/lookup?op=index&options=mr&search=",
961                          searchkey,
962                          NULL);
963     xfree (searchkey);
964     if (!request)
965       {
966         err = gpg_error_from_syserror ();
967         goto leave;
968       }
969   }
970
971   /* Send the request.  */
972   err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
973   if (handle_send_request_error (err, request, &tries))
974     {
975       reselect = 1;
976       goto again;
977     }
978   if (err)
979     goto leave;
980
981   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
982   if (err)
983     goto leave;
984
985   /* Peek at the response.  */
986   {
987     int c = es_getc (fp);
988     if (c == -1)
989       {
990         err = es_ferror (fp)?gpg_error_from_syserror ():gpg_error (GPG_ERR_EOF);
991         log_error ("error reading response: %s\n", gpg_strerror (err));
992         goto leave;
993       }
994     if (c == '<')
995       {
996         /* The document begins with a '<': Assume a HTML response,
997            which we don't support.  */
998         err = gpg_error (GPG_ERR_UNSUPPORTED_ENCODING);
999         goto leave;
1000       }
1001     es_ungetc (c, fp);
1002   }
1003
1004   /* Return the read stream.  */
1005   *r_fp = fp;
1006   fp = NULL;
1007
1008  leave:
1009   es_fclose (fp);
1010   xfree (request);
1011   xfree (hostport);
1012   return err;
1013 }
1014
1015
1016 /* Get the key described key the KEYSPEC string from the keyserver
1017    identified by URI.  On success R_FP has an open stream to read the
1018    data.  */
1019 gpg_error_t
1020 ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
1021 {
1022   gpg_error_t err;
1023   KEYDB_SEARCH_DESC desc;
1024   char kidbuf[40+1];
1025   char *hostport = NULL;
1026   char *request = NULL;
1027   estream_t fp = NULL;
1028   int reselect;
1029   unsigned int tries = SEND_REQUEST_RETRIES;
1030
1031   *r_fp = NULL;
1032
1033   /* Remove search type indicator and adjust PATTERN accordingly.
1034      Note that HKP keyservers like the 0x to be present when searching
1035      by keyid.  We need to re-format the fingerprint and keyids so to
1036      remove the gpg specific force-use-of-this-key flag ("!").  */
1037   err = classify_user_id (keyspec, &desc, 1);
1038   if (err)
1039     return err;
1040   switch (desc.mode)
1041     {
1042     case KEYDB_SEARCH_MODE_SHORT_KID:
1043       snprintf (kidbuf, sizeof kidbuf, "%08lX", (ulong)desc.u.kid[1]);
1044       break;
1045     case KEYDB_SEARCH_MODE_LONG_KID:
1046       snprintf (kidbuf, sizeof kidbuf, "%08lX%08lX",
1047                 (ulong)desc.u.kid[0], (ulong)desc.u.kid[1]);
1048       break;
1049     case KEYDB_SEARCH_MODE_FPR20:
1050     case KEYDB_SEARCH_MODE_FPR:
1051       /* This is a v4 fingerprint. */
1052       bin2hex (desc.u.fpr, 20, kidbuf);
1053       break;
1054
1055     case KEYDB_SEARCH_MODE_FPR16:
1056       log_error ("HKP keyservers do not support v3 fingerprints\n");
1057     default:
1058       return gpg_error (GPG_ERR_INV_USER_ID);
1059     }
1060
1061   reselect = 0;
1062  again:
1063   /* Build the request string.  */
1064   xfree (hostport);
1065   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect);
1066   if (!hostport)
1067     {
1068       err = gpg_error_from_syserror ();
1069       goto leave;
1070     }
1071
1072   xfree (request);
1073   request = strconcat (hostport,
1074                        "/pks/lookup?op=get&options=mr&search=0x",
1075                        kidbuf,
1076                        NULL);
1077   if (!request)
1078     {
1079       err = gpg_error_from_syserror ();
1080       goto leave;
1081     }
1082
1083   /* Send the request.  */
1084   err = send_request (ctrl, request, hostport, NULL, NULL, &fp);
1085   if (handle_send_request_error (err, request, &tries))
1086     {
1087       reselect = 1;
1088       goto again;
1089     }
1090   if (err)
1091     goto leave;
1092
1093   err = dirmngr_status (ctrl, "SOURCE", hostport, NULL);
1094   if (err)
1095     goto leave;
1096
1097   /* Return the read stream and close the HTTP context.  */
1098   *r_fp = fp;
1099   fp = NULL;
1100
1101  leave:
1102   es_fclose (fp);
1103   xfree (request);
1104   xfree (hostport);
1105   return err;
1106 }
1107
1108
1109
1110 \f
1111 /* Callback parameters for put_post_cb.  */
1112 struct put_post_parm_s
1113 {
1114   char *datastring;
1115 };
1116
1117
1118 /* Helper for ks_hkp_put.  */
1119 static gpg_error_t
1120 put_post_cb (void *opaque, http_t http)
1121 {
1122   struct put_post_parm_s *parm = opaque;
1123   gpg_error_t err = 0;
1124   estream_t fp;
1125   size_t len;
1126
1127   fp = http_get_write_ptr (http);
1128   len = strlen (parm->datastring);
1129
1130   es_fprintf (fp,
1131               "Content-Type: application/x-www-form-urlencoded\r\n"
1132               "Content-Length: %zu\r\n", len+8 /* 8 is for "keytext" */);
1133   http_start_data (http);
1134   if (es_fputs ("keytext=", fp) || es_write (fp, parm->datastring, len, NULL))
1135     err = gpg_error_from_syserror ();
1136   return err;
1137 }
1138
1139
1140 /* Send the key in {DATA,DATALEN} to the keyserver identified by  URI.  */
1141 gpg_error_t
1142 ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
1143 {
1144   gpg_error_t err;
1145   char *hostport = NULL;
1146   char *request = NULL;
1147   estream_t fp = NULL;
1148   struct put_post_parm_s parm;
1149   char *armored = NULL;
1150   int reselect;
1151   unsigned int tries = SEND_REQUEST_RETRIES;
1152
1153   parm.datastring = NULL;
1154
1155   err = armor_data (&armored, data, datalen);
1156   if (err)
1157     goto leave;
1158
1159   parm.datastring = http_escape_string (armored, EXTRA_ESCAPE_CHARS);
1160   if (!parm.datastring)
1161     {
1162       err = gpg_error_from_syserror ();
1163       goto leave;
1164     }
1165   xfree (armored);
1166   armored = NULL;
1167
1168   /* Build the request string.  */
1169   reselect = 0;
1170  again:
1171   xfree (hostport);
1172   hostport = make_host_part (ctrl, uri->scheme, uri->host, uri->port, reselect);
1173   if (!hostport)
1174     {
1175       err = gpg_error_from_syserror ();
1176       goto leave;
1177     }
1178
1179   xfree (request);
1180   request = strconcat (hostport, "/pks/add", NULL);
1181   if (!request)
1182     {
1183       err = gpg_error_from_syserror ();
1184       goto leave;
1185     }
1186
1187   /* Send the request.  */
1188   err = send_request (ctrl, request, hostport, put_post_cb, &parm, &fp);
1189   if (handle_send_request_error (err, request, &tries))
1190     {
1191       reselect = 1;
1192       goto again;
1193     }
1194   if (err)
1195     goto leave;
1196
1197  leave:
1198   es_fclose (fp);
1199   xfree (parm.datastring);
1200   xfree (armored);
1201   xfree (request);
1202   xfree (hostport);
1203   return err;
1204 }