mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
* call-scd.c (unescape_status_string): New. Actual a copy of
../g10/call-agent.c (card_getattr_cb, agent_card_getattr): New. * command-ssh.c (card_key_available): New. (ssh_handler_request_identities): First see whether a card key is available. * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the application does dot support the getattr call. * app.c (select_application): Return an error code and the application context in an new arg. * command.c (open_card): Adjusted for that. Don't use the fallback if no card is present. Return an error if the card has been removed without a reset. (do_reset, cmd_serialno): Clear that error flag. (TEST_CARD_REMOVAL): New. Use it with all command handlers. (scd_update_reader_status_file): Set the error flag on all changes.
This commit is contained in:
parent
3af261572b
commit
1f1f28555a
@ -1,5 +1,13 @@
|
|||||||
2005-02-24 Werner Koch <wk@g10code.com>
|
2005-02-24 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* call-scd.c (unescape_status_string): New. Actual a copy of
|
||||||
|
../g10/call-agent.c
|
||||||
|
(card_getattr_cb, agent_card_getattr): New.
|
||||||
|
|
||||||
|
* command-ssh.c (card_key_available): New.
|
||||||
|
(ssh_handler_request_identities): First see whether a card key is
|
||||||
|
available.
|
||||||
|
|
||||||
* gpg-agent.c (handle_connections): Need to check for events if
|
* gpg-agent.c (handle_connections): Need to check for events if
|
||||||
select returns with -1.
|
select returns with -1.
|
||||||
|
|
||||||
|
@ -259,6 +259,7 @@ int agent_card_pkdecrypt (ctrl_t ctrl,
|
|||||||
int agent_card_readcert (ctrl_t ctrl,
|
int agent_card_readcert (ctrl_t ctrl,
|
||||||
const char *id, char **r_buf, size_t *r_buflen);
|
const char *id, char **r_buf, size_t *r_buflen);
|
||||||
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
|
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
|
||||||
|
gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
|
||||||
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
|
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
|
||||||
int (*getpin_cb)(void *, const char *, char*, size_t),
|
int (*getpin_cb)(void *, const char *, char*, size_t),
|
||||||
void *getpin_cb_arg, void *assuan_context);
|
void *getpin_cb_arg, void *assuan_context);
|
||||||
|
133
agent/call-scd.c
133
agent/call-scd.c
@ -1,5 +1,5 @@
|
|||||||
/* call-scd.c - fork of the scdaemon to do SC operations
|
/* call-scd.c - fork of the scdaemon to do SC operations
|
||||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
* Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -66,7 +66,7 @@ static pth_mutex_t scd_lock;
|
|||||||
static int active_connection_fd = -1;
|
static int active_connection_fd = -1;
|
||||||
static int active_connection = 0;
|
static int active_connection = 0;
|
||||||
|
|
||||||
/* callback parameter for learn card */
|
/* Callback parameter for learn card */
|
||||||
struct learn_parm_s {
|
struct learn_parm_s {
|
||||||
void (*kpinfo_cb)(void*, const char *);
|
void (*kpinfo_cb)(void*, const char *);
|
||||||
void *kpinfo_cb_arg;
|
void *kpinfo_cb_arg;
|
||||||
@ -266,6 +266,41 @@ agent_reset_scd (ctrl_t ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return a new malloced string by unescaping the string S. Escaping
|
||||||
|
is percent escaping and '+'/space mapping. A binary Nul will
|
||||||
|
silently be replaced by a 0xFF. Function returns NULL to indicate
|
||||||
|
an out of memory status. */
|
||||||
|
static char *
|
||||||
|
unescape_status_string (const unsigned char *s)
|
||||||
|
{
|
||||||
|
char *buffer, *d;
|
||||||
|
|
||||||
|
buffer = d = xtrymalloc (strlen (s)+1);
|
||||||
|
if (!buffer)
|
||||||
|
return NULL;
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
|
if (*s == '%' && s[1] && s[2])
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
*d = xtoi_2 (s);
|
||||||
|
if (!*d)
|
||||||
|
*d = '\xff';
|
||||||
|
d++;
|
||||||
|
s += 2;
|
||||||
|
}
|
||||||
|
else if (*s == '+')
|
||||||
|
{
|
||||||
|
*d++ = ' ';
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*d++ = *s++;
|
||||||
|
}
|
||||||
|
*d = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -375,14 +410,6 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Hmm, do we really need this reset - scddaemon should do this or
|
|
||||||
we can do this if we for some reason figure out that the
|
|
||||||
operation might have failed due to a missing RESET. Hmmm, I feel
|
|
||||||
this is really SCdaemon's duty */
|
|
||||||
/* rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); */
|
|
||||||
/* if (rc) */
|
|
||||||
/* return unlock_scd (map_assuan_err (rc)); */
|
|
||||||
|
|
||||||
rc = assuan_transact (scd_ctx, "SERIALNO",
|
rc = assuan_transact (scd_ctx, "SERIALNO",
|
||||||
NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL,
|
||||||
get_serialno_cb, &serialno);
|
get_serialno_cb, &serialno);
|
||||||
@ -395,6 +422,8 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno)
|
|||||||
return unlock_scd (0);
|
return unlock_scd (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static AssuanError
|
static AssuanError
|
||||||
membuf_data_cb (void *opaque, const void *buffer, size_t length)
|
membuf_data_cb (void *opaque, const void *buffer, size_t length)
|
||||||
@ -644,6 +673,90 @@ agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Type used with the card_getattr_cb. */
|
||||||
|
struct card_getattr_parm_s {
|
||||||
|
const char *keyword; /* Keyword to look for. */
|
||||||
|
size_t keywordlen; /* strlen of KEYWORD. */
|
||||||
|
char *data; /* Malloced and unescaped data. */
|
||||||
|
int error; /* ERRNO value or 0 on success. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Callback function for agent_card_getattr. */
|
||||||
|
static assuan_error_t
|
||||||
|
card_getattr_cb (void *opaque, const char *line)
|
||||||
|
{
|
||||||
|
struct card_getattr_parm_s *parm = opaque;
|
||||||
|
const char *keyword = line;
|
||||||
|
int keywordlen;
|
||||||
|
|
||||||
|
if (parm->data)
|
||||||
|
return 0; /* We want only the first occurrence. */
|
||||||
|
|
||||||
|
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
|
||||||
|
;
|
||||||
|
while (spacep (line))
|
||||||
|
line++;
|
||||||
|
|
||||||
|
if (keywordlen == parm->keywordlen
|
||||||
|
&& !memcmp (keyword, parm->keyword, keywordlen))
|
||||||
|
{
|
||||||
|
parm->data = unescape_status_string (line);
|
||||||
|
if (!parm->data)
|
||||||
|
parm->error = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Call the agent to retrieve a single line data object. On success
|
||||||
|
the object is malloced and stored at RESULT; it is guaranteed that
|
||||||
|
NULL is never stored in this case. On error an error code is
|
||||||
|
returned and NULL stored at RESULT. */
|
||||||
|
gpg_error_t
|
||||||
|
agent_card_getattr (ctrl_t ctrl, const char *name, char **result)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct card_getattr_parm_s parm;
|
||||||
|
char line[ASSUAN_LINELENGTH];
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
|
||||||
|
if (!*name)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
memset (&parm, 0, sizeof parm);
|
||||||
|
parm.keyword = name;
|
||||||
|
parm.keywordlen = strlen (name);
|
||||||
|
|
||||||
|
/* We assume that NAME does not need escaping. */
|
||||||
|
if (8 + strlen (name) > DIM(line)-1)
|
||||||
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
stpcpy (stpcpy (line, "GETATTR "), name);
|
||||||
|
|
||||||
|
err = start_scd (ctrl);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = map_assuan_err (assuan_transact (scd_ctx, line,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
card_getattr_cb, &parm));
|
||||||
|
if (!err && parm.error)
|
||||||
|
err = gpg_error_from_errno (parm.error);
|
||||||
|
|
||||||
|
if (!err && !parm.data)
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
*result = parm.data;
|
||||||
|
else
|
||||||
|
xfree (parm.data);
|
||||||
|
|
||||||
|
return unlock_scd (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static AssuanError
|
static AssuanError
|
||||||
|
@ -1201,7 +1201,7 @@ sexp_key_extract (gcry_sexp_t sexp,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract the car from SEXP, and create a newly created C-string it,
|
/* Extract the car from SEXP, and create a newly created C-string
|
||||||
which is to be stored in IDENTIFIER. */
|
which is to be stored in IDENTIFIER. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
sexp_extract_identifier (gcry_sexp_t sexp, const char **identifier)
|
sexp_extract_identifier (gcry_sexp_t sexp, const char **identifier)
|
||||||
@ -1404,6 +1404,7 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the public key KEY_PUBLIC to STREAM in SSH key format. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
|
ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
|
||||||
{
|
{
|
||||||
@ -1516,7 +1517,78 @@ key_secret_to_public (gcry_sexp_t *key_public,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Chec whether a smartcard is available and whether it has a usable
|
||||||
|
key. Store a copy of that key at R_PK and return 0. If no key is
|
||||||
|
available store NULL at R_PK and return an error code. */
|
||||||
|
static gpg_error_t
|
||||||
|
card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
char *appname;
|
||||||
|
unsigned char *sbuf;
|
||||||
|
size_t sbuflen;
|
||||||
|
gcry_sexp_t pk;
|
||||||
|
|
||||||
|
*r_pk = NULL;
|
||||||
|
|
||||||
|
/* First see whether a card is available and whether the application
|
||||||
|
is supported. */
|
||||||
|
err = agent_card_getattr (ctrl, "APPTYPE", &appname);
|
||||||
|
if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
|
||||||
|
{
|
||||||
|
/* Ask for the serial number to reset the card. */
|
||||||
|
err = agent_card_serialno (ctrl, &appname);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info (_("can't get serial number of card: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
log_info (_("detected card with S/N: %s\n"), appname);
|
||||||
|
xfree (appname);
|
||||||
|
err = agent_card_getattr (ctrl, "APPTYPE", &appname);
|
||||||
|
}
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error (_("error getting application type of card: %s\n"),
|
||||||
|
gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (strcmp (appname, "OPENPGP"))
|
||||||
|
{
|
||||||
|
log_info (_("card application `%s' is not supported\n"), appname);
|
||||||
|
xfree (appname);
|
||||||
|
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
|
}
|
||||||
|
xfree (appname);
|
||||||
|
appname = NULL;
|
||||||
|
|
||||||
|
/* Read the public key. */
|
||||||
|
err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL);
|
||||||
|
err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen);
|
||||||
|
xfree (sbuf);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("failed to build S-Exp from received card key: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*r_pk = pk;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Request handler.
|
Request handler.
|
||||||
@ -1589,91 +1661,95 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over key files. */
|
|
||||||
|
|
||||||
/* FIXME: make sure that buffer gets deallocated properly. */
|
|
||||||
|
/* First check whether a key is currently available in the card
|
||||||
|
reader - this should be allowed even without being listed in
|
||||||
|
sshcontrol.txt. */
|
||||||
|
|
||||||
|
if (!card_key_available (ctrl, &key_public))
|
||||||
|
{
|
||||||
|
err = ssh_send_key_public (key_blobs, key_public);
|
||||||
|
gcry_sexp_release (key_public);
|
||||||
|
key_public = NULL;
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
key_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Then look at all the registered an allowed keys. */
|
||||||
|
|
||||||
|
|
||||||
/* Fixme: We should better iterate over the control file and check
|
/* Fixme: We should better iterate over the control file and check
|
||||||
whether the key file is there. This is better in resepct to
|
whether the key file is there. This is better in resepct to
|
||||||
performance if tehre are a lot of key sin our key storage. */
|
performance if tehre are a lot of key sin our key storage. */
|
||||||
|
/* FIXME: make sure that buffer gets deallocated properly. */
|
||||||
err = open_control_file (&ctrl_fp, 0);
|
err = open_control_file (&ctrl_fp, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
#warning Really need to fix this fixme.
|
while ( (dir_entry = readdir (dir)) )
|
||||||
/*
|
|
||||||
FIXME: First check whether a key is currently available in the card reader - this should be allowed even without being listed in sshcontrol.txt.
|
|
||||||
*/
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
dir_entry = readdir (dir);
|
if ((strlen (dir_entry->d_name) == 44)
|
||||||
if (dir_entry)
|
&& (! strncmp (dir_entry->d_name + 40, ".key", 4)))
|
||||||
{
|
{
|
||||||
if ((strlen (dir_entry->d_name) == 44)
|
char hexgrip[41];
|
||||||
&& (! strncmp (dir_entry->d_name + 40, ".key", 4)))
|
int disabled;
|
||||||
{
|
|
||||||
char hexgrip[41];
|
|
||||||
int disabled;
|
|
||||||
|
|
||||||
/* We do only want to return keys listed in our control
|
/* We do only want to return keys listed in our control
|
||||||
file. */
|
file. */
|
||||||
strncpy (hexgrip, dir_entry->d_name, 40);
|
strncpy (hexgrip, dir_entry->d_name, 40);
|
||||||
hexgrip[40] = 0;
|
hexgrip[40] = 0;
|
||||||
if ( strlen (hexgrip) != 40 )
|
if ( strlen (hexgrip) != 40 )
|
||||||
continue;
|
continue;
|
||||||
if (search_control_file (ctrl_fp, hexgrip, &disabled)
|
if (search_control_file (ctrl_fp, hexgrip, &disabled)
|
||||||
|| disabled)
|
|| disabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
strncpy (key_path + key_directory_n + 1, dir_entry->d_name, 40);
|
strncpy (key_path + key_directory_n + 1, dir_entry->d_name, 40);
|
||||||
|
|
||||||
/* Read file content. */
|
/* Read file content. */
|
||||||
err = file_to_buffer (key_path, &buffer, &buffer_n);
|
err = file_to_buffer (key_path, &buffer, &buffer_n);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n);
|
err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
|
|
||||||
err = sexp_extract_identifier (key_secret, &key_type);
|
err = sexp_extract_identifier (key_secret, &key_type);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
err = ssh_key_type_lookup (NULL, key_type, &spec);
|
err = ssh_key_type_lookup (NULL, key_type, &spec);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
xfree ((void *) key_type);
|
xfree ((void *) key_type);
|
||||||
key_type = NULL;
|
key_type = NULL;
|
||||||
|
|
||||||
err = key_secret_to_public (&key_public, spec, key_secret);
|
err = key_secret_to_public (&key_public, spec, key_secret);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
gcry_sexp_release (key_secret);
|
gcry_sexp_release (key_secret);
|
||||||
key_secret = NULL;
|
key_secret = NULL;
|
||||||
|
|
||||||
err = ssh_send_key_public (key_blobs, key_public);
|
err = ssh_send_key_public (key_blobs, key_public);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
goto out;
|
||||||
|
|
||||||
gcry_sexp_release (key_public);
|
gcry_sexp_release (key_public);
|
||||||
key_public = NULL;
|
key_public = NULL;
|
||||||
|
|
||||||
key_counter++;
|
key_counter++;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = es_fseek (key_blobs, 0, SEEK_SET);
|
ret = es_fseek (key_blobs, 0, SEEK_SET);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
2005-02-24 Werner Koch <wk@g10code.com>
|
2005-02-24 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* app.c (app_getattr): Return APPTYPE or SERIALNO type even if the
|
||||||
|
application does dot support the getattr call.
|
||||||
|
|
||||||
* app-openpgp.c (get_one_do): Never try to get a non cacheable
|
* app-openpgp.c (get_one_do): Never try to get a non cacheable
|
||||||
object from the cache.
|
object from the cache.
|
||||||
(get_one_do): Add new arg to return an error code. Changed all
|
(get_one_do): Add new arg to return an error code. Changed all
|
||||||
@ -13,6 +16,7 @@
|
|||||||
been removed without a reset.
|
been removed without a reset.
|
||||||
(do_reset, cmd_serialno): Clear that error flag.
|
(do_reset, cmd_serialno): Clear that error flag.
|
||||||
(TEST_CARD_REMOVAL): New. Use it with all command handlers.
|
(TEST_CARD_REMOVAL): New. Use it with all command handlers.
|
||||||
|
(scd_update_reader_status_file): Set the error flag on all changes.
|
||||||
|
|
||||||
* scdaemon.c (ticker_thread): Termintate if a shutdown is pending.
|
* scdaemon.c (ticker_thread): Termintate if a shutdown is pending.
|
||||||
|
|
||||||
|
29
scd/app.c
29
scd/app.c
@ -305,6 +305,35 @@ app_getattr (APP app, CTRL ctrl, const char *name)
|
|||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
if (!app->initialized)
|
if (!app->initialized)
|
||||||
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||||
|
|
||||||
|
if (app->apptype && name && !strcmp (name, "APPTYPE"))
|
||||||
|
{
|
||||||
|
send_status_info (ctrl, "APPTYPE",
|
||||||
|
app->apptype, strlen (app->apptype), NULL, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (name && !strcmp (name, "SERIALNO"))
|
||||||
|
{
|
||||||
|
char *serial_and_stamp;
|
||||||
|
char *serial;
|
||||||
|
time_t stamp;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = app_get_serial_and_stamp (app, &serial, &stamp);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
rc = asprintf (&serial_and_stamp, "%s %lu",
|
||||||
|
serial, (unsigned long)stamp);
|
||||||
|
rc = (rc < 0)? gpg_error_from_errno (errno) : 0;
|
||||||
|
xfree (serial);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
send_status_info (ctrl, "SERIALNO",
|
||||||
|
serial_and_stamp, strlen (serial_and_stamp), NULL, 0);
|
||||||
|
free (serial_and_stamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!app->fnc.getattr)
|
if (!app->fnc.getattr)
|
||||||
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
||||||
return app->fnc.getattr (app, ctrl, name);
|
return app->fnc.getattr (app, ctrl, name);
|
||||||
|
@ -239,7 +239,7 @@ percent_plus_unescape (unsigned char *string)
|
|||||||
operations are done on the same card unless he calls this function.
|
operations are done on the same card unless he calls this function.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
|
cmd_serialno (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@ -248,7 +248,8 @@ cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
|
|||||||
time_t stamp;
|
time_t stamp;
|
||||||
|
|
||||||
/* Clear the remove flag so that the open_card is able to reread it. */
|
/* Clear the remove flag so that the open_card is able to reread it. */
|
||||||
ctrl->server_local->card_removed = 0;
|
if (ctrl->server_local->card_removed)
|
||||||
|
do_reset (ctrl, 0);
|
||||||
|
|
||||||
if ((rc = open_card (ctrl, *line? line:NULL)))
|
if ((rc = open_card (ctrl, *line? line:NULL)))
|
||||||
return rc;
|
return rc;
|
||||||
@ -1092,7 +1093,6 @@ cmd_checkpin (ASSUAN_CONTEXT ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Tell the assuan library about our commands */
|
/* Tell the assuan library about our commands */
|
||||||
static int
|
static int
|
||||||
@ -1299,10 +1299,6 @@ scd_update_reader_status_file (void)
|
|||||||
char templ[50];
|
char templ[50];
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
last[slot].any = 1;
|
|
||||||
last[slot].status = status;
|
|
||||||
last[slot].changed = changed;
|
|
||||||
|
|
||||||
log_info ("updating status of slot %d to 0x%04X\n", slot, status);
|
log_info ("updating status of slot %d to 0x%04X\n", slot, status);
|
||||||
|
|
||||||
sprintf (templ, "reader_%d.status", slot);
|
sprintf (templ, "reader_%d.status", slot);
|
||||||
@ -1318,7 +1314,19 @@ scd_update_reader_status_file (void)
|
|||||||
}
|
}
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
|
||||||
/* Send a signal to the primary client, if any. */
|
/* Set the card removed flag. We will set this on any
|
||||||
|
card change because a reset or SERIALNO request must be
|
||||||
|
done in any case. */
|
||||||
|
if (primary_connection && primary_connection->server_local
|
||||||
|
&& last[slot].any )
|
||||||
|
primary_connection->server_local->card_removed = 1;
|
||||||
|
|
||||||
|
last[slot].any = 1;
|
||||||
|
last[slot].status = status;
|
||||||
|
last[slot].changed = changed;
|
||||||
|
|
||||||
|
|
||||||
|
/* Send a signal to the primary client, if any. */
|
||||||
if (primary_connection && primary_connection->server_local
|
if (primary_connection && primary_connection->server_local
|
||||||
&& primary_connection->server_local->assuan_ctx)
|
&& primary_connection->server_local->assuan_ctx)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user