Make use of the *_NAME etc macros.
[gnupg.git] / g10 / server.c
index 87a52d2..8bf7a08 100644 (file)
 
 
 /* Data used to associate an Assuan context with local server data.  */
 
 
 /* Data used to associate an Assuan context with local server data.  */
-struct server_local_s 
+struct server_local_s
 {
   /* Our current Assuan context. */
 {
   /* Our current Assuan context. */
-  assuan_context_t assuan_ctx;  
+  assuan_context_t assuan_ctx;
   /* File descriptor as set by the MESSAGE command. */
   /* File descriptor as set by the MESSAGE command. */
-  gnupg_fd_t message_fd;               
+  gnupg_fd_t message_fd;
 
   /* List of prepared recipients.  */
   pk_list_t recplist;
 
 
   /* List of prepared recipients.  */
   pk_list_t recplist;
 
+  /* Set if pinentry notifications should be passed back to the
+     client. */
+  int allow_pinentry_notify;
 };
 
 
 \f
 /* Helper to close the message fd if it is open. */
 };
 
 
 \f
 /* Helper to close the message fd if it is open. */
-static void 
+static void
 close_message_fd (ctrl_t ctrl)
 {
   if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
     {
       assuan_sock_close (ctrl->server_local->message_fd);
       ctrl->server_local->message_fd = GNUPG_INVALID_FD;
 close_message_fd (ctrl_t ctrl)
 {
   if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
     {
       assuan_sock_close (ctrl->server_local->message_fd);
       ctrl->server_local->message_fd = GNUPG_INVALID_FD;
-    } 
+    }
 }
 
 
 }
 
 
@@ -89,7 +92,7 @@ has_option (const char *line, const char *name)
 {
   const char *s;
   int n = strlen (name);
 {
   const char *s;
   int n = strlen (name);
-  
+
   s = strstr (line, name);
   if (s && s >= skip_options (line))
     return 0;
   s = strstr (line, name);
   if (s && s >= skip_options (line))
     return 0;
@@ -105,9 +108,8 @@ has_option (const char *line, const char *name)
 static gpg_error_t
 option_handler (assuan_context_t ctx, const char *key, const char *value)
 {
 static gpg_error_t
 option_handler (assuan_context_t ctx, const char *key, const char *value)
 {
-/*   ctrl_t ctrl = assuan_get_pointer (ctx); */
+  ctrl_t ctrl = assuan_get_pointer (ctx);
 
 
-  (void)ctx;
   (void)value;
 
   /* Fixme: Implement the tty and locale args. */
   (void)value;
 
   /* Fixme: Implement the tty and locale args. */
@@ -136,6 +138,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
     {
       /* This is for now a dummy option. */
     }
     {
       /* This is for now a dummy option. */
     }
+  else if (!strcmp (key, "allow-pinentry-notify"))
+    {
+      ctrl->server_local->allow_pinentry_notify = 1;
+    }
   else
     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
   else
     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
 
@@ -144,23 +150,26 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
 
 
 /* Called by libassuan for RESET commands. */
 
 
 /* Called by libassuan for RESET commands. */
-static void
-reset_notify (assuan_context_t ctx)
+static gpg_error_t
+reset_notify (assuan_context_t ctx, char *line)
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
 {
   ctrl_t ctrl = assuan_get_pointer (ctx);
 
+  (void)line;
+
   release_pk_list (ctrl->server_local->recplist);
   ctrl->server_local->recplist = NULL;
 
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
   release_pk_list (ctrl->server_local->recplist);
   ctrl->server_local->recplist = NULL;
 
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
+  return 0;
 }
 
 
 /* Called by libassuan for INPUT commands. */
 }
 
 
 /* Called by libassuan for INPUT commands. */
-static void
-input_notify (assuan_context_t ctx, const char *line)
+static gpg_error_t
+input_notify (assuan_context_t ctx, char *line)
 {
 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
 
 {
 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
 
@@ -176,15 +185,16 @@ input_notify (assuan_context_t ctx, const char *line)
     {
       /* FIXME (autodetect encoding) */
     }
     {
       /* FIXME (autodetect encoding) */
     }
+  return 0;
 }
 
 
 /* Called by libassuan for OUTPUT commands. */
 }
 
 
 /* Called by libassuan for OUTPUT commands. */
-static void
-output_notify (assuan_context_t ctx, const char *line)
+static gpg_error_t
+output_notify (assuan_context_t ctx, char *line)
 {
 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
 {
 /*   ctrl_t ctrl = assuan_get_pointer (ctx); */
-  
+
   (void)ctx;
 
   if (strstr (line, "--armor"))
   (void)ctx;
 
   if (strstr (line, "--armor"))
@@ -193,6 +203,7 @@ output_notify (assuan_context_t ctx, const char *line)
     {
       /* FIXME */
     }
     {
       /* FIXME */
     }
+  return 0;
 }
 
 
 }
 
 
@@ -226,9 +237,9 @@ cmd_recipient (assuan_context_t ctx, char *line)
     remusr = rcpts;
   */
 
     remusr = rcpts;
   */
 
-  err = find_and_check_key (line, PUBKEY_USAGE_ENC, hidden, 
+  err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
                             &ctrl->server_local->recplist);
                             &ctrl->server_local->recplist);
-  
+
   if (err)
     log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
   return err;
   if (err)
     log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
   return err;
@@ -261,7 +272,7 @@ cmd_signer (assuan_context_t ctx, char *line)
 
 
 \f
 
 
 \f
-/*  ENCRYPT 
+/*  ENCRYPT
 
    Do the actual encryption process.  Takes the plaintext from the
    INPUT command, writes the ciphertext to the file descriptor set
 
    Do the actual encryption process.  Takes the plaintext from the
    INPUT command, writes the ciphertext to the file descriptor set
@@ -289,7 +300,7 @@ cmd_encrypt (assuan_context_t ctx, char *line)
 
   (void)line; /* LINE is not used.  */
 
 
   (void)line; /* LINE is not used.  */
 
-  if ( !ctrl->server_local->recplist ) 
+  if ( !ctrl->server_local->recplist )
     {
       write_status_text (STATUS_NO_RECP, "0");
       err = gpg_error (GPG_ERR_NO_USER_ID);
     {
       write_status_text (STATUS_NO_RECP, "0");
       err = gpg_error (GPG_ERR_NO_USER_ID);
@@ -313,13 +324,13 @@ cmd_encrypt (assuan_context_t ctx, char *line)
      PGP-2 mode.  Do all the other checks we do in gpg.c for aEncr.
      Maybe we should drop the PGP2 compatibility. */
 
      PGP-2 mode.  Do all the other checks we do in gpg.c for aEncr.
      Maybe we should drop the PGP2 compatibility. */
 
-  
+
   /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
      from the default list. */
 
   /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
   /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
      from the default list. */
 
   /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
-    
-  err = encrypt_crypt (inp_fd, NULL, NULL, 0,
+
+  err = encrypt_crypt (ctrl, inp_fd, NULL, NULL, 0,
                        ctrl->server_local->recplist,
                        out_fd);
 
                        ctrl->server_local->recplist,
                        out_fd);
 
@@ -345,14 +356,36 @@ cmd_encrypt (assuan_context_t ctx, char *line)
 \f
 /*  DECRYPT
 
 \f
 /*  DECRYPT
 
-   This performs the decrypt operation after doing some checks on the
-   internal state (e.g. that only needed data has been set).   */
+    This performs the decrypt operation.  */
 static gpg_error_t
 cmd_decrypt (assuan_context_t ctx, char *line)
 {
 static gpg_error_t
 cmd_decrypt (assuan_context_t ctx, char *line)
 {
-  (void)ctx;
-  (void)line;
-  return gpg_error (GPG_ERR_NOT_SUPPORTED);
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  int inp_fd, out_fd;
+
+  (void)line; /* LINE is not used.  */
+
+  inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
+  if (inp_fd == -1)
+    return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
+  out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
+  if (out_fd == -1)
+    return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
+
+  glo_ctrl.lasterr = 0;
+  err = decrypt_message_fd (ctrl, inp_fd, out_fd);
+  if (!err)
+    err = glo_ctrl.lasterr;
+
+  /* Close and reset the fds. */
+  close_message_fd (ctrl);
+  assuan_close_input_fd (ctx);
+  assuan_close_output_fd (ctx);
+
+  if (err)
+    log_error ("command '%s' failed: %s\n", "DECRYPT", gpg_strerror (err));
+  return err;
 }
 
 
 }
 
 
@@ -362,7 +395,7 @@ cmd_decrypt (assuan_context_t ctx, char *line)
    This does a verify operation on the message send to the input-FD.
    The result is written out using status lines.  If an output FD was
    given, the signed text will be written to that.
    This does a verify operation on the message send to the input-FD.
    The result is written out using status lines.  If an output FD was
    given, the signed text will be written to that.
-  
+
    If the signature is a detached one, the server will inquire about
    the signed material and the client must provide it.
  */
    If the signature is a detached one, the server will inquire about
    the signed material and the client must provide it.
  */
@@ -373,11 +406,11 @@ cmd_verify (assuan_context_t ctx, char *line)
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gnupg_fd_t fd = assuan_get_input_fd (ctx);
   gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
   ctrl_t ctrl = assuan_get_pointer (ctx);
   gnupg_fd_t fd = assuan_get_input_fd (ctx);
   gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
-  FILE *out_fp = NULL;
+  estream_t out_fp = NULL;
 
   /* FIXME: Revamp this code it is nearly to 3 years old and was only
      intended as a quick test.  */
 
   /* FIXME: Revamp this code it is nearly to 3 years old and was only
      intended as a quick test.  */
-  
+
   (void)line;
 
   if (fd == GNUPG_INVALID_FD)
   (void)line;
 
   if (fd == GNUPG_INVALID_FD)
@@ -385,27 +418,23 @@ cmd_verify (assuan_context_t ctx, char *line)
 
   if (out_fd != GNUPG_INVALID_FD)
     {
 
   if (out_fd != GNUPG_INVALID_FD)
     {
-      out_fp = fdopen ( dup (FD2INT (out_fd)), "w");
+      out_fp = es_fdopen_nc (out_fd, "w");
       if (!out_fp)
       if (!out_fp)
-        return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
+        return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     }
 
   log_debug ("WARNING: The server mode is WORK "
              "iN PROGRESS and not ready for use\n");
 
     }
 
   log_debug ("WARNING: The server mode is WORK "
              "iN PROGRESS and not ready for use\n");
 
-  /* Need to dup it because it might get closed and libassuan won't
-     know about it then. */
-  rc = gpg_verify (ctrl,
-                   dup ( FD2INT (fd)), 
-                   dup ( FD2INT (ctrl->server_local->message_fd)),
-                   out_fp);
+  rc = gpg_verify (ctrl, fd, ctrl->server_local->message_fd, out_fp);
 
 
-  if (out_fp)
-    fclose (out_fp);
+  es_fclose (out_fp);
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
 
+  if (rc)
+    log_error ("command '%s' failed: %s\n", "VERIFY", gpg_strerror (rc));
   return rc;
 }
 
   return rc;
 }
 
@@ -572,16 +601,36 @@ cmd_getinfo (assuan_context_t ctx, char *line)
   return rc;
 }
 
   return rc;
 }
 
+static const char hlp_passwd[] =
+  "PASSWD <userID>\n"
+  "\n"
+  "Change the passphrase of the secret key for USERID.";
+static gpg_error_t
+cmd_passwd (assuan_context_t ctx, char *line)
+{
+  /* ctrl_t ctrl = assuan_get_pointer (ctx); */
+  gpg_error_t err;
+
+  (void)ctx;
+  line = skip_options (line);
+
+  err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+  return err;
+}
+
+
 
 \f
 /* Helper to register our commands with libassuan. */
 static int
 register_commands (assuan_context_t ctx)
 {
 
 \f
 /* Helper to register our commands with libassuan. */
 static int
 register_commands (assuan_context_t ctx)
 {
-  static struct 
+  static struct
   {
     const char *name;
   {
     const char *name;
-    gpg_error_t (*handler)(assuan_context_t, char *line);
+    assuan_handler_t handler;
+    const char * const help;
   } table[] = {
     { "RECIPIENT",     cmd_recipient },
     { "SIGNER",        cmd_signer    },
   } table[] = {
     { "RECIPIENT",     cmd_recipient },
     { "SIGNER",        cmd_signer    },
@@ -591,24 +640,26 @@ register_commands (assuan_context_t ctx)
     { "SIGN",          cmd_sign      },
     { "IMPORT",        cmd_import    },
     { "EXPORT",        cmd_export    },
     { "SIGN",          cmd_sign      },
     { "IMPORT",        cmd_import    },
     { "EXPORT",        cmd_export    },
-    { "INPUT",         NULL          }, 
-    { "OUTPUT",        NULL          }, 
+    { "INPUT",         NULL          },
+    { "OUTPUT",        NULL          },
     { "MESSAGE",       cmd_message   },
     { "LISTKEYS",      cmd_listkeys  },
     { "LISTSECRETKEYS",cmd_listsecretkeys },
     { "GENKEY",        cmd_genkey    },
     { "DELKEYS",       cmd_delkeys   },
     { "GETINFO",       cmd_getinfo   },
     { "MESSAGE",       cmd_message   },
     { "LISTKEYS",      cmd_listkeys  },
     { "LISTSECRETKEYS",cmd_listsecretkeys },
     { "GENKEY",        cmd_genkey    },
     { "DELKEYS",       cmd_delkeys   },
     { "GETINFO",       cmd_getinfo   },
+    { "PASSWD",        cmd_passwd,  hlp_passwd},
     { NULL }
   };
   int i, rc;
 
   for (i=0; table[i].name; i++)
     {
     { NULL }
   };
   int i, rc;
 
   for (i=0; table[i].name; i++)
     {
-      rc = assuan_register_command (ctx, table[i].name, table[i].handler);
+      rc = assuan_register_command (ctx, table[i].name,
+                                    table[i].handler, table[i].help);
       if (rc)
         return rc;
       if (rc)
         return rc;
-    } 
+    }
   return 0;
 }
 
   return 0;
 }
 
@@ -629,8 +680,8 @@ gpg_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 FILEDES in this case.  */
   /* 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 FILEDES in this case.  */
-  filedes[0] = 0;
-  filedes[1] = 1;
+  filedes[0] = assuan_fdopen (0);
+  filedes[1] = assuan_fdopen (1);
   rc = assuan_new (&ctx);
   if (rc)
     {
   rc = assuan_new (&ctx);
   if (rc)
     {
@@ -638,7 +689,7 @@ gpg_server (ctrl_t ctrl)
                 gpg_strerror (rc));
       goto leave;
     }
                 gpg_strerror (rc));
       goto leave;
     }
-  
+
   rc = assuan_init_pipe_server (ctx, filedes);
   if (rc)
     {
   rc = assuan_init_pipe_server (ctx, filedes);
   if (rc)
     {
@@ -658,7 +709,7 @@ gpg_server (ctrl_t ctrl)
   if (opt.verbose || opt.debug)
     {
       char *tmp = NULL;
   if (opt.verbose || opt.debug)
     {
       char *tmp = NULL;
-      const char *s1 = getenv ("GPG_AGENT_INFO");
+      const char *s1 = getenv (GPG_AGENT_INFO_NAME);
 
       tmp = xtryasprintf ("Home: %s\n"
                           "Config: %s\n"
 
       tmp = xtryasprintf ("Home: %s\n"
                           "Config: %s\n"
@@ -690,9 +741,6 @@ gpg_server (ctrl_t ctrl)
   ctrl->server_local->assuan_ctx = ctx;
   ctrl->server_local->message_fd = GNUPG_INVALID_FD;
 
   ctrl->server_local->assuan_ctx = ctx;
   ctrl->server_local->message_fd = GNUPG_INVALID_FD;
 
-  if (DBG_ASSUAN)
-    assuan_set_log_stream (ctx, log_get_stream ());
-
   for (;;)
     {
       rc = assuan_accept (ctx);
   for (;;)
     {
       rc = assuan_accept (ctx);
@@ -706,7 +754,7 @@ gpg_server (ctrl_t ctrl)
           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
           break;
         }
           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
           break;
         }
-      
+
       rc = assuan_process (ctx);
       if (rc)
         {
       rc = assuan_process (ctx);
       if (rc)
         {
@@ -727,3 +775,28 @@ gpg_server (ctrl_t ctrl)
   return rc;
 }
 
   return rc;
 }
 
+
+/* Helper to notify the client about Pinentry events.  Because that
+   might disturb some older clients, this is only done when enabled
+   via an option.  If it is not enabled we tell Windows to allow
+   setting the foreground window right here.  Returns an gpg error
+   code. */
+gpg_error_t
+gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
+{
+  if (!ctrl || !ctrl->server_local
+      || !ctrl->server_local->allow_pinentry_notify)
+    {
+      gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
+      /* Client might be interested in that event - send as status line.  */
+      if (!strncmp (line, "PINENTRY_LAUNCHED", 17)
+          && (line[17]==' '||!line[17]))
+        {
+          for (line += 17; *line && spacep (line); line++)
+            ;
+          write_status_text (STATUS_PINENTRY_LAUNCHED, line);
+        }
+      return 0;
+    }
+  return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
+}