wkd: Implement --blacklist option for gpg-wks-client

* tools/gpg-wks-client.c (blacklist_array, blacklist_array_len): New.
(parse_arguments): Install blacklist.
(read_file): New.
(cmp_blacklist, add_blacklist, is_in_blacklist): New.
(mirror_one_key): Check list.
* tools/gpg-wks.h (opt): Remove field blacklist.
--

GnuPG-bug-id: 6224
This commit is contained in:
Werner Koch 2022-10-07 17:35:44 +02:00
parent 0a151548b6
commit b0b4e24c4f
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 193 additions and 4 deletions

View File

@ -53,6 +53,26 @@ Directory.
.B gpg-wks-client
.RI [ options ]
.B \-\-read
.br
.B gpg-wks-client
.RI [ options ]
.B \-\-mirror
.br
.B gpg-wks-client
.RI [ options ]
.B \-\-install-key
.br
.B gpg-wks-client
.RI [ options ]
.B \-\-remove-key
.br
.B gpg-wks-client
.RI [ options ]
.B \-\-print-wkd-hash
.br
.B gpg-wks-client
.RI [ options ]
.B \-\-print-wkd-url
@end ifset
@mansect description
@ -101,6 +121,13 @@ fingerprint and the mailbox separated by a space. The command
@option{--remove-key} removes a key from that directory, its only
argument is a user-id.
The command @option{--mirror} is similar to @option{--install-key} but
takes the keys from the the LDAP server configured for Dirmngr. If no
arguments are given all keys and user ids are installed. If arguments
are given they are taken as domain names to limit the to be installed
keys. The option @option{--blacklist} may be used to further limit
the to be installed keys.
The command @option{--print-wkd-hash} prints the WKD user-id identifiers
and the corresponding mailboxes from the user-ids given on the command
line or via stdin (one user-id per line).
@ -175,8 +202,16 @@ easily get the return code of the process.
@itemx --directory @var{dir}
@opindex directory
Use @var{dir} as top level directory for the commands
@option{--install-key} and @option{--remove-key}. The default is
@file{openpgpkey}.
@option{--mirror}, @option{--install-key} and @option{--remove-key}.
The default is @file{openpgpkey}.
@item --blacklist @var{file}
@opindex blacklist
This option is used to exclude certain mail addresses from a mirror
operation. The format of @var{file} is one mail address (just the
addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines
starting with a '#' are ignored.
@item --verbose
@opindex verbose

View File

@ -144,8 +144,14 @@ static struct debug_flags_s debug_flags [] =
/* Value of the option --fake-submission-addr. */
const char *fake_submission_addr;
/* An array with blacklisted addresses and its length. Use
* is_in_blacklist to check. */
static char **blacklist_array;
static size_t blacklist_array_len;
static void wrong_args (const char *text) GPGRT_ATTR_NORETURN;
static void add_blacklist (const char *fname);
static gpg_error_t proc_userid_from_stdin (gpg_error_t (*func)(const char *),
const char *text);
static gpg_error_t command_supported (char *userid);
@ -249,7 +255,7 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
opt.no_autostart = 1;
break;
case oBlacklist:
opt.blacklist = pargs->r.ret_str;
add_blacklist (pargs->r.ret_str);
break;
case aSupported:
@ -477,6 +483,153 @@ main (int argc, char **argv)
}
/* Read a file FNAME into a buffer and return that malloced buffer.
* Caller must free the buffer. On error NULL is returned, on success
* the valid length of the buffer is stored at R_LENGTH. The returned
* buffer is guaranteed to be Nul terminated. */
static char *
read_file (const char *fname, size_t *r_length)
{
estream_t fp;
char *buf;
size_t buflen;
if (!strcmp (fname, "-"))
{
size_t nread, bufsize = 0;
fp = es_stdin;
es_set_binary (fp);
buf = NULL;
buflen = 0;
#define NCHUNK 32767
do
{
bufsize += NCHUNK;
if (!buf)
buf = xmalloc (bufsize+1);
else
buf = xrealloc (buf, bufsize+1);
nread = es_fread (buf+buflen, 1, NCHUNK, fp);
if (nread < NCHUNK && es_ferror (fp))
{
log_error ("error reading '[stdin]': %s\n", strerror (errno));
xfree (buf);
return NULL;
}
buflen += nread;
}
while (nread == NCHUNK);
#undef NCHUNK
}
else
{
struct stat st;
fp = es_fopen (fname, "rb");
if (!fp)
{
log_error ("can't open '%s': %s\n", fname, strerror (errno));
return NULL;
}
if (fstat (es_fileno (fp), &st))
{
log_error ("can't stat '%s': %s\n", fname, strerror (errno));
es_fclose (fp);
return NULL;
}
buflen = st.st_size;
buf = xmalloc (buflen+1);
if (es_fread (buf, buflen, 1, fp) != 1)
{
log_error ("error reading '%s': %s\n", fname, strerror (errno));
es_fclose (fp);
xfree (buf);
return NULL;
}
es_fclose (fp);
}
buf[buflen] = 0;
if (r_length)
*r_length = buflen;
return buf;
}
static int
cmp_blacklist (const void *arg_a, const void *arg_b)
{
const char *a = *(const char **)arg_a;
const char *b = *(const char **)arg_b;
return strcmp (a, b);
}
/* Add a blacklist to our global table. This is called during option
* parsing and thus any use of log_error will eventually stop further
* processing. */
static void
add_blacklist (const char *fname)
{
char *buffer;
char *p, *pend;
char **array;
size_t arraysize, arrayidx;
buffer = read_file (fname, NULL);
if (!buffer)
return;
/* Estimate the number of entries by counting the non-comment lines. */
arraysize = 2; /* For the first and an extra NULL item. */
for (p=buffer; *p; p++)
if (*p == '\n' && p[1] && p[1] != '#')
arraysize++;
array = xcalloc (arraysize, sizeof *array);
arrayidx = 0;
/* Loop over all lines. */
for (p = buffer; p && *p; p = pend)
{
pend = strchr (p, '\n');
if (pend)
*pend++ = 0;
trim_spaces (p);
if (!*p || *p == '#' )
continue;
ascii_strlwr (p);
log_assert (arrayidx < arraysize);
array[arrayidx] = p;
arrayidx++;
}
log_assert (arrayidx < arraysize);
qsort (array, arrayidx, sizeof *array, cmp_blacklist);
blacklist_array = array;
blacklist_array_len = arrayidx;
gpgrt_annotate_leaked_object (buffer);
gpgrt_annotate_leaked_object (blacklist_array);
}
/* Return true if NAME is in a blacklist. */
static int
is_in_blacklist (const char *name)
{
if (!name || !blacklist_array)
return 0;
return !!bsearch (&name, blacklist_array, blacklist_array_len,
sizeof *blacklist_array, cmp_blacklist);
}
/* Read user ids from stdin and call FUNC for each user id. TEXT is
* used for error messages. */
static gpg_error_t
@ -1765,6 +1918,8 @@ mirror_one_key (estream_t key)
continue; /* No mail box or already processed. */
if (!domain_matches_mbox (domain, uid->mbox))
continue; /* We don't want this one. */
if (is_in_blacklist (uid->mbox))
continue;
err = mirror_one_keys_userid (key, uid->mbox, uidlist, fpr);
if (err)

View File

@ -44,7 +44,6 @@ struct
const char *directory;
const char *default_from;
strlist_t extra_headers;
const char *blacklist;
} opt;
/* Debug values and macros. */