* certcheck.c: Fixed use of DBG_CRYPTO and DBG_X509.
[gnupg.git] / sm / server.c
index 8d73a10..7bfd3fc 100644 (file)
@@ -1,5 +1,5 @@
 /* server.c - Server mode and main entry point 
- *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -27,8 +27,9 @@
 #include <ctype.h>
 #include <unistd.h>
 
+#include <assuan.h>
+
 #include "gpgsm.h"
-#include "../assuan/assuan.h"
 
 #define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
 
@@ -38,17 +39,18 @@ static FILE *statusfp;
 
 /* Data used to assuciate an Assuan context with local server data */
 struct server_local_s {
-  ASSUAN_CONTEXT assuan_ctx;
+  assuan_context_t assuan_ctx;
   int message_fd;
   int list_internal;
   int list_external;
-  CERTLIST recplist;
-  CERTLIST signerlist;
+  certlist_t recplist;
+  certlist_t signerlist;
+  certlist_t default_recplist; /* As set by main() - don't release. */
 };
 
 
 
-/* note, that it is sufficient to allocate the target string D as
+/* Note that it is sufficient to allocate the target string D as
    long as the source string S, i.e.: strlen(s)+1; */
 static void
 strcpy_escaped_plus (char *d, const unsigned char *s)
@@ -168,6 +170,11 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
       else
         return ASSUAN_Parameter_Error;
     }
+  else if (!strcmp (key, "with-validation"))
+    {
+      int i = *value? atoi (value) : 0;
+      ctrl->with_validation = i;
+    }
   else
     return ASSUAN_Invalid_Option;
 
@@ -232,7 +239,7 @@ output_notify (ASSUAN_CONTEXT ctx, const char *line)
   way of specification [we will support this].  If this is a valid and
   trusted recipient the server does respond with OK, otherwise the
   return is an ERR with the reason why the recipient can't be used,
-  the encryption will then not be done for this recipient.  IF the
+  the encryption will then not be done for this recipient.  If the
   policy is not to encrypt at all if not all recipients are valid, the
   client has to take care of this.  All RECIPIENT commands are
   cumulative until a RESET or an successful ENCRYPT command.  */
@@ -242,20 +249,23 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
   CTRL ctrl = assuan_get_pointer (ctx);
   int rc;
 
-  rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist);
+  rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist, 0);
   if (rc)
-    gpgsm_status2 (ctrl, STATUS_INV_RECP,
-                   rc == -1? "1":
-                   rc == GNUPG_No_Public_Key?       "1":
-                   rc == GNUPG_Ambiguous_Name?      "2":
-                   rc == GNUPG_Wrong_Key_Usage?     "3":
-                   rc == GNUPG_Certificate_Revoked? "4":
-                   rc == GNUPG_Certificate_Expired? "5":
-                   rc == GNUPG_No_CRL_Known?        "6":
-                   rc == GNUPG_CRL_Too_Old?         "7":
-                   rc == GNUPG_No_Policy_Match?     "8":
+    {
+      gpg_err_code_t r = gpg_err_code (rc);
+      gpgsm_status2 (ctrl, STATUS_INV_RECP,
+                   r == -1? "1":
+                   r == GPG_ERR_NO_PUBKEY?       "1":
+                   r == GPG_ERR_AMBIGUOUS_NAME?  "2":
+                   r == GPG_ERR_WRONG_KEY_USAGE? "3":
+                   r == GPG_ERR_CERT_REVOKED?    "4":
+                   r == GPG_ERR_CERT_EXPIRED?    "5":
+                   r == GPG_ERR_NO_CRL_KNOWN?    "6":
+                   r == GPG_ERR_CRL_TOO_OLD?     "7":
+                   r == GPG_ERR_NO_POLICY_MATCH? "8":
                    "0",
                    line, NULL);
+    }
 
   return map_to_assuan_status (rc);
 }
@@ -282,22 +292,25 @@ cmd_signer (ASSUAN_CONTEXT ctx, char *line)
   CTRL ctrl = assuan_get_pointer (ctx);
   int rc;
 
-  rc = gpgsm_add_to_certlist (ctrl, line, 1, &ctrl->server_local->signerlist);
+  rc = gpgsm_add_to_certlist (ctrl, line, 1,
+                              &ctrl->server_local->signerlist, 0);
   if (rc)
-    gpgsm_status2 (ctrl, STATUS_INV_RECP,
-                   rc == -1? "1":
-                   rc == GNUPG_No_Public_Key?       "1":
-                   rc == GNUPG_Ambiguous_Name?      "2":
-                   rc == GNUPG_Wrong_Key_Usage?     "3":
-                   rc == GNUPG_Certificate_Revoked? "4":
-                   rc == GNUPG_Certificate_Expired? "5":
-                   rc == GNUPG_No_CRL_Known?        "6":
-                   rc == GNUPG_CRL_Too_Old?         "7":
-                   rc == GNUPG_No_Policy_Match?     "8":
-                   rc == GNUPG_No_Secret_Key?       "9":
+    {
+      gpg_err_code_t r = gpg_err_code (rc);
+      gpgsm_status2 (ctrl, STATUS_INV_RECP,
+                   r == -1?                          "1":
+                   r == GPG_ERR_NO_PUBKEY?           "1":
+                   r == GPG_ERR_AMBIGUOUS_NAME?      "2":
+                   r == GPG_ERR_WRONG_KEY_USAGE?     "3":
+                   r == GPG_ERR_CERT_REVOKED?        "4":
+                   r == GPG_ERR_CERT_EXPIRED?        "5":
+                   r == GPG_ERR_NO_CRL_KNOWN?        "6":
+                   r == GPG_ERR_CRL_TOO_OLD?         "7":
+                   r == GPG_ERR_NO_POLICY_MATCH?     "8":
+                   r == GPG_ERR_NO_SECKEY?           "9":
                    "0",
-                   line, NULL);
-
+                  line, NULL);
+    }
   return map_to_assuan_status (rc);
 }
 
@@ -319,6 +332,7 @@ static int
 cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
 {
   CTRL ctrl = assuan_get_pointer (ctx);
+  certlist_t cl;
   int inp_fd, out_fd;
   FILE *out_fp;
   int rc;
@@ -333,14 +347,26 @@ cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
   out_fp = fdopen ( dup(out_fd), "w");
   if (!out_fp)
     return set_error (General_Error, "fdopen() failed");
-  rc = gpgsm_encrypt (assuan_get_pointer (ctx),
-                      ctrl->server_local->recplist,
-                      inp_fd, out_fp);
+  
+  /* Now add all encrypt-to marked recipients from the default
+     list. */
+  rc = 0;
+  if (!opt.no_encrypt_to)
+    {
+      for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
+        if (cl->is_encrypt_to)
+          rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
+                                           &ctrl->server_local->recplist, 1);
+    }
+  if (!rc)
+    rc = gpgsm_encrypt (assuan_get_pointer (ctx),
+                        ctrl->server_local->recplist,
+                        inp_fd, out_fp);
   fclose (out_fp);
 
   gpgsm_release_certlist (ctrl->server_local->recplist);
   ctrl->server_local->recplist = NULL;
-  /* close and reset the fd */
+  /* Close and reset the fd */
   close_message_fd (ctrl);
   assuan_close_input_fd (ctx);
   assuan_close_output_fd (ctx);
@@ -625,6 +651,7 @@ do_listkeys (ASSUAN_CONTEXT ctx, char *line, int mode)
   char *p;
   STRLIST list, sl;
   unsigned int listmode;
+  gpg_error_t err;
 
   if (!fp)
     return set_error (General_Error, "no data stream");
@@ -658,9 +685,9 @@ do_listkeys (ASSUAN_CONTEXT ctx, char *line, int mode)
     listmode |= (1<<6);
   if (ctrl->server_local->list_external)
     listmode |= (1<<7);
-  gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
+  err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
   free_strlist (list);
-  return 0;
+  return map_to_assuan_status (err);
 }
 
 static int 
@@ -719,48 +746,48 @@ register_commands (ASSUAN_CONTEXT ctx)
 {
   static struct {
     const char *name;
-    int cmd_id;
     int (*handler)(ASSUAN_CONTEXT, char *line);
   } table[] = {
-    { "RECIPIENT",  0,  cmd_recipient },
-    { "SIGNER",     0,  cmd_signer },
-    { "ENCRYPT",    0,  cmd_encrypt },
-    { "DECRYPT",    0,  cmd_decrypt },
-    { "VERIFY",     0,  cmd_verify },
-    { "SIGN",       0,  cmd_sign },
-    { "IMPORT",     0,  cmd_import },
-    { "EXPORT",     0,  cmd_export },
-    { "",     ASSUAN_CMD_INPUT, NULL }, 
-    { "",     ASSUAN_CMD_OUTPUT, NULL }, 
-    { "MESSAGE",    0,  cmd_message },
-    { "LISTKEYS",   0,  cmd_listkeys },
-    { "LISTSECRETKEYS",  0,  cmd_listsecretkeys },
-    { "GENKEY",     0,  cmd_genkey },
-    { "DELKEYS",    0,  cmd_delkeys },
+    { "RECIPIENT",     cmd_recipient },
+    { "SIGNER",        cmd_signer },
+    { "ENCRYPT",       cmd_encrypt },
+    { "DECRYPT",       cmd_decrypt },
+    { "VERIFY",        cmd_verify },
+    { "SIGN",          cmd_sign },
+    { "IMPORT",        cmd_import },
+    { "EXPORT",        cmd_export },
+    { "INPUT",         NULL }, 
+    { "OUTPUT",        NULL }, 
+    { "MESSAGE",       cmd_message },
+    { "LISTKEYS",      cmd_listkeys },
+    { "LISTSECRETKEYS",cmd_listsecretkeys },
+    { "GENKEY",        cmd_genkey },
+    { "DELKEYS",       cmd_delkeys },
     { NULL }
   };
-  int i, j, rc;
+  int i, rc;
 
-  for (i=j=0; table[i].name; i++)
+  for (i=0; table[i].name; i++)
     {
-      rc = assuan_register_command (ctx,
-                                    table[i].cmd_id? table[i].cmd_id
-                                                   : (ASSUAN_CMD_USER + j++),
-                                    table[i].name, table[i].handler);
+      rc = assuan_register_command (ctx, table[i].name, table[i].handler);
       if (rc)
         return rc;
     } 
   return 0;
 }
 
-/* Startup the server */
+/* Startup the server. DEFAULT_RECPLIST is the list of recipients as
+   set from the command line or config file.  We only require those
+   marked as encrypt-to. */
 void
-gpgsm_server (void)
+gpgsm_server (certlist_t default_recplist)
 {
   int rc;
   int filedes[2];
   ASSUAN_CONTEXT ctx;
   struct server_control_s ctrl;
+  static const char hello[] = ("GNU Privacy Guard's S/M server "
+                               VERSION " ready");
 
   memset (&ctrl, 0, sizeof ctrl);
   gpgsm_init_default_ctrl (&ctrl);
@@ -784,7 +811,30 @@ gpgsm_server (void)
                  assuan_strerror(rc));
       gpgsm_exit (2);
     }
-  assuan_set_hello_line (ctx, "GNU Privacy Guard's S/M server ready");
+  if (opt.verbose || opt.debug)
+    {
+      char *tmp = NULL;
+      const char *s1 = getenv ("GPG_AGENT_INFO");
+      const char *s2 = getenv ("DIRMNGR_INFO");
+
+      if (asprintf (&tmp,
+                    "Home: %s\n"
+                    "Config: %s\n"
+                    "AgentInfo: %s\n"
+                    "DirmngrInfo: %s\n"
+                    "%s",
+                    opt.homedir,
+                    opt.config_filename,
+                    s1?s1:"[not set]",
+                    s2?s2:"[not set]",
+                    hello) > 0)
+        {
+          assuan_set_hello_line (ctx, tmp);
+          free (tmp);
+        }
+    }
+  else
+    assuan_set_hello_line (ctx, hello);
 
   assuan_register_reset_notify (ctx, reset_notify);
   assuan_register_input_notify (ctx, input_notify);
@@ -797,6 +847,7 @@ gpgsm_server (void)
   ctrl.server_local->message_fd = -1;
   ctrl.server_local->list_internal = 1;
   ctrl.server_local->list_external = 0;
+  ctrl.server_local->default_recplist = default_recplist;
 
   if (DBG_ASSUAN)
     assuan_set_log_stream (ctx, log_get_stream ());
@@ -841,6 +892,7 @@ get_status_string ( int no )
     case STATUS_ENTER  : s = "ENTER"; break;
     case STATUS_LEAVE  : s = "LEAVE"; break;
     case STATUS_ABORT  : s = "ABORT"; break;
+    case STATUS_NEWSIG : s = "NEWSIG"; break;
     case STATUS_GOODSIG: s = "GOODSIG"; break;
     case STATUS_SIGEXPIRED: s = "SIGEXPIRED"; break;
     case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
@@ -878,6 +930,7 @@ get_status_string ( int no )
     case STATUS_BADMDC  : s = "BADMDC"; break;
     case STATUS_ERRMDC  : s = "ERRMDC"; break;
     case STATUS_IMPORTED        : s = "IMPORTED"; break;
+    case STATUS_IMPORT_OK        : s = "IMPORT_OK"; break;
     case STATUS_IMPORT_RES      : s = "IMPORT_RES"; break;
     case STATUS_FILE_START      : s = "FILE_START"; break;
     case STATUS_FILE_DONE       : s = "FILE_DONE"; break;
@@ -904,24 +957,26 @@ get_status_string ( int no )
     case STATUS_EXPKEYSIG      : s = "EXPKEYSIG"; break;
     case STATUS_TRUNCATED      : s = "TRUNCATED"; break;
     case STATUS_ERROR          : s = "ERROR"; break;
+    case STATUS_IMPORT_PROBLEM : s = "IMPORT_PROBLEM"; break;
     default: s = "?"; break;
     }
   return s;
 }
 
 
-void
+gpg_error_t
 gpgsm_status2 (CTRL ctrl, int no, ...)
 {
+  gpg_error_t err = 0;
   va_list arg_ptr;
   const char *text;
 
   va_start (arg_ptr, no);
 
-  if (ctrl->no_server)
+  if (ctrl->no_server && ctrl->status_fd == -1)
+    ; /* No status wanted. */
+  else if (ctrl->no_server)
     {
-      if (ctrl->status_fd == -1)
-        return; /* no status wanted */
       if (!statusfp)
         {
           if (ctrl->status_fd == 1)
@@ -976,19 +1031,32 @@ gpgsm_status2 (CTRL ctrl, int no, ...)
             *p++ = *text++;
         }
       *p = 0;
-      assuan_write_status (ctx, get_status_string (no), buf);
+      err = map_assuan_err (assuan_write_status (ctx,
+                                                 get_status_string (no), buf));
     }
 
   va_end (arg_ptr);
+  return err;
 }
 
-void
+gpg_error_t
 gpgsm_status (CTRL ctrl, int no, const char *text)
 {
-  gpgsm_status2 (ctrl, no, text, NULL);
+  return gpgsm_status2 (ctrl, no, text, NULL);
 }
 
+gpg_error_t
+gpgsm_status_with_err_code (CTRL ctrl, int no, const char *text,
+                            gpg_err_code_t ec)
+{
+  char buf[30];
 
+  sprintf (buf, "%u", (unsigned int)ec);
+  if (text)
+    return gpgsm_status2 (ctrl, no, text, buf, NULL);
+  else
+    return gpgsm_status2 (ctrl, no, buf, NULL);
+}
 
 #if 0
 /*