aboutsummaryrefslogtreecommitdiffstats
path: root/scd/sc-investigate.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/sc-investigate.c')
-rw-r--r--scd/sc-investigate.c812
1 files changed, 0 insertions, 812 deletions
diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c
deleted file mode 100644
index 1f1920650..000000000
--- a/scd/sc-investigate.c
+++ /dev/null
@@ -1,812 +0,0 @@
-/* sc-investigate.c - A tool to look around on smartcards.
- * Copyright (C) 2003 Free Software Foundation, Inc.
- *
- * This file is part of GnuPG.
- *
- * GnuPG is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GnuPG is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <unistd.h>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-#endif
-
-#ifdef HAVE_READLINE_READLINE_H
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif
-
-#define JNLIB_NEED_LOG_LOGV
-#include "scdaemon.h"
-#include <gcrypt.h>
-
-#include "apdu.h" /* for open_reader */
-#include "atr.h"
-#include "app-common.h"
-#include "iso7816.h"
-
-#define _(a) (a)
-
-#define CONTROL_D ('D' - 'A' + 1)
-
-
-enum cmd_and_opt_values
-{
- oInteractive = 'i',
- oVerbose = 'v',
- oQuiet = 'q',
- oReaderPort = 500,
- octapiDriver,
-
- oDebug,
- oDebugAll,
-
- oDisableCCID,
-
-
- oGenRandom,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oInteractive, "interactive", 0, "start in interactive explorer mode"},
- { oQuiet, "quiet", 0, "quiet" },
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
- { octapiDriver, "ctapi-driver", 2, "|NAME|use NAME as ctAPI driver"},
- { oDisableCCID, "disable-ccid", 0,
-#ifdef HAVE_LIBUSB
- "do not use the internal CCID driver"
-#else
- "@"
-#endif
- },
- { oDebug, "debug" ,4|16, "set debugging flags"},
- { oDebugAll, "debug-all" ,0, "enable full debugging"},
- { oGenRandom, "gen-random", 4, "|N|generate N bytes of random"},
- {0}
-};
-
-#ifndef HAVE_OPENSC
-#ifdef USE_GNU_PTH
-/* Pth wrapper function definitions. */
-GCRY_THREAD_OPTION_PTH_IMPL;
-#endif /*USE_GNU_PTH*/
-#endif /*!HAVE_OPENSC*/
-
-static void interactive_shell (int slot);
-static void dump_other_cards (int slot);
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "sc-investigate (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
- break;
- case 1:
- case 40: p = _("Usage: sc-investigate [options] (-h for help)\n");
- break;
- case 41: p = _("Syntax: sc-investigate [options] [args]]\n"
- "Have a look at smartcards\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-/* Used by gcry for logging */
-static void
-my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
-{
- /* translate the log levels */
- switch (level)
- {
- case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
- case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
- case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
- case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
- case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
- case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
- case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
- default: level = JNLIB_LOG_ERROR; break;
- }
- log_logv (level, fmt, arg_ptr);
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int slot, rc;
- const char *reader_port = NULL;
- unsigned long gen_random = 0;
- int interactive = 0;
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("sc-investigate", 1);
-
- /* Try to auto set the character set. */
- set_native_charset (NULL);
-
- /* Libgcrypt requires us to register the threading model first. We
- can't use pth at all if we are using OpenSC becuase OpenSC uses
- ptreads. Note that this will also do the pth_init. */
-#ifndef HAVE_OPENSC
-#ifdef USE_GNU_PTH
- rc = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
- if (rc)
- {
- log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
- gpg_strerror (rc));
- }
-#endif /*USE_GNU_PTH*/
-#endif /*!HAVE_OPENSC*/
-
- /* Check that the libraries are suitable. Do it here because
- the option parsing may need services of the library */
- if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
- {
- log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
- NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
- }
-
-
- gcry_set_log_handler (my_gcry_logger, NULL);
- /* FIXME? gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);*/
-
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- while (arg_parse (&pargs, opts) )
- {
- switch (pargs.r_opt)
- {
- case oVerbose: opt.verbose++; break;
- case oQuiet: opt.quiet++; break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- case oReaderPort: reader_port = pargs.r.ret_str; break;
- case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
- case oDisableCCID: opt.disable_ccid = 1; break;
- case oGenRandom: gen_random = pargs.r.ret_ulong; break;
- case oInteractive: interactive = 1; break;
- default : pargs.err = 2; break;
- }
- }
- if (log_get_errorcount(0))
- exit(2);
-
- if (opt.verbose < 2)
- opt.verbose = 2; /* Hack to let select_openpgp print some info. */
-
- if (argc)
- usage (1);
-
- slot = apdu_open_reader (reader_port);
- if (slot == -1)
- exit (1);
-
- if (!gen_random && !opt.quiet)
- {
- rc = atr_dump (slot, stdout);
- if (rc)
- log_error ("can't dump ATR: %s\n", gpg_strerror (rc));
- }
-
- if (interactive)
- interactive_shell (slot);
- else
- {
- struct app_ctx_s appbuf;
-
- /* Fixme: We better use app.c directly. */
- memset (&appbuf, 0, sizeof appbuf);
- appbuf.slot = slot;
- rc = app_select_openpgp (&appbuf);
- if (rc)
- {
- if (!opt.quiet)
- log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- memset (&appbuf, 0, sizeof appbuf);
- appbuf.slot = slot;
- rc = app_select_dinsig (&appbuf);
- if (rc)
- {
- if (!opt.quiet)
- log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc));
- dump_other_cards (slot);
- }
- else
- {
- appbuf.initialized = 1;
- log_info ("dinsig application selected\n");
- }
- }
- else
- {
- appbuf.initialized = 1;
- log_info ("openpgp application selected\n");
-
- if (gen_random)
- {
- size_t nbytes;
- unsigned char *buffer;
-
- buffer = xmalloc (4096);
- do
- {
- nbytes = gen_random > 4096? 4096 : gen_random;
- rc = app_get_challenge (&appbuf, nbytes, buffer);
- if (rc)
- log_error ("app_get_challenge failed: %s\n",gpg_strerror (rc));
- else
- {
- if (fwrite (buffer, nbytes, 1, stdout) != 1)
- log_error ("writing to stdout failed: %s\n",
- strerror (errno));
- gen_random -= nbytes;
- }
- }
- while (gen_random && !log_get_errorcount (0));
- xfree (buffer);
- }
- }
- }
-
- return log_get_errorcount (0)? 2:0;
-}
-
-
-
-void
-send_status_info (CTRL ctrl, const char *keyword, ...)
-{
- /* DUMMY */
-}
-
-
-
-/* Dump BUFFER of length NBYTES in a nicely human readable format. */
-static void
-dump_buffer (const unsigned char *buffer, size_t nbytes)
-{
- int i;
-
- while (nbytes)
- {
- for (i=0; i < 16 && i < nbytes; i++)
- printf ("%02X%s ", buffer[i], i==8? " ":"");
- for (; i < 16; i++)
- printf (" %s ", i==8? " ":"");
- putchar (' ');
- putchar (' ');
- for (i=0; i < 16 && i < nbytes; i++)
- if (isprint (buffer[i]))
- putchar (buffer[i]);
- else
- putchar ('.');
- nbytes -= i;
- buffer += i;
- for (; i < 16; i++)
- putchar (' ');
- putchar ('\n');
- }
-}
-
-
-static void
-dump_or_store_buffer (const char *arg,
- const unsigned char *buffer, size_t nbytes)
-{
- const char *s = strchr (arg, '>');
- int append;
- FILE *fp;
-
- if (!s)
- {
- dump_buffer (buffer, nbytes);
- return;
- }
- if ((append = (*++s == '>')))
- s++;
- fp = fopen (s, append? "ab":"wb");
- if (!fp)
- {
- log_error ("failed to create `%s': %s\n", s, strerror (errno));
- return;
- }
- if (nbytes && fwrite (buffer, nbytes, 1, fp) != 1)
- log_error ("failed to write to `%s': %s\n", s, strerror (errno));
- if (fclose (fp))
- log_error ("failed to close `%s': %s\n", s, strerror (errno));
-}
-
-
-/* Convert STRING into a a newly allocated buffer and return the
- length of the buffer in R_LENGTH. Detect xx:xx:xx... sequence and
- unhexify that one. */
-static unsigned char *
-pin_to_buffer (const char *string, size_t *r_length)
-{
- unsigned char *buffer = xmalloc (strlen (string)+1);
- const char *s;
- size_t n;
-
- for (s=string, n=0; *s; s += 3)
- {
- if (hexdigitp (s) && hexdigitp (s+1) && (s[2]==':'||!s[2]))
- {
- buffer[n++] = xtoi_2 (s);
- if (!s[2])
- break;
- }
- else
- {
- memcpy (buffer, string, strlen (string));
- *r_length = strlen (string);
- return buffer;
- }
- }
- *r_length = n;
- return buffer;
-}
-
-
-static char *
-my_read_line (int use_readline, char *prompt)
-{
- static char buf[256];
-
-#ifdef HAVE_READLINE
- if (use_readline)
- {
- char *line = readline (prompt);
- if (line)
- trim_spaces (line);
- if (line && strlen (line) > 2 )
- add_history (line);
- return line;
- }
-#endif
- /* Either we don't have readline or we are not running
- interactively */
-#ifndef HAVE_READLINE
- printf ("%s", prompt );
-#endif
- fflush(stdout);
- if (!fgets(buf, sizeof(buf), stdin))
- return NULL;
- if (!strlen(buf))
- return NULL;
- if (buf[strlen (buf)-1] == '\n')
- buf[strlen (buf)-1] = 0;
- trim_spaces (buf);
- return buf;
-}
-
-/* Run a shell for interactive exploration of the card. */
-static void
-interactive_shell (int slot)
-{
- enum cmdids
- {
- cmdNOP = 0,
- cmdQUIT, cmdHELP,
- cmdSELECT,
- cmdCHDIR,
- cmdLS,
- cmdAPP,
- cmdREAD,
- cmdREADREC,
- cmdREADSHORTREC,
- cmdDEBUG,
- cmdVERIFY,
- cmdCHANGEREF,
- cmdREADPK,
-
- cmdINVCMD
- };
- static struct
- {
- const char *name;
- enum cmdids id;
- const char *desc;
- } cmds[] = {
- { "quit" , cmdQUIT , "quit this menu" },
- { "q" , cmdQUIT , NULL },
- { "help" , cmdHELP , "show this help" },
- { "?" , cmdHELP , NULL },
- { "debug" , cmdDEBUG, "set debugging flags" },
- { "select" , cmdSELECT, "select file (EF)" },
- { "s" , cmdSELECT, NULL },
- { "chdir" , cmdCHDIR, "change directory (select DF)"},
- { "cd" , cmdCHDIR, NULL },
- { "ls" , cmdLS, "list directory (some cards only)"},
- { "app" , cmdAPP, "select application"},
- { "read" , cmdREAD, "read binary" },
- { "rb" , cmdREAD, NULL },
- { "readrec", cmdREADREC, "read record(s)" },
- { "rr" , cmdREADREC, NULL },
- { "rsr" , cmdREADSHORTREC, "readshortrec RECNO SHORT_EF" },
- { "verify" , cmdVERIFY, "verify CHVNO PIN" },
- { "ver" , cmdVERIFY, NULL },
- { "changeref", cmdCHANGEREF, "change reference data" },
- { "readpk", cmdREADPK, "read a public key" },
- { NULL, cmdINVCMD }
- };
- enum cmdids cmd = cmdNOP;
- int use_readline = isatty (fileno(stdin));
- char *line;
- gpg_error_t err = 0;
- unsigned char *result = NULL;
- size_t resultlen;
-
-#ifdef HAVE_READLINE
- if (use_readline)
- using_history ();
-#endif
-
- for (;;)
- {
- int arg_number;
- const char *arg_string = "";
- const char *arg_next = "";
- char *p;
- int i;
-
- if (err)
- printf ("command failed: %s\n", gpg_strerror (err));
- err = 0;
- xfree (result);
- result = NULL;
-
- printf ("\n");
- do
- {
- line = my_read_line (use_readline, "cmd> ");
- }
- while ( line && *line == '#' );
-
- arg_number = 0;
- if (!line || *line == CONTROL_D)
- cmd = cmdQUIT;
- else if (!*line)
- cmd = cmdNOP;
- else {
- if ((p=strchr (line,' ')))
- {
- char *endp;
-
- *p++ = 0;
- trim_spaces (line);
- trim_spaces (p);
- arg_number = strtol (p, &endp, 0);
- arg_string = p;
- if (endp != p)
- {
- arg_next = endp;
- while ( spacep (arg_next) )
- arg_next++;
- }
- }
-
- for (i=0; cmds[i].name; i++ )
- if (!ascii_strcasecmp (line, cmds[i].name ))
- break;
-
- cmd = cmds[i].id;
- }
-
- switch (cmd)
- {
- case cmdHELP:
- for (i=0; cmds[i].name; i++ )
- if (cmds[i].desc)
- printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
- break;
-
- case cmdQUIT:
- goto leave;
-
- case cmdNOP:
- break;
-
- case cmdDEBUG:
- if (!*arg_string)
- opt.debug = opt.debug? 0 : 2048;
- else
- opt.debug = arg_number;
- break;
-
- case cmdSELECT:
- err = iso7816_select_file (slot, arg_number, 0, NULL, NULL);
- break;
-
- case cmdCHDIR:
- err = iso7816_select_file (slot, arg_number, 1, NULL, NULL);
- break;
-
- case cmdLS:
- err = iso7816_list_directory (slot, 1, &result, &resultlen);
- if (!err || gpg_err_code (err) == GPG_ERR_ENOENT)
- err = iso7816_list_directory (slot, 0, &result, &resultlen);
- /* FIXME: Do something with RESULT. */
- break;
-
- case cmdAPP:
- {
- app_t app;
-
- app = select_application (NULL, slot, *arg_string? arg_string:NULL);
- if (app)
- {
- char *sn;
-
- app_get_serial_and_stamp (app, &sn, NULL);
- log_info ("application `%s' ready; sn=%s\n",
- app->apptype?app->apptype:"?", sn? sn:"[none]");
- release_application (app);
- }
- }
- break;
-
- case cmdREAD:
- err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- break;
-
- case cmdREADREC:
- if (*arg_string == '*' && (!arg_string[1] || arg_string[1] == ' '))
- {
- /* Fixme: Can't write to a file yet. */
- for (i=1, err=0; !err; i++)
- {
- xfree (result); result = NULL;
- err = iso7816_read_record (slot, i, 1, 0,
- &result, &resultlen);
- if (!err)
- dump_buffer (result, resultlen);
- }
- if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
- err = 0;
- }
- else
- {
- err = iso7816_read_record (slot, arg_number, 1, 0,
- &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- }
- break;
-
- case cmdREADSHORTREC:
- {
- int short_ef;
-
- short_ef = strtol (arg_next, NULL, 0);
-
- if (short_ef < 1 || short_ef > 254)
- printf ("error: short EF must be between 1 and 254\n");
- else
- {
- err = iso7816_read_record (slot, arg_number, 1, short_ef,
- &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- }
- }
- break;
-
- case cmdVERIFY:
- if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31)
- printf ("error: invalid CHVNO\n");
- else
- {
- unsigned char *pin;
- size_t pinlen;
-
- pin = pin_to_buffer (arg_next, &pinlen);
- err = iso7816_verify (slot, arg_number, pin, pinlen);
- xfree (pin);
- }
- break;
-
- case cmdCHANGEREF:
- {
- const char *newpin = arg_next;
-
- while ( *newpin && !spacep (newpin) )
- newpin++;
- while ( spacep (newpin) )
- newpin++;
-
- if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31)
- printf ("error: invalid CHVNO\n");
- else if (!*arg_next || !*newpin || newpin == arg_next)
- printf ("usage: changeref CHVNO OLDPIN NEWPIN\n");
- else
- {
- char *oldpin = xstrdup (arg_next);
- unsigned char *oldpin_buf, *newpin_buf;
- size_t oldpin_len, newpin_len;
-
- for (p=oldpin; *p && !spacep (p); p++ )
- ;
- *p = 0;
- oldpin_buf = pin_to_buffer (oldpin, &oldpin_len);
- newpin_buf = pin_to_buffer (newpin, &newpin_len);
-
- err = iso7816_change_reference_data (slot, arg_number,
- oldpin_buf, oldpin_len,
- newpin_buf, newpin_len);
-
- xfree (newpin_buf);
- xfree (oldpin_buf);
- xfree (oldpin);
- }
- }
- break;
-
- case cmdREADPK:
- if (arg_number < 1 || arg_number > 255)
- printf ("usage: readpk CRTBYTE1\n");
- else
- {
- unsigned char crt[2];
-
- crt[0] = arg_number;
- crt[1] = 0;
- err = iso7816_read_public_key(slot, crt, 2,
- &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- }
- break;
-
-
- case cmdINVCMD:
- default:
- printf ("\n");
- printf ("Invalid command (try \"help\")\n");
- break;
- } /* End command switch. */
- } /* End of main menu loop. */
-
- leave:
- ;
-}
-
-
-
-/* Figure out whether the current card is a German Geldkarte and print
- what we know about it. */
-static int
-dump_geldkarte (int slot)
-{
- unsigned char *r = NULL;
- size_t rlen;
- const char *t;
-
- if (iso7816_read_record (slot, 1, 1, 0xbc, &r, &rlen))
- return -1;
- /* We require that the record is at least 24 bytes, the first byte
- is 0x67 and the filler byte is correct. */
- if (rlen < 24 || *r != 0x67 || r[22])
- return -1;
-
- /* The short Bankleitzahl consists of 3 bytes at offset 1. */
- switch (r[1])
- {
- case 0x21: t = "Oeffentlich-rechtliche oder private Bank"; break;
- case 0x22: t = "Privat- oder Gesch�ftsbank"; break;
- case 0x25: t = "Sparkasse"; break;
- case 0x26:
- case 0x29: t = "Genossenschaftsbank"; break;
- default:
- xfree (r);
- return -1; /* Probably not a Geldkarte. */
- }
-
- printf ("KBLZ .....: %02X-%02X%02X (%s)\n", r[1], r[2], r[3], t);
- printf ("Card-No ..: %02X%02X%02X%02X%02X\n", r[4], r[5], r[6], r[7], r[8]);
-
-/* Byte 10 enth�lt im linken Halbbyte eine Pr�fziffer, die nach dem */
-/* Verfahren 'Luhn formula for computing modulus 10' �ber die Ziffern der */
-/* ersten 9 Byte berechnet ist. */
-
-/* Das rechte Halbbyte wird zu 'D' gesetzt. */
-
-/* F�r die Berechnung der Luhn-Pr�fziffer sind die folgenden Schritte */
-/* durchzuf�hren: */
-
-/* Schritt 1: Mit der rechtesten Ziffer beginnend ist einschlie�lich dieser */
-/* Ziffer jede �bern�chste Ziffer zu verdoppeln (mit 2 multiplizieren). */
-
-/* Schritt 2: Die einzelnen Ziffern der Produkte aus Schritt 1 und die bei */
-/* diesen Multiplikationen unber�hrt gebliebenen Ziffern sind zu addieren. */
-
-/* Schritt 3: Das Ergebnis der Addition aus Schritt 2 ist von dem auf die */
-/* n�chst h�here Zahl mit der Einerstelle 0 aufgerundeten Ergebnis der */
-/* Addition aus Schritt 2 abzuziehen. Wenn das Ergebnis der Addition aus */
-/* Schritt 2 bereits eine Zahl mit der Einerstelle 0 ergibt (z.B. 30, 40, */
-/* usw.), ist die Pr�fziffer 0. */
-
-/* Beispiel: Kartennummer ohne Pr�fziffer: 992 839 871 */
-
-/* 9 9 2 8 3 9 8 7 1 */
-
-/* x 2 x 2 x 2 x 2 x 2 Schritt 1 */
-
-/* 18 4 6 16 2 */
-
-/* 1+8 +9 +4 +8 +6 +9 +1+6 +7 +2 = 61 Schritt 2 */
-
-/* 70-61 = 9 Schritt 3 */
-
-/* Pr�fziffer zu 992 839 871 = 9 */
-
-
- printf ("Expires at: %02X/%02X\n", r[11], r[10] );
- printf ("Valid from: %02X.%02X.%02X\n", r[14], r[13], r[12]);
- printf ("Country ..: %02X%02X\n", r[15], r[16]);
- printf ("Currency .: %c%c%c\n", isascii (r[17])? r[17]:' ',
- isascii (r[18])? r[18]:' ', isascii (r[19])? r[19]:' ');
- printf ("Cur.-Mult : %s\n",
- r[20] == 0x01? "0.01":
- r[20] == 0x02? "0.1":
- r[20] == 0x04? "1":
- r[20] == 0x08? "10":
- r[20] == 0x10? "100":
- r[20] == 0x20? "1000": "?");
- printf ("ZKA ChipID: %02X\n", r[21]);
- printf ("OS version: %02X\n", r[23]);
-
- xfree (r);
- return 0;
-}
-
-
-
-/* Try to figure out the type of teh card and dump its contents. */
-static void
-dump_other_cards (int slot)
-{
-
- if (!dump_geldkarte (slot))
- return;
-
-}
-