tests: Move environment creation and teardown into each test.
[gnupg.git] / sm / server.c
index 201a34b..d6a2dbb 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -30,6 +30,7 @@
 #include "gpgsm.h"
 #include <assuan.h>
 #include "sysutils.h"
+#include "server-help.h"
 
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
@@ -55,8 +56,8 @@ struct server_local_s {
 
 
 /* Cookie definition for assuan data line output.  */
-static ssize_t data_line_cookie_write (void *cookie,
-                                       const void *buffer, size_t size);
+static gpgrt_ssize_t data_line_cookie_write (void *cookie,
+                                             const void *buffer, size_t size);
 static int data_line_cookie_close (void *cookie);
 static es_cookie_io_functions_t data_line_cookie_functions =
   {
@@ -95,41 +96,9 @@ strcpy_escaped_plus (char *d, const char *s)
 }
 
 
-/* Skip over options.
-   Blanks after the options are also removed. */
-static char *
-skip_options (const char *line)
-{
-  while (spacep (line))
-    line++;
-  while ( *line == '-' && line[1] == '-' )
-    {
-      while (*line && !spacep (line))
-        line++;
-      while (spacep (line))
-        line++;
-    }
-  return (char*)line;
-}
-
-
-/* Check whether the option NAME appears in LINE */
-static int
-has_option (const char *line, const char *name)
-{
-  const char *s;
-  int n = strlen (name);
-
-  s = strstr (line, name);
-  if (s && s >= skip_options (line))
-    return 0;
-  return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-
 /* A write handler used by es_fopencookie to write assuan data
    lines.  */
-static ssize_t
+static gpgrt_ssize_t
 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
 {
   assuan_context_t ctx = cookie;
@@ -140,7 +109,7 @@ data_line_cookie_write (void *cookie, const void *buffer, size_t size)
       return -1;
     }
 
-  return size;
+  return (gpgrt_ssize_t)size;
 }
 
 static int
@@ -274,6 +243,11 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
       int i = *value? atoi (value) : 0;
       ctrl->with_validation = i;
     }
+  else if (!strcmp (key, "with-secret"))
+    {
+      int i = *value? atoi (value) : 0;
+      ctrl->with_secret = i;
+    }
   else if (!strcmp (key, "validation-model"))
     {
       int i = gpgsm_parse_validation_model (value);
@@ -304,6 +278,16 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
     {
       ctrl->server_local->no_encrypt_to = 1;
     }
+  else if (!strcmp (key, "offline"))
+    {
+      /* We ignore this option if gpgsm has been started with
+         --disable-dirmngr (which also sets offline).  */
+      if (!opt.disable_dirmngr)
+        {
+          int i = *value? !!atoi (value) : 1;
+          ctrl->offline = i;
+        }
+    }
   else
     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
@@ -410,7 +394,7 @@ static const char hlp_signer[] =
   "used, the signing will then not be done for this key.  If the policy\n"
   "is not to sign at all if not all signer keys are valid, the client\n"
   "has to take care of this.  All SIGNER commands are cumulative until\n"
-  "a RESET but they are *not* reset by an SIGN command becuase it can\n"
+  "a RESET but they are *not* reset by an SIGN command because it can\n"
   "be expected that set of signers are used for more than one sign\n"
   "operation.";
 static gpg_error_t
@@ -666,13 +650,15 @@ cmd_import (assuan_context_t ctx, char *line)
 
 
 static const char hlp_export[] =
-  "EXPORT [--data [--armor|--base64]] [--] <pattern>\n"
+  "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
   "\n"
   "Export the certificates selected by PATTERN.  With --data the output\n"
   "is returned using Assuan D lines; the default is to use the sink given\n"
   "by the last \"OUTPUT\" command.  The options --armor or --base64 encode \n"
   "the output using the PEM respective a plain base-64 format; the default\n"
-  "is a binary format which is only suitable for a single certificate.";
+  "is a binary format which is only suitable for a single certificate.\n"
+  "With --secret the secret key is exported using the PKCS#8 format,\n"
+  "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
 static gpg_error_t
 cmd_export (assuan_context_t ctx, char *line)
 {
@@ -680,15 +666,23 @@ cmd_export (assuan_context_t ctx, char *line)
   char *p;
   strlist_t list, sl;
   int use_data;
+  int opt_secret;
+  int opt_raw = 0;
+  int opt_pkcs12 = 0;
 
   use_data = has_option (line, "--data");
-
   if (use_data)
     {
       /* We need to override any possible setting done by an OUTPUT command. */
       ctrl->create_pem = has_option (line, "--armor");
       ctrl->create_base64 = has_option (line, "--base64");
     }
+  opt_secret = has_option (line, "--secret");
+  if (opt_secret)
+    {
+      opt_raw = has_option (line, "--raw");
+      opt_pkcs12 = has_option (line, "--pkcs12");
+    }
 
   line = skip_options (line);
 
@@ -715,6 +709,14 @@ cmd_export (assuan_context_t ctx, char *line)
         }
     }
 
+  if (opt_secret)
+    {
+      if (!list || !*list->d)
+        return set_error (GPG_ERR_NO_DATA, "No key given");
+      if (list->next)
+        return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
+  }
+
   if (use_data)
     {
       estream_t stream;
@@ -726,7 +728,11 @@ cmd_export (assuan_context_t ctx, char *line)
           return set_error (GPG_ERR_ASS_GENERAL,
                             "error setting up a data stream");
         }
-      gpgsm_export (ctrl, list, stream);
+      if (opt_secret)
+        gpgsm_p12_export (ctrl, list->d, stream,
+                          opt_raw? 2 : opt_pkcs12 ? 0 : 1);
+      else
+        gpgsm_export (ctrl, list, stream);
       es_fclose (stream);
     }
   else
@@ -746,7 +752,11 @@ cmd_export (assuan_context_t ctx, char *line)
           return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
         }
 
-      gpgsm_export (ctrl, list, out_fp);
+      if (opt_secret)
+        gpgsm_p12_export (ctrl, list->d, out_fp,
+                          opt_raw? 2 : opt_pkcs12 ? 0 : 1);
+      else
+        gpgsm_export (ctrl, list, out_fp);
       es_fclose (out_fp);
     }
 
@@ -1029,7 +1039,7 @@ static const char hlp_getauditlog[] =
   "If --data is used, the output is send using D-lines and not to the\n"
   "file descriptor given by an OUTPUT command.\n"
   "\n"
-  "If --html is used the output is formated as an XHTML block. This is\n"
+  "If --html is used the output is formatted as an XHTML block. This is\n"
   "designed to be incorporated into a HTML document.";
 static gpg_error_t
 cmd_getauditlog (assuan_context_t ctx, char *line)
@@ -1042,7 +1052,7 @@ cmd_getauditlog (assuan_context_t ctx, char *line)
 
   opt_data = has_option (line, "--data");
   opt_html = has_option (line, "--html");
-  line = skip_options (line);
+  /* Not needed: line = skip_options (line); */
 
   if (!ctrl->audit)
     return gpg_error (GPG_ERR_NO_DATA);
@@ -1088,10 +1098,12 @@ static const char hlp_getinfo[] =
   "  pid         - Return the process id of the server.\n"
   "  agent-check - Return success if the agent is running.\n"
   "  cmd_has_option CMD OPT\n"
-  "              - Returns OK if the command CMD implements the option OPT.";
+  "              - Returns OK if the command CMD implements the option OPT.\n"
+  "  offline     - Returns OK if the connection is in offline mode.";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
 {
+  ctrl_t ctrl = assuan_get_pointer (ctx);
   int rc = 0;
 
   if (!strcmp (line, "version"))
@@ -1108,7 +1120,6 @@ cmd_getinfo (assuan_context_t ctx, char *line)
     }
   else if (!strcmp (line, "agent-check"))
     {
-      ctrl_t ctrl = assuan_get_pointer (ctx);
       rc = gpgsm_agent_send_nop (ctrl);
     }
   else if (!strncmp (line, "cmd_has_option", 14)
@@ -1143,6 +1154,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
             }
         }
     }
+  else if (!strcmp (line, "offline"))
+    {
+      rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL);
+    }
   else
     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
 
@@ -1293,22 +1308,17 @@ gpgsm_server (certlist_t default_recplist)
     }
   if (opt.verbose || opt.debug)
     {
-      char *tmp = NULL;
-      const char *s1 = getenv (GPG_AGENT_INFO_NAME);
+      char *tmp;
 
       /* Fixme: Use the really used socket name.  */
       if (asprintf (&tmp,
                     "Home: %s\n"
                     "Config: %s\n"
-                    "AgentInfo: %s\n"
                     "DirmngrInfo: %s\n"
                     "%s",
-                    opt.homedir,
+                    gnupg_homedir (),
                     opt.config_filename,
-                    s1?s1:"[not set]",
-                    (dirmngr_user_socket_name ()
-                     ? dirmngr_user_socket_name ()
-                     : dirmngr_sys_socket_name ()),
+                    dirmngr_socket_name (),
                     hello) > 0)
         {
           assuan_set_hello_line (ctx, tmp);