First take on a W32 port

This commit is contained in:
Werner Koch 2004-12-02 07:48:09 +00:00
parent e0e1585fc8
commit 4a73d94757
22 changed files with 1476 additions and 41 deletions

View File

@ -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.

View 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)
{

View 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

View 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

View 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)

View 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)

437
common/simple-gettext.c Normal file
View File

@ -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 */

View File

@ -31,8 +31,12 @@
#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
}

73
common/strsep.c Normal file
View File

@ -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;
}

View 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 --*/

172
common/w32reg.c Normal file
View File

@ -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__ */

View 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

View 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.

View File

@ -34,9 +34,11 @@
#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>

View File

@ -42,7 +42,11 @@
#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

View 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.

View 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

View File

@ -31,8 +31,11 @@
/* 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"

View 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));

691
scd/app-p15.c Normal file
View File

@ -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;
}

View 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.

View 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