From dc5a80930b2c18011a40f1d929119c2545cc1124 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 6 Aug 2010 13:52:01 +0000 Subject: [PATCH] More work on the dirmngr. It now builds for W32 and W32CE and quick tests show that it works on W32. --- ChangeLog | 4 + common/ChangeLog | 14 ++++ common/homedir.c | 17 +++- common/http.c | 145 ++++++++++++++++----------------- common/http.h | 47 ++++++----- dirmngr/ChangeLog | 21 +++++ dirmngr/certcache.c | 7 +- dirmngr/crlcache.c | 10 +-- dirmngr/crlfetch.c | 4 +- dirmngr/dirmngr.c | 12 ++- dirmngr/ldap-wrapper-ce.c | 2 +- dirmngr/misc.c | 47 ++++++++++- dirmngr/misc.h | 10 +-- dirmngr/server.c | 166 ++++++++++++++++++++++++++++++-------- 14 files changed, 353 insertions(+), 153 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4755b9d51..433b50de1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-08-05 Werner Koch + + * configure.ac (AH_BOTTOM): Remove HTTP_USE_ESTREAM. + 2010-08-02 Werner Koch * configure.ac: Require libksba 1.1.0 due to the use of diff --git a/common/ChangeLog b/common/ChangeLog index 2096ffd60..d69053429 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,17 @@ +2010-08-06 Werner Koch + + * homedir.c (dirmngr_socket_name) [W32CE]: Base on default homedir. + (gnupg_cachedir) [W32CE]: Drop drive letter. + + * http.c (http_open_document): Rename to _http_open_document and + add arg ERRSOURCE. Pass ERRSOURCE to all called funcs. + (http_wait_response, http_open, http_parse_uri): Likewise. + (do_parse_uri, parse_response, store_header): Change to return an + gpg_err_code_t. Change callers. + (send_request): Add arg ERRSOURCE. Change callers. + * http.h (http_open_document, http_wait_response, http_open) + (http_parse_uri): Define as macro. + 2010-08-05 Werner Koch * estream.h (es_asprintf, es_vasprintf): Add lost prototyps. diff --git a/common/homedir.c b/common/homedir.c index 3cd8e9dea..b1bde095c 100644 --- a/common/homedir.c +++ b/common/homedir.c @@ -412,7 +412,12 @@ gnupg_cachedir (void) dir = tmp; } else - dir = "c:\\temp\\cache\\dirmngr"; + { + dir = "c:\\temp\\cache\\gnupg"; +#ifdef HAVE_W32CE_SYSTEM + dir += 2; +#endif + } } return dir; #else /*!HAVE_W32_SYSTEM*/ @@ -430,6 +435,12 @@ dirmngr_socket_name (void) if (!name) { + char *p; +# ifdef HAVE_W32CE_SYSTEM + const char *s1, *s2; + + s1 = default_homedir (); +# else char s1[MAX_PATH]; const char *s2; @@ -440,9 +451,13 @@ dirmngr_socket_name (void) that. */ if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0) strcpy (s1, "C:\\WINDOWS"); +# endif s2 = DIRSEP_S "S.dirmngr"; name = xmalloc (strlen (s1) + strlen (s2) + 1); strcpy (stpcpy (name, s1), s2); + for (p=name; *p; p++) + if (*p == '/') + *p = '\\'; } return name; #else /*!HAVE_W32_SYSTEM*/ diff --git a/common/http.c b/common/http.c index 4ce742020..1e3e89790 100644 --- a/common/http.c +++ b/common/http.c @@ -131,21 +131,18 @@ typedef unsigned long longcounter_t; # define counter_strtoul(a) strtoul ((a), NULL, 10) #endif -#if defined(HTTP_USE_ESTREAM) && defined (__GNUC__) -# warning HTTP_USE_ESTREAM is an obsolete macro -#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 gpg_err_code_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, - const char *srvtag,strlist_t headers); + const char *srvtag,strlist_t headers, + gpg_err_source_t errsource); static char *build_rel_path (parsed_uri_t uri); static gpg_error_t parse_response (http_t hd); @@ -334,9 +331,10 @@ http_register_tls_callback ( gpg_error_t (*cb) (http_t, void *, int) ) 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, const char *srvtag,strlist_t headers) +_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, const char *srvtag, strlist_t headers, + gpg_err_source_t errsource) { gpg_error_t err; http_t hd; @@ -344,7 +342,7 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url, *r_hd = NULL; if (!(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST)) - return gpg_error (GPG_ERR_INV_ARG); + return gpg_err_make (errsource, GPG_ERR_INV_ARG); /* Create the handle. */ hd = xtrycalloc (1, sizeof *hd); @@ -355,9 +353,9 @@ http_open (http_t *r_hd, http_req_t reqtype, const char *url, hd->flags = flags; hd->tls_context = tls_context; - err = http_parse_uri (&hd->uri, url); + err = _http_parse_uri (&hd->uri, url, errsource); if (!err) - err = send_request (hd, auth, proxy, srvtag, headers); + err = send_request (hd, auth, proxy, srvtag, headers, errsource); if (err) { @@ -391,7 +389,7 @@ http_start_data (http_t hd) gpg_error_t -http_wait_response (http_t hd) +_http_wait_response (http_t hd, gpg_err_source_t errsource) { gpg_error_t err; cookie_t cookie; @@ -402,7 +400,7 @@ http_wait_response (http_t hd) /* Close the write stream but keep the socket open. */ cookie = hd->write_cookie; if (!cookie) - return gpg_error (GPG_ERR_INTERNAL); + return gpg_err_make (errsource, GPG_ERR_INTERNAL); cookie->keep_socket = 1; es_fclose (hd->fp_write); @@ -420,7 +418,7 @@ http_wait_response (http_t hd) /* Create a new cookie and a stream for reading. */ cookie = xtrycalloc (1, sizeof *cookie); if (!cookie) - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); cookie->fd = hd->sock; if (hd->uri->use_tls) cookie->tls_session = hd->tls_context; @@ -431,7 +429,7 @@ http_wait_response (http_t hd) { xfree (cookie); hd->read_cookie = NULL; - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); } err = parse_response (hd); @@ -444,18 +442,19 @@ http_wait_response (http_t hd) 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, const char *srvtag,strlist_t headers) +_http_open_document (http_t *r_hd, const char *document, + const char *auth, unsigned int flags, const char *proxy, + void *tls_context, const char *srvtag, strlist_t headers, + gpg_err_source_t errsource) { gpg_error_t err; - err = http_open (r_hd, HTTP_REQ_GET, document, auth, flags, - proxy, tls_context, srvtag, headers); + err = _http_open (r_hd, HTTP_REQ_GET, document, auth, flags, + proxy, tls_context, srvtag, headers, errsource); if (err) return err; - err = http_wait_response (*r_hd); + err = _http_wait_response (*r_hd, errsource); if (err) http_close (*r_hd, 0); @@ -513,13 +512,14 @@ http_get_status_code (http_t hd) * resources (even on error). */ gpg_error_t -http_parse_uri (parsed_uri_t * ret_uri, const char *uri) +_http_parse_uri (parsed_uri_t * ret_uri, const char *uri, + gpg_err_source_t errsource) { *ret_uri = xtrycalloc (1, sizeof **ret_uri + strlen (uri)); if (!*ret_uri) - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); strcpy ((*ret_uri)->buffer, uri); - return do_parse_uri (*ret_uri, 0); + return gpg_err_make (errsource, do_parse_uri (*ret_uri, 0)); } void @@ -539,7 +539,7 @@ http_release_parsed_uri (parsed_uri_t uri) } -static gpg_error_t +static gpg_err_code_t do_parse_uri (parsed_uri_t uri, int only_local_part) { uri_tuple_t *tail; @@ -557,13 +557,13 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) /* A quick validity check. */ if (strspn (p, VALID_URI_CHARS) != n) - return gpg_error (GPG_ERR_BAD_URI); /* Invalid characters found. */ + return 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. */ + return GPG_ERR_BAD_URI; /* No scheme. */ *p2++ = 0; for (pp=p; *pp; pp++) *pp = tolower (*(unsigned char*)pp); @@ -578,13 +578,13 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) } #endif else - return gpg_error (GPG_ERR_INV_URI); /* Unsupported scheme */ + return 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. */ + return GPG_ERR_INV_URI; /* Does not start with a slash. */ p++; if (*p == '/') /* There seems to be a hostname. */ @@ -622,9 +622,9 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) } if ((n = remove_escapes (uri->host)) < 0) - return gpg_error (GPG_ERR_BAD_URI); + return GPG_ERR_BAD_URI; if (n != strlen (uri->host)) - return gpg_error (GPG_ERR_BAD_URI); /* Hostname incudes a Nul. */ + return GPG_ERR_BAD_URI; /* Hostname incudes a Nul. */ p = p2 ? p2 : NULL; } } /* End global URI part. */ @@ -641,9 +641,9 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) uri->path = p; if ((n = remove_escapes (p)) < 0) - return gpg_error (GPG_ERR_BAD_URI); + return GPG_ERR_BAD_URI; if (n != strlen (p)) - return gpg_error (GPG_ERR_BAD_URI); /* Path includes a Nul. */ + return GPG_ERR_BAD_URI; /* Path includes a Nul. */ p = p2 ? p2 : NULL; if (!p || !*p) @@ -658,7 +658,7 @@ do_parse_uri (parsed_uri_t uri, int only_local_part) if ((p2 = strchr (p, '&'))) *p2++ = 0; if (!(elem = parse_tuple (p))) - return gpg_error (GPG_ERR_BAD_URI); + return GPG_ERR_BAD_URI; *tail = elem; tail = &elem->next; @@ -816,7 +816,8 @@ parse_tuple (char *string) */ static gpg_error_t send_request (http_t hd, const char *auth, - const char *proxy,const char *srvtag,strlist_t headers) + const char *proxy, const char *srvtag, strlist_t headers, + gpg_err_source_t errsource) { gnutls_session_t tls_session; gpg_error_t err; @@ -832,7 +833,7 @@ send_request (http_t hd, const char *auth, if (hd->uri->use_tls && !tls_session) { log_error ("TLS requested but no GNUTLS context provided\n"); - return gpg_error (GPG_ERR_INTERNAL); + return gpg_err_make (errsource, GPG_ERR_INTERNAL); } server = *hd->uri->host ? hd->uri->host : "localhost"; @@ -848,14 +849,13 @@ send_request (http_t hd, const char *auth, if (proxy) http_proxy = proxy; - err = http_parse_uri (&uri, http_proxy); + err = _http_parse_uri (&uri, http_proxy, errsource); 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); - + return gpg_err_make (errsource, GPG_ERR_CONFIGURATION); } if (uri->auth) @@ -866,7 +866,7 @@ send_request (http_t hd, const char *auth, uri->auth, strlen(uri->auth)); if (!proxy_authstr) { - err = gpg_error_from_syserror (); + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); http_release_parsed_uri (uri); return err; } @@ -887,9 +887,9 @@ send_request (http_t hd, const char *auth, if (hd->sock == -1) { xfree (proxy_authstr); - return (save_errno - ? gpg_error_from_errno (save_errno) - : gpg_error (GPG_ERR_NOT_FOUND)); + return gpg_err_make (errsource, (save_errno + ? gpg_err_code_from_errno (save_errno) + : GPG_ERR_NOT_FOUND)); } #ifdef HTTP_USE_GNUTLS @@ -907,7 +907,7 @@ send_request (http_t hd, const char *auth, { log_info ("TLS handshake failed: %s\n", gnutls_strerror (rc)); xfree (proxy_authstr); - return gpg_error (GPG_ERR_NETWORK); + return gpg_err_make (errsource, GPG_ERR_NETWORK); } if (tls_callback) @@ -934,7 +934,7 @@ send_request (http_t hd, const char *auth, if (!myauth) { xfree (proxy_authstr); - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); } remove_escapes (myauth); } @@ -952,13 +952,13 @@ send_request (http_t hd, const char *auth, if (!authstr) { xfree (proxy_authstr); - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); } } p = build_rel_path (hd->uri); if (!p) - return gpg_error_from_syserror (); + return gpg_err_make (errsource, gpg_err_code_from_syserror ()); if (http_proxy && *http_proxy) { @@ -991,7 +991,7 @@ send_request (http_t hd, const char *auth, xfree (p); if (!request) { - err = gpg_error_from_syserror (); + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); xfree (authstr); xfree (proxy_authstr); return err; @@ -1006,7 +1006,7 @@ send_request (http_t hd, const char *auth, cookie = xtrycalloc (1, sizeof *cookie); if (!cookie) { - err = gpg_error_from_syserror (); + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); goto leave; } cookie->fd = hd->sock; @@ -1017,12 +1017,12 @@ send_request (http_t hd, const char *auth, hd->fp_write = es_fopencookie (cookie, "w", cookie_functions); if (!hd->fp_write) { + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); 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 (); + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); else err = 0; @@ -1033,7 +1033,7 @@ send_request (http_t hd, const char *auth, if ((es_fputs (headers->d, hd->fp_write) || es_fflush (hd->fp_write)) || (es_fputs("\r\n",hd->fp_write) || es_fflush(hd->fp_write))) { - err = gpg_error_from_syserror (); + err = gpg_err_make (errsource, gpg_err_code_from_syserror ()); break; } } @@ -1128,7 +1128,7 @@ capitalize_header_name (char *name) /* 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 +static gpg_err_code_t store_header (http_t hd, char *line) { size_t n; @@ -1143,17 +1143,17 @@ store_header (http_t hd, char *line) line[--n] = 0; } if (!n) /* we are never called to hit this. */ - return gpg_error (GPG_ERR_BUG); + return 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); + return GPG_ERR_PROTOCOL_VIOLATION; n += strlen (hd->headers->value); p = xtrymalloc (n+1); if (!p) - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); strcpy (stpcpy (p, hd->headers->value), line); xfree (hd->headers->value); hd->headers->value = p; @@ -1163,7 +1163,7 @@ store_header (http_t hd, char *line) capitalize_header_name (line); p = strchr (line, ':'); if (!p) - return gpg_error (GPG_ERR_PROTOCOL_VIOLATION); + return GPG_ERR_PROTOCOL_VIOLATION; *p++ = 0; while (*p == ' ' || *p == '\t') p++; @@ -1178,7 +1178,7 @@ store_header (http_t hd, char *line) 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 (); + return gpg_err_code_from_syserror (); strcpy (stpcpy (stpcpy (p, h->value), ","), value); xfree (h->value); h->value = p; @@ -1188,13 +1188,13 @@ store_header (http_t hd, char *line) /* Append a new header. */ h = xtrymalloc (sizeof *h + strlen (line)); if (!h) - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); strcpy (h->name, line); h->value = xtrymalloc (strlen (value)+1); if (!h->value) { xfree (h); - return gpg_error_from_syserror (); + return gpg_err_code_from_syserror (); } strcpy (h->value, value); h->next = hd->headers; @@ -1226,7 +1226,7 @@ http_get_header (http_t hd, const char *name) * Parse the response from a server. * Returns: Errorcode and sets some files in the handle */ -static gpg_error_t +static gpg_err_code_t parse_response (http_t hd) { char *line, *p, *p2; @@ -1250,12 +1250,13 @@ parse_response (http_t hd) 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. */ + return gpg_err_code_from_syserror (); /* Out of core. */ if (!maxlen) - return gpg_error (GPG_ERR_TRUNCATED); /* Line has been truncated. */ + return GPG_ERR_TRUNCATED; /* Line has been truncated. */ if (!len) - return gpg_error (GPG_ERR_EOF); - if ( (hd->flags & HTTP_FLAG_LOG_RESP) ) + return GPG_ERR_EOF; + + if ((hd->flags & HTTP_FLAG_LOG_RESP)) log_info ("RESP: `%.*s'\n", (int)strlen(line)-(*line&&line[1]?2:0),line); } @@ -1294,21 +1295,21 @@ parse_response (http_t hd) 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. */ + return gpg_err_code_from_syserror (); /* Out of core. */ /* Note, that we can silently ignore truncated lines. */ if (!len) - return gpg_error (GPG_ERR_EOF); + return 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) ) + if ((hd->flags & HTTP_FLAG_LOG_RESP)) log_info ("RESP: `%.*s'\n", (int)strlen(line)-(*line&&line[1]?2:0),line); if (*line) { - gpg_error_t err = store_header (hd, line); - if (err) - return err; + gpg_err_code_t ec = store_header (hd, line); + if (ec) + return ec; } } while (len && *line); diff --git a/common/http.h b/common/http.h index 2dd612ebc..ac9cb1513 100644 --- a/common/http.h +++ b/common/http.h @@ -70,33 +70,44 @@ 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); +gpg_error_t _http_parse_uri (parsed_uri_t *ret_uri, const char *uri, + gpg_err_source_t errsource); +#define http_parse_uri(a,b) \ + _http_parse_uri ((a), (b), GPG_ERR_SOURCE_DEFAULT) 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, - const char *srvtag, - strlist_t headers); +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, + const char *srvtag, + strlist_t headers, + gpg_err_source_t errsource); +#define http_open(a,b,c,d,e,f,g,h,i) \ + _http_open ((a),(b),(c),(d),(e),(f),(g),(h),(i), GPG_ERR_SOURCE_DEFAULT) void http_start_data (http_t hd); -gpg_error_t http_wait_response (http_t hd); +gpg_error_t _http_wait_response (http_t hd, gpg_err_source_t errsource); +#define http_wait_response(a) \ + _http_wait_response ((a), GPG_ERR_SOURCE_DEFAULT) 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, - const char *srvtag, - strlist_t headers); +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, + const char *srvtag, + strlist_t headers, + gpg_err_source_t errsource); +#define http_open_document(a,b,c,d,e,f,g,h) \ + _http_open_document ((a),(b),(c),(d),(e),(f),(g),(h), GPG_ERR_SOURCE_DEFAULT) estream_t http_get_read_ptr (http_t hd); estream_t http_get_write_ptr (http_t hd); diff --git a/dirmngr/ChangeLog b/dirmngr/ChangeLog index 57cc1c772..737ff35fa 100644 --- a/dirmngr/ChangeLog +++ b/dirmngr/ChangeLog @@ -1,3 +1,24 @@ +2010-08-06 Werner Koch + + * dirmngr.c (JNLIB_NEED_AFLOCAL): Define macro. + (main): Use SUN_LEN macro. + (main) [W32]: Allow EEXIST in addition to EADDRINUSE. + (JNLIB_NEED_AFLOCAL): + +2010-08-05 Werner Koch + + * server.c (set_error, leave_cmd): New. + (cmd_validate, cmd_ldapserver, cmd_isvalid, cmd_checkcrl) + (cmd_checkocsp, cmd_lookup, cmd_listcrls, cmd_cachecert): Use + leave_cmd. + (cmd_getinfo): New. + (data_line_cookie_write, data_line_cookie_close): New. + (cmd_listcrls): Replace assuan_get_data_fp by es_fopencookie. + + * misc.c (create_estream_ksba_reader, my_estream_ksba_reader_cb): New. + * certcache.c (load_certs_from_dir): Use create_estream_ksba_reader. + * crlcache.c (crl_cache_load): Ditto. + 2010-08-03 Werner Koch * dirmngr_ldap.c (pth_enter, pth_leave) [USE_LDAPWRAPPER]: Turn diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c index 46d2ac365..d8528118e 100644 --- a/dirmngr/certcache.c +++ b/dirmngr/certcache.c @@ -360,13 +360,10 @@ load_certs_from_dir (const char *dirname, int are_trusted) fname, strerror (errno)); continue; } - err = ksba_reader_new (&reader); - if (!err) - err = ksba_reader_set_file (reader, fp); + + err = create_estream_ksba_reader (&reader, fp); if (err) { - log_error (_("can't setup KSBA reader: %s\n"), gpg_strerror (err)); - ksba_reader_release (reader); es_fclose (fp); continue; } diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c index 441ae9ee0..e08741924 100644 --- a/dirmngr/crlcache.c +++ b/dirmngr/crlcache.c @@ -2369,18 +2369,12 @@ crl_cache_load (ctrl_t ctrl, const char *filename) return err; } - err = ksba_reader_new (&reader); + err = create_estream_ksba_reader (&reader, fp); if (!err) - err = ksba_reader_set_file (reader, fp); - if (err) { - log_error (_("error initializing reader object: %s\n"), - gpg_strerror (err)); + err = crl_cache_insert (ctrl, filename, reader); ksba_reader_release (reader); - return err; } - err = crl_cache_insert (ctrl, filename, reader); - ksba_reader_release (reader); es_fclose (fp); return err; } diff --git a/dirmngr/crlfetch.c b/dirmngr/crlfetch.c index 6c2762cac..83897a698 100644 --- a/dirmngr/crlfetch.c +++ b/dirmngr/crlfetch.c @@ -30,6 +30,7 @@ #include "http.h" #include "estream.h" +#include "ldap-wrapper.h" /* For detecting armored CRLs received via HTTP (yes, such CRLS really @@ -228,7 +229,8 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader) pointer (or well the callback context) with the reader. It is only required when closing the reader thus there is no performance issue doing it - this way. */ + this way. FIXME: We now have a close notification + which might be used here. */ register_file_reader (*reader, cb_ctx); http_close (hd, 1); } diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c index 52efb9be4..7aafc48ce 100644 --- a/dirmngr/dirmngr.c +++ b/dirmngr/dirmngr.c @@ -44,6 +44,7 @@ #define JNLIB_NEED_LOG_LOGV +#define JNLIB_NEED_AFLOCAL #include "dirmngr.h" #include @@ -963,12 +964,17 @@ main (int argc, char **argv) memset (&serv_addr, 0, sizeof serv_addr); serv_addr.sun_family = AF_UNIX; strcpy (serv_addr.sun_path, socket_name); - len = (offsetof (struct sockaddr_un, sun_path) - + strlen (serv_addr.sun_path) + 1); + len = SUN_LEN (&serv_addr); rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); - if (rc == -1 && errno == EADDRINUSE) + if (rc == -1 + && (errno == EADDRINUSE +#ifdef HAVE_W32_SYSTEM + || errno == EEXIST +#endif + )) { + /* Fixme: We should test whether a dirmngr is already running. */ gnupg_remove (socket_name); rc = assuan_sock_bind (fd, (struct sockaddr*) &serv_addr, len); } diff --git a/dirmngr/ldap-wrapper-ce.c b/dirmngr/ldap-wrapper-ce.c index b55153466..9e6f785de 100644 --- a/dirmngr/ldap-wrapper-ce.c +++ b/dirmngr/ldap-wrapper-ce.c @@ -199,7 +199,7 @@ outstream_reader_cb (void *cb_value, char *buffer, size_t count, const char *src; size_t nread = 0; - if (!buffer && !count && !nread) + if (!buffer && !count && !r_nread) return gpg_error (GPG_ERR_NOT_SUPPORTED); /* Rewind is not supported. */ *r_nread = 0; diff --git a/dirmngr/misc.c b/dirmngr/misc.c index 040d4434a..3d33bee58 100644 --- a/dirmngr/misc.c +++ b/dirmngr/misc.c @@ -1,6 +1,6 @@ /* misc.c - miscellaneous * Copyright (C) 2002 Klarälvdalens Datakonsult AB - * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004, 2010 Free Software Foundation, Inc. * * This file is part of DirMngr. * @@ -484,3 +484,48 @@ host_and_port_from_url (const char *url, int *port) return buf; } + +/* A KSBA reader callback to read from an estream. */ +static int +my_estream_ksba_reader_cb (void *cb_value, char *buffer, size_t count, + size_t *r_nread) +{ + estream_t fp = cb_value; + + if (!fp) + return gpg_error (GPG_ERR_INV_VALUE); + + if (!buffer && !count && !r_nread) + { + es_rewind (fp); + return 0; + } + + *r_nread = es_fread (buffer, 1, count, fp); + if (!*r_nread) + return -1; /* EOF or error. */ + return 0; /* Success. */ +} + + +/* Create a KSBA reader object and connect it to the estream FP. */ +gpg_error_t +create_estream_ksba_reader (ksba_reader_t *r_reader, estream_t fp) +{ + gpg_error_t err; + ksba_reader_t reader; + + *r_reader = NULL; + err = ksba_reader_new (&reader); + if (!err) + err = ksba_reader_set_cb (reader, my_estream_ksba_reader_cb, fp); + if (err) + { + log_error (_("error initializing reader object: %s\n"), + gpg_strerror (err)); + ksba_reader_release (reader); + return err; + } + *r_reader = reader; + return 0; +} diff --git a/dirmngr/misc.h b/dirmngr/misc.h index b721549ec..928bf78ae 100644 --- a/dirmngr/misc.h +++ b/dirmngr/misc.h @@ -73,15 +73,9 @@ void dump_cert (const char *text, ksba_cert_t cert); URL. */ char *host_and_port_from_url (const char *url, int *port); +/* Create a KSBA reader object and connect it to the estream FP. */ +gpg_error_t create_estream_ksba_reader (ksba_reader_t *r_reader, estream_t fp); -#ifdef HAVE_FOPENCOOKIE -/* We have to implement funopen in terms of glibc's fopencookie. */ -FILE *funopen(void *cookie, - int (*readfn)(void *, char *, int), - int (*writefn)(void *, const char *, int), - fpos_t (*seekfn)(void *, fpos_t, int), - int (*closefn)(void *)); -#endif /*HAVE_FOPENCOOKIE*/ #endif /* MISC_H */ diff --git a/dirmngr/server.c b/dirmngr/server.c index ce0a5b3c8..584cae743 100644 --- a/dirmngr/server.c +++ b/dirmngr/server.c @@ -40,6 +40,7 @@ #include "certcache.h" #include "validate.h" #include "misc.h" +#include "ldap-wrapper.h" /* To avoid DoS attacks we limit the size of a certificate to something reasonable. */ @@ -47,6 +48,7 @@ #define PARM_ERROR(t) assuan_set_error (ctx, \ gpg_error (GPG_ERR_ASS_PARAMETER), (t)) +#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t)) @@ -61,6 +63,20 @@ struct server_local_s }; +/* Cookie definition for assuan data line output. */ +static ssize_t data_line_cookie_write (void *cookie, + const void *buffer, size_t size); +static int data_line_cookie_close (void *cookie); +static es_cookie_io_functions_t data_line_cookie_functions = + { + NULL, + data_line_cookie_write, + NULL, + data_line_cookie_close + }; + + + /* Accessor for the local ldapservers variable. */ @@ -74,6 +90,55 @@ get_ldapservers_from_ctrl (ctrl_t ctrl) } +/* Helper to print a message while leaving a command. */ +static gpg_error_t +leave_cmd (assuan_context_t ctx, gpg_error_t err) +{ + if (err) + { + const char *name = assuan_get_command_name (ctx); + if (!name) + name = "?"; + if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT) + log_error ("command '%s' failed: %s\n", name, + gpg_strerror (err)); + else + log_error ("command '%s' failed: %s <%s>\n", name, + gpg_strerror (err), gpg_strsource (err)); + } + return err; +} + +/* A write handler used by es_fopencookie to write assuan data + lines. */ +static ssize_t +data_line_cookie_write (void *cookie, const void *buffer, size_t size) +{ + assuan_context_t ctx = cookie; + + if (assuan_send_data (ctx, buffer, size)) + { + gpg_err_set_errno (EIO); + return -1; + } + + return size; +} + +static int +data_line_cookie_close (void *cookie) +{ + assuan_context_t ctx = cookie; + + if (assuan_send_data (ctx, NULL, 0)) + { + gpg_err_set_errno (EIO); + return -1; + } + + return 0; +} + /* Copy the % and + escaped string S into the buffer D and replace the escape sequences. Note, that it is sufficient to allocate the @@ -452,17 +517,17 @@ cmd_ldapserver (assuan_context_t ctx, char *line) while (spacep (line)) line++; if (*line == '\0') - return PARM_ERROR (_("ldapserver missing")); + return leave_cmd (ctx, PARM_ERROR (_("ldapserver missing"))); server = ldapserver_parse_one (line, "", 0); if (! server) - return gpg_error (GPG_ERR_INV_ARG); + return leave_cmd (ctx, gpg_error (GPG_ERR_INV_ARG)); last_next_p = &ctrl->server_local->ldapservers; while (*last_next_p) last_next_p = &(*last_next_p)->next; *last_next_p = server; - return 0; + return leave_cmd (ctx, 0); } @@ -522,7 +587,7 @@ cmd_isvalid (assuan_context_t ctx, char *line) if (strlen (issuerhash) != 40) { xfree (issuerhash); - return PARM_ERROR (_("serialno missing in cert ID")); + return leave_cmd (ctx, PARM_ERROR (_("serialno missing in cert ID"))); } ocsp_mode = 1; } @@ -574,10 +639,8 @@ cmd_isvalid (assuan_context_t ctx, char *line) } } - if (err) - log_error (_("command %s failed: %s\n"), "ISVALID", gpg_strerror (err)); xfree (issuerhash); - return err; + return leave_cmd (ctx, err); } @@ -688,10 +751,8 @@ cmd_checkcrl (assuan_context_t ctx, char *line) } leave: - if (err) - log_error (_("command %s failed: %s\n"), "CHECKCRL", gpg_strerror (err)); ksba_cert_release (cert); - return err; + return leave_cmd (ctx, err); } @@ -773,10 +834,8 @@ cmd_checkocsp (assuan_context_t ctx, char *line) err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder); leave: - if (err) - log_error (_("command %s failed: %s\n"), "CHECKOCSP", gpg_strerror (err)); ksba_cert_release (cert); - return err; + return leave_cmd (ctx, err); } @@ -1066,10 +1125,7 @@ cmd_lookup (assuan_context_t ctx, char *line) else err = lookup_cert_by_pattern (ctx, line, single, cache_only); - if (err) - log_error (_("command %s failed: %s\n"), "LOOKUP", gpg_strerror (err)); - - return err; + return leave_cmd (ctx, err); } @@ -1126,9 +1182,7 @@ cmd_loadcrl (assuan_context_t ctx, char *line) } } - if (err) - log_error (_("command %s failed: %s\n"), "LOADCRL", gpg_strerror (err)); - return err; + return leave_cmd (ctx, err); } @@ -1143,17 +1197,19 @@ static gpg_error_t cmd_listcrls (assuan_context_t ctx, char *line) { gpg_error_t err; - estream_t fp = assuan_get_data_fp (ctx); + estream_t fp; (void)line; + fp = es_fopencookie (ctx, "w", data_line_cookie_functions); if (!fp) - return PARM_ERROR (_("no data stream")); - - err = crl_cache_list (fp); - if (err) - log_error (_("command %s failed: %s\n"), "LISTCRLS", gpg_strerror (err)); - return err; + err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream"); + else + { + err = crl_cache_list (fp); + es_fclose (fp); + } + return leave_cmd (ctx, err); } @@ -1204,10 +1260,8 @@ cmd_cachecert (assuan_context_t ctx, char *line) err = cache_cert (cert); leave: - if (err) - log_error (_("command %s failed: %s\n"), "CACHECERT", gpg_strerror (err)); ksba_cert_release (cert); - return err; + return leave_cmd (ctx, err); } @@ -1273,14 +1327,57 @@ cmd_validate (assuan_context_t ctx, char *line) err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_CERT, NULL); leave: - if (err) - log_error (_("command %s failed: %s\n"), "VALIDATE", gpg_strerror (err)); ksba_cert_release (cert); - return err; + return leave_cmd (ctx, err); +} + + + +static const char hlp_getinfo[] = + "GETINFO \n" + "\n" + "Multi purpose command to return certain information. \n" + "Supported values of WHAT are:\n" + "\n" + "version - Return the version of the program.\n" + "pid - Return the process id of the server.\n" + "\n" + "socket_name - Return the name of the socket.\n"; +static gpg_error_t +cmd_getinfo (assuan_context_t ctx, char *line) +{ + gpg_error_t err; + + if (!strcmp (line, "version")) + { + const char *s = VERSION; + err = assuan_send_data (ctx, s, strlen (s)); + } + else if (!strcmp (line, "pid")) + { + char numbuf[50]; + + snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ()); + err = assuan_send_data (ctx, numbuf, strlen (numbuf)); + } + else if (!strcmp (line, "socket_name")) + { + const char *s = dirmngr_socket_name (); + + if (s) + err = assuan_send_data (ctx, s, strlen (s)); + else + err = gpg_error (GPG_ERR_NO_DATA); + } + else + err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); + + return leave_cmd (ctx, err); } + /* Tell the assuan library about our commands. */ static int register_commands (assuan_context_t ctx) @@ -1299,8 +1396,7 @@ register_commands (assuan_context_t ctx) { "LISTCRLS", cmd_listcrls, hlp_listcrls }, { "CACHECERT", cmd_cachecert, hlp_cachecert }, { "VALIDATE", cmd_validate, hlp_validate }, - { "INPUT", NULL }, - { "OUTPUT", NULL }, + { "GETINFO", cmd_getinfo, hlp_getinfo }, { NULL, NULL } }; int i, j, rc;