* 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 <gcrypt.h>
#include <assuan.h>
-#include "i18n.h"
+#include "../common/i18n.h"
#include "keydb.h"
-#include "asshelp.h"
+#include "../common/asshelp.h"
struct membuf {
};
struct run_command_parm_s {
+ ctrl_t ctrl;
assuan_context_t ctx;
};
}
+/* 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 (ctrl_t ctrl, assuan_context_t ctx,
+ const char *servername, int mode)
+{
+ gpg_error_t err;
+ char *serverversion;
+ const char *myversion = strusage (13);
+
+ err = get_assuan_server_version (ctx, mode, &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);
+ if (!opt.quiet)
+ {
+ log_info (_("Note: Outdated servers may lack important"
+ " security fixes.\n"));
+ log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+ "gpgconf --kill all");
+ }
+ gpgsm_status2 (ctrl, STATUS_WARNING, "server_version_mismatch 0",
+ warn, NULL);
+ xfree (warn);
+ }
+ }
+ xfree (serverversion);
+ return err;
+}
+
+
/* This function prepares the dirmngr for a new session. The
audit-events option is used so that other dirmngr clients won't get
disturbed by such events. */
struct keyserver_spec *server;
if (!err)
+ err = warn_version_mismatch (ctrl, ctx, DIRMNGR_NAME, 0);
+
+ if (!err)
{
err = assuan_transact (ctx, "OPTION audit-events=1",
NULL, NULL, NULL, NULL, NULL, NULL);
char *pass = server->pass ? server->pass : "";
char *base = server->base ? server->base : "";
- snprintf (line, DIM (line) - 1, "LDAPSERVER %s:%i:%s:%s:%s",
+ snprintf (line, DIM (line), "LDAPSERVER %s:%i:%s:%s:%s",
server->host, server->port, user, pass, base);
- line[DIM (line) - 1] = 0;
- err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
- err = 0; /* Allow the use of old dirmngr versions. */
+ assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ /* The code below is not required because we don't return an error. */
+ /* err = [above call] */
+ /* if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD) */
+ /* err = 0; /\* Allow the use of old dirmngr versions. *\/ */
server = server->next;
}
gpg_error_t err;
assuan_context_t ctx;
- if (opt.disable_dirmngr)
+ if (opt.disable_dirmngr || ctrl->offline)
return gpg_error (GPG_ERR_NO_DIRMNGR);
if (*ctx_r)
to take care of the implicit option sending caching. */
err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
- opt.homedir, opt.dirmngr_program,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.dirmngr_program,
+ opt.autostart, opt.verbose, DBG_IPC,
gpgsm_status2, ctrl);
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
{
dirmngr_ctx_locked = 1;
err = start_dirmngr_ext (ctrl, &dirmngr_ctx);
- /* We do not check ERR but the existance of a context because the
+ /* We do not check ERR but the existence of a context because the
error might come from a failed command send to the dirmngr.
Fixme: Why don't we close the drimngr context if we encountered
an error in prepare_dirmngr? */
}
else
{
- log_error ("unsupported inquiry '%s'\n", line);
+ log_error ("unsupported certificate inquiry '%s'\n", line);
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
ksba_cert_t cert;
- err = gpgsm_find_cert (line, ski, &cert);
+ err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));
}
-/* Take a 20 byte hexencoded string and put it into the the provided
+/* Take a 20 byte hexencoded string and put it into the provided
20 byte buffer FPR in binary format. */
static int
unhexify_fpr (const char *hexstr, unsigned char *fpr)
;
if (*s || (n != 40))
return 0; /* no fingerprint (invalid or wrong length). */
- n /= 2;
for (s=hexstr, n=0; *s; s += 2, n++)
fpr[n] = xtoi_2 (s);
return 1; /* okay */
Values for USE_OCSP:
0 = Do CRL check.
- 1 = Do an OCSP check.
- 2 = Do an OCSP check using only the default responder.
+ 1 = Do an OCSP check but fallback to CRL unless CRLS are disabled.
+ 2 = Do only an OCSP check using only the default responder.
*/
int
gpgsm_dirmngr_isvalid (ctrl_t ctrl,
{
static int did_options;
int rc;
- char *certid;
+ char *certid, *certfpr;
char line[ASSUAN_LINELENGTH];
struct inq_certificate_parm_s parm;
struct isvalid_status_parm_s stparm;
if (rc)
return rc;
- if (use_ocsp)
- {
- certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
- }
- else
+ certfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+ certid = gpgsm_get_certid (cert);
+ if (!certid)
{
- certid = gpgsm_get_certid (cert);
- if (!certid)
- {
- log_error ("error getting the certificate ID\n");
- release_dirmngr (ctrl);
- return gpg_error (GPG_ERR_GENERAL);
- }
+ log_error ("error getting the certificate ID\n");
+ release_dirmngr (ctrl);
+ return gpg_error (GPG_ERR_GENERAL);
}
if (opt.verbose > 1)
stparm.seen = 0;
memset (stparm.fpr, 0, 20);
- /* FIXME: If --disable-crl-checks has been set, we should pass an
- option to dirmngr, so that no fallback CRL check is done after an
- ocsp check. It is not a problem right now as dirmngr does not
- fallback to CRL checking. */
-
/* It is sufficient to send the options only once because we have
- one connection per process only. */
+ * one connection per process only. */
if (!did_options)
{
if (opt.force_crl_refresh)
NULL, NULL, NULL, NULL, NULL, NULL);
did_options = 1;
}
- snprintf (line, DIM(line)-1, "ISVALID%s %s",
- use_ocsp == 2? " --only-ocsp --force-default-responder":"",
- certid);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "ISVALID%s%s %s%s%s",
+ use_ocsp == 2 || opt.no_crl_check ? " --only-ocsp":"",
+ use_ocsp == 2? " --force-default-responder":"",
+ certid,
+ use_ocsp? " ":"",
+ use_ocsp? certfpr:"");
xfree (certid);
+ xfree (certfpr);
rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
inq_certificate, &parm,
isvalid_status_cb, &stparm);
if (opt.verbose > 1)
log_info ("response of dirmngr: %s\n", rc? gpg_strerror (rc): "okay");
- rc = rc;
if (!rc && stparm.seen)
{
from the dirmngr. Try our own cert store now. */
KEYDB_HANDLE kh;
- kh = keydb_new (0);
+ kh = keydb_new ();
if (!kh)
rc = gpg_error (GPG_ERR_ENOMEM);
if (!rc)
- rc = keydb_search_fpr (kh, stparm.fpr);
+ rc = keydb_search_fpr (ctrl, kh, stparm.fpr);
if (!rc)
rc = keydb_get_cert (kh, &rspcert);
if (rc)
return out_of_core ();
}
- snprintf (line, DIM(line)-1, "LOOKUP%s %s",
+ snprintf (line, DIM(line), "LOOKUP%s %s",
cache_only? " --cache-only":"", pattern);
- line[DIM(line)-1] = 0;
xfree (pattern);
parm.ctrl = ctrl;
*r_cert = NULL;
bin2hex (fpr, 20, hexfpr);
- snprintf (line, DIM(line)-1, "LOOKUP --signle --cache-only 0x%s", hexfpr);
+ snprintf (line, DIM(line), "LOOKUP --single --cache-only 0x%s", hexfpr);
init_membuf (&mb, 4096);
err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
if (!*line)
return gpg_error (GPG_ERR_ASS_PARAMETER);
- err = gpgsm_find_cert (line, NULL, &cert);
+ err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, 1);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));
line = s;
log_info ("dirmngr: %s\n", line);
}
+ else if ((s = has_leading_keyword (line, "ISTRUSTED")))
+ {
+ /* The server is asking us whether the certificate is a trusted
+ root certificate. */
+ char fpr[41];
+ struct rootca_flags_s rootca_flags;
+ int n;
+
+ line = s;
+
+ for (s=line,n=0; hexdigitp (s); s++, n++)
+ ;
+ if (*s || n != 40)
+ return gpg_error (GPG_ERR_ASS_PARAMETER);
+ for (s=line, n=0; n < 40; s++, n++)
+ fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
+ fpr[n] = 0;
+
+ if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
+ rc = assuan_send_data (parm->ctx, "1", 1);
+ else
+ rc = 0;
+ return rc;
+ }
else
{
- log_error ("unsupported inquiry '%s'\n", line);
+ log_error ("unsupported command inquiry '%s'\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
if (rc)
return rc;
+ parm.ctrl = ctrl;
parm.ctx = dirmngr_ctx;
len = strlen (command) + 1;