From 8b8925a2bdbb12dd537dde20a27cdb1416c2f1ae Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 16 Jul 2010 13:19:45 +0000 Subject: [PATCH] Some work on porting dirmngr (unfinished) Ported gpgtar to W32. --- autogen.sh | 4 +- common/ChangeLog | 29 + common/b64enc.c | 146 ++- common/estream.c | 16 +- common/http.c | 173 ++- common/http.h | 10 +- common/util.h | 6 + dirmngr/ChangeLog | 23 + dirmngr/Makefile.am | 4 +- dirmngr/b64dec.c | 217 ---- dirmngr/b64enc.c | 213 ---- dirmngr/cdblib.c | 54 +- dirmngr/certcache.c | 8 +- dirmngr/crlcache.c | 237 ++-- dirmngr/crlcache.h | 2 +- dirmngr/crlfetch.c | 3 +- dirmngr/dirmngr-client.c | 2 +- dirmngr/dirmngr-err.h | 12 + dirmngr/dirmngr.c | 95 +- dirmngr/dirmngr.h | 6 +- dirmngr/dirmngr_ldap.c | 24 +- dirmngr/http.c | 1863 ------------------------------- dirmngr/http.h | 109 -- dirmngr/ocsp.c | 6 +- dirmngr/server.c | 2 +- doc/gpg.texi | 11 +- scripts/gpg-w32-dev/GNUmakefile | 2 +- tools/ChangeLog | 8 + tools/Makefile.am | 3 +- tools/gpgtar-create.c | 258 ++++- tools/gpgtar-extract.c | 84 +- tools/gpgtar-list.c | 3 +- tools/gpgtar.c | 20 +- tools/gpgtar.h | 3 +- 34 files changed, 865 insertions(+), 2791 deletions(-) delete mode 100644 dirmngr/b64dec.c delete mode 100644 dirmngr/b64enc.c create mode 100644 dirmngr/dirmngr-err.h delete mode 100644 dirmngr/http.c delete mode 100644 dirmngr/http.h diff --git a/autogen.sh b/autogen.sh index 5dc8669e6..ab4c7dad8 100755 --- a/autogen.sh +++ b/autogen.sh @@ -103,13 +103,13 @@ if [ "$myhost" = "w32" ]; then w32root="$w32ce_root" [ -z "$w32root" ] && w32root="$HOME/w32ce_root" toolprefixes="$w32ce_toolprefixes arm-mingw32ce" - extraoptions="--disable-scdaemon --disable-zip --disable-ldap --disable-dirmngr $w32ce_extraoptions" + extraoptions="--disable-scdaemon --disable-zip $w32ce_extraoptions" ;; *) [ -z "$w32root" ] && w32root="$HOME/w32root" toolprefixes="$w32_toolprefixes i586-mingw32msvc" toolprefixes="$toolprefixes i386-mingw32msvc mingw32" - extraoptions="$w32_extraoptions" + extraoptions="--enable-gpgtar $w32_extraoptions" ;; esac echo "Using $w32root as standard install directory" >&2 diff --git a/common/ChangeLog b/common/ChangeLog index dd8c0a3a2..ae928ad9b 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,32 @@ +2010-07-16 Werner Koch + + * http.h (HTTP_FLAG_IGNORE_CL): Add flag . + * http.c (WITHOUT_GNU_PTH): Test macro for Pth support. + (http_parse_uri): s/xcalloc/xtrycalloc/. + (send_request): Replace of discrete allocation and sprintf by + xtryasprintf. + (http_wait_response): Replace HTTP_FLAG_NO_SHUTDOWN by + HTTP_FLAG_SHUTDOWN to change the default to no shutdown. + (cookie_read) [HAVE_PTH]: Use pth_read. + (longcounter_t): New. + (struct cookie_s): Add support for content length. Turn flag + fields into bit types. + (parse_response): Parse content length header. + (cookie_read): Take care of the content length. + +2010-07-08 Werner Koch + + * estream.c (estream_functions_file): Remove and replace by + identical estream_functions_fd. + +2010-07-06 Werner Koch + + * util.h (b64state): Add field STREAM. + * b64enc.c (b64enc_start): Factor code out to .. + (enc_start): new. + (b64enc_start_es, my_fputs): New. + (b64enc_write, b64enc_finish): Support estream. + 2010-06-24 Werner Koch * asshelp.c (lock_agent_spawning) [W32]: Use CreateMutexW. diff --git a/common/b64enc.c b/common/b64enc.c index 4722bd1e1..1e277f4cb 100644 --- a/common/b64enc.c +++ b/common/b64enc.c @@ -1,5 +1,5 @@ /* b64enc.c - Simple Base64 encoder. - * Copyright (C) 2001, 2003, 2004, 2008 Free Software Foundation, Inc. + * Copyright (C) 2001, 2003, 2004, 2008, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -136,20 +136,13 @@ static const u32 crc_table[256] = { }; -/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL - and not an empty string, this string will be used as the title for - the armor lines, with TITLE being an empty string, we don't write - the header lines and furthermore even don't write any linefeeds. - If TITLE starts with "PGP " the OpenPGP CRC checksum will be - written as well. With TITLE beeing NULL, we merely don't write - header but make sure that lines are not too long. Note, that we - don't write any output unless at least one byte get written using - b64enc_write. */ -gpg_error_t -b64enc_start (struct b64state *state, FILE *fp, const char *title) +static gpg_error_t +enc_start (struct b64state *state, FILE *fp, estream_t stream, + const char *title) { memset (state, 0, sizeof *state); state->fp = fp; + state->stream = stream; if (title && !*title) state->flags |= B64ENC_NO_LINEFEEDS; else if (title) @@ -167,6 +160,39 @@ b64enc_start (struct b64state *state, FILE *fp, const char *title) } +/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL + and not an empty string, this string will be used as the title for + the armor lines, with TITLE being an empty string, we don't write + the header lines and furthermore even don't write any linefeeds. + If TITLE starts with "PGP " the OpenPGP CRC checksum will be + written as well. With TITLE beeing NULL, we merely don't write + header but make sure that lines are not too long. Note, that we + don't write any output unless at least one byte get written using + b64enc_write. */ +gpg_error_t +b64enc_start (struct b64state *state, FILE *fp, const char *title) +{ + return enc_start (state, fp, NULL, title); +} + +/* Same as b64enc_start but takes an estream. */ +gpg_error_t +b64enc_start_es (struct b64state *state, estream_t fp, const char *title) +{ + return enc_start (state, NULL, fp, title); +} + + +static int +my_fputs (const char *string, struct b64state *state) +{ + if (state->stream) + return es_fputs (string, state->stream); + else + return fputs (string, state->fp); +} + + /* Write NBYTES from BUFFER to the Base 64 stream identified by STATE. With BUFFER and NBYTES being 0, merely do a fflush on the stream. */ @@ -176,13 +202,13 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes) unsigned char radbuf[4]; int idx, quad_count; const unsigned char *p; - FILE *fp = state->fp; if (!nbytes) { - if (buffer && fflush (fp)) - goto write_error; + if (buffer) + if (state->stream? es_fflush (state->stream) : fflush (state->fp)) + goto write_error; return 0; } @@ -190,12 +216,12 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes) { if (state->title) { - if ( fputs ("-----BEGIN ", fp) == EOF - || fputs (state->title, fp) == EOF - || fputs ("-----\n", fp) == EOF) + if ( my_fputs ("-----BEGIN ", state) == EOF + || my_fputs (state->title, state) == EOF + || my_fputs ("-----\n", state) == EOF) goto write_error; if ( (state->flags & B64ENC_USE_PGPCRC) - && fputs ("\n", fp) == EOF) + && my_fputs ("\n", state) == EOF) goto write_error; } @@ -228,16 +254,27 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes) tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; tmp[3] = bintoasc[radbuf[2]&077]; - for (idx=0; idx < 4; idx++) - putc (tmp[idx], fp); - idx = 0; - if (ferror (fp)) - goto write_error; + if (state->stream) + { + for (idx=0; idx < 4; idx++) + es_putc (tmp[idx], state->stream); + idx = 0; + if (es_ferror (state->stream)) + goto write_error; + } + else + { + for (idx=0; idx < 4; idx++) + putc (tmp[idx], state->fp); + idx = 0; + if (ferror (state->fp)) + goto write_error; + } if (++quad_count >= (64/4)) { quad_count = 0; if (!(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) + && my_fputs ("\n", state) == EOF) goto write_error; } } @@ -251,20 +288,19 @@ b64enc_write (struct b64state *state, const void *buffer, size_t nbytes) return gpg_error_from_syserror (); } + gpg_error_t b64enc_finish (struct b64state *state) { gpg_error_t err = 0; unsigned char radbuf[4]; int idx, quad_count; - FILE *fp; char tmp[4]; if (!(state->flags & B64ENC_DID_HEADER)) goto cleanup; /* Flush the base64 encoding */ - fp = state->fp; idx = state->idx; quad_count = state->quad_count; assert (idx < 4); @@ -285,17 +321,28 @@ b64enc_finish (struct b64state *state) tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077]; tmp[3] = '='; } - for (idx=0; idx < 4; idx++) - putc (tmp[idx], fp); - idx = 0; - if (ferror (fp)) - goto write_error; - + if (state->stream) + { + for (idx=0; idx < 4; idx++) + es_putc (tmp[idx], state->stream); + idx = 0; + if (es_ferror (state->stream)) + goto write_error; + } + else + { + for (idx=0; idx < 4; idx++) + putc (tmp[idx], state->fp); + idx = 0; + if (ferror (state->fp)) + goto write_error; + } + if (++quad_count >= (64/4)) { quad_count = 0; if (!(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) + && my_fputs ("\n", state) == EOF) goto write_error; } } @@ -303,13 +350,13 @@ b64enc_finish (struct b64state *state) /* Finish the last line and write the trailer. */ if (quad_count && !(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) + && my_fputs ("\n", state) == EOF) goto write_error; if ( (state->flags & B64ENC_USE_PGPCRC) ) { /* Write the CRC. */ - putc ('=', fp); + my_fputs ("=", state); radbuf[0] = state->crc >>16; radbuf[1] = state->crc >> 8; radbuf[2] = state->crc; @@ -317,20 +364,30 @@ b64enc_finish (struct b64state *state) tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; tmp[3] = bintoasc[radbuf[2]&077]; - for (idx=0; idx < 4; idx++) - putc (tmp[idx], fp); - if (ferror (fp)) - goto write_error; + if (state->stream) + { + for (idx=0; idx < 4; idx++) + es_putc (tmp[idx], state->stream); + if (es_ferror (state->stream)) + goto write_error; + } + else + { + for (idx=0; idx < 4; idx++) + putc (tmp[idx], state->fp); + if (ferror (state->fp)) + goto write_error; + } if (!(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) + && my_fputs ("\n", state) == EOF) goto write_error; } if (state->title) { - if ( fputs ("-----END ", fp) == EOF - || fputs (state->title, fp) == EOF - || fputs ("-----\n", fp) == EOF) + if ( my_fputs ("-----END ", state) == EOF + || my_fputs (state->title, state) == EOF + || my_fputs ("-----\n", state) == EOF) goto write_error; } @@ -346,6 +403,7 @@ b64enc_finish (struct b64state *state) state->title = NULL; } state->fp = NULL; + state->stream = NULL; return err; } diff --git a/common/estream.c b/common/estream.c index bf7955d06..3ab68b5ff 100644 --- a/common/estream.c +++ b/common/estream.c @@ -994,7 +994,7 @@ es_func_fp_seek (void *cookie, off_t *offset, int whence) return 0; } -/* Destroy function for fd objects. */ +/* Destroy function for FILE* objects. */ static int es_func_fp_destroy (void *cookie) { @@ -1076,14 +1076,6 @@ es_func_file_create (void **cookie, int *filedes, return err; } -static es_cookie_io_functions_t estream_functions_file = - { - es_func_fd_read, - es_func_fd_write, - es_func_fd_seek, - es_func_fd_destroy - }; - static int es_convert_mode (const char *mode, unsigned int *modeflags) @@ -2197,7 +2189,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) goto out; create_called = 1; - err = es_create (&stream, cookie, fd, estream_functions_file, modeflags, 0); + err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0); if (err) goto out; @@ -2207,7 +2199,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) out: if (err && create_called) - (*estream_functions_file.func_close) (cookie); + (*estream_functions_fd.func_close) (cookie); return stream; } @@ -2519,7 +2511,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode, goto leave; create_called = 1; - es_initialize (stream, cookie, fd, estream_functions_file, modeflags); + es_initialize (stream, cookie, fd, estream_functions_fd, modeflags); leave: diff --git a/common/http.c b/common/http.c index bb39768e4..ab159e28e 100644 --- a/common/http.c +++ b/common/http.c @@ -1,6 +1,6 @@ /* http.c - HTTP protocol handler * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, - * 2009 Free Software Foundation, Inc. + * 2009, 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -57,6 +57,16 @@ # include #endif /*!HAVE_W32_SYSTEM*/ +#ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth. */ +# undef HAVE_PTH +# undef USE_GNU_PTH +#endif + +#ifdef HAVE_PTH +# include +#endif + + #ifdef HTTP_USE_GNUTLS # include /* For non-understandable reasons GNUTLS dropped the _t suffix from @@ -75,13 +85,13 @@ typedef gnutls_transport_ptr gnutls_transport_ptr_t; #include "i18n.h" #include "http.h" #ifdef USE_DNS_SRV -#include "srv.h" +# include "srv.h" #else /*!USE_DNS_SRV*/ -/* If we are not compiling with SRV record support we provide stub - data structures. */ -#ifndef MAXDNAME -#define MAXDNAME 1025 -#endif + /* If we are not compiling with SRV record support we provide stub + data structures. */ +# ifndef MAXDNAME +# define MAXDNAME 1025 +# endif struct srventry { unsigned short priority; @@ -110,6 +120,15 @@ struct srventry "01234567890@" \ "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" +/* A long counter type. */ +#ifdef HAVE_STRTOULL +typedef unsigned long long longcounter_t; +# define counter_strtoul(a) strtoull ((a), NULL, 10) +#else +typedef unsigned long longcounter_t; +# define counter_strtoul(a) strtoul ((a), NULL, 10) +#endif + /* Define a prefix to map stream functions to the estream library. */ #ifdef HTTP_USE_ESTREAM #define P_ES(a) es_ ## a @@ -152,9 +171,19 @@ static es_cookie_io_functions_t cookie_functions = struct cookie_s { - int fd; /* File descriptor or -1 if already closed. */ - gnutls_session_t tls_session; /* TLS session context or NULL if not used. */ - int keep_socket; /* Flag to communicate with teh close handler. */ + /* File descriptor or -1 if already closed. */ + int fd; + + /* TLS session context or NULL if not used. */ + gnutls_session_t tls_session; + + /* The remaining content length and a flag telling whether to use + the content length. */ + longcounter_t content_length; + unsigned int content_length_valid:1; + + /* Flag to communicate with the close handler. */ + unsigned int keep_socket:1; }; typedef struct cookie_s *cookie_t; @@ -180,17 +209,18 @@ struct http_context_s { unsigned int status_code; int sock; - int in_data; + unsigned int in_data:1; + unsigned int is_http_0_9:1; #ifdef HTTP_USE_ESTREAM estream_t fp_read; estream_t fp_write; void *write_cookie; + void *read_cookie; #else /*!HTTP_USE_ESTREAM*/ FILE *fp_read; FILE *fp_write; #endif /*!HTTP_USE_ESTREAM*/ void *tls_context; - int is_http_0_9; parsed_uri_t uri; http_req_t req_type; char *buffer; /* Line buffer. */ @@ -417,7 +447,10 @@ http_wait_response (http_t hd) hd->write_cookie = NULL; #endif - if (!(hd->flags & HTTP_FLAG_NO_SHUTDOWN)) + /* Shutdown one end of the socket is desired. As per HTTP/1.0 this + is not required but some very old servers (e.g. the original pksd + key server didn't worked without it. */ + if ((hd->flags & HTTP_FLAG_SHUTDOWN)) shutdown (hd->sock, 1); hd->in_data = 0; @@ -537,7 +570,9 @@ http_get_status_code (http_t hd) gpg_error_t http_parse_uri (parsed_uri_t * ret_uri, const char *uri) { - *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri)); + *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri)); + if (!*ret_uri) + return gpg_error_from_syserror (); strcpy ((*ret_uri)->buffer, uri); return do_parse_uri (*ret_uri, 0); } @@ -980,29 +1015,16 @@ send_request (http_t hd, const char *auth, if (!p) return gpg_error_from_syserror (); - request = xtrymalloc (2 * strlen (server) - + strlen (p) - + (authstr?strlen(authstr):0) - + (proxy_authstr?strlen(proxy_authstr):0) - + 100); - if (!request) - { - err = gpg_error_from_syserror (); - xfree (p); - xfree (authstr); - xfree (proxy_authstr); - return err; - } - if (http_proxy && *http_proxy) { - sprintf (request, "%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD ? "HEAD" : - hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - server, port, *p == '/' ? "" : "/", p, - authstr ? authstr : "", - proxy_authstr ? proxy_authstr : ""); + request = xtryasprintf + ("%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s", + hd->req_type == HTTP_REQ_GET ? "GET" : + hd->req_type == HTTP_REQ_HEAD ? "HEAD" : + hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", + server, port, *p == '/' ? "" : "/", p, + authstr ? authstr : "", + proxy_authstr ? proxy_authstr : ""); } else { @@ -1011,16 +1033,24 @@ send_request (http_t hd, const char *auth, if (port == 80) *portstr = 0; else - sprintf (portstr, ":%u", port); + snprintf (portstr, sizeof portstr, ":%u", port); - sprintf (request, "%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD ? "HEAD" : - hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - *p == '/' ? "" : "/", p, server, portstr, - authstr? authstr:""); + request = xtryasprintf + ("%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s", + hd->req_type == HTTP_REQ_GET ? "GET" : + hd->req_type == HTTP_REQ_HEAD ? "HEAD" : + hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", + *p == '/' ? "" : "/", p, server, portstr, + authstr? authstr:""); } xfree (p); + if (!request) + { + err = gpg_error_from_syserror (); + xfree (authstr); + xfree (proxy_authstr); + return err; + } #ifdef HTTP_USE_ESTREAM @@ -1072,18 +1102,16 @@ send_request (http_t hd, const char *auth, function and only then assign a stdio stream. This allows for better error reporting that through standard stdio means. */ err = write_server (hd->sock, request, strlen (request)); - - if(err==0) - for(;headers;headers=headers->next) + if (!err) + for (;headers;headers=headers->next) { - err = write_server( hd->sock, headers->d, strlen(headers->d) ); - if(err) + err = write_server (hd->sock, headers->d, strlen(headers->d)); + if (err) break; - err = write_server( hd->sock, "\r\n", 2 ); - if(err) + err = write_server (hd->sock, "\r\n", 2); + if (err) break; } - if (!err) { hd->fp_write = fdopen (hd->sock, "w"); @@ -1351,9 +1379,7 @@ store_header (http_t hd, char *line) is valid as along as HD has not been closed and no othe request has been send. If the header was not found, NULL is returned. Name must be canonicalized, that is the first letter of each dash - delimited part must be uppercase and all other letters lowercase. - Note that the context must have been opened with the - HTTP_FLAG_NEED_HEADER. */ + delimited part must be uppercase and all other letters lowercase. */ const char * http_get_header (http_t hd, const char *name) { @@ -1376,6 +1402,8 @@ parse_response (http_t hd) { char *line, *p, *p2; size_t maxlen, len; + cookie_t cookie = hd->read_cookie; + const char *s; /* Delete old header lines. */ while (hd->headers) @@ -1447,7 +1475,7 @@ parse_response (http_t hd) if ( (hd->flags & HTTP_FLAG_LOG_RESP) ) log_info ("RESP: `%.*s'\n", (int)strlen(line)-(*line&&line[1]?2:0),line); - if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line ) + if (*line) { gpg_error_t err = store_header (hd, line); if (err) @@ -1456,6 +1484,17 @@ parse_response (http_t hd) } while (len && *line); + cookie->content_length_valid = 0; + if (!(hd->flags & HTTP_FLAG_IGNORE_CL)) + { + s = http_get_header (hd, "Content-Length"); + if (s) + { + cookie->content_length_valid = 1; + cookie->content_length = counter_strtoul (s); + } + } + return 0; } @@ -1601,6 +1640,7 @@ connect_server (const char *server, unsigned short port, } } #else + (void)flags; (void)srvtag; #endif /*USE_DNS_SRV*/ @@ -1739,6 +1779,7 @@ write_server (int sock, const char *data, size_t length) { int nleft; + /* FIXME: We would better use pth I/O functions. */ nleft = length; while (nleft > 0) { @@ -1787,6 +1828,14 @@ cookie_read (void *cookie, void *buffer, size_t size) cookie_t c = cookie; int nread; + if (c->content_length_valid) + { + if (!c->content_length) + return 0; /* EOF */ + if (c->content_length < size) + size = c->content_length; + } + #ifdef HTTP_USE_GNUTLS if (c->tls_session) { @@ -1817,7 +1866,9 @@ cookie_read (void *cookie, void *buffer, size_t size) { do { -#ifdef HAVE_W32_SYSTEM +#ifdef HAVE_PTH + nread = pth_read (c->fd, buffer, size); +#elif defined(HAVE_W32_SYSTEM) /* Under Windows we need to use recv for a socket. */ nread = recv (c->fd, buffer, size, 0); #else @@ -1827,6 +1878,14 @@ cookie_read (void *cookie, void *buffer, size_t size) while (nread == -1 && errno == EINTR); } + if (c->content_length_valid && nread > 0) + { + if (nread < c->content_length) + c->content_length -= nread; + else + c->content_length = 0; + } + return nread; } @@ -2028,9 +2087,7 @@ main (int argc, char **argv) http_release_parsed_uri (uri); uri = NULL; - rc = http_open_document (&hd, *argv, NULL, - HTTP_FLAG_NO_SHUTDOWN | HTTP_FLAG_NEED_HEADER, - NULL, tls_session); + rc = http_open_document (&hd, *argv, NULL, 0, NULL, tls_session); if (rc) { log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc)); diff --git a/common/http.h b/common/http.h index e7120f561..b00d87a3f 100644 --- a/common/http.h +++ b/common/http.h @@ -1,6 +1,6 @@ /* http.h - HTTP protocol handler - * Copyright (C) 1999, 2000, 2001, 2003, - * 2006 Free Software Foundation, Inc. + * Copyright (C) 1999, 2000, 2001, 2003, 2006, + * 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -62,9 +62,9 @@ http_req_t; enum { HTTP_FLAG_TRY_PROXY = 1, - HTTP_FLAG_NO_SHUTDOWN = 2, - HTTP_FLAG_LOG_RESP = 4, - HTTP_FLAG_NEED_HEADER = 8 + HTTP_FLAG_SHUTDOWN = 2, + HTTP_FLAG_LOG_RESP = 8, + HTTP_FLAG_IGNORE_CL = 32 }; struct http_context_s; diff --git a/common/util.h b/common/util.h index 2735cef3d..fdea333b5 100644 --- a/common/util.h +++ b/common/util.h @@ -27,6 +27,9 @@ #ifndef GPG_ERR_MISSING_KEY #define GPG_ERR_MISSING_KEY 181 #endif +#ifndef GPG_ERR_LIMIT_REACHED +#define GPG_ERR_LIMIT_REACHED 183 +#endif /* Hash function used with libksba. */ #define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write) @@ -128,6 +131,7 @@ struct b64state int idx; int quad_count; FILE *fp; + estream_t stream; char *title; unsigned char radbuf[4]; u32 crc; @@ -136,6 +140,8 @@ struct b64state }; gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title); +gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp, + const char *title); gpg_error_t b64enc_write (struct b64state *state, const void *buffer, size_t nbytes); gpg_error_t b64enc_finish (struct b64state *state); diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog index c6db553de..c95a2f2d6 100644 --- a/dirmngr/ChangeLog +++ b/dirmngr/ChangeLog @@ -1,3 +1,26 @@ +2010-07-16 Werner Koch + + * http.c, http.h: Remove. + + * dirmngr-err.h: New. + * dirmngr.h: Include dirmngr-err.h instead of gpg-error.h + + * cdblib.c: Replace assignments to ERRNO by a call to + gpg_err_set_errno. Include dirmngr-err.h. + (cdb_free) [__MINGW32CE__]: Do not use get_osfhandle. + + * dirmngr.c [!HAVE_SIGNAL_H]: Don't include signal.h. + (USE_W32_SERVICE): New. Use this to control the use of the W32 + service system. + +2010-07-06 Werner Koch + + * dirmngr.c (main): Print note on directory name changes. + + Replace almost all uses of stdio by estream. + + * b64dec.c, b64enc.c: Remove. They are duplicated in ../common/. + 2010-06-28 Werner Koch * dirmngr_ldap.c (my_i18n_init): Remove. diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am index 7fbff02ff..537bdf035 100644 --- a/dirmngr/Makefile.am +++ b/dirmngr/Makefile.am @@ -38,7 +38,7 @@ noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \ ldapserver.h ldapserver.c certcache.c certcache.h \ - b64dec.c cdb.h cdblib.c ldap.c http.c http.h misc.c \ + cdb.h cdblib.c ldap.c misc.c dirmngr-err.h \ ocsp.c ocsp.h validate.c validate.h dirmngr_LDADD = $(libcommonpth) ../gl/libgnu.a $(DNSLIBS) $(LIBASSUAN_LIBS) \ @@ -56,7 +56,7 @@ dirmngr_ldap_LDFLAGS = dirmngr_ldap_LDADD = $(libcommon) ../gl/libgnu.a $(DNSLIBS) \ $(GPG_ERROR_LIBS) $(LDAPLIBS) $(LIBINTL) $(LIBICONV) -dirmngr_client_SOURCES = dirmngr-client.c b64enc.c no-libgcrypt.c +dirmngr_client_SOURCES = dirmngr-client.c no-libgcrypt.c dirmngr_client_LDADD = $(libcommon) ../gl/libgnu.a $(LIBASSUAN_LIBS) \ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) diff --git a/dirmngr/b64dec.c b/dirmngr/b64dec.c deleted file mode 100644 index af223aef2..000000000 --- a/dirmngr/b64dec.c +++ /dev/null @@ -1,217 +0,0 @@ -/* b64dec.c - Simple Base64 decoder. - * Copyright (C) 2008 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include "i18n.h" -#include "util.h" - - -/* The reverse base-64 list used for base-64 decoding. */ -static unsigned char const asctobin[128] = - { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff - }; - -enum decoder_states - { - s_init, s_idle, s_lfseen, s_begin, - s_b64_0, s_b64_1, s_b64_2, s_b64_3, - s_waitendtitle, s_waitend - }; - - - -/* Initialize the context for the base64 decoder. If TITLE is NULL a - plain base64 decoding is done. If it is the empty string the - decoder will skip everything until a "-----BEGIN " line has been - seen, decoding ends at a "----END " line. - - Not yet implemented: If TITLE is either "PGP" or begins with "PGP " - the PGP armor lines are skipped as well. */ -gpg_error_t -b64dec_start (struct b64state *state, const char *title) -{ - memset (state, 0, sizeof *state); - if (title) - { - if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' ')) - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); - - state->title = xtrystrdup (title); - if (!state->title) - return gpg_error_from_syserror (); - state->idx = s_init; - } - else - state->idx = s_b64_0; - return 0; -} - - -/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the - new length of the buffer at R_NBYTES. */ -gpg_error_t -b64dec_proc (struct b64state *state, void *buffer, size_t length, - size_t *r_nbytes) -{ - enum decoder_states ds = state->idx; - unsigned char val = state->radbuf[0]; - int pos = state->quad_count; - char *d, *s; - - if (state->stop_seen) - { - *r_nbytes = 0; - return gpg_error (GPG_ERR_EOF); - } - - for (s=d=buffer; length && !state->stop_seen; length--, s++) - { - switch (ds) - { - case s_idle: - if (*s == '\n') - { - ds = s_lfseen; - pos = 0; - } - break; - case s_init: - ds = s_lfseen; - case s_lfseen: - if (*s != "-----BEGIN "[pos]) - ds = s_idle; - else if (pos == 10) - ds = s_begin; - else - pos++; - break; - case s_begin: - if (*s == '\n') - ds = s_b64_0; - break; - case s_b64_0: - case s_b64_1: - case s_b64_2: - case s_b64_3: - { - int c; - - if (*s == '-' && state->title) - { - /* Not a valid Base64 character: assume end - header. */ - ds = s_waitend; - } - else if (*s == '=') - { - /* Pad character: stop */ - if (ds == s_b64_1) - *d++ = val; - ds = state->title? s_waitendtitle : s_waitend; - } - else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t') - ; /* Skip white spaces. */ - else if ( (*s & 0x80) - || (c = asctobin[*(unsigned char *)s]) == 255) - { - /* Skip invalid encodings. */ - state->invalid_encoding = 1; - } - else if (ds == s_b64_0) - { - val = c << 2; - ds = s_b64_1; - } - else if (ds == s_b64_1) - { - val |= (c>>4)&3; - *d++ = val; - val = (c<<4)&0xf0; - ds = s_b64_2; - } - else if (ds == s_b64_2) - { - val |= (c>>2)&15; - *d++ = val; - val = (c<<6)&0xc0; - ds = s_b64_3; - } - else - { - val |= c&0x3f; - *d++ = val; - ds = s_b64_0; - } - } - break; - case s_waitendtitle: - if (*s == '-') - ds = s_waitend; - break; - case s_waitend: - if ( *s == '\n') - state->stop_seen = 1; - break; - default: - BUG(); - } - } - - - state->idx = ds; - state->radbuf[0] = val; - state->quad_count = pos; - *r_nbytes = (d -(char*) buffer); - return 0; -} - - -/* This function needs to be called before releasing the decoder - state. It may return an error code in case an encoding error has - been found during decoding. */ -gpg_error_t -b64dec_finish (struct b64state *state) -{ - xfree (state->title); - state->title = NULL; - return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0; -} - diff --git a/dirmngr/b64enc.c b/dirmngr/b64enc.c deleted file mode 100644 index 4429a8e75..000000000 --- a/dirmngr/b64enc.c +++ /dev/null @@ -1,213 +0,0 @@ -/* b64enc.c - Simple Base64 encoder. - * Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include - -#include "i18n.h" -#include "util.h" - -#define B64ENC_DID_HEADER 1 -#define B64ENC_DID_TRAILER 2 -#define B64ENC_NO_LINEFEEDS 16 - - -/* The base-64 character list */ -static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - -/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL - and not an empty string, this string will be used as the title for - the armor lines, with TITLE being an empty string, we don't write - the header lines and furthermore even don't write any linefeeds. - With TITLE beeing NULL, we merely don't write header but make sure - that lines are not too long. Note, that we don't write any output - unless at least one byte get written using b64enc_write. */ -gpg_error_t -b64enc_start (struct b64state *state, FILE *fp, const char *title) -{ - memset (state, 0, sizeof *state); - state->fp = fp; - if (title && !*title) - state->flags |= B64ENC_NO_LINEFEEDS; - else if (title) - { - state->title = strdup (title); - if (!state->title) - return gpg_error_from_errno (errno); - } - return 0; -} - - -/* Write NBYTES from BUFFER to the Base 64 stream identified by - STATE. With BUFFER and NBYTES being 0, merely do a fflush on the - stream. */ -gpg_error_t -b64enc_write (struct b64state *state, const void *buffer, size_t nbytes) -{ - unsigned char radbuf[4]; - int idx, quad_count; - const unsigned char *p; - FILE *fp = state->fp; - - - if (!nbytes) - { - if (buffer && fflush (fp)) - goto write_error; - return 0; - } - - if (!(state->flags & B64ENC_DID_HEADER)) - { - if (state->title) - { - if ( fputs ("-----BEGIN ", fp) == EOF - || fputs (state->title, fp) == EOF - || fputs ("-----\n", fp) == EOF) - goto write_error; - } - state->flags |= B64ENC_DID_HEADER; - } - - idx = state->idx; - quad_count = state->quad_count; - assert (idx < 4); - memcpy (radbuf, state->radbuf, idx); - - for (p=buffer; nbytes; p++, nbytes--) - { - radbuf[idx++] = *p; - if (idx > 2) - { - char tmp[4]; - - tmp[0] = bintoasc[(*radbuf >> 2) & 077]; - tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077]; - tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077]; - tmp[3] = bintoasc[radbuf[2]&077]; - for (idx=0; idx < 4; idx++) - putc (tmp[idx], fp); - idx = 0; - if (ferror (fp)) - goto write_error; - if (++quad_count >= (64/4)) - { - quad_count = 0; - if (!(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) - goto write_error; - } - } - } - memcpy (state->radbuf, radbuf, idx); - state->idx = idx; - state->quad_count = quad_count; - return 0; - - write_error: - return gpg_error_from_errno (errno); -} - -gpg_error_t -b64enc_finish (struct b64state *state) -{ - gpg_error_t err = 0; - unsigned char radbuf[4]; - int idx, quad_count; - FILE *fp; - - if (!(state->flags & B64ENC_DID_HEADER)) - goto cleanup; - - /* Flush the base64 encoding */ - fp = state->fp; - idx = state->idx; - quad_count = state->quad_count; - assert (idx < 4); - memcpy (radbuf, state->radbuf, idx); - - if (idx) - { - char tmp[4]; - - tmp[0] = bintoasc[(*radbuf>>2)&077]; - if (idx == 1) - { - tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077]; - tmp[2] = '='; - tmp[3] = '='; - } - else - { - tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077]; - tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077]; - tmp[3] = '='; - } - for (idx=0; idx < 4; idx++) - putc (tmp[idx], fp); - idx = 0; - if (ferror (fp)) - goto write_error; - - if (++quad_count >= (64/4)) - { - quad_count = 0; - if (!(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) - goto write_error; - } - } - - /* Finish the last line and write the trailer. */ - if (quad_count - && !(state->flags & B64ENC_NO_LINEFEEDS) - && fputs ("\n", fp) == EOF) - goto write_error; - - if (state->title) - { - if ( fputs ("-----END ", fp) == EOF - || fputs (state->title, fp) == EOF - || fputs ("-----\n", fp) == EOF) - goto write_error; - } - - goto cleanup; - - write_error: - err = gpg_error_from_errno (errno); - - cleanup: - if (state->title) - { - free (state->title); - state->title = NULL; - } - state->fp = NULL; - return err; -} - diff --git a/dirmngr/cdblib.c b/dirmngr/cdblib.c index de60fe926..16d53aed8 100644 --- a/dirmngr/cdblib.c +++ b/dirmngr/cdblib.c @@ -73,6 +73,8 @@ # endif #endif #include + +#include "dirmngr-err.h" #include "cdb.h" #ifndef EPROTO @@ -123,13 +125,17 @@ cdb_init(struct cdb *cdbp, int fd) return -1; /* trivial sanity check: at least toc should be here */ if (st.st_size < 2048) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } fsize = (unsigned)(st.st_size & 0xffffffffu); /* memory-map file */ #ifdef _WIN32 +# ifdef __MINGW32CE__ + hFile = fd; +# else hFile = (HANDLE) _get_osfhandle(fd); +#endif if (hFile == (HANDLE) -1) return -1; hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); @@ -177,7 +183,11 @@ cdb_free(struct cdb *cdbp) HANDLE hFile, hMapping; #endif #ifdef _WIN32 +#ifdef __MINGW32CE__ + hFile = cdbp->cdb_fd; +#else hFile = (HANDLE) _get_osfhandle(cdbp->cdb_fd); +#endif hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); UnmapViewOfFile((void*) cdbp->cdb_mem); CloseHandle(hMapping); @@ -199,7 +209,7 @@ int cdb_read(const struct cdb *cdbp, void *buf, unsigned len, cdbi_t pos) { if (pos > cdbp->cdb_fsize || cdbp->cdb_fsize - pos < len) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } memcpy(buf, cdbp->cdb_mem + pos, len); @@ -243,7 +253,7 @@ cdb_find(struct cdb *cdbp, const void *key, cdbi_t klen) || pos > cdbp->cdb_fsize /* htab start within file ? */ || httodo > cdbp->cdb_fsize - pos) /* entrie htab within file ? */ { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } @@ -258,19 +268,19 @@ cdb_find(struct cdb *cdbp, const void *key, cdbi_t klen) return 0; if (cdb_unpack(htp) == hval) { if (pos > cdbp->cdb_fsize - 8) { /* key+val lengths */ - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } if (cdb_unpack(cdbp->cdb_mem + pos) == klen) { if (cdbp->cdb_fsize - klen < pos + 8) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } if (memcmp(key, cdbp->cdb_mem + pos + 8, klen) == 0) { n = cdb_unpack(cdbp->cdb_mem + pos + 4); pos += 8 + klen; if (cdbp->cdb_fsize < n || cdbp->cdb_fsize - n < pos) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } cdbp->cdb_vpos = pos; @@ -331,7 +341,7 @@ cdb_findinit(struct cdb_find *cdbfp, struct cdb *cdbp, || pos > cdbp->cdb_fsize || cdbfp->cdb_httodo > cdbp->cdb_fsize - pos) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } @@ -368,12 +378,12 @@ cdb_findnext(struct cdb_find *cdbfp) cdbfp->cdb_httodo -= 8; if (n) { if (pos > cdbp->cdb_fsize - 8) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } if (cdb_unpack(cdbp->cdb_mem + pos) == cdbfp->cdb_klen) { if (cdbp->cdb_fsize - cdbfp->cdb_klen < pos + 8) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } if (memcmp(cdbfp->cdb_key, @@ -381,7 +391,7 @@ cdb_findnext(struct cdb_find *cdbfp) n = cdb_unpack(cdbp->cdb_mem + pos + 4); pos += 8 + cdbfp->cdb_klen; if (cdbp->cdb_fsize < n || cdbp->cdb_fsize - n < pos) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } cdbp->cdb_vpos = pos; @@ -410,7 +420,7 @@ cdb_findnext(struct cdb_find *cdbfp) || pos > cdbp->cdb_fsize || cdbfp->cdb_httodo > cdbp->cdb_fsize - pos) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } @@ -425,7 +435,7 @@ cdb_findnext(struct cdb_find *cdbfp) while (!pos); if (pos > cdbp->cdb_fsize - 8) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } @@ -436,7 +446,7 @@ cdb_findnext(struct cdb_find *cdbfp) n = 8 + cdbp->cdb_klen + cdbp->cdb_vlen; if ( pos > cdbp->cdb_fsize || pos > cdbp->cdb_fsize - n) { - errno = EPROTO; + gpg_err_set_errno (EPROTO); return -1; } return 1; /* Found. */ @@ -454,7 +464,7 @@ cdb_bread(int fd, void *buf, int len) while(l < 0 && errno == EINTR); if (l <= 0) { if (!l) - errno = EIO; + gpg_err_set_errno (EIO); return -1; } buf = (char*)buf + l; @@ -555,7 +565,7 @@ cdb_make_add(struct cdb_make *cdbmp, struct cdb_rl *rl; if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) || vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) { - errno = ENOMEM; + gpg_err_set_errno (ENOMEM); return -1; } hval = cdb_hash(key, klen); @@ -563,7 +573,7 @@ cdb_make_add(struct cdb_make *cdbmp, if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) { rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl)); if (!rl) { - errno = ENOMEM; + gpg_err_set_errno (ENOMEM); return -1; } rl->cnt = 0; @@ -603,7 +613,7 @@ cdb_make_put(struct cdb_make *cdbmp, return -1; if (c) { if (flags == CDB_PUT_INSERT) { - errno = EEXIST; + gpg_err_set_errno (EEXIST); return 1; } else if (flags == CDB_PUT_REPLACE) { @@ -621,7 +631,7 @@ cdb_make_put(struct cdb_make *cdbmp, if (!rl || rl->cnt >= sizeof(rl->rec)/sizeof(rl->rec[0])) { rl = (struct cdb_rl*)malloc(sizeof(struct cdb_rl)); if (!rl) { - errno = ENOMEM; + gpg_err_set_errno (ENOMEM); return -1; } rl->cnt = 0; @@ -633,13 +643,13 @@ cdb_make_put(struct cdb_make *cdbmp, break; default: - errno = EINVAL; + gpg_err_set_errno (EINVAL); return -1; } if (klen > 0xffffffff - (cdbmp->cdb_dpos + 8) || vlen > 0xffffffff - (cdbmp->cdb_dpos + klen + 8)) { - errno = ENOMEM; + gpg_err_set_errno (ENOMEM); return -1; } rl->rec[c].hval = hval; @@ -812,7 +822,7 @@ cdb_make_finish_internal(struct cdb_make *cdbmp) unsigned t, i; if (((0xffffffff - cdbmp->cdb_dpos) >> 3) < cdbmp->cdb_rcnt) { - errno = ENOMEM; + gpg_err_set_errno (ENOMEM); return -1; } @@ -837,7 +847,7 @@ cdb_make_finish_internal(struct cdb_make *cdbmp) /* allocate memory to hold max htable */ htab = (struct cdb_rec*)malloc((hsize + 2) * sizeof(struct cdb_rec)); if (!htab) { - errno = ENOENT; + gpg_err_set_errno (ENOENT); return -1; } p = (unsigned char *)htab; diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index c40bb17d0..46d2ac365 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -328,7 +328,7 @@ load_certs_from_dir (const char *dirname, int are_trusted) struct dirent *ep; char *p; size_t n; - FILE *fp; + estream_t fp; ksba_reader_t reader; ksba_cert_t cert; char *fname = NULL; @@ -353,7 +353,7 @@ load_certs_from_dir (const char *dirname, int are_trusted) xfree (fname); fname = make_filename (dirname, p, NULL); - fp = fopen (fname, "rb"); + fp = es_fopen (fname, "rb"); if (!fp) { log_error (_("can't open `%s': %s\n"), @@ -367,7 +367,7 @@ load_certs_from_dir (const char *dirname, int are_trusted) { log_error (_("can't setup KSBA reader: %s\n"), gpg_strerror (err)); ksba_reader_release (reader); - fclose (fp); + es_fclose (fp); continue; } @@ -375,7 +375,7 @@ load_certs_from_dir (const char *dirname, int are_trusted) if (!err) err = ksba_cert_read_der (cert, reader); ksba_reader_release (reader); - fclose (fp); + es_fclose (fp); if (err) { log_error (_("can't parse certificate `%s': %s\n"), diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 9ec5414fa..aeb6304b0 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -218,7 +218,7 @@ create_directory_if_needed (const char *name) log_error (_("error creating directory `%s': %s\n"), fname, strerror (errno)); xfree (fname); - errno = save_errno; + gpg_err_set_errno (save_errno); return -1; } } @@ -298,7 +298,7 @@ cleanup_cache_dir (int force) removed, the function will read the last line of a file, even if that is not terminated by a LF. */ static char * -next_line_from_file (FILE *fp, gpg_error_t *r_err) +next_line_from_file (estream_t fp, gpg_error_t *r_err) { char buf[300]; char *largebuf = NULL; @@ -311,7 +311,7 @@ next_line_from_file (FILE *fp, gpg_error_t *r_err) *r_err = 0; p = buf; buflen = sizeof buf - 1; - while ((c=getc (fp)) != EOF && c != '\n') + while ((c=es_getc (fp)) != EOF && c != '\n') { if (len >= buflen) { @@ -401,12 +401,12 @@ release_cache (crl_cache_t cache) /* Open the dir file FNAME or create a new one if it does not yet exist. */ -static FILE * +static estream_t open_dir_file (const char *fname) { - FILE *fp; + estream_t fp; - fp = fopen (fname, "r"); + fp = es_fopen (fname, "r"); if (!fp) { log_error (_("failed to open cache dir file `%s': %s\n"), @@ -416,22 +416,22 @@ open_dir_file (const char *fname) if (create_directory_if_needed (NULL) || create_directory_if_needed (DBDIR_D)) return NULL; - fp = fopen (fname, "w"); + fp = es_fopen (fname, "w"); if (!fp) { log_error (_("error creating new cache dir file `%s': %s\n"), fname, strerror (errno)); return NULL; } - fprintf (fp, "v:%d:\n", DBDIRVERSION); - if (ferror (fp)) + es_fprintf (fp, "v:%d:\n", DBDIRVERSION); + if (es_ferror (fp)) { log_error (_("error writing new cache dir file `%s': %s\n"), fname, strerror (errno)); - fclose (fp); + es_fclose (fp); return NULL; } - if (fclose (fp)) + if (es_fclose (fp)) { log_error (_("error closing new cache dir file `%s': %s\n"), fname, strerror (errno)); @@ -440,7 +440,7 @@ open_dir_file (const char *fname) log_info (_("new cache dir file `%s' created\n"), fname); - fp = fopen (fname, "r"); + fp = es_fopen (fname, "r"); if (!fp) { log_error (_("failed to re-open cache dir file `%s': %s\n"), @@ -454,13 +454,13 @@ open_dir_file (const char *fname) /* Helper for open_dir. */ static gpg_error_t -check_dir_version (FILE **fpadr, const char *fname, +check_dir_version (estream_t *fpadr, const char *fname, unsigned int *lineno, int cleanup_on_mismatch) { char *line; gpg_error_t lineerr = 0; - FILE *fp = *fpadr; + estream_t fp = *fpadr; int created = 0; retry: @@ -485,7 +485,7 @@ check_dir_version (FILE **fpadr, const char *fname, if (!created && cleanup_on_mismatch) { log_error (_("old version of cache directory - cleaning up\n")); - fclose (fp); + es_fclose (fp); *fpadr = NULL; if (!cleanup_cache_dir (1)) { @@ -521,7 +521,7 @@ open_dir (crl_cache_t *r_cache) char *fname; char *line = NULL; gpg_error_t lineerr = 0; - FILE *fp; + estream_t fp; crl_cache_entry_t entry, *entrytail; unsigned int lineno; gpg_error_t err = 0; @@ -649,7 +649,7 @@ open_dir (crl_cache_t *r_cache) log_error (_("error reading `%s': %s\n"), fname, gpg_strerror (err)); goto leave; } - if (ferror (fp)) + if (es_ferror (fp)) { log_error (_("error reading `%s': %s\n"), fname, strerror (errno)); err = gpg_error (GPG_ERR_CONFIGURATION); @@ -695,8 +695,7 @@ open_dir (crl_cache_t *r_cache) leave: - if (fp) - fclose (fp); + es_fclose (fp); xfree (line); xfree (fname); if (err) @@ -709,54 +708,54 @@ open_dir (crl_cache_t *r_cache) } static void -write_percented_string (const char *s, FILE *fp) +write_percented_string (const char *s, estream_t fp) { for (; *s; s++) if (*s == ':') - fputs ("%3A", fp); + es_fputs ("%3A", fp); else if (*s == '\n') - fputs ("%0A", fp); + es_fputs ("%0A", fp); else if (*s == '\r') - fputs ("%0D", fp); + es_fputs ("%0D", fp); else - putc (*s, fp); + es_putc (*s, fp); } static void -write_dir_line_crl (FILE *fp, crl_cache_entry_t e) +write_dir_line_crl (estream_t fp, crl_cache_entry_t e) { if (e->invalid) - fprintf (fp, "i%d", e->invalid); + es_fprintf (fp, "i%d", e->invalid); else if (e->user_trust_req) - putc ('u', fp); + es_putc ('u', fp); else - putc ('c', fp); - putc (':', fp); - fputs (e->issuer_hash, fp); - putc (':', fp); + es_putc ('c', fp); + es_putc (':', fp); + es_fputs (e->issuer_hash, fp); + es_putc (':', fp); write_percented_string (e->issuer, fp); - putc (':', fp); + es_putc (':', fp); write_percented_string (e->url, fp); - putc (':', fp); - fwrite (e->this_update, 15, 1, fp); - putc (':', fp); - fwrite (e->next_update, 15, 1, fp); - putc (':', fp); - fputs (e->dbfile_hash, fp); - putc (':', fp); + es_putc (':', fp); + es_fwrite (e->this_update, 15, 1, fp); + es_putc (':', fp); + es_fwrite (e->next_update, 15, 1, fp); + es_putc (':', fp); + es_fputs (e->dbfile_hash, fp); + es_putc (':', fp); if (e->crl_number) - fputs (e->crl_number, fp); - putc (':', fp); + es_fputs (e->crl_number, fp); + es_putc (':', fp); if (e->authority_issuer) write_percented_string (e->authority_issuer, fp); - putc (':', fp); + es_putc (':', fp); if (e->authority_serialno) - fputs (e->authority_serialno, fp); - putc (':', fp); + es_fputs (e->authority_serialno, fp); + es_putc (':', fp); if (e->check_trust_anchor && e->user_trust_req) - fputs (e->check_trust_anchor, fp); - putc ('\n', fp); + es_fputs (e->check_trust_anchor, fp); + es_putc ('\n', fp); } @@ -768,7 +767,8 @@ update_dir (crl_cache_t cache) char *tmpfname = NULL; char *line = NULL; gpg_error_t lineerr = 0; - FILE *fp, *fpout = NULL; + estream_t fp; + estream_t fpout = NULL; crl_cache_entry_t e; unsigned int lineno; gpg_error_t err = 0; @@ -781,7 +781,7 @@ update_dir (crl_cache_t cache) e->mark = 1; lineno = 0; - fp = fopen (fname, "r"); + fp = es_fopen (fname, "r"); if (!fp) { err = gpg_error_from_errno (errno); @@ -792,7 +792,7 @@ update_dir (crl_cache_t cache) err = check_dir_version (&fp, fname, &lineno, 0); if (err) goto leave; - rewind (fp); + es_rewind (fp); lineno = 0; /* Create a temporary DIR file. */ @@ -827,7 +827,7 @@ update_dir (crl_cache_t cache) tmpfname = make_filename (opt.homedir_cache, DBDIR_D, tmpbuf, NULL); xfree (tmpbuf); } - fpout = fopen (tmpfname, "w"); + fpout = es_fopen (tmpfname, "w"); if (!fpout) { err = gpg_error_from_errno (errno); @@ -868,30 +868,30 @@ update_dir (crl_cache_t cache) { /* We ignore entries we don't have in our cache because they may have been added in the meantime by other instances of dirmngr. */ - fprintf (fpout, "# Next line added by " - "another process; our pid is %lu\n", - (unsigned long)getpid ()); - fputs (line, fpout); - putc ('\n', fpout); + es_fprintf (fpout, "# Next line added by " + "another process; our pid is %lu\n", + (unsigned long)getpid ()); + es_fputs (line, fpout); + es_putc ('\n', fpout); } } else { - fputs ("# Invalid line detected: ", fpout); - fputs (line, fpout); - putc ('\n', fpout); + es_fputs ("# Invalid line detected: ", fpout); + es_fputs (line, fpout); + es_putc ('\n', fpout); } } else { /* Write out all non CRL lines as they are. */ - fputs (line, fpout); - putc ('\n', fpout); + es_fputs (line, fpout); + es_putc ('\n', fpout); } xfree (line); } - if (!ferror (fp) && !ferror (fpout) && !lineerr) + if (!es_ferror (fp) && !ferror (es_fpout) && !lineerr) { /* Write out the remaining entries. */ for (e= cache->entries; e; e = e->next) @@ -908,12 +908,12 @@ update_dir (crl_cache_t cache) log_error (_("error reading `%s': %s\n"), fname, gpg_strerror (err)); goto leave; } - if (ferror (fp)) + if (es_ferror (fp)) { err = gpg_error_from_errno (errno); log_error (_("error reading `%s': %s\n"), fname, strerror (errno)); } - if (ferror (fpout)) + if (es_ferror (fpout)) { err = gpg_error_from_errno (errno); log_error (_("error writing `%s': %s\n"), tmpfname, strerror (errno)); @@ -922,9 +922,9 @@ update_dir (crl_cache_t cache) goto leave; /* Rename the files. */ - fclose (fp); + es_fclose (fp); fp = NULL; - if (fclose (fpout)) + if (es_fclose (fpout)) { err = gpg_error_from_errno (errno); log_error (_("error closing `%s': %s\n"), tmpfname, strerror (errno)); @@ -947,14 +947,13 @@ update_dir (crl_cache_t cache) leave: /* Fixme: Relinquish update lock. */ xfree (line); - if (fp) - fclose (fp); + es_fclose (fp); xfree (fname); if (fpout) { - fclose (fpout); + es_fclose (fpout); if (err && tmpfname) - remove (tmpfname); + gnupg_remove (tmpfname); } xfree (tmpfname); return err; @@ -984,14 +983,14 @@ make_db_file_name (const char *issuer_hash) static int hash_dbfile (const char *fname, unsigned char *md5buffer) { - FILE *fp; + estream_t fp; char *buffer; size_t n; gcry_md_hd_t md5; gpg_err_code_t err; buffer = xtrymalloc (65536); - fp = buffer? fopen (fname, "rb") : NULL; + fp = buffer? es_fopen (fname, "rb") : NULL; if (!fp) { log_error (_("can't hash `%s': %s\n"), fname, strerror (errno)); @@ -1005,7 +1004,7 @@ hash_dbfile (const char *fname, unsigned char *md5buffer) log_error (_("error setting up MD5 hash context: %s\n"), gpg_strerror (err)); xfree (buffer); - fclose (fp); + es_fclose (fp); return -1; } @@ -1015,12 +1014,12 @@ hash_dbfile (const char *fname, unsigned char *md5buffer) for (;;) { - n = fread (buffer, 1, 65536, fp); - if (n < 65536 && ferror (fp)) + n = es_fread (buffer, 1, 65536, fp); + if (n < 65536 && es_ferror (fp)) { log_error (_("error hashing `%s': %s\n"), fname, strerror (errno)); xfree (buffer); - fclose (fp); + es_fclose (fp); gcry_md_close (md5); return -1; } @@ -1028,7 +1027,7 @@ hash_dbfile (const char *fname, unsigned char *md5buffer) break; gcry_md_write (md5, buffer, n); } - fclose (fp); + es_fclose (fp); xfree (buffer); gcry_md_final (md5); @@ -2017,7 +2016,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) *p = '.'; fname = make_filename (opt.homedir_cache, DBDIR_D, tmpfname, NULL); xfree (tmpfname); - if (!remove (fname)) + if (!gnupg_remove (fname)) log_info (_("removed stale temporary cache file `%s'\n"), fname); else if (errno != ENOENT) { @@ -2198,7 +2197,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) close (fd_cdb); if (fname) { - remove (fname); + gnupg_remove (fname); xfree (fname); } xfree (newfname); @@ -2214,7 +2213,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader) /* Print one cached entry E in a human readable format to stream FP. Return 0 on success. */ static gpg_error_t -list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, FILE *fp) +list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp) { struct cdb_find cdbfp; struct cdb *cdb; @@ -2222,44 +2221,46 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, FILE *fp) int warn = 0; const unsigned char *s; - fputs ("--------------------------------------------------------\n", fp ); - fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url ); - fprintf (fp, " Issuer:\t%s\n", e->issuer ); - fprintf (fp, " Issuer Hash:\t%s\n", e->issuer_hash ); - fprintf (fp, " This Update:\t%s\n", e->this_update ); - fprintf (fp, " Next Update:\t%s\n", e->next_update ); - fprintf (fp, " CRL Number :\t%s\n", e->crl_number? e->crl_number: "none"); - fprintf (fp, " AuthKeyId :\t%s\n", - e->authority_serialno? e->authority_serialno:"none"); + es_fputs ("--------------------------------------------------------\n", fp ); + es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url ); + es_fprintf (fp, " Issuer:\t%s\n", e->issuer ); + es_fprintf (fp, " Issuer Hash:\t%s\n", e->issuer_hash ); + es_fprintf (fp, " This Update:\t%s\n", e->this_update ); + es_fprintf (fp, " Next Update:\t%s\n", e->next_update ); + es_fprintf (fp, " CRL Number :\t%s\n", e->crl_number? e->crl_number: "none"); + es_fprintf (fp, " AuthKeyId :\t%s\n", + e->authority_serialno? e->authority_serialno:"none"); if (e->authority_serialno && e->authority_issuer) { - fputs (" \t", fp); + es_fputs (" \t", fp); for (s=e->authority_issuer; *s; s++) if (*s == '\x01') - fputs ("\n \t", fp); + es_fputs ("\n \t", fp); else - putc (*s, fp); - putc ('\n', fp); + es_putc (*s, fp); + es_putc ('\n', fp); } - fprintf (fp, " Trust Check:\t%s\n", - !e->user_trust_req? "[system]" : - e->check_trust_anchor? e->check_trust_anchor:"[missing]"); + es_fprintf (fp, " Trust Check:\t%s\n", + !e->user_trust_req? "[system]" : + e->check_trust_anchor? e->check_trust_anchor:"[missing]"); if ((e->invalid & 1)) - fprintf (fp, _(" ERROR: The CRL will not be used because it was still too old after an update!\n")); + es_fprintf (fp, _(" ERROR: The CRL will not be used " + "because it was still too old after an update!\n")); if ((e->invalid & 2)) - fprintf (fp, _(" ERROR: The CRL will not be used due to an unknown critical extension!\n")); + es_fprintf (fp, _(" ERROR: The CRL will not be used " + "due to an unknown critical extension!\n")); if ((e->invalid & ~3)) - fprintf (fp, _(" ERROR: The CRL will not be used\n")); + es_fprintf (fp, _(" ERROR: The CRL will not be used\n")); cdb = lock_db_file (cache, e); if (!cdb) return gpg_error (GPG_ERR_GENERAL); if (!e->dbfile_checked) - fprintf (fp, _(" ERROR: This cached CRL may has been tampered with!\n")); + es_fprintf (fp, _(" ERROR: This cached CRL may has been tampered with!\n")); - putc ('\n', fp); + es_putc ('\n', fp); rc = cdb_findinit (&cdbfp, cdb, NULL, 0); while (!rc && (rc=cdb_findnext (&cdbfp)) > 0 ) @@ -2299,36 +2300,36 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, FILE *fp) } reason = *record; - fputs (" ", fp); + es_fputs (" ", fp); for (i = 0; i < n; i++) - fprintf (fp, "%02X", keyrecord[i]); - fputs (":\t reasons( ", fp); + es_fprintf (fp, "%02X", keyrecord[i]); + es_fputs (":\t reasons( ", fp); if (reason & KSBA_CRLREASON_UNSPECIFIED) - fputs( "unspecified ", fp ), any = 1; + es_fputs( "unspecified ", fp ), any = 1; if (reason & KSBA_CRLREASON_KEY_COMPROMISE ) - fputs( "key_compromise ", fp ), any = 1; + es_fputs( "key_compromise ", fp ), any = 1; if (reason & KSBA_CRLREASON_CA_COMPROMISE ) - fputs( "ca_compromise ", fp ), any = 1; + es_fputs( "ca_compromise ", fp ), any = 1; if (reason & KSBA_CRLREASON_AFFILIATION_CHANGED ) - fputs( "affiliation_changed ", fp ), any = 1; + es_fputs( "affiliation_changed ", fp ), any = 1; if (reason & KSBA_CRLREASON_SUPERSEDED ) - fputs( "superseeded", fp ), any = 1; + es_fputs( "superseeded", fp ), any = 1; if (reason & KSBA_CRLREASON_CESSATION_OF_OPERATION ) - fputs( "cessation_of_operation", fp ), any = 1; + es_fputs( "cessation_of_operation", fp ), any = 1; if (reason & KSBA_CRLREASON_CERTIFICATE_HOLD ) - fputs( "certificate_hold", fp ), any = 1; + es_fputs( "certificate_hold", fp ), any = 1; if (reason && !any) - fputs( "other", fp ); + es_fputs( "other", fp ); - fprintf (fp, ") rdate: %.15s\n", record+1); + es_fprintf (fp, ") rdate: %.15s\n", record+1); } if (rc) log_error (_("error reading cache entry from db: %s\n"), strerror (rc)); unlock_db_file (cache, e); - fprintf (fp, _("End CRL dump\n") ); - putc ('\n', fp); + es_fprintf (fp, _("End CRL dump\n") ); + es_putc ('\n', fp); return (rc||warn)? gpg_error (GPG_ERR_GENERAL) : 0; } @@ -2337,7 +2338,7 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, FILE *fp) /* Print the contents of the CRL CACHE in a human readable format to stream FP. */ gpg_error_t -crl_cache_list (FILE *fp) +crl_cache_list (estream_t fp) { crl_cache_t cache = get_current_cache (); crl_cache_entry_t entry; @@ -2357,10 +2358,10 @@ gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename) { gpg_error_t err; - FILE *fp; + estream_t fp; ksba_reader_t reader; - fp = fopen (filename, "r"); + fp = es_fopen (filename, "r"); if (!fp) { err = gpg_error_from_errno (errno); @@ -2380,7 +2381,7 @@ crl_cache_load (ctrl_t ctrl, const char *filename) } err = crl_cache_insert (ctrl, filename, reader); ksba_reader_release (reader); - fclose (fp); + es_fclose (fp); return err; } diff --git a/dirmngr/crlcache.h b/dirmngr/crlcache.h index b9e487436..c2995129c 100644 --- a/dirmngr/crlcache.h +++ b/dirmngr/crlcache.h @@ -60,7 +60,7 @@ gpg_error_t crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert, gpg_error_t crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader); -gpg_error_t crl_cache_list (FILE* fp); +gpg_error_t crl_cache_list (estream_t fp); gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename); diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index ca6c77a84..e89931e89 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -193,9 +193,8 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) else err = http_open_document (&hd, url, NULL, (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0) - |HTTP_FLAG_NEED_HEADER |(DBG_LOOKUP? HTTP_FLAG_LOG_RESP:0), - opt.http_proxy, NULL); + opt.http_proxy, NULL, NULL, NULL); switch ( err? 99999 : http_get_status_code (hd) ) { diff --git a/dirmngr/dirmngr-client.c b/dirmngr/dirmngr-client.c index 00b12b712..5aba0c80a 100644 --- a/dirmngr/dirmngr-client.c +++ b/dirmngr/dirmngr-client.c @@ -485,7 +485,7 @@ start_dirmngr (int only_daemon) i=0; if (log_get_fd () != -1) no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ()); - no_close_list[i++] = assuan_fd_from_posix_fd (fileno (stderr)); + no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr)); no_close_list[i] = -1; /* Connect to the agent and perform initial handshaking. */ diff --git a/dirmngr/dirmngr-err.h b/dirmngr/dirmngr-err.h new file mode 100644 index 000000000..17e825570 --- /dev/null +++ b/dirmngr/dirmngr-err.h @@ -0,0 +1,12 @@ +/* Definition of the gpg-error source. */ + +#ifndef DIRMNGR_ERR_H +#define DIRMNGR_ERR_H + +#ifdef GPG_ERR_SOURCE_DEFAULT +#error GPG_ERR_SOURCE_DEFAULT already defined +#endif +#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_DIRMNGR +#include + +#endif /*DIRMNGR_ERR_H*/ diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 12b74bd00..5a913905d 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -37,7 +37,9 @@ #endif #include #include -#include +#ifdef HAVE_SIGNAL_H +# include +#endif #include @@ -53,6 +55,16 @@ #include "ldapserver.h" #include "asshelp.h" +/* The plain Windows version uses the windows service system. For + example to start the service you may use "sc start dirmngr". + WindowsCE does not support this; the service system over there is + based on a single process with all services being DLLs - we can't + support this easily. */ +#if defined(HAVE_W32_SYSTEM) && !defined(HAVE_W32CE_SYSTEM) +# define USE_W32_SERVICE 1 +#endif + + enum cmd_and_opt_values { aNull = 0, oCsh = 'c', @@ -119,7 +131,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_c (aServer, "server", N_("run in server mode (foreground)") ), ARGPARSE_c (aDaemon, "daemon", N_("run in daemon mode (background)") ), -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE ARGPARSE_c (aService, "service", N_("run as windows service (background)")), #endif ARGPARSE_c (aListCRLs, "list-crls", N_("list the contents of the CRL cache")), @@ -374,9 +386,9 @@ set_debug (void) static void wrong_args (const char *text) { - fputs (_("usage: dirmngr [options] "), stderr); - fputs (text, stderr); - putc ('\n', stderr); + es_fputs (_("usage: dirmngr [options] "), es_stderr); + es_fputs (text, es_stderr); + es_putc ('\n', es_stderr); dirmngr_exit (2); } @@ -514,7 +526,7 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread) } -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE /* The global status of our service. */ SERVICE_STATUS_HANDLE service_handle; SERVICE_STATUS service_status; @@ -544,7 +556,7 @@ w32_service_control (DWORD control, DWORD event_type, LPVOID event_data, } return 0; } -#endif /*HAVE_W32_SYSTEM*/ +#endif /*USE_W32_SERVICE*/ #ifndef HAVE_W32_SYSTEM static int @@ -559,14 +571,14 @@ pid_suffix_callback (unsigned long *r_suffix) #endif /*!HAVE_W32_SYSTEM*/ -#ifdef HAVE_W32_SYSTEM -#define main real_main +#ifdef USE_W32_SERVICE +# define main real_main #endif int main (int argc, char **argv) { -#ifdef HAVE_W32_SYSTEM -#undef main +#ifdef USE_W32_SERVICE +# undef main #endif enum cmd_and_opt_values cmd = 0; ARGPARSE_ARGS pargs; @@ -589,7 +601,7 @@ main (int argc, char **argv) int homedir_seen = 0; struct assuan_malloc_hooks malloc_hooks; -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE /* The option will be set by main() below if we should run as a system daemon. */ if (opt.system_service) @@ -610,7 +622,7 @@ main (int argc, char **argv) service_status.dwWaitHint = 10000; /* 10 seconds timeout. */ SetServiceStatus (service_handle, &service_status); } -#endif /*HAVE_W32_SYSTEM*/ +#endif /*USE_W32_SERVICE*/ set_strusage (my_strusage); log_set_prefix ("dirmngr", 1|4); @@ -833,7 +845,7 @@ main (int argc, char **argv) } if (configfp) { - fclose( configfp ); + fclose (configfp); configfp = NULL; /* Keep a copy of the name so that it can be read on SIGHUP. */ opt.config_filename = configname; @@ -854,15 +866,22 @@ main (int argc, char **argv) if (greeting) { - fprintf (stderr, "%s %s; %s\n", - strusage(11), strusage(13), strusage(14) ); - fprintf (stderr, "%s\n", strusage(15) ); + es_fprintf (es_stderr, "%s %s; %s\n", + strusage(11), strusage(13), strusage(14) ); + es_fprintf (es_stderr, "%s\n", strusage(15) ); } #ifdef IS_DEVELOPMENT_VERSION log_info ("NOTE: this is a development version!\n"); #endif + if (!access ("/etc/dirmngr", F_OK) && !strncmp (opt.homedir, "/etc/", 5)) + log_info + ("NOTE: DirMngr is now a proper part of GnuPG. The configuration and" + " other directory names changed. Please check that no other version" + " of dirmngr is still installed. To disable this warning, remove the" + " directory `/etc/dirmngr'.\n"); + if (gnupg_faked_time_p ()) { gnupg_isotime_t tbuf; @@ -975,7 +994,7 @@ main (int argc, char **argv) rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); if (rc == -1 && errno == EADDRINUSE) { - remove (socket_name); + gnupg_remove (socket_name); rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); } if (rc != -1 @@ -1000,7 +1019,7 @@ main (int argc, char **argv) if (opt.verbose) log_info (_("listening on socket `%s'\n"), socket_name ); - fflush (NULL); + es_fflush (NULL); #ifdef HAVE_W32_SYSTEM pid = getpid (); @@ -1085,7 +1104,7 @@ main (int argc, char **argv) launch_reaper_thread (); cert_cache_init (); crl_cache_init (); -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE if (opt.system_service) { service_status.dwCurrentState = SERVICE_RUNNING; @@ -1095,7 +1114,7 @@ main (int argc, char **argv) handle_connections (fd); assuan_sock_close (fd); shutdown_reaper (); -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE if (opt.system_service) { service_status.dwCurrentState = SERVICE_STOPPED; @@ -1110,7 +1129,7 @@ main (int argc, char **argv) wrong_args ("--list-crls"); launch_reaper_thread (); crl_cache_init (); - crl_cache_list (stdout); + crl_cache_list (es_stdout); } else if (cmd == aLoadCRL) { @@ -1260,7 +1279,7 @@ main (int argc, char **argv) } -#ifdef HAVE_W32_SYSTEM +#ifdef USE_W32_SERVICE int main (int argc, char *argv[]) { @@ -1291,7 +1310,7 @@ main (int argc, char *argv[]) return 0; } } -#endif +#endif /*USE_W32_SERVICE*/ static void @@ -1307,7 +1326,7 @@ cleanup (void) { cleanup_socket = 0; if (socket_name && *socket_name) - remove (socket_name); + gnupg_remove (socket_name); } } @@ -1351,9 +1370,9 @@ parse_ldapserver_file (const char* filename) ldap_server_t server, serverstart, *serverend; int c; unsigned int lineno = 0; - FILE *fp; + estream_t fp; - fp = fopen (filename, "r"); + fp = es_fopen (filename, "r"); if (!fp) { log_error (_("error opening `%s': %s\n"), filename, strerror (errno)); @@ -1362,18 +1381,18 @@ parse_ldapserver_file (const char* filename) serverstart = NULL; serverend = &serverstart; - while (fgets (buffer, sizeof buffer, fp)) + while (es_fgets (buffer, sizeof buffer, fp)) { lineno++; if (!*buffer || buffer[strlen(buffer)-1] != '\n') { - if (*buffer && feof (fp)) + if (*buffer && es_feof (fp)) ; /* Last line not terminated - continue. */ else { log_error (_("%s:%u: line too long - skipped\n"), filename, lineno); - while ( (c=fgetc (fp)) != EOF && c != '\n') + while ( (c=es_fgetc (fp)) != EOF && c != '\n') ; /* Skip until end of line. */ continue; } @@ -1393,9 +1412,9 @@ parse_ldapserver_file (const char* filename) } } - if (ferror (fp)) + if (es_ferror (fp)) log_error (_("error reading `%s': %s\n"), filename, strerror (errno)); - fclose (fp); + es_fclose (fp); return serverstart; } @@ -1406,7 +1425,7 @@ parse_ocsp_signer (const char *string) { gpg_error_t err; char *fname; - FILE *fp; + estream_t fp; char line[256]; char *p; fingerprint_list_t list, *list_tail, item; @@ -1444,7 +1463,7 @@ parse_ocsp_signer (const char *string) fname = make_filename (opt.homedir, string, NULL); } - fp = fopen (fname, "r"); + fp = es_fopen (fname, "r"); if (!fp) { err = gpg_error_from_syserror (); @@ -1457,16 +1476,16 @@ parse_ocsp_signer (const char *string) list_tail = &list; for (;;) { - if (!fgets (line, DIM(line)-1, fp) ) + if (!es_fgets (line, DIM(line)-1, fp) ) { - if (!feof (fp)) + if (!es_feof (fp)) { err = gpg_error_from_syserror (); log_error (_("%s:%u: read error: %s\n"), fname, lnr, gpg_strerror (err)); errflag = 1; } - fclose (fp); + es_fclose (fp); if (errflag) { while (list) @@ -1484,7 +1503,7 @@ parse_ocsp_signer (const char *string) if (!*line || line[strlen(line)-1] != '\n') { /* Eat until end of line. */ - while ( (c=getc (fp)) != EOF && c != '\n') + while ( (c=es_getc (fp)) != EOF && c != '\n') ; err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG /* */: GPG_ERR_INCOMPLETE_LINE); diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h index e6fa0d318..67f2122d9 100644 --- a/dirmngr/dirmngr.h +++ b/dirmngr/dirmngr.h @@ -21,11 +21,7 @@ #ifndef DIRMNGR_H #define DIRMNGR_H -#ifdef GPG_ERR_SOURCE_DEFAULT -#error GPG_ERR_SOURCE_DEFAULT already defined -#endif -#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_DIRMNGR -#include +#include "./dirmngr-err.h" #define map_assuan_err(a) \ map_assuan_err_with_source (GPG_ERR_SOURCE_DEFAULT, (a)) #include diff --git a/dirmngr/dirmngr_ldap.c b/dirmngr/dirmngr_ldap.c index f862081c1..fccbc58d1 100644 --- a/dirmngr/dirmngr_ldap.c +++ b/dirmngr/dirmngr_ldap.c @@ -25,7 +25,9 @@ #include #include #include -#include +#ifdef HAVE_SIGNAL_H +# include +#endif #include #include #include @@ -171,6 +173,7 @@ main (int argc, char **argv ) #ifdef HAVE_W32_SYSTEM /* Yeah, right. Sigh. */ +#error FIXME _setmode (_fileno (stdout), _O_BINARY); #endif @@ -313,7 +316,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr) if (opt.multi) { /* Write item marker. */ - if (fwrite ("I\0\0\0\0", 5, 1, stdout) != 1) + if (es_fwrite ("I\0\0\0\0", 5, 1, es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); @@ -390,8 +393,8 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr) tmp[2] = (n >> 16); tmp[3] = (n >> 8); tmp[4] = (n); - if (fwrite (tmp, 5, 1, stdout) != 1 - || fwrite (attr, n, 1, stdout) != 1) + if (es_fwrite (tmp, 5, 1, es_stdout) != 1 + || es_fwrite (attr, n, 1, es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); @@ -415,7 +418,7 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr) tmp[3] = (n >> 8); tmp[4] = (n); - if (fwrite (tmp, 5, 1, stdout) != 1) + if (es_fwrite (tmp, 5, 1, es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); @@ -429,8 +432,9 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr) /* Note: this does not work for STDOUT on a Windows console, where it fails with "Not enough space" for CRLs which are 52 KB or larger. */ - if (fwrite (values[0]->bv_val, values[0]->bv_len, - 1, stdout) != 1) +#warning still true - implement in estream + if (es_fwrite (values[0]->bv_val, values[0]->bv_len, + 1, es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); @@ -452,8 +456,8 @@ print_ldap_entries (LDAP *ld, LDAPMessage *msg, char *want_attr) if (cnt > MAX_CNT) cnt = MAX_CNT; - if (fwrite (((char *) values[0]->bv_val) + n, cnt, 1, - stdout) != 1) + if (es_fwrite (((char *) values[0]->bv_val) + n, cnt, 1, + es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); @@ -572,7 +576,7 @@ fetch_ldap (const char *url, const LDAPURLDesc *ludp) &opt.timeout, &msg); if (rc == LDAP_SIZELIMIT_EXCEEDED && opt.multi) { - if (fwrite ("E\0\0\0\x09truncated", 14, 1, stdout) != 1) + if (es_fwrite ("E\0\0\0\x09truncated", 14, 1, es_stdout) != 1) { log_error (_("error writing to stdout: %s\n"), strerror (errno)); diff --git a/dirmngr/http.c b/dirmngr/http.c deleted file mode 100644 index b65a92adc..000000000 --- a/dirmngr/http.c +++ /dev/null @@ -1,1863 +0,0 @@ -/* http.c - HTTP protocol handler - * Copyright (C) 1999, 2001, 2002, 2003, 2004, - * 2006, 2009 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -/* Simple HTTP client implementation. We try to keep the code as - self-contained as possible. There are some contraints however: - - - estream is required. We now require estream because it provides a - very useful and portable asprintf implementation and the fopencookie - function. - - stpcpy is required - - fixme: list other requirements. - - - - With HTTP_USE_GNUTLS support for https is provided (this also - requires estream). - - With HTTP_NO_WSASTARTUP the socket initialization is not done - under Windows. This is useful if the socket layer has already - been initialized elsewhere. This also avoids the installation of - an exit handler to cleanup the socket layer. -*/ - -#warning Duplicated code with common/http.c - -#ifdef HAVE_CONFIG_H -# include -#endif -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_W32_SYSTEM -# include -#else /*!HAVE_W32_SYSTEM*/ -# include -# include -# include -# include -# include -# include -# include -#endif /*!HAVE_W32_SYSTEM*/ - -#include - -#ifdef HTTP_USE_GNUTLS -# include -/* For non-understandable reasons GNUTLS dropped the _t suffix from - all types. yes, ISO-C might be read as this but there are still - other name space conflicts and using _t is actually a Good - Thing. */ -typedef gnutls_session gnutls_session_t; -typedef gnutls_transport_ptr gnutls_transport_ptr_t; -#endif /*HTTP_USE_GNUTLS*/ - -#ifdef TEST -#undef USE_DNS_SRV -#endif - -#include "util.h" -#include "i18n.h" -#include "http.h" -#ifdef USE_DNS_SRV -#include "srv.h" -#else /*!USE_DNS_SRV*/ -/* If we are not compiling with SRV record support we provide stub - data structures. */ -#ifndef MAXDNAME -#define MAXDNAME 1025 -#endif -struct srventry -{ - unsigned short priority; - unsigned short weight; - unsigned short port; - int run_count; - char target[MAXDNAME]; -}; -#endif/*!USE_DNS_SRV*/ - - -#ifdef HAVE_W32_SYSTEM -#define sock_close(a) closesocket(a) -#else -#define sock_close(a) close(a) -#endif - -#ifndef EAGAIN -#define EAGAIN EWOULDBLOCK -#endif - -#define HTTP_PROXY_ENV "http_proxy" -#define MAX_LINELEN 20000 /* Max. length of a HTTP header line. */ -#define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \ - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ - "01234567890@" \ - "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~" - -/* A long counter type. */ -#ifdef HAVE_STRTOULL -typedef unsigned long long longcounter_t; -#define counter_strtoul(a) strtoull ((a), NULL, 10) -#else -typedef unsigned long longcounter_t; -#define counter_strtoul(a) strtoul ((a), NULL, 10) -#endif - -#ifndef HTTP_USE_GNUTLS -typedef void * gnutls_session_t; -#endif - -static gpg_error_t do_parse_uri (parsed_uri_t uri, int only_local_part); -static int remove_escapes (char *string); -static int insert_escapes (char *buffer, const char *string, - const char *special); -static uri_tuple_t parse_tuple (char *string); -static gpg_error_t send_request (http_t hd, - const char *auth, const char *proxy); -static char *build_rel_path (parsed_uri_t uri); -static gpg_error_t parse_response (http_t hd); - -static int connect_server (const char *server, unsigned short port, - unsigned int flags, const char *srvtag); - -static ssize_t cookie_read (void *cookie, void *buffer, size_t size); -static ssize_t cookie_write (void *cookie, const void *buffer, size_t size); -static int cookie_close (void *cookie); - -static es_cookie_io_functions_t cookie_functions = - { - cookie_read, - cookie_write, - NULL, - cookie_close - }; - -struct cookie_s -{ - int fd; /* File descriptor or -1 if already closed. */ - gnutls_session_t tls_session; /* TLS session context or NULL if not used. */ - - /* The remaining content length and a flag telling whether to use - the content length. */ - longcounter_t content_length; - unsigned int content_length_valid:1; - - /* Flag to communicate with the close handler. */ - unsigned int keep_socket:1; -}; -typedef struct cookie_s *cookie_t; - - -#ifdef HTTP_USE_GNUTLS -static gpg_error_t (*tls_callback) (http_t, gnutls_session_t, int); -#endif /*HTTP_USE_GNUTLS*/ - - -/* An object to save header lines. */ -struct header_s -{ - struct header_s *next; - char *value; /* The value of the header (malloced). */ - char name[1]; /* The name of the header (canonicalized). */ -}; -typedef struct header_s *header_t; - - -/* Our handle context. */ -struct http_context_s -{ - unsigned int status_code; - int sock; - unsigned int in_data:1; - unsigned int is_http_0_9:1; - estream_t fp_read; - estream_t fp_write; - void *write_cookie; - void *read_cookie; - void *tls_context; - parsed_uri_t uri; - http_req_t req_type; - char *buffer; /* Line buffer. */ - size_t buffer_size; - unsigned int flags; - header_t headers; /* Received headers. */ -}; - - - - -#if defined(HAVE_W32_SYSTEM) && !defined(HTTP_NO_WSASTARTUP) - -#if GNUPG_MAJOR_VERSION == 1 -#define REQ_WINSOCK_MAJOR 1 -#define REQ_WINSOCK_MINOR 1 -#else -#define REQ_WINSOCK_MAJOR 2 -#define REQ_WINSOCK_MINOR 2 -#endif - - -static void -deinit_sockets (void) -{ - WSACleanup(); -} - -static void -init_sockets (void) -{ - static int initialized; - static WSADATA wsdata; - - if (initialized) - return; - - if ( WSAStartup( MAKEWORD (REQ_WINSOCK_MINOR, REQ_WINSOCK_MAJOR), &wsdata ) ) - { - log_error ("error initializing socket library: ec=%d\n", - (int)WSAGetLastError () ); - return; - } - if ( LOBYTE(wsdata.wVersion) != REQ_WINSOCK_MAJOR - || HIBYTE(wsdata.wVersion) != REQ_WINSOCK_MINOR ) - { - log_error ("socket library version is %x.%x - but %d.%d needed\n", - LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion), - REQ_WINSOCK_MAJOR, REQ_WINSOCK_MINOR); - WSACleanup(); - return; - } - atexit ( deinit_sockets ); - initialized = 1; -} -#endif /*HAVE_W32_SYSTEM && !HTTP_NO_WSASTARTUP*/ - - - -/* - * Helper function to create an HTTP header with hex encoded data. A - * new buffer is returned. This buffer is the concatenation of the - * string PREFIX, the hex-encoded DATA of length LEN and the string - * SUFFIX. On error NULL is returned and ERRNO set. - */ -static char * -make_header_line (const char *prefix, const char *suffix, - const void *data, size_t len ) -{ - static unsigned char bintoasc[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - const unsigned int *s = data; - char *buffer, *p; - - buffer = xtrymalloc (strlen (prefix) + (len+2)/3*4 + strlen (suffix) + 1); - if (!buffer) - return NULL; - p = stpcpy (buffer, prefix); - for ( ; len >= 3 ; len -= 3, s += 3 ) - { - *p++ = bintoasc[(s[0] >> 2) & 077]; - *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077]; - *p++ = bintoasc[(((s[1]<<2)&074)|((s[2]>>6)&03))&077]; - *p++ = bintoasc[s[2]&077]; - } - if ( len == 2 ) - { - *p++ = bintoasc[(s[0] >> 2) & 077]; - *p++ = bintoasc[(((s[0] <<4)&060)|((s[1] >> 4)&017))&077]; - *p++ = bintoasc[((s[1]<<2)&074)]; - *p++ = '='; - } - else if ( len == 1 ) - { - *p++ = bintoasc[(s[0] >> 2) & 077]; - *p++ = bintoasc[(s[0] <<4)&060]; - *p++ = '='; - *p++ = '='; - } - strcpy (p, suffix); - return buffer; -} - - - - -void -http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) ) -{ -#ifdef HTTP_USE_GNUTLS - tls_callback = (gpg_error_t (*) (http_t, gnutls_session_t, int))cb; -#else - (void)cb; -#endif -} - - - -/* Start a HTTP retrieval and return on success in R_HD a context - pointer for completing the the request and to wait for the - response. */ -gpg_error_t -http_open (http_t *r_hd, http_req_t reqtype, const char *url, - const char *auth, unsigned int flags, const char *proxy, - void *tls_context) -{ - gpg_error_t err; - http_t hd; - - *r_hd = NULL; - - if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST)) - return gpg_error (GPG_ERR_INV_ARG); - - /* Make need_header default unless ignore_cl is set. We might want - to drop the need_header entirely. */ - if (!(flags & HTTP_FLAG_IGNORE_CL)) - flags |= HTTP_FLAG_NEED_HEADER; - - /* Create the handle. */ - hd = xtrycalloc (1, sizeof *hd); - if (!hd) - return gpg_error_from_syserror (); - hd->sock = -1; - hd->req_type = reqtype; - hd->flags = flags; - hd->tls_context = tls_context; - - err = http_parse_uri (&hd->uri, url); - if (!err) - err = send_request (hd, auth, proxy); - - if (err) - { - if (!hd->fp_read && !hd->fp_write && hd->sock != -1) - sock_close (hd->sock); - if (hd->fp_read) - es_fclose (hd->fp_read); - if (hd->fp_write) - es_fclose (hd->fp_write); - http_release_parsed_uri (hd->uri); - xfree (hd); - } - else - *r_hd = hd; - return err; -} - - -void -http_start_data (http_t hd) -{ - if (!hd->in_data) - { - es_fputs ("\r\n", hd->fp_write); - es_fflush (hd->fp_write); - hd->in_data = 1; - } - else - es_fflush (hd->fp_write); -} - - -gpg_error_t -http_wait_response (http_t hd) -{ - gpg_error_t err; - cookie_t cookie; - - /* Make sure that we are in the data. */ - http_start_data (hd); - - cookie = hd->write_cookie; - if (!cookie) - return gpg_error (GPG_ERR_INTERNAL); - - /* Close the write stream but keep the socket open. */ - cookie->keep_socket = 1; - es_fclose (hd->fp_write); - hd->fp_write = NULL; - hd->write_cookie = NULL; - - /* Shutdown one end of the socket is desired. As per HTTP/1.0 this - is not required but some very old servers (e.g. the original pksd - key server didn't worked without it. */ - if ((hd->flags & HTTP_FLAG_SHUTDOWN)) - shutdown (hd->sock, 1); - hd->in_data = 0; - - /* Create a new cookie and a stream for reading. */ - cookie = xtrycalloc (1, sizeof *cookie); - if (!cookie) - return gpg_error_from_syserror (); - cookie->fd = hd->sock; - if (hd->uri->use_tls) - cookie->tls_session = hd->tls_context; - - hd->read_cookie = cookie; - hd->fp_read = es_fopencookie (cookie, "r", cookie_functions); - if (!hd->fp_read) - { - xfree (cookie); - hd->read_cookie = NULL; - return gpg_error_from_syserror (); - } - - err = parse_response (hd); - return err; -} - - -/* Convenience function to send a request and wait for the response. - Closes the handle on error. If PROXY is not NULL, this value will - be used as an HTTP proxy and any enabled $http_proxy gets - ignored. */ -gpg_error_t -http_open_document (http_t *r_hd, const char *document, - const char *auth, unsigned int flags, const char *proxy, - void *tls_context) -{ - gpg_error_t err; - - err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags, - proxy, tls_context); - if (err) - return err; - - err = http_wait_response (*r_hd); - if (err) - http_close (*r_hd, 0); - - return err; -} - - -void -http_close (http_t hd, int keep_read_stream) -{ - if (!hd) - return; - if (!hd->fp_read && !hd->fp_write && hd->sock != -1) - sock_close (hd->sock); - if (hd->fp_read && !keep_read_stream) - es_fclose (hd->fp_read); - if (hd->fp_write) - es_fclose (hd->fp_write); - http_release_parsed_uri (hd->uri); - while (hd->headers) - { - header_t tmp = hd->headers->next; - xfree (hd->headers->value); - xfree (hd->headers); - hd->headers = tmp; - } - xfree (hd->buffer); - xfree (hd); -} - - -estream_t -http_get_read_ptr (http_t hd) -{ - return hd?hd->fp_read:NULL; -} - -estream_t -http_get_write_ptr (http_t hd) -{ - return hd?hd->fp_write:NULL; -} - -unsigned int -http_get_status_code (http_t hd) -{ - return hd?hd->status_code:0; -} - - - -/* - * Parse an URI and put the result into the newly allocated RET_URI. - * The caller must always use release_parsed_uri() to releases the - * resources (even on error). - */ -gpg_error_t -http_parse_uri (parsed_uri_t * ret_uri, const char *uri) -{ - *ret_uri = xcalloc (1, sizeof **ret_uri + strlen (uri)); - strcpy ((*ret_uri)->buffer, uri); - return do_parse_uri (*ret_uri, 0); -} - -void -http_release_parsed_uri (parsed_uri_t uri) -{ - if (uri) - { - uri_tuple_t r, r2; - - for (r = uri->query; r; r = r2) - { - r2 = r->next; - xfree (r); - } - xfree (uri); - } -} - - -static gpg_error_t -do_parse_uri (parsed_uri_t uri, int only_local_part) -{ - uri_tuple_t *tail; - char *p, *p2, *p3, *pp; - int n; - - p = uri->buffer; - n = strlen (uri->buffer); - - /* Initialize all fields to an empty string or an empty list. */ - uri->scheme = uri->host = uri->path = p + n; - uri->port = 0; - uri->params = uri->query = NULL; - uri->use_tls = 0; - - /* A quick validity check. */ - if (strspn (p, VALID_URI_CHARS) != n) - return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */ - - if (!only_local_part) - { - /* Find the scheme. */ - if (!(p2 = strchr (p, ':')) || p2 == p) - return gpg_error (GPG_ERR_BAD_URI); /* No scheme. */ - *p2++ = 0; - for (pp=p; *pp; pp++) - *pp = tolower (*(unsigned char*)pp); - uri->scheme = p; - if (!strcmp (uri->scheme, "http")) - uri->port = 80; -#ifdef HTTP_USE_GNUTLS - else if (!strcmp (uri->scheme, "https")) - { - uri->port = 443; - uri->use_tls = 1; - } -#endif - else - return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */ - - p = p2; - - /* Find the hostname */ - if (*p != '/') - return gpg_error (GPG_ERR_INV_URI); /* Does not start with a slash. */ - - p++; - if (*p == '/') /* There seems to be a hostname. */ - { - p++; - if ((p2 = strchr (p, '/'))) - *p2++ = 0; - - /* Check for username/password encoding */ - if ((p3 = strchr (p, '@'))) - { - uri->auth = p; - *p3++ = '\0'; - p = p3; - } - - for (pp=p; *pp; pp++) - *pp = tolower (*(unsigned char*)pp); - uri->host = p; - if ((p3 = strchr (p, ':'))) - { - *p3++ = 0; - uri->port = atoi (p3); - } - - uri->host = p; - if ((n = remove_escapes (uri->host)) < 0) - return gpg_error (GPG_ERR_BAD_URI); - if (n != strlen (p)) - return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */ - p = p2 ? p2 : NULL; - } - } /* End global URI part. */ - - /* Parse the pathname part */ - if (!p || !*p) - return 0; /* We don't have a path. Okay. */ - - /* TODO: Here we have to check params. */ - - /* Do we have a query part? */ - if ((p2 = strchr (p, '?'))) - *p2++ = 0; - - uri->path = p; - if ((n = remove_escapes (p)) < 0) - return gpg_error (GPG_ERR_BAD_URI); - if (n != strlen (p)) - return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */ - p = p2 ? p2 : NULL; - - if (!p || !*p) - return 0; /* We don't have a query string. Okay. */ - - /* Now parse the query string. */ - tail = &uri->query; - for (;;) - { - uri_tuple_t elem; - - if ((p2 = strchr (p, '&'))) - *p2++ = 0; - if (!(elem = parse_tuple (p))) - return gpg_error (GPG_ERR_BAD_URI); - *tail = elem; - tail = &elem->next; - - if (!p2) - break; /* Ready. */ - p = p2; - } - - return 0; -} - - -/* - * Remove all %xx escapes; this is done in-place. Returns: New length - * of the string. - */ -static int -remove_escapes (char *string) -{ - int n = 0; - unsigned char *p, *s; - - for (p = s = (unsigned char*)string; *s; s++) - { - if (*s == '%') - { - if (s[1] && s[2] && isxdigit (s[1]) && isxdigit (s[2])) - { - s++; - *p = *s >= '0' && *s <= '9' ? *s - '0' : - *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10; - *p <<= 4; - s++; - *p |= *s >= '0' && *s <= '9' ? *s - '0' : - *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10; - p++; - n++; - } - else - { - *p++ = *s++; - if (*s) - *p++ = *s++; - if (*s) - *p++ = *s++; - if (*s) - *p = 0; - return -1; /* Bad URI. */ - } - } - else - { - *p++ = *s; - n++; - } - } - *p = 0; /* Make sure to keep a string terminator. */ - return n; -} - - -static int -insert_escapes (char *buffer, const char *string, - const char *special) -{ - const unsigned char *s = (const unsigned char*)string; - int n = 0; - - for (; *s; s++) - { - if (strchr (VALID_URI_CHARS, *s) && !strchr (special, *s)) - { - if (buffer) - *(unsigned char*)buffer++ = *s; - n++; - } - else - { - if (buffer) - { - sprintf (buffer, "%%%02X", *s); - buffer += 3; - } - n += 3; - } - } - return n; -} - - -/* Allocate a new string from STRING using standard HTTP escaping as - well as escaping of characters given in SPECIALS. A common pattern - for SPECIALS is "%;?&=". However it depends on the needs, for - example "+" and "/: often needs to be escaped too. Returns NULL on - failure and sets ERRNO. */ -char * -http_escape_string (const char *string, const char *specials) -{ - int n; - char *buf; - - n = insert_escapes (NULL, string, specials); - buf = xtrymalloc (n+1); - if (buf) - { - insert_escapes (buf, string, specials); - buf[n] = 0; - } - return buf; -} - - - -static uri_tuple_t -parse_tuple (char *string) -{ - char *p = string; - char *p2; - int n; - uri_tuple_t tuple; - - if ((p2 = strchr (p, '='))) - *p2++ = 0; - if ((n = remove_escapes (p)) < 0) - return NULL; /* Bad URI. */ - if (n != strlen (p)) - return NULL; /* Name with a Nul in it. */ - tuple = xtrycalloc (1, sizeof *tuple); - if (!tuple) - return NULL; /* Out of core. */ - tuple->name = p; - if (!p2) /* We have only the name, so we assume an empty value string. */ - { - tuple->value = p + strlen (p); - tuple->valuelen = 0; - tuple->no_value = 1; /* Explicitly mark that we have seen no '='. */ - } - else /* Name and value. */ - { - if ((n = remove_escapes (p2)) < 0) - { - xfree (tuple); - return NULL; /* Bad URI. */ - } - tuple->value = p2; - tuple->valuelen = n; - } - return tuple; -} - - -/* - * Send a HTTP request to the server - * Returns 0 if the request was successful - */ -static gpg_error_t -send_request (http_t hd, const char *auth, const char *proxy) -{ - gnutls_session_t tls_session; - gpg_error_t err; - const char *server; - char *request, *p; - unsigned short port; - const char *http_proxy = NULL; - char *proxy_authstr = NULL; - char *authstr = NULL; - int save_errno; - cookie_t cookie; - - - tls_session = hd->tls_context; - if (hd->uri->use_tls && !tls_session) - { - log_error ("TLS requested but no GNUTLS context provided\n"); - return gpg_error (GPG_ERR_INTERNAL); - } - - server = *hd->uri->host ? hd->uri->host : "localhost"; - port = hd->uri->port ? hd->uri->port : 80; - - if ( (proxy && *proxy) - || ( (hd->flags & HTTP_FLAG_TRY_PROXY) - && (http_proxy = getenv (HTTP_PROXY_ENV)) - && *http_proxy )) - { - parsed_uri_t uri; - - if (proxy) - http_proxy = proxy; - - err = http_parse_uri (&uri, http_proxy); - if (err) - { - log_error ("invalid HTTP proxy (%s): %s\n", - http_proxy, gpg_strerror (err)); - http_release_parsed_uri (uri); - return gpg_error (GPG_ERR_CONFIGURATION); - - } - - if (uri->auth) - { - remove_escapes (uri->auth); - proxy_authstr = make_header_line ("Proxy-Authorization: Basic ", - "\r\n", - uri->auth, strlen(uri->auth)); - if (!proxy_authstr) - { - err = gpg_error_from_syserror (); - http_release_parsed_uri (uri); - return err; - } - } - - hd->sock = connect_server (*uri->host ? uri->host : "localhost", - uri->port ? uri->port : 80, - hd->flags, hd->uri->scheme); - save_errno = errno; - http_release_parsed_uri (uri); - } - else - { - hd->sock = connect_server (server, port, hd->flags, hd->uri->scheme); - save_errno = errno; - } - - if (hd->sock == -1) - { - xfree (proxy_authstr); - return (save_errno - ? gpg_error_from_errno (save_errno) - : gpg_error (GPG_ERR_NOT_FOUND)); - } - -#ifdef HTTP_USE_GNUTLS - if (hd->uri->use_tls) - { - int rc; - - gnutls_transport_set_ptr (tls_session, (gnutls_transport_ptr_t)hd->sock); - do - { - rc = gnutls_handshake (tls_session); - } - while (rc == GNUTLS_E_INTERRUPTED || rc == GNUTLS_E_AGAIN); - if (rc < 0) - { - log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc)); - xfree (proxy_authstr); - return gpg_error (GPG_ERR_NETWORK); - } - - if (tls_callback) - { - err = tls_callback (hd, tls_session, 0); - if (err) - { - log_info ("TLS connection authentication failed: %s\n", - gpg_strerror (err)); - xfree (proxy_authstr); - return err; - } - } - } -#endif /*HTTP_USE_GNUTLS*/ - - if (auth || hd->uri->auth) - { - char *myauth; - - if (auth) - { - myauth = xtrystrdup (auth); - if (!myauth) - { - xfree (proxy_authstr); - return gpg_error_from_syserror (); - } - remove_escapes (myauth); - } - else - { - remove_escapes (hd->uri->auth); - myauth = hd->uri->auth; - } - - authstr = make_header_line ("Authorization: Basic %s", "\r\n", - myauth, strlen (myauth)); - if (auth) - xfree (myauth); - - if (!authstr) - { - xfree (proxy_authstr); - return gpg_error_from_syserror (); - } - } - - p = build_rel_path (hd->uri); - if (!p) - return gpg_error_from_syserror (); - - if (http_proxy && *http_proxy) - { - request = es_asprintf - ("%s http://%s:%hu%s%s HTTP/1.0\r\n%s%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD ? "HEAD" : - hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - server, port, *p == '/' ? "" : "/", p, - authstr ? authstr : "", - proxy_authstr ? proxy_authstr : ""); - } - else - { - char portstr[35]; - - if (port == 80) - *portstr = 0; - else - snprintf (portstr, sizeof portstr, ":%u", port); - - request = es_asprintf - ("%s %s%s HTTP/1.0\r\nHost: %s%s\r\n%s", - hd->req_type == HTTP_REQ_GET ? "GET" : - hd->req_type == HTTP_REQ_HEAD ? "HEAD" : - hd->req_type == HTTP_REQ_POST ? "POST" : "OOPS", - *p == '/' ? "" : "/", p, server, portstr, - authstr? authstr:""); - } - xfree (p); - if (!request) - { - err = gpg_error_from_syserror (); - xfree (authstr); - xfree (proxy_authstr); - return err; - } - - /* First setup estream so that we can write even the first line - using estream. This is also required for the sake of gnutls. */ - cookie = xtrycalloc (1, sizeof *cookie); - if (!cookie) - { - err = gpg_error_from_syserror (); - goto leave; - } - cookie->fd = hd->sock; - hd->write_cookie = cookie; - if (hd->uri->use_tls) - cookie->tls_session = tls_session; - hd->fp_write = es_fopencookie (cookie, "w", cookie_functions); - if (!hd->fp_write) - { - xfree (cookie); - hd->write_cookie = NULL; - err = gpg_error_from_syserror (); - } - else if (es_fputs (request, hd->fp_write) || es_fflush (hd->fp_write)) - err = gpg_error_from_syserror (); - else - err = 0; - - leave: - es_free (request); - xfree (authstr); - xfree (proxy_authstr); - - return err; -} - - -/* - * Build the relative path from the parsed URI. Minimal - * implementation. May return NULL in case of memory failure; errno - * is then set accordingly. - */ -static char * -build_rel_path (parsed_uri_t uri) -{ - uri_tuple_t r; - char *rel_path, *p; - int n; - - /* Count the needed space. */ - n = insert_escapes (NULL, uri->path, "%;?&"); - /* TODO: build params. */ - for (r = uri->query; r; r = r->next) - { - n++; /* '?'/'&' */ - n += insert_escapes (NULL, r->name, "%;?&="); - if (!r->no_value) - { - n++; /* '=' */ - n += insert_escapes (NULL, r->value, "%;?&="); - } - } - n++; - - /* Now allocate and copy. */ - p = rel_path = xtrymalloc (n); - if (!p) - return NULL; - n = insert_escapes (p, uri->path, "%;?&"); - p += n; - /* TODO: add params. */ - for (r = uri->query; r; r = r->next) - { - *p++ = r == uri->query ? '?' : '&'; - n = insert_escapes (p, r->name, "%;?&="); - p += n; - if (!r->no_value) - { - *p++ = '='; - /* TODO: Use valuelen. */ - n = insert_escapes (p, r->value, "%;?&="); - p += n; - } - } - *p = 0; - return rel_path; -} - - -/* Transform a header name into a standard capitalized format; e.g. - "Content-Type". Conversion stops at the colon. As usual we don't - use the localized versions of ctype.h. */ -static void -capitalize_header_name (char *name) -{ - int first = 1; - - for (; *name && *name != ':'; name++) - { - if (*name == '-') - first = 1; - else if (first) - { - if (*name >= 'a' && *name <= 'z') - *name = *name - 'a' + 'A'; - first = 0; - } - else if (*name >= 'A' && *name <= 'Z') - *name = *name - 'A' + 'a'; - } -} - - -/* Store an HTTP header line in LINE away. Line continuation is - supported as well as merging of headers with the same name. This - function may modify LINE. */ -static gpg_error_t -store_header (http_t hd, char *line) -{ - size_t n; - char *p, *value; - header_t h; - - n = strlen (line); - if (n && line[n-1] == '\n') - { - line[--n] = 0; - if (n && line[n-1] == '\r') - line[--n] = 0; - } - if (!n) /* we are never called to hit this. */ - return gpg_error (GPG_ERR_BUG); - if (*line == ' ' || *line == '\t') - { - /* Continuation. This won't happen too often as it is not - recommended. We use a straightforward implementaion. */ - if (!hd->headers) - return gpg_error (GPG_ERR_PROTOCOL_VIOLATION); - n += strlen (hd->headers->value); - p = xtrymalloc (n+1); - if (!p) - return gpg_error_from_syserror (); - strcpy (stpcpy (p, hd->headers->value), line); - xfree (hd->headers->value); - hd->headers->value = p; - return 0; - } - - capitalize_header_name (line); - p = strchr (line, ':'); - if (!p) - return gpg_error (GPG_ERR_PROTOCOL_VIOLATION); - *p++ = 0; - while (*p == ' ' || *p == '\t') - p++; - value = p; - - for (h=hd->headers; h; h = h->next) - if ( !strcmp (h->name, line) ) - break; - if (h) - { - /* We have already seen a line with that name. Thus we assume - it is a comma separated list and merge them. */ - p = xtrymalloc (strlen (h->value) + 1 + strlen (value)+ 1); - if (!p) - return gpg_error_from_syserror (); - strcpy (stpcpy (stpcpy (p, h->value), ","), value); - xfree (h->value); - h->value = p; - return 0; - } - - /* Append a new header. */ - h = xtrymalloc (sizeof *h + strlen (line)); - if (!h) - return gpg_error_from_syserror (); - strcpy (h->name, line); - h->value = xtrymalloc (strlen (value)+1); - if (!h->value) - { - xfree (h); - return gpg_error_from_syserror (); - } - strcpy (h->value, value); - h->next = hd->headers; - hd->headers = h; - - return 0; -} - - -/* Return the header NAME from the last response. The returned value - is valid as along as HD has not been closed and no othe request has - been send. If the header was not found, NULL is returned. Name - must be canonicalized, that is the first letter of each dash - delimited part must be uppercase and all other letters lowercase. - Note that the context must have been opened with the - HTTP_FLAG_NEED_HEADER. */ -const char * -http_get_header (http_t hd, const char *name) -{ - header_t h; - - for (h=hd->headers; h; h = h->next) - if ( !strcmp (h->name, name) ) - return h->value; - return NULL; -} - - - -/* - * Parse the response from a server. - * Returns: Errorcode and sets some files in the handle - */ -static gpg_error_t -parse_response (http_t hd) -{ - char *line, *p, *p2; - size_t maxlen, len; - cookie_t cookie = hd->read_cookie; - const char *s; - - /* Delete old header lines. */ - while (hd->headers) - { - header_t tmp = hd->headers->next; - xfree (hd->headers->value); - xfree (hd->headers); - hd->headers = tmp; - } - - /* Wait for the status line. */ - do - { - maxlen = MAX_LINELEN; - len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen); - line = hd->buffer; - if (!line) - return gpg_error_from_syserror (); /* Out of core. */ - if (!maxlen) - return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */ - if (!len) - return gpg_error (GPG_ERR_EOF); - if ( (hd->flags & HTTP_FLAG_LOG_RESP) ) - log_info ("RESP: `%.*s'\n", - (int)strlen(line)-(*line&&line[1]?2:0),line); - } - while (!*line); - - if ((p = strchr (line, '/'))) - *p++ = 0; - if (!p || strcmp (line, "HTTP")) - return 0; /* Assume http 0.9. */ - - if ((p2 = strpbrk (p, " \t"))) - { - *p2++ = 0; - p2 += strspn (p2, " \t"); - } - if (!p2) - return 0; /* Also assume http 0.9. */ - p = p2; - /* TODO: Add HTTP version number check. */ - if ((p2 = strpbrk (p, " \t"))) - *p2++ = 0; - if (!isdigit ((unsigned int)p[0]) || !isdigit ((unsigned int)p[1]) - || !isdigit ((unsigned int)p[2]) || p[3]) - { - /* Malformed HTTP status code - assume http 0.9. */ - hd->is_http_0_9 = 1; - hd->status_code = 200; - return 0; - } - hd->status_code = atoi (p); - - /* Skip all the header lines and wait for the empty line. */ - do - { - maxlen = MAX_LINELEN; - len = es_read_line (hd->fp_read, &hd->buffer, &hd->buffer_size, &maxlen); - line = hd->buffer; - if (!line) - return gpg_error_from_syserror (); /* Out of core. */ - /* Note, that we can silently ignore truncated lines. */ - if (!len) - return gpg_error (GPG_ERR_EOF); - /* Trim line endings of empty lines. */ - if ((*line == '\r' && line[1] == '\n') || *line == '\n') - *line = 0; - if ( (hd->flags & HTTP_FLAG_LOG_RESP) ) - log_info ("RESP: `%.*s'\n", - (int)strlen(line)-(*line&&line[1]?2:0),line); - if ( (hd->flags & HTTP_FLAG_NEED_HEADER) && *line ) - { - gpg_error_t err = store_header (hd, line); - if (err) - return err; - } - } - while (len && *line); - - cookie->content_length_valid = 0; - if (!(hd->flags & HTTP_FLAG_IGNORE_CL)) - { - s = http_get_header (hd, "Content-Length"); - if (s) - { - cookie->content_length_valid = 1; - cookie->content_length = counter_strtoul (s); - } - } - - return 0; -} - -#if 0 -static int -start_server () -{ - struct sockaddr_in mya; - struct sockaddr_in peer; - int fd, client; - fd_set rfds; - int addrlen; - int i; - - if ((fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) - { - log_error ("socket() failed: %s\n", strerror (errno)); - return -1; - } - i = 1; - if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (byte *) & i, sizeof (i))) - log_info ("setsockopt(SO_REUSEADDR) failed: %s\n", strerror (errno)); - - mya.sin_family = AF_INET; - memset (&mya.sin_addr, 0, sizeof (mya.sin_addr)); - mya.sin_port = htons (11371); - - if (bind (fd, (struct sockaddr *) &mya, sizeof (mya))) - { - log_error ("bind to port 11371 failed: %s\n", strerror (errno)); - sock_close (fd); - return -1; - } - - if (listen (fd, 5)) - { - log_error ("listen failed: %s\n", strerror (errno)); - sock_close (fd); - return -1; - } - - for (;;) - { - FD_ZERO (&rfds); - FD_SET (fd, &rfds); - - if (select (fd + 1, &rfds, NULL, NULL, NULL) <= 0) - continue; /* ignore any errors */ - - if (!FD_ISSET (fd, &rfds)) - continue; - - addrlen = sizeof peer; - client = accept (fd, (struct sockaddr *) &peer, &addrlen); - if (client == -1) - continue; /* oops */ - - log_info ("connect from %s\n", inet_ntoa (peer.sin_addr)); - - fflush (stdout); - fflush (stderr); - if (!fork ()) - { - int c; - FILE *fp; - - fp = fdopen (client, "r"); - while ((c = getc (fp)) != EOF) - putchar (c); - fclose (fp); - exit (0); - } - sock_close (client); - } - - - return 0; -} -#endif - -/* Actually connect to a server. Returns the file descripto or -1 on - error. ERRNO is set on error. */ -static int -connect_server (const char *server, unsigned short port, - unsigned int flags, const char *srvtag) -{ - int sock = -1; - int srvcount = 0; - int hostfound = 0; - int srv, connected; - int last_errno = 0; - struct srventry *serverlist = NULL; - -#ifdef HAVE_W32_SYSTEM - unsigned long inaddr; - -#ifndef HTTP_NO_WSASTARTUP - init_sockets (); -#endif - /* Win32 gethostbyname doesn't handle IP addresses internally, so we - try inet_addr first on that platform only. */ - inaddr = inet_addr(server); - if ( inaddr != INADDR_NONE ) - { - struct sockaddr_in addr; - - memset(&addr,0,sizeof(addr)); - - sock = socket(AF_INET,SOCK_STREAM,0); - if ( sock==INVALID_SOCKET ) - { - log_error("error creating socket: ec=%d\n",(int)WSAGetLastError()); - return -1; - } - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - memcpy (&addr.sin_addr,&inaddr,sizeof(inaddr)); - - if (!connect (sock,(struct sockaddr *)&addr,sizeof(addr)) ) - return sock; - sock_close(sock); - return -1; - } -#endif /*HAVE_W32_SYSTEM*/ - -#ifdef USE_DNS_SRV - /* Do the SRV thing */ - if ((flags & HTTP_FLAG_TRY_SRV) && srvtag) - { - /* We're using SRV, so append the tags. */ - if (1+strlen (srvtag) + 6 + strlen (server) + 1 <= MAXDNAME) - { - char srvname[MAXDNAME]; - - stpcpy (stpcpy (stpcpy (stpcpy (srvname,"_"), srvtag), - "._tcp."), server); - srvcount = getsrv (srvname, &serverlist); - } - } -#else /*!USE_DNS_SRV*/ - (void)flags; - (void)srvtag; -#endif /*!USE_DNS_SRV*/ - - if (!serverlist) - { - /* Either we're not using SRV, or the SRV lookup failed. Make - up a fake SRV record. */ - serverlist = xtrycalloc (1, sizeof *serverlist); - if (!serverlist) - return -1; /* Out of core. */ - serverlist->port = port; - strncpy (serverlist->target, server, MAXDNAME); - serverlist->target[MAXDNAME-1] = '\0'; - srvcount = 1; - } - -#ifdef HAVE_GETADDRINFO - connected = 0; - for (srv=0; srv < srvcount && !connected; srv++) - { - struct addrinfo hints, *res, *ai; - char portstr[35]; - - sprintf (portstr, "%hu", port); - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo (serverlist[srv].target, portstr, &hints, &res)) - continue; /* Not found - try next one. */ - hostfound = 1; - - for (ai = res; ai && !connected; ai = ai->ai_next) - { - if (sock != -1) - sock_close (sock); - sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock == -1) - { - int save_errno = errno; - log_error ("error creating socket: %s\n", strerror (errno)); - freeaddrinfo (res); - xfree (serverlist); - errno = save_errno; - return -1; - } - - if (connect (sock, ai->ai_addr, ai->ai_addrlen)) - last_errno = errno; - else - connected = 1; - } - freeaddrinfo (res); - } -#else /* !HAVE_GETADDRINFO */ - connected = 0; - for (srv=0; srv < srvcount && !connected; srv++) - { - int i; - struct hostent *host = NULL; - struct sockaddr_in addr; - - /* Note: This code is not thread-safe. */ - - memset (&addr, 0, sizeof (addr)); - host = gethostbyname (serverlist[srv].target); - if (!host) - continue; - hostfound = 1; - - if (sock != -1) - sock_close (sock); - sock = socket (host->h_addrtype, SOCK_STREAM, 0); - if (sock == -1) - { - log_error (_("error creating socket: %s\n"), strerror (errno)); - xfree (serverlist); - return -1; - } - - addr.sin_family = host->h_addrtype; - if (addr.sin_family != AF_INET) - { - log_error ("unknown address family for `%s'\n", - serverlist[srv].target); - xfree (serverlist); - return -1; - } - addr.sin_port = htons (serverlist[srv].port); - if (host->h_length != 4) - { - log_error ("illegal address length for `%s'\n", - serverlist[srv].target); - xfree (serverlist); - return -1; - } - - /* Try all A records until one responds. */ - for (i = 0; host->h_addr_list[i] && !connected; i++) - { - memcpy (&addr.sin_addr, host->h_addr_list[i], host->h_length); - if (connect (sock, (struct sockaddr *) &addr, sizeof (addr))) - last_errno = errno; - else - { - connected = 1; - break; - } - } - } -#endif /* !HAVE_GETADDRINFO */ - - xfree (serverlist); - - if (!connected) - { -#ifdef HAVE_W32_SYSTEM - log_error ("can't connect to `%s': %s%sec=%d\n", - server, - hostfound? "":_("host not found"), - hostfound? "":" - ", (int)WSAGetLastError()); -#else - log_error ("can't connect to `%s': %s\n", - server, - hostfound? strerror (last_errno):"host not found"); -#endif - if (sock != -1) - sock_close (sock); - errno = last_errno; - return -1; - } - return sock; -} - - - - -/* Read handler for estream. */ -static ssize_t -cookie_read (void *cookie, void *buffer, size_t size) -{ - cookie_t c = cookie; - int nread; - - if (c->content_length_valid) - { - if (!c->content_length) - return 0; /* EOF */ - if (c->content_length < size) - size = c->content_length; - } - -#ifdef HTTP_USE_GNUTLS - if (c->tls_session) - { - again: - nread = gnutls_record_recv (c->tls_session, buffer, size); - if (nread < 0) - { - if (nread == GNUTLS_E_INTERRUPTED) - goto again; - if (nread == GNUTLS_E_AGAIN) - { - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 50000; - select (0, NULL, NULL, NULL, &tv); - goto again; - } - if (nread == GNUTLS_E_REHANDSHAKE) - goto again; /* A client is allowed to just ignore this request. */ - log_info ("TLS network read failed: %s\n", gnutls_strerror (nread)); - errno = EIO; - return -1; - } - } - else -#endif /*HTTP_USE_GNUTLS*/ - { - do - { - nread = pth_read (c->fd, buffer, size); - } - while (nread == -1 && errno == EINTR); - } - - if (c->content_length_valid && nread > 0) - { - if (nread < c->content_length) - c->content_length -= nread; - else - c->content_length = 0; - } - - return nread; -} - -/* Write handler for estream. */ -static ssize_t -cookie_write (void *cookie, const void *buffer, size_t size) -{ - cookie_t c = cookie; - int nwritten = 0; - -#ifdef HTTP_USE_GNUTLS - if (c->tls_session) - { - int nleft = size; - while (nleft > 0) - { - nwritten = gnutls_record_send (c->tls_session, buffer, nleft); - if (nwritten <= 0) - { - if (nwritten == GNUTLS_E_INTERRUPTED) - continue; - if (nwritten == GNUTLS_E_AGAIN) - { - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 50000; - select (0, NULL, NULL, NULL, &tv); - continue; - } - log_info ("TLS network write failed: %s\n", - gnutls_strerror (nwritten)); - errno = EIO; - return -1; - } - nleft -= nwritten; - buffer += nwritten; - } - } - else -#endif /*HTTP_USE_GNUTLS*/ - { - do - { - nwritten = pth_write (c->fd, buffer, size); - } - while (nwritten == -1 && errno == EINTR); - } - - return nwritten; -} - -/* Close handler for estream. */ -static int -cookie_close (void *cookie) -{ - cookie_t c = cookie; - - if (!c) - return 0; - -#ifdef HTTP_USE_GNUTLS - if (c->tls_session && !c->keep_socket) - { - /* This indicates that the read end has been closed. */ - gnutls_bye (c->tls_session, GNUTLS_SHUT_RDWR); - } -#endif /*HTTP_USE_GNUTLS*/ - if (c->fd != -1 && !c->keep_socket) - sock_close (c->fd); - - xfree (c); - return 0; -} - - - - -/**** Test code ****/ -#ifdef TEST - -static gpg_error_t -verify_callback (http_t hd, void *tls_context, int reserved) -{ - log_info ("verification of certificates skipped\n"); - return 0; -} - - - -/* static void */ -/* my_gnutls_log (int level, const char *text) */ -/* { */ -/* fprintf (stderr, "gnutls:L%d: %s", level, text); */ -/* } */ - -int -main (int argc, char **argv) -{ - int rc; - parsed_uri_t uri; - uri_tuple_t r; - http_t hd; - int c; - gnutls_session_t tls_session = NULL; -#ifdef HTTP_USE_GNUTLS - gnutls_certificate_credentials certcred; - const int certprio[] = { GNUTLS_CRT_X509, 0 }; -#endif /*HTTP_USE_GNUTLS*/ - header_t hdr; - - es_init (); - log_set_prefix ("http-test", 1 | 4); - if (argc == 1) - { - /*start_server (); */ - return 0; - } - - if (argc != 2) - { - fprintf (stderr, "usage: http-test uri\n"); - return 1; - } - argc--; - argv++; - -#ifdef HTTP_USE_GNUTLS - rc = gnutls_global_init (); - if (rc) - log_error ("gnutls_global_init failed: %s\n", gnutls_strerror (rc)); - rc = gnutls_certificate_allocate_credentials (&certcred); - if (rc) - log_error ("gnutls_certificate_allocate_credentials failed: %s\n", - gnutls_strerror (rc)); -/* rc = gnutls_certificate_set_x509_trust_file */ -/* (certcred, "ca.pem", GNUTLS_X509_FMT_PEM); */ -/* if (rc) */ -/* log_error ("gnutls_certificate_set_x509_trust_file failed: %s\n", */ -/* gnutls_strerror (rc)); */ - rc = gnutls_init (&tls_session, GNUTLS_CLIENT); - if (rc) - log_error ("gnutls_init failed: %s\n", gnutls_strerror (rc)); - rc = gnutls_set_default_priority (tls_session); - if (rc) - log_error ("gnutls_set_default_priority failed: %s\n", - gnutls_strerror (rc)); - rc = gnutls_certificate_type_set_priority (tls_session, certprio); - if (rc) - log_error ("gnutls_certificate_type_set_priority failed: %s\n", - gnutls_strerror (rc)); - rc = gnutls_credentials_set (tls_session, GNUTLS_CRD_CERTIFICATE, certcred); - if (rc) - log_error ("gnutls_credentials_set failed: %s\n", gnutls_strerror (rc)); -/* gnutls_global_set_log_function (my_gnutls_log); */ -/* gnutls_global_set_log_level (4); */ - - http_register_tls_callback (verify_callback); -#endif /*HTTP_USE_GNUTLS*/ - - rc = http_parse_uri (&uri, *argv); - if (rc) - { - log_error ("`%s': %s\n", *argv, gpg_strerror (rc)); - http_release_parsed_uri (uri); - return 1; - } - - printf ("Scheme: %s\n", uri->scheme); - printf ("Host : %s\n", uri->host); - printf ("Port : %u\n", uri->port); - printf ("Path : %s\n", uri->path); - for (r = uri->params; r; r = r->next) - { - printf ("Params: %s", r->name); - if (!r->no_value) - { - printf ("=%s", r->value); - if (strlen (r->value) != r->valuelen) - printf (" [real length=%d]", (int) r->valuelen); - } - putchar ('\n'); - } - for (r = uri->query; r; r = r->next) - { - printf ("Query : %s", r->name); - if (!r->no_value) - { - printf ("=%s", r->value); - if (strlen (r->value) != r->valuelen) - printf (" [real length=%d]", (int) r->valuelen); - } - putchar ('\n'); - } - http_release_parsed_uri (uri); - uri = NULL; - - rc = http_open_document (&hd, *argv, NULL, - HTTP_FLAG_NEED_HEADER, - NULL, tls_session); - if (rc) - { - log_error ("can't get `%s': %s\n", *argv, gpg_strerror (rc)); - return 1; - } - log_info ("open_http_document succeeded; status=%u\n", - http_get_status_code (hd)); - for (hdr = hd->headers; hdr; hdr = hdr->next) - printf ("HDR: %s: %s\n", hdr->name, hdr->value); - switch (http_get_status_code (hd)) - { - case 200: - while ((c = es_getc (http_get_read_ptr (hd))) != EOF) - putchar (c); - break; - case 301: - case 302: - printf ("Redirected to `%s'\n", http_get_header (hd, "Location")); - break; - } - http_close (hd, 0); - -#ifdef HTTP_USE_GNUTLS - gnutls_deinit (tls_session); - gnutls_certificate_free_credentials (certcred); - gnutls_global_deinit (); -#endif /*HTTP_USE_GNUTLS*/ - - return 0; -} -#endif /*TEST*/ - -/* -Local Variables: -compile-command: "gcc -I.. -I../gl -DTEST -DHAVE_CONFIG_H -Wall -O2 -g -o http-test http.c -L. -lcommon -L../jnlib -ljnlib -lgcrypt -lpth -lgnutls" -End: -*/ diff --git a/dirmngr/http.h b/dirmngr/http.h deleted file mode 100644 index 6e688b8d1..000000000 --- a/dirmngr/http.h +++ /dev/null @@ -1,109 +0,0 @@ -/* http.h - HTTP protocol handler - * Copyright (C) 1999, 2000, 2001, 2003, - * 2006 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ -#ifndef GNUPG_COMMON_HTTP_H -#define GNUPG_COMMON_HTTP_H - -#include -#include "estream.h" - -struct uri_tuple_s { - struct uri_tuple_s *next; - const char *name; /* A pointer into name. */ - char *value; /* A pointer to value (a Nul is always appended). */ - size_t valuelen; /* The real length of the value; we need it - because the value may contain embedded Nuls. */ - int no_value; /* True if no value has been given in the URL. */ -}; -typedef struct uri_tuple_s *uri_tuple_t; - -struct parsed_uri_s -{ - /* All these pointers point into BUFFER; most stuff is not escaped. */ - char *scheme; /* Pointer to the scheme string (lowercase). */ - int use_tls; /* Whether TLS should be used. */ - char *auth; /* username/password for basic auth */ - char *host; /* Host (converted to lowercase). */ - unsigned short port; /* Port (always set if the host is set). */ - char *path; /* Path. */ - uri_tuple_t params; /* ";xxxxx" */ - uri_tuple_t query; /* "?xxx=yyy" */ - char buffer[1]; /* Buffer which holds a (modified) copy of the URI. */ -}; -typedef struct parsed_uri_s *parsed_uri_t; - -typedef enum - { - HTTP_REQ_GET = 1, - HTTP_REQ_HEAD = 2, - HTTP_REQ_POST = 3 - } -http_req_t; - -/* We put the flag values into an enum, so that gdb can display them. */ -enum - { - HTTP_FLAG_TRY_PROXY = 1, - HTTP_FLAG_SHUTDOWN = 2, - HTTP_FLAG_TRY_SRV = 4, - HTTP_FLAG_LOG_RESP = 8, - HTTP_FLAG_NEED_HEADER = 16, - HTTP_FLAG_IGNORE_CL = 32 - }; - -struct http_context_s; -typedef struct http_context_s *http_t; - -void http_register_tls_callback (gpg_error_t (*cb) (http_t, void *, int)); - -gpg_error_t http_parse_uri (parsed_uri_t *ret_uri, const char *uri); - -void http_release_parsed_uri (parsed_uri_t uri); - -gpg_error_t http_open (http_t *r_hd, http_req_t reqtype, - const char *url, - const char *auth, - unsigned int flags, - const char *proxy, - void *tls_context); - -void http_start_data (http_t hd); - -gpg_error_t http_wait_response (http_t hd); - -void http_close (http_t hd, int keep_read_stream); - -gpg_error_t http_open_document (http_t *r_hd, - const char *document, - const char *auth, - unsigned int flags, - const char *proxy, - void *tls_context); - -estream_t http_get_read_ptr (http_t hd); -estream_t http_get_write_ptr (http_t hd); -unsigned int http_get_status_code (http_t hd); -const char *http_get_header (http_t hd, const char *name); - -char *http_escape_string (const char *string, const char *specials); - - -#endif /*GNUPG_COMMON_HTTP_H*/ diff --git a/dirmngr/ocsp.c b/dirmngr/ocsp.c index a8db51d17..ec727f014 100644 --- a/dirmngr/ocsp.c +++ b/dirmngr/ocsp.c @@ -166,10 +166,8 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp, gcry_md_hd_t md, once_more: err = http_open (&http, HTTP_REQ_POST, url, NULL, - (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0) - |HTTP_FLAG_NEED_HEADER, - opt.http_proxy, - NULL); + (opt.honor_http_proxy? HTTP_FLAG_TRY_PROXY:0), + opt.http_proxy, NULL, NULL, NULL); if (err) { log_error (_("error connecting to `%s': %s\n"), url, gpg_strerror (err)); diff --git a/dirmngr/server.c b/dirmngr/server.c index a7b623cb1..ce0a5b3c8 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -1143,7 +1143,7 @@ static gpg_error_t cmd_listcrls (assuan_context_t ctx, char *line) { gpg_error_t err; - FILE *fp = assuan_get_data_fp (ctx); + estream_t fp = assuan_get_data_fp (ctx); (void)line; diff --git a/doc/gpg.texi b/doc/gpg.texi index 1b85129d6..3b22fa70e 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -527,12 +527,13 @@ Print message digest of algorithm ALGO for all given files or STDIN. With the second form (or a deprecated "*" as algo) digests for all available algorithms are printed. -@item --gen-random @code{0|1|2} +@item --gen-random @code{0|1|2} @code{count} @opindex gen-random -Emit @var{count} random bytes of the given quality level. If count is -not given or zero, an endless sequence of random bytes will be emitted. -PLEASE, don't use this command unless you know what you are doing; it -may remove precious entropy from the system! +Emit @var{count} random bytes of the given quality level 0, 1 or 2. If +@var{count} is not given or zero, an endless sequence of random bytes +will be emitted. If used with @option{--armor} the output will be +base64 encoded. PLEASE, don't use this command unless you know what +you are doing; it may remove precious entropy from the system! @item --gen-prime @code{mode} @code{bits} @opindex gen-prime diff --git a/scripts/gpg-w32-dev/GNUmakefile b/scripts/gpg-w32-dev/GNUmakefile index f6502c279..10ba92f62 100644 --- a/scripts/gpg-w32-dev/GNUmakefile +++ b/scripts/gpg-w32-dev/GNUmakefile @@ -83,7 +83,7 @@ else pkgrep = ftp://ftp.gnupg.org/gcrypt speedo_pkg_libgpg_error_tar = $(pkgrep)/libgpg-error/libgpg-error-1.8.tar.bz2 speedo_pkg_libassuan_tar = $(pkgrep)/libassuan/libassuan-2.0.0.tar.bz2 - speedo_pkg_libgcrypt_tar = $(pkgrep)/libgcrypt/libgcrypt-1.4.5.tar.bz2 + speedo_pkg_libgcrypt_tar = $(pkgrep)/libgcrypt/libgcrypt-1.4.6.tar.bz2 speedo_pkg_libksba_tar = $(pkgrep)/libksba/libksba-1.0.7.tar.bz2 speedo_pkg_gpgme_tar = $(pkgrep)/gpgme/gpgme-1.3.0.tar.bz2 endif diff --git a/tools/ChangeLog b/tools/ChangeLog index d3238b28c..5599ff578 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,11 @@ +2010-07-16 Werner Koch + + * gpgtar-create.c: Rewrite to better support W32. + +2010-07-01 Werner Koch + + * gpgtar.c: Add option --set-filename. + 2010-06-24 Werner Koch * gpgconf-comp.c (gpg_agent_runtime_change) diff --git a/tools/Makefile.am b/tools/Makefile.am index fc9725a72..73913de44 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -128,7 +128,8 @@ gpgtar_SOURCES = \ gpgtar-list.c \ no-libgcrypt.c gpgtar_CFLAGS = $(GPG_ERROR_CFLAGS) $(PTH_CFLAGS) -gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS) +#gpgtar_LDADD = $(commonpth_libs) $(PTH_LIBS) $(GPG_ERROR_LIBS) +gpgtar_LDADD = $(common_libs) $(GPG_ERROR_LIBS) $(W32SOCKLIBS) # Make sure that all libs are build before we use them. This is diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c index c7a75f90f..2b2c441fe 100644 --- a/tools/gpgtar-create.c +++ b/tools/gpgtar-create.c @@ -25,14 +25,14 @@ #include #include #include -/* #ifdef HAVE_W32_SYSTEM */ -/* # define WIN32_LEAN_AND_MEAN */ -/* # include */ -/* #else /\*!HAVE_W32_SYSTEM*\/ */ +#ifdef HAVE_W32_SYSTEM +# define WIN32_LEAN_AND_MEAN +# include +#else /*!HAVE_W32_SYSTEM*/ # include # include # include -/* #endif /\*!HAVE_W32_SYSTEM*\/ */ +#endif /*!HAVE_W32_SYSTEM*/ #include #include "i18n.h" @@ -58,9 +58,83 @@ struct scanctrl_s /* Given a fresh header object HDR with only the name field set, try - to gather all available info. */ + to gather all available info. This is the W32 version. */ +#ifdef HAVE_W32_SYSTEM static gpg_error_t -fillup_entry (tar_header_t hdr) +fillup_entry_w32 (tar_header_t hdr) +{ + char *p; + wchar_t *wfname; + WIN32_FILE_ATTRIBUTE_DATA fad; + DWORD attr; + + for (p=hdr->name; *p; p++) + if (*p == '/') + *p = '\\'; + wfname = utf8_to_wchar (hdr->name); + for (p=hdr->name; *p; p++) + if (*p == '\\') + *p = '/'; + if (!wfname) + { + log_error ("error utf8-ing `%s': %s\n", hdr->name, w32_strerror (-1)); + return gpg_error_from_syserror (); + } + if (!GetFileAttributesExW (wfname, GetFileExInfoStandard, &fad)) + { + log_error ("error stat-ing `%s': %s\n", hdr->name, w32_strerror (-1)); + xfree (wfname); + return gpg_error_from_syserror (); + } + xfree (wfname); + + attr = fad.dwFileAttributes; + + if ((attr & FILE_ATTRIBUTE_NORMAL)) + hdr->typeflag = TF_REGULAR; + else if ((attr & FILE_ATTRIBUTE_DIRECTORY)) + hdr->typeflag = TF_DIRECTORY; + else if ((attr & FILE_ATTRIBUTE_DEVICE)) + hdr->typeflag = TF_NOTSUP; + else if ((attr & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_TEMPORARY))) + hdr->typeflag = TF_NOTSUP; + else + hdr->typeflag = TF_REGULAR; + + /* Map some attributes to USTAR defined mode bits. */ + hdr->mode = 0640; /* User may read and write, group only read. */ + if ((attr & FILE_ATTRIBUTE_DIRECTORY)) + hdr->mode |= 0110; /* Dirs are user and group executable. */ + if ((attr & FILE_ATTRIBUTE_READONLY)) + hdr->mode &= ~0200; /* Clear the user write bit. */ + if ((attr & FILE_ATTRIBUTE_HIDDEN)) + hdr->mode &= ~0707; /* Clear all user and other bits. */ + if ((attr & FILE_ATTRIBUTE_SYSTEM)) + hdr->mode |= 0004; /* Make it readable by other. */ + + /* Only set the size for a regular file. */ + if (hdr->typeflag == TF_REGULAR) + hdr->size = (fad.nFileSizeHigh * (unsigned long long)(MAXDWORD+1) + + fad.nFileSizeLow); + + hdr->mtime = (((unsigned long long)fad.ftLastWriteTime.dwHighDateTime << 32) + | fad.ftLastWriteTime.dwLowDateTime); + if (!hdr->mtime) + hdr->mtime = (((unsigned long long)fad.ftCreationTime.dwHighDateTime << 32) + | fad.ftCreationTime.dwLowDateTime); + hdr->mtime -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */ + hdr->mtime /= 10000000; /* Convert from 0.1us to seconds. */ + + return 0; +} +#endif /*HAVE_W32_SYSTEM*/ + + +/* Given a fresh header obje`mtime = sbuf.st_mtime; - return 0; } +#endif /*!HAVE_W32_SYSTEM*/ - +/* Add a new entry. The name of a director entry is ENTRYNAME; if + that is NULL, DNAME is the name of the directory itself. Under + Windows ENTRYNAME shall have backslashes replaced by standard + slashes. */ static gpg_error_t -add_entry (const char *dname, size_t dnamelen, struct dirent *de, - scanctrl_t scanctrl) +add_entry (const char *dname, const char *entryname, scanctrl_t scanctrl) { gpg_error_t err; tar_header_t hdr; char *p; + size_t dnamelen = strlen (dname); assert (dnamelen); hdr = xtrycalloc (1, sizeof *hdr + dnamelen + 1 - + (de? strlen (de->d_name) : 0)); + + (entryname? strlen (entryname) : 0) + 1); if (!hdr) - { - err = gpg_error_from_syserror (); - log_error (_("error reading directory `%s': %s\n"), - dname, gpg_strerror (err)); - return err; - } + return gpg_error_from_syserror (); p = stpcpy (hdr->name, dname); - if (de) + if (entryname) { if (dname[dnamelen-1] != '/') *p++ = '/'; - strcpy (p, de->d_name); + strcpy (p, entryname); } else { @@ -171,11 +243,10 @@ add_entry (const char *dname, size_t dnamelen, struct dirent *de, hdr->name[dnamelen-1] = 0; } #ifdef HAVE_DOSISH_SYSTEM - for (p=hdr->name; *p; p++) - if (*p == '\\') - *p = '/'; + err = fillup_entry_w32 (hdr); +#else + err = fillup_entry_posix (hdr); #endif - err = fillup_entry (hdr); if (err) xfree (hdr); else @@ -194,12 +265,101 @@ static gpg_error_t scan_directory (const char *dname, scanctrl_t scanctrl) { gpg_error_t err = 0; - size_t dnamelen; + +#ifdef HAVE_W32_SYSTEM + WIN32_FIND_DATAW fi; + HANDLE hd = INVALID_HANDLE_VALUE; + char *p; + + if (!*dname) + return 0; /* An empty directory name has no entries. */ + + { + char *fname; + wchar_t *wfname; + + fname = xtrymalloc (strlen (dname) + 2 + 2 + 1); + if (!fname) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (!strcmp (dname, "/")) + strcpy (fname, "/*"); /* Trailing slash is not allowed. */ + else if (!strcmp (dname, ".")) + strcpy (fname, "*"); + else if (*dname && dname[strlen (dname)-1] == '/') + strcpy (stpcpy (fname, dname), "*"); + else if (*dname && dname[strlen (dname)-1] != '*') + strcpy (stpcpy (fname, dname), "/*"); + else + strcpy (fname, dname); + + for (p=fname; *p; p++) + if (*p == '/') + *p = '\\'; + wfname = utf8_to_wchar (fname); + xfree (fname); + if (!wfname) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, gpg_strerror (err)); + goto leave; + } + hd = FindFirstFileW (wfname, &fi); + if (hd == INVALID_HANDLE_VALUE) + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, w32_strerror (-1)); + xfree (wfname); + goto leave; + } + xfree (wfname); + } + + do + { + char *fname = wchar_to_utf8 (fi.cFileName); + if (!fname) + { + err = gpg_error_from_syserror (); + log_error ("error utf8-ing filename: %s\n", w32_strerror (-1)); + break; + } + for (p=fname; *p; p++) + if (*p == '\\') + *p = '/'; + if (!strcmp (fname, "." ) || !strcmp (fname, "..")) + err = 0; /* Skip self and parent dir entry. */ + else if (!strncmp (dname, "./", 2) && dname[2]) + err = add_entry (dname+2, fname, scanctrl); + else + err = add_entry (dname, fname, scanctrl); + xfree (fname); + } + while (!err && FindNextFileW (hd, &fi)); + if (err) + ; + else if (GetLastError () == ERROR_NO_MORE_FILES) + err = 0; + else + { + err = gpg_error_from_syserror (); + log_error (_("error reading directory `%s': %s\n"), + dname, w32_strerror (-1)); + } + + leave: + if (hd != INVALID_HANDLE_VALUE) + FindClose (hd); + +#else /*!HAVE_W32_SYSTEM*/ DIR *dir; struct dirent *de; - dnamelen = strlen (dname); - if (!dnamelen) + if (!*dname) return 0; /* An empty directory name has no entries. */ dir = opendir (dname); @@ -216,13 +376,14 @@ scan_directory (const char *dname, scanctrl_t scanctrl) if (!strcmp (de->d_name, "." ) || !strcmp (de->d_name, "..")) continue; /* Skip self and parent dir entry. */ - err = add_entry (dname, dnamelen, de, scanctrl); + err = add_entry (dname, de->d_name, scanctrl); if (err) goto leave; } leave: closedir (dir); +#endif /*!HAVE_W32_SYSTEM*/ return err; } @@ -343,6 +504,9 @@ store_uname (char *buffer, size_t length, unsigned long uid) if (!initialized || uid != lastuid) { +#ifdef HAVE_W32_SYSTEM + mem2str (lastuname, uid? "user":"root", sizeof lastuname); +#else struct passwd *pw = getpwuid (uid); lastuid = uid; @@ -354,6 +518,7 @@ store_uname (char *buffer, size_t length, unsigned long uid) log_info ("failed to get name for uid %lu\n", uid); *lastuname = 0; } +#endif } mem2str (buffer, lastuname, length); } @@ -368,6 +533,9 @@ store_gname (char *buffer, size_t length, unsigned long gid) if (!initialized || gid != lastgid) { +#ifdef HAVE_W32_SYSTEM + mem2str (lastgname, gid? "users":"root", sizeof lastgname); +#else struct group *gr = getgrgid (gid); lastgid = gid; @@ -379,6 +547,7 @@ store_gname (char *buffer, size_t length, unsigned long gid) log_info ("failed to get name for gid %lu\n", gid); *lastgname = 0; } +#endif } mem2str (buffer, lastgname, length); } @@ -446,6 +615,7 @@ build_header (void *record, tar_header_t hdr) store_uname (raw->uname, sizeof raw->uname, hdr->uid); store_gname (raw->gname, sizeof raw->gname, hdr->gid); +#ifndef HAVE_W32_SYSTEM if (hdr->typeflag == TF_SYMLINK) { int nread; @@ -460,7 +630,7 @@ build_header (void *record, tar_header_t hdr) } raw->linkname[nread] = 0; } - +#endif /*HAVE_W32_SYSTEM*/ /* Compute the checksum. */ memset (raw->checksum, ' ', sizeof raw->checksum); @@ -520,6 +690,8 @@ write_file (estream_t stream, tar_header_t hdr) while (hdr->nrecords--) { nbytes = hdr->nrecords? RECORDSIZE : (hdr->size % RECORDSIZE); + if (!nbytes) + nbytes = RECORDSIZE; nread = es_fread (record, 1, nbytes, infp); if (nread != nbytes) { @@ -572,24 +744,40 @@ gpgtar_create (char **inpattern) struct scanctrl_s scanctrl_buffer; scanctrl_t scanctrl = &scanctrl_buffer; tar_header_t hdr, *start_tail; - estream_t outstream; + estream_t outstream = NULL; memset (scanctrl, 0, sizeof *scanctrl); scanctrl->flist_tail = &scanctrl->flist; for (; (pattern = *inpattern); inpattern++) { + char *pat, *p; + if (!*pattern) continue; + + pat = xtrystrdup (pattern); + if (!pat) + { + err = gpg_error_from_syserror (); + log_error ("memory allocation problem: %s\n", gpg_strerror (err)); + goto leave; + } + for (p=pat; *p; p++) + if (*p == '\\') + *p = '/'; + if (opt.verbose > 1) - log_info ("scanning `%s'\n", pattern); + log_info ("scanning `%s'\n", pat); start_tail = scanctrl->flist_tail; - if (!pattern_valid_p (pattern)) - log_error ("skipping invalid name `%s'\n", pattern); - else if (!add_entry (pattern, strlen (pattern), NULL, scanctrl) + if (!pattern_valid_p (pat)) + log_error ("skipping invalid name `%s'\n", pat); + else if (!add_entry (pat, NULL, scanctrl) && *start_tail && ((*start_tail)->typeflag & TF_DIRECTORY)) - scan_recursive (pattern, scanctrl); + scan_recursive (pat, scanctrl); + + xfree (pat); } if (opt.outfile) diff --git a/tools/gpgtar-extract.c b/tools/gpgtar-extract.c index 002215c5d..028ac0df4 100644 --- a/tools/gpgtar-extract.c +++ b/tools/gpgtar-extract.c @@ -32,7 +32,6 @@ #include "gpgtar.h" - static gpg_error_t extract_regular (estream_t stream, const char *dirname, tar_header_t hdr) @@ -79,6 +78,8 @@ extract_regular (estream_t stream, const char *dirname, /* Fixme: Set permissions etc. */ leave: + if (!err && opt.verbose) + log_info ("extracted `%s/'\n", fname); es_fclose (outfp); if (err && fname && outfp) { @@ -96,7 +97,9 @@ extract_directory (const char *dirname, tar_header_t hdr) { gpg_error_t err; char *fname; - + size_t prefixlen; + + prefixlen = strlen (dirname) + 1; fname = strconcat (dirname, "/", hdr->name, NULL); if (!fname) { @@ -107,14 +110,40 @@ extract_directory (const char *dirname, tar_header_t hdr) else err = 0; + if (fname[strlen (fname)-1] == '/') + fname[strlen (fname)-1] = 0; + + /* Note that we don't need to care about EEXIST because we always + extract into a new hierarchy. */ if (gnupg_mkdir (fname, "-rwx------")) { err = gpg_error_from_syserror (); - log_error ("error creating directory `%s': %s\n", - fname, gpg_strerror (err)); + if (gpg_err_code (err) == GPG_ERR_ENOENT) + { + /* Try to create the directory with parents but keep the + original error code in case of a failure. */ + char *p; + int rc = 0; + + for (p = fname+prefixlen; (p = strchr (p, '/')); p++) + { + *p = 0; + rc = gnupg_mkdir (fname, "-rwx------"); + *p = '/'; + if (rc) + break; + } + if (!rc && !gnupg_mkdir (fname, "-rwx------")) + err = 0; + } + if (err) + log_error ("error creating directory `%s': %s\n", + fname, gpg_strerror (err)); } leave: + if (!err && opt.verbose) + log_info ("created `%s/'\n", fname); xfree (fname); return err; } @@ -155,7 +184,8 @@ extract (estream_t stream, const char *dirname, tar_header_t hdr) { char record[RECORDSIZE]; - log_info ("unsupported file type for `%s' - skipped\n", hdr->name); + log_info ("unsupported file type %d for `%s' - skipped\n", + (int)hdr->typeflag, hdr->name); for (err = 0, n=0; !err && n < hdr->nrecords; n++) err = read_record (stream, record); } @@ -171,9 +201,31 @@ static char * create_directory (const char *dirprefix) { gpg_error_t err = 0; + char *prefix_buffer = NULL; char *dirname = NULL; + size_t n; int idx; + /* Remove common suffixes. */ + n = strlen (dirprefix); + if (n > 4 && (!compare_filenames (dirprefix + n - 4, EXTSEP_S "gpg") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "pgp") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "asc") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "pem") + || !compare_filenames (dirprefix + n - 4, EXTSEP_S "p7e"))) + { + prefix_buffer = xtrystrdup (dirprefix); + if (!prefix_buffer) + { + err = gpg_error_from_syserror (); + goto leave; + } + prefix_buffer[n-4] = 0; + dirprefix = prefix_buffer; + } + + + for (idx=1; idx < 5000; idx++) { xfree (dirname); @@ -184,14 +236,14 @@ create_directory (const char *dirprefix) goto leave; } if (!gnupg_mkdir (dirname, "-rwx------")) - goto leave; + goto leave; /* Ready. */ if (errno != EEXIST && errno != ENOTDIR) { err = gpg_error_from_syserror (); goto leave; } } - err = gpg_error_from_syserror (); + err = gpg_error (GPG_ERR_LIMIT_REACHED); leave: if (err) @@ -201,6 +253,7 @@ create_directory (const char *dirprefix) xfree (dirname); dirname = NULL; } + xfree (prefix_buffer); return dirname; } @@ -217,9 +270,6 @@ gpgtar_extract (const char *filename) if (filename) { - dirprefix = strrchr (filename, '/'); - if (dirprefix) - dirprefix++; stream = es_fopen (filename, "rb"); if (!stream) { @@ -231,6 +281,20 @@ gpgtar_extract (const char *filename) else stream = es_stdin; /* FIXME: How can we enforce binary mode? */ + + if (filename) + { + dirprefix = strrchr (filename, '/'); + if (dirprefix) + dirprefix++; + } + else if (opt.filename) + { + dirprefix = strrchr (opt.filename, '/'); + if (dirprefix) + dirprefix++; + } + if (!dirprefix || !*dirprefix) dirprefix = "GPGARCH"; diff --git a/tools/gpgtar-list.c b/tools/gpgtar-list.c index 82711c19e..1de15b58c 100644 --- a/tools/gpgtar-list.c +++ b/tools/gpgtar-list.c @@ -89,8 +89,7 @@ parse_header (const void *record, const char *filename) for (namelen=0; namelen < sizeof raw->name && raw->name[namelen]; namelen++) ; if (namelen == sizeof raw->name) - log_info ("%s: warning: name not terminated by a nul byte\n", - filename); + log_info ("%s: warning: name not terminated by a nul byte\n", filename); for (n=namelen+1; n < sizeof raw->name; n++) if (raw->name[n]) { diff --git a/tools/gpgtar.c b/tools/gpgtar.c index 555fe39dc..8a9aaaf9b 100644 --- a/tools/gpgtar.c +++ b/tools/gpgtar.c @@ -59,6 +59,7 @@ enum cmd_and_opt_values aSignEncrypt, oSkipCrypto, + oSetFilename, aList }; @@ -82,6 +83,7 @@ static ARGPARSE_OPTS opts[] = { ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")), ARGPARSE_s_n (oSkipCrypto, "skip-crypto", N_("skip the crypto processing")), + ARGPARSE_s_s (oSetFilename, "set-filename", "@"), ARGPARSE_end () }; @@ -175,6 +177,7 @@ main (int argc, char **argv) switch (pargs.r_opt) { case oOutput: opt.outfile = pargs.r.ret_str; break; + case oSetFilename: opt.filename = pargs.r.ret_str; break; case oQuiet: opt.quiet = 1; break; case oVerbose: opt.verbose++; break; case oNoVerbose: opt.verbose = 0; break; @@ -208,6 +211,8 @@ main (int argc, char **argv) if (argc > 1) usage (1); fname = argc ? *argv : NULL; + if (opt.filename) + log_info ("note: ignoring option --set-filename\n"); if (skip_crypto) gpgtar_list (fname); else @@ -217,6 +222,8 @@ main (int argc, char **argv) case aEncrypt: if (!argc) usage (1); + if (opt.filename) + log_info ("note: ignoring option --set-filename\n"); if (skip_crypto) gpgtar_create (argv); else @@ -298,6 +305,7 @@ write_record (estream_t stream, const void *record) /* Return true if FP is an unarmored OpenPGP message. Note that this fucntion reads a few bytes from FP but pushes them back. */ +#if 0 static int openpgp_message_p (estream_t fp) { @@ -332,7 +340,7 @@ openpgp_message_p (estream_t fp) } return 0; } - +#endif @@ -340,7 +348,8 @@ openpgp_message_p (estream_t fp) static void tar_and_encrypt (char **inpattern) { - + (void)inpattern; + log_error ("tar_and_encrypt has not yet been implemented\n"); } @@ -348,8 +357,8 @@ tar_and_encrypt (char **inpattern) static void decrypt_and_untar (const char *fname) { - - + (void)fname; + log_error ("decrypt_and_untar has not yet been implemented\n"); } @@ -357,5 +366,6 @@ decrypt_and_untar (const char *fname) static void decrypt_and_list (const char *fname) { - + (void)fname; + log_error ("decrypt_and_list has not yet been implemented\n"); } diff --git a/tools/gpgtar.h b/tools/gpgtar.h index 57fb34a48..08dfcf8b7 100644 --- a/tools/gpgtar.h +++ b/tools/gpgtar.h @@ -27,8 +27,9 @@ struct { int verbose; int quiet; - char *outfile; + const char *outfile; int symmetric; + const char *filename; } opt;