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