diff options
Diffstat (limited to 'agent/call-scd.c')
-rw-r--r-- | agent/call-scd.c | 133 |
1 files changed, 123 insertions, 10 deletions
diff --git a/agent/call-scd.c b/agent/call-scd.c index bffdbcbad..f7d32f7cf 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -1,5 +1,5 @@ /* 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. * @@ -66,7 +66,7 @@ static pth_mutex_t scd_lock; static int active_connection_fd = -1; static int active_connection = 0; -/* callback parameter for learn card */ +/* Callback parameter for learn card */ struct learn_parm_s { void (*kpinfo_cb)(void*, const char *); 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) 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", NULL, NULL, NULL, NULL, get_serialno_cb, &serialno); @@ -395,6 +422,8 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno) return unlock_scd (0); } + + static AssuanError 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 |