X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=g10%2Fcall-dirmngr.c;h=e452c971e251dbc8a64b6af5b9ca7c2da3952245;hb=ac9c4f87d9e015cdbaa757ba267c36d79d23db58;hp=ef4ca765113b8cff4937a51ea6957b4e0a5f0435;hpb=ed6a57244711b05833b351b7f7c88015e7ef16a7;p=platform%2Fupstream%2Fgpg2.git diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c index ef4ca76..e452c97 100644 --- a/g10/call-dirmngr.c +++ b/g10/call-dirmngr.c @@ -78,6 +78,16 @@ struct ks_put_parm_s }; +/* Parameter structure used with the DNS_CERT command. */ +struct dns_cert_parm_s +{ + estream_t memfp; + unsigned char *fpr; + size_t fprlen; + char *url; +}; + + /* Data used to associate an session with dirmngr contexts. We can't use a simple one to one mapping because we sometimes need two connections to the dirmngr; for example while doing a listing and @@ -94,6 +104,9 @@ struct dirmngr_local_s /* The active Assuan context. */ assuan_context_t ctx; + /* Flag set when the keyserver names have been send. */ + int set_keyservers_done; + /* Flag set to true while an operation is running on CTX. */ int is_active; }; @@ -145,29 +158,21 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx) } else if (!err) { - keyserver_spec_t ksi; + char *line; /* Tell the dirmngr that we want to collect audit event. */ /* err = assuan_transact (agent_ctx, "OPTION audit-events=1", */ /* NULL, NULL, NULL, NULL, NULL, NULL); */ - - /* Set all configured keyservers. We clear existing keyservers - so that any keyserver configured in GPG overrides keyservers - possibly still configured in Dirmngr for the session (Note - that the keyserver list of a session in Dirmngr survives a - RESET. */ - for (ksi = opt.keyserver; !err && ksi; ksi = ksi->next) + if (opt.keyserver_options.http_proxy) { - char *line; - - line = xtryasprintf ("KEYSERVER%s %s", - ksi == opt.keyserver? " --clear":"", ksi->uri); + line = xtryasprintf ("OPTION http-proxy=%s", + opt.keyserver_options.http_proxy); if (!line) err = gpg_error_from_syserror (); else { - err = assuan_transact (ctx, line, - NULL, NULL, NULL, NULL, NULL, NULL); + err = assuan_transact (ctx, line, NULL, NULL, NULL, + NULL, NULL, NULL); xfree (line); } } @@ -205,7 +210,42 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx) { /* Found an inactive local session - return that. */ assert (!dml->is_active); + + /* But first do the per session init if not yet done. */ + if (!dml->set_keyservers_done) + { + keyserver_spec_t ksi; + + /* Set all configured keyservers. We clear existing + keyservers so that any keyserver configured in GPG + overrides keyservers possibly still configured in Dirmngr + for the session (Note that the keyserver list of a + session in Dirmngr survives a RESET. */ + for (ksi = opt.keyserver; ksi; ksi = ksi->next) + { + char *line; + + line = xtryasprintf + ("KEYSERVER%s %s", + ksi == opt.keyserver? " --clear":"", ksi->uri); + if (!line) + err = gpg_error_from_syserror (); + else + { + err = assuan_transact (dml->ctx, line, NULL, NULL, NULL, + NULL, NULL, NULL); + xfree (line); + } + + if (err) + return err; + } + + dml->set_keyservers_done = 1; + } + dml->is_active = 1; + *r_ctx = dml->ctx; return 0; } @@ -219,6 +259,7 @@ open_context (ctrl_t ctrl, assuan_context_t *r_ctx) xfree (dml); return err; } + /* To be on the nPth thread safe site we need to add it to a list; this is far easier than to have a lock for this function. It should not happen anyway but the code is free @@ -253,6 +294,29 @@ close_context (ctrl_t ctrl, assuan_context_t ctx) } +/* Clear the set_keyservers_done flag on context CTX. */ +static void +clear_context_flags (ctrl_t ctrl, assuan_context_t ctx) +{ + dirmngr_local_t dml; + + if (!ctx) + return; + + for (dml = ctrl->dirmngr_local; dml; dml = dml->next) + { + if (dml->ctx == ctx) + { + if (!dml->is_active) + log_fatal ("clear_context_flags on inactive dirmngr ctx %p\n", ctx); + dml->set_keyservers_done = 0; + return; + } + } + log_fatal ("clear_context_flags on unknown dirmngr ctx %p\n", ctx); +} + + /* Status callback for ks_get and ks_search. */ static gpg_error_t @@ -453,6 +517,7 @@ ks_get_data_cb (void *opaque, const void *data, size_t datalen) 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, estream_t *r_fp, char **r_source) { gpg_error_t err; @@ -475,6 +540,27 @@ gpg_dirmngr_ks_get (ctrl_t ctrl, char **pattern, if (err) return err; + /* If we have an override keyserver we first indicate that the next + user of the context needs to again setup the global keyservers and + them we send the override keyserver. */ + if (override_keyserver) + { + clear_context_flags (ctrl, ctx); + line = xtryasprintf ("KEYSERVER --clear %s", override_keyserver->uri); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + err = assuan_transact (ctx, line, NULL, NULL, NULL, + NULL, NULL, NULL); + if (err) + goto leave; + + xfree (line); + line = NULL; + } + /* Lump all patterns into one string. */ init_membuf (&mb, 1024); put_membuf_str (&mb, "KS_GET --"); @@ -881,3 +967,228 @@ gpg_dirmngr_ks_put (ctrl_t ctrl, void *data, size_t datalen, kbnode_t keyblock) close_context (ctrl, ctx); return err; } + + + +/* Data callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_data_cb (void *opaque, const void *data, size_t datalen) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + size_t nwritten; + + if (!data) + return 0; /* Ignore END commands. */ + if (!parm->memfp) + return 0; /* Data is not required. */ + + if (es_write (parm->memfp, data, datalen, &nwritten)) + err = gpg_error_from_syserror (); + + return err; +} + + +/* Status callback for the DNS_CERT command. */ +static gpg_error_t +dns_cert_status_cb (void *opaque, const char *line) +{ + struct dns_cert_parm_s *parm = opaque; + gpg_error_t err = 0; + const char *s; + size_t nbytes; + + if ((s = has_leading_keyword (line, "FPR"))) + { + char *buf; + + if (!(buf = xtrystrdup (s))) + err = gpg_error_from_syserror (); + else if (parm->fpr) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!hex2str (buf, buf, strlen (buf)+1, &nbytes)) + err = gpg_error_from_syserror (); + else if (nbytes < 20) + err = gpg_error (GPG_ERR_TOO_SHORT); + else + { + parm->fpr = xtrymalloc (nbytes); + if (!parm->fpr) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, buf, (parm->fprlen = nbytes)); + } + xfree (buf); + } + else if ((s = has_leading_keyword (line, "URL")) && *s) + { + if (parm->url) + err = gpg_error (GPG_ERR_DUP_KEY); + else if (!(parm->fpr = xtrymalloc (nbytes))) + err = gpg_error_from_syserror (); + else + memcpy (parm->fpr, line, (parm->fprlen = nbytes)); + } + + return err; +} + +/* Ask the dirmngr for a DNS CERT record. Depending on the found + subtypes different return values are set: + + - For a PGP subtype a new estream with that key will be returned at + R_KEY and the other return parameters are set to NULL/0. + + - For an IPGP subtype the fingerprint is stored as a malloced block + at (R_FPR,R_FPRLEN). If an URL is available it is stored as a + malloced string at R_URL; NULL is stored if there is no URL. + + If CERTTYPE is DNS_CERTTYPE_ANY this function returns the first + CERT record found with a supported type; it is expected that only + one CERT record is used. If CERTTYPE is one of the supported + certtypes, only records with this certtype are considered and the + first one found is returned. All R_* args are optional. */ +gpg_error_t +gpg_dirmngr_dns_cert (ctrl_t ctrl, const char *name, const char *certtype, + estream_t *r_key, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_key) + *r_key = NULL; + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT %s %s", certtype, 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, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_key) + { + es_rewind (parm.memfp); + *r_key = parm.memfp; + parm.memfp = NULL; + } + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + es_fclose (parm.memfp); + xfree (line); + close_context (ctrl, ctx); + return err; +} + + +/* Ask the dirmngr for PKA info. On success the retrieved fingerprint + is returned in a malloced buffer at R_FPR and its length is stored + at R_FPRLEN. If an URL is available it is stored as a malloced + string at R_URL. On error all return values are set to NULL/0. */ +gpg_error_t +gpg_dirmngr_get_pka (ctrl_t ctrl, const char *userid, + unsigned char **r_fpr, size_t *r_fprlen, + char **r_url) +{ + gpg_error_t err; + assuan_context_t ctx; + struct dns_cert_parm_s parm; + char *line = NULL; + + memset (&parm, 0, sizeof parm); + if (r_fpr) + *r_fpr = NULL; + if (r_fprlen) + *r_fprlen = 0; + if (r_url) + *r_url = NULL; + + err = open_context (ctrl, &ctx); + if (err) + return err; + + line = es_bsprintf ("DNS_CERT --pka -- %s", userid); + if (!line) + { + err = gpg_error_from_syserror (); + goto leave; + } + if (strlen (line) + 2 >= ASSUAN_LINELENGTH) + { + err = gpg_error (GPG_ERR_TOO_LARGE); + goto leave; + } + + err = assuan_transact (ctx, line, dns_cert_data_cb, &parm, + NULL, NULL, dns_cert_status_cb, &parm); + if (err) + goto leave; + + if (r_fpr && parm.fpr) + { + *r_fpr = parm.fpr; + parm.fpr = NULL; + } + if (r_fprlen) + *r_fprlen = parm.fprlen; + + if (r_url && parm.url) + { + *r_url = parm.url; + parm.url = NULL; + } + + leave: + xfree (parm.fpr); + xfree (parm.url); + xfree (line); + close_context (ctrl, ctx); + return err; +}