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