First take on a W32 port
authorWerner Koch <wk@gnupg.org>
Thu, 2 Dec 2004 07:48:09 +0000 (07:48 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 2 Dec 2004 07:48:09 +0000 (07:48 +0000)
22 files changed:
ChangeLog
agent/gpg-agent.c
common/ChangeLog
common/Makefile.am
common/fseeko.c
common/ftello.c
common/simple-gettext.c [new file with mode: 0644]
common/simple-pwquery.c
common/strsep.c [new file with mode: 0644]
common/util.h
common/w32reg.c [new file with mode: 0644]
configure.ac
jnlib/ChangeLog
jnlib/logging.c
jnlib/types.h
kbx/ChangeLog
kbx/Makefile.am
kbx/keybox-defs.h
kbx/keybox-update.c
scd/app-p15.c [new file with mode: 0644]
sm/ChangeLog
sm/gpgsm.c

index 4751d4d..c95cd9a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2004-11-26  Werner Koch  <wk@g10code.com>
+
+       * configure.ac: Replace strsep.  Replaced use of "target" by
+       "host".
+       
+
 2004-10-22  Werner Koch  <wk@g10code.com>
 
        Released 1.9.12.
index d3d6287..92af49b 100644 (file)
@@ -244,12 +244,12 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
 }
 
 
-/* Setup the debugging.  With a LEVEL of NULL only the active debug
-   flags are propagated to the subsystems.  With LEVEL set, a specific
-   set of debug flags is set; thus overriding all flags already
-   set. Note that we don't fail here, because it is important to keep
-   gpg-agent running even after re-reading the options due to a
-   SIGHUP. */
+/* Setup the debugging.  With the global variable DEBUG_LEVEL set to NULL
+   only the active debug flags are propagated to the subsystems.  With
+   DEBUG_LEVEL set, a specific set of debug flags is set; thus overriding
+   all flags already set. Note that we don't fail here, because it is
+   important to keep gpg-agent running even after re-reading the
+   options due to a SIGHUP. */
 static void
 set_debug (void)
 {
index d5ded50..9224055 100644 (file)
@@ -1,3 +1,12 @@
+2004-11-26  Werner Koch  <wk@g10code.com>
+
+       * simple-gettext.c: New taken from gnupg 1.3.x
+
+       * simple-pwquery.c [_WIN32]: Include winsock2.h.
+       (agent_open): Disable it until we have our AF_UNIX implementation
+       ready.
+       * fseeko.c, ftello.c: Include sys/types for the sake of W32.
+
 2004-11-23  Werner Koch  <wk@g10code.com>
 
        * b64enc.c: Include stdio.h and string.h
index 64b565c..12fdf7b 100644 (file)
@@ -41,6 +41,8 @@ libcommon_a_SOURCES = \
        iobuf.c iobuf.h \
        ttyio.c ttyio.h \
        asshelp.c asshelp.h \
+       simple-gettext.c \
+       w32reg.c \
        signal.c \
        dynload.h
 
index f151b09..06838e4 100644 (file)
@@ -22,6 +22,7 @@
 #include <config.h>
 #endif
 #include <stdio.h>
+#include <sys/types.h>  /* Defines off_t under W32.  */
 
 int
 fseeko (FILE *stream, off_t off, int whence)
index e314190..6837be9 100644 (file)
@@ -22,6 +22,7 @@
 #include <config.h>
 #endif
 #include <stdio.h>
+#include <sys/types.h>  /* Defines off_t under W32.  */
 
 off_t
 ftello (FILE *stream)
diff --git a/common/simple-gettext.c b/common/simple-gettext.c
new file mode 100644 (file)
index 0000000..4287606
--- /dev/null
@@ -0,0 +1,437 @@
+/* simple-gettext.c  - a simplified version of gettext.
+ * Copyright (C) 1995, 1996, 1997, 1999 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
+ */
+
+/* This is a simplified version of gettext written by Ulrich Drepper.
+ * It is used for the Win32 version of GnuPG beucase all the overhead
+ * of gettext is not needed and we have to do some special Win32 stuff.
+ * I decided that this is far easier than to tweak gettext for the special
+ * cases (I tried it but it is a lot of code). wk 15.09.99
+ */
+
+#include <config.h>
+#ifdef USE_SIMPLE_GETTEXT
+#if !defined (_WIN32) && !defined (__CYGWIN32__)
+#error This file can only be used under Windows or Cygwin32
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util.h"
+
+
+/* The magic number of the GNU message catalog format. */
+#define MAGIC        0x950412de
+#define MAGIC_SWAPPED 0xde120495
+
+/* Revision number of the currently used .mo (binary) file format.  */
+#define MO_REVISION_NUMBER 0
+
+
+/* Header for binary .mo file format.  */
+struct mo_file_header
+{
+  /* The magic number. */
+  u32 magic;
+  /* The revision number of the file format.  */
+  u32 revision;
+  /* The number of strings pairs.  */
+  u32 nstrings;
+  /* Offset of table with start offsets of original strings.  */
+  u32 orig_tab_offset;
+  /* Offset of table with start offsets of translation strings.  */
+  u32 trans_tab_offset;
+  /* Size of hashing table.  */
+  u32 hash_tab_size;
+  /* Offset of first hashing entry.  */
+  u32 hash_tab_offset;
+};
+
+struct string_desc
+{
+  /* Length of addressed string.  */
+  u32 length;
+  /* Offset of string in file. */
+  u32 offset;
+};
+
+
+struct overflow_space_s
+{
+  struct overflow_space_s *next;
+  u32 idx;
+  char d[1];
+};
+
+struct loaded_domain
+{
+  char *data;
+  int must_swap;
+  u32 nstrings;
+  char *mapped;  /* 0 = not yet mapped, 1 = mapped,
+                    2 = mapped to
+                    overflow space */
+  struct overflow_space_s *overflow_space;
+  struct string_desc *orig_tab;
+  struct string_desc *trans_tab;
+  u32 hash_size;
+  u32 *hash_tab;
+};
+
+
+static struct loaded_domain *the_domain;
+
+static __inline__ u32
+do_swap_u32( u32 i )
+{
+  return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
+}
+
+#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) )
+
+
+/* We assume to have `unsigned long int' value with at least 32 bits.  */
+#define HASHWORDBITS 32
+
+/* The so called `hashpjw' function by P.J. Weinberger
+   [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
+   1986, 1987 Bell Telephone Laboratories, Inc.]  */
+
+static __inline__ ulong
+hash_string( const char *str_param )
+{
+    unsigned long int hval, g;
+    const char *str = str_param;
+
+    hval = 0;
+    while (*str != '\0')
+    {
+       hval <<= 4;
+       hval += (unsigned long int) *str++;
+       g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
+       if (g != 0)
+       {
+         hval ^= g >> (HASHWORDBITS - 8);
+         hval ^= g;
+       }
+    }
+    return hval;
+}
+
+
+static struct loaded_domain *
+load_domain( const char *filename )
+{
+    FILE *fp;
+    size_t size;
+    struct stat st;
+    struct mo_file_header *data = NULL;
+    struct loaded_domain *domain = NULL;
+    size_t to_read;
+    char *read_ptr;
+
+    fp = fopen( filename, "rb" );
+    if( !fp )
+       return NULL; /* can't open the file */
+    /* we must know about the size of the file */
+    if( fstat( fileno(fp ), &st )
+       || (size = (size_t)st.st_size) != st.st_size
+       || size < sizeof (struct mo_file_header) ) {
+       fclose( fp );
+       return NULL;
+    }
+
+    data = malloc( size );
+    if( !data ) {
+       fclose( fp );
+       return NULL; /* out of memory */
+    }
+
+    to_read = size;
+    read_ptr = (char *) data;
+    do {
+       long int nb = fread( read_ptr, 1, to_read, fp );
+       if( nb < to_read ) {
+           fclose (fp);
+           free(data);
+           return NULL; /* read error */
+       }
+       read_ptr += nb;
+       to_read -= nb;
+    } while( to_read > 0 );
+    fclose (fp);
+
+    /* Using the magic number we can test whether it really is a message
+     * catalog file.  */
+    if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) {
+       /* The magic number is wrong: not a message catalog file.  */
+       free( data );
+       return NULL;
+    }
+
+    domain = calloc( 1, sizeof *domain );
+    if( !domain )  {
+       free( data );
+       return NULL;
+    }
+    domain->data = (char *) data;
+    domain->must_swap = data->magic != MAGIC;
+
+    /* Fill in the information about the available tables.  */
+    switch( SWAPIT(domain->must_swap, data->revision) ) {
+      case 0:
+       domain->nstrings = SWAPIT(domain->must_swap, data->nstrings);
+       domain->orig_tab = (struct string_desc *)
+         ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset));
+       domain->trans_tab = (struct string_desc *)
+         ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset));
+       domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size);
+       domain->hash_tab = (u32 *)
+         ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset));
+      break;
+
+      default: /* This is an invalid revision. */
+       free( data );
+       free( domain );
+       return NULL;
+    }
+
+    /* Allocate an array to keep track of code page mappings. */
+    domain->mapped = calloc( 1, domain->nstrings );
+    if( !domain->mapped ) {
+        free( data );
+        free( domain );
+        return NULL;
+    }
+
+    return domain;
+}
+
+
+/****************
+ * Set the file used for translations. Pass a NULL to disable
+ * translation.  A new filename may be set at anytime.
+ * WARNING: After changing the filename you should not access any data
+ *         retrieved by gettext().
+ */
+int
+set_gettext_file( const char *filename )
+{
+    struct loaded_domain *domain = NULL;
+
+    if( filename && *filename ) {
+       if( filename[0] == '/'
+#ifdef HAVE_DRIVE_LETTERS
+           || ( isalpha(filename[0])
+                && filename[1] == ':'
+                && (filename[2] == '/' || filename[2] == '\\') )
+#endif
+          ) {
+           /* absolute path - use it as is */
+           domain = load_domain( filename );
+       }
+       else { /* relative path - append ".mo" and get dir from the environment */
+           char *buf = NULL;
+           char *dir;
+            char *p;
+
+           dir = read_w32_registry_string( NULL,
+                                           "Control Panel\\Mingw32\\NLS",
+                                           "MODir" );
+           if( dir && (buf=malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {
+               strcpy(stpcpy(stpcpy(stpcpy( buf, dir),"\\"), filename),".mo");
+                /* Better make sure that we don't mix forward and
+                   backward slashes.  It seems that some Windoze
+                   versions don't accept this. */
+                for (p=buf; *p; p++)
+                  {
+                    if (*p == '/')
+                      *p = '\\';
+                  }
+               domain = load_domain( buf );
+               free(buf);
+           }
+           free(dir);
+       }
+       if( !domain )
+           return -1;
+    }
+
+    if( the_domain ) {
+        struct overflow_space_s *os, *os2;
+       free( the_domain->data );
+       free( the_domain->mapped );
+        for (os=the_domain->overflow_space; os; os = os2) {
+            os2 = os->next;
+            free (os);
+        }
+       free( the_domain );
+       the_domain = NULL;
+    }
+    the_domain = domain;
+    return 0;
+}
+
+
+static const char*
+get_string( struct loaded_domain *domain, u32 idx )
+{
+  struct overflow_space_s *os;
+  char *p;
+
+  p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset);
+  if (!domain->mapped[idx]) 
+    {
+      size_t plen, buflen;
+      char *buf;
+
+      domain->mapped[idx] = 1;
+
+      plen = strlen (p);
+      buf = utf8_to_native (p, plen, -1);
+      buflen = strlen (buf);
+      if (buflen <= plen)
+        strcpy (p, buf);
+      else
+        {
+          /* There is not enough space for the translation - store it
+             in the overflow_space else and mark that in the mapped
+             array.  Because we expect that this won't happen too
+             often, we use a simple linked list.  */
+          os = malloc (sizeof *os + buflen);
+          if (os)
+            {
+              os->idx = idx;
+              strcpy (os->d, buf);
+              os->next = domain->overflow_space;
+              domain->overflow_space = os;
+              p = os->d;
+            }
+          else
+            p = "ERROR in GETTEXT MALLOC";
+        }
+      xfree (buf);
+    }
+  else if (domain->mapped[idx] == 2) 
+    { /* We need to get the string from the overflow_space. */
+      for (os=domain->overflow_space; os; os = os->next)
+        if (os->idx == idx)
+          return (const char*)os->d;
+      p = "ERROR in GETTEXT\n";
+    }
+  return (const char*)p;
+}
+
+
+
+const char *
+gettext( const char *msgid )
+{
+    struct loaded_domain *domain;
+    size_t act = 0;
+    size_t top, bottom;
+
+    if( !(domain = the_domain) )
+       goto not_found;
+
+    /* Locate the MSGID and its translation.  */
+    if( domain->hash_size > 2 && domain->hash_tab ) {
+       /* Use the hashing table.  */
+       u32 len = strlen (msgid);
+       u32 hash_val = hash_string (msgid);
+       u32 idx = hash_val % domain->hash_size;
+       u32 incr = 1 + (hash_val % (domain->hash_size - 2));
+       u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]);
+
+       if ( !nstr ) /* Hash table entry is empty.  */
+           goto not_found;
+
+       if( SWAPIT(domain->must_swap,
+                   domain->orig_tab[nstr - 1].length) == len
+           && !strcmp( msgid,
+                      domain->data + SWAPIT(domain->must_swap,
+                                   domain->orig_tab[nstr - 1].offset)) )
+           return get_string( domain, nstr - 1 );
+
+       for(;;) {
+           if (idx >= domain->hash_size - incr)
+               idx -= domain->hash_size - incr;
+           else
+               idx += incr;
+
+           nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]);
+           if( !nstr )
+               goto not_found; /* Hash table entry is empty.  */
+
+           if ( SWAPIT(domain->must_swap,
+                               domain->orig_tab[nstr - 1].length) == len
+                && !strcmp (msgid,
+                        domain->data + SWAPIT(domain->must_swap,
+                                          domain->orig_tab[nstr - 1].offset)))
+               return get_string( domain, nstr-1 );
+       }
+       /* NOTREACHED */
+    }
+
+    /* Now we try the default method:  binary search in the sorted
+       array of messages.  */
+    bottom = 0;
+    top = domain->nstrings;
+    while( bottom < top ) {
+       int cmp_val;
+
+       act = (bottom + top) / 2;
+       cmp_val = strcmp(msgid, domain->data
+                              + SWAPIT(domain->must_swap,
+                                       domain->orig_tab[act].offset));
+       if (cmp_val < 0)
+           top = act;
+       else if (cmp_val > 0)
+           bottom = act + 1;
+       else
+           return get_string( domain, act );
+    }
+
+  not_found:
+    return msgid;
+}
+
+#if 0
+       unsigned int cp1, cp2;
+
+       cp1 = GetConsoleCP();
+       cp2 = GetConsoleOutputCP();
+
+       log_info("InputCP=%u  OutputCP=%u\n", cp1, cp2 );
+
+       if( !SetConsoleOutputCP( 1252 ) )
+            log_info("SetConsoleOutputCP failed: %s\n", w32_strerror (0));
+
+       cp1 = GetConsoleCP();
+       cp2 = GetConsoleOutputCP();
+       log_info("InputCP=%u  OutputCP=%u after switch1\n", cp1, cp2 );
+#endif
+
+#endif /* USE_SIMPLE_GETTEXT */
index 0bc8128..fab6306 100644 (file)
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#else
 #include <sys/socket.h>
 #include <sys/un.h>
+#endif
 #ifdef HAVE_LOCALE_H
 #include <locale.h>
 #endif
@@ -255,6 +259,9 @@ agent_send_all_options (int fd)
 static int
 agent_open (int *rfd)
 {
+#ifdef _WIN32
+  return SPWQ_NO_AGENT;  /* FIXME */
+#else
   int rc;
   int fd;
   char *infostr, *p;
@@ -346,6 +353,7 @@ agent_open (int *rfd)
 
   *rfd = fd;
   return 0;
+#endif
 }
 
 
diff --git a/common/strsep.c b/common/strsep.c
new file mode 100644 (file)
index 0000000..af3f02e
--- /dev/null
@@ -0,0 +1,73 @@
+/* strsep.c - Replacement for strsep().
+ * Copyright (C) 2002 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+
+/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c */
+#warning need to get the correct copyright years from glibc
+char *
+strsep (char **stringp, const char *delim)
+{
+  char *begin, *end;
+
+  begin = *stringp;
+  if (begin == NULL)
+    return NULL;
+
+  /* A frequent case is when the delimiter string contains only one
+     character.  Here we don't need to call the expensive `strpbrk'
+     function and instead work using `strchr'.  */
+  if (delim[0] == '\0' || delim[1] == '\0')
+    {
+      char ch = delim[0];
+
+      if (ch == '\0')
+        end = NULL;
+      else
+        {
+          if (*begin == ch)
+            end = begin;
+          else if (*begin == '\0')
+            end = NULL;
+          else
+            end = strchr (begin + 1, ch);
+        }
+    }
+  else
+    /* Find the end of the token.  */
+    end = strpbrk (begin, delim);
+
+  if (end)
+    {
+      /* Terminate the token and set *STRINGP past NUL character.  */
+      *end++ = '\0';
+      *stringp = end;
+    }
+  else
+    /* No more delimiters; this is the last token.  */
+    *stringp = NULL;
+
+  return begin;
+}
+
index b9ffe65..fad7d38 100644 (file)
@@ -144,7 +144,9 @@ int is_file_compressed (const char *s, int *ret_rc);
 int vasprintf (char **result, const char *format, va_list args);
 int asprintf (char **result, const char *format, ...) JNLIB_GCC_A_PRINTF(2,3);
 #endif
-
+#ifndef HAVE_STRSEP
+char *strsep (char **stringp, const char *delim);
+#endif
 
 
 /*-- some macros to replace ctype ones and avoid locale problems --*/
diff --git a/common/w32reg.c b/common/w32reg.c
new file mode 100644 (file)
index 0000000..19fb613
--- /dev/null
@@ -0,0 +1,172 @@
+/* w32reg.c -  MS-Windows Registry access
+ *     Copyright (C) 1999, 2002 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>
+#if defined (_WIN32) || defined (__CYGWIN32__)
+ /* This module is only used in this environment */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <windows.h>
+
+#include "util.h"
+
+static HKEY
+get_root_key(const char *root)
+{
+    HKEY root_key;
+       
+    if( !root )
+        root_key = HKEY_CURRENT_USER;
+    else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
+       root_key = HKEY_CLASSES_ROOT;
+    else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
+       root_key = HKEY_CURRENT_USER;
+    else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
+       root_key = HKEY_LOCAL_MACHINE;
+    else if( !strcmp( root, "HKEY_USERS" ) )
+       root_key = HKEY_USERS;
+    else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
+       root_key = HKEY_PERFORMANCE_DATA;
+    else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
+       root_key = HKEY_CURRENT_CONFIG;
+    else
+        return NULL;
+       
+    return root_key;
+}
+
+
+/****************
+ * Return a string from the Win32 Registry or NULL in case of
+ * error.  Caller must release the return value.   A NULL for root
+ * is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.
+ * NOTE: The value is allocated with a plain malloc() - use free() and not
+ * the usual m_free()!!!
+ */
+char *
+read_w32_registry_string( const char *root, const char *dir, const char *name )
+{
+    HKEY root_key, key_handle;
+    DWORD n1, nbytes, type;
+    char *result = NULL;
+
+    if ( !(root_key = get_root_key(root) ) )
+       return NULL;
+
+    if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) )
+      {
+        if (root)
+          return NULL; /* no need for a RegClose, so return direct */
+        /* It seems to be common practise to fall back to HLM. */
+        if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
+          return NULL; /* still no need for a RegClose, so return direct */
+      }
+
+    nbytes = 1;
+    if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
+       goto leave;
+    result = malloc( (n1=nbytes+1) );
+    if( !result )
+       goto leave;
+    if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) {
+       free(result); result = NULL;
+       goto leave;
+    }
+    result[nbytes] = 0; /* make sure it is really a string  */
+    if (type == REG_EXPAND_SZ && strchr (result, '%')) {
+        char *tmp;
+        
+        n1 += 1000;
+        tmp = malloc (n1+1);
+        if (!tmp)
+            goto leave;
+        nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+        if (nbytes && nbytes > n1) {
+            free (tmp);
+            n1 = nbytes;
+            tmp = malloc (n1 + 1);
+            if (!tmp)
+                goto leave;
+            nbytes = ExpandEnvironmentStrings (result, tmp, n1);
+            if (nbytes && nbytes > n1) {
+                free (tmp); /* oops - truncated, better don't expand at all */
+                goto leave;
+            }
+            tmp[nbytes] = 0;
+            free (result);
+            result = tmp;
+        }
+        else if (nbytes) { /* okay, reduce the length */
+            tmp[nbytes] = 0;
+            free (result);
+            result = malloc (strlen (tmp)+1);
+            if (!result)
+                result = tmp;
+            else {
+                strcpy (result, tmp);
+                free (tmp);
+            }
+        }
+        else {  /* error - don't expand */
+            free (tmp);
+        }
+    }
+
+  leave:
+    RegCloseKey( key_handle );
+    return result;
+}
+
+
+int
+write_w32_registry_string(const char *root, const char *dir, 
+                          const char *name, const char *value)
+{
+    HKEY root_key, reg_key;
+       
+    if ( !(root_key = get_root_key(root) ) )
+       return -1;
+
+    if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, &reg_key ) 
+         != ERROR_SUCCESS )
+       return -1;
+       
+    if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, 
+                        strlen( value ) ) != ERROR_SUCCESS ) {
+        if ( RegCreateKey( root_key, name, &reg_key ) != ERROR_SUCCESS ) {
+            RegCloseKey(reg_key);
+            return -1;
+        }
+        if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value,
+                            strlen( value ) ) != ERROR_SUCCESS ) {
+            RegCloseKey(reg_key);
+            return -1;
+        }
+    }
+
+    RegCloseKey( reg_key );
+       
+    return 0;
+}
+
+#endif /* __MINGW32__ || __CYGWIN32__ */
index b0affbb..8b6bc4d 100644 (file)
@@ -343,7 +343,7 @@ GNUPG_CHECK_DOCBOOK_TO_TEXI
 
 try_gettext=yes
 have_dosish_system=no
-case "${target}" in
+case "${host}" in
     *-*-mingw32*)
         # special stuff for Windoze NT
         ac_cv_have_dev_random=no
@@ -660,7 +660,7 @@ fi
 
 AC_SUBST(GPGKEYS_MAILTO)
 
-case "${target}" in
+case "${host}" in
     *-*-mingw32*)
         PRINTABLE_OS_NAME="MingW32"
         ;;
@@ -782,7 +782,7 @@ AC_REPLACE_FUNCS(mkdtemp)
 AC_REPLACE_FUNCS(fseeko ftello)
 AC_REPLACE_FUNCS(isascii)
 AC_REPLACE_FUNCS(putc_unlocked)
-
+AC_REPLACE_FUNCS(strsep)
 
 
 
@@ -970,7 +970,7 @@ GNUPG_CHECK_GNUMAKE
 
 # add some extra libs here so that previous tests don't fail for
 # mysterious reasons - the final link step should bail out. 
-case "${target}" in
+case "${host}" in
     *-*-mingw32*)
         W32LIBS="-lwsock32"
         ;;
@@ -1038,6 +1038,14 @@ if test "$build_agent_only" = "yes" ; then
   build_scdaemon=no
 fi
 
+# We don't yet want to build some parts for W32
+case "${host}" in 
+    *-mingw32*) 
+      build_gpg=no
+      ;;
+esac
+
+
 AM_CONDITIONAL(BUILD_GPG,   test "$build_gpg" = "yes")
 AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes")
 AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes")
@@ -1140,7 +1148,7 @@ AC_OUTPUT
 echo "
         GnuPG v${VERSION} has been configured as follows:
         
-        Platform:  $PRINTABLE_OS_NAME ($target)
+        Platform:  $PRINTABLE_OS_NAME ($host)
 
         OpenPGP:   $build_gpg
         S/MIME:    $build_gpgsm
index 4c52590..5ca33d5 100644 (file)
@@ -1,3 +1,7 @@
+2004-11-26  Werner Koch  <wk@g10code.com>
+
+       * logging.c [_WIN32]: Don't include socket headers.
+
 2004-11-30  Timo Schulz  <ts@g10code.com>
 
        * w32-afunix.c: New. AF_UNIX emulation for W32.
index 5397a11..960d816 100644 (file)
 #include <errno.h>
 #include <time.h>
 #include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/socket.h>
 #include <sys/un.h>
+#endif
 #include <unistd.h>
 #include <fcntl.h>
 #include <assert.h>
index 230d150..934b7a6 100644 (file)
 
 #ifndef HAVE_BYTE_TYPEDEF
   #undef byte      /* maybe there is a macro with this name */
+/* Windows typedefs byte in the rpc headers.  Avoid warning about
+   double definition.  */
+#if !(defined(_WIN32) && defined(cbNDRContext))
   typedef unsigned char byte;
+#endif
   #define HAVE_BYTE_TYPEDEF
 #endif
 
index c10ea12..ea5b9db 100644 (file)
@@ -1,3 +1,9 @@
+2004-11-26  Werner Koch  <wk@g10code.com>
+
+       * Makefile.am (kbxutil_LDADD): Add ../common/libcommon.a
+
+       * keybox-defs.h: Include stringhelp.h.
+
 2004-09-30  Werner Koch  <wk@g10code.com>
 
        * kbxutil.c (i18n_init): Always use LC_ALL.
index 0b35587..ea8436d 100644 (file)
@@ -43,11 +43,8 @@ common_sources = \
 
 libkeybox_a_SOURCES = $(common_sources)
 
+# Note that libcommon is only required to resolve the LIBOBJS.
 kbxutil_SOURCES = kbxutil.c $(common_sources)
 kbxutil_LDADD   = ../jnlib/libjnlib.a  $(KSBA_LIBS) $(LIBGCRYPT_LIBS) \
-                  -lgpg-error @LIBINTL@ 
-
-
-
-
+                  -lgpg-error $(LIBINTL) ../common/libcommon.a
 
index 4906a38..5724b85 100644 (file)
 
 /* We include the type defintions from jnlib instead of defining our
    owns here.  This will not allow us build KBX in a standalone way
-   but tehre is currently no need for it anyway. */
+   but there is currently no need for it anyway.  Same goes for
+   stringhelp.h which for example provides a replacement for stpcpy -
+   fixme: Better the LIBOBJ mechnism. */
 #include "../jnlib/types.h"
+#include "../jnlib/stringhelp.h"
 
 #include "keybox.h"
 
index 1695550..eabaa1d 100644 (file)
@@ -66,7 +66,7 @@ create_tmp_file (const char *template,
       strcpy (tmpfname + strlen (template)-4, EXTSEP_S "tmp");
     }
   else 
-    { /* file does not end with kbx; hmmm */
+    { /* File does not end with kbx; hmmm. */
       bakfname = xtrymalloc ( strlen (template) + 5);
       if (!bakfname)
         return gpg_error (gpg_err_code_from_errno (errno));
diff --git a/scd/app-p15.c b/scd/app-p15.c
new file mode 100644 (file)
index 0000000..af2eed4
--- /dev/null
@@ -0,0 +1,691 @@
+/* app-p15.c - The pkcs#15 card application.
+ *     Copyright (C) 2004 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 <assert.h>
+#include <time.h>
+
+#include "scdaemon.h"
+
+#include "iso7816.h"
+#include "app-common.h"
+#include "tlv.h"
+
+
+/* Context local to this application. */
+struct app_local_s 
+{
+  unsigned short home_df;  /* The home DF. Note, that we don't yet
+                              support a multilevel hierachy.  Thus we
+                              assume this is directly below the MF.  */
+  struct
+  {
+    unsigned short private_keys;
+    unsigned short public_keys;
+    unsigned short trusted_public_keys;
+    unsigned short secret_keys;
+    unsigned short certificates;
+    unsigned short trusted_certificates;
+    unsigned short useful_certificates;
+    unsigned short data_objects;
+    unsigned short auth_objects;
+  } odf;  
+
+
+};
+
+
+
+
+/* Do a select and a read for the file with EFID.  EFID is a
+   desctription of the EF to be used with error messages.  On success
+   BUFFER and BUFLEN contain the entire content of the EF.  The caller
+   must free BUFFER but only on success. */
+static gpg_error_t 
+select_and_read_binary (int slot, unsigned short efid, const char *efid_desc,
+                        unsigned char **buffer, size_t *buflen)
+{
+  gpg_error_t err;
+
+  err = iso7816_select_file (slot, efid, 0, NULL, NULL);
+  if (err)
+    {
+      log_error ("error selecting %s (0x%04X): %s\n",
+                 efid_desc, efid, gpg_strerror (err));
+      return err;
+    }
+  err = iso7816_read_binary (slot, 0, 0, buffer, buflen);
+  if (err)
+    {
+      log_error ("error reading %s (0x%04X): %s\n",
+                 efid_desc, efid, gpg_strerror (err));
+      return err;
+    }
+  return 0;
+}
+
+
+
+
+/* Read and parse the Object Directory File and store away the
+   pointers.
+
+   Example of such a file:
+
+   A0 06 30 04 04 02 60 34  = Private Keys
+   A4 06 30 04 04 02 60 35  = Certificates 
+   A5 06 30 04 04 02 60 36  = TrustedCertificates
+   A7 06 30 04 04 02 60 37  = DataObjects
+   A8 06 30 04 04 02 60 38  = AuthObjects
+    
+   These are all PathOrObjects using the path CHOICE.  The paths are
+   octet strings of length 2.  Using this Path CHOICE is recommended,
+   so we only implement that for now.
+*/
+static gpg_error_t
+read_ef_odf (app_t app)
+{
+  gpg_error_t err;
+  unsigned char *buffer, *p;
+  size_t buflen;
+  unsigned short value;
+
+  err = select_and_read_binary (app->slot, 0x5031, "ODF", &buffer, &buflen);
+  if (err)
+    return err;
+
+  if (len < 8)
+    {
+      log_error ("error: ODF too short\n");
+      xfree (buffer);
+      return gpg_error (GPG_ERR_INV_OBJ);
+    }
+  for (p=buffer; buflen >= 8; p += 8, buflen -= 8)
+    {
+      if ( (p[0] & 0xf0) != 0xA0
+           || memcmp (p+1, "\x06\x30\x04\x04\x02", 5) )
+        {
+          log_error ("ODF format is not supported by us\n");
+          xfree (buffer);
+          return gpg_error (GPG_ERR_INV_OBJ);
+        }
+      switch ((p[0] & 0x0f))
+        {
+        case 0: value = app->app_local->odf.private_keys; break;
+        case 1: value = app->app_local->odf.public_keys; break;
+        case 2: value = app->app_local->odf.trusted_public_keys; break;
+        case 3: value = app->app_local->odf.secret_keys; break;
+        case 4: value = app->app_local->odf.certificates; break;
+        case 5: value = app->app_local->odf.trusted_certificates; break;
+        case 6: value = app->app_local->odf.useful_certificates; break;
+        case 7: value = app->app_local->odf.data_objects; break;
+        case 8: value = app->app_local->odf.auth_objects; break;
+        default: value = 0; break;
+        }
+      if (value)
+        {
+          log_error ("duplicate object type %d in ODF ignored\n",(p[0)&0x0f));
+          continue;
+        }
+      value = ((p[6] << 8) | p[7]);
+      switch ((p[0] & 0x0f))
+        {
+        case 0: app->app_local->odf.private_keys = value; break;
+        case 1: app->app_local->odf.public_keys = value; break;
+        case 2: app->app_local->odf.trusted_public_keys = value; break;
+        case 3: app->app_local->odf.secret_keys = value; break;
+        case 4: app->app_local->odf.certificates = value; break;
+        case 5: app->app_local->odf.trusted_certificates = value; break;
+        case 6: app->app_local->odf.useful_certificates = value; break;
+        case 7: app->app_local->odf.data_objects = value; break;
+        case 8: app->app_local->odf.auth_objects = value; break;
+        default: 
+          log_error ("unknown object type %d in ODF ignored\n", (p[0)&0x0f));
+        }
+    }
+
+  if (buflen)
+    log_info ("warning: %u bytes of garbage detected at end of ODF\n", buflen);
+
+  xfree (buffer);
+  return 0;
+}
+
+
+
+/* Read and  parse the Private Key Directory Files. */
+/*
+  6034 (privatekeys)
+
+30 33 30 11 0C 08 53 4B 2E  43 48 2E 44 53 03 02   030...SK.CH.DS..
+06 80 04 01 07 30 0C 04 01  01 03 03 06 00 40 02   .....0........@.
+02 00 50 A1 10 30 0E 30 08  04 06 3F 00 40 16 00   ..P..0.0...?.@..
+50 02 02 04 00 30 33 30 11  0C 08 53 4B 2E 43 48   P....030...SK.CH
+2E 4B 45 03 02 06 80 04 01  0A 30 0C 04 01 0C 03   .KE.......0.....
+03 06 44 00 02 02 00 52 A1  10 30 0E 30 08 04 06   ..D....R..0.0...
+3F 00 40 16 00 52 02 02 04  00 30 34 30 12 0C 09   ?.@..R....040...
+53 4B 2E 43 48 2E 41 55 54  03 02 06 80 04 01 0A   SK.CH.AUT.......
+30 0C 04 01 0D 03 03 06 20  00 02 02 00 51 A1 10   0....... ....Q..
+30 0E 30 08 04 06 3F 00 40  16 00 51 02 02 04 00   0.0...?.@..Q....
+30 37 30 15 0C 0C 53 4B 2E  43 48 2E 44 53 2D 53   070...SK.CH.DS-S
+50 58 03 02 06 80 04 01 0A  30 0C 04 01 02 03 03   PX.......0......
+06 20 00 02 02 00 53 A1 10  30 0E 30 08 04 06 3F   . ....S..0.0...?
+00 40 16 00 53 02 02 04 00  00 00 00 00 00 00 00   .@..S...........
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+
+*/
+static gpg_error_t
+read_ef_prkdf (app_t app)
+{
+
+
+}
+
+/* Read and  parse the Public Key Directory Files. */
+static gpg_error_t
+read_ef_pukdf (app_t app)
+{
+
+
+}
+
+
+/* Read and parse the Certificate Directory Files. */
+/* 
+
+6035 (certificates)
+
+30 2A 30 15 0C 0C 43 5F 58  35 30 39 2E 43 48 2E   0*0...C_X509.CH.
+44 53 03 02 06 40 04 01 0A  30 03 04 01 01 A1 0C   DS...@...0......
+30 0A 30 08 04 06 3F 00 40  16 C0 00 30 2A 30 15   0.0...?.@...0*0.
+0C 0C 43 5F 58 35 30 39 2E  43 48 2E 4B 45 03 02   ..C_X509.CH.KE..
+06 40 04 01 0A 30 03 04 01  0C A1 0C 30 0A 30 08   .@...0......0.0.
+04 06 3F 00 40 16 C2 00 30  2B 30 16 0C 0D 43 5F   ..?.@...0+0...C_
+58 35 30 39 2E 43 48 2E 41  55 54 03 02 06 40 04   X509.CH.AUT...@.
+01 0A 30 03 04 01 0D A1 0C  30 0A 30 08 04 06 3F   ..0......0.0...?
+00 40 16 C5 00 30 2E 30 19  0C 10 43 5F 58 35 30   .@...0.0...C_X50
+39 2E 43 48 2E 44 53 2D 53  50 58 03 02 06 40 04   9.CH.DS-SPX...@.
+01 0A 30 03 04 01 02 A1 0C  30 0A 30 08 04 06 3F   ..0......0.0...?
+00 40 16 C1 20 00 00 00 00  00 00 00 00 00 00 00   .@.. ...........
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+
+   0   42: SEQUENCE {
+   2   21:   SEQUENCE {   -- commonObjectAttributes
+   4   12:     UTF8String 'C_X509.CH.DS'
+  18    2:     BIT STRING 6 unused bits
+         :       '10'B (bit 1)
+  22    1:     OCTET STRING 0A
+         :     }
+  25    3:   SEQUENCE {   -- commonCertificateAttributes
+  27    1:     OCTET STRING 01
+         :     }
+  30   12:   [1] {        -- certAttributes
+  32   10:     SEQUENCE {
+  34    8:       SEQUENCE {
+  36    6:         OCTET STRING 3F 00 40 16 C0 00
+         :         }
+         :       }
+         :     }
+         :   }
+
+
+
+6036 (trustedcertificates)
+
+30 35 30 06 03 02 00 00 04  00 30 16 04 14 2D 36   050.......0...-6
+33 39 33 33 39 34 30 33 39  37 37 36 34 30 31 32   3933940397764012
+31 36 A1 13 30 11 30 0F 04  06 3F 00 40 16 C7 08   16..0.0...?.@...
+02 01 00 80 02 02 29 30 35  30 06 03 02 00 00 04   ......)050......
+00 30 16 04 14 2D 34 30 31  39 30 35 32 37 32 36   .0...-4019052726
+38 30 31 36 39 33 34 39 32  A1 13 30 11 30 0F 04   801693492..0.0..
+06 3F 00 40 16 C7 0E 02 01  00 80 02 04 12 30 34   .?.@..........04
+30 06 03 02 00 00 04 00 30  15 04 13 37 39 36 33   0.......0...7963
+32 38 33 36 35 30 37 36 36  34 38 32 39 36 30 A1   283650766482960.
+13 30 11 30 0F 04 06 3F 00  40 16 C0 08 02 01 00   .0.0...?.@......
+80 02 04 11 00 00 00 00 00  00 00 00 00 00 00 00   ................
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+
+   0   53: SEQUENCE {
+   2    6:   SEQUENCE {
+   4    2:     BIT STRING
+         :       '00000000'B
+         :       Error: Spurious zero bits in bitstring.
+   8    0:     OCTET STRING
+         :       Error: Object has zero length.
+         :     }
+  10   22:   SEQUENCE {
+  12   20:     OCTET STRING '-6393394039776401216'
+         :     }
+  34   19:   [1] {
+  36   17:     SEQUENCE {
+  38   15:       SEQUENCE {
+  40    6:         OCTET STRING 3F 00 40 16 C7 08
+  48    1:         INTEGER 0       -- index
+  51    2:         [0] 02 29       -- length
+         :         }
+         :       }
+         :     }
+         :   }
+
+
+*/
+static gpg_error_t
+read_ef_cdf (app_t app)
+{
+  gpg_error_t err;
+  unsigned char *buffer = NULL;
+  size_t buflen;
+  unsigned short value;
+  unsigned short fid;
+  const unsigned char *p;
+  size_t n, objlen, hdrlen;
+  int class, tag, constructed, ndef;
+  
+  fid = app->app_local->odf.certificates;
+  if (!fid)
+    return 0; /* No certificates. */
+  
+  err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen);
+  if (err)
+    return err;
+  
+  p = buffer;
+  n = buflen;
+
+  /* Loop over the records.  We stop as soon as we detect a new record
+     starting with 0x00 or 0xff as these values are commonly used to pad
+     the the read datablocks and are no valid ASN.1 encoding. */
+  while (n && *p && *p == 0xff)
+    {
+      const unsigned char *pp;
+      size_t nn;
+
+      err = parse_ber_header (&p, &n, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (!err && (objlen > n || tag != TAG_SEQUENCE))
+        err = gpg_error (GPG_ERR_INV_OBJ);
+      if (err)
+        {
+          log_error ("error parsing CDF record: %s\n", gpg_strerror (err));
+          goto leave;
+        }
+      pp = p;
+      nn = objlen;
+      p += objlen;
+      n -= objlen;
+
+      /* Skip the commonObjectAttributes.  */
+      err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (!err && (objlen > nn || tag != TAG_SEQUENCE))
+        err = gpg_error (GPG_ERR_INV_OBJ);
+      if (err)
+        {
+          log_error ("error parsing CDF record: %s - skipped\n",
+                     gpg_strerror (err));
+          continue;
+        }
+      pp += objlen;
+      nn -= objlen;
+
+      /* Skip the commonCertificateAttributes.  */
+      err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
+                              &ndef, &objlen, &hdrlen);
+      if (!err && (objlen > nn || tag != TAG_SEQUENCE))
+        err = gpg_error (GPG_ERR_INV_OBJ);
+      if (err)
+        {
+          log_error ("error parsing CDF record: %s - skipped\n",
+                     gpg_strerror (err));
+          continue;
+        }
+      pp += objlen;
+      nn -= objlen;
+
+      /* FIXME: Check that this is a reference to a certificate. */
+
+
+    }
+
+
+ leave:
+  xfree (buffer);
+  return err;
+}
+
+/* Read and parse Authentication Object Directory Files.  */
+static gpg_error_t 
+read_ef_aodf (app_t app)
+{
+
+}
+
+
+/* 6037 (dataobjects)
+
+30 1E 30 0B 0C 06 45 46 2E  47 44 4F 04 01 0A 30   0.0...EF.GDO...0
+02 0C 00 A1 0B 30 09 04 04  3F 00 2F 02 80 01 0E   .....0...?./....
+30 30 30 18 0C 0F 64 69 73  70 6C 61 79 20 6D 65   000...display me
+73 73 61 67 65 03 02 06 C0  04 01 0A 30 05 0C 03   ssage.......0...
+42 53 53 A1 0D 30 0B 04 06  3F 00 40 16 D0 00 80   BSS..0...?.@....
+01 20 30 2B 30 0C 0C 03 53  53 4F 03 02 06 C0 04   . 0+0...SSO.....
+01 0A 30 0B 0C 09 53 61 66  65 47 75 61 72 64 A1   ..0...SafeGuard.
+0E 30 0C 04 06 3F 00 0F FF  30 02 80 02 03 00 30   .0...?...0.....0
+30 30 11 0C 08 53 47 41 53  64 61 74 61 03 02 06   00...SGASdata...
+C0 04 01 0A 30 0B 0C 09 53  61 66 65 47 75 61 72   ....0...SafeGuar
+64 A1 0E 30 0C 04 06 3F 00  0F FF 40 01 80 02 00   d..0...?...@....
+80 30 30 30 11 0C 08 55 73  65 72 64 61 74 61 03   .000...Userdata.
+02 06 40 04 01 0A 30 0B 0C  09 53 61 66 65 47 75   ..@...0...SafeGu
+61 72 64 A1 0E 30 0C 04 06  3F 00 0F FF 30 01 80   ard..0...?...0..
+02 01 00 30 2C 30 13 0C 0A  62 61 73 69 63 20 64   ...0,0...basic d
+61 74 61 03 02 06 C0 04 01  0A 30 05 0C 03 49 44   ata.......0...ID
+44 A1 0E 30 0C 04 06 3F 00  40 17 D0 01 80 02 02   D..0...?.@......
+00 30 2F 30 16 0C 0D 65 78  74 65 6E 64 65 64 20   .0/0...extended 
+64 61 74 61 03 02 06 C0 04  01 0A 30 05 0C 03 49   data.......0...I
+44 44 A1 0E 30 0C 04 06 3F  00 40 17 D0 02 80 02   DD..0...?.@.....
+08 00 30 34 30 1B 0C 12 73  70 65 63 69 61 6C 20   ..040...special 
+70 72 69 76 69 6C 65 67 65  73 03 02 06 C0 04 01   privileges......
+0A 30 05 0C 03 49 44 44 A1  0E 30 0C 04 06 3F 00   .0...IDD..0...?.
+40 17 D0 03 80 02 04 00                            @.......        
+
+   0   30: SEQUENCE {
+   2   11:   SEQUENCE {
+   4    6:     UTF8String 'EF.GDO'
+  12    1:     OCTET STRING 0A
+         :     }
+  15    2:   SEQUENCE {
+  17    0:     UTF8String
+         :       Error: Object has zero length.
+         :     }
+  19   11:   [1] {
+  21    9:     SEQUENCE {
+  23    4:       OCTET STRING 3F 00 2F 02
+  29    1:       [0] 0E
+         :       }
+         :     }
+         :   }
+
+
+
+6038 (authobjects)
+
+30 2A 30 0B 0C 05 62 61 73  69 63 03 02 00 C0 30   0*0...basic....0
+03 04 01 0A A1 16 30 14 03  03 00 0C 10 0A 01 01   ......0.........
+02 01 06 02 01 06 02 01 08  80 01 01 30 51 30 19   ............0Q0.
+0C 13 73 70 65 63 69 66 69  63 20 50 49 4E 20 66   ..specific PIN f
+6F 72 20 44 53 03 02 00 C0  30 03 04 01 07 A1 2F   or DS....0...../
+30 2D 03 03 00 4C 10 0A 01  01 02 01 06 02 01 06   0-...L..........
+02 01 08 80 01 02 18 0F 32  30 30 32 30 34 31 39   ........20020419
+31 32 31 33 34 31 5A 30 06  04 04 3F 00 40 16      121341Z0...?.@. 
+
+   0   42: SEQUENCE {
+   2   11:   SEQUENCE {
+   4    5:     UTF8String 'basic'
+  11    2:     BIT STRING
+         :       '00000011'B
+         :       Error: Spurious zero bits in bitstring.
+         :     }
+  15    3:   SEQUENCE {
+  17    1:     OCTET STRING 0A
+         :     }
+  20   22:   [1] {
+  22   20:     SEQUENCE {
+  24    3:       BIT STRING
+         :         '0000100000110000'B
+         :         Error: Spurious zero bits in bitstring.
+  29    1:       ENUMERATED 1
+  32    1:       INTEGER 6
+  35    1:       INTEGER 6
+  38    1:       INTEGER 8
+  41    1:       [0] 01
+         :       }
+         :     }
+         :   }
+
+
+
+*/
+
+
+/* Read and parse the EF(TokenInfo). 
+
+TokenInfo ::= SEQUENCE {
+    version            INTEGER {v1(0)} (v1,...),
+    serialNumber       OCTET STRING,
+    manufacturerID     Label OPTIONAL,
+    label              [0] Label OPTIONAL,
+    tokenflags                 TokenFlags,
+    seInfo             SEQUENCE OF SecurityEnvironmentInfo OPTIONAL,
+    recordInfo                 [1] RecordInfo OPTIONAL,
+    supportedAlgorithms        [2] SEQUENCE OF AlgorithmInfo OPTIONAL,
+    ...,
+    issuerId           [3] Label OPTIONAL,
+    holderId           [4] Label OPTIONAL,
+    lastUpdate         [5] LastUpdate OPTIONAL,
+    preferredLanguage  PrintableString OPTIONAL -- In accordance with
+    -- IETF RFC 1766 
+} (CONSTRAINED BY { -- Each AlgorithmInfo.reference value must be unique --})
+
+TokenFlags ::= BIT STRING {
+    readonly           (0),
+    loginRequired      (1),
+    prnGeneration      (2),
+    eidCompliant       (3)
+}
+
+
+ 5032:
+
+30 31 02 01 00 04 04 05 45  36 9F 0C 0C 44 2D 54   01......E6...D-T
+72 75 73 74 20 47 6D 62 48  80 14 4F 66 66 69 63   rust GmbH..Offic
+65 20 69 64 65 6E 74 69 74  79 20 63 61 72 64 03   e identity card.
+02 00 40 20 63 61 72 64 03  02 00 40 00 00 00 00   ..@ card...@....
+00 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00   ................
+
+   0   49: SEQUENCE {
+   2    1:   INTEGER 0
+   5    4:   OCTET STRING 05 45 36 9F
+  11   12:   UTF8String 'D-Trust GmbH'
+  25   20:   [0] 'Office identity card'
+  47    2:   BIT STRING
+         :     '00000010'B (bit 1)
+         :     Error: Spurious zero bits in bitstring.
+         :   }
+
+
+
+
+ */
+static gpg_error_t
+read_ef_tokeninfo (app_t app)
+{
+  unsigned short efid = 0x5032;
+
+}
+
+
+/* Get all the basic information from the pkcs#15 card, check the
+   structure and init our context.  This is used once at application
+   initialization. */
+static gpg_error_t
+read_p15_info (app_t app)
+{
+  gpg_error_t err;
+
+  err = read_ed_odf (app);
+  if (err)
+    return err;
+
+}
+
+
+static int
+do_learn_status (APP app, CTRL ctrl)
+{
+  gpg_error_t err;
+  char ct_buf[100], id_buf[100];
+  int i;
+
+  /* Output information about all useful objects. */
+  for (i=0; objlist[i].fid; i++)
+    {
+      if (filelist[i].certtype)
+        {
+          size_t len;
+
+          len = app_help_read_length_of_cert (app->slot,
+                                              filelist[i].fid, NULL);
+          if (len)
+            {
+              /* FIXME: We should store the length in the application's
+                 context so that a following readcert does only need to
+                 read that many bytes. */
+              sprintf (ct_buf, "%d", filelist[i].certtype);
+              sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid);
+              send_status_info (ctrl, "CERTINFO",
+                                ct_buf, strlen (ct_buf), 
+                                id_buf, strlen (id_buf), 
+                                NULL, (size_t)0);
+            }
+        }
+      else if (filelist[i].iskeypair)
+        {
+          char gripstr[40+1];
+
+          err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
+          if (err)
+            log_error ("can't get keygrip from FID 0x%04X: %s\n",
+                       filelist[i].fid, gpg_strerror (err));
+          else
+            {
+              sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid);
+              send_status_info (ctrl, "KEYPAIRINFO",
+                                gripstr, 40, 
+                                id_buf, strlen (id_buf), 
+                                NULL, (size_t)0);
+            }
+        }
+    }
+
+  return 0;
+}
+
+
+
+
+/* Release all resources.  */
+static void
+do_deinit (app_t app)
+{
+  if (app && app->app_local)
+    {
+      xfree (app->app_local);
+      app->app_local = NULL;
+    }
+}
+
+
+/* Select the PKCS#15 application on the card in SLOT.  */
+int
+app_select_p15 (APP app)
+{
+  static char const aid[] = { 0xA0, 0, 0, 0, 0x63,
+                              0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 };
+  int slot = app->slot;
+  int rc;
+  
+  rc = iso7816_select_application (slot, aid, sizeof aid);
+  if (!rc)
+    {
+      app->apptype = "P15";
+
+      app->app_local = xtrycalloc (1, sizeof *app->app_local);
+      if (!app->app_local)
+        {
+          rc = gpg_error_from_errno (errno);
+          goto leave;
+        }
+
+      /* Read basic information and check whether this is a real
+         card.  */
+      rc = read_p15_info (app);
+      
+      /* Special serial number munging.  We need to do one case here
+         because we need to access the EF(TokenInfo).  */
+      if (app->serialnolen == 12
+          && !memcmp (app->serial, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12))
+        {
+          /* This is a German card with a silly serial number.  Try to get
+             the serial number from the EF(TokenInfo). We indicate such a
+             serial number by the using the prefix: "FF0100". */
+          const char *efser = card->p15card->serial_number;
+          char *p;
+          
+          if (!efser)
+            efser = "";
+          
+          xfree (*serial);
+          *serial = NULL;
+          p = xtrymalloc (strlen (efser) + 7);
+          if (!p)
+            rc = gpg_error (gpg_err_code_from_errno (errno));
+          else
+            {
+              strcpy (p, "FF0100");
+              strcpy (p+6, efser);
+              *serial = p;
+            }
+        }
+      else
+        rc = app_munge_serialno (app);
+
+      app->fnc.deinit = do_deinit;
+      app->fnc.learn_status = do_learn_status;
+      app->fnc.readcert = do_readcert;
+      app->fnc.getattr = NULL;
+      app->fnc.setattr = NULL;
+      app->fnc.genkey = NULL;
+      app->fnc.sign = do_sign;
+      app->fnc.auth = NULL;
+      app->fnc.decipher = do_decipher;
+      app->fnc.change_pin = NULL;
+      app->fnc.check_pin = NULL;
+
+    leave:
+      if (rc)
+        {
+          xfree (app->app_local);
+          app->app_local = NULL;
+        }
+      
+   }
+
+  return rc;
+}
+
+
index acfa7f3..5f35e48 100644 (file)
@@ -1,3 +1,10 @@
+2004-11-29  Werner Koch  <wk@g10code.com>
+
+       * gpgsm.c (set_debug): Changed to use a globals DEBUG_LEVEL and
+       DEBUG_VALUE.
+       (main): Made DEBUG_LEVEL global and introduced DEBUG_VALUE.  This
+       now allows to add debug flags on top of a debug-level setting.
+
 2004-11-23  Werner Koch  <wk@g10code.com>
 
        * gpgsm.c: New option --prefer-system-dirmngr.
index c9ce8fd..c96683a 100644 (file)
@@ -438,6 +438,10 @@ int gpgsm_errors_seen = 0;
 /* It is possible that we are currentlu running under setuid permissions */
 static int maybe_setuid = 1;
 
+/* Helper to implement --debug-level and --debug*/
+static const char *debug_level;
+static unsigned int debug_value;
+
 /* Option --enable-special-filenames */
 static int allow_special_filenames;
 
@@ -580,45 +584,44 @@ wrong_args (const char *text)
 }
 
 
-/* Setup the debugging.  With a LEVEL of NULL only the active debug
-   flags are propagated to the subsystems.  With LEVEL set, a specific
-   set of debug flags is set; thus overriding all flags already
-   set. */
+/* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
+   debug flags are propagated to the subsystems.  With DEBUG_LEVEL
+   set, a specific set of debug flags is set; and individual debugging
+   flags will be added on top.  */
 static void
-set_debug (const char *level)
+set_debug (void)
 {
-  if (!level)
+  if (!debug_level)
     ;
-  else if (!strcmp (level, "none"))
+  else if (!strcmp (debug_level, "none"))
     opt.debug = 0;
-  else if (!strcmp (level, "basic"))
+  else if (!strcmp (debug_level, "basic"))
     opt.debug = DBG_ASSUAN_VALUE;
-  else if (!strcmp (level, "advanced"))
+  else if (!strcmp (debug_level, "advanced"))
     opt.debug = DBG_ASSUAN_VALUE|DBG_X509_VALUE;
-  else if (!strcmp (level, "expert"))
+  else if (!strcmp (debug_level, "expert"))
     opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE
                  |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
-  else if (!strcmp (level, "guru"))
+  else if (!strcmp (debug_level, "guru"))
     opt.debug = ~0;
   else
     {
-      log_error (_("invalid debug-level `%s' given\n"), level);
+      log_error (_("invalid debug-level `%s' given\n"), debug_level);
       gpgsm_exit(2);
     }
 
+  opt.debug |= debug_value;
 
   if (opt.debug && !opt.verbose)
-    {
-      opt.verbose = 1;
-      gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
-    }
-  if (opt.debug && opt.quiet)
+    opt.verbose = 1;
+  if (opt.debug)
     opt.quiet = 0;
 
   if (opt.debug & DBG_MPI_VALUE)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
   if (opt.debug & DBG_CRYPTO_VALUE )
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+  gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
 }
  
 
@@ -695,7 +698,6 @@ main ( int argc, char **argv)
   int greeting = 0;
   int nogreeting = 0;
   int debug_wait = 0;
-  const char *debug_level = NULL;
   int use_random_seed = 1;
   int with_fpr = 0;
   char *def_digest_string = NULL;
@@ -1010,8 +1012,8 @@ main ( int argc, char **argv)
 
         case oKeyring: append_to_strlist (&nrings, pargs.r.ret_str); break;
 
-        case oDebug: opt.debug |= pargs.r.ret_ulong; break;
-        case oDebugAll: opt.debug = ~0; break;
+        case oDebug: debug_value |= pargs.r.ret_ulong; break;
+        case oDebugAll: debug_value = ~0; break;
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
         case oDebugAllowCoreDump:
@@ -1201,7 +1203,7 @@ main ( int argc, char **argv)
 
   gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
 
-  set_debug (debug_level);
+  set_debug ();
 
   /* Although we alwasy use gpgsm_exit, we better install a regualr
      exit handler so that at least the secure memory gets wiped