* 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 <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
-#include <assert.h>
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#include "i18n.h"
#include "asshelp.h"
#include "keyserver.h"
+#include "status.h"
#include "call-dirmngr.h"
}
+/* Print a warning if the server's version number is less than our
+ version number. Returns an error code on a connection problem. */
+static gpg_error_t
+warn_version_mismatch (assuan_context_t ctx, const char *servername)
+{
+ gpg_error_t err;
+ char *serverversion;
+ const char *myversion = strusage (13);
+
+ err = get_assuan_server_version (ctx, 0, &serverversion);
+ if (err)
+ log_error (_("error getting version from '%s': %s\n"),
+ servername, gpg_strerror (err));
+ else if (compare_version_strings (serverversion, myversion) < 0)
+ {
+ char *warn;
+
+ warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+ servername, serverversion, myversion);
+ if (!warn)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ log_info (_("WARNING: %s\n"), warn);
+ write_status_strings (STATUS_WARNING, "server_version_mismatch 0",
+ " ", warn, NULL);
+ xfree (warn);
+ }
+ }
+ xfree (serverversion);
+ return err;
+}
+
+
/* Try to connect to the Dirmngr via a socket or spawn it if possible.
Handle the server's initial greeting and set global options. */
static gpg_error_t
*r_ctx = NULL;
err = start_new_dirmngr (&ctx,
GPG_ERR_SOURCE_DEFAULT,
- opt.homedir,
opt.dirmngr_program,
opt.autostart, opt.verbose, DBG_IPC,
NULL /*gpg_status2*/, ctrl);
log_info (_("no dirmngr running in this session\n"));
}
}
- else if (!err)
+ else if (!err && !(err = warn_version_mismatch (ctx, DIRMNGR_NAME)))
{
char *line;
else if ((opt.keyserver_options.options & KEYSERVER_HONOR_KEYSERVER_URL))
{
/* Tell the dirmngr that this possibly privacy invading
- option is in use. If Dirmngr is running in TOR mode, it
+ option is in use. If Dirmngr is running in Tor mode, it
will return an error. */
err = assuan_transact (ctx, "OPTION honor-keyserver-url-used",
NULL, NULL, NULL, NULL, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_FORBIDDEN)
log_error (_("keyserver option \"honor-keyserver-url\""
- " may not be used in TOR mode\n"));
+ " may not be used in Tor mode\n"));
else if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
err = 0; /* Old dirmngr versions do not support this option. */
}
if (dml)
{
/* Found an inactive local session - return that. */
- assert (!dml->is_active);
+ log_assert (!dml->is_active);
/* But first do the per session init if not yet done. */
if (!dml->set_keyservers_done)
{
struct ks_status_parm_s *parm = opaque;
gpg_error_t err = 0;
- const char *s;
+ const char *s, *s2;
+ const char *warn;
if ((s = has_leading_keyword (line, parm->keyword? parm->keyword : "SOURCE")))
{
err = gpg_error_from_syserror ();
}
}
+ else if ((s = has_leading_keyword (line, "WARNING")))
+ {
+ if ((s2 = has_leading_keyword (s, "tor_not_running")))
+ warn = _("Tor is not running");
+ else if ((s2 = has_leading_keyword (s, "tor_config_problem")))
+ warn = _("Tor is not properly configured");
+ else
+ warn = NULL;
+
+ if (warn)
+ {
+ log_info (_("WARNING: %s\n"), warn);
+ if (s2)
+ {
+ while (*s2 && !spacep (s2))
+ s2++;
+ while (*s2 && spacep (s2))
+ s2++;
+ if (*s2)
+ print_further_info ("%s", s2);
+ }
+ }
+ }
return err;
}
memset (&stparm, 0, sizeof stparm);
stparm.keyword = "KEYSERVER";
- *r_keyserver = NULL;
+ if (r_keyserver)
+ *r_keyserver = NULL;
err = open_context (ctrl, &ctx);
if (err)
goto leave;
}
- *r_keyserver = stparm.source;
+ if (r_keyserver)
+ *r_keyserver = stparm.source;
+ else
+ xfree (stparm.source);
stparm.source = NULL;
leave:
don't need to escape the patterns before sending them to the
server.
+ If QUICK is set the dirmngr is advised to use a shorter timeout.
+
If R_SOURCE is not NULL the source of the data is stored as a
malloced string there. If a source is not known NULL is stored.
are able to ask for (1000-10-1)/(2+8+1) = 90 keys at once. */
gpg_error_t
gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern,
- keyserver_spec_t override_keyserver,
+ keyserver_spec_t override_keyserver, int quick,
estream_t *r_fp, char **r_source)
{
gpg_error_t err;
/* Lump all patterns into one string. */
init_membuf (&mb, 1024);
- put_membuf_str (&mb, "KS_GET --");
+ put_membuf_str (&mb, quick? "KS_GET --quick --" : "KS_GET --");
for (idx=0; pattern[idx]; idx++)
{
put_membuf (&mb, " ", 1); /* Append Delimiter. */
type_str = "sig";
break;
default:
- assert (! "Unhandled type.");
+ log_assert (! "Unhandled type.");
}
if (pub_key_length > 0)
\f
-/* Data callback for the DNS_CERT command. */
+/* Data callback for the DNS_CERT and WKD_GET commands. */
static gpg_error_t
dns_cert_data_cb (void *opaque, const void *data, size_t datalen)
{
{
if (parm->url)
err = gpg_error (GPG_ERR_DUP_KEY);
- else if (!(parm->fpr = xtrymalloc (nbytes)))
+ else if (!(parm->url = xtrystrdup (s)))
err = gpg_error_from_syserror ();
- else
- memcpy (parm->fpr, line, (parm->fprlen = nbytes));
}
return err;
close_context (ctrl, ctx);
return err;
}
+
+
+\f
+/* Ask the dirmngr to retrieve a key via the Web Key Directory
+ * protocol. If QUICK is set the dirmngr is advised to use a shorter
+ * timeout. On success a new estream with the key is stored at R_KEY.
+ */
+gpg_error_t
+gpg_dirmngr_wkd_get (ctrl_t ctrl, const char *name, int quick, estream_t *r_key)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ struct dns_cert_parm_s parm;
+ char *line = NULL;
+
+ memset (&parm, 0, sizeof parm);
+
+ err = open_context (ctrl, &ctx);
+ if (err)
+ return err;
+
+ line = es_bsprintf ("WKD_GET%s -- %s", quick?" --quick":"", name);
+ if (!line)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ if (strlen (line) + 2 >= ASSUAN_LINELENGTH)
+ {
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ goto leave;
+ }
+
+ parm.memfp = es_fopenmem (0, "rwb");
+ if (!parm.memfp)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ err = assuan_transact (ctx, line, dns_cert_data_cb, &parm,
+ NULL, NULL, NULL, &parm);
+ if (err)
+ goto leave;
+
+ if (r_key)
+ {
+ es_rewind (parm.memfp);
+ *r_key = parm.memfp;
+ parm.memfp = NULL;
+ }
+
+ leave:
+ xfree (parm.fpr);
+ xfree (parm.url);
+ es_fclose (parm.memfp);
+ xfree (line);
+ close_context (ctrl, ctx);
+ return err;
+}