Improve some comments.
[gnupg.git] / g13 / server.c
index fd18b90..0c4563e 100644 (file)
@@ -14,7 +14,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>
 #include "i18n.h"
 #include "keyblob.h"
 #include "server.h"
-#include "mount.h"
 #include "create.h"
+#include "mount.h"
+#include "suspend.h"
+#include "../common/server-help.h"
+#include "../common/call-gpg.h"
 
 
 /* The filepointer for status message used in non-server mode */
@@ -39,14 +42,12 @@ static FILE *statusfp;
 
 /* Local data for this server module.  A pointer to this is stored in
    the CTRL object of each connection.  */
-struct server_local_s 
+struct server_local_s
 {
   /* The Assuan contect we are working on.  */
   assuan_context_t assuan_ctx;
 
   char *containername;  /* Malloced active containername.  */
-
-  strlist_t recipients; /* List of recipients.  */
 };
 
 
@@ -59,44 +60,13 @@ static int command_has_option (const char *cmd, const char *cmdopt);
 
 \f
 /*
-   Helper functions. 
+   Helper functions.
  */
 
 /* Set an error and a description.  */
 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
 
 
-/* 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))); */
-/* } */
-
-
 /* Helper to print a message while leaving a command.  */
 static gpg_error_t
 leave_cmd (assuan_context_t ctx, gpg_error_t err)
@@ -194,7 +164,7 @@ reset_notify (assuan_context_t ctx, char *line)
   xfree (ctrl->server_local->containername);
   ctrl->server_local->containername = NULL;
 
-  FREE_STRLIST (ctrl->server_local->recipients);
+  FREE_STRLIST (ctrl->recipients);
 
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
@@ -202,17 +172,7 @@ reset_notify (assuan_context_t ctx, char *line)
 }
 
 
-
-/* OPEN [options] <filename>
-
-   Open the container FILENAME.  FILENAME must be percent-plus
-   escaped.  A quick check to see whether this is a suitable G13
-   container file is done.  However no cryptographic check or any
-   other check is done.  This command is used to define the target for
-   further commands.  The filename is reset with the RESET command,
-   another OPEN or the CREATE command.
- */
-static const char hlp_open[] = 
+static const char hlp_open[] =
   "OPEN [<options>] <filename>\n"
   "\n"
   "Open the container FILENAME.  FILENAME must be percent-plus\n"
@@ -265,19 +225,19 @@ cmd_open (assuan_context_t ctx, char *line)
   ctrl->server_local->containername = xtrystrdup (line);
   if (!ctrl->server_local->containername)
     err = gpg_error_from_syserror ();
-  
-  
+
+
  leave:
   return leave_cmd (ctx, err);
 }
 
 
-/* MOUNT [options] [<mountpoint>]
-
-   Mount the currently open file onto MOUNTPOINT.  If MOUNTPOINT is
-   not given the system picks an unused mountpoint.  MOUNTPOINT must
-   be percent-plus escaped to allow for arbitrary names.
- */
+static const char hlp_mount[] =
+  "MOUNT [options] [<mountpoint>]\n"
+  "\n"
+  "Mount the currently open file onto MOUNTPOINT.  If MOUNTPOINT is not\n"
+  "given the system picks an unused mountpoint.  MOUNTPOINT must\n"
+  "be percent-plus escaped to allow for arbitrary names.";
 static gpg_error_t
 cmd_mount (assuan_context_t ctx, char *line)
 {
@@ -315,7 +275,7 @@ cmd_mount (assuan_context_t ctx, char *line)
     }
 
   /* Perform the mount.  */
-  err = g13_mount_container (ctrl, ctrl->server_local->containername, 
+  err = g13_mount_container (ctrl, ctrl->server_local->containername,
                              *line? line : NULL);
 
  leave:
@@ -323,12 +283,12 @@ cmd_mount (assuan_context_t ctx, char *line)
 }
 
 
-/* UMOUNT [options] [<mountpoint>]
-
-   Unmount the currently open file or the one opened at MOUNTPOINT.
-   MOUNTPOINT must be percent-plus escaped.  On success the mountpoint
-   is returned via a "MOUNTPOINT" status line.
- */
+static const char hlp_umount[] =
+  "UMOUNT [options] [<mountpoint>]\n"
+  "\n"
+  "Unmount the currently open file or the one opened at MOUNTPOINT.\n"
+  "MOUNTPOINT must be percent-plus escaped.  On success the mountpoint\n"
+  "is returned via a \"MOUNTPOINT\" status line.";
 static gpg_error_t
 cmd_umount (assuan_context_t ctx, char *line)
 {
@@ -360,7 +320,7 @@ cmd_umount (assuan_context_t ctx, char *line)
     }
 
   /* Perform the unmount.  */
-  err = g13_umount_container (ctrl, ctrl->server_local->containername, 
+  err = g13_umount_container (ctrl, ctrl->server_local->containername,
                               *line? line : NULL);
 
  leave:
@@ -368,13 +328,62 @@ cmd_umount (assuan_context_t ctx, char *line)
 }
 
 
+static const char hlp_suspend[] =
+  "SUSPEND\n"
+  "\n"
+  "Suspend the currently set device.";
+static gpg_error_t
+cmd_suspend (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
 
-/* RECIPIENT <userID>
+  line = skip_options (line);
+  if (*line)
+    {
+      err = gpg_error (GPG_ERR_ASS_SYNTAX);
+      goto leave;
+    }
 
-   FIXME - description. 
-   All RECIPIENT commands are cumulative until a RESET or an
-   successful CREATE command.
- */
+  /* Perform the suspend operation.  */
+  err = g13_suspend_container (ctrl, ctrl->server_local->containername);
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_resume[] =
+  "RESUME\n"
+  "\n"
+  "Resume the currently set device.";
+static gpg_error_t
+cmd_resume (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+
+  line = skip_options (line);
+  if (*line)
+    {
+      err = gpg_error (GPG_ERR_ASS_SYNTAX);
+      goto leave;
+    }
+
+  /* Perform the suspend operation.  */
+  err = g13_resume_container (ctrl, ctrl->server_local->containername);
+
+ leave:
+  return leave_cmd (ctx, err);
+}
+
+
+static const char hlp_recipient[] =
+  "RECIPIENT <userID>\n"
+  "\n"
+  "Add USERID to the list of recipients to be used for the next CREATE\n"
+  "command.  All recipient commands are cumulative until a RESET or an\n"
+  "successful create command.";
 static gpg_error_t
 cmd_recipient (assuan_context_t ctx, char *line)
 {
@@ -383,17 +392,17 @@ cmd_recipient (assuan_context_t ctx, char *line)
 
   line = skip_options (line);
 
-  if (!add_to_strlist_try (&ctrl->server_local->recipients, line))
+  if (!add_to_strlist_try (&ctrl->recipients, line))
     err = gpg_error_from_syserror ();
 
   return leave_cmd (ctx, err);
 }
 
 
-/* SIGNER <userID>
-
-   FIXME - description. 
- */
+static const char hlp_signer[] =
+  "SIGNER <userID>\n"
+  "\n"
+  "Not yet implemented.";
 static gpg_error_t
 cmd_signer (assuan_context_t ctx, char *line)
 {
@@ -408,11 +417,11 @@ cmd_signer (assuan_context_t ctx, char *line)
 }
 
 
-/* CREATE [options] filename
-
-   Create a new container.  On success the OPEN command is done
-   implictly for the new container.
- */
+static const char hlp_create[] =
+  "CREATE [options] <filename>\n"
+  "\n"
+  "Create a new container.  On success the OPEN command is \n"
+  "implictly done for the new container.";
 static gpg_error_t
 cmd_create (assuan_context_t ctx, char *line)
 {
@@ -449,12 +458,12 @@ cmd_create (assuan_context_t ctx, char *line)
     }
 
   /* Create container.  */
-  err = g13_create_container (ctrl, line, ctrl->server_local->recipients);
+  err = g13_create_container (ctrl, line);
 
   if (!err)
     {
-      FREE_STRLIST (ctrl->server_local->recipients);
-  
+      FREE_STRLIST (ctrl->recipients);
+
       /* Store the filename.  */
       ctrl->server_local->containername = xtrystrdup (line);
       if (!ctrl->server_local->containername)
@@ -466,17 +475,16 @@ cmd_create (assuan_context_t ctx, char *line)
 }
 
 
-/* GETINFO <what>
-
-   Multipurpose function to return a variety of information.
-   Supported values for WHAT are:
-
-     version     - Return the version of the program.
-     pid         - Return the process id of the server.
-     cmd_has_option CMD OPT
-                 - Returns OK if the command CMD implements the option OPT.
-
- */
+static const char hlp_getinfo[] =
+  "GETINFO <what>\n"
+  "\n"
+  "Multipurpose function to return a variety of information.\n"
+  "Supported values for WHAT are:\n"
+  "\n"
+  "  version     - Return the version of the program.\n"
+  "  pid         - Return the process id of the server.\n"
+  "  cmd_has_option CMD OPT\n"
+  "              - Return OK if the command CMD implements the option OPT.";
 static gpg_error_t
 cmd_getinfo (assuan_context_t ctx, char *line)
 {
@@ -540,7 +548,7 @@ command_has_option (const char *cmd, const char *cmdopt)
 {
   (void)cmd;
   (void)cmdopt;
-      
+
   return 0;
 }
 
@@ -554,15 +562,17 @@ register_commands (assuan_context_t ctx)
     assuan_handler_t handler;
     const char * const help;
   } table[] =  {
-    { "OPEN",          cmd_open, hlp_open },
-    { "MOUNT",         cmd_mount },
-    { "UMOUNT",        cmd_umount },
-    { "RECIPIENT",     cmd_recipient },
-    { "SIGNER",        cmd_signer },
-    { "CREATE",        cmd_create },
-    { "INPUT",         NULL }, 
-    { "OUTPUT",        NULL }, 
-    { "GETINFO",       cmd_getinfo },
+    { "OPEN",          cmd_open,   hlp_open },
+    { "MOUNT",         cmd_mount,  hlp_mount},
+    { "UMOUNT",        cmd_umount, hlp_umount },
+    { "SUSPEND",       cmd_suspend, hlp_suspend },
+    { "RESUME",        cmd_resume,  hlp_resume },
+    { "RECIPIENT",     cmd_recipient, hlp_recipient },
+    { "SIGNER",        cmd_signer, hlp_signer },
+    { "CREATE",        cmd_create, hlp_create },
+    { "INPUT",         NULL },
+    { "OUTPUT",        NULL },
+    { "GETINFO",       cmd_getinfo,hlp_getinfo },
     { NULL }
   };
   gpg_error_t err;
@@ -574,7 +584,7 @@ register_commands (assuan_context_t ctx)
                                      table[i].help);
       if (err)
         return err;
-    } 
+    }
   return 0;
 }
 
@@ -586,7 +596,7 @@ gpg_error_t
 g13_server (ctrl_t ctrl)
 {
   gpg_error_t err;
-  int filedes[2];
+  assuan_fd_t filedes[2];
   assuan_context_t ctx = NULL;
   static const char hello[] = ("GNU Privacy Guard's G13 server "
                                PACKAGE_VERSION " ready");
@@ -594,8 +604,8 @@ g13_server (ctrl_t ctrl)
   /* We use a pipe based server so that we can work from scripts.
      assuan_init_pipe_server will automagically detect when we are
      called with a socketpair and ignore FIELDES in this case. */
-  filedes[0] = 0;
-  filedes[1] = 1;
+  filedes[0] = assuan_fdopen (0);
+  filedes[1] = assuan_fdopen (1);
   err = assuan_new (&ctx);
   if (err)
     {
@@ -623,16 +633,13 @@ g13_server (ctrl_t ctrl)
 
   if (opt.verbose || opt.debug)
     {
-      char *tmp = NULL;
-      const char *s1 = getenv ("GPG_AGENT_INFO");
+      char *tmp;
 
       tmp = xtryasprintf ("Home: %s\n"
                           "Config: %s\n"
-                          "AgentInfo: %s\n"
                           "%s",
-                          opt.homedir,
+                          gnupg_homedir (),
                           opt.config_filename,
-                          s1?s1:"[not set]",
                           hello);
       if (tmp)
         {
@@ -654,9 +661,6 @@ g13_server (ctrl_t ctrl)
     }
   ctrl->server_local->assuan_ctx = ctx;
 
-  if (DBG_ASSUAN)
-    assuan_set_log_stream (ctx, log_get_stream ());
-
   while ( !(err = assuan_accept (ctx)) )
     {
       err = assuan_process (ctx);
@@ -667,7 +671,7 @@ g13_server (ctrl_t ctrl)
     err = 0;
   else
     log_info ("Assuan accept problem: %s\n", gpg_strerror (err));
-  
+
  leave:
   reset_notify (ctx, NULL);  /* Release all items hold by SERVER_LOCAL.  */
   if (ctrl->server_local)
@@ -704,17 +708,17 @@ g13_status (ctrl_t ctrl, int no, ...)
             statusfp = stderr;
           else
             statusfp = fdopen (ctrl->status_fd, "w");
-          
+
           if (!statusfp)
             {
               log_fatal ("can't open fd %d for status output: %s\n",
                          ctrl->status_fd, strerror(errno));
             }
         }
-      
+
       fputs ("[GNUPG:] ", statusfp);
       fputs (get_status_string (no), statusfp);
-    
+
       while ( (text = va_arg (arg_ptr, const char*) ))
         {
           putc ( ' ', statusfp );
@@ -769,3 +773,26 @@ g13_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
 }
 
 
+/*
+ * Decrypt the keyblob (ENCKEYBLOB,ENCKEYBLOBLEN) and store the result
+ * at (R_KEYBLOB, R_KEYBLOBLEN).  Returns 0 on success or an error
+ * code.  On error R_KEYBLOB is set to NULL.
+ *
+ * This actually does not belong here but for that simple wrapper it
+ * does not make sense to add another source file.  Note that we do
+ * not want to have this in keyblob.c, because that code is also used
+ * by the syshelp.
+ */
+gpg_error_t
+g13_keyblob_decrypt (ctrl_t ctrl, const void *enckeyblob, size_t enckeybloblen,
+                     void **r_keyblob, size_t *r_keybloblen)
+{
+  gpg_error_t err;
+
+  /* FIXME:  For now we only implement OpenPGP.  */
+  err = gpg_decrypt_blob (ctrl, opt.gpg_program, opt.gpg_arguments,
+                          enckeyblob, enckeybloblen,
+                          r_keyblob, r_keybloblen);
+
+  return err;
+}