Line data Source code
1 : /* http.c - HTTP protocol handler
2 : * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
3 : * 2011 Free Software Foundation, Inc.
4 : * Copyright (C) 2014 Werner Koch
5 : * Copyright (C) 2015 g10 Code GmbH
6 : *
7 : * This file is part of GnuPG.
8 : *
9 : * This file is free software; you can redistribute it and/or modify
10 : * it under the terms of either
11 : *
12 : * - the GNU Lesser General Public License as published by the Free
13 : * Software Foundation; either version 3 of the License, or (at
14 : * your option) any later version.
15 : *
16 : * or
17 : *
18 : * - the GNU General Public License as published by the Free
19 : * Software Foundation; either version 2 of the License, or (at
20 : * your option) any later version.
21 : *
22 : * or both in parallel, as here.
23 : *
24 : * This file is distributed in the hope that it will be useful,
25 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 : * GNU General Public License for more details.
28 : *
29 : * You should have received a copy of the GNU General Public License
30 : * along with this program; if not, see <https://www.gnu.org/licenses/>.
31 : */
32 :
33 : /* Simple HTTP client implementation. We try to keep the code as
34 : self-contained as possible. There are some contraints however:
35 :
36 : - estream is required. We now require estream because it provides a
37 : very useful and portable asprintf implementation and the fopencookie
38 : function.
39 : - stpcpy is required
40 : - fixme: list other requirements.
41 :
42 :
43 : - With HTTP_USE_NTBTLS or HTTP_USE_GNUTLS support for https is
44 : provided (this also requires estream).
45 :
46 : - With HTTP_NO_WSASTARTUP the socket initialization is not done
47 : under Windows. This is useful if the socket layer has already
48 : been initialized elsewhere. This also avoids the installation of
49 : an exit handler to cleanup the socket layer.
50 : */
51 :
52 : #ifdef HAVE_CONFIG_H
53 : # include <config.h>
54 : #endif
55 : #include <stdio.h>
56 : #include <stdlib.h>
57 : #include <stdarg.h>
58 : #include <string.h>
59 : #include <ctype.h>
60 : #include <errno.h>
61 : #include <unistd.h>
62 :
63 : #ifdef HAVE_W32_SYSTEM
64 : # ifdef HAVE_WINSOCK2_H
65 : # include <winsock2.h>
66 : # endif
67 : # include <windows.h>
68 : #else /*!HAVE_W32_SYSTEM*/
69 : # include <sys/types.h>
70 : # include <sys/socket.h>
71 : # include <sys/time.h>
72 : # include <time.h>
73 : # include <netinet/in.h>
74 : # include <arpa/inet.h>
75 : # include <netdb.h>
76 : #endif /*!HAVE_W32_SYSTEM*/
77 :
78 : #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
79 : # undef USE_NPTH
80 : #endif
81 :
82 : #ifdef USE_NPTH
83 : # include <npth.h>
84 : #endif
85 :
86 : #if defined (HTTP_USE_GNUTLS) && defined (HTTP_USE_NTBTLS)
87 : # error Both, HTTP_USE_GNUTLS and HTTP_USE_NTBTLS, are defined.
88 : #endif
89 :
90 : #ifdef HTTP_USE_NTBTLS
91 : # include <ntbtls.h>
92 : #elif HTTP_USE_GNUTLS
93 : # include <gnutls/gnutls.h>
94 : # include <gnutls/x509.h>
95 : #endif /*HTTP_USE_GNUTLS*/
96 :
97 : #include <assuan.h> /* We need the socket wrapper. */
98 :
99 : #include "util.h"
100 : #include "i18n.h"
101 : #include "dns-stuff.h"
102 : #include "http.h"
103 :
104 :
105 : #ifdef USE_NPTH
106 : # define my_select(a,b,c,d,e) npth_select ((a), (b), (c), (d), (e))
107 : # define my_accept(a,b,c) npth_accept ((a), (b), (c))
108 : #else
109 : # define my_select(a,b,c,d,e) select ((a), (b), (c), (d), (e))
110 : # define my_accept(a,b,c) accept ((a), (b), (c))
111 : #endif
112 :
113 : #ifdef HAVE_W32_SYSTEM
114 : #define sock_close(a) closesocket(a)
115 : #else
116 : #define sock_close(a) close(a)
117 : #endif
118 :
119 : #ifndef EAGAIN
120 : #define EAGAIN EWOULDBLOCK
121 : #endif
122 : #ifndef INADDR_NONE /* Slowaris is missing that. */
123 : #define INADDR_NONE ((unsigned long)(-1))
124 : #endif /*INADDR_NONE*/
125 :
126 : #define HTTP_PROXY_ENV "http_proxy"
127 : #define MAX_LINELEN 20000 /* Max. length of a HTTP header line. */
128 : #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \
129 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
130 : "01234567890@" \
131 : "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
132 :
133 : #if HTTP_USE_NTBTLS
134 : typedef ntbtls_t tls_session_t;
135 : # define USE_TLS 1
136 : #elif HTTP_USE_GNUTLS
137 : typedef gnutls_session_t tls_session_t;
138 : # define USE_TLS 1
139 : #else
140 : typedef void *tls_session_t;
141 : # undef USE_TLS
142 : #endif
143 :
144 : static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part,
145 : int no_scheme_check, int force_tls);
146 : static gpg_error_t parse_uri (parsed_uri_t *ret_uri, const char *uri,
147 : int no_scheme_check, int force_tls);
148 : static int remove_escapes (char *string);
149 : static int insert_escapes (char *buffer, const char *string,
150 : const char *special);
151 : static uri_tuple_t parse_tuple (char *string);
152 : static gpg_error_t send_request (http_t hd, const char *httphost,
153 : const char *auth,const char *proxy,
154 : const char *srvtag,strlist_t headers);
155 : static char *build_rel_path (parsed_uri_t uri);
156 : static gpg_error_t parse_response (http_t hd);
157 :
158 : static assuan_fd_t connect_server (const char *server, unsigned short port,
159 : unsigned int flags, const char *srvtag,
160 : int *r_host_not_found);
161 : static gpg_error_t write_server (int sock, const char *data, size_t length);
162 :
163 : static gpgrt_ssize_t cookie_read (void *cookie, void *buffer, size_t size);
164 : static gpgrt_ssize_t cookie_write (void *cookie,
165 : const void *buffer, size_t size);
166 : static int cookie_close (void *cookie);
167 :
168 :
169 : /* A socket object used to a allow ref counting of sockets. */
170 : struct my_socket_s
171 : {
172 : assuan_fd_t fd; /* The actual socket - shall never be ASSUAN_INVALID_FD. */
173 : int refcount; /* Number of references to this socket. */
174 : };
175 : typedef struct my_socket_s *my_socket_t;
176 :
177 :
178 : /* Cookie function structure and cookie object. */
179 : static es_cookie_io_functions_t cookie_functions =
180 : {
181 : cookie_read,
182 : cookie_write,
183 : NULL,
184 : cookie_close
185 : };
186 :
187 : struct cookie_s
188 : {
189 : /* Socket object or NULL if already closed. */
190 : my_socket_t sock;
191 :
192 : /* The session object or NULL if not used. */
193 : http_session_t session;
194 :
195 : /* True if TLS is to be used. */
196 : int use_tls;
197 :
198 : /* The remaining content length and a flag telling whether to use
199 : the content length. */
200 : uint64_t content_length;
201 : unsigned int content_length_valid:1;
202 : };
203 : typedef struct cookie_s *cookie_t;
204 :
205 : /* The session object. */
206 : struct http_session_s
207 : {
208 : int refcount; /* Number of references to this object. */
209 : #ifdef HTTP_USE_GNUTLS
210 : gnutls_certificate_credentials_t certcred;
211 : #endif /*HTTP_USE_GNUTLS*/
212 : #ifdef USE_TLS
213 : tls_session_t tls_session;
214 : struct {
215 : int done; /* Verifciation has been done. */
216 : int rc; /* TLS verification return code. */
217 : unsigned int status; /* Verification status. */
218 : } verify;
219 : char *servername; /* Malloced server name. */
220 : #endif /*USE_TLS*/
221 : /* A callback function to log details of TLS certifciates. */
222 : void (*cert_log_cb) (http_session_t, gpg_error_t, const char *,
223 : const void **, size_t *);
224 : };
225 :
226 :
227 : /* An object to save header lines. */
228 : struct header_s
229 : {
230 : struct header_s *next;
231 : char *value; /* The value of the header (malloced). */
232 : char name[1]; /* The name of the header (canonicalized). */
233 : };
234 : typedef struct header_s *header_t;
235 :
236 :
237 : /* Our handle context. */
238 : struct http_context_s
239 : {
240 : unsigned int status_code;
241 : my_socket_t sock;
242 : unsigned int in_data:1;
243 : unsigned int is_http_0_9:1;
244 : estream_t fp_read;
245 : estream_t fp_write;
246 : void *write_cookie;
247 : void *read_cookie;
248 : http_session_t session;
249 : parsed_uri_t uri;
250 : http_req_t req_type;
251 : char *buffer; /* Line buffer. */
252 : size_t buffer_size;
253 : unsigned int flags;
254 : header_t headers; /* Received headers. */
255 : };
256 :
257 :
258 : /* The global callback for the verification function. */
259 : static gpg_error_t (*tls_callback) (http_t, http_session_t, int);
260 :
261 : /* The list of files with trusted CA certificates. */
262 : static strlist_t tls_ca_certlist;
263 :
264 : /* The global callback for net activity. */
265 : static void (*netactivity_cb)(void);
266 :
267 :
268 :
269 : #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
270 :
271 : #if GNUPG_MAJOR_VERSION == 1
272 : #define REQ_WINSOCK_MAJOR 1
273 : #define REQ_WINSOCK_MINOR 1
274 : #else
275 : #define REQ_WINSOCK_MAJOR 2
276 : #define REQ_WINSOCK_MINOR 2
277 : #endif
278 :
279 :
280 : static void
281 : deinit_sockets (void)
282 : {
283 : WSACleanup();
284 : }
285 :
286 : static void
287 : init_sockets (void)
288 : {
289 : static int initialized;
290 : static WSADATA wsdata;
291 :
292 : if (initialized)
293 : return;
294 :
295 : if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) )
296 : {
297 : log_error ("error initializing socket library: ec=%d\n",
298 : (int)WSAGetLastError () );
299 : return;
300 : }
301 : if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR
302 : || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR )
303 : {
304 : log_error ("socket library version is %x.%x - but %d.%d needed\n",
305 : LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion),
306 : REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR);
307 : WSACleanup();
308 : return;
309 : }
310 : atexit ( deinit_sockets );
311 : initialized = 1;
312 : }
313 : #endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/
314 :
315 :
316 : /* Create a new socket object. Returns NULL and closes FD if not
317 : enough memory is available. */
318 : static my_socket_t
319 0 : _my_socket_new (int lnr, assuan_fd_t fd)
320 : {
321 : my_socket_t so;
322 :
323 0 : so = xtrymalloc (sizeof *so);
324 0 : if (!so)
325 : {
326 0 : int save_errno = errno;
327 0 : assuan_sock_close (fd);
328 0 : gpg_err_set_errno (save_errno);
329 0 : return NULL;
330 : }
331 0 : so->fd = fd;
332 0 : so->refcount = 1;
333 : /* log_debug ("http.c:socket_new(%d): object %p for fd %d created\n", */
334 : /* lnr, so, so->fd); */
335 : (void)lnr;
336 0 : return so;
337 : }
338 : #define my_socket_new(a) _my_socket_new (__LINE__, (a))
339 :
340 : /* Bump up the reference counter for the socket object SO. */
341 : static my_socket_t
342 0 : _my_socket_ref (int lnr, my_socket_t so)
343 : {
344 0 : so->refcount++;
345 : /* log_debug ("http.c:socket_ref(%d) object %p for fd %d refcount now %d\n", */
346 : /* lnr, so, so->fd, so->refcount); */
347 : (void)lnr;
348 0 : return so;
349 : }
350 : #define my_socket_ref(a) _my_socket_ref (__LINE__,(a))
351 :
352 :
353 : /* Bump down the reference counter for the socket object SO. If SO
354 : has no more references, close the socket and release the
355 : object. */
356 : static void
357 0 : _my_socket_unref (int lnr, my_socket_t so,
358 : void (*preclose)(void*), void *preclosearg)
359 : {
360 0 : if (so)
361 : {
362 0 : so->refcount--;
363 : /* log_debug ("http.c:socket_unref(%d): object %p for fd %d ref now %d\n", */
364 : /* lnr, so, so->fd, so->refcount); */
365 : (void)lnr;
366 0 : if (!so->refcount)
367 : {
368 0 : if (preclose)
369 0 : preclose (preclosearg);
370 0 : assuan_sock_close (so->fd);
371 0 : xfree (so);
372 : }
373 : }
374 0 : }
375 : #define my_socket_unref(a,b,c) _my_socket_unref (__LINE__,(a),(b),(c))
376 :
377 :
378 : #ifdef HTTP_USE_GNUTLS
379 : static ssize_t
380 0 : my_gnutls_read (gnutls_transport_ptr_t ptr, void *buffer, size_t size)
381 : {
382 0 : my_socket_t sock = ptr;
383 : #if USE_NPTH
384 0 : return npth_read (sock->fd, buffer, size);
385 : #else
386 0 : return read (sock->fd, buffer, size);
387 : #endif
388 : }
389 : static ssize_t
390 0 : my_gnutls_write (gnutls_transport_ptr_t ptr, const void *buffer, size_t size)
391 : {
392 0 : my_socket_t sock = ptr;
393 : #if USE_NPTH
394 0 : return npth_write (sock->fd, buffer, size);
395 : #else
396 0 : return write (sock->fd, buffer, size);
397 : #endif
398 : }
399 : #endif /*HTTP_USE_GNUTLS*/
400 :
401 :
402 :
403 :
404 : /* This notification function is called by estream whenever stream is
405 : closed. Its purpose is to mark the closing in the handle so
406 : that a http_close won't accidentally close the estream. The function
407 : http_close removes this notification so that it won't be called if
408 : http_close was used before an es_fclose. */
409 : static void
410 0 : fp_onclose_notification (estream_t stream, void *opaque)
411 : {
412 0 : http_t hd = opaque;
413 :
414 0 : if (hd->fp_read && hd->fp_read == stream)
415 0 : hd->fp_read = NULL;
416 0 : else if (hd->fp_write && hd->fp_write == stream)
417 0 : hd->fp_write = NULL;
418 0 : }
419 :
420 :
421 : /*
422 : * Helper function to create an HTTP header with hex encoded data. A
423 : * new buffer is returned. This buffer is the concatenation of the
424 : * string PREFIX, the hex-encoded DATA of length LEN and the string
425 : * SUFFIX. On error NULL is returned and ERRNO set.
426 : */
427 : static char *
428 0 : make_header_line (const char *prefix, const char *suffix,
429 : const void *data, size_t len )
430 : {
431 : static unsigned char bintoasc[] =
432 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
433 : "abcdefghijklmnopqrstuvwxyz"
434 : "0123456789+/";
435 0 : const unsigned char *s = data;
436 : char *buffer, *p;
437 :
438 0 : buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1);
439 0 : if (!buffer)
440 0 : return NULL;
441 0 : p = stpcpy (buffer, prefix);
442 0 : for ( ; len >= 3 ; len -= 3, s += 3 )
443 : {
444 0 : *p++ = bintoasc[(s[0] >> 2) & 077];
445 0 : *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
446 0 : *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077];
447 0 : *p++ = bintoasc[s[2]&077];
448 0 : *p = 0;
449 : }
450 0 : if ( len == 2 )
451 : {
452 0 : *p++ = bintoasc[(s[0] >> 2) & 077];
453 0 : *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077];
454 0 : *p++ = bintoasc[((s[1]<<2)&074)];
455 0 : *p++ = '=';
456 : }
457 0 : else if ( len == 1 )
458 : {
459 0 : *p++ = bintoasc[(s[0] >> 2) & 077];
460 0 : *p++ = bintoasc[(s[0] <<4)&060];
461 0 : *p++ = '=';
462 0 : *p++ = '=';
463 : }
464 0 : *p = 0;
465 0 : strcpy (p, suffix);
466 0 : return buffer;
467 : }
468 :
469 :
470 :
471 :
472 : /* Register a non-standard global TLS callback function. If no
473 : verification is desired a callback needs to be registered which
474 : always returns NULL. */
475 : void
476 0 : http_register_tls_callback (gpg_error_t (*cb)(http_t, http_session_t, int))
477 : {
478 0 : tls_callback = cb;
479 0 : }
480 :
481 :
482 : /* Register a CA certificate for future use. The certificate is
483 : expected to be in FNAME. PEM format is assume if FNAME has a
484 : suffix of ".pem". If FNAME is NULL the list of CA files is
485 : removed. */
486 : void
487 0 : http_register_tls_ca (const char *fname)
488 : {
489 : strlist_t sl;
490 :
491 0 : if (!fname)
492 : {
493 0 : free_strlist (tls_ca_certlist);
494 0 : tls_ca_certlist = NULL;
495 : }
496 : else
497 : {
498 : /* Warn if we can't access right now, but register it anyway in
499 : case it becomes accessible later */
500 0 : if (access (fname, F_OK))
501 0 : log_info (_("can't access '%s': %s\n"), fname,
502 : gpg_strerror (gpg_error_from_syserror()));
503 0 : sl = add_to_strlist (&tls_ca_certlist, fname);
504 0 : if (*sl->d && !strcmp (sl->d + strlen (sl->d) - 4, ".pem"))
505 0 : sl->flags = 1;
506 : }
507 0 : }
508 :
509 :
510 : /* Register a callback which is called every time the HTTP mode has
511 : * made a successful connection to some server. */
512 : void
513 0 : http_register_netactivity_cb (void (*cb)(void))
514 : {
515 0 : netactivity_cb = cb;
516 0 : }
517 :
518 :
519 : /* Call the netactivity callback if any. */
520 : static void
521 0 : notify_netactivity (void)
522 : {
523 0 : if (netactivity_cb)
524 0 : netactivity_cb ();
525 0 : }
526 :
527 :
528 :
529 : #ifdef USE_TLS
530 : /* Free the TLS session associated with SESS, if any. */
531 : static void
532 0 : close_tls_session (http_session_t sess)
533 : {
534 0 : if (sess->tls_session)
535 : {
536 : # ifdef HTTP_USE_GNUTLS
537 0 : my_socket_t sock = gnutls_transport_get_ptr (sess->tls_session);
538 0 : my_socket_unref (sock, NULL, NULL);
539 0 : gnutls_deinit (sess->tls_session);
540 0 : if (sess->certcred)
541 0 : gnutls_certificate_free_credentials (sess->certcred);
542 : # endif /*HTTP_USE_GNUTLS*/
543 0 : xfree (sess->servername);
544 0 : sess->tls_session = NULL;
545 : }
546 0 : }
547 : #endif /*USE_TLS*/
548 :
549 :
550 : /* Release a session. Take care not to release it while it is being
551 : used by a http context object. */
552 : static void
553 0 : session_unref (int lnr, http_session_t sess)
554 : {
555 0 : if (!sess)
556 0 : return;
557 :
558 0 : sess->refcount--;
559 : /* log_debug ("http.c:session_unref(%d): sess %p ref now %d\n", */
560 : /* lnr, sess, sess->refcount); */
561 : (void)lnr;
562 0 : if (sess->refcount)
563 0 : return;
564 :
565 : #ifdef USE_TLS
566 0 : close_tls_session (sess);
567 : #endif /*USE_TLS*/
568 :
569 0 : xfree (sess);
570 : }
571 : #define http_session_unref(a) session_unref (__LINE__, (a))
572 :
573 : void
574 0 : http_session_release (http_session_t sess)
575 : {
576 0 : http_session_unref (sess);
577 0 : }
578 :
579 :
580 : /* Create a new session object which is currently used to enable TLS
581 : * support. It may eventually allow reusing existing connections.
582 : * Valid values for FLAGS are:
583 : * HTTP_FLAG_TRUST_DEF - Use the CAs set with http_register_tls_ca
584 : * HTTP_FLAG_TRUST_SYS - Also use the CAs defined by the system
585 : */
586 : gpg_error_t
587 0 : http_session_new (http_session_t *r_session, const char *tls_priority,
588 : const char *intended_hostname, unsigned int flags)
589 : {
590 : gpg_error_t err;
591 : http_session_t sess;
592 :
593 0 : *r_session = NULL;
594 :
595 0 : sess = xtrycalloc (1, sizeof *sess);
596 0 : if (!sess)
597 0 : return gpg_error_from_syserror ();
598 0 : sess->refcount = 1;
599 :
600 : #if HTTP_USE_NTBTLS
601 : {
602 : (void)tls_priority;
603 :
604 : err = ntbtls_new (&sess->tls_session, NTBTLS_CLIENT);
605 : if (err)
606 : {
607 : log_error ("ntbtls_new failed: %s\n", gpg_strerror (err));
608 : goto leave;
609 : }
610 : }
611 : #elif HTTP_USE_GNUTLS
612 : {
613 : const char *errpos;
614 : int rc;
615 : strlist_t sl;
616 0 : int add_system_cas = !!(flags & HTTP_FLAG_TRUST_SYS);
617 : int is_hkps_pool;
618 :
619 0 : rc = gnutls_certificate_allocate_credentials (&sess->certcred);
620 0 : if (rc < 0)
621 : {
622 0 : log_error ("gnutls_certificate_allocate_credentials failed: %s\n",
623 : gnutls_strerror (rc));
624 0 : err = gpg_error (GPG_ERR_GENERAL);
625 0 : goto leave;
626 : }
627 :
628 0 : is_hkps_pool = (intended_hostname
629 0 : && !ascii_strcasecmp (intended_hostname,
630 : "hkps.pool.sks-keyservers.net"));
631 :
632 : /* If the user has not specified a CA list, and they are looking
633 : * for the hkps pool from sks-keyservers.net, then default to
634 : * Kristian's certificate authority: */
635 0 : if (!tls_ca_certlist && is_hkps_pool)
636 : {
637 0 : char *pemname = make_filename_try (gnupg_datadir (),
638 : "sks-keyservers.netCA.pem", NULL);
639 0 : if (!pemname)
640 : {
641 0 : err = gpg_error_from_syserror ();
642 0 : log_error ("setting CA from file '%s' failed: %s\n",
643 : pemname, gpg_strerror (err));
644 : }
645 : else
646 : {
647 0 : rc = gnutls_certificate_set_x509_trust_file
648 : (sess->certcred, pemname, GNUTLS_X509_FMT_PEM);
649 0 : if (rc < 0)
650 0 : log_info ("setting CA from file '%s' failed: %s\n",
651 : pemname, gnutls_strerror (rc));
652 0 : xfree (pemname);
653 : }
654 : }
655 :
656 : /* Add configured certificates to the session. */
657 0 : if ((flags & HTTP_FLAG_TRUST_DEF))
658 : {
659 0 : for (sl = tls_ca_certlist; sl; sl = sl->next)
660 : {
661 0 : rc = gnutls_certificate_set_x509_trust_file
662 0 : (sess->certcred, sl->d,
663 0 : (sl->flags & 1)? GNUTLS_X509_FMT_PEM : GNUTLS_X509_FMT_DER);
664 0 : if (rc < 0)
665 0 : log_info ("setting CA from file '%s' failed: %s\n",
666 0 : sl->d, gnutls_strerror (rc));
667 : }
668 0 : if (!tls_ca_certlist && !is_hkps_pool)
669 0 : add_system_cas = 1;
670 : }
671 :
672 : /* Add system certificates to the session. */
673 0 : if (add_system_cas)
674 : {
675 : #if GNUTLS_VERSION_NUMBER >= 0x030014
676 : static int shown;
677 :
678 0 : rc = gnutls_certificate_set_x509_system_trust (sess->certcred);
679 0 : if (rc < 0)
680 0 : log_info ("setting system CAs failed: %s\n", gnutls_strerror (rc));
681 0 : else if (!shown)
682 : {
683 0 : shown = 1;
684 0 : log_info ("number of system provided CAs: %d\n", rc);
685 : }
686 : #endif /* gnutls >= 3.0.20 */
687 : }
688 :
689 0 : rc = gnutls_init (&sess->tls_session, GNUTLS_CLIENT);
690 0 : if (rc < 0)
691 : {
692 0 : log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc));
693 0 : err = gpg_error (GPG_ERR_GENERAL);
694 0 : goto leave;
695 : }
696 : /* A new session has the transport ptr set to (void*(-1), we need
697 : it to be NULL. */
698 0 : gnutls_transport_set_ptr (sess->tls_session, NULL);
699 :
700 0 : rc = gnutls_priority_set_direct (sess->tls_session,
701 : tls_priority? tls_priority : "NORMAL",
702 : &errpos);
703 0 : if (rc < 0)
704 : {
705 0 : log_error ("gnutls_priority_set_direct failed at '%s': %s\n",
706 : errpos, gnutls_strerror (rc));
707 0 : err = gpg_error (GPG_ERR_GENERAL);
708 0 : goto leave;
709 : }
710 :
711 0 : rc = gnutls_credentials_set (sess->tls_session,
712 0 : GNUTLS_CRD_CERTIFICATE, sess->certcred);
713 0 : if (rc < 0)
714 : {
715 0 : log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc));
716 0 : err = gpg_error (GPG_ERR_GENERAL);
717 0 : goto leave;
718 : }
719 : }
720 : #else /*!HTTP_USE_GNUTLS*/
721 : {
722 : (void)tls_priority;
723 : }
724 : #endif /*!HTTP_USE_GNUTLS*/
725 :
726 : /* log_debug ("http.c:session_new: sess %p created\n", sess); */
727 0 : err = 0;
728 :
729 : #if USE_TLS
730 : leave:
731 : #endif /*USE_TLS*/
732 0 : if (err)
733 0 : http_session_unref (sess);
734 : else
735 0 : *r_session = sess;
736 :
737 0 : return err;
738 : }
739 :
740 :
741 : /* Increment the reference count for session SESS. Passing NULL for
742 : SESS is allowed. */
743 : http_session_t
744 0 : http_session_ref (http_session_t sess)
745 : {
746 0 : if (sess)
747 : {
748 0 : sess->refcount++;
749 : /* log_debug ("http.c:session_ref: sess %p ref now %d\n", sess, */
750 : /* sess->refcount); */
751 : }
752 0 : return sess;
753 : }
754 :
755 :
756 : void
757 0 : http_session_set_log_cb (http_session_t sess,
758 : void (*cb)(http_session_t, gpg_error_t,
759 : const char *hostname,
760 : const void **certs, size_t *certlens))
761 : {
762 0 : sess->cert_log_cb = cb;
763 0 : }
764 :
765 :
766 :
767 :
768 : /* Start a HTTP retrieval and on success store at R_HD a context
769 : pointer for completing the request and to wait for the response.
770 : If HTTPHOST is not NULL it is used for the Host header instead of a
771 : Host header derived from the URL. */
772 : gpg_error_t
773 0 : http_open (http_t *r_hd, http_req_t reqtype, const char *url,
774 : const char *httphost,
775 : const char *auth, unsigned int flags, const char *proxy,
776 : http_session_t session, const char *srvtag, strlist_t headers)
777 : {
778 : gpg_error_t err;
779 : http_t hd;
780 :
781 0 : *r_hd = NULL;
782 :
783 0 : if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST))
784 0 : return gpg_err_make (default_errsource, GPG_ERR_INV_ARG);
785 :
786 : /* Create the handle. */
787 0 : hd = xtrycalloc (1, sizeof *hd);
788 0 : if (!hd)
789 0 : return gpg_error_from_syserror ();
790 0 : hd->req_type = reqtype;
791 0 : hd->flags = flags;
792 0 : hd->session = http_session_ref (session);
793 :
794 0 : err = parse_uri (&hd->uri, url, 0, !!(flags & HTTP_FLAG_FORCE_TLS));
795 0 : if (!err)
796 0 : err = send_request (hd, httphost, auth, proxy, srvtag, headers);
797 :
798 0 : if (err)
799 : {
800 0 : my_socket_unref (hd->sock, NULL, NULL);
801 0 : if (hd->fp_read)
802 0 : es_fclose (hd->fp_read);
803 0 : if (hd->fp_write)
804 0 : es_fclose (hd->fp_write);
805 0 : http_session_unref (hd->session);
806 0 : xfree (hd);
807 : }
808 : else
809 0 : *r_hd = hd;
810 0 : return err;
811 : }
812 :
813 :
814 : /* This function is useful to connect to a generic TCP service using
815 : this http abstraction layer. This has the advantage of providing
816 : service tags and an estream interface. */
817 : gpg_error_t
818 0 : http_raw_connect (http_t *r_hd, const char *server, unsigned short port,
819 : unsigned int flags, const char *srvtag)
820 : {
821 0 : gpg_error_t err = 0;
822 : http_t hd;
823 : cookie_t cookie;
824 : int hnf;
825 :
826 0 : *r_hd = NULL;
827 :
828 0 : if ((flags & HTTP_FLAG_FORCE_TOR))
829 : {
830 : int mode;
831 :
832 0 : if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
833 : {
834 0 : log_error ("Tor support is not available\n");
835 0 : return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
836 : }
837 : }
838 :
839 : /* Create the handle. */
840 0 : hd = xtrycalloc (1, sizeof *hd);
841 0 : if (!hd)
842 0 : return gpg_error_from_syserror ();
843 0 : hd->req_type = HTTP_REQ_OPAQUE;
844 0 : hd->flags = flags;
845 :
846 : /* Connect. */
847 : {
848 : assuan_fd_t sock;
849 :
850 0 : sock = connect_server (server, port, hd->flags, srvtag, &hnf);
851 0 : if (sock == ASSUAN_INVALID_FD)
852 : {
853 0 : err = gpg_err_make (default_errsource,
854 0 : (hnf? GPG_ERR_UNKNOWN_HOST
855 : : gpg_err_code_from_syserror ()));
856 0 : xfree (hd);
857 0 : return err;
858 : }
859 0 : hd->sock = my_socket_new (sock);
860 0 : if (!hd->sock)
861 : {
862 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
863 0 : xfree (hd);
864 0 : return err;
865 : }
866 : }
867 :
868 : /* Setup estreams for reading and writing. */
869 0 : cookie = xtrycalloc (1, sizeof *cookie);
870 0 : if (!cookie)
871 : {
872 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
873 0 : goto leave;
874 : }
875 0 : cookie->sock = my_socket_ref (hd->sock);
876 0 : hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
877 0 : if (!hd->fp_write)
878 : {
879 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
880 0 : my_socket_unref (cookie->sock, NULL, NULL);
881 0 : xfree (cookie);
882 0 : goto leave;
883 : }
884 0 : hd->write_cookie = cookie; /* Cookie now owned by FP_WRITE. */
885 :
886 0 : cookie = xtrycalloc (1, sizeof *cookie);
887 0 : if (!cookie)
888 : {
889 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
890 0 : goto leave;
891 : }
892 0 : cookie->sock = my_socket_ref (hd->sock);
893 0 : hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
894 0 : if (!hd->fp_read)
895 : {
896 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
897 0 : my_socket_unref (cookie->sock, NULL, NULL);
898 0 : xfree (cookie);
899 0 : goto leave;
900 : }
901 0 : hd->read_cookie = cookie; /* Cookie now owned by FP_READ. */
902 :
903 : /* Register close notification to interlock the use of es_fclose in
904 : http_close and in user code. */
905 0 : err = es_onclose (hd->fp_write, 1, fp_onclose_notification, hd);
906 0 : if (!err)
907 0 : err = es_onclose (hd->fp_read, 1, fp_onclose_notification, hd);
908 :
909 : leave:
910 0 : if (err)
911 : {
912 0 : if (hd->fp_read)
913 0 : es_fclose (hd->fp_read);
914 0 : if (hd->fp_write)
915 0 : es_fclose (hd->fp_write);
916 0 : my_socket_unref (hd->sock, NULL, NULL);
917 0 : xfree (hd);
918 : }
919 : else
920 0 : *r_hd = hd;
921 0 : return err;
922 : }
923 :
924 :
925 :
926 :
927 : void
928 0 : http_start_data (http_t hd)
929 : {
930 0 : if (!hd->in_data)
931 : {
932 0 : es_fputs ("\r\n", hd->fp_write);
933 0 : es_fflush (hd->fp_write);
934 0 : hd->in_data = 1;
935 : }
936 : else
937 0 : es_fflush (hd->fp_write);
938 0 : }
939 :
940 :
941 : gpg_error_t
942 0 : http_wait_response (http_t hd)
943 : {
944 : gpg_error_t err;
945 : cookie_t cookie;
946 :
947 : /* Make sure that we are in the data. */
948 0 : http_start_data (hd);
949 :
950 : /* Close the write stream. Note that the reference counted socket
951 : object keeps the actual system socket open. */
952 0 : cookie = hd->write_cookie;
953 0 : if (!cookie)
954 0 : return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
955 :
956 0 : es_fclose (hd->fp_write);
957 0 : hd->fp_write = NULL;
958 : /* The close has released the cookie and thus we better set it to NULL. */
959 0 : hd->write_cookie = NULL;
960 :
961 : /* Shutdown one end of the socket is desired. As per HTTP/1.0 this
962 : is not required but some very old servers (e.g. the original pksd
963 : keyserver didn't worked without it. */
964 0 : if ((hd->flags & HTTP_FLAG_SHUTDOWN))
965 0 : shutdown (hd->sock->fd, 1);
966 0 : hd->in_data = 0;
967 :
968 : /* Create a new cookie and a stream for reading. */
969 0 : cookie = xtrycalloc (1, sizeof *cookie);
970 0 : if (!cookie)
971 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
972 0 : cookie->sock = my_socket_ref (hd->sock);
973 0 : cookie->session = http_session_ref (hd->session);
974 0 : cookie->use_tls = hd->uri->use_tls;
975 :
976 0 : hd->read_cookie = cookie;
977 0 : hd->fp_read = es_fopencookie (cookie, "r", cookie_functions);
978 0 : if (!hd->fp_read)
979 : {
980 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
981 0 : my_socket_unref (cookie->sock, NULL, NULL);
982 0 : http_session_unref (cookie->session);
983 0 : xfree (cookie);
984 0 : hd->read_cookie = NULL;
985 0 : return err;
986 : }
987 :
988 0 : err = parse_response (hd);
989 :
990 0 : if (!err)
991 0 : err = es_onclose (hd->fp_read, 1, fp_onclose_notification, hd);
992 :
993 0 : return err;
994 : }
995 :
996 :
997 : /* Convenience function to send a request and wait for the response.
998 : Closes the handle on error. If PROXY is not NULL, this value will
999 : be used as an HTTP proxy and any enabled $http_proxy gets
1000 : ignored. */
1001 : gpg_error_t
1002 0 : http_open_document (http_t *r_hd, const char *document,
1003 : const char *auth, unsigned int flags, const char *proxy,
1004 : http_session_t session,
1005 : const char *srvtag, strlist_t headers)
1006 : {
1007 : gpg_error_t err;
1008 :
1009 0 : err = http_open (r_hd, HTTP_REQ_GET, document, NULL, auth, flags,
1010 : proxy, session, srvtag, headers);
1011 0 : if (err)
1012 0 : return err;
1013 :
1014 0 : err = http_wait_response (*r_hd);
1015 0 : if (err)
1016 0 : http_close (*r_hd, 0);
1017 :
1018 0 : return err;
1019 : }
1020 :
1021 :
1022 : void
1023 0 : http_close (http_t hd, int keep_read_stream)
1024 : {
1025 0 : if (!hd)
1026 0 : return;
1027 :
1028 : /* First remove the close notifications for the streams. */
1029 0 : if (hd->fp_read)
1030 0 : es_onclose (hd->fp_read, 0, fp_onclose_notification, hd);
1031 0 : if (hd->fp_write)
1032 0 : es_onclose (hd->fp_write, 0, fp_onclose_notification, hd);
1033 :
1034 : /* Now we can close the streams. */
1035 0 : my_socket_unref (hd->sock, NULL, NULL);
1036 0 : if (hd->fp_read && !keep_read_stream)
1037 0 : es_fclose (hd->fp_read);
1038 0 : if (hd->fp_write)
1039 0 : es_fclose (hd->fp_write);
1040 0 : http_session_unref (hd->session);
1041 0 : http_release_parsed_uri (hd->uri);
1042 0 : while (hd->headers)
1043 : {
1044 0 : header_t tmp = hd->headers->next;
1045 0 : xfree (hd->headers->value);
1046 0 : xfree (hd->headers);
1047 0 : hd->headers = tmp;
1048 : }
1049 0 : xfree (hd->buffer);
1050 0 : xfree (hd);
1051 : }
1052 :
1053 :
1054 : estream_t
1055 0 : http_get_read_ptr (http_t hd)
1056 : {
1057 0 : return hd?hd->fp_read:NULL;
1058 : }
1059 :
1060 : estream_t
1061 0 : http_get_write_ptr (http_t hd)
1062 : {
1063 0 : return hd?hd->fp_write:NULL;
1064 : }
1065 :
1066 : unsigned int
1067 0 : http_get_status_code (http_t hd)
1068 : {
1069 0 : return hd?hd->status_code:0;
1070 : }
1071 :
1072 : /* Return information pertaining to TLS. If TLS is not in use for HD,
1073 : NULL is returned. WHAT is used ask for specific information:
1074 :
1075 : (NULL) := Only check whether TLS is is use. Returns an
1076 : unspecified string if TLS is in use. That string may
1077 : even be the empty string.
1078 : */
1079 : const char *
1080 0 : http_get_tls_info (http_t hd, const char *what)
1081 : {
1082 : (void)what;
1083 :
1084 0 : if (!hd)
1085 0 : return NULL;
1086 :
1087 0 : return hd->uri->use_tls? "":NULL;
1088 : }
1089 :
1090 :
1091 :
1092 : static gpg_error_t
1093 0 : parse_uri (parsed_uri_t *ret_uri, const char *uri,
1094 : int no_scheme_check, int force_tls)
1095 : {
1096 : gpg_err_code_t ec;
1097 :
1098 0 : *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri));
1099 0 : if (!*ret_uri)
1100 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1101 0 : strcpy ((*ret_uri)->buffer, uri);
1102 0 : ec = do_parse_uri (*ret_uri, 0, no_scheme_check, force_tls);
1103 0 : if (ec)
1104 : {
1105 0 : xfree (*ret_uri);
1106 0 : *ret_uri = NULL;
1107 : }
1108 0 : return gpg_err_make (default_errsource, ec);
1109 : }
1110 :
1111 :
1112 : /*
1113 : * Parse an URI and put the result into the newly allocated RET_URI.
1114 : * On success the caller must use http_release_parsed_uri() to
1115 : * releases the resources. If NO_SCHEME_CHECK is set, the function
1116 : * tries to parse the URL in the same way it would do for an HTTP
1117 : * style URI.
1118 : */
1119 : gpg_error_t
1120 0 : http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
1121 : int no_scheme_check)
1122 : {
1123 0 : return parse_uri (ret_uri, uri, no_scheme_check, 0);
1124 : }
1125 :
1126 :
1127 : void
1128 6 : http_release_parsed_uri (parsed_uri_t uri)
1129 : {
1130 6 : if (uri)
1131 : {
1132 : uri_tuple_t r, r2;
1133 :
1134 7 : for (r = uri->query; r; r = r2)
1135 : {
1136 1 : r2 = r->next;
1137 1 : xfree (r);
1138 : }
1139 6 : xfree (uri);
1140 : }
1141 6 : }
1142 :
1143 :
1144 : static gpg_err_code_t
1145 0 : do_parse_uri (parsed_uri_t uri, int only_local_part,
1146 : int no_scheme_check, int force_tls)
1147 : {
1148 : uri_tuple_t *tail;
1149 : char *p, *p2, *p3, *pp;
1150 : int n;
1151 :
1152 0 : p = uri->buffer;
1153 0 : n = strlen (uri->buffer);
1154 :
1155 : /* Initialize all fields to an empty string or an empty list. */
1156 0 : uri->scheme = uri->host = uri->path = p + n;
1157 0 : uri->port = 0;
1158 0 : uri->params = uri->query = NULL;
1159 0 : uri->use_tls = 0;
1160 0 : uri->is_http = 0;
1161 0 : uri->opaque = 0;
1162 0 : uri->v6lit = 0;
1163 0 : uri->onion = 0;
1164 :
1165 : /* A quick validity check. */
1166 0 : if (strspn (p, VALID_URI_CHARS) != n)
1167 0 : return GPG_ERR_BAD_URI; /* Invalid characters found. */
1168 :
1169 0 : if (!only_local_part)
1170 : {
1171 : /* Find the scheme. */
1172 0 : if (!(p2 = strchr (p, ':')) || p2 == p)
1173 0 : return GPG_ERR_BAD_URI; /* No scheme. */
1174 0 : *p2++ = 0;
1175 0 : for (pp=p; *pp; pp++)
1176 0 : *pp = tolower (*(unsigned char*)pp);
1177 0 : uri->scheme = p;
1178 0 : if (!strcmp (uri->scheme, "http") && !force_tls)
1179 : {
1180 0 : uri->port = 80;
1181 0 : uri->is_http = 1;
1182 : }
1183 0 : else if (!strcmp (uri->scheme, "hkp") && !force_tls)
1184 : {
1185 0 : uri->port = 11371;
1186 0 : uri->is_http = 1;
1187 : }
1188 : #ifdef USE_TLS
1189 0 : else if (!strcmp (uri->scheme, "https") || !strcmp (uri->scheme,"hkps")
1190 0 : || (force_tls && (!strcmp (uri->scheme, "http")
1191 0 : || !strcmp (uri->scheme,"hkp"))))
1192 : {
1193 0 : uri->port = 443;
1194 0 : uri->is_http = 1;
1195 0 : uri->use_tls = 1;
1196 : }
1197 : #endif /*USE_TLS*/
1198 0 : else if (!no_scheme_check)
1199 0 : return GPG_ERR_INV_URI; /* Unsupported scheme */
1200 :
1201 0 : p = p2;
1202 :
1203 0 : if (*p == '/' && p[1] == '/' ) /* There seems to be a hostname. */
1204 : {
1205 0 : p += 2;
1206 0 : if ((p2 = strchr (p, '/')))
1207 0 : *p2++ = 0;
1208 :
1209 : /* Check for username/password encoding */
1210 0 : if ((p3 = strchr (p, '@')))
1211 : {
1212 0 : uri->auth = p;
1213 0 : *p3++ = '\0';
1214 0 : p = p3;
1215 : }
1216 :
1217 0 : for (pp=p; *pp; pp++)
1218 0 : *pp = tolower (*(unsigned char*)pp);
1219 :
1220 : /* Handle an IPv6 literal */
1221 0 : if( *p == '[' && (p3=strchr( p, ']' )) )
1222 : {
1223 0 : *p3++ = '\0';
1224 : /* worst case, uri->host should have length 0, points to \0 */
1225 0 : uri->host = p + 1;
1226 0 : uri->v6lit = 1;
1227 0 : p = p3;
1228 : }
1229 : else
1230 0 : uri->host = p;
1231 :
1232 0 : if ((p3 = strchr (p, ':')))
1233 : {
1234 0 : *p3++ = '\0';
1235 0 : uri->port = atoi (p3);
1236 : }
1237 :
1238 0 : if ((n = remove_escapes (uri->host)) < 0)
1239 0 : return GPG_ERR_BAD_URI;
1240 0 : if (n != strlen (uri->host))
1241 0 : return GPG_ERR_BAD_URI; /* Hostname incudes a Nul. */
1242 0 : p = p2 ? p2 : NULL;
1243 : }
1244 0 : else if (uri->is_http)
1245 0 : return GPG_ERR_INV_URI; /* No Leading double slash for HTTP. */
1246 : else
1247 : {
1248 0 : uri->opaque = 1;
1249 0 : uri->path = p;
1250 0 : if (is_onion_address (uri->path))
1251 0 : uri->onion = 1;
1252 0 : return 0;
1253 : }
1254 :
1255 : } /* End global URI part. */
1256 :
1257 : /* Parse the pathname part if any. */
1258 0 : if (p && *p)
1259 : {
1260 : /* TODO: Here we have to check params. */
1261 :
1262 : /* Do we have a query part? */
1263 0 : if ((p2 = strchr (p, '?')))
1264 0 : *p2++ = 0;
1265 :
1266 0 : uri->path = p;
1267 0 : if ((n = remove_escapes (p)) < 0)
1268 0 : return GPG_ERR_BAD_URI;
1269 0 : if (n != strlen (p))
1270 0 : return GPG_ERR_BAD_URI; /* Path includes a Nul. */
1271 0 : p = p2 ? p2 : NULL;
1272 :
1273 : /* Parse a query string if any. */
1274 0 : if (p && *p)
1275 : {
1276 0 : tail = &uri->query;
1277 : for (;;)
1278 : {
1279 : uri_tuple_t elem;
1280 :
1281 0 : if ((p2 = strchr (p, '&')))
1282 0 : *p2++ = 0;
1283 0 : if (!(elem = parse_tuple (p)))
1284 0 : return GPG_ERR_BAD_URI;
1285 0 : *tail = elem;
1286 0 : tail = &elem->next;
1287 :
1288 0 : if (!p2)
1289 0 : break; /* Ready. */
1290 0 : p = p2;
1291 0 : }
1292 : }
1293 : }
1294 :
1295 0 : if (is_onion_address (uri->host))
1296 0 : uri->onion = 1;
1297 :
1298 0 : return 0;
1299 : }
1300 :
1301 :
1302 : /*
1303 : * Remove all %xx escapes; this is done in-place. Returns: New length
1304 : * of the string.
1305 : */
1306 : static int
1307 0 : remove_escapes (char *string)
1308 : {
1309 0 : int n = 0;
1310 : unsigned char *p, *s;
1311 :
1312 0 : for (p = s = (unsigned char*)string; *s; s++)
1313 : {
1314 0 : if (*s == '%')
1315 : {
1316 0 : if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2]))
1317 : {
1318 0 : s++;
1319 0 : *p = *s >= '0' && *s <= '9' ? *s - '0' :
1320 0 : *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
1321 0 : *p <<= 4;
1322 0 : s++;
1323 0 : *p |= *s >= '0' && *s <= '9' ? *s - '0' :
1324 0 : *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10;
1325 0 : p++;
1326 0 : n++;
1327 : }
1328 : else
1329 : {
1330 0 : *p++ = *s++;
1331 0 : if (*s)
1332 0 : *p++ = *s++;
1333 0 : if (*s)
1334 0 : *p++ = *s++;
1335 0 : if (*s)
1336 0 : *p = 0;
1337 0 : return -1; /* Bad URI. */
1338 : }
1339 : }
1340 : else
1341 : {
1342 0 : *p++ = *s;
1343 0 : n++;
1344 : }
1345 : }
1346 0 : *p = 0; /* Make sure to keep a string terminator. */
1347 0 : return n;
1348 : }
1349 :
1350 :
1351 : /* If SPECIAL is NULL this function escapes in forms mode. */
1352 : static size_t
1353 0 : escape_data (char *buffer, const void *data, size_t datalen,
1354 : const char *special)
1355 : {
1356 0 : int forms = !special;
1357 : const unsigned char *s;
1358 0 : size_t n = 0;
1359 :
1360 0 : if (forms)
1361 0 : special = "%;?&=";
1362 :
1363 0 : for (s = data; datalen; s++, datalen--)
1364 : {
1365 0 : if (forms && *s == ' ')
1366 : {
1367 0 : if (buffer)
1368 0 : *buffer++ = '+';
1369 0 : n++;
1370 : }
1371 0 : else if (forms && *s == '\n')
1372 : {
1373 0 : if (buffer)
1374 0 : memcpy (buffer, "%0D%0A", 6);
1375 0 : n += 6;
1376 : }
1377 0 : else if (forms && *s == '\r' && datalen > 1 && s[1] == '\n')
1378 : {
1379 0 : if (buffer)
1380 0 : memcpy (buffer, "%0D%0A", 6);
1381 0 : n += 6;
1382 0 : s++;
1383 0 : datalen--;
1384 : }
1385 0 : else if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s))
1386 : {
1387 0 : if (buffer)
1388 0 : *(unsigned char*)buffer++ = *s;
1389 0 : n++;
1390 : }
1391 : else
1392 : {
1393 0 : if (buffer)
1394 : {
1395 0 : snprintf (buffer, 4, "%%%02X", *s);
1396 0 : buffer += 3;
1397 : }
1398 0 : n += 3;
1399 : }
1400 : }
1401 0 : return n;
1402 : }
1403 :
1404 :
1405 : static int
1406 0 : insert_escapes (char *buffer, const char *string,
1407 : const char *special)
1408 : {
1409 0 : return escape_data (buffer, string, strlen (string), special);
1410 : }
1411 :
1412 :
1413 : /* Allocate a new string from STRING using standard HTTP escaping as
1414 : well as escaping of characters given in SPECIALS. A common pattern
1415 : for SPECIALS is "%;?&=". However it depends on the needs, for
1416 : example "+" and "/: often needs to be escaped too. Returns NULL on
1417 : failure and sets ERRNO. If SPECIAL is NULL a dedicated forms
1418 : encoding mode is used. */
1419 : char *
1420 0 : http_escape_string (const char *string, const char *specials)
1421 : {
1422 : int n;
1423 : char *buf;
1424 :
1425 0 : n = insert_escapes (NULL, string, specials);
1426 0 : buf = xtrymalloc (n+1);
1427 0 : if (buf)
1428 : {
1429 0 : insert_escapes (buf, string, specials);
1430 0 : buf[n] = 0;
1431 : }
1432 0 : return buf;
1433 : }
1434 :
1435 : /* Allocate a new string from {DATA,DATALEN} using standard HTTP
1436 : escaping as well as escaping of characters given in SPECIALS. A
1437 : common pattern for SPECIALS is "%;?&=". However it depends on the
1438 : needs, for example "+" and "/: often needs to be escaped too.
1439 : Returns NULL on failure and sets ERRNO. If SPECIAL is NULL a
1440 : dedicated forms encoding mode is used. */
1441 : char *
1442 0 : http_escape_data (const void *data, size_t datalen, const char *specials)
1443 : {
1444 : int n;
1445 : char *buf;
1446 :
1447 0 : n = escape_data (NULL, data, datalen, specials);
1448 0 : buf = xtrymalloc (n+1);
1449 0 : if (buf)
1450 : {
1451 0 : escape_data (buf, data, datalen, specials);
1452 0 : buf[n] = 0;
1453 : }
1454 0 : return buf;
1455 : }
1456 :
1457 :
1458 : static uri_tuple_t
1459 0 : parse_tuple (char *string)
1460 : {
1461 0 : char *p = string;
1462 : char *p2;
1463 : int n;
1464 : uri_tuple_t tuple;
1465 :
1466 0 : if ((p2 = strchr (p, '=')))
1467 0 : *p2++ = 0;
1468 0 : if ((n = remove_escapes (p)) < 0)
1469 0 : return NULL; /* Bad URI. */
1470 0 : if (n != strlen (p))
1471 0 : return NULL; /* Name with a Nul in it. */
1472 0 : tuple = xtrycalloc (1, sizeof *tuple);
1473 0 : if (!tuple)
1474 0 : return NULL; /* Out of core. */
1475 0 : tuple->name = p;
1476 0 : if (!p2) /* We have only the name, so we assume an empty value string. */
1477 : {
1478 0 : tuple->value = p + strlen (p);
1479 0 : tuple->valuelen = 0;
1480 0 : tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */
1481 : }
1482 : else /* Name and value. */
1483 : {
1484 0 : if ((n = remove_escapes (p2)) < 0)
1485 : {
1486 0 : xfree (tuple);
1487 0 : return NULL; /* Bad URI. */
1488 : }
1489 0 : tuple->value = p2;
1490 0 : tuple->valuelen = n;
1491 : }
1492 0 : return tuple;
1493 : }
1494 :
1495 :
1496 : /* Return true if STRING is likely "hostname:port" or only "hostname". */
1497 : static int
1498 0 : is_hostname_port (const char *string)
1499 : {
1500 0 : int colons = 0;
1501 :
1502 0 : if (!string || !*string)
1503 0 : return 0;
1504 0 : for (; *string; string++)
1505 : {
1506 0 : if (*string == ':')
1507 : {
1508 0 : if (colons)
1509 0 : return 0;
1510 0 : if (!string[1])
1511 0 : return 0;
1512 0 : colons++;
1513 : }
1514 0 : else if (!colons && strchr (" \t\f\n\v_@[]/", *string))
1515 0 : return 0; /* Invalid characters in hostname. */
1516 0 : else if (colons && !digitp (string))
1517 0 : return 0; /* Not a digit in the port. */
1518 : }
1519 0 : return 1;
1520 : }
1521 :
1522 :
1523 : /*
1524 : * Send a HTTP request to the server
1525 : * Returns 0 if the request was successful
1526 : */
1527 : static gpg_error_t
1528 0 : send_request (http_t hd, const char *httphost, const char *auth,
1529 : const char *proxy, const char *srvtag, strlist_t headers)
1530 : {
1531 : gpg_error_t err;
1532 : const char *server;
1533 : char *request, *p;
1534 : unsigned short port;
1535 0 : const char *http_proxy = NULL;
1536 0 : char *proxy_authstr = NULL;
1537 0 : char *authstr = NULL;
1538 : int sock;
1539 : int hnf;
1540 :
1541 0 : if (hd->uri->use_tls && !hd->session)
1542 : {
1543 0 : log_error ("TLS requested but no session object provided\n");
1544 0 : return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
1545 : }
1546 : #ifdef USE_TLS
1547 0 : if (hd->uri->use_tls && !hd->session->tls_session)
1548 : {
1549 0 : log_error ("TLS requested but no GNUTLS context available\n");
1550 0 : return gpg_err_make (default_errsource, GPG_ERR_INTERNAL);
1551 : }
1552 : #endif /*USE_TLS*/
1553 :
1554 0 : if ((hd->flags & HTTP_FLAG_FORCE_TOR))
1555 : {
1556 : int mode;
1557 :
1558 0 : if (assuan_sock_get_flag (ASSUAN_INVALID_FD, "tor-mode", &mode) || !mode)
1559 : {
1560 0 : log_error ("Tor support is not available\n");
1561 0 : return gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
1562 : }
1563 : }
1564 :
1565 0 : server = *hd->uri->host ? hd->uri->host : "localhost";
1566 0 : port = hd->uri->port ? hd->uri->port : 80;
1567 :
1568 : /* Try to use SNI. */
1569 : #ifdef USE_TLS
1570 0 : if (hd->uri->use_tls)
1571 : {
1572 : # if HTTP_USE_GNUTLS
1573 : int rc;
1574 : # endif
1575 :
1576 0 : xfree (hd->session->servername);
1577 0 : hd->session->servername = xtrystrdup (httphost? httphost : server);
1578 0 : if (!hd->session->servername)
1579 : {
1580 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1581 0 : return err;
1582 : }
1583 :
1584 : # if HTTP_USE_NTBTLS
1585 : err = ntbtls_set_hostname (hd->session->tls_session,
1586 : hd->session->servername);
1587 : if (err)
1588 : {
1589 : log_info ("ntbtls_set_hostname failed: %s\n", gpg_strerror (err));
1590 : return err;
1591 : }
1592 : # elif HTTP_USE_GNUTLS
1593 0 : rc = gnutls_server_name_set (hd->session->tls_session,
1594 : GNUTLS_NAME_DNS,
1595 0 : hd->session->servername,
1596 0 : strlen (hd->session->servername));
1597 0 : if (rc < 0)
1598 0 : log_info ("gnutls_server_name_set failed: %s\n", gnutls_strerror (rc));
1599 : # endif /*HTTP_USE_GNUTLS*/
1600 : }
1601 : #endif /*USE_TLS*/
1602 :
1603 0 : if ( (proxy && *proxy)
1604 0 : || ( (hd->flags & HTTP_FLAG_TRY_PROXY)
1605 0 : && (http_proxy = getenv (HTTP_PROXY_ENV))
1606 0 : && *http_proxy ))
1607 0 : {
1608 : parsed_uri_t uri;
1609 : int save_errno;
1610 :
1611 0 : if (proxy)
1612 0 : http_proxy = proxy;
1613 :
1614 0 : err = parse_uri (&uri, http_proxy, 0, 0);
1615 0 : if (gpg_err_code (err) == GPG_ERR_INV_URI
1616 0 : && is_hostname_port (http_proxy))
1617 : {
1618 : /* Retry assuming a "hostname:port" string. */
1619 0 : char *tmpname = strconcat ("http://", http_proxy, NULL);
1620 0 : if (tmpname && !parse_uri (&uri, tmpname, 0, 0))
1621 0 : err = 0;
1622 0 : xfree (tmpname);
1623 : }
1624 :
1625 0 : if (err)
1626 : ;
1627 0 : else if (!strcmp (uri->scheme, "http") || !strcmp (uri->scheme, "socks4"))
1628 : ;
1629 0 : else if (!strcmp (uri->scheme, "socks5h"))
1630 0 : err = gpg_err_make (default_errsource, GPG_ERR_NOT_IMPLEMENTED);
1631 : else
1632 0 : err = gpg_err_make (default_errsource, GPG_ERR_INV_URI);
1633 :
1634 0 : if (err)
1635 : {
1636 0 : log_error ("invalid HTTP proxy (%s): %s\n",
1637 : http_proxy, gpg_strerror (err));
1638 0 : return gpg_err_make (default_errsource, GPG_ERR_CONFIGURATION);
1639 : }
1640 :
1641 0 : if (uri->auth)
1642 : {
1643 0 : remove_escapes (uri->auth);
1644 0 : proxy_authstr = make_header_line ("Proxy-Authorization: Basic ",
1645 : "\r\n",
1646 0 : uri->auth, strlen(uri->auth));
1647 0 : if (!proxy_authstr)
1648 : {
1649 0 : err = gpg_err_make (default_errsource,
1650 : gpg_err_code_from_syserror ());
1651 0 : http_release_parsed_uri (uri);
1652 0 : return err;
1653 : }
1654 : }
1655 :
1656 0 : sock = connect_server (*uri->host ? uri->host : "localhost",
1657 0 : uri->port ? uri->port : 80,
1658 : hd->flags, srvtag, &hnf);
1659 0 : save_errno = errno;
1660 0 : http_release_parsed_uri (uri);
1661 0 : if (sock == ASSUAN_INVALID_FD)
1662 0 : gpg_err_set_errno (save_errno);
1663 : }
1664 : else
1665 : {
1666 0 : sock = connect_server (server, port, hd->flags, srvtag, &hnf);
1667 : }
1668 :
1669 0 : if (sock == ASSUAN_INVALID_FD)
1670 : {
1671 0 : xfree (proxy_authstr);
1672 0 : return gpg_err_make (default_errsource,
1673 0 : (hnf? GPG_ERR_UNKNOWN_HOST
1674 : : gpg_err_code_from_syserror ()));
1675 : }
1676 0 : hd->sock = my_socket_new (sock);
1677 0 : if (!hd->sock)
1678 : {
1679 0 : xfree (proxy_authstr);
1680 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1681 : }
1682 :
1683 :
1684 :
1685 : #if HTTP_USE_NTBTLS
1686 : if (hd->uri->use_tls)
1687 : {
1688 : my_socket_ref (hd->sock);
1689 :
1690 : while ((err = ntbtls_handshake (hd->session->tls_session)))
1691 : {
1692 : switch (err)
1693 : {
1694 : default:
1695 : log_info ("TLS handshake failed: %s <%s>\n",
1696 : gpg_strerror (err), gpg_strsource (err));
1697 : xfree (proxy_authstr);
1698 : return err;
1699 : }
1700 : }
1701 :
1702 : hd->session->verify.done = 0;
1703 : if (tls_callback)
1704 : err = tls_callback (hd, hd->session, 0);
1705 : else
1706 : err = http_verify_server_credentials (hd->session);
1707 : if (err)
1708 : {
1709 : log_info ("TLS connection authentication failed: %s <%s>\n",
1710 : gpg_strerror (err), gpg_strsource (err));
1711 : xfree (proxy_authstr);
1712 : return err;
1713 : }
1714 : }
1715 : #elif HTTP_USE_GNUTLS
1716 0 : if (hd->uri->use_tls)
1717 : {
1718 : int rc;
1719 :
1720 0 : my_socket_ref (hd->sock);
1721 0 : gnutls_transport_set_ptr (hd->session->tls_session, hd->sock);
1722 0 : gnutls_transport_set_pull_function (hd->session->tls_session,
1723 : my_gnutls_read);
1724 0 : gnutls_transport_set_push_function (hd->session->tls_session,
1725 : my_gnutls_write);
1726 :
1727 : do
1728 : {
1729 0 : rc = gnutls_handshake (hd->session->tls_session);
1730 : }
1731 0 : while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN);
1732 0 : if (rc < 0)
1733 : {
1734 0 : if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED
1735 0 : || rc == GNUTLS_E_FATAL_ALERT_RECEIVED)
1736 0 : {
1737 : gnutls_alert_description_t alertno;
1738 : const char *alertstr;
1739 :
1740 0 : alertno = gnutls_alert_get (hd->session->tls_session);
1741 0 : alertstr = gnutls_alert_get_name (alertno);
1742 0 : log_info ("TLS handshake failed: %s (alert %d)\n",
1743 : alertstr, (int)alertno);
1744 0 : if (alertno == GNUTLS_A_UNRECOGNIZED_NAME && server)
1745 0 : log_info (" (sent server name '%s')\n", server);
1746 : }
1747 : else
1748 0 : log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc));
1749 0 : xfree (proxy_authstr);
1750 0 : return gpg_err_make (default_errsource, GPG_ERR_NETWORK);
1751 : }
1752 :
1753 0 : hd->session->verify.done = 0;
1754 0 : if (tls_callback)
1755 0 : err = tls_callback (hd, hd->session, 0);
1756 : else
1757 0 : err = http_verify_server_credentials (hd->session);
1758 0 : if (err)
1759 : {
1760 0 : log_info ("TLS connection authentication failed: %s\n",
1761 : gpg_strerror (err));
1762 0 : xfree (proxy_authstr);
1763 0 : return err;
1764 : }
1765 : }
1766 : #endif /*HTTP_USE_GNUTLS*/
1767 :
1768 0 : if (auth || hd->uri->auth)
1769 : {
1770 : char *myauth;
1771 :
1772 0 : if (auth)
1773 : {
1774 0 : myauth = xtrystrdup (auth);
1775 0 : if (!myauth)
1776 : {
1777 0 : xfree (proxy_authstr);
1778 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1779 : }
1780 0 : remove_escapes (myauth);
1781 : }
1782 : else
1783 : {
1784 0 : remove_escapes (hd->uri->auth);
1785 0 : myauth = hd->uri->auth;
1786 : }
1787 :
1788 0 : authstr = make_header_line ("Authorization: Basic ", "\r\n",
1789 : myauth, strlen (myauth));
1790 0 : if (auth)
1791 0 : xfree (myauth);
1792 :
1793 0 : if (!authstr)
1794 : {
1795 0 : xfree (proxy_authstr);
1796 0 : return gpg_err_make (default_errsource,
1797 : gpg_err_code_from_syserror ());
1798 : }
1799 : }
1800 :
1801 0 : p = build_rel_path (hd->uri);
1802 0 : if (!p)
1803 0 : return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1804 :
1805 0 : if (http_proxy && *http_proxy)
1806 : {
1807 0 : request = es_bsprintf
1808 : ("%s %s://%s:%hu%s%s HTTP/1.0\r\n%s%s",
1809 0 : hd->req_type == HTTP_REQ_GET ? "GET" :
1810 0 : hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1811 0 : hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1812 0 : hd->uri->use_tls? "https" : "http",
1813 : httphost? httphost : server,
1814 0 : port, *p == '/' ? "" : "/", p,
1815 : authstr ? authstr : "",
1816 : proxy_authstr ? proxy_authstr : "");
1817 : }
1818 : else
1819 : {
1820 : char portstr[35];
1821 :
1822 0 : if (port == 80)
1823 0 : *portstr = 0;
1824 : else
1825 0 : snprintf (portstr, sizeof portstr, ":%u", port);
1826 :
1827 0 : request = es_bsprintf
1828 : ("%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s",
1829 0 : hd->req_type == HTTP_REQ_GET ? "GET" :
1830 0 : hd->req_type == HTTP_REQ_HEAD ? "HEAD" :
1831 0 : hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS",
1832 0 : *p == '/' ? "" : "/", p,
1833 : httphost? httphost : server,
1834 : portstr,
1835 : authstr? authstr:"");
1836 : }
1837 0 : xfree (p);
1838 0 : if (!request)
1839 : {
1840 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1841 0 : xfree (authstr);
1842 0 : xfree (proxy_authstr);
1843 0 : return err;
1844 : }
1845 :
1846 : /* log_debug ("request:\n%s\nEND request\n", request); */
1847 :
1848 : /* First setup estream so that we can write even the first line
1849 : using estream. This is also required for the sake of gnutls. */
1850 : {
1851 : cookie_t cookie;
1852 :
1853 0 : cookie = xtrycalloc (1, sizeof *cookie);
1854 0 : if (!cookie)
1855 : {
1856 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1857 0 : goto leave;
1858 : }
1859 0 : cookie->sock = my_socket_ref (hd->sock);
1860 0 : hd->write_cookie = cookie;
1861 0 : cookie->use_tls = hd->uri->use_tls;
1862 0 : cookie->session = http_session_ref (hd->session);
1863 :
1864 0 : hd->fp_write = es_fopencookie (cookie, "w", cookie_functions);
1865 0 : if (!hd->fp_write)
1866 : {
1867 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1868 0 : my_socket_unref (cookie->sock, NULL, NULL);
1869 0 : xfree (cookie);
1870 0 : hd->write_cookie = NULL;
1871 : }
1872 0 : else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write))
1873 0 : err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
1874 : else
1875 0 : err = 0;
1876 :
1877 0 : if (!err)
1878 : {
1879 0 : for (;headers; headers=headers->next)
1880 : {
1881 0 : if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write))
1882 0 : || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write)))
1883 : {
1884 0 : err = gpg_err_make (default_errsource,
1885 : gpg_err_code_from_syserror ());
1886 0 : break;
1887 : }
1888 : }
1889 : }
1890 : }
1891 :
1892 : leave:
1893 0 : es_free (request);
1894 0 : xfree (authstr);
1895 0 : xfree (proxy_authstr);
1896 :
1897 0 : return err;
1898 : }
1899 :
1900 :
1901 : /*
1902 : * Build the relative path from the parsed URI. Minimal
1903 : * implementation. May return NULL in case of memory failure; errno
1904 : * is then set accordingly.
1905 : */
1906 : static char *
1907 0 : build_rel_path (parsed_uri_t uri)
1908 : {
1909 : uri_tuple_t r;
1910 : char *rel_path, *p;
1911 : int n;
1912 :
1913 : /* Count the needed space. */
1914 0 : n = insert_escapes (NULL, uri->path, "%;?&");
1915 : /* TODO: build params. */
1916 0 : for (r = uri->query; r; r = r->next)
1917 : {
1918 0 : n++; /* '?'/'&' */
1919 0 : n += insert_escapes (NULL, r->name, "%;?&=");
1920 0 : if (!r->no_value)
1921 : {
1922 0 : n++; /* '=' */
1923 0 : n += insert_escapes (NULL, r->value, "%;?&=");
1924 : }
1925 : }
1926 0 : n++;
1927 :
1928 : /* Now allocate and copy. */
1929 0 : p = rel_path = xtrymalloc (n);
1930 0 : if (!p)
1931 0 : return NULL;
1932 0 : n = insert_escapes (p, uri->path, "%;?&");
1933 0 : p += n;
1934 : /* TODO: add params. */
1935 0 : for (r = uri->query; r; r = r->next)
1936 : {
1937 0 : *p++ = r == uri->query ? '?' : '&';
1938 0 : n = insert_escapes (p, r->name, "%;?&=");
1939 0 : p += n;
1940 0 : if (!r->no_value)
1941 : {
1942 0 : *p++ = '=';
1943 : /* TODO: Use valuelen. */
1944 0 : n = insert_escapes (p, r->value, "%;?&=");
1945 0 : p += n;
1946 : }
1947 : }
1948 0 : *p = 0;
1949 0 : return rel_path;
1950 : }
1951 :
1952 :
1953 : /* Transform a header name into a standard capitalized format; e.g.
1954 : "Content-Type". Conversion stops at the colon. As usual we don't
1955 : use the localized versions of ctype.h. */
1956 : static void
1957 0 : capitalize_header_name (char *name)
1958 : {
1959 0 : int first = 1;
1960 :
1961 0 : for (; *name && *name != ':'; name++)
1962 : {
1963 0 : if (*name == '-')
1964 0 : first = 1;
1965 0 : else if (first)
1966 : {
1967 0 : if (*name >= 'a' && *name <= 'z')
1968 0 : *name = *name - 'a' + 'A';
1969 0 : first = 0;
1970 : }
1971 0 : else if (*name >= 'A' && *name <= 'Z')
1972 0 : *name = *name - 'A' + 'a';
1973 : }
1974 0 : }
1975 :
1976 :
1977 : /* Store an HTTP header line in LINE away. Line continuation is
1978 : supported as well as merging of headers with the same name. This
1979 : function may modify LINE. */
1980 : static gpg_err_code_t
1981 0 : store_header (http_t hd, char *line)
1982 : {
1983 : size_t n;
1984 : char *p, *value;
1985 : header_t h;
1986 :
1987 0 : n = strlen (line);
1988 0 : if (n && line[n-1] == '\n')
1989 : {
1990 0 : line[--n] = 0;
1991 0 : if (n && line[n-1] == '\r')
1992 0 : line[--n] = 0;
1993 : }
1994 0 : if (!n) /* we are never called to hit this. */
1995 0 : return GPG_ERR_BUG;
1996 0 : if (*line == ' ' || *line == '\t')
1997 : {
1998 : /* Continuation. This won't happen too often as it is not
1999 : recommended. We use a straightforward implementaion. */
2000 0 : if (!hd->headers)
2001 0 : return GPG_ERR_PROTOCOL_VIOLATION;
2002 0 : n += strlen (hd->headers->value);
2003 0 : p = xtrymalloc (n+1);
2004 0 : if (!p)
2005 0 : return gpg_err_code_from_syserror ();
2006 0 : strcpy (stpcpy (p, hd->headers->value), line);
2007 0 : xfree (hd->headers->value);
2008 0 : hd->headers->value = p;
2009 0 : return 0;
2010 : }
2011 :
2012 0 : capitalize_header_name (line);
2013 0 : p = strchr (line, ':');
2014 0 : if (!p)
2015 0 : return GPG_ERR_PROTOCOL_VIOLATION;
2016 0 : *p++ = 0;
2017 0 : while (*p == ' ' || *p == '\t')
2018 0 : p++;
2019 0 : value = p;
2020 :
2021 0 : for (h=hd->headers; h; h = h->next)
2022 0 : if ( !strcmp (h->name, line) )
2023 0 : break;
2024 0 : if (h)
2025 : {
2026 : /* We have already seen a line with that name. Thus we assume
2027 : it is a comma separated list and merge them. */
2028 0 : p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1);
2029 0 : if (!p)
2030 0 : return gpg_err_code_from_syserror ();
2031 0 : strcpy (stpcpy (stpcpy (p, h->value), ","), value);
2032 0 : xfree (h->value);
2033 0 : h->value = p;
2034 0 : return 0;
2035 : }
2036 :
2037 : /* Append a new header. */
2038 0 : h = xtrymalloc (sizeof *h + strlen (line));
2039 0 : if (!h)
2040 0 : return gpg_err_code_from_syserror ();
2041 0 : strcpy (h->name, line);
2042 0 : h->value = xtrymalloc (strlen (value)+1);
2043 0 : if (!h->value)
2044 : {
2045 0 : xfree (h);
2046 0 : return gpg_err_code_from_syserror ();
2047 : }
2048 0 : strcpy (h->value, value);
2049 0 : h->next = hd->headers;
2050 0 : hd->headers = h;
2051 :
2052 0 : return 0;
2053 : }
2054 :
2055 :
2056 : /* Return the header NAME from the last response. The returned value
2057 : is valid as along as HD has not been closed and no other request
2058 : has been send. If the header was not found, NULL is returned. NAME
2059 : must be canonicalized, that is the first letter of each dash
2060 : delimited part must be uppercase and all other letters lowercase. */
2061 : const char *
2062 0 : http_get_header (http_t hd, const char *name)
2063 : {
2064 : header_t h;
2065 :
2066 0 : for (h=hd->headers; h; h = h->next)
2067 0 : if ( !strcmp (h->name, name) )
2068 0 : return h->value;
2069 0 : return NULL;
2070 : }
2071 :
2072 :
2073 : /* Return a newly allocated and NULL terminated array with pointers to
2074 : header names. The array must be released with xfree() and its
2075 : content is only values as long as no other request has been
2076 : send. */
2077 : const char **
2078 0 : http_get_header_names (http_t hd)
2079 : {
2080 : const char **array;
2081 : size_t n;
2082 : header_t h;
2083 :
2084 0 : for (n=0, h = hd->headers; h; h = h->next)
2085 0 : n++;
2086 0 : array = xtrycalloc (n+1, sizeof *array);
2087 0 : if (array)
2088 : {
2089 0 : for (n=0, h = hd->headers; h; h = h->next)
2090 0 : array[n++] = h->name;
2091 : }
2092 :
2093 0 : return array;
2094 : }
2095 :
2096 :
2097 : /*
2098 : * Parse the response from a server.
2099 : * Returns: Errorcode and sets some files in the handle
2100 : */
2101 : static gpg_err_code_t
2102 0 : parse_response (http_t hd)
2103 : {
2104 : char *line, *p, *p2;
2105 : size_t maxlen, len;
2106 0 : cookie_t cookie = hd->read_cookie;
2107 : const char *s;
2108 :
2109 : /* Delete old header lines. */
2110 0 : while (hd->headers)
2111 : {
2112 0 : header_t tmp = hd->headers->next;
2113 0 : xfree (hd->headers->value);
2114 0 : xfree (hd->headers);
2115 0 : hd->headers = tmp;
2116 : }
2117 :
2118 : /* Wait for the status line. */
2119 : do
2120 : {
2121 0 : maxlen = MAX_LINELEN;
2122 0 : len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
2123 0 : line = hd->buffer;
2124 0 : if (!line)
2125 0 : return gpg_err_code_from_syserror (); /* Out of core. */
2126 0 : if (!maxlen)
2127 0 : return GPG_ERR_TRUNCATED; /* Line has been truncated. */
2128 0 : if (!len)
2129 0 : return GPG_ERR_EOF;
2130 :
2131 0 : if ((hd->flags & HTTP_FLAG_LOG_RESP))
2132 0 : log_info ("RESP: '%.*s'\n",
2133 0 : (int)strlen(line)-(*line&&line[1]?2:0),line);
2134 : }
2135 0 : while (!*line);
2136 :
2137 0 : if ((p = strchr (line, '/')))
2138 0 : *p++ = 0;
2139 0 : if (!p || strcmp (line, "HTTP"))
2140 0 : return 0; /* Assume http 0.9. */
2141 :
2142 0 : if ((p2 = strpbrk (p, " \t")))
2143 : {
2144 0 : *p2++ = 0;
2145 0 : p2 += strspn (p2, " \t");
2146 : }
2147 0 : if (!p2)
2148 0 : return 0; /* Also assume http 0.9. */
2149 0 : p = p2;
2150 : /* TODO: Add HTTP version number check. */
2151 0 : if ((p2 = strpbrk (p, " \t")))
2152 0 : *p2++ = 0;
2153 0 : if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1])
2154 0 : || !isdigit ((unsigned int)p[2]) || p[3])
2155 : {
2156 : /* Malformed HTTP status code - assume http 0.9. */
2157 0 : hd->is_http_0_9 = 1;
2158 0 : hd->status_code = 200;
2159 0 : return 0;
2160 : }
2161 0 : hd->status_code = atoi (p);
2162 :
2163 : /* Skip all the header lines and wait for the empty line. */
2164 : do
2165 : {
2166 0 : maxlen = MAX_LINELEN;
2167 0 : len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen);
2168 0 : line = hd->buffer;
2169 0 : if (!line)
2170 0 : return gpg_err_code_from_syserror (); /* Out of core. */
2171 : /* Note, that we can silently ignore truncated lines. */
2172 0 : if (!len)
2173 0 : return GPG_ERR_EOF;
2174 : /* Trim line endings of empty lines. */
2175 0 : if ((*line == '\r' && line[1] == '\n') || *line == '\n')
2176 0 : *line = 0;
2177 0 : if ((hd->flags & HTTP_FLAG_LOG_RESP))
2178 0 : log_info ("RESP: '%.*s'\n",
2179 0 : (int)strlen(line)-(*line&&line[1]?2:0),line);
2180 0 : if (*line)
2181 : {
2182 0 : gpg_err_code_t ec = store_header (hd, line);
2183 0 : if (ec)
2184 0 : return ec;
2185 : }
2186 : }
2187 0 : while (len && *line);
2188 :
2189 0 : cookie->content_length_valid = 0;
2190 0 : if (!(hd->flags & HTTP_FLAG_IGNORE_CL))
2191 : {
2192 0 : s = http_get_header (hd, "Content-Length");
2193 0 : if (s)
2194 : {
2195 0 : cookie->content_length_valid = 1;
2196 0 : cookie->content_length = string_to_u64 (s);
2197 : }
2198 : }
2199 :
2200 0 : return 0;
2201 : }
2202 :
2203 : #if 0
2204 : static int
2205 : start_server ()
2206 : {
2207 : struct sockaddr_in mya;
2208 : struct sockaddr_in peer;
2209 : int fd, client;
2210 : fd_set rfds;
2211 : int addrlen;
2212 : int i;
2213 :
2214 : if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
2215 : {
2216 : log_error ("socket() failed: %s\n", strerror (errno));
2217 : return -1;
2218 : }
2219 : i = 1;
2220 : if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i)))
2221 : log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno));
2222 :
2223 : mya.sin_family = AF_INET;
2224 : memset (&mya.sin_addr, 0, sizeof (mya.sin_addr));
2225 : mya.sin_port = htons (11371);
2226 :
2227 : if (bind (fd, (struct sockaddr *) &mya, sizeof (mya)))
2228 : {
2229 : log_error ("bind to port 11371 failed: %s\n", strerror (errno));
2230 : sock_close (fd);
2231 : return -1;
2232 : }
2233 :
2234 : if (listen (fd, 5))
2235 : {
2236 : log_error ("listen failed: %s\n", strerror (errno));
2237 : sock_close (fd);
2238 : return -1;
2239 : }
2240 :
2241 : for (;;)
2242 : {
2243 : FD_ZERO (&rfds);
2244 : FD_SET (fd, &rfds);
2245 :
2246 : if (my_select (fd + 1, &rfds, NULL, NULL, NULL) <= 0)
2247 : continue; /* ignore any errors */
2248 :
2249 : if (!FD_ISSET (fd, &rfds))
2250 : continue;
2251 :
2252 : addrlen = sizeof peer;
2253 : client = my_accept (fd, (struct sockaddr *) &peer, &addrlen);
2254 : if (client == -1)
2255 : continue; /* oops */
2256 :
2257 : log_info ("connect from %s\n", inet_ntoa (peer.sin_addr));
2258 :
2259 : fflush (stdout);
2260 : fflush (stderr);
2261 : if (!fork ())
2262 : {
2263 : int c;
2264 : FILE *fp;
2265 :
2266 : fp = fdopen (client, "r");
2267 : while ((c = getc (fp)) != EOF)
2268 : putchar (c);
2269 : fclose (fp);
2270 : exit (0);
2271 : }
2272 : sock_close (client);
2273 : }
2274 :
2275 :
2276 : return 0;
2277 : }
2278 : #endif
2279 :
2280 : /* Actually connect to a server. Returns the file descriptor or -1 on
2281 : error. ERRNO is set on error. */
2282 : static assuan_fd_t
2283 0 : connect_server (const char *server, unsigned short port,
2284 : unsigned int flags, const char *srvtag, int *r_host_not_found)
2285 : {
2286 : gpg_error_t err;
2287 0 : assuan_fd_t sock = ASSUAN_INVALID_FD;
2288 0 : int srvcount = 0;
2289 0 : int hostfound = 0;
2290 0 : int anyhostaddr = 0;
2291 : int srv, connected;
2292 0 : int last_errno = 0;
2293 0 : struct srventry *serverlist = NULL;
2294 : int ret;
2295 :
2296 0 : *r_host_not_found = 0;
2297 : #if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP)
2298 : init_sockets ();
2299 : #endif /*Windows*/
2300 :
2301 : /* Onion addresses require special treatment. */
2302 0 : if (is_onion_address (server))
2303 : {
2304 : #ifdef ASSUAN_SOCK_TOR
2305 :
2306 0 : sock = assuan_sock_connect_byname (server, port, 0, NULL,
2307 : ASSUAN_SOCK_TOR);
2308 0 : if (sock == ASSUAN_INVALID_FD)
2309 : {
2310 0 : if (errno == EHOSTUNREACH)
2311 0 : *r_host_not_found = 1;
2312 0 : log_error ("can't connect to '%s': %s\n", server, strerror (errno));
2313 : }
2314 : else
2315 0 : notify_netactivity ();
2316 0 : return sock;
2317 :
2318 : #else /*!ASSUAN_SOCK_TOR*/
2319 :
2320 : gpg_err_set_errno (ENETUNREACH);
2321 : return -1; /* Out of core. */
2322 :
2323 : #endif /*!HASSUAN_SOCK_TOR*/
2324 : }
2325 :
2326 : #ifdef USE_DNS_SRV
2327 : /* Do the SRV thing */
2328 0 : if (srvtag)
2329 : {
2330 : /* We're using SRV, so append the tags. */
2331 0 : if (1 + strlen (srvtag) + 6 + strlen (server) + 1
2332 : <= DIMof (struct srventry, target))
2333 : {
2334 0 : char *srvname = xtrymalloc (DIMof (struct srventry, target));
2335 :
2336 0 : if (!srvname) /* Out of core */
2337 : {
2338 0 : serverlist = NULL;
2339 0 : srvcount = 0;
2340 : }
2341 : else
2342 : {
2343 0 : stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag),
2344 : "._tcp."), server);
2345 0 : srvcount = getsrv (srvname, &serverlist);
2346 0 : xfree (srvname);
2347 : }
2348 : }
2349 : }
2350 : #else
2351 : (void)flags;
2352 : (void)srvtag;
2353 : #endif /*USE_DNS_SRV*/
2354 :
2355 0 : if (!serverlist)
2356 : {
2357 : /* Either we're not using SRV, or the SRV lookup failed. Make
2358 : up a fake SRV record. */
2359 0 : serverlist = xtrycalloc (1, sizeof *serverlist);
2360 0 : if (!serverlist)
2361 0 : return -1; /* Out of core. */
2362 0 : serverlist->port = port;
2363 0 : strncpy (serverlist->target, server, DIMof (struct srventry, target));
2364 0 : serverlist->target[DIMof (struct srventry, target)-1] = '\0';
2365 0 : srvcount = 1;
2366 : }
2367 :
2368 0 : connected = 0;
2369 0 : for (srv=0; srv < srvcount && !connected; srv++)
2370 : {
2371 : dns_addrinfo_t aibuf, ai;
2372 :
2373 0 : err = resolve_dns_name (serverlist[srv].target, port, 0, SOCK_STREAM,
2374 : &aibuf, NULL);
2375 0 : if (err)
2376 : {
2377 0 : log_info ("resolving '%s' failed: %s\n",
2378 0 : serverlist[srv].target, gpg_strerror (err));
2379 0 : continue; /* Not found - try next one. */
2380 : }
2381 0 : hostfound = 1;
2382 :
2383 0 : for (ai = aibuf; ai && !connected; ai = ai->next)
2384 : {
2385 0 : if (ai->family == AF_INET && (flags & HTTP_FLAG_IGNORE_IPv4))
2386 0 : continue;
2387 0 : if (ai->family == AF_INET6 && (flags & HTTP_FLAG_IGNORE_IPv6))
2388 0 : continue;
2389 :
2390 0 : if (sock != ASSUAN_INVALID_FD)
2391 0 : assuan_sock_close (sock);
2392 0 : sock = assuan_sock_new (ai->family, ai->socktype, ai->protocol);
2393 0 : if (sock == ASSUAN_INVALID_FD)
2394 : {
2395 0 : int save_errno = errno;
2396 0 : log_error ("error creating socket: %s\n", strerror (errno));
2397 0 : free_dns_addrinfo (aibuf);
2398 0 : xfree (serverlist);
2399 0 : errno = save_errno;
2400 0 : return ASSUAN_INVALID_FD;
2401 : }
2402 :
2403 0 : anyhostaddr = 1;
2404 0 : ret = assuan_sock_connect (sock, ai->addr, ai->addrlen);
2405 0 : if (ret)
2406 0 : last_errno = errno;
2407 : else
2408 : {
2409 0 : connected = 1;
2410 0 : notify_netactivity ();
2411 : }
2412 : }
2413 0 : free_dns_addrinfo (aibuf);
2414 : }
2415 :
2416 0 : xfree (serverlist);
2417 :
2418 0 : if (!connected)
2419 : {
2420 0 : if (!hostfound)
2421 0 : log_error ("can't connect to '%s': %s\n",
2422 : server, "host not found");
2423 0 : else if (!anyhostaddr)
2424 0 : log_error ("can't connect to '%s': %s\n",
2425 : server, "no IP address for host");
2426 : else
2427 : {
2428 : #ifdef HAVE_W32_SYSTEM
2429 : log_error ("can't connect to '%s': ec=%d\n",
2430 : server, (int)WSAGetLastError());
2431 : #else
2432 0 : log_error ("can't connect to '%s': %s\n",
2433 : server, strerror (last_errno));
2434 : #endif
2435 : }
2436 0 : if (!hostfound || (hostfound && !anyhostaddr))
2437 0 : *r_host_not_found = 1;
2438 0 : if (sock != ASSUAN_INVALID_FD)
2439 0 : assuan_sock_close (sock);
2440 0 : gpg_err_set_errno (last_errno);
2441 0 : return ASSUAN_INVALID_FD;
2442 : }
2443 0 : return sock;
2444 : }
2445 :
2446 :
2447 : static gpg_error_t
2448 0 : write_server (int sock, const char *data, size_t length)
2449 : {
2450 : int nleft;
2451 : int nwritten;
2452 :
2453 0 : nleft = length;
2454 0 : while (nleft > 0)
2455 : {
2456 : #if defined(HAVE_W32_SYSTEM)
2457 : # if defined(USE_NPTH)
2458 : npth_unprotect ();
2459 : # endif
2460 : nwritten = send (sock, data, nleft, 0);
2461 : # if defined(USE_NPTH)
2462 : npth_protect ();
2463 : # endif
2464 : if ( nwritten == SOCKET_ERROR )
2465 : {
2466 : log_info ("network write failed: ec=%d\n", (int)WSAGetLastError ());
2467 : return gpg_error (GPG_ERR_NETWORK);
2468 : }
2469 : #else /*!HAVE_W32_SYSTEM*/
2470 : # ifdef USE_NPTH
2471 0 : nwritten = npth_write (sock, data, nleft);
2472 : # else
2473 0 : nwritten = write (sock, data, nleft);
2474 : # endif
2475 0 : if (nwritten == -1)
2476 : {
2477 0 : if (errno == EINTR)
2478 0 : continue;
2479 0 : if (errno == EAGAIN)
2480 : {
2481 : struct timeval tv;
2482 :
2483 0 : tv.tv_sec = 0;
2484 0 : tv.tv_usec = 50000;
2485 0 : my_select (0, NULL, NULL, NULL, &tv);
2486 0 : continue;
2487 : }
2488 0 : log_info ("network write failed: %s\n", strerror (errno));
2489 0 : return gpg_error_from_syserror ();
2490 : }
2491 : #endif /*!HAVE_W32_SYSTEM*/
2492 0 : nleft -= nwritten;
2493 0 : data += nwritten;
2494 : }
2495 :
2496 0 : return 0;
2497 : }
2498 :
2499 :
2500 :
2501 : /* Read handler for estream. */
2502 : static gpgrt_ssize_t
2503 0 : cookie_read (void *cookie, void *buffer, size_t size)
2504 : {
2505 0 : cookie_t c = cookie;
2506 : int nread;
2507 :
2508 0 : if (c->content_length_valid)
2509 : {
2510 0 : if (!c->content_length)
2511 0 : return 0; /* EOF */
2512 0 : if (c->content_length < size)
2513 0 : size = c->content_length;
2514 : }
2515 :
2516 : #ifdef HTTP_USE_GNUTLS
2517 0 : if (c->use_tls && c->session && c->session->tls_session)
2518 : {
2519 : again:
2520 0 : nread = gnutls_record_recv (c->session->tls_session, buffer, size);
2521 0 : if (nread < 0)
2522 : {
2523 0 : if (nread == GNUTLS_E_INTERRUPTED)
2524 0 : goto again;
2525 0 : if (nread == GNUTLS_E_AGAIN)
2526 : {
2527 : struct timeval tv;
2528 :
2529 0 : tv.tv_sec = 0;
2530 0 : tv.tv_usec = 50000;
2531 0 : my_select (0, NULL, NULL, NULL, &tv);
2532 0 : goto again;
2533 : }
2534 0 : if (nread == GNUTLS_E_REHANDSHAKE)
2535 0 : goto again; /* A client is allowed to just ignore this request. */
2536 0 : if (nread == GNUTLS_E_PREMATURE_TERMINATION)
2537 : {
2538 : /* The server terminated the connection. Close the TLS
2539 : session, and indicate EOF using a short read. */
2540 0 : close_tls_session (c->session);
2541 0 : return 0;
2542 : }
2543 0 : log_info ("TLS network read failed: %s\n", gnutls_strerror (nread));
2544 0 : gpg_err_set_errno (EIO);
2545 0 : return -1;
2546 : }
2547 : }
2548 : else
2549 : #endif /*HTTP_USE_GNUTLS*/
2550 : {
2551 : do
2552 : {
2553 : #ifdef HAVE_W32_SYSTEM
2554 : /* Under Windows we need to use recv for a socket. */
2555 : # if defined(USE_NPTH)
2556 : npth_unprotect ();
2557 : # endif
2558 : nread = recv (c->sock->fd, buffer, size, 0);
2559 : # if defined(USE_NPTH)
2560 : npth_protect ();
2561 : # endif
2562 :
2563 : #else /*!HAVE_W32_SYSTEM*/
2564 :
2565 : # ifdef USE_NPTH
2566 0 : nread = npth_read (c->sock->fd, buffer, size);
2567 : # else
2568 0 : nread = read (c->sock->fd, buffer, size);
2569 : # endif
2570 :
2571 : #endif /*!HAVE_W32_SYSTEM*/
2572 : }
2573 0 : while (nread == -1 && errno == EINTR);
2574 : }
2575 :
2576 0 : if (c->content_length_valid && nread > 0)
2577 : {
2578 0 : if (nread < c->content_length)
2579 0 : c->content_length -= nread;
2580 : else
2581 0 : c->content_length = 0;
2582 : }
2583 :
2584 0 : return (gpgrt_ssize_t)nread;
2585 : }
2586 :
2587 : /* Write handler for estream. */
2588 : static gpgrt_ssize_t
2589 0 : cookie_write (void *cookie, const void *buffer_arg, size_t size)
2590 : {
2591 0 : const char *buffer = buffer_arg;
2592 0 : cookie_t c = cookie;
2593 0 : int nwritten = 0;
2594 :
2595 : #ifdef HTTP_USE_GNUTLS
2596 0 : if (c->use_tls && c->session && c->session->tls_session)
2597 0 : {
2598 0 : int nleft = size;
2599 0 : while (nleft > 0)
2600 : {
2601 0 : nwritten = gnutls_record_send (c->session->tls_session,
2602 : buffer, nleft);
2603 0 : if (nwritten <= 0)
2604 : {
2605 0 : if (nwritten == GNUTLS_E_INTERRUPTED)
2606 0 : continue;
2607 0 : if (nwritten == GNUTLS_E_AGAIN)
2608 : {
2609 : struct timeval tv;
2610 :
2611 0 : tv.tv_sec = 0;
2612 0 : tv.tv_usec = 50000;
2613 0 : my_select (0, NULL, NULL, NULL, &tv);
2614 0 : continue;
2615 : }
2616 0 : log_info ("TLS network write failed: %s\n",
2617 : gnutls_strerror (nwritten));
2618 0 : gpg_err_set_errno (EIO);
2619 0 : return -1;
2620 : }
2621 0 : nleft -= nwritten;
2622 0 : buffer += nwritten;
2623 : }
2624 : }
2625 : else
2626 : #endif /*HTTP_USE_GNUTLS*/
2627 : {
2628 0 : if ( write_server (c->sock->fd, buffer, size) )
2629 : {
2630 0 : gpg_err_set_errno (EIO);
2631 0 : nwritten = -1;
2632 : }
2633 : else
2634 0 : nwritten = size;
2635 : }
2636 :
2637 0 : return (gpgrt_ssize_t)nwritten;
2638 : }
2639 :
2640 :
2641 : #ifdef HTTP_USE_GNUTLS
2642 : /* Wrapper for gnutls_bye used by my_socket_unref. */
2643 : static void
2644 0 : send_gnutls_bye (void *opaque)
2645 : {
2646 0 : tls_session_t tls_session = opaque;
2647 : int ret;
2648 :
2649 : again:
2650 : do
2651 0 : ret = gnutls_bye (tls_session, GNUTLS_SHUT_RDWR);
2652 0 : while (ret == GNUTLS_E_INTERRUPTED);
2653 0 : if (ret == GNUTLS_E_AGAIN)
2654 : {
2655 : struct timeval tv;
2656 :
2657 0 : tv.tv_sec = 0;
2658 0 : tv.tv_usec = 50000;
2659 0 : my_select (0, NULL, NULL, NULL, &tv);
2660 0 : goto again;
2661 : }
2662 0 : }
2663 : #endif /*HTTP_USE_GNUTLS*/
2664 :
2665 : /* Close handler for estream. */
2666 : static int
2667 0 : cookie_close (void *cookie)
2668 : {
2669 0 : cookie_t c = cookie;
2670 :
2671 0 : if (!c)
2672 0 : return 0;
2673 :
2674 : #ifdef HTTP_USE_GNUTLS
2675 0 : if (c->use_tls && c->session && c->session->tls_session)
2676 0 : my_socket_unref (c->sock, send_gnutls_bye, c->session->tls_session);
2677 : else
2678 : #endif /*HTTP_USE_GNUTLS*/
2679 0 : if (c->sock)
2680 0 : my_socket_unref (c->sock, NULL, NULL);
2681 :
2682 0 : if (c->session)
2683 0 : http_session_unref (c->session);
2684 0 : xfree (c);
2685 0 : return 0;
2686 : }
2687 :
2688 :
2689 :
2690 :
2691 : /* Verify the credentials of the server. Returns 0 on success and
2692 : store the result in the session object. */
2693 : gpg_error_t
2694 0 : http_verify_server_credentials (http_session_t sess)
2695 : {
2696 : #if HTTP_USE_NTBTLS
2697 : (void)sess;
2698 : return 0; /* FIXME!! */
2699 : #elif HTTP_USE_GNUTLS
2700 : static const char const errprefix[] = "TLS verification of peer failed";
2701 : int rc;
2702 : unsigned int status;
2703 : const char *hostname;
2704 : const gnutls_datum_t *certlist;
2705 : unsigned int certlistlen;
2706 : gnutls_x509_crt_t cert;
2707 0 : gpg_error_t err = 0;
2708 :
2709 0 : sess->verify.done = 1;
2710 0 : sess->verify.status = 0;
2711 0 : sess->verify.rc = GNUTLS_E_CERTIFICATE_ERROR;
2712 :
2713 0 : if (gnutls_certificate_type_get (sess->tls_session) != GNUTLS_CRT_X509)
2714 : {
2715 0 : log_error ("%s: %s\n", errprefix, "not an X.509 certificate");
2716 0 : sess->verify.rc = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;
2717 0 : return gpg_error (GPG_ERR_GENERAL);
2718 : }
2719 :
2720 0 : rc = gnutls_certificate_verify_peers2 (sess->tls_session, &status);
2721 0 : if (rc)
2722 : {
2723 0 : log_error ("%s: %s\n", errprefix, gnutls_strerror (rc));
2724 0 : if (!err)
2725 0 : err = gpg_error (GPG_ERR_GENERAL);
2726 : }
2727 0 : else if (status)
2728 : {
2729 0 : log_error ("%s: status=0x%04x\n", errprefix, status);
2730 : #if GNUTLS_VERSION_NUMBER >= 0x030104
2731 : {
2732 : gnutls_datum_t statusdat;
2733 :
2734 0 : if (!gnutls_certificate_verification_status_print
2735 : (status, GNUTLS_CRT_X509, &statusdat, 0))
2736 : {
2737 0 : log_info ("%s: %s\n", errprefix, statusdat.data);
2738 0 : gnutls_free (statusdat.data);
2739 : }
2740 : }
2741 : #endif /*gnutls >= 3.1.4*/
2742 :
2743 0 : sess->verify.status = status;
2744 0 : if (!err)
2745 0 : err = gpg_error (GPG_ERR_GENERAL);
2746 : }
2747 :
2748 0 : hostname = sess->servername;
2749 0 : if (!hostname || !strchr (hostname, '.'))
2750 : {
2751 0 : log_error ("%s: %s\n", errprefix, "hostname missing");
2752 0 : if (!err)
2753 0 : err = gpg_error (GPG_ERR_GENERAL);
2754 : }
2755 :
2756 0 : certlist = gnutls_certificate_get_peers (sess->tls_session, &certlistlen);
2757 0 : if (!certlistlen)
2758 : {
2759 0 : log_error ("%s: %s\n", errprefix, "server did not send a certificate");
2760 0 : if (!err)
2761 0 : err = gpg_error (GPG_ERR_GENERAL);
2762 :
2763 : /* Need to stop here. */
2764 0 : if (err)
2765 0 : return err;
2766 : }
2767 :
2768 0 : rc = gnutls_x509_crt_init (&cert);
2769 0 : if (rc < 0)
2770 : {
2771 0 : if (!err)
2772 0 : err = gpg_error (GPG_ERR_GENERAL);
2773 0 : if (err)
2774 0 : return err;
2775 : }
2776 :
2777 0 : rc = gnutls_x509_crt_import (cert, &certlist[0], GNUTLS_X509_FMT_DER);
2778 0 : if (rc < 0)
2779 : {
2780 0 : log_error ("%s: %s: %s\n", errprefix, "error importing certificate",
2781 : gnutls_strerror (rc));
2782 0 : if (!err)
2783 0 : err = gpg_error (GPG_ERR_GENERAL);
2784 : }
2785 :
2786 0 : if (!gnutls_x509_crt_check_hostname (cert, hostname))
2787 : {
2788 0 : log_error ("%s: %s\n", errprefix, "hostname does not match");
2789 0 : if (!err)
2790 0 : err = gpg_error (GPG_ERR_GENERAL);
2791 : }
2792 :
2793 0 : gnutls_x509_crt_deinit (cert);
2794 :
2795 0 : if (!err)
2796 0 : sess->verify.rc = 0;
2797 :
2798 0 : if (sess->cert_log_cb)
2799 : {
2800 : const void *bufarr[10];
2801 : size_t buflenarr[10];
2802 : size_t n;
2803 :
2804 0 : for (n = 0; n < certlistlen && n < DIM (bufarr)-1; n++)
2805 : {
2806 0 : bufarr[n] = certlist[n].data;
2807 0 : buflenarr[n] = certlist[n].size;
2808 : }
2809 0 : bufarr[n] = NULL;
2810 0 : buflenarr[n] = 0;
2811 0 : sess->cert_log_cb (sess, err, hostname, bufarr, buflenarr);
2812 : }
2813 :
2814 0 : return err;
2815 : #else /*!HTTP_USE_GNUTLS*/
2816 : (void)sess;
2817 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
2818 : #endif
2819 : }
2820 :
2821 : /* Return the first query variable with the specified key. If there
2822 : is no such variable, return NULL. */
2823 : struct uri_tuple_s *
2824 0 : uri_query_lookup (parsed_uri_t uri, const char *key)
2825 : {
2826 : struct uri_tuple_s *t;
2827 :
2828 0 : for (t = uri->query; t; t = t->next)
2829 0 : if (strcmp (t->name, key) == 0)
2830 0 : return t;
2831 :
2832 0 : return NULL;
2833 : }
|