1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

Merge branch 'STABLE-BRANCH-2-2' into master

--

Signed-off-by: Werner Koch <wk@gnupg.org>
Conflicts:
	NEWS - include release info from 2.2.1
	configure.ac - keep master.
This commit is contained in:
Werner Koch 2017-09-26 12:00:03 +02:00
commit cd2d758f3f
No known key found for this signature in database
GPG Key ID: CD21A80AC8C52565
15 changed files with 513 additions and 114 deletions

25
NEWS
View File

@ -1,10 +1,29 @@
Noteworthy changes in version 2.3.0 (unreleased)
------------------------------------------------
Changes also found in 2.2.1:
* Release dates of 2.2.x versions:
* gpg: Fix formatting of the user id in batch mode key generation
if only "name-email" is given.
* gpgv: Fix annoying "not suitable for" warnings.
* wks: Convey only the newest user id to the provider. This is the
case if different names are used with the same addr-spec.
* wks: Create a complying user id for provider policy mailbox-only.
* wks: Add workaround for posteo.de.
* scd: Fix the use of large ECC keys with an OpenPGP card.
* dirmngr: Use system provided root certificates if no specific HKP
certificates are configured. If build with GNUTLS, this was
already the case.
Release dates of 2.2.x versions:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Version 2.2.1 (unreleased)
Version 2.2.1 (2017-09-19)
Noteworthy changes in version 2.2.0 (2017-08-28)
@ -18,6 +37,8 @@ Noteworthy changes in version 2.2.0 (2017-08-28)
* Fixed a few minor bugs.
See-also: gnupg-announce/2017q3/000413.html
Noteworthy changes in version 2.1.23 (2017-08-09)
-------------------------------------------------

View File

@ -94,6 +94,10 @@ static int initialization_done;
/* Total number of non-permanent certificates. */
static unsigned int total_nonperm_certificates;
/* For each cert class the corresponding bit is set if at least one
* certificate of that class is loaded permanetly. */
static unsigned int any_cert_of_class;
#ifdef HAVE_W32_SYSTEM
/* We load some functions dynamically. Provide typedefs for tehse
@ -343,7 +347,9 @@ put_cert (ksba_cert_t cert, int permanent, unsigned int trustclass,
ci->permanent = !!permanent;
ci->trustclasses = trustclass;
if (!permanent)
if (permanent)
any_cert_of_class |= trustclass;
else
total_nonperm_certificates++;
return 0;
@ -758,6 +764,7 @@ cert_cache_deinit (int full)
}
total_nonperm_certificates = 0;
any_cert_of_class = 0;
initialization_done = 0;
release_cache_lock ();
}
@ -814,6 +821,15 @@ cert_cache_print_stats (void)
}
/* Return true if any cert of a class in MASK is permanently
* loaded. */
int
cert_cache_any_in_class (unsigned int mask)
{
return !!(any_cert_of_class & mask);
}
/* Put CERT into the certificate cache. */
gpg_error_t
cache_cert (ksba_cert_t cert)

View File

@ -39,6 +39,9 @@ void cert_cache_deinit (int full);
/* Print some statistics to the log file. */
void cert_cache_print_stats (void);
/* Return true if any cert of a class in MASK is permanently loaded. */
int cert_cache_any_in_class (unsigned int mask);
/* Compute the fingerprint of the certificate CERT and put it into
the 20 bytes large buffer DIGEST. Return address of this buffer. */
unsigned char *cert_compute_fpr (ksba_cert_t cert, unsigned char *digest);

View File

@ -91,6 +91,12 @@ gnupg_http_tls_verify_cb (void *opaque,
validate_flags |= VALIDATE_FLAG_TRUST_HKP;
if ((http_flags & HTTP_FLAG_TRUST_SYS))
validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM;
/* If HKP trust is requested and there are no HKP certificates
* configured, also try thye standard system certificates. */
if ((validate_flags & VALIDATE_FLAG_TRUST_HKP)
&& !cert_cache_any_in_class (CERTTRUST_CLASS_HKP))
validate_flags |= VALIDATE_FLAG_TRUST_SYSTEM;
}
if ((http_flags & HTTP_FLAG_NO_CRL))

View File

@ -78,7 +78,9 @@ the command is a properly formatted mail with all standard headers.
This mail can be fed to @command{sendmail(8)} or any other tool to
actually send that mail. If @command{sendmail(8)} is installed the
option @option{--send} can be used to directly send the created
request.
request. If the provider request a 'mailbox-only' user id and no such
user id is found, @command{gpg-wks-client} will try an additional user
id.
The @option{--receive} and @option{--read} commands are used to
process confirmation mails as send from the service provider. The

View File

@ -202,6 +202,7 @@ main( int argc, char **argv )
dotlock_disable ();
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
additional_weak_digest("MD5");
gnupg_initialize_compliance (GNUPG_MODULE_NAME_GPG);
pargs.argc = &argc;
pargs.argv = &argv;

View File

@ -3529,7 +3529,14 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
if( s2 )
p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
if( s3 )
{
/* If we have only the email part, do not add the space
* and the angle brackets. */
if (*r->u.value)
p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
else
p = stpcpy (p, s3);
}
append_to_parameter (para, r);
have_user_id=1;
}

View File

@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg-2.1.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2017-08-09 12:49+0200\n"
"PO-Revision-Date: 2017-09-26 11:51+0200\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German <de@li.org>\n"
"Language: de\n"
@ -194,7 +194,7 @@ msgid "failed to create stream from socket: %s\n"
msgstr "Das Erzeugen eines Datenstroms aus dem Socket schlug fehl: %s\n"
msgid "Please insert the card with serial number"
msgstr "Die legen Sie die Karte mit der folgenden Seriennummer ein:"
msgstr "Bitte legen Sie die Karte mit der folgenden Seriennummer ein"
msgid "Please remove the current card and insert the one with serial number"
msgstr ""

View File

@ -3,18 +3,19 @@
# Dokianakis Theofanis <madf@hellug.gr>, 2002.
# !-- psbl.surriel.com rejected (2011-01-11)
# Designated-Translator: none
#
# Dimitris Maroulidis <dmaroulidis@dimitrismaroulidis.com>, 2017.
msgid ""
msgstr ""
"Project-Id-Version: gnupg-1.1.92\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2003-06-27 12:00+0200\n"
"Last-Translator: Dokianakis Theofanis <madf@hellug.gr>\n"
"Language-Team: Greek <nls@tux.hellug.gr>\n"
"PO-Revision-Date: 2017-09-14 21:14+0300\n"
"Last-Translator: Dimitris Maroulidis <dmaroulidis@dimitrismaroulidis.com>\n"
"Language-Team: team@gnome.gr\n"
"Language: el\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#, fuzzy, c-format
msgid "failed to acquire the pinentry lock: %s\n"
@ -4423,7 +4424,7 @@ msgid "Keyring"
msgstr "Κλειδοθήκη"
msgid "Primary key fingerprint:"
msgstr "Αποτύπωμα πρωτεύων κλειδιού:"
msgstr "Αποτύπωμα πρωτεύοντος κλειδιού:"
msgid " Subkey fingerprint:"
msgstr " Αποτύπωμα υποκλειδιού:"
@ -4431,7 +4432,7 @@ msgstr " Αποτύπωμα υποκλειδιού:"
#. TRANSLATORS: this should fit into 24 bytes so that the
#. * fingerprint data is properly aligned with the user ID
msgid " Primary key fingerprint:"
msgstr " Αποτύπωμα πρωτεύων κλειδιού:"
msgstr " Αποτύπωμα πρωτ. κλειδιού:"
msgid " Subkey fingerprint:"
msgstr " Αποτύπωμα υποκλειδιού:"

View File

@ -119,7 +119,7 @@ const char *fake_submission_addr;
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
static gpg_error_t command_supported (char *userid);
static gpg_error_t command_check (char *userid);
static gpg_error_t command_send (const char *fingerprint, char *userid);
static gpg_error_t command_send (const char *fingerprint, const char *userid);
static gpg_error_t encrypt_response (estream_t *r_output, estream_t input,
const char *addrspec,
const char *fingerprint);
@ -348,13 +348,13 @@ get_key_status_cb (void *opaque, const char *keyword, char *args)
/* Get a key by fingerprint from gpg's keyring and make sure that the
* mail address ADDRSPEC is included in the key. The key is returned
* as a new memory stream at R_KEY.
*
* Fixme: After we have implemented import and export filters for gpg
* this function shall only return a key with just this user id. */
* mail address ADDRSPEC is included in the key. If EXACT is set the
* returned user id must match Addrspec exactly and not just in the
* addr-spec (mailbox) part. The key is returned as a new memory
* stream at R_KEY. */
static gpg_error_t
get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
int exact)
{
gpg_error_t err;
ccparray_t ccp;
@ -379,7 +379,7 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
es_fputs ("Content-Type: application/pgp-keys\n"
"\n", key);
filterexp = es_bsprintf ("keep-uid=mbox = %s", addrspec);
filterexp = es_bsprintf ("keep-uid=%s=%s", exact? "uid":"mbox", addrspec);
if (!filterexp)
{
err = gpg_error_from_syserror ();
@ -438,6 +438,49 @@ get_key (estream_t *r_key, const char *fingerprint, const char *addrspec)
}
/* Add the user id UID to the key identified by FINGERPRINT. */
static gpg_error_t
add_user_id (const char *fingerprint, const char *uid)
{
gpg_error_t err;
ccparray_t ccp;
const char **argv = NULL;
ccparray_init (&ccp, 0);
ccparray_put (&ccp, "--no-options");
if (!opt.verbose)
ccparray_put (&ccp, "--quiet");
else if (opt.verbose > 1)
ccparray_put (&ccp, "--verbose");
ccparray_put (&ccp, "--batch");
ccparray_put (&ccp, "--always-trust");
ccparray_put (&ccp, "--quick-add-uid");
ccparray_put (&ccp, fingerprint);
ccparray_put (&ccp, uid);
ccparray_put (&ccp, NULL);
argv = ccparray_get (&ccp, NULL);
if (!argv)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
NULL, NULL,
NULL, NULL);
if (err)
{
log_error ("adding user id failed: %s\n", gpg_strerror (err));
goto leave;
}
leave:
xfree (argv);
return err;
}
struct decrypt_stream_parm_s
{
@ -600,8 +643,8 @@ command_check (char *userid)
char *addrspec = NULL;
estream_t key = NULL;
char *fpr = NULL;
strlist_t mboxes = NULL;
strlist_t sl;
uidinfo_list_t mboxes = NULL;
uidinfo_list_t sl;
int found = 0;
addrspec = mailbox_from_userid (userid);
@ -647,10 +690,9 @@ command_check (char *userid)
/* Look closer at the key. */
err = wks_list_key (key, &fpr, &mboxes);
if (err || !fpr)
if (err)
{
log_error ("error parsing key: %s\n",
err? gpg_strerror (err) : "no fingerprint found");
log_error ("error parsing key: %s\n", gpg_strerror (err));
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
@ -660,10 +702,15 @@ command_check (char *userid)
for (sl = mboxes; sl; sl = sl->next)
{
if (!strcmp (sl->d, addrspec))
if (sl->mbox && !strcmp (sl->mbox, addrspec))
found = 1;
if (opt.verbose)
log_info (" addr-spec: %s\n", sl->d);
{
log_info (" user-id: %s\n", sl->uid);
log_info (" created: %s\n", asctimestamp (sl->created));
if (sl->mbox)
log_info (" addr-spec: %s\n", sl->mbox);
}
}
if (!found)
{
@ -674,7 +721,7 @@ command_check (char *userid)
leave:
xfree (fpr);
free_strlist (mboxes);
free_uidinfo_list (mboxes);
es_fclose (key);
xfree (addrspec);
return err;
@ -685,7 +732,7 @@ command_check (char *userid)
/* Locate the key by fingerprint and userid and send a publication
* request. */
static gpg_error_t
command_send (const char *fingerprint, char *userid)
command_send (const char *fingerprint, const char *userid)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
@ -695,6 +742,12 @@ command_send (const char *fingerprint, char *userid)
char *submission_to = NULL;
mime_maker_t mime = NULL;
struct policy_flags_s policy;
int no_encrypt = 0;
int posteo_hack = 0;
const char *domain;
uidinfo_list_t uidlist = NULL;
uidinfo_list_t uid, thisuid;
time_t thistime;
memset (&policy, 0, sizeof policy);
@ -706,6 +759,7 @@ command_send (const char *fingerprint, char *userid)
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
addrspec = mailbox_from_userid (userid);
if (!addrspec)
{
@ -713,10 +767,14 @@ command_send (const char *fingerprint, char *userid)
err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave;
}
err = get_key (&key, fingerprint, addrspec);
err = get_key (&key, fingerprint, addrspec, 0);
if (err)
goto leave;
domain = strchr (addrspec, '@');
log_assert (domain);
domain++;
/* Get the submission address. */
if (fake_submission_addr)
{
@ -727,11 +785,8 @@ command_send (const char *fingerprint, char *userid)
err = wkd_get_submission_address (addrspec, &submission_to);
if (err)
{
char *domain = strchr (addrspec, '@');
if (domain)
domain = domain + 1;
log_error (_("looking up WKS submission address for %s: %s\n"),
domain ? domain : addrspec, gpg_strerror (err));
log_error (_("error looking up submission address for domain '%s': %s\n"),
domain, gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_NO_DATA)
log_error (_("this domain probably doesn't support WKS.\n"));
goto leave;
@ -762,14 +817,92 @@ command_send (const char *fingerprint, char *userid)
if (policy.auth_submit)
log_info ("no confirmation required for '%s'\n", addrspec);
/* In case the key has several uids with the same addr-spec we will
* use the newest one. */
err = wks_list_key (key, NULL, &uidlist);
if (err)
{
log_error ("error parsing key: %s\n",gpg_strerror (err));
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
thistime = 0;
thisuid = NULL;
for (uid = uidlist; uid; uid = uid->next)
{
if (!uid->mbox)
continue; /* Should not happen anyway. */
if (policy.mailbox_only
&& ascii_strcasecmp (uid->uid, uid->mbox))
continue; /* UID has more than just the mailbox. */
if (uid->created > thistime)
{
thistime = uid->created;
thisuid = uid;
}
}
if (!thisuid)
thisuid = uidlist; /* This is the case for a missing timestamp. */
if (opt.verbose)
log_info ("submitting key with user id '%s'\n", thisuid->uid);
/* If we have more than one user id we need to filter the key to
* include only THISUID. */
if (uidlist->next)
{
estream_t newkey;
es_rewind (key);
err = wks_filter_uid (&newkey, key, thisuid->uid);
if (err)
{
log_error ("error filtering key: %s\n", gpg_strerror (err));
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
es_fclose (key);
key = newkey;
}
if (policy.mailbox_only
&& (!thisuid->mbox || ascii_strcasecmp (thisuid->uid, thisuid->mbox)))
{
log_info ("Warning: policy requires 'mailbox-only'"
" - adding user id '%s'\n", addrspec);
err = add_user_id (fingerprint, addrspec);
if (err)
goto leave;
/* Need to get the key again. This time we request filtering
* for the full user id, so that we do not need check and filter
* the key again. */
es_fclose (key);
key = NULL;
err = get_key (&key, fingerprint, addrspec, 1);
if (err)
goto leave;
}
/* Hack to support posteo but let them disable this by setting the
* new policy-version flag. */
if (policy.protocol_version < 3
&& !ascii_strcasecmp (domain, "posteo.de"))
{
log_info ("Warning: Using draft-1 method for domain '%s'\n", domain);
no_encrypt = 1;
posteo_hack = 1;
}
/* Encrypt the key part. */
if (!no_encrypt)
{
es_rewind (key);
err = encrypt_response (&keyenc, key, submission_to, fingerprint);
if (err)
goto leave;
es_fclose (key);
key = NULL;
}
/* Send the key. */
err = mime_maker_new (&mime, NULL);
@ -791,6 +924,50 @@ command_send (const char *fingerprint, char *userid)
if (err)
goto leave;
if (no_encrypt)
{
void *data;
size_t datalen, n;
if (posteo_hack)
{
/* Needs a multipart/mixed with one(!) attachment. It does
* not grok a non-multipart mail. */
err = mime_maker_add_header (mime, "Content-Type", "multipart/mixed");
if (err)
goto leave;
err = mime_maker_add_container (mime);
if (err)
goto leave;
}
err = mime_maker_add_header (mime, "Content-type",
"application/pgp-keys");
if (err)
goto leave;
if (es_fclose_snatch (key, &data, &datalen))
{
err = gpg_error_from_syserror ();
goto leave;
}
key = NULL;
/* We need to skip over the first line which has a content-type
* header not needed here. */
for (n=0; n < datalen ; n++)
if (((const char *)data)[n] == '\n')
{
n++;
break;
}
err = mime_maker_add_body_data (mime, (char*)data + n, datalen - n);
xfree (data);
if (err)
goto leave;
}
else
{
err = mime_maker_add_header (mime, "Content-Type",
"multipart/encrypted; "
"protocol=\"application/pgp-encrypted\"");
@ -815,12 +992,14 @@ command_send (const char *fingerprint, char *userid)
err = mime_maker_add_stream (mime, &keyenc);
if (err)
goto leave;
}
err = wks_send_mime (mime);
leave:
mime_maker_release (mime);
xfree (submission_to);
free_uidinfo_list (uidlist);
es_fclose (keyenc);
es_fclose (key);
xfree (addrspec);

View File

@ -127,7 +127,7 @@ static struct debug_flags_s debug_flags [] =
struct server_ctx_s
{
char *fpr;
strlist_t mboxes; /* List of addr-specs taken from the UIDs. */
uidinfo_list_t mboxes; /* List with addr-specs taken from the UIDs. */
unsigned int draft_version_2:1; /* Client supports the draft 2. */
};
typedef struct server_ctx_s *server_ctx_t;
@ -1092,7 +1092,7 @@ static gpg_error_t
process_new_key (server_ctx_t ctx, estream_t key)
{
gpg_error_t err;
strlist_t sl;
uidinfo_list_t sl;
const char *s;
char *dname = NULL;
char *nonce = NULL;
@ -1101,27 +1101,25 @@ process_new_key (server_ctx_t ctx, estream_t key)
/* First figure out the user id from the key. */
xfree (ctx->fpr);
free_strlist (ctx->mboxes);
free_uidinfo_list (ctx->mboxes);
err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
if (err)
goto leave;
if (!ctx->fpr)
{
log_error ("error parsing key (no fingerprint)\n");
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
log_assert (ctx->fpr);
log_info ("fingerprint: %s\n", ctx->fpr);
for (sl = ctx->mboxes; sl; sl = sl->next)
{
log_info (" addr-spec: %s\n", sl->d);
if (sl->mbox)
log_info (" addr-spec: %s\n", sl->mbox);
}
/* Walk over all user ids and send confirmation requests for those
* we support. */
for (sl = ctx->mboxes; sl; sl = sl->next)
{
s = strchr (sl->d, '@');
if (!sl->mbox)
continue;
s = strchr (sl->mbox, '@');
log_assert (s && s[1]);
xfree (dname);
dname = make_filename_try (opt.directory, s+1, NULL);
@ -1133,26 +1131,26 @@ process_new_key (server_ctx_t ctx, estream_t key)
if (access (dname, W_OK))
{
log_info ("skipping address '%s': Domain not configured\n", sl->d);
log_info ("skipping address '%s': Domain not configured\n", sl->mbox);
continue;
}
if (get_policy_flags (&policybuf, sl->d))
if (get_policy_flags (&policybuf, sl->mbox))
{
log_info ("skipping address '%s': Bad policy flags\n", sl->d);
log_info ("skipping address '%s': Bad policy flags\n", sl->mbox);
continue;
}
if (policybuf.auth_submit)
{
/* Bypass the confirmation stuff and publish the key as is. */
log_info ("publishing address '%s'\n", sl->d);
log_info ("publishing address '%s'\n", sl->mbox);
/* FIXME: We need to make sure that we do this only for the
* address in the mail. */
log_debug ("auth-submit not yet working!\n");
}
else
{
log_info ("storing address '%s'\n", sl->d);
log_info ("storing address '%s'\n", sl->mbox);
xfree (nonce);
xfree (fname);
@ -1160,7 +1158,7 @@ process_new_key (server_ctx_t ctx, estream_t key)
if (err)
goto leave;
err = send_confirmation_request (ctx, sl->d, nonce, fname);
err = send_confirmation_request (ctx, sl->mbox, nonce, fname);
if (err)
goto leave;
}
@ -1313,7 +1311,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
char *hash = NULL;
const char *domain;
const char *s;
strlist_t sl;
uidinfo_list_t sl;
char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
/* FIXME: There is a bug in name-value.c which adds white space for
@ -1351,25 +1349,21 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
/* We need to get the fingerprint from the key. */
xfree (ctx->fpr);
free_strlist (ctx->mboxes);
free_uidinfo_list (ctx->mboxes);
err = wks_list_key (key, &ctx->fpr, &ctx->mboxes);
if (err)
goto leave;
if (!ctx->fpr)
{
log_error ("error parsing key (no fingerprint)\n");
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
log_assert (ctx->fpr);
log_info ("fingerprint: %s\n", ctx->fpr);
for (sl = ctx->mboxes; sl; sl = sl->next)
log_info (" addr-spec: %s\n", sl->d);
if (sl->mbox)
log_info (" addr-spec: %s\n", sl->mbox);
/* Check that the key has 'address' as a user id. We use
* case-insensitive matching because the client is expected to
* return the address verbatim. */
for (sl = ctx->mboxes; sl; sl = sl->next)
if (!strcmp (sl->d, address))
if (sl->mbox && !strcmp (sl->mbox, address))
break;
if (!sl)
{
@ -1565,7 +1559,7 @@ command_receive_cb (void *opaque, const char *mediatype,
}
xfree (ctx.fpr);
free_strlist (ctx.mboxes);
free_uidinfo_list (ctx.mboxes);
return err;
}

View File

@ -63,16 +63,32 @@ struct policy_flags_s
unsigned int mailbox_only : 1;
unsigned int dane_only : 1;
unsigned int auth_submit : 1;
unsigned int protocol_version; /* The supported WKS_DRAFT_VERION or 0 */
unsigned int max_pending; /* Seconds to wait for a confirmation. */
};
typedef struct policy_flags_s *policy_flags_t;
/* An object to convey user ids of a key. */
struct uidinfo_list_s
{
struct uidinfo_list_s *next;
time_t created; /* Time the userid was created. */
char *mbox; /* NULL or the malloced mailbox from UID. */
char uid[1];
};
typedef struct uidinfo_list_s *uidinfo_list_t;
/*-- wks-util.c --*/
void wks_set_status_fd (int fd);
void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3);
gpg_error_t wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes);
void free_uidinfo_list (uidinfo_list_t list);
gpg_error_t wks_list_key (estream_t key, char **r_fpr,
uidinfo_list_t *r_mboxes);
gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key,
const char *uid);
gpg_error_t wks_send_mime (mime_maker_t mime);
gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
int ignore_unknown);

View File

@ -478,7 +478,8 @@ add_body (mime_maker_t ctx, const void *data, size_t datalen)
/* Add STRING as body to the mail or the current MIME container. A
* second call to this function is not allowed.
* second call to this function or mime_make_add_body_data is not
* allowed.
*
* FIXME: We may want to have an append_body to add more data to a body.
*/
@ -489,6 +490,16 @@ mime_maker_add_body (mime_maker_t ctx, const char *string)
}
/* Add (DATA,DATALEN) as body to the mail or the current MIME
* container. Note that a second call to this function or to
* mime_make_add_body is not allowed. */
gpg_error_t
mime_maker_add_body_data (mime_maker_t ctx, const void *data, size_t datalen)
{
return add_body (ctx, data, datalen);
}
/* This is the same as mime_maker_add_body but takes a stream as
* argument. As of now the stream is copied to the MIME object but
* eventually we may delay that and read the stream only at the time

View File

@ -34,6 +34,8 @@ void mime_maker_dump_tree (mime_maker_t ctx);
gpg_error_t mime_maker_add_header (mime_maker_t ctx,
const char *name, const char *value);
gpg_error_t mime_maker_add_body (mime_maker_t ctx, const char *string);
gpg_error_t mime_maker_add_body_data (mime_maker_t ctx,
const void *data, size_t datalen);
gpg_error_t mime_maker_add_stream (mime_maker_t ctx, estream_t *stream_addr);
gpg_error_t mime_maker_add_container (mime_maker_t ctx);
gpg_error_t mime_maker_end_container (mime_maker_t ctx);

View File

@ -90,9 +90,52 @@ wks_write_status (int no, const char *format, ...)
/* Helper for wks_list_key. */
/* Append UID to LIST and return the new item. On success LIST is
* updated. On error ERRNO is set and NULL returned. */
static uidinfo_list_t
append_to_uidinfo_list (uidinfo_list_t *list, const char *uid, time_t created)
{
uidinfo_list_t r, sl;
sl = xtrymalloc (sizeof *sl + strlen (uid));
if (!sl)
return NULL;
strcpy (sl->uid, uid);
sl->created = created;
sl->mbox = mailbox_from_userid (uid);
sl->next = NULL;
if (!*list)
*list = sl;
else
{
for (r = *list; r->next; r = r->next )
;
r->next = sl;
}
return sl;
}
/* Free the list of uid infos at LIST. */
void
free_uidinfo_list (uidinfo_list_t list)
{
while (list)
{
uidinfo_list_t tmp = list->next;
xfree (list->mbox);
xfree (list);
list = tmp;
}
}
/* Helper for wks_list_key and wks_filter_uid. */
static void
list_key_status_cb (void *opaque, const char *keyword, char *args)
key_status_cb (void *opaque, const char *keyword, char *args)
{
(void)opaque;
@ -103,9 +146,10 @@ list_key_status_cb (void *opaque, const char *keyword, char *args)
/* Run gpg on KEY and store the primary fingerprint at R_FPR and the
* list of mailboxes at R_MBOXES. Returns 0 on success; on error NULL
* is stored at R_FPR and R_MBOXES and an error code is returned. */
* is stored at R_FPR and R_MBOXES and an error code is returned.
* R_FPR may be NULL if the fingerprint is not needed. */
gpg_error_t
wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes)
{
gpg_error_t err;
ccparray_t ccp;
@ -118,10 +162,10 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
char **fields = NULL;
int nfields;
int lnr;
char *mbox = NULL;
char *fpr = NULL;
strlist_t mboxes = NULL;
uidinfo_list_t mboxes = NULL;
if (r_fpr)
*r_fpr = NULL;
*r_mboxes = NULL;
@ -158,7 +202,7 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
}
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, listing,
list_key_status_cb, NULL);
key_status_cb, NULL);
if (err)
{
log_error ("import failed: %s\n", gpg_strerror (err));
@ -232,9 +276,8 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
else if (!strcmp (fields[0], "uid") && nfields > 9)
{
/* Fixme: Unescape fields[9] */
xfree (mbox);
mbox = mailbox_from_userid (fields[9]);
if (mbox && !append_to_strlist_try (&mboxes, mbox))
if (!append_to_uidinfo_list (&mboxes, fields[9],
parse_timestamp (fields[5], NULL)))
{
err = gpg_error_from_syserror ();
goto leave;
@ -248,15 +291,23 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
goto leave;
}
if (!fpr)
{
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
if (r_fpr)
{
*r_fpr = fpr;
fpr = NULL;
}
*r_mboxes = mboxes;
mboxes = NULL;
leave:
xfree (fpr);
xfree (mboxes);
xfree (mbox);
free_uidinfo_list (mboxes);
xfree (fields);
es_free (line);
xfree (argv);
@ -265,6 +316,85 @@ wks_list_key (estream_t key, char **r_fpr, strlist_t *r_mboxes)
}
/* Run gpg as a filter on KEY and write the output to a new stream
* stored at R_NEWKEY. The new key will containn only the user id
* UID. Returns 0 on success. Only one key is expected in KEY. */
gpg_error_t
wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid)
{
gpg_error_t err;
ccparray_t ccp;
const char **argv = NULL;
estream_t newkey;
char *filterexp = NULL;
*r_newkey = NULL;
/* Open a memory stream. */
newkey = es_fopenmem (0, "w+b");
if (!newkey)
{
err = gpg_error_from_syserror ();
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
return err;
}
/* Prefix the key with the MIME content type. */
es_fputs ("Content-Type: application/pgp-keys\n"
"\n", newkey);
filterexp = es_bsprintf ("keep-uid=uid=%s", uid);
if (!filterexp)
{
err = gpg_error_from_syserror ();
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
goto leave;
}
ccparray_init (&ccp, 0);
ccparray_put (&ccp, "--no-options");
if (!opt.verbose)
ccparray_put (&ccp, "--quiet");
else if (opt.verbose > 1)
ccparray_put (&ccp, "--verbose");
ccparray_put (&ccp, "--batch");
ccparray_put (&ccp, "--status-fd=2");
ccparray_put (&ccp, "--always-trust");
ccparray_put (&ccp, "--armor");
ccparray_put (&ccp, "--import-options=import-export");
ccparray_put (&ccp, "--import-filter");
ccparray_put (&ccp, filterexp);
ccparray_put (&ccp, "--import");
ccparray_put (&ccp, NULL);
argv = ccparray_get (&ccp, NULL);
if (!argv)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, newkey,
key_status_cb, NULL);
if (err)
{
log_error ("import/export failed: %s\n", gpg_strerror (err));
goto leave;
}
es_rewind (newkey);
*r_newkey = newkey;
newkey = NULL;
leave:
xfree (filterexp);
xfree (argv);
es_fclose (newkey);
return err;
}
/* Helper to write mail to the output(s). */
gpg_error_t
wks_send_mime (mime_maker_t mime)
@ -316,7 +446,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
TOK_MAILBOX_ONLY,
TOK_DANE_ONLY,
TOK_AUTH_SUBMIT,
TOK_MAX_PENDING
TOK_MAX_PENDING,
TOK_PROTOCOL_VERSION
};
static struct {
const char *name;
@ -325,7 +456,8 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
{ "mailbox-only", TOK_MAILBOX_ONLY },
{ "dane-only", TOK_DANE_ONLY },
{ "auth-submit", TOK_AUTH_SUBMIT },
{ "max-pending", TOK_MAX_PENDING }
{ "max-pending", TOK_MAX_PENDING },
{ "protocol-version", TOK_PROTOCOL_VERSION }
};
gpg_error_t err = 0;
int lnr = 0;
@ -400,6 +532,14 @@ wks_parse_policy (policy_flags_t flags, estream_t stream, int ignore_unknown)
* and decide whether to allow other units. */
flags->max_pending = atoi (value);
break;
case TOK_PROTOCOL_VERSION:
if (!value)
{
err = gpg_error (GPG_ERR_SYNTAX);
goto leave;
}
flags->protocol_version = atoi (value);
break;
}
}