Browse Source

2008-10-01 Marcus Brinkmann <marcus@g10code.com>

	* src/agent.c (agent_connect): Set assuan log stream.
	* src/p11-initialize.c: Include "debug.h".
	(C_Initialize): Call _scute_debug_init.
	* src/Makefile.am (sources): Add debug.c.
	* src/debug.c: New file.
	* src/debug.h: Rewritten.
	* src/agent.c, src/cert-gpgsm.c, src/cert-object.c,
          src/slots.c, src/error-mapping.c: More or improved or
          adjusted debug output.
Marcus Brinkmann 17 năm trước cách đây
mục cha
commit
37d267f741
10 tập tin đã thay đổi với 331 bổ sung61 xóa
  1. 12 0
      ChangeLog
  2. 1 1
      src/Makefile.am
  3. 35 20
      src/agent.c
  4. 4 4
      src/cert-gpgsm.c
  5. 111 28
      src/cert-object.c
  6. 143 0
      src/debug.c
  7. 19 5
      src/debug.h
  8. 1 1
      src/error-mapping.c
  9. 4 1
      src/p11-initialize.c
  10. 1 1
      src/slots.c

+ 12 - 0
ChangeLog

@@ -1,3 +1,15 @@
+2008-10-01  Marcus Brinkmann  <marcus@g10code.com>
+
+	* src/agent.c (agent_connect): Set assuan log stream.
+	* src/p11-initialize.c: Include "debug.h".
+	(C_Initialize): Call _scute_debug_init.
+	* src/Makefile.am (sources): Add debug.c.
+	* src/debug.c: New file.
+	* src/debug.h: Rewritten.
+	* src/agent.c, src/cert-gpgsm.c, src/cert-object.c,
+          src/slots.c, src/error-mapping.c: More or improved or
+          adjusted debug output.
+
 2008-09-30  Marcus Brinkmann  <marcus@g10code.com>
 
 	* src/cert-object.c [!CERT_PARSING]: Disable some certificate

+ 1 - 1
src/Makefile.am

@@ -31,7 +31,7 @@
 
 EXTRA_DIST = libscute.vers scute.def versioninfo.rc.in stpcpy.h
 
-sources = cryptoki.h pkcs11.h debug.h settings.h support.h		\
+sources = cryptoki.h pkcs11.h debug.c debug.h settings.h support.h	\
 	locking.h locking.c error-mapping.h error-mapping.c		\
 	get-path.c agent.h agent.c					\
 	slots.h slots.c table.h table.c					\

+ 35 - 20
src/agent.c

@@ -67,7 +67,7 @@ gnupg_allow_set_foregound_window (pid_t pid)
     return;
 #ifdef HAVE_W32_SYSTEM
   else if (!AllowSetForegroundWindow (pid))
-    DEBUG ("AllowSetForegroundWindow(%lu) failed: %i\n",
+    DEBUG (DBG_CRIT, "AllowSetForegroundWindow(%lu) failed: %i\n",
 	   (unsigned long)pid, GetLastError ());
 #endif
 }
@@ -190,7 +190,7 @@ spawn_process_detached (const char *pgmname, const char *argv[])
               | GetPriorityClass (GetCurrentProcess ())
               | CREATE_NEW_PROCESS_GROUP
               | DETACHED_PROCESS); 
-  DEBUG ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
+  DEBUG (DBG_INFO, "CreateProcess(detached), path=`%s' cmdline=`%s'\n",
 	 pgmname, cmdline);
   if (!CreateProcess (pgmname,       /* Program to start.  */
                       cmdline,       /* Command line arguments.  */
@@ -204,16 +204,16 @@ spawn_process_detached (const char *pgmname, const char *argv[])
                       &pi            /* Returns process information.  */
                       ))
     {
-      DEBUG ("CreateProcess(detached) failed: %i\n", GetLastError ());
+      DEBUG (DBG_CRIT, "CreateProcess(detached) failed: %i\n",
+	     GetLastError ());
       free (cmdline);
       return gpg_error (GPG_ERR_GENERAL);
     }
   free (cmdline);
   cmdline = NULL;
 
-  DEBUG ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
-	 " dwProcessID=%d dwThreadId=%d\n",
-	 pi.hProcess, pi.hThread,
+  DEBUG (DBG_INFO, "CreateProcess(detached) ready: hProcess=%p hThread=%p"
+	 " dwProcessID=%d dwThreadId=%d\n", pi.hProcess, pi.hThread,
 	 (int) pi.dwProcessId, (int) pi.dwThreadId);
 
   CloseHandle (pi.hThread); 
@@ -255,8 +255,9 @@ agent_connect (assuan_context_t *ctx_r)
 	  const char *agent_program;
 
           /* With no success start a new server.  */
-	  DEBUG ("no running GPG agent at %s, starting one\n", sockname);
-          
+	  DEBUG (DBG_INFO, "no running GPG agent at %s, starting one\n",
+		 sockname);
+
           agent_program = get_gpg_agent_path ();
 
 #ifdef HAVE_W32_SYSTEM
@@ -275,7 +276,7 @@ agent_connect (assuan_context_t *ctx_r)
 
             err = spawn_process_detached (agent_program, argv);
             if (err)
-              DEBUG ("failed to start agent `%s': %s\n",
+              DEBUG (DBG_CRIT, "failed to start agent `%s': %s\n",
 		     agent_program, gpg_strerror (err));
             else
               {
@@ -324,7 +325,7 @@ agent_connect (assuan_context_t *ctx_r)
 
       if (!(ptr = strchr (infostr, PATHSEP_C)) || ptr == infostr)
 	{
-	  DEBUG ("malformed GPG_AGENT_INFO environment variable");
+	  DEBUG (DBG_CRIT, "malformed GPG_AGENT_INFO environment variable");
 	  free (infostr);
 	  force_pipe_server = 1;
 	  goto restart;
@@ -337,7 +338,7 @@ agent_connect (assuan_context_t *ctx_r)
       protocol_version = *ptr ? atoi (ptr + 1) : 0;
       if (protocol_version != 1)
 	{
-	  DEBUG ("GPG agent protocol version '%d' not supported",
+	  DEBUG (DBG_CRIT, "GPG agent protocol version '%d' not supported",
 		 protocol_version);
 	  free (infostr);
 	  force_pipe_server = 1;
@@ -348,7 +349,7 @@ agent_connect (assuan_context_t *ctx_r)
       free (infostr);
       if (err)
 	{
-	  DEBUG ("cannot connect to GPG agent: %s", gpg_strerror (err));
+	  DEBUG (DBG_CRIT, "cannot connect to GPG agent: %s", gpg_strerror (err));
 	  force_pipe_server = 1;
 	  goto restart;
 	}
@@ -356,10 +357,13 @@ agent_connect (assuan_context_t *ctx_r)
 
   if (err)
     {
-      DEBUG ("cannot connect to GPG agent: %s", gpg_strerror (err));
+      DEBUG (DBG_CRIT, "cannot connect to GPG agent: %s", gpg_strerror (err));
       return gpg_error (GPG_ERR_NO_AGENT);
     }
 
+  if (_scute_debug_flags & DBG_ASSUAN)
+    assuan_set_log_stream (*ctx_r, _scute_debug_stream);
+
   return 0;
 }
 
@@ -377,13 +381,12 @@ default_inq_cb (void *opaque, const char *line)
       /* We do not pass errors to avoid breaking other code.  */
     }
   else
-    DEBUG ("ignoring gpg-agent inquiry `%s'\n", line);
+    DEBUG (DBG_CRIT, "ignoring gpg-agent inquiry `%s'\n", line);
 
   return 0;
 }
 
 
-
 /* Send a simple command to the agent.  */
 static gpg_error_t 
 agent_simple_cmd (assuan_context_t ctx, const char *fmt, ...)
@@ -403,7 +406,8 @@ agent_simple_cmd (assuan_context_t ctx, const char *fmt, ...)
   err = assuan_transact (ctx, optstr, NULL, NULL, default_inq_cb,
 			 NULL, NULL, NULL);
   if (err)
-    DEBUG ("gpg-agent command '%s' failed: %s", optstr, gpg_strerror (err));
+    DEBUG (DBG_CRIT, "gpg-agent command '%s' failed: %s", optstr,
+	   gpg_strerror (err));
   free (optstr);
       
   return err;
@@ -526,10 +530,11 @@ scute_agent_initialize (void)
 
   if (agent_ctx)
     {
-      DEBUG ("GPG Agent connection already established");
+      DEBUG (DBG_CRIT, "GPG Agent connection already established");
       return 0;
     }
 
+  DEBUG (DBG_INFO, "Establishing connection to gpg-agent");
   err = agent_connect (&agent_ctx);
   if (err)
     return err;
@@ -863,7 +868,10 @@ pksign_cb (void *opaque, const void *buffer, size_t length)
   struct signature *sig = opaque;
 
   if (sig->len + length > MAX_SIGNATURE_LEN)
-    return gpg_error (GPG_ERR_BAD_DATA);
+    {
+      DEBUG (DBG_INFO, "maximum signature length exceeded");
+      return gpg_error (GPG_ERR_BAD_DATA);
+    }
 
   memcpy (&sig->data[sig->len], buffer, length);
   sig->len += length;
@@ -1028,7 +1036,10 @@ scute_agent_get_cert (int no, struct cert *cert)
 			 NULL, NULL, NULL, NULL);
   /* Just to be safe... */
   if (!err && cert_s.cert_der_len <= 16)
-    err = gpg_error (GPG_ERR_BAD_CERT);
+    {
+      DEBUG (DBG_INFO, "bad card certificate rejected");
+      err = gpg_error (GPG_ERR_BAD_CERT);
+    }
   if (err)
     {
       if (cert_s.cert_der)
@@ -1036,6 +1047,9 @@ scute_agent_get_cert (int no, struct cert *cert)
       return err;
     }
 
+  DEBUG (DBG_INFO, "got certificate from card with length %i",
+	 cert_s.cert_der_len);
+
   cert->cert_der = cert_s.cert_der;
   cert->cert_der_len = cert_s.cert_der_len;
 
@@ -1048,10 +1062,11 @@ scute_agent_finalize (void)
 {
   if (!agent_ctx)
     {
-      DEBUG ("no GPG Agent connection established");
+      DEBUG (DBG_CRIT, "no GPG Agent connection established");
       return;
     }
 
+  DEBUG (DBG_INFO, "releasing agent context");
   assuan_disconnect (agent_ctx);
   agent_ctx = NULL;
 }

+ 4 - 4
src/cert-gpgsm.c

@@ -564,7 +564,7 @@ export_cert_compat (char *fpr, struct cert *cert)
   if (err)
     {
       close (output_fds[0]);
-      DEBUG ("failed to spawn %s\n", get_gpgsm_path ());
+      DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
       return err;
     }
 
@@ -653,7 +653,7 @@ export_cert (char *fpr, struct cert *cert)
 				 NULL, NULL, 128);
   if (err)
     {
-      DEBUG ("spawning %s\n", get_gpgsm_path ());
+      DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
       return err;
     }
 
@@ -731,7 +731,7 @@ scute_gpgsm_search_certs_by_grip (const char *grip,
 				 NULL, NULL, 128);
   if (err)
     {
-      DEBUG ("spawning %s\n", get_gpgsm_path ());
+      DEBUG (DBG_CRIT, "spawning %s\n", get_gpgsm_path ());
       return err;
     }
 
@@ -762,7 +762,7 @@ scute_gpgsm_search_certs_by_fpr (const char *fpr,
 				 NULL, NULL, 128);
   if (err)
     {
-      DEBUG ("failed to spawn %s\n", get_gpgsm_path ());
+      DEBUG (DBG_CRIT, "failed to spawn %s\n", get_gpgsm_path ());
       return err;
     }
 

+ 111 - 28
src/cert-object.c

@@ -42,6 +42,7 @@
 #include "cryptoki.h"
 #include "support.h"
 #include "cert.h"
+#include "debug.h"
 
 
 /* Parsing certificates is problematic, as there is no reliable
@@ -85,7 +86,11 @@ time_to_ck_date (time_t *atime, CK_DATE *ckdate)
   if (!(broken_time.tm_year >= 0 && broken_time.tm_year <= 8099
 	&& broken_time.tm_mon >= 0 && broken_time.tm_mon <= 11
 	&& broken_time.tm_mday >= 1 && broken_time.tm_mday <= 31))
-    return false;
+    { 
+      DEBUG (DBG_INFO, "unrepresentable time %i-%i-%i",
+	     broken_time.tm_year, broken_time.tm_mon, broken_time.tm_mday);
+      return false;
+    }
 
 #define LAST_DIGIT(d) (((d) % 10) + '0')
   nr = broken_time.tm_year + 1900;
@@ -120,7 +125,10 @@ asn1_get_len (unsigned char **asn1, int *asn1_len, int *rlen)
   int result = 0;
 
   if (len < 1)
-    return gpg_error (GPG_ERR_GENERAL);
+    {
+      DEBUG (DBG_INFO, "unexpected end of certificate");
+      return gpg_error (GPG_ERR_GENERAL);
+    }
 
   if (*ptr & 0x80)
     {
@@ -132,8 +140,16 @@ asn1_get_len (unsigned char **asn1, int *asn1_len, int *rlen)
     cnt = 1;
 
   /* We only support a limited number of length bytes.  */
-  if (cnt > 2 || len < cnt)
-    return gpg_error (GPG_ERR_GENERAL);
+  if (cnt > 2)
+    {
+      DEBUG (DBG_INFO, "unsupported length field");
+      return gpg_error (GPG_ERR_GENERAL);
+    }
+  if (len < cnt)
+    {
+      DEBUG (DBG_INFO, "unexpected end of certificate");
+      return gpg_error (GPG_ERR_GENERAL);
+    }
 
   while (cnt--)
     {
@@ -175,8 +191,16 @@ asn1_get_element (unsigned char *cert, int cert_len,
   for (i = 0; i < path_size; i++)
     {
       prev_certp = certp;
-      if (cert_left < 1 || *certp != path[i].tag)
-	return gpg_error (GPG_ERR_GENERAL);
+      if (cert_left < 1)
+	{
+	  DEBUG (DBG_INFO, "unexpected end of certificate");
+	  return gpg_error (GPG_ERR_GENERAL);
+	}
+      if (*certp != path[i].tag)
+	{
+	  DEBUG (DBG_INFO, "wrong element in lookup path");
+	  return gpg_error (GPG_ERR_GENERAL);
+	}
       certp++;
       cert_left--;
       err = asn1_get_len (&certp, &cert_left, &len);
@@ -185,7 +209,10 @@ asn1_get_element (unsigned char *cert, int cert_len,
       if (!path[i].enter)
 	{
 	  if (cert_left < len)
-	    return gpg_error (GPG_ERR_GENERAL);
+	    {
+	      DEBUG (DBG_INFO, "unexpected end of certificate");
+	      return gpg_error (GPG_ERR_GENERAL);
+	    }
 	  certp += len;
 	  cert_left -= len;
 	}
@@ -195,8 +222,16 @@ asn1_get_element (unsigned char *cert, int cert_len,
 	     bit string.  */
 	  if (path[i].tag == '\x03')
 	    {
-	      if (cert_left < 1 || *certp != '\x00')
-		return gpg_error (GPG_ERR_GENERAL);
+	      if (cert_left < 1)
+		{
+		  DEBUG (DBG_INFO, "unexpected end of certificate");
+		  return gpg_error (GPG_ERR_GENERAL);
+		}
+	      if (*certp != '\x00')
+		{
+		  DEBUG (DBG_INFO, "expected binary encapsulation missing");
+		  return gpg_error (GPG_ERR_GENERAL);
+		}
 	      certp++;
 	      cert_left--;
 	    }
@@ -280,7 +315,10 @@ asn1_get_modulus (unsigned char *cert, int cert_len,
     return err;
 
   if (*sub_len < 1)
-    return gpg_error (GPG_ERR_GENERAL);
+    {
+      DEBUG (DBG_INFO, "modulus too short");
+      return gpg_error (GPG_ERR_GENERAL);
+    }
 
   (*sub_start)++;
   (*sub_len)--;
@@ -322,7 +360,10 @@ asn1_get_public_exp (unsigned char *cert, int cert_len,
     return err;
 
   if (*sub_len < 1)
-    return gpg_error (GPG_ERR_GENERAL);
+    {
+      DEBUG (DBG_INFO, "public exponent too short");
+      return gpg_error (GPG_ERR_GENERAL);
+    }
 
   (*sub_start)++;
   (*sub_len)--;
@@ -351,7 +392,10 @@ attr_one (CK_ATTRIBUTE_PTR attr, CK_ULONG *attr_count,
   attr[i].ulValueLen = size;
   attr[i].pValue = malloc (size);
   if (attr[i].pValue == NULL)
-    return gpg_error (GPG_ERR_ENOMEM);
+    {
+      DEBUG (DBG_CRIT, "out of memory");
+      return gpg_error (GPG_ERR_ENOMEM);
+    }
   memcpy (attr[i].pValue, val, size);
   (*attr_count)++;
   return 0;
@@ -413,16 +457,31 @@ scute_attr_cert (struct cert *cert,
   /* See below.  */
   err = asn1_get_subject (cert->cert_der, cert->cert_der_len,
 			  &subject_start, &subject_len);
+  if (err)
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get subject: %s",
+	     gpg_strerror (err));
+      return err;
+    }
 #endif
 #if CERT_PARSING
-  if (!err)
-    err = asn1_get_issuer (cert->cert_der, cert->cert_der_len,
-			   &issuer_start, &issuer_len);
-  if (!err)
-    err = asn1_get_serial (cert->cert_der, cert->cert_der_len,
-			   &serial_start, &serial_len);
+  err = asn1_get_issuer (cert->cert_der, cert->cert_der_len,
+			 &issuer_start, &issuer_len);
   if (err)
-    return err;
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get issuer: %s",
+	     gpg_strerror (err));
+      return err;
+    }
+
+  err = asn1_get_serial (cert->cert_der, cert->cert_der_len,
+			 &serial_start, &serial_len);
+  if (err)
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get serial: %s",
+	     gpg_strerror (err));
+      return err;
+    }
 #endif
 
 
@@ -430,7 +489,10 @@ scute_attr_cert (struct cert *cert,
   attr = malloc (sizeof (CK_ATTRIBUTE) * NR_ATTR_CERT);
   attr_count = 0;
   if (!attr)
-    return gpg_error (GPG_ERR_ENOMEM);
+    {
+      DEBUG (DBG_INFO, "out of memory");
+      return gpg_error (GPG_ERR_ENOMEM);
+    }
 
 #define one_attr_ext(type, val, size)					\
   if (!err)								\
@@ -506,6 +568,8 @@ scute_attr_cert (struct cert *cert,
 
   if (err)
     {
+      DEBUG (DBG_INFO, "could not build certificate object: %s",
+	     gpg_strerror (err));
       scute_attr_free (attr, attr_count);
       return err;
     }
@@ -563,21 +627,38 @@ scute_attr_prv (struct cert *cert, CK_ATTRIBUTE_PTR *attrp,
 #if CERT_PARSING
   err = asn1_get_subject (cert->cert_der, cert->cert_der_len,
 			  &subject_start, &subject_len);
-  if (!err)
-    err = asn1_get_modulus (cert->cert_der, cert->cert_der_len,
-			    &modulus_start, &modulus_len);
-  if (!err)
-    err = asn1_get_public_exp (cert->cert_der, cert->cert_der_len,
-			       &public_exp_start, &public_exp_len);
   if (err)
-    return err;
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get subject: %s",
+	     gpg_strerror (err));
+      return err;
+    }
+  err = asn1_get_modulus (cert->cert_der, cert->cert_der_len,
+			  &modulus_start, &modulus_len);
+  if (err)
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get modulus: %s",
+	     gpg_strerror (err));
+      return err;
+    }
+  err = asn1_get_public_exp (cert->cert_der, cert->cert_der_len,
+			     &public_exp_start, &public_exp_len);
+  if (err)
+    {
+      DEBUG (DBG_INFO, "rejecting certificate: could not get public exp: %s",
+	     gpg_strerror (err));
+      return err;
+    }
 #endif
 
 #define NR_ATTR_PRV 27
   attr = malloc (sizeof (CK_ATTRIBUTE) * NR_ATTR_PRV);
   attr_count = 0;
   if (!attr)
-    return gpg_error (GPG_ERR_ENOMEM);
+    {
+      DEBUG (DBG_INFO, "out of core");
+      return gpg_error (GPG_ERR_ENOMEM);
+    }
 
 #undef one_attr_ext
 #define one_attr_ext(type, val, size)					\
@@ -659,6 +740,8 @@ scute_attr_prv (struct cert *cert, CK_ATTRIBUTE_PTR *attrp,
 
   if (err)
     {
+      DEBUG (DBG_INFO, "could not build private certificate object: %s",
+	     gpg_strerror (err));
       scute_attr_free (attr, attr_count);
       return err;
     }

+ 143 - 0
src/debug.c

@@ -0,0 +1,143 @@
+/* debug.c - Cryptoki implementation.
+   Copyright (C) 2008 g10 Code GmbH
+
+   This file is part of Scute.
+ 
+   Scute 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.
+
+   Scute 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 Scute; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+   In addition, as a special exception, g10 Code GmbH gives permission
+   to link this library: with the Mozilla Foundation's code for
+   Mozilla (or with modified versions of it that use the same license
+   as the "Mozilla" code), and distribute the linked executables.  You
+   must obey the GNU General Public License in all respects for all of
+   the code used other than "Mozilla".  If you modify this file, you
+   may extend this exception to your version of the file, but you are
+   not obligated to do so.  If you do not wish to do so, delete this
+   exception statement from your version.  */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <assuan.h>
+#include <gpg-error.h>
+#include <string.h>
+
+#include "debug.h"
+
+
+FILE *_scute_debug_stream;
+
+unsigned int _scute_debug_flags;
+
+
+#ifdef HAVE_W32_SYSTEM
+#define PATHSEP_C ';'
+#else
+#define PATHSEP_C ':'
+#endif
+
+
+/* Remove leading and trailing white spaces.  */
+static char *
+trim_spaces (char *str)
+{
+  char *string, *p, *mark;
+
+  string = str;
+  /* Find first non space character.  */
+  for (p = string; *p && isspace (*(unsigned char *) p); p++)
+    ;
+  /* Move characters.  */
+  for (mark = NULL; (*string = *p); string++, p++)
+    if (isspace (*(unsigned char *) p))
+      {
+	if (!mark)
+	  mark = string;
+      }
+    else
+      mark = NULL;
+  if (mark)
+    *mark = '\0';	/* Remove trailing spaces.  */
+
+  return str;
+}
+
+#include <errno.h>
+
+void
+_scute_debug_init (void)
+{
+  static int initialized;
+
+  if (!initialized)
+    {
+      char *e;
+      const char *s1, *s2;;
+      FILE *stream;
+
+      e = getenv ("SCUTE_DEBUG");
+
+      initialized = 1;
+     
+      stream = stderr;
+      if (e)
+	{
+	  _scute_debug_flags = atoi (e);
+	  s1 = strchr (e, PATHSEP_C);
+	  if (s1)
+	    {
+#ifndef HAVE_W32_SYSTEM
+	      if (getuid () == geteuid ())
+		{
+#endif
+		  char *p;
+		  FILE *fp;
+
+		  s1++;
+		  if (!(s2 = strchr (s1, PATHSEP_C)))
+		    s2 = s1 + strlen (s1);
+		  p = malloc (s2 - s1 + 1);
+		  if (p)
+		    {
+		      memcpy (p, s1, s2 - s1);
+		      p[s2-s1] = 0;
+		      trim_spaces (p);
+		      fp = fopen (p,"a");
+		      if (fp)
+			{
+			  setvbuf (fp, NULL, _IOLBF, 0);
+			  stream = fp;
+			}
+		      free (p);
+		    }
+#ifndef HAVE_W32_SYSTEM
+		}
+#endif
+	    }
+        }
+
+      if (_scute_debug_flags > 0)
+        fprintf (stream, "scute debug init: flags=0x%x\n", _scute_debug_flags);
+
+      assuan_set_assuan_log_prefix ("scute-assuan");
+      _scute_debug_stream = stream;
+      if (_scute_debug_flags & DBG_ASSUAN)
+	assuan_set_assuan_log_stream (stream);
+    }
+}

+ 19 - 5
src/debug.h

@@ -1,5 +1,5 @@
 /* debug.c - Debug interface.
-   Copyright (C) 2006 g10 Code GmbH
+   Copyright (C) 2006, 2008 g10 Code GmbH
 
    This file is part of Scute.
  
@@ -34,9 +34,23 @@
 
 #define DEBUG_PREFIX "scute: "
 
-/* FIXME: Eventually, we should control output with an environment
-   variable.  */
-#define DEBUG(format, ...) \
-  fprintf (stderr, DEBUG_PREFIX "%s: " format "\n", __func__, ##__VA_ARGS__)
+#define DBG_CRIT 0
+#define DBG_INFO (1 << 0)
+#define DBG_ASSUAN (1 << 1)
+
+extern FILE *_scute_debug_stream;
+extern unsigned int _scute_debug_flags;
+
+#define DEBUG(flag, format, ...)  \
+  do \
+    { \
+      if (_scute_debug_flags & (flag)) \
+        fprintf (_scute_debug_stream, \
+                 DEBUG_PREFIX "%s: " format "\n", __func__, ##__VA_ARGS__); \
+    } \
+  while (0)
+
+void _scute_debug_init (void);
+
 
 #endif /* !DEBUG_H */

+ 1 - 1
src/error-mapping.c

@@ -65,7 +65,7 @@ CK_RV
 scute_gpg_err_to_ck (gpg_error_t err)
 {
   if (err)
-    DEBUG ("Error occured: %s (%s)\n", gpg_strerror (err),
+    DEBUG (DBG_CRIT, "Error occured: %s (%s)\n", gpg_strerror (err),
 	   gpg_strsource (err));
 
   switch (gpg_err_code (err))

+ 4 - 1
src/p11-initialize.c

@@ -43,8 +43,9 @@
 #include "agent.h"
 #include "error-mapping.h"
 #include "slots.h"
+#include "debug.h"
+
 
-
 CK_DEFINE_FUNCTION(CK_RV, C_Initialize) (CK_VOID_PTR pInitArgs)
 {
   CK_RV err;
@@ -56,6 +57,8 @@ CK_DEFINE_FUNCTION(CK_RV, C_Initialize) (CK_VOID_PTR pInitArgs)
      substitute for assuan_error_t.  */
   assuan_set_assuan_err_source (GPG_ERR_SOURCE_ANY);
 
+  _scute_debug_init ();
+
   /* Check the threading configuration.  */
   if (pInitArgs != NULL_PTR)
     {

+ 1 - 1
src/slots.c

@@ -423,7 +423,7 @@ slots_update_slot (slot_iterator_t id)
 	       || strncmp (slot->info.serialno, "D27600012401", 12)
 	       || strlen (slot->info.serialno) != 32))
     {
-      DEBUG ("token not an OpenPGP card: %s", slot->info.serialno);
+      DEBUG (DBG_INFO, "token not an OpenPGP card: %s", slot->info.serialno);
       err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
       scute_agent_release_card_info (&slot->info);
     }