Implemented server main loop and started with import command.
authorWerner Koch <wk@gnupg.org>
Wed, 7 Nov 2001 17:44:22 +0000 (17:44 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 7 Nov 2001 17:44:22 +0000 (17:44 +0000)
sm/Makefile.am
sm/gpgsm.c
sm/gpgsm.h
sm/import.c [new file with mode: 0644]
sm/misc.c [new file with mode: 0644]
sm/mkerrors [new file with mode: 0755]
sm/server.c
sm/util.h

index 82a5e48..47de0a8 100644 (file)
@@ -22,12 +22,17 @@ bin_PROGRAMS = gpgsm
 
 INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
 LDFLAGS = @LDFLAGS@ $(LIBGCRYPT_LIBS)
+BUILT_SOURCES = errors.c
 
 gpgsm_SOURCES = \
        gpgsm.c gpgsm.h \
-       util.h \
-       server.c 
+       util.h misc.c errors.c \
+       server.c \
+       import.c 
 
-gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a
+gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
+              ../../libksba/src/.libs/libksba.a
 
 
+errors.c : gpgsm.h mkerrors
+       $(srcdir)/mkerrors < $(srcdir)/gpgsm.h > errors.c
index 8b715f4..972ce08 100644 (file)
@@ -477,7 +477,7 @@ main ( int argc, char **argv)
   int orig_argc;
   char **orig_argv;
   const char *fname;
-  char *username;
+  /*  char *username;*/
   int may_coredump;
   STRLIST sl, remusr= NULL, locusr=NULL;
   STRLIST nrings=NULL;
index ac16933..1c66e10 100644 (file)
 
 #include "util.h"
 
+/* Error numbers */
+enum {
+  GPGSM_EOF = -1,
+  GPGSM_No_Error = 0,
+  GPGSM_General_Error = 1, 
+  GPGSM_Out_Of_Core = 2,
+  GPGSM_Invalid_Value = 3,
+  GPGSM_IO_Error = 4,
+
+
+};
+
+
 /* A large struct name "opt" to keep global flags */
 struct {
   unsigned int debug; /* debug flags (DBG_foo_VALUE) */
@@ -83,4 +96,7 @@ void gpgsm_exit (int rc);
 void gpgsm_server (void);
 
 
+/*-- import.c --*/
+int gpgsm_import (int in_fd);
+
 #endif /*GPGSM_H*/
diff --git a/sm/import.c b/sm/import.c
new file mode 100644 (file)
index 0000000..b3827e2
--- /dev/null
@@ -0,0 +1,213 @@
+/* import.c - Import certificates
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h> 
+#include <time.h>
+#include <assert.h>
+
+#include <ksba.h>
+
+#include "gpgsm.h"
+
+struct reader_cb_parm_s {
+  FILE *fp;
+};
+
+
+static int
+reader_cb (void *cb_value, unsigned char *buffer, size_t count, size_t *nread)
+{
+  struct reader_cb_parm_s *parm = cb_value;
+  size_t n;
+  int c = 0;
+
+  *nread = 0;
+  if (!buffer)
+    return -1; /* not supported */
+
+  for (n=0; n < count; n++)
+    {
+      c = getc (parm->fp);
+      if (c == EOF)
+        {
+          if ( ferror (parm->fp) )
+            return -1;
+          if (n)
+            break; /* return what we have beofre an EOF */
+          return -1;
+        }
+      *buffer++ = c;
+    }
+
+  *nread = n;
+  return 0;
+}
+
+
+static void
+print_integer (unsigned char *p)
+{
+  unsigned long len;
+
+  if (!p)
+    fputs ("none", stdout);
+  else
+    {
+      len = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+      for (p+=4; len; len--, p++)
+        printf ("%02X", *p);
+    }
+}
+
+static void
+print_time (time_t t)
+{
+
+  if (!t)
+    fputs ("none", stdout);
+  else if ( t == (time_t)(-1) )
+    fputs ("error", stdout);
+  else
+    {
+      struct tm *tp;
+
+      tp = gmtime (&t);
+      printf ("%04d-%02d-%02d %02d:%02d:%02d",
+              1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+              tp->tm_hour, tp->tm_min, tp->tm_sec);
+      assert (!tp->tm_isdst);
+    }
+}
+
+static void
+print_dn (char *p)
+{
+
+  if (!p)
+    fputs ("error", stdout);
+  else
+    printf ("`%s'", p);
+}
+
+
+
+\f
+int
+gpgsm_import (int in_fd)
+{
+  int rc;
+  KsbaReader reader = NULL;
+  KsbaCert cert = NULL;
+  struct reader_cb_parm_s rparm;
+
+  memset (&rparm, 0, sizeof rparm);
+
+  rparm.fp = fdopen ( dup (in_fd), "rb");
+  if (!rparm.fp)
+    {
+      log_error ("fdopen() failed: %s\n", strerror (errno));
+      rc = seterr (IO_Error);
+      goto leave;
+    }
+
+  /* setup a skaba reader which uses a callback function so that we can 
+     strip off a base64 encoding when necessary */
+  reader = ksba_reader_new ();
+  if (!reader)
+    {
+      rc = seterr (Out_Of_Core);
+      goto leave;
+    }
+
+  rc = ksba_reader_set_cb (reader, reader_cb, &rparm );
+  if (rc)
+    {
+      ksba_reader_release (reader);
+      rc = map_ksba_err (rc);
+      goto leave;
+    }
+
+  cert = ksba_cert_new ();
+  if (!cert)
+    {
+      rc = seterr (Out_Of_Core);
+      goto leave;
+    }
+
+  rc = ksba_cert_read_der (cert, reader);
+  if (rc)
+    {
+      rc = map_ksba_err (rc);
+      goto leave;
+    }
+
+  {
+    unsigned char *p;
+    char *dn;
+    time_t t;
+    
+    p = ksba_cert_get_serial (cert);
+    fputs ("serial: ", stdout);
+    print_integer (p);
+    ksba_free (p);
+    putchar ('\n');
+
+    t = ksba_cert_get_validity (cert, 0);
+    fputs ("notBefore: ", stdout);
+    print_time (t);
+    putchar ('\n');
+    t = ksba_cert_get_validity (cert, 1);
+    fputs ("notAfter: ", stdout);
+    print_time (t);
+    putchar ('\n');
+    
+    dn = ksba_cert_get_issuer (cert);
+    fputs ("issuer: ", stdout);
+    print_dn (dn);
+    ksba_free (dn);
+    putchar ('\n');
+    
+    dn = ksba_cert_get_subject (cert);
+    fputs ("subject: ", stdout);
+    print_dn (dn);
+    ksba_free (dn);
+    putchar ('\n');
+
+    printf ("hash algo: %d\n", ksba_cert_get_digest_algo (cert));
+    
+    ksba_cert_hash (cert, NULL, NULL);
+  }
+
+ leave:
+  ksba_cert_release (cert);
+  ksba_reader_release (reader);
+  if (rparm.fp)
+    fclose (rparm.fp);
+  return rc;
+}
+
+
+
+
diff --git a/sm/misc.c b/sm/misc.c
new file mode 100644 (file)
index 0000000..c1bc346
--- /dev/null
+++ b/sm/misc.c
@@ -0,0 +1,41 @@
+/* misc.c - Miscellaneous fucntions
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <ksba.h>
+
+#include "util.h"
+
+
+/* Note: we might want to wrap this in a macro to get our hands on
+   the line and file wehre the error occired */
+int
+map_ksba_err (int err)
+{
+  return -1;
+}
+
diff --git a/sm/mkerrors b/sm/mkerrors
new file mode 100755 (executable)
index 0000000..46c28e8
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/sh
+# mkerrors - Extract error strings from gpgsm.h
+#            and create C source for gpgsm_strerror
+#      Copyright (C) 2001 Free Software Foundation, Inc.
+#
+# This file is part of GnuPG.
+#
+# GnuPG is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# GnuPG is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+cat <<EOF
+/* Generated automatically by mkerrors */
+/* Do not edit! */
+
+#include <config.h>
+#include <stdio.h>
+#include "gpgsm.h"
+
+/**
+ * gpgsm_strerror:
+ * @err:  Error code 
+ * 
+ * This function returns a textual representaion of the given
+ * errorcode. If this is an unknown value, a string with the value
+ * is returned (Beware: it is hold in a static buffer).
+ * 
+ * Return value: String with the error description.
+ **/
+const char *
+gpgsm_strerror (int err)
+{
+  const char *s;
+  static char buf[25];
+
+  switch (err)
+    {
+EOF
+
+awk '
+/GPGSM_No_Error/  { okay=1 }
+!okay              {next}
+/}/                { exit 0 }
+/GPGSM_[A-Za-z_]*/ { print_code($1) }
+
+
+function print_code( s )
+{
+printf "    case %s: s=\"", s ;
+gsub(/_/, " ", s );
+printf "%s\"; break;\n", tolower(substr(s,7));
+}
+'
+
+cat <<EOF
+    default:  sprintf (buf, "ec=%d", err ); s=buf; break;
+    }
+
+  return s;
+}
+
+EOF
\ No newline at end of file
index 51e7a39..daea496 100644 (file)
 #include "gpgsm.h"
 #include "../assuan/assuan.h"
 
+#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
 
 
+/*  RECIPIENT <userID>
+
+  Set the recipient for the encryption.  <userID> should be the
+  internal representation of the key; the server may accept any other
+  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
+  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 ENCRYPT command.  */
+static int 
+cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
+{
+  
+
+  return set_error (Not_Implemented, "fixme");
+}
+
+
+/* ENCRYPT [armor]
+
+  Do the actual encryption process. Takes the plaintext from the INPUT
+  command, writes to the ciphertext to the file descriptor set with
+  the OUTPUT command, take the recipients form all the recipients set
+  so far.  If this command fails the clients should try to delete all
+  output currently done or otherwise mark it as invalid.  GPGSM does
+  ensure that there won't be any security problem with leftover data
+  on the output in this case.
+
+  This command should in general not fail, as all necessary checks
+  have been done while setting the recipients.  The input and output
+  pipes are closed.
+
+  The optional armor parameter may be used to request base64 encoded
+  output.  */
+static int 
+cmd_encrypt (ASSUAN_CONTEXT ctx, char *line)
+{
+  
+
+  return set_error (Not_Implemented, "fixme");
+}
+
+/* DECRYPT
+
+  This performs the decrypt operation after doing some check on the
+  internal state. (e.g. that only needed data has been set).  Because
+  it utilises the GPG-Agent for the session key decryption, there is
+  no need to ask the client for a protecting passphrase - GpgAgent
+  does take care of this but requesting this from the user. */
+static int 
+cmd_decrypt (ASSUAN_CONTEXT ctx, char *line)
+{
+  
+
+  return set_error (Not_Implemented, "fixme");
+}
+
+
+/* VERIFY
+
+  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.
+
+  The behavior for detached signatures has not yet been specified.  */
+static int 
+cmd_verify (ASSUAN_CONTEXT ctx, char *line)
+{
+  
+
+  return set_error (Not_Implemented, "fixme");
+}
+
+
+/* SIGN
+
+   FIXME */
+static int 
+cmd_sign (ASSUAN_CONTEXT ctx, char *line)
+{
+  
+
+  return set_error (Not_Implemented, "fixme");
+}
+
+
+/* IMPORT
+
+  Import the certificates read form the input-fd, return status
+  message for each imported one.  The import checks the validity of
+  the certificate but not of the path.  It is possible to import
+  expired certificates.  */
+static int 
+cmd_import (ASSUAN_CONTEXT ctx, char *line)
+{
+  int fd = assuan_get_input_fd (ctx);
+
+  if (fd == -1)
+    return set_error (No_Input, NULL);
+
+  gpgsm_import (fd);
+
+  return 0;
+}
+
+
+
+\f
+/* Tell the assuan library about our commands */
+static int
+register_commands (ASSUAN_CONTEXT ctx)
+{
+  static struct {
+    const char *name;
+    int cmd_id;
+    int (*handler)(ASSUAN_CONTEXT, char *line);
+  } table[] = {
+    { "RECIPIENT",  0,  cmd_recipient },
+    { "ENCRYPT",    0,  cmd_encrypt },
+    { "DECRYPT",    0,  cmd_decrypt },
+    { "VERIFY",     0,  cmd_verify },
+    { "SIGN",       0,  cmd_sign },
+    { "IMPORT",     0,  cmd_import },
+    { "",     ASSUAN_CMD_INPUT, NULL }, 
+    { "",     ASSUAN_CMD_OUTPUT, NULL }, 
+    { NULL }
+  };
+  int i, j, rc;
+
+  for (i=j=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);
+      if (rc)
+        return rc;
+    } 
+  return 0;
+}
+
+/* Startup the server */
 void
 gpgsm_server (void)
 {
@@ -50,7 +195,44 @@ gpgsm_server (void)
                  assuan_strerror(rc));
       gpgsm_exit (2);
     }
+  rc = register_commands (ctx);
+  if (rc)
+    {
+      log_error ("failed to the register commands with Assuan: %s\n",
+                 assuan_strerror(rc));
+      gpgsm_exit (2);
+    }
+
+  log_info ("Assuan started\n");
+  for (;;)
+    {
+      rc = assuan_accept (ctx);
+      if (rc == -1)
+        {
+          log_info ("Assuan terminated\n");
+          break;
+        }
+      else if (rc)
+        {
+          log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
+          break;
+        }
+      
+      rc = assuan_process (ctx);
+      if (rc)
+        {
+          log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
+          continue;
+        }
+    }
 
 
   assuan_deinit_pipe_server (ctx);
 }
+
+
+
+
+
+
+
index d2ac4c1..f3b4ab7 100644 (file)
--- a/sm/util.h
+++ b/sm/util.h
@@ -42,5 +42,9 @@
 #define xstrdup(a)       gcry_xstrdup ((a))
 
 
+#define seterr(a)  (GPGSM_ ## a)
+
+/*-- misc.c --*/
+int map_ksba_err (int err);
 
 #endif /*UTIL_H*/