Browse Source

2006-11-21 Marcus Brinkmann <marcus@g10code.de>

	* src/cert-gpgsm.c (cert_reset): Free CERT->cert_der if set.
	(export_cert): Reimplement using data channel.
	(export_cert_compat): This contains the old version for
	compatibility.
	* src/cert.h (MAX_CERT_SIZE): Macro removed.
	(struct cert): Changed member CERT_DER into a pointer.
Marcus Brinkmann 19 years ago
parent
commit
1b41c0f314
3 changed files with 110 additions and 9 deletions
  1. 7 0
      ChangeLog
  2. 102 7
      src/cert-gpgsm.c
  3. 1 2
      src/cert.h

+ 7 - 0
ChangeLog

@@ -1,5 +1,12 @@
 2006-11-21  Marcus Brinkmann  <marcus@g10code.de>
 2006-11-21  Marcus Brinkmann  <marcus@g10code.de>
 
 
+	* src/cert-gpgsm.c (cert_reset): Free CERT->cert_der if set.
+	(export_cert): Reimplement using data channel.
+	(export_cert_compat): This contains the old version for
+	compatibility.
+	* src/cert.h (MAX_CERT_SIZE): Macro removed.
+	(struct cert): Changed member CERT_DER into a pointer.
+
 	* configure.ac (AC_CONFIG_FILES): Add doc/manual/Makefile.
 	* configure.ac (AC_CONFIG_FILES): Add doc/manual/Makefile.
 	* doc/Makefile.am (SUBDIRS): New variable.
 	* doc/Makefile.am (SUBDIRS): New variable.
 	* doc/manual/Makefile, doc/manual/scute.texi, doc/manual/gpl.texi,
 	* doc/manual/Makefile, doc/manual/scute.texi, doc/manual/gpl.texi,

+ 102 - 7
src/cert-gpgsm.c

@@ -34,7 +34,6 @@
 #include <config.h>
 #include <config.h>
 #endif
 #endif
 
 
-#include <errno.h>
 #include <time.h>
 #include <time.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -80,6 +79,8 @@ cert_reset (struct cert *cert)
     free (cert->issuer_name);
     free (cert->issuer_name);
   if (cert->uid)
   if (cert->uid)
     free (cert->uid);
     free (cert->uid);
+  if (cert->cert_der)
+    free (cert->cert_der);
 
 
   memset (cert, '\0', sizeof (struct cert));
   memset (cert, '\0', sizeof (struct cert));
 }
 }
@@ -162,7 +163,7 @@ decode_c_string (const char *src, char **destp, size_t len)
 	 string.  */
 	 string.  */
       dest = malloc (strlen (src) + 1);
       dest = malloc (strlen (src) + 1);
       if (!dest)
       if (!dest)
-	return gpg_error_from_errno (errno);
+	return gpg_error_from_syserror ();
 
 
       *destp = dest;
       *destp = dest;
     }
     }
@@ -351,7 +352,7 @@ search_certs_line (struct search_ctx *ctx)
 	{
 	{
 	  cert->issuer_serial = strdup (field[7]);
 	  cert->issuer_serial = strdup (field[7]);
 	  if (!cert->issuer_serial)
 	  if (!cert->issuer_serial)
-	    return gpg_error_from_errno (errno);
+	    return gpg_error_from_syserror ();
 	}
 	}
 
 
 #if 0
 #if 0
@@ -519,8 +520,10 @@ struct search_ctx_by_field
 };
 };
   
   
 
 
+/* This is a compatibility function for GPGSM 2.0.0, which does not
+   support the --data option with the EXPORT command.  */
 static gpg_error_t
 static gpg_error_t
-export_cert (char *fpr, struct cert *cert)
+export_cert_compat (char *fpr, struct cert *cert)
 {
 {
   gpg_error_t err;
   gpg_error_t err;
   assuan_context_t ctx;
   assuan_context_t ctx;
@@ -531,8 +534,13 @@ export_cert (char *fpr, struct cert *cert)
   int output_fds[2];
   int output_fds[2];
   int child_fds[2];
   int child_fds[2];
 
 
+#define MAX_CERT_SIZE 4096
+  cert->cert_der = malloc (MAX_CERT_SIZE);
+  if (!cert->cert_der)
+    return gpg_error_from_syserror ();
+
   if(pipe (output_fds) < 0)
   if(pipe (output_fds) < 0)
-    return gpg_error_from_errno (errno);
+    return gpg_error_from_syserror ();
 
 
   child_fds[0] = output_fds[1];
   child_fds[0] = output_fds[1];
   child_fds[1] = -1;
   child_fds[1] = -1;
@@ -576,6 +584,95 @@ export_cert (char *fpr, struct cert *cert)
 }
 }
 
 
 
 
+struct export_hook
+{
+  /* The exported data.  */
+  char *buffer;
+
+  /* The length of the exported data buffer.  */
+  unsigned int buffer_len;
+
+  /* The size of the allocated exported data buffer.  */
+  unsigned int buffer_size;
+};
+
+#define EXP_DATA_START 4096
+
+static gpg_error_t
+export_cert_cb (void *hook, char *line, size_t line_len)
+{
+  struct export_hook *exp = hook;
+
+  if (exp->buffer_size - exp->buffer_len < line_len)
+    {
+      unsigned int new_buffer_size = exp->buffer_size * 2;
+      char *new_buffer = realloc (exp->buffer, new_buffer_size);
+
+      if (!new_buffer)
+	return gpg_error_from_syserror ();
+
+      exp->buffer = new_buffer;
+      exp->buffer_size = new_buffer_size;
+    }
+
+  memcpy (exp->buffer + exp->buffer_len, line, line_len);
+
+  return 0;
+}
+
+
+static gpg_error_t
+export_cert (char *fpr, struct cert *cert)
+{
+  gpg_error_t err;
+  assuan_context_t ctx;
+  const char *argv[] = { "gpgsm", "--server", NULL };
+#define COMMANDLINELEN 80
+  char cmd[COMMANDLINELEN];
+  int output_fds[2];
+  int child_fds[2];
+  struct export_hook exp;
+
+  if(pipe (output_fds) < 0)
+    return gpg_error_from_syserror ();
+
+  child_fds[0] = output_fds[1];
+  child_fds[1] = -1;
+
+  err = assuan_pipe_connect (&ctx, GPGSM_PATH, argv, child_fds);
+  close (output_fds[1]);
+  if (err)
+    {
+      close (output_fds[0]);
+      return err;
+    }
+
+  exp.buffer = NULL;
+  exp.buffer_len = 0;
+  exp.buffer_size = 0;
+
+  snprintf (cmd, sizeof (cmd), "EXPORT --data -- %s\n", cert->fpr);
+  err = assuan_transact (ctx, cmd, export_cert_cb, &exp,
+			 NULL, NULL, NULL, NULL);
+  assuan_disconnect (ctx);
+  close (output_fds[0]);
+
+  /* For compatibility with GPGSM 2.0.0, we fall back to a work around
+     in that case.  */
+  if (gpg_err_code (err) == GPG_ERR_ASS_NO_OUTPUT)
+    {
+      if (cert->cert_der)
+	{
+	  free (cert->cert_der);
+	  cert->cert_der = NULL;
+	}
+      err = export_cert_compat (fpr, cert);
+    }
+
+  return err;
+}
+
+
 static gpg_error_t
 static gpg_error_t
 search_certs_by_field (void *hook, struct cert *cert)
 search_certs_by_field (void *hook, struct cert *cert)
 {
 {
@@ -593,8 +690,6 @@ search_certs_by_field (void *hook, struct cert *cert)
 	return err;
 	return err;
 
 
       err = (*ctx->search_cb) (ctx->search_cb_hook, cert);
       err = (*ctx->search_cb) (ctx->search_cb_hook, cert);
-
-      /* If necessary, release cert->der here.  */
     }
     }
 
 
   return err;
   return err;

+ 1 - 2
src/cert.h

@@ -85,8 +85,7 @@ struct cert
   /* The certificate in DER format.  This is not entered by the search
   /* The certificate in DER format.  This is not entered by the search
      function, but afterwards by the filter before converting it into
      function, but afterwards by the filter before converting it into
      a PKCS #11 object.  */
      a PKCS #11 object.  */
-#define MAX_CERT_SIZE 4096
-  unsigned char cert_der[MAX_CERT_SIZE];
+  unsigned char *cert_der;
   int cert_der_len;
   int cert_der_len;
 };
 };