* command.c (cmd_updatestartuptty): New.
[gnupg.git] / scd / app.c
1 /* app.c - Application selection.
2  *      Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 # include <pth.h>
27
28 #include "scdaemon.h"
29 #include "app-common.h"
30 #include "apdu.h"
31 #include "iso7816.h"
32 #include "tlv.h"
33
34 /* This table is used to keep track of locks on a per reader base.
35    The index into the table is the slot number of the reader.  The
36    mutex will be initialized on demand (one of the advantages of a
37    userland threading system). */
38 static struct
39 {
40   int initialized;
41   pth_mutex_t lock;
42   app_t app;        /* Application context in use or NULL. */
43 } lock_table[10];
44
45
46 /* Lock the reader SLOT.  This function shall be used right before
47    calling any of the actual application functions to serialize access
48    to the reader.  We do this always even if the reader is not
49    actually used.  This allows an actual connection to assume that it
50    never shares a reader (while performing one command).  Returns 0 on
51    success; only then the unlock_reader function must be called after
52    returning from the handler. */
53 static gpg_error_t 
54 lock_reader (int slot)
55 {
56   gpg_error_t err;
57
58   if (slot < 0 || slot >= DIM (lock_table))
59     return gpg_error (slot<0? GPG_ERR_INV_VALUE : GPG_ERR_RESOURCE_LIMIT);
60
61   if (!lock_table[slot].initialized)
62     {
63       if (!pth_mutex_init (&lock_table[slot].lock))
64         {
65           err = gpg_error_from_errno (errno);
66           log_error ("error initializing mutex: %s\n", strerror (errno));
67           return err;
68         }
69       lock_table[slot].initialized = 1;
70       lock_table[slot].app = NULL;
71     }
72   
73   if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL))
74     {
75       err = gpg_error_from_errno (errno);
76       log_error ("failed to acquire APP lock for slot %d: %s\n",
77                  slot, strerror (errno));
78       return err;
79     }
80
81   return 0;
82 }
83
84 /* Release a lock on the reader.  See lock_reader(). */
85 static void
86 unlock_reader (int slot)
87 {
88   if (slot < 0 || slot >= DIM (lock_table)
89       || !lock_table[slot].initialized)
90     log_bug ("unlock_reader called for invalid slot %d\n", slot);
91
92   if (!pth_mutex_release (&lock_table[slot].lock))
93     log_error ("failed to release APP lock for slot %d: %s\n",
94                slot, strerror (errno));
95
96 }
97
98
99 static void
100 dump_mutex_state (pth_mutex_t *m)
101 {
102   if (!(m->mx_state & PTH_MUTEX_INITIALIZED))
103     log_printf ("not_initialized");
104   else if (!(m->mx_state & PTH_MUTEX_LOCKED))
105     log_printf ("not_locked");
106   else
107     log_printf ("locked tid=0x%lx count=%lu", (long)m->mx_owner, m->mx_count);
108 }
109
110
111 /* This function may be called to print information pertaining to the
112    current state of this module to the log. */
113 void
114 app_dump_state (void)
115 {
116   int slot;
117
118   for (slot=0; slot < DIM (lock_table); slot++)
119     if (lock_table[slot].initialized)
120       {
121         log_info ("app_dump_state: slot=%d lock=", slot);
122         dump_mutex_state (&lock_table[slot].lock);
123         if (lock_table[slot].app)
124           log_printf (" app=%p type=`%s'",
125                       lock_table[slot].app, lock_table[slot].app->apptype);
126         log_printf ("\n");
127       }
128 }
129
130  
131 /* Check wether the application NAME is allowed.  This does not mean
132    we have support for it though.  */
133 static int
134 is_app_allowed (const char *name)
135 {
136   strlist_t l;
137
138   for (l=opt.disabled_applications; l; l = l->next)
139     if (!strcmp (l->d, name))
140       return 0; /* no */
141   return 1; /* yes */
142 }
143
144
145 /* If called with NAME as NULL, select the best fitting application
146    and return a context; otherwise select the application with NAME
147    and return a context.  SLOT identifies the reader device. Returns
148    an error code and stores NULL at R_APP if no application was found
149    or no card is present. */
150 gpg_error_t
151 select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
152 {
153   gpg_error_t err;
154   app_t app = NULL;
155   unsigned char *result = NULL;
156   size_t resultlen;
157
158   *r_app = NULL;
159
160   err = lock_reader (slot);
161   if (err)
162     return err;
163
164   /* First check whether we already have an application to share. */
165   app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
166   if (app && name)
167     if (!app->apptype || ascii_strcasecmp (app->apptype, name))
168       {
169         unlock_reader (slot);
170         if (app->apptype)
171           log_info ("application `%s' in use by reader %d - can't switch\n",
172                     app->apptype, slot);
173         return gpg_error (GPG_ERR_CONFLICT);
174       }
175
176   if (app)
177     {
178       if (app->slot != slot)
179         log_bug ("slot mismatch %d/%d\n", app->slot, slot);
180       app->ref_count++;
181       *r_app = app;
182       unlock_reader (slot);
183       return 0; /* Okay: We share that one. */
184     }
185
186   app = xtrycalloc (1, sizeof *app);
187   if (!app)
188     {
189       err = gpg_error_from_errno (errno);
190       log_info ("error allocating context: %s\n", gpg_strerror (err));
191       unlock_reader (slot);
192       return err;
193     }
194   app->slot = slot;
195
196
197   /* Fixme: We should now first check whether a card is at all
198      present. */
199
200   /* Try to read the GDO file first to get a default serial number. */
201   err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
202   if (!err)
203     err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
204   if (!err)
205      err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
206   if (!err)
207     {
208       size_t n;
209       const unsigned char *p;
210
211       p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
212       if (p)
213         resultlen -= (p-result);
214       if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
215         {
216           /* The object it does not fit into the buffer.  This is an
217              invalid encoding (or the buffer is too short.  However, I
218              have some test cards with such an invalid encoding and
219              therefore I use this ugly workaround to return something
220              I can further experiment with. */
221           log_info ("enabling BMI testcard workaround\n");
222           n--;
223         }
224
225       if (p && n <= resultlen)
226         {
227           /* The GDO file is pretty short, thus we simply reuse it for
228              storing the serial number. */
229           memmove (result, p, n);
230           app->serialno = result;
231           app->serialnolen = n;
232           err = app_munge_serialno (app);
233           if (err)
234             goto leave;
235         }
236       else
237         xfree (result);
238       result = NULL;
239     }
240
241   /* For certain error codes, there is no need to try more.  */
242   if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
243     goto leave;
244   
245
246   /* Figure out the application to use.  */
247   err = gpg_error (GPG_ERR_NOT_FOUND);
248
249   if (err && is_app_allowed ("openpgp")
250           && (!name || !strcmp (name, "openpgp")))
251     err = app_select_openpgp (app);
252   if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
253     err = app_select_nks (app);
254   if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
255     err = app_select_p15 (app);
256   if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
257     err = app_select_dinsig (app);
258   if (err && name)
259     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
260
261  leave:
262   if (err)
263     {
264       if (name)
265         log_info ("can't select application `%s': %s\n",
266                   name, gpg_strerror (err));
267       else
268         log_info ("no supported card application found: %s\n",
269                   gpg_strerror (err));
270       xfree (app);
271       unlock_reader (slot);
272       return err;
273     }
274
275   app->initialized = 1;
276   app->ref_count = 1;
277   lock_table[slot].app = app;
278   *r_app = app;
279   unlock_reader (slot);
280   return 0;
281 }
282
283
284 /* Free the resources associated with the application APP.  APP is
285    allowed to be NULL in which case this is a no-op.  Note that we are
286    using reference counting to track the users of the application. */
287 void
288 release_application (app_t app)
289 {
290   int slot;
291
292   if (!app)
293     return;
294
295   if (app->ref_count < 1)
296     log_bug ("trying to release an already released context\n");
297   if (--app->ref_count)
298     return;
299
300   /* Clear the reference to the application from the lock table. */
301   for (slot = 0;  slot < DIM (lock_table); slot++)
302     if (lock_table[slot].initialized && lock_table[slot].app == app)
303       lock_table[slot].app = NULL;
304
305   /* Deallocate. */
306   if (app->fnc.deinit)
307     {
308       app->fnc.deinit (app);
309       app->fnc.deinit = NULL;
310     }
311
312   xfree (app->serialno);
313   xfree (app);
314 }
315
316
317
318 /* The serial number may need some cosmetics.  Do it here.  This
319    function shall only be called once after a new serial number has
320    been put into APP->serialno. 
321
322    Prefixes we use:
323    
324      FF 00 00 = For serial numbers starting with an FF
325      FF 01 00 = Some german p15 cards return an empty serial number so the
326                 serial number from the EF(TokenInfo) is used instead.
327      
328      All other serial number not starting with FF are used as they are.
329 */
330 gpg_error_t
331 app_munge_serialno (app_t app)
332 {
333   if (app->serialnolen && app->serialno[0] == 0xff)
334     { 
335       /* The serial number starts with our special prefix.  This
336          requires that we put our default prefix "FF0000" in front. */
337       unsigned char *p = xtrymalloc (app->serialnolen + 3);
338       if (!p)
339         return gpg_error (gpg_err_code_from_errno (errno));
340       memcpy (p, "\xff\0", 3);
341       memcpy (p+3, app->serialno, app->serialnolen);
342       app->serialnolen += 3;
343       xfree (app->serialno);
344       app->serialno = p;
345     }
346   return 0;
347 }
348
349
350
351 /* Retrieve the serial number and the time of the last update of the
352    card.  The serial number is returned as a malloced string (hex
353    encoded) in SERIAL and the time of update is returned in STAMP.  If
354    no update time is available the returned value is 0.  Caller must
355    free SERIAL unless the function returns an error.  If STAMP is not
356    of interest, NULL may be passed. */
357 gpg_error_t 
358 app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
359 {
360   unsigned char *buf, *p;
361   int i;
362
363   if (!app || !serial)
364     return gpg_error (GPG_ERR_INV_VALUE);
365
366   *serial = NULL;
367   if (stamp)
368     *stamp = 0; /* not available */
369
370   buf = xtrymalloc (app->serialnolen * 2 + 1);
371   if (!buf)
372     return gpg_error_from_errno (errno);
373   for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
374     sprintf (p, "%02X", app->serialno[i]);
375   *p = 0;
376   *serial = buf;
377   return 0;
378 }
379
380
381 /* Write out the application specifig status lines for the LEARN
382    command. */
383 gpg_error_t
384 app_write_learn_status (app_t app, CTRL ctrl)
385 {
386   gpg_error_t err;
387
388   if (!app)
389     return gpg_error (GPG_ERR_INV_VALUE);
390   if (!app->initialized)
391     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
392   if (!app->fnc.learn_status)
393     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
394
395   if (app->apptype)
396     send_status_info (ctrl, "APPTYPE",
397                       app->apptype, strlen (app->apptype), NULL, 0);
398   err = lock_reader (app->slot);
399   if (err)
400     return err;
401   err = app->fnc.learn_status (app, ctrl);
402   unlock_reader (app->slot);
403   return err;
404 }
405
406
407 /* Read the certificate with id CERTID (as returned by learn_status in
408    the CERTINFO status lines) and return it in the freshly allocated
409    buffer put into CERT and the length of the certificate put into
410    CERTLEN. */
411 gpg_error_t
412 app_readcert (app_t app, const char *certid,
413               unsigned char **cert, size_t *certlen)
414 {
415   gpg_error_t err;
416
417   if (!app)
418     return gpg_error (GPG_ERR_INV_VALUE);
419   if (!app->initialized)
420     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
421   if (!app->fnc.readcert)
422     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
423   err = lock_reader (app->slot);
424   if (err)
425     return err;
426   err = app->fnc.readcert (app, certid, cert, certlen);
427   unlock_reader (app->slot);
428   return err;
429 }
430
431
432 /* Read the key with ID KEYID.  On success a canonical encoded
433    S-expression with the public key will get stored at PK and its
434    length (for assertions) at PKLEN; the caller must release that
435    buffer. On error NULL will be stored at PK and PKLEN and an error
436    code returned.
437
438    This function might not be supported by all applications.  */
439 gpg_error_t
440 app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
441 {
442   gpg_error_t err;
443
444   if (pk)
445     *pk = NULL;
446   if (pklen)
447     *pklen = 0;
448
449   if (!app || !keyid || !pk || !pklen)
450     return gpg_error (GPG_ERR_INV_VALUE);
451   if (!app->initialized)
452     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
453   if (!app->fnc.readkey)
454     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
455   err = lock_reader (app->slot);
456   if (err)
457     return err;
458   err= app->fnc.readkey (app, keyid, pk, pklen);
459   unlock_reader (app->slot);
460   return err;
461 }
462
463
464 /* Perform a GETATTR operation.  */
465 gpg_error_t 
466 app_getattr (app_t app, CTRL ctrl, const char *name)
467 {
468   gpg_error_t err;
469
470   if (!app || !name || !*name)
471     return gpg_error (GPG_ERR_INV_VALUE);
472   if (!app->initialized)
473     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
474
475   if (app->apptype && name && !strcmp (name, "APPTYPE"))
476     {
477       send_status_info (ctrl, "APPTYPE",
478                         app->apptype, strlen (app->apptype), NULL, 0);
479       return 0;
480     }
481   if (name && !strcmp (name, "SERIALNO"))
482     {
483       char *serial;
484       time_t stamp;
485       int rc;
486       
487       rc = app_get_serial_and_stamp (app, &serial, &stamp);
488       if (rc)
489         return rc;
490       send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0);
491       xfree (serial);
492       return 0;
493     }
494
495   if (!app->fnc.getattr)
496     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
497   err = lock_reader (app->slot);
498   if (err)
499     return err;
500   err =  app->fnc.getattr (app, ctrl, name);
501   unlock_reader (app->slot);
502   return err;
503 }
504
505 /* Perform a SETATTR operation.  */
506 gpg_error_t 
507 app_setattr (app_t app, const char *name,
508              gpg_error_t (*pincb)(void*, const char *, char **),
509              void *pincb_arg,
510              const unsigned char *value, size_t valuelen)
511 {
512   gpg_error_t err;
513
514   if (!app || !name || !*name || !value)
515     return gpg_error (GPG_ERR_INV_VALUE);
516   if (!app->initialized)
517     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
518   if (!app->fnc.setattr)
519     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
520   err = lock_reader (app->slot);
521   if (err)
522     return err;
523   err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen);
524   unlock_reader (app->slot);
525   return err;
526 }
527
528 /* Create the signature and return the allocated result in OUTDATA.
529    If a PIN is required the PINCB will be used to ask for the PIN; it
530    should return the PIN in an allocated buffer and put it into PIN.  */
531 gpg_error_t 
532 app_sign (app_t app, const char *keyidstr, int hashalgo,
533           gpg_error_t (*pincb)(void*, const char *, char **),
534           void *pincb_arg,
535           const void *indata, size_t indatalen,
536           unsigned char **outdata, size_t *outdatalen )
537 {
538   gpg_error_t err;
539
540   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
541     return gpg_error (GPG_ERR_INV_VALUE);
542   if (!app->initialized)
543     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
544   if (!app->fnc.sign)
545     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
546   err = lock_reader (app->slot);
547   if (err)
548     return err;
549   err = app->fnc.sign (app, keyidstr, hashalgo,
550                        pincb, pincb_arg,
551                        indata, indatalen,
552                        outdata, outdatalen);
553   unlock_reader (app->slot);
554   if (opt.verbose)
555     log_info ("operation sign result: %s\n", gpg_strerror (err));
556   return err;
557 }
558
559 /* Create the signature using the INTERNAL AUTHENTICATE command and
560    return the allocated result in OUTDATA.  If a PIN is required the
561    PINCB will be used to ask for the PIN; it should return the PIN in
562    an allocated buffer and put it into PIN.  */
563 gpg_error_t 
564 app_auth (app_t app, const char *keyidstr,
565           gpg_error_t (*pincb)(void*, const char *, char **),
566           void *pincb_arg,
567           const void *indata, size_t indatalen,
568           unsigned char **outdata, size_t *outdatalen )
569 {
570   gpg_error_t err;
571
572   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
573     return gpg_error (GPG_ERR_INV_VALUE);
574   if (!app->initialized)
575     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
576   if (!app->fnc.auth)
577     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
578   err = lock_reader (app->slot);
579   if (err)
580     return err;
581   err = app->fnc.auth (app, keyidstr,
582                        pincb, pincb_arg,
583                        indata, indatalen,
584                        outdata, outdatalen);
585   unlock_reader (app->slot);
586   if (opt.verbose)
587     log_info ("operation auth result: %s\n", gpg_strerror (err));
588   return err;
589 }
590
591
592 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
593    If a PIN is required the PINCB will be used to ask for the PIN; it
594    should return the PIN in an allocated buffer and put it into PIN.  */
595 gpg_error_t 
596 app_decipher (app_t app, const char *keyidstr,
597               gpg_error_t (*pincb)(void*, const char *, char **),
598               void *pincb_arg,
599               const void *indata, size_t indatalen,
600               unsigned char **outdata, size_t *outdatalen )
601 {
602   gpg_error_t err;
603
604   if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
605     return gpg_error (GPG_ERR_INV_VALUE);
606   if (!app->initialized)
607     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
608   if (!app->fnc.decipher)
609     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
610   err = lock_reader (app->slot);
611   if (err)
612     return err;
613   err = app->fnc.decipher (app, keyidstr,
614                            pincb, pincb_arg,
615                            indata, indatalen,
616                            outdata, outdatalen);
617   unlock_reader (app->slot);
618   if (opt.verbose)
619     log_info ("operation decipher result: %s\n", gpg_strerror (err));
620   return err;
621 }
622
623
624 /* Perform the WRITEKEY operation.  */
625 gpg_error_t
626 app_writekey (app_t app, ctrl_t ctrl,
627               const char *keyidstr, unsigned int flags,
628               gpg_error_t (*pincb)(void*, const char *, char **),
629               void *pincb_arg,
630               const unsigned char *keydata, size_t keydatalen)
631 {
632   gpg_error_t err;
633
634   if (!app || !keyidstr || !*keyidstr || !pincb)
635     return gpg_error (GPG_ERR_INV_VALUE);
636   if (!app->initialized)
637     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
638   if (!app->fnc.writekey)
639     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
640   err = lock_reader (app->slot);
641   if (err)
642     return err;
643   err = app->fnc.writekey (app, ctrl, keyidstr, flags,
644                            pincb, pincb_arg, keydata, keydatalen);
645   unlock_reader (app->slot);
646   if (opt.verbose)
647     log_info ("operation writekey result: %s\n", gpg_strerror (err));
648   return err;
649
650 }
651
652
653 /* Perform a SETATTR operation.  */
654 gpg_error_t 
655 app_genkey (app_t app, CTRL ctrl, const char *keynostr, unsigned int flags,
656             gpg_error_t (*pincb)(void*, const char *, char **),
657             void *pincb_arg)
658 {
659   gpg_error_t err;
660
661   if (!app || !keynostr || !*keynostr || !pincb)
662     return gpg_error (GPG_ERR_INV_VALUE);
663   if (!app->initialized)
664     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
665   if (!app->fnc.genkey)
666     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
667   err = lock_reader (app->slot);
668   if (err)
669     return err;
670   err = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg);
671   unlock_reader (app->slot);
672   if (opt.verbose)
673     log_info ("operation genkey result: %s\n", gpg_strerror (err));
674   return err;
675 }
676
677
678 /* Perform a GET CHALLENGE operation.  This fucntion is special as it
679    directly accesses the card without any application specific
680    wrapper. */
681 gpg_error_t
682 app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer)
683 {
684   gpg_error_t err;
685
686   if (!app || !nbytes || !buffer)
687     return gpg_error (GPG_ERR_INV_VALUE);
688   if (!app->initialized)
689     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
690   err = lock_reader (app->slot);
691   if (err)
692     return err;
693   err = iso7816_get_challenge (app->slot, nbytes, buffer);
694   unlock_reader (app->slot);
695   return err;
696 }
697
698
699
700 /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation.  */
701 gpg_error_t 
702 app_change_pin (app_t app, CTRL ctrl, const char *chvnostr, int reset_mode,
703                 gpg_error_t (*pincb)(void*, const char *, char **),
704                 void *pincb_arg)
705 {
706   gpg_error_t err;
707
708   if (!app || !chvnostr || !*chvnostr || !pincb)
709     return gpg_error (GPG_ERR_INV_VALUE);
710   if (!app->initialized)
711     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
712   if (!app->fnc.change_pin)
713     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
714   err = lock_reader (app->slot);
715   if (err)
716     return err;
717   err = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode,
718                              pincb, pincb_arg);
719   unlock_reader (app->slot);
720   if (opt.verbose)
721     log_info ("operation change_pin result: %s\n", gpg_strerror (err));
722   return err;
723 }
724
725
726 /* Perform a VERIFY operation without doing anything lese.  This may
727    be used to initialze a the PIN cache for long lasting other
728    operations.  Its use is highly application dependent. */
729 gpg_error_t 
730 app_check_pin (app_t app, const char *keyidstr,
731                gpg_error_t (*pincb)(void*, const char *, char **),
732                void *pincb_arg)
733 {
734   gpg_error_t err;
735
736   if (!app || !keyidstr || !*keyidstr || !pincb)
737     return gpg_error (GPG_ERR_INV_VALUE);
738   if (!app->initialized)
739     return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
740   if (!app->fnc.check_pin)
741     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
742   err = lock_reader (app->slot);
743   if (err)
744     return err;
745   err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
746   unlock_reader (app->slot);
747   if (opt.verbose)
748     log_info ("operation check_pin result: %s\n", gpg_strerror (err));
749   return err;
750 }
751