mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-23 10:29:58 +01:00
wks: Move a few server functions to wks-util.
* tools/gpg-wks-server.c (write_to_file): Move to ... * tools/wks-util.c: here. * tools/gpg-wks-server.c (compute_hu_fname): Move to ... * tools/wks-util.c (wks_compute_hu_fname): here. * tools/gpg-wks-server.c (fname_from_userid): Move to ... * tools/wks-util.c (wks_fname_from_userid): here. * tools/gpg-wks-server.c (command_install_key): Move to ... * tools/wks-util.c (wks_cmd_install_key): here and change caller. * tools/gpg-wks-server.c (command_remove_key): Move to ... * tools/wks-util.c (wks_cmd_remove_key): here and change callers. Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 99094c992c20dd22971beb3527cfda109cd1df89)
This commit is contained in:
parent
6008410e51
commit
51b722c6f5
@ -157,8 +157,6 @@ static gpg_error_t command_receive_cb (void *opaque,
|
|||||||
const char *mediatype, estream_t fp,
|
const char *mediatype, estream_t fp,
|
||||||
unsigned int flags);
|
unsigned int flags);
|
||||||
static gpg_error_t command_list_domains (void);
|
static gpg_error_t command_list_domains (void);
|
||||||
static gpg_error_t command_install_key (const char *fname, const char *userid);
|
|
||||||
static gpg_error_t command_remove_key (const char *mailaddr);
|
|
||||||
static gpg_error_t command_revoke_key (const char *mailaddr);
|
static gpg_error_t command_revoke_key (const char *mailaddr);
|
||||||
static gpg_error_t command_check_key (const char *mailaddr);
|
static gpg_error_t command_check_key (const char *mailaddr);
|
||||||
static gpg_error_t command_cron (void);
|
static gpg_error_t command_cron (void);
|
||||||
@ -385,13 +383,13 @@ main (int argc, char **argv)
|
|||||||
case aInstallKey:
|
case aInstallKey:
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
wrong_args ("--install-key FILE USER-ID");
|
wrong_args ("--install-key FILE USER-ID");
|
||||||
err = command_install_key (*argv, argv[1]);
|
err = wks_cmd_install_key (*argv, argv[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case aRemoveKey:
|
case aRemoveKey:
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
wrong_args ("--remove-key USER-ID");
|
wrong_args ("--remove-key USER-ID");
|
||||||
err = command_remove_key (*argv);
|
err = wks_cmd_remove_key (*argv);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case aRevokeKey:
|
case aRevokeKey:
|
||||||
@ -1346,81 +1344,6 @@ send_congratulation_message (const char *mbox, const char *keyfile)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write the content of SRC to the new file FNAME. */
|
|
||||||
static gpg_error_t
|
|
||||||
write_to_file (estream_t src, const char *fname)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
estream_t dst;
|
|
||||||
char buffer[4096];
|
|
||||||
size_t nread, written;
|
|
||||||
|
|
||||||
dst = es_fopen (fname, "wb");
|
|
||||||
if (!dst)
|
|
||||||
return gpg_error_from_syserror ();
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
nread = es_fread (buffer, 1, sizeof buffer, src);
|
|
||||||
if (!nread)
|
|
||||||
break;
|
|
||||||
written = es_fwrite (buffer, 1, nread, dst);
|
|
||||||
if (written != nread)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
while (!es_feof (src) && !es_ferror (src) && !es_ferror (dst));
|
|
||||||
if (!es_feof (src) || es_ferror (src) || es_ferror (dst))
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
es_fclose (dst);
|
|
||||||
gnupg_remove (fname);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (es_fclose (dst))
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Compute the the full file name for the key with ADDRSPEC and return
|
|
||||||
* it at R_FNAME. */
|
|
||||||
static gpg_error_t
|
|
||||||
compute_hu_fname (char **r_fname, const char *addrspec)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
char *hash;
|
|
||||||
const char *domain;
|
|
||||||
char sha1buf[20];
|
|
||||||
|
|
||||||
*r_fname = NULL;
|
|
||||||
|
|
||||||
domain = strchr (addrspec, '@');
|
|
||||||
if (!domain || !domain[1] || domain == addrspec)
|
|
||||||
return gpg_error (GPG_ERR_INV_ARG);
|
|
||||||
domain++;
|
|
||||||
|
|
||||||
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, addrspec, domain - addrspec - 1);
|
|
||||||
hash = zb32_encode (sha1buf, 8*20);
|
|
||||||
if (!hash)
|
|
||||||
return gpg_error_from_syserror ();
|
|
||||||
|
|
||||||
*r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
|
|
||||||
if (!*r_fname)
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
else
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
xfree (hash);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check that we have send a request with NONCE and publish the key. */
|
/* Check that we have send a request with NONCE and publish the key. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
|
check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
|
||||||
@ -1495,7 +1418,7 @@ check_and_publish (server_ctx_t ctx, const char *address, const char *nonce)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Hash user ID and create filename. */
|
/* Hash user ID and create filename. */
|
||||||
err = compute_hu_fname (&fnewname, address);
|
err = wks_compute_hu_fname (&fnewname, address);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
@ -2004,195 +1927,6 @@ command_cron (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Install a single key into the WKD by reading FNAME and extracting
|
|
||||||
* USERID. */
|
|
||||||
static gpg_error_t
|
|
||||||
command_install_key (const char *fname, const char *userid)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
KEYDB_SEARCH_DESC desc;
|
|
||||||
estream_t fp = NULL;
|
|
||||||
char *addrspec = NULL;
|
|
||||||
char *fpr = NULL;
|
|
||||||
uidinfo_list_t uidlist = NULL;
|
|
||||||
uidinfo_list_t uid, thisuid;
|
|
||||||
time_t thistime;
|
|
||||||
char *huname = NULL;
|
|
||||||
int any;
|
|
||||||
|
|
||||||
addrspec = mailbox_from_userid (userid);
|
|
||||||
if (!addrspec)
|
|
||||||
{
|
|
||||||
log_error ("\"%s\" is not a proper mail address\n", userid);
|
|
||||||
err = gpg_error (GPG_ERR_INV_USER_ID);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!classify_user_id (fname, &desc, 1)
|
|
||||||
&& (desc.mode == KEYDB_SEARCH_MODE_FPR
|
|
||||||
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
|
|
||||||
{
|
|
||||||
/* FNAME looks like a fingerprint. Get the key from the
|
|
||||||
* standard keyring. */
|
|
||||||
err = wks_get_key (&fp, fname, addrspec, 0);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("error getting key '%s' (uid='%s'): %s\n",
|
|
||||||
fname, addrspec, gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else /* Take it from the file */
|
|
||||||
{
|
|
||||||
fp = es_fopen (fname, "rb");
|
|
||||||
if (!fp)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* List the key so that we can figure out the newest UID with the
|
|
||||||
* requested addrspec. */
|
|
||||||
err = wks_list_key (fp, &fpr, &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;
|
|
||||||
any = 0;
|
|
||||||
for (uid = uidlist; uid; uid = uid->next)
|
|
||||||
{
|
|
||||||
if (!uid->mbox)
|
|
||||||
continue; /* Should not happen anyway. */
|
|
||||||
if (ascii_strcasecmp (uid->mbox, addrspec))
|
|
||||||
continue; /* Not the requested addrspec. */
|
|
||||||
any = 1;
|
|
||||||
if (uid->created > thistime)
|
|
||||||
{
|
|
||||||
thistime = uid->created;
|
|
||||||
thisuid = uid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!thisuid)
|
|
||||||
thisuid = uidlist; /* This is the case for a missing timestamp. */
|
|
||||||
if (!any)
|
|
||||||
{
|
|
||||||
log_error ("public key in '%s' has no mail address '%s'\n",
|
|
||||||
fname, addrspec);
|
|
||||||
err = gpg_error (GPG_ERR_INV_USER_ID);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt.verbose)
|
|
||||||
log_info ("using key with user id '%s'\n", thisuid->uid);
|
|
||||||
|
|
||||||
{
|
|
||||||
estream_t fp2;
|
|
||||||
|
|
||||||
es_rewind (fp);
|
|
||||||
err = wks_filter_uid (&fp2, fp, thisuid->uid, 1);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("error filtering key: %s\n", gpg_strerror (err));
|
|
||||||
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
es_fclose (fp);
|
|
||||||
fp = fp2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hash user ID and create filename. */
|
|
||||||
err = compute_hu_fname (&huname, addrspec);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Publish. */
|
|
||||||
err = write_to_file (fp, huname);
|
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
log_error ("copying key to '%s' failed: %s\n", huname,gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure it is world readable. */
|
|
||||||
if (gnupg_chmod (huname, "-rwxr--r--"))
|
|
||||||
log_error ("can't set permissions of '%s': %s\n",
|
|
||||||
huname, gpg_strerror (gpg_err_code_from_syserror()));
|
|
||||||
|
|
||||||
if (!opt.quiet)
|
|
||||||
log_info ("key %s published for '%s'\n", fpr, addrspec);
|
|
||||||
|
|
||||||
leave:
|
|
||||||
xfree (huname);
|
|
||||||
free_uidinfo_list (uidlist);
|
|
||||||
xfree (fpr);
|
|
||||||
xfree (addrspec);
|
|
||||||
es_fclose (fp);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the filename and optionally the addrspec for USERID at
|
|
||||||
* R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. */
|
|
||||||
static gpg_error_t
|
|
||||||
fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
char *addrspec = NULL;
|
|
||||||
const char *domain;
|
|
||||||
char *hash = NULL;
|
|
||||||
const char *s;
|
|
||||||
char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
|
|
||||||
|
|
||||||
*r_fname = NULL;
|
|
||||||
if (r_addrspec)
|
|
||||||
*r_addrspec = NULL;
|
|
||||||
|
|
||||||
addrspec = mailbox_from_userid (userid);
|
|
||||||
if (!addrspec)
|
|
||||||
{
|
|
||||||
if (opt.verbose)
|
|
||||||
log_info ("\"%s\" is not a proper mail address\n", userid);
|
|
||||||
err = gpg_error (GPG_ERR_INV_USER_ID);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
domain = strchr (addrspec, '@');
|
|
||||||
log_assert (domain);
|
|
||||||
domain++;
|
|
||||||
|
|
||||||
/* Hash user ID and create filename. */
|
|
||||||
s = strchr (addrspec, '@');
|
|
||||||
log_assert (s);
|
|
||||||
gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, addrspec, s - addrspec);
|
|
||||||
hash = zb32_encode (shaxbuf, 8*20);
|
|
||||||
if (!hash)
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
*r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
|
|
||||||
if (!*r_fname)
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
else
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
leave:
|
|
||||||
if (r_addrspec && addrspec)
|
|
||||||
*r_addrspec = addrspec;
|
|
||||||
else
|
|
||||||
xfree (addrspec);
|
|
||||||
xfree (hash);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether the key with USER_ID is installed. */
|
/* Check whether the key with USER_ID is installed. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
command_check_key (const char *userid)
|
command_check_key (const char *userid)
|
||||||
@ -2201,7 +1935,7 @@ command_check_key (const char *userid)
|
|||||||
char *addrspec = NULL;
|
char *addrspec = NULL;
|
||||||
char *fname = NULL;
|
char *fname = NULL;
|
||||||
|
|
||||||
err = fname_from_userid (userid, &fname, &addrspec);
|
err = wks_fname_from_userid (userid, &fname, &addrspec);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
@ -2236,49 +1970,11 @@ command_check_key (const char *userid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Remove the key with mail address in USERID. */
|
|
||||||
static gpg_error_t
|
|
||||||
command_remove_key (const char *userid)
|
|
||||||
{
|
|
||||||
gpg_error_t err;
|
|
||||||
char *addrspec = NULL;
|
|
||||||
char *fname = NULL;
|
|
||||||
|
|
||||||
err = fname_from_userid (userid, &fname, &addrspec);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
if (gnupg_remove (fname))
|
|
||||||
{
|
|
||||||
err = gpg_error_from_syserror ();
|
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
|
||||||
{
|
|
||||||
if (!opt.quiet)
|
|
||||||
log_info ("key for '%s' is not installed\n", addrspec);
|
|
||||||
log_inc_errorcount ();
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
log_error ("error removing '%s': %s\n", fname, gpg_strerror (err));
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opt.verbose)
|
|
||||||
log_info ("key for '%s' removed\n", addrspec);
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
leave:
|
|
||||||
xfree (fname);
|
|
||||||
xfree (addrspec);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Revoke the key with mail address MAILADDR. */
|
/* Revoke the key with mail address MAILADDR. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
command_revoke_key (const char *mailaddr)
|
command_revoke_key (const char *mailaddr)
|
||||||
{
|
{
|
||||||
/* Remove should be different from removing but we have not yet
|
/* Remove should be different from removing but we have not yet
|
||||||
* defined a suitable way to do this. */
|
* defined a suitable way to do this. */
|
||||||
return command_remove_key (mailaddr);
|
return wks_cmd_remove_key (mailaddr);
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,13 @@ gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
|
|||||||
int ignore_unknown);
|
int ignore_unknown);
|
||||||
void wks_free_policy (policy_flags_t policy);
|
void wks_free_policy (policy_flags_t policy);
|
||||||
|
|
||||||
|
gpg_error_t wks_fname_from_userid (const char *userid,
|
||||||
|
char **r_fname, char **r_addrspec);
|
||||||
|
gpg_error_t wks_compute_hu_fname (char **r_fname, const char *addrspec);
|
||||||
|
gpg_error_t wks_cmd_install_key (const char *fname, const char *userid);
|
||||||
|
gpg_error_t wks_cmd_remove_key (const char *userid);
|
||||||
|
|
||||||
|
|
||||||
/*-- wks-receive.c --*/
|
/*-- wks-receive.c --*/
|
||||||
|
|
||||||
/* Flag values for the receive callback. */
|
/* Flag values for the receive callback. */
|
||||||
|
305
tools/wks-util.c
305
tools/wks-util.c
@ -24,7 +24,10 @@
|
|||||||
#include "../common/status.h"
|
#include "../common/status.h"
|
||||||
#include "../common/ccparray.h"
|
#include "../common/ccparray.h"
|
||||||
#include "../common/exectool.h"
|
#include "../common/exectool.h"
|
||||||
|
#include "../common/zb32.h"
|
||||||
|
#include "../common/userids.h"
|
||||||
#include "../common/mbox-util.h"
|
#include "../common/mbox-util.h"
|
||||||
|
#include "../common/sysutils.h"
|
||||||
#include "mime-maker.h"
|
#include "mime-maker.h"
|
||||||
#include "send-mail.h"
|
#include "send-mail.h"
|
||||||
#include "gpg-wks.h"
|
#include "gpg-wks.h"
|
||||||
@ -699,3 +702,305 @@ wks_free_policy (policy_flags_t policy)
|
|||||||
memset (policy, 0, sizeof *policy);
|
memset (policy, 0, sizeof *policy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the content of SRC to the new file FNAME. */
|
||||||
|
static gpg_error_t
|
||||||
|
write_to_file (estream_t src, const char *fname)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
estream_t dst;
|
||||||
|
char buffer[4096];
|
||||||
|
size_t nread, written;
|
||||||
|
|
||||||
|
dst = es_fopen (fname, "wb");
|
||||||
|
if (!dst)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nread = es_fread (buffer, 1, sizeof buffer, src);
|
||||||
|
if (!nread)
|
||||||
|
break;
|
||||||
|
written = es_fwrite (buffer, 1, nread, dst);
|
||||||
|
if (written != nread)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (!es_feof (src) && !es_ferror (src) && !es_ferror (dst));
|
||||||
|
if (!es_feof (src) || es_ferror (src) || es_ferror (dst))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
es_fclose (dst);
|
||||||
|
gnupg_remove (fname);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es_fclose (dst))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error closing '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the filename and optionally the addrspec for USERID at
|
||||||
|
* R_FNAME and R_ADDRSPEC. R_ADDRSPEC might also be set on error. */
|
||||||
|
gpg_error_t
|
||||||
|
wks_fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *addrspec = NULL;
|
||||||
|
const char *domain;
|
||||||
|
char *hash = NULL;
|
||||||
|
const char *s;
|
||||||
|
char shaxbuf[32]; /* Used for SHA-1 and SHA-256 */
|
||||||
|
|
||||||
|
*r_fname = NULL;
|
||||||
|
if (r_addrspec)
|
||||||
|
*r_addrspec = NULL;
|
||||||
|
|
||||||
|
addrspec = mailbox_from_userid (userid);
|
||||||
|
if (!addrspec)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("\"%s\" is not a proper mail address\n", userid);
|
||||||
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
domain = strchr (addrspec, '@');
|
||||||
|
log_assert (domain);
|
||||||
|
domain++;
|
||||||
|
|
||||||
|
/* Hash user ID and create filename. */
|
||||||
|
s = strchr (addrspec, '@');
|
||||||
|
log_assert (s);
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA1, shaxbuf, addrspec, s - addrspec);
|
||||||
|
hash = zb32_encode (shaxbuf, 8*20);
|
||||||
|
if (!hash)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
|
||||||
|
if (!*r_fname)
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
else
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (r_addrspec && addrspec)
|
||||||
|
*r_addrspec = addrspec;
|
||||||
|
else
|
||||||
|
xfree (addrspec);
|
||||||
|
xfree (hash);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compute the the full file name for the key with ADDRSPEC and return
|
||||||
|
* it at R_FNAME. */
|
||||||
|
gpg_error_t
|
||||||
|
wks_compute_hu_fname (char **r_fname, const char *addrspec)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *hash;
|
||||||
|
const char *domain;
|
||||||
|
char sha1buf[20];
|
||||||
|
|
||||||
|
*r_fname = NULL;
|
||||||
|
|
||||||
|
domain = strchr (addrspec, '@');
|
||||||
|
if (!domain || !domain[1] || domain == addrspec)
|
||||||
|
return gpg_error (GPG_ERR_INV_ARG);
|
||||||
|
domain++;
|
||||||
|
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1buf, addrspec, domain - addrspec - 1);
|
||||||
|
hash = zb32_encode (sha1buf, 8*20);
|
||||||
|
if (!hash)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
|
*r_fname = make_filename_try (opt.directory, domain, "hu", hash, NULL);
|
||||||
|
if (!*r_fname)
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
else
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
xfree (hash);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Install a single key into the WKD by reading FNAME and extracting
|
||||||
|
* USERID. */
|
||||||
|
gpg_error_t
|
||||||
|
wks_cmd_install_key (const char *fname, const char *userid)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
KEYDB_SEARCH_DESC desc;
|
||||||
|
estream_t fp = NULL;
|
||||||
|
char *addrspec = NULL;
|
||||||
|
char *fpr = NULL;
|
||||||
|
uidinfo_list_t uidlist = NULL;
|
||||||
|
uidinfo_list_t uid, thisuid;
|
||||||
|
time_t thistime;
|
||||||
|
char *huname = NULL;
|
||||||
|
int any;
|
||||||
|
|
||||||
|
addrspec = mailbox_from_userid (userid);
|
||||||
|
if (!addrspec)
|
||||||
|
{
|
||||||
|
log_error ("\"%s\" is not a proper mail address\n", userid);
|
||||||
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!classify_user_id (fname, &desc, 1)
|
||||||
|
&& (desc.mode == KEYDB_SEARCH_MODE_FPR
|
||||||
|
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
|
||||||
|
{
|
||||||
|
/* FNAME looks like a fingerprint. Get the key from the
|
||||||
|
* standard keyring. */
|
||||||
|
err = wks_get_key (&fp, fname, addrspec, 0);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error getting key '%s' (uid='%s'): %s\n",
|
||||||
|
fname, addrspec, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Take it from the file */
|
||||||
|
{
|
||||||
|
fp = es_fopen (fname, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error reading '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List the key so that we can figure out the newest UID with the
|
||||||
|
* requested addrspec. */
|
||||||
|
err = wks_list_key (fp, &fpr, &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;
|
||||||
|
any = 0;
|
||||||
|
for (uid = uidlist; uid; uid = uid->next)
|
||||||
|
{
|
||||||
|
if (!uid->mbox)
|
||||||
|
continue; /* Should not happen anyway. */
|
||||||
|
if (ascii_strcasecmp (uid->mbox, addrspec))
|
||||||
|
continue; /* Not the requested addrspec. */
|
||||||
|
any = 1;
|
||||||
|
if (uid->created > thistime)
|
||||||
|
{
|
||||||
|
thistime = uid->created;
|
||||||
|
thisuid = uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!thisuid)
|
||||||
|
thisuid = uidlist; /* This is the case for a missing timestamp. */
|
||||||
|
if (!any)
|
||||||
|
{
|
||||||
|
log_error ("public key in '%s' has no mail address '%s'\n",
|
||||||
|
fname, addrspec);
|
||||||
|
err = gpg_error (GPG_ERR_INV_USER_ID);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("using key with user id '%s'\n", thisuid->uid);
|
||||||
|
|
||||||
|
{
|
||||||
|
estream_t fp2;
|
||||||
|
|
||||||
|
es_rewind (fp);
|
||||||
|
err = wks_filter_uid (&fp2, fp, thisuid->uid, 1);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error filtering key: %s\n", gpg_strerror (err));
|
||||||
|
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
es_fclose (fp);
|
||||||
|
fp = fp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hash user ID and create filename. */
|
||||||
|
err = wks_compute_hu_fname (&huname, addrspec);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
/* Publish. */
|
||||||
|
err = write_to_file (fp, huname);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("copying key to '%s' failed: %s\n", huname,gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure it is world readable. */
|
||||||
|
if (gnupg_chmod (huname, "-rwxr--r--"))
|
||||||
|
log_error ("can't set permissions of '%s': %s\n",
|
||||||
|
huname, gpg_strerror (gpg_err_code_from_syserror()));
|
||||||
|
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info ("key %s published for '%s'\n", fpr, addrspec);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (huname);
|
||||||
|
free_uidinfo_list (uidlist);
|
||||||
|
xfree (fpr);
|
||||||
|
xfree (addrspec);
|
||||||
|
es_fclose (fp);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Remove the key with mail address in USERID. */
|
||||||
|
gpg_error_t
|
||||||
|
wks_cmd_remove_key (const char *userid)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *addrspec = NULL;
|
||||||
|
char *fname = NULL;
|
||||||
|
|
||||||
|
err = wks_fname_from_userid (userid, &fname, &addrspec);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (gnupg_remove (fname))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
|
{
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info ("key for '%s' is not installed\n", addrspec);
|
||||||
|
log_inc_errorcount ();
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error ("error removing '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("key for '%s' removed\n", addrspec);
|
||||||
|
err = 0;
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (fname);
|
||||||
|
xfree (addrspec);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user