Add a sample key.
[gnupg.git] / g10 / call-agent.c
1 /* call-agent.c - Divert GPG operations to the agent.
2  * Copyright (C) 2001, 2002, 2003, 2006, 2007, 
3  *               2008 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h> 
27 #include <time.h>
28 #include <assert.h>
29 #ifdef HAVE_LOCALE_H
30 #include <locale.h>
31 #endif
32 #include <assuan.h>
33
34 #include "gpg.h"
35 #include "util.h"
36 #include "membuf.h"
37 #include "options.h"
38 #include "i18n.h"
39 #include "asshelp.h"
40 #include "sysutils.h"
41 #include "call-agent.h"
42
43 #ifndef DBG_ASSUAN
44 # define DBG_ASSUAN 1
45 #endif
46
47 static assuan_context_t agent_ctx = NULL;
48
49 struct cipher_parm_s 
50 {
51   assuan_context_t ctx;
52   const char *ciphertext;
53   size_t ciphertextlen;
54 };
55
56 struct writecert_parm_s
57 {
58   assuan_context_t ctx;
59   const unsigned char *certdata;
60   size_t certdatalen;
61 };
62
63 struct writekey_parm_s
64 {
65   assuan_context_t ctx;
66   const unsigned char *keydata;
67   size_t keydatalen;
68 };
69
70 struct genkey_parm_s 
71 {
72   assuan_context_t ctx;
73   const char *sexp;
74   size_t sexplen;
75 };
76
77
78 \f
79 /* Try to connect to the agent via socket or fork it off and work by
80    pipes.  Handle the server's initial greeting */
81 static int
82 start_agent (void)
83 {
84   int rc;
85
86   if (agent_ctx)
87     return 0; /* Fixme: We need a context for each thread or serialize
88                  the access to the agent. */
89
90   rc = start_new_gpg_agent (&agent_ctx,
91                             GPG_ERR_SOURCE_DEFAULT,
92                             opt.homedir,
93                             opt.agent_program,
94                             opt.display, opt.ttyname, opt.ttytype,
95                             opt.lc_ctype, opt.lc_messages,
96                             opt.xauthority, opt.pinentry_user_data,
97                             opt.verbose, DBG_ASSUAN,
98                             NULL, NULL);
99   if (!rc)
100     {
101       /* Tell the agent that we support Pinentry notifications.  No
102          error checking so that it will work also with older
103          agents.  */
104       assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
105                        NULL, NULL, NULL, NULL, NULL, NULL);
106     }
107
108   return rc;
109 }
110
111
112 /* Return a new malloced string by unescaping the string S.  Escaping
113    is percent escaping and '+'/space mapping.  A binary nul will
114    silently be replaced by a 0xFF.  Function returns NULL to indicate
115    an out of memory status. */
116 static char *
117 unescape_status_string (const unsigned char *s)
118 {
119   char *buffer, *d;
120
121   buffer = d = xtrymalloc (strlen (s)+1);
122   if (!buffer)
123     return NULL;
124   while (*s)
125     {
126       if (*s == '%' && s[1] && s[2])
127         { 
128           s++;
129           *d = xtoi_2 (s);
130           if (!*d)
131             *d = '\xff';
132           d++;
133           s += 2;
134         }
135       else if (*s == '+')
136         {
137           *d++ = ' ';
138           s++;
139         }
140       else
141         *d++ = *s++;
142     }
143   *d = 0; 
144   return buffer;
145 }
146
147 /* Copy the text ATEXT into the buffer P and do plus '+' and percent
148    escaping.  Note that the provided buffer needs to be 3 times the
149    size of ATEXT plus 1.  Returns a pointer to the leading Nul in P. */
150 static char *
151 my_percent_plus_escape (char *p, const char *atext)
152 {
153   const unsigned char *s;
154
155   for (s=atext; *s; s++)
156     {
157       if (*s < ' ' || *s == '+' || *s == '%')
158         {
159           snprintf (p, 4, "%%%02X", *s);
160           p += 3;
161         }
162       else if (*s == ' ')
163         *p++ = '+';
164       else
165         *p++ = *s;
166     }
167   *p = 0;
168   return p;
169 }
170
171 /* Take a 20 byte hexencoded string and put it into the the provided
172    20 byte buffer FPR in binary format. */
173 static int
174 unhexify_fpr (const char *hexstr, unsigned char *fpr)
175 {
176   const char *s;
177   int n;
178
179   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
180     ;
181   if (*s || (n != 40))
182     return 0; /* no fingerprint (invalid or wrong length). */
183   n /= 2;
184   for (s=hexstr, n=0; *s; s += 2, n++)
185     fpr[n] = xtoi_2 (s);
186   return 1; /* okay */
187 }
188
189 /* Take the serial number from LINE and return it verbatim in a newly
190    allocated string.  We make sure that only hex characters are
191    returned. */
192 static char *
193 store_serialno (const char *line)
194 {
195   const char *s;
196   char *p;
197
198   for (s=line; hexdigitp (s); s++)
199     ;
200   p = xtrymalloc (s + 1 - line);
201   if (p)
202     {
203       memcpy (p, line, s-line);
204       p[s-line] = 0;
205     }
206   return p;
207 }
208
209
210 \f
211 /* This is a dummy data line callback.  */
212 static int
213 dummy_data_cb (void *opaque, const void *buffer, size_t length)
214 {
215   (void)opaque;
216   (void)buffer;
217   (void)length;
218   return 0;
219 }
220
221
222 /* This is the default inquiry callback.  It mainly handles the
223    Pinentry notifications.  */
224 static int
225 default_inq_cb (void *opaque, const char *line)
226 {
227   (void)opaque;
228
229   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
230     {
231       /* There is no working server mode yet thus we use
232          AllowSetForegroundWindow window right here.  We might want to
233          do this anyway in case gpg is called on the console. */
234       gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
235       /* We do not pass errors to avoid breaking other code.  */
236     }
237   else
238     log_debug ("ignoring gpg-agent inquiry `%s'\n", line);
239
240   return 0;
241 }
242
243
244
245 /* Release the card info structure INFO. */
246 void
247 agent_release_card_info (struct agent_card_info_s *info)
248 {
249   if (!info)
250     return;
251
252   xfree (info->serialno); info->serialno = NULL;
253   xfree (info->apptype); info->apptype = NULL;
254   xfree (info->disp_name); info->disp_name = NULL;
255   xfree (info->disp_lang); info->disp_lang = NULL;
256   xfree (info->pubkey_url); info->pubkey_url = NULL;
257   xfree (info->login_data); info->login_data = NULL;
258   info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
259   info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
260 }
261
262 static int
263 learn_status_cb (void *opaque, const char *line)
264 {
265   struct agent_card_info_s *parm = opaque;
266   const char *keyword = line;
267   int keywordlen;
268   int i;
269
270   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
271     ;
272   while (spacep (line))
273     line++;
274
275   if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
276     {
277       xfree (parm->serialno);
278       parm->serialno = store_serialno (line);
279       parm->is_v2 = (strlen (parm->serialno) >= 16 
280                      && xtoi_2 (parm->serialno+12) >= 2 );
281     }
282   else if (keywordlen == 7 && !memcmp (keyword, "APPTYPE", keywordlen))
283     {
284       xfree (parm->apptype);
285       parm->apptype = unescape_status_string (line);
286     }
287   else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
288     {
289       xfree (parm->disp_name);
290       parm->disp_name = unescape_status_string (line);
291     }
292   else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
293     {
294       xfree (parm->disp_lang);
295       parm->disp_lang = unescape_status_string (line);
296     }
297   else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
298     {
299       parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
300     }
301   else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
302     {
303       xfree (parm->pubkey_url);
304       parm->pubkey_url = unescape_status_string (line);
305     }
306   else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
307     {
308       xfree (parm->login_data);
309       parm->login_data = unescape_status_string (line);
310     }
311   else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
312     {
313       parm->sig_counter = strtoul (line, NULL, 0);
314     }
315   else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
316     {
317       char *p, *buf;
318
319       buf = p = unescape_status_string (line);
320       if (buf)
321         {
322           while (spacep (p))
323             p++;
324           parm->chv1_cached = atoi (p);
325           while (*p && !spacep (p))
326             p++;
327           while (spacep (p))
328             p++;
329           for (i=0; *p && i < 3; i++)
330             {
331               parm->chvmaxlen[i] = atoi (p);
332               while (*p && !spacep (p))
333                 p++;
334               while (spacep (p))
335                 p++;
336             }
337           for (i=0; *p && i < 3; i++)
338             {
339               parm->chvretry[i] = atoi (p);
340               while (*p && !spacep (p))
341                 p++;
342               while (spacep (p))
343                 p++;
344             }
345           xfree (buf);
346         }
347     }
348   else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
349     {
350       int no = atoi (line);
351       while (*line && !spacep (line))
352         line++;
353       while (spacep (line))
354         line++;
355       if (no == 1)
356         parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
357       else if (no == 2)
358         parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
359       else if (no == 3)
360         parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
361     }
362   else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
363     {
364       int no = atoi (line);
365       while (*line && !spacep (line))
366         line++;
367       while (spacep (line))
368         line++;
369       if (no == 1)
370         parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
371       else if (no == 2)
372         parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
373       else if (no == 3)
374         parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
375     }
376   
377   return 0;
378 }
379
380 /* Call the agent to learn about a smartcard */
381 int
382 agent_learn (struct agent_card_info_s *info)
383 {
384   int rc;
385
386   rc = start_agent ();
387   if (rc)
388     return rc;
389
390   memset (info, 0, sizeof *info);
391   rc = assuan_transact (agent_ctx, "LEARN --send",
392                         dummy_data_cb, NULL, default_inq_cb, NULL,
393                         learn_status_cb, info);
394   
395   return rc;
396 }
397
398 /* Call the agent to retrieve a data object.  This function returns
399    the data in the same structure as used by the learn command.  It is
400    allowed to update such a structure using this commmand. */
401 int
402 agent_scd_getattr (const char *name, struct agent_card_info_s *info)
403 {
404   int rc;
405   char line[ASSUAN_LINELENGTH];
406
407   if (!*name)
408     return gpg_error (GPG_ERR_INV_VALUE);
409
410   /* We assume that NAME does not need escaping. */
411   if (12 + strlen (name) > DIM(line)-1)
412     return gpg_error (GPG_ERR_TOO_LARGE);
413   stpcpy (stpcpy (line, "SCD GETATTR "), name); 
414
415   rc = start_agent ();
416   if (rc)
417     return rc;
418
419   rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL,
420                         learn_status_cb, info);
421   
422   return rc;
423 }
424
425 \f
426 /* Send an setattr command to the SCdaemon.  SERIALNO is not actually
427    used here but required by gpg 1.4's implementation of this code in
428    cardglue.c. */
429 int
430 agent_scd_setattr (const char *name,
431                    const unsigned char *value, size_t valuelen,
432                    const char *serialno)
433 {
434   int rc;
435   char line[ASSUAN_LINELENGTH];
436   char *p;
437
438   (void)serialno;
439
440   if (!*name || !valuelen)
441     return gpg_error (GPG_ERR_INV_VALUE);
442
443   /* We assume that NAME does not need escaping. */
444   if (12 + strlen (name) > DIM(line)-1)
445     return gpg_error (GPG_ERR_TOO_LARGE);
446       
447   p = stpcpy (stpcpy (line, "SCD SETATTR "), name); 
448   *p++ = ' ';
449   for (; valuelen; value++, valuelen--)
450     {
451       if (p >= line + DIM(line)-5 )
452         return gpg_error (GPG_ERR_TOO_LARGE);
453       if (*value < ' ' || *value == '+' || *value == '%')
454         {
455           sprintf (p, "%%%02X", *value);
456           p += 3;
457         }
458       else if (*value == ' ')
459         *p++ = '+';
460       else
461         *p++ = *value;
462     }
463   *p = 0;
464
465   rc = start_agent ();
466   if (rc)
467     return rc;
468
469   rc = assuan_transact (agent_ctx, line, NULL, NULL, 
470                         default_inq_cb, NULL, NULL, NULL);
471   return rc;
472 }
473
474
475 \f
476 /* Handle a CERTDATA inquiry.  Note, we only send the data,
477    assuan_transact takes care of flushing and writing the END
478    command. */
479 static int
480 inq_writecert_parms (void *opaque, const char *line)
481 {
482   int rc;
483   struct writecert_parm_s *parm = opaque; 
484
485   if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8]))
486     {
487       rc = assuan_send_data (parm->ctx, parm->certdata, parm->certdatalen);
488     }
489   else
490     rc = default_inq_cb (opaque, line);
491
492   return rc;
493 }
494
495
496 /* Send a WRITECERT command to the SCdaemon. */
497 int 
498 agent_scd_writecert (const char *certidstr,
499                      const unsigned char *certdata, size_t certdatalen)
500 {
501   int rc;
502   char line[ASSUAN_LINELENGTH];
503   struct writecert_parm_s parms;
504
505   rc = start_agent ();
506   if (rc)
507     return rc;
508
509   memset (&parms, 0, sizeof parms);
510
511   snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
512   line[DIM(line)-1] = 0;
513   parms.ctx = agent_ctx;
514   parms.certdata = certdata;
515   parms.certdatalen = certdatalen;
516   
517   rc = assuan_transact (agent_ctx, line, NULL, NULL,
518                         inq_writecert_parms, &parms, NULL, NULL);
519
520   return rc;
521 }
522
523
524
525 \f
526 /* Handle a KEYDATA inquiry.  Note, we only send the data,
527    assuan_transact takes care of flushing and writing the end */
528 static int
529 inq_writekey_parms (void *opaque, const char *line)
530 {
531   int rc;
532   struct writekey_parm_s *parm = opaque; 
533
534   if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
535     {
536       rc = assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
537     }
538   else
539     rc = default_inq_cb (opaque, line);
540
541   return rc;
542 }
543
544
545 /* Send a WRITEKEY command to the SCdaemon. */
546 int 
547 agent_scd_writekey (int keyno, const char *serialno,
548                     const unsigned char *keydata, size_t keydatalen)
549 {
550   int rc;
551   char line[ASSUAN_LINELENGTH];
552   struct writekey_parm_s parms;
553
554   (void)serialno;
555
556   rc = start_agent ();
557   if (rc)
558     return rc;
559
560   memset (&parms, 0, sizeof parms);
561
562   snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
563   line[DIM(line)-1] = 0;
564   parms.ctx = agent_ctx;
565   parms.keydata = keydata;
566   parms.keydatalen = keydatalen;
567   
568   rc = assuan_transact (agent_ctx, line, NULL, NULL,
569                         inq_writekey_parms, &parms, NULL, NULL);
570
571   return rc;
572 }
573
574
575
576 \f
577 /* Status callback for the SCD GENKEY command. */
578 static int
579 scd_genkey_cb (void *opaque, const char *line)
580 {
581   struct agent_card_genkey_s *parm = opaque;
582   const char *keyword = line;
583   int keywordlen;
584   gpg_error_t rc;
585
586   log_debug ("got status line `%s'\n", line);
587   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
588     ;
589   while (spacep (line))
590     line++;
591
592   if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
593     {
594       parm->fprvalid = unhexify_fpr (line, parm->fpr);
595     }
596   if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
597     {
598       gcry_mpi_t a;
599       const char *name = line;
600
601       while (*line && !spacep (line))
602         line++;
603       while (spacep (line))
604         line++;
605
606       rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
607       if (rc)
608         log_error ("error parsing received key data: %s\n", gpg_strerror (rc));
609       else if (*name == 'n' && spacep (name+1))
610         parm->n = a;
611       else if (*name == 'e' && spacep (name+1))
612         parm->e = a;
613       else
614         {
615           log_info ("unknown parameter name in received key data\n");
616           gcry_mpi_release (a);
617         }
618     }
619   else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
620     {
621       parm->created_at = (u32)strtoul (line, NULL, 10);
622     }
623
624   return 0;
625 }
626
627 /* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
628    this implementation.  If CREATEDATE has been given, it will be
629    passed to SCDAEMON so that the key can be created with this
630    timestamp; note the user needs to use the returned timestamp as old
631    versions of scddaemon don't support this option.  */
632 int
633 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
634                   const char *serialno, u32 createtime)
635 {
636   int rc;
637   char line[ASSUAN_LINELENGTH];
638   gnupg_isotime_t tbuf;
639
640   (void)serialno;
641
642   rc = start_agent ();
643   if (rc)
644     return rc;
645
646   if (createtime)
647     epoch2isotime (tbuf, createtime);
648   else
649     *tbuf = 0;
650
651   memset (info, 0, sizeof *info);
652   snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
653             *tbuf? "--timestamp=":"", tbuf,
654             force? "--force":"", 
655             keyno);
656   line[DIM(line)-1] = 0;
657
658   memset (info, 0, sizeof *info);
659   rc = assuan_transact (agent_ctx, line,
660                         NULL, NULL, default_inq_cb, NULL,
661                         scd_genkey_cb, info);
662   
663   return rc;
664 }
665
666 \f
667 static int
668 membuf_data_cb (void *opaque, const void *buffer, size_t length)
669 {
670   membuf_t *data = opaque;
671
672   if (buffer)
673     put_membuf (data, buffer, length);
674   return 0;
675 }
676   
677 /* Send a sign command to the scdaemon via gpg-agent's pass thru
678    mechanism. */
679 int
680 agent_scd_pksign (const char *serialno, int hashalgo,
681                   const unsigned char *indata, size_t indatalen,
682                   unsigned char **r_buf, size_t *r_buflen)
683 {
684   int rc, i;
685   char *p, line[ASSUAN_LINELENGTH];
686   membuf_t data;
687   size_t len;
688
689   /* Note, hashalgo is not yet used but hardwired to SHA1 in SCdaemon. */
690
691   *r_buf = NULL;
692   *r_buflen = 0;
693
694   rc = start_agent ();
695   if (rc)
696     return rc;
697
698   if (indatalen*2 + 50 > DIM(line))
699     return gpg_error (GPG_ERR_GENERAL);
700
701   sprintf (line, "SCD SETDATA ");
702   p = line + strlen (line);
703   for (i=0; i < indatalen ; i++, p += 2 )
704     sprintf (p, "%02X", indata[i]);
705   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
706   if (rc)
707     return rc;
708
709   init_membuf (&data, 1024);
710 #if 0
711   if (!hashalgo) /* Temporary test hack. */
712     snprintf (line, DIM(line)-1, "SCD PKAUTH %s", serialno);
713   else
714 #endif
715     snprintf (line, DIM(line)-1, "SCD PKSIGN %s%s",
716               hashalgo == GCRY_MD_RMD160? "--hash=rmd160 " : "",
717               serialno);
718   line[DIM(line)-1] = 0;
719   rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data,
720                         default_inq_cb, NULL, NULL, NULL);
721   if (rc)
722     {
723       xfree (get_membuf (&data, &len));
724       return rc;
725     }
726   *r_buf = get_membuf (&data, r_buflen);
727
728   return 0;
729 }
730
731
732 /* Decrypt INDATA of length INDATALEN using the card identified by
733    SERIALNO.  Return the plaintext in a nwly allocated buffer stored
734    at the address of R_BUF. 
735
736    Note, we currently support only RSA or more exactly algorithms
737    taking one input data element. */
738 int
739 agent_scd_pkdecrypt (const char *serialno,
740                      const unsigned char *indata, size_t indatalen,
741                      unsigned char **r_buf, size_t *r_buflen)
742 {
743   int rc, i;
744   char *p, line[ASSUAN_LINELENGTH];
745   membuf_t data;
746   size_t len;
747
748   *r_buf = NULL;
749   rc = start_agent ();
750   if (rc)
751     return rc;
752
753   /* FIXME: use secure memory where appropriate */
754   if (indatalen*2 + 50 > DIM(line))
755     return gpg_error (GPG_ERR_GENERAL);
756
757   sprintf (line, "SCD SETDATA ");
758   p = line + strlen (line);
759   for (i=0; i < indatalen ; i++, p += 2 )
760     sprintf (p, "%02X", indata[i]);
761   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
762   if (rc)
763     return rc;
764
765   init_membuf (&data, 1024);
766   snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
767   line[DIM(line)-1] = 0;
768   rc = assuan_transact (agent_ctx, line,
769                         membuf_data_cb, &data,
770                         default_inq_cb, NULL, NULL, NULL);
771   if (rc)
772     {
773       xfree (get_membuf (&data, &len));
774       return rc;
775     }
776   *r_buf = get_membuf (&data, r_buflen);
777   if (!*r_buf)
778     return gpg_error (GPG_ERR_ENOMEM);
779
780   return 0;
781 }
782
783
784 /* Change the PIN of an OpenPGP card or reset the retry counter.
785    CHVNO 1: Change the PIN
786          2: For v1 cards: Same as 1.
787             For v2 cards: Reset the PIN using the Reset Code.
788          3: Change the admin PIN
789        101: Set a new PIN and reset the retry counter
790        102: For v1 cars: Same as 101.
791             For v2 cards: Set a new Reset Code.
792    SERIALNO is not used.
793  */
794 int
795 agent_scd_change_pin (int chvno, const char *serialno)
796 {
797   int rc;
798   char line[ASSUAN_LINELENGTH];
799   const char *reset = "";
800
801   (void)serialno;
802
803   if (chvno >= 100)
804     reset = "--reset";
805   chvno %= 100;
806
807   rc = start_agent ();
808   if (rc)
809     return rc;
810
811   snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
812   line[DIM(line)-1] = 0;
813   rc = assuan_transact (agent_ctx, line, NULL, NULL,
814                         default_inq_cb, NULL, NULL, NULL);
815   return rc;
816 }
817
818
819 /* Perform a CHECKPIN operation.  SERIALNO should be the serial
820    number of the card - optionally followed by the fingerprint;
821    however the fingerprint is ignored here. */
822 int
823 agent_scd_checkpin  (const char *serialno)
824 {
825   int rc;
826   char line[ASSUAN_LINELENGTH];
827
828   rc = start_agent ();
829   if (rc)
830     return rc;
831
832   snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
833   line[DIM(line)-1] = 0;
834   return assuan_transact (agent_ctx, line,
835                           NULL, NULL,
836                           default_inq_cb, NULL, NULL, NULL);
837 }
838
839
840 /* Dummy function, only used by the gpg 1.4 implementation. */
841 void
842 agent_clear_pin_cache (const char *sn)
843 {
844   (void)sn;
845 }
846
847
848
849 \f
850 /* Note: All strings shall be UTF-8. On success the caller needs to
851    free the string stored at R_PASSPHRASE. On error NULL will be
852    stored at R_PASSPHRASE and an appropriate fpf error code
853    returned. */
854 gpg_error_t
855 agent_get_passphrase (const char *cache_id,
856                       const char *err_msg,
857                       const char *prompt,
858                       const char *desc_msg,
859                       char **r_passphrase)
860 {
861   int rc;
862   char *line, *p;
863   char cmd[] = "GET_PASSPHRASE --data -- ";
864   membuf_t data;
865
866   *r_passphrase = NULL;
867
868   rc = start_agent ();
869   if (rc)
870     return rc;
871
872   /* We allocate 3 times the needed space for the texts so that
873      there is enough space for escaping. */
874   line = xtrymalloc ( strlen (cmd) + 1
875                       + (cache_id? 3*strlen (cache_id): 1) + 1
876                       + (err_msg?  3*strlen (err_msg): 1) + 1
877                       + (prompt?   3*strlen (prompt): 1) + 1
878                       + (desc_msg? 3*strlen (desc_msg): 1) + 1
879                       + 1);
880   if (!line)
881     return gpg_error_from_syserror ();
882
883   p = stpcpy (line, cmd);
884   if (cache_id && *cache_id)
885     p = my_percent_plus_escape (p, cache_id);
886   else
887     *p++ = 'X';
888   *p++ = ' ';
889
890   if (err_msg && *err_msg)
891     p = my_percent_plus_escape (p, err_msg);
892   else
893     *p++ = 'X';
894   *p++ = ' ';
895
896   if (prompt && *prompt)
897     p = my_percent_plus_escape (p, prompt);
898   else
899     *p++ = 'X'; 
900   *p++ = ' ';
901
902   if (desc_msg && *desc_msg)
903     p = my_percent_plus_escape (p, desc_msg);
904   else
905     *p++ = 'X';
906   *p = 0;
907
908   init_membuf_secure (&data, 64);
909   rc = assuan_transact (agent_ctx, line, 
910                         membuf_data_cb, &data,
911                         default_inq_cb, NULL, NULL, NULL);
912
913   if (rc)
914     xfree (get_membuf (&data, NULL));
915   else 
916     {
917       put_membuf (&data, "", 1);
918       *r_passphrase = get_membuf (&data, NULL);
919       if (!*r_passphrase)
920         rc = gpg_error_from_syserror ();
921     }
922   xfree (line);
923   return rc;
924 }
925
926
927 gpg_error_t
928 agent_clear_passphrase (const char *cache_id)
929 {
930   int rc;
931   char line[ASSUAN_LINELENGTH];
932
933   if (!cache_id || !*cache_id)
934     return 0;
935
936   rc = start_agent ();
937   if (rc)
938     return rc;
939
940   snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
941   line[DIM(line)-1] = 0;
942   return assuan_transact (agent_ctx, line, NULL, NULL,
943                           default_inq_cb, NULL, NULL, NULL);
944 }