wks: New server options --check, --with-dir, with-file.
authorWerner Koch <wk@gnupg.org>
Tue, 19 Dec 2017 16:42:10 +0000 (17:42 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 19 Dec 2017 16:42:10 +0000 (17:42 +0100)
* tools/gpg-wks-server.c (aCheck, oWithDir, oWithFile): New const.
(opts): New options --check, --with-dir, and --with-file.
(main): Call command_check_key.
(command_list_domains): Implement option --with-dir.
(fname_from_userid): New.
(command_check_key): New.
(command_remove_key): Implement existsing command.
(command_revoke_key): Call command_remove_key as a simple
implementation.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/wks.texi
tools/gpg-wks-server.c

index 029dbf0..7f7d515 100644 (file)
@@ -174,18 +174,23 @@ Display a brief help page and exit.
 .br
 .B gpg-wks-server
 .RI [ options ]
+.B \-\-check-key
+.I user-id
+.br
+.B gpg-wks-server
+.RI [ options ]
 .B \-\-install-key
 .I file
 .br
 .B gpg-wks-server
 .RI [ options ]
 .B \-\-remove-key
-.I mailaddr
+.I user-id
 .br
 .B gpg-wks-server
 .RI [ options ]
 .B \-\-revoke-key
-.I mailaddr
+.I user-id
 @end ifset
 
 @mansect description
@@ -208,8 +213,22 @@ The command @option{--list-domains} prints all configured domains.
 Further it creates missing directories for the configuration and
 prints warnings pertaining to problems in the configuration.
 
-The commands @option{--install-key}, @option{--remove-key}, and
-@option{--revoke-key} are not yet functional.
+The command @option{--check-key} (or just @option{--check}) checks
+whether a key with the given user-id is installed.  The process return
+success in this case; to also print a diagnostic, use option
+@option{-v}.  If the key is not installed a diagnostics is printed and
+the process returns failure; to suppress the diagnostic, use option
+@option{-q}.  More than one user-id can be given; see also option
+@option{with-file}.
+
+The command @option{--remove-key} uninstalls a key from the WKD.  The
+process return success in this case; to also print a diagnostic, use
+option @option{-v}.  If the key is not installed a diagnostics is
+printed and the process returns failure; to suppress the diagnostic,
+use option @option{-q}.
+
+The commands @option{--install-key} and @option{--revoke-key} are not
+yet functional.
 
 
 @mansect options
@@ -237,6 +256,16 @@ Requires installation of that command.
 Write the created mail also to @var{file}. Note that the value
 @code{-} for @var{file} would write it to stdout.
 
+@item --with-dir
+@opindex with-dir
+Also print the directory name for each domain listed by command
+@option{--list-domains}.
+
+@item --with-file
+@opindex with-file
+With command @option{--check-key} print for each user-id, the address,
+'i' for installed key or 'n' for not installed key, and the filename.
+
 @item --verbose
 @opindex verbose
 Enable extra informational output.
index 7e3f050..0b1d642 100644 (file)
@@ -66,11 +66,14 @@ enum cmd_and_opt_values
     aInstallKey,
     aRevokeKey,
     aRemoveKey,
+    aCheck,
 
     oGpgProgram,
     oSend,
     oFrom,
     oHeader,
+    oWithDir,
+    oWithFile,
 
     oDummy
   };
@@ -86,12 +89,15 @@ static ARGPARSE_OPTS opts[] = {
               ("run regular jobs")),
   ARGPARSE_c (aListDomains, "list-domains",
               ("list configured domains")),
+  ARGPARSE_c (aCheck, "check",
+              ("check whether a key is installed")),
+  ARGPARSE_c (aCheck, "check-key", "@"),
   ARGPARSE_c (aInstallKey, "install-key",
-              "|FILE|install a key from FILE into the WKD"),
+              "install a key from FILE into the WKD"),
   ARGPARSE_c (aRemoveKey, "remove-key",
-              "|ADDR|remove the key ADDR from the WKD"),
+              "remove a key from the WKD"),
   ARGPARSE_c (aRevokeKey, "revoke-key",
-              "|ADDR|mark the key ADDR in the WKD as revoked"),
+              "mark a key as revoked"),
 
   ARGPARSE_group (301, ("@\nOptions:\n ")),
 
@@ -104,6 +110,8 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_s_s (oFrom, "from", "|ADDR|use ADDR as the default sender"),
   ARGPARSE_s_s (oHeader, "header" ,
                 "|NAME=VALUE|add \"NAME: VALUE\" as header to all mails"),
+  ARGPARSE_s_n (oWithDir, "with-dir", "@"),
+  ARGPARSE_s_n (oWithFile, "with-file", "@"),
 
   ARGPARSE_end ()
 };
@@ -132,6 +140,13 @@ struct server_ctx_s
 };
 typedef struct server_ctx_s *server_ctx_t;
 
+
+/* Flag for --with-dir.  */
+static int opt_with_dir;
+/* Flag for --with-file.  */
+static int opt_with_file;
+
+
 /* Prototypes.  */
 static gpg_error_t get_domain_list (strlist_t *r_list);
 
@@ -142,6 +157,7 @@ static gpg_error_t command_list_domains (void);
 static gpg_error_t command_install_key (const char *fname);
 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_check_key (const char *mailaddr);
 static gpg_error_t command_cron (void);
 
 
@@ -220,10 +236,17 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
         case oOutput:
           opt.output = pargs->r.ret_str;
           break;
+        case oWithDir:
+          opt_with_dir = 1;
+          break;
+        case oWithFile:
+          opt_with_file = 1;
+          break;
 
        case aReceive:
         case aCron:
         case aListDomains:
+        case aCheck:
         case aInstallKey:
         case aRemoveKey:
         case aRevokeKey:
@@ -243,7 +266,7 @@ parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
 int
 main (int argc, char **argv)
 {
-  gpg_error_t err;
+  gpg_error_t err, firsterr;
   ARGPARSE_ARGS pargs;
   enum cmd_and_opt_values cmd;
 
@@ -360,16 +383,29 @@ main (int argc, char **argv)
 
     case aRemoveKey:
       if (argc != 1)
-        wrong_args ("--remove-key MAILADDR");
+        wrong_args ("--remove-key USER-ID");
       err = command_remove_key (*argv);
       break;
 
     case aRevokeKey:
       if (argc != 1)
-        wrong_args ("--revoke-key MAILADDR");
+        wrong_args ("--revoke-key USER-ID");
       err = command_revoke_key (*argv);
       break;
 
+    case aCheck:
+      if (!argc)
+        wrong_args ("--check USER-IDs");
+      firsterr = 0;
+      for (; argc; argc--, argv++)
+        {
+          err = command_check_key (*argv);
+          if (!firsterr)
+            firsterr = err;
+        }
+      err = firsterr;
+      break;
+
     default:
       usage (1);
       err = gpg_error (GPG_ERR_BUG);
@@ -1776,7 +1812,11 @@ command_list_domains (void)
       domain = strrchr (sl->d, '/');
       log_assert (domain);
       domain++;
-      es_printf ("%s\n", domain);
+      if (opt_with_dir)
+        es_printf ("%s %s\n", domain, sl->d);
+      else
+        es_printf ("%s\n", domain);
+
 
       /* Check that the required directories are there.  */
       for (i=0; i < DIM (requireddirs); i++)
@@ -1900,12 +1940,140 @@ command_install_key (const char *fname)
 }
 
 
-/* Remove the key with mail address MAILADDR.  */
+/* Return the filename and optioanlly the addrspec for USERID at
+ * R_FNAME and R_ADDRSPEC.  R_ADDRSPEC might also be set on error.  */
 static gpg_error_t
-command_remove_key (const char *mailaddr)
+fname_from_userid (const char *userid, char **r_fname, char **r_addrspec)
 {
-  (void)mailaddr;
-  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  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.  */
+static gpg_error_t
+command_check_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 (access (fname, R_OK))
+    {
+      err = gpg_error_from_syserror ();
+      if (opt_with_file)
+        es_printf ("%s n %s\n", addrspec, fname);
+      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 stating '%s': %s\n", fname, gpg_strerror (err));
+      goto leave;
+    }
+
+  if (opt_with_file)
+    es_printf ("%s i %s\n", addrspec, fname);
+
+  if (opt.verbose)
+    log_info ("key for '%s' is installed\n", addrspec);
+  err = 0;
+
+ leave:
+  xfree (fname);
+  xfree (addrspec);
+  return err;
+}
+
+
+/* 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;
 }
 
 
@@ -1913,6 +2081,7 @@ command_remove_key (const char *mailaddr)
 static gpg_error_t
 command_revoke_key (const char *mailaddr)
 {
-  (void)mailaddr;
-  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+  /* Remove should be different from removing but we have not yet
+   * defined a suitable way to do this.  */
+  return command_remove_key (mailaddr);
 }