Marked all unused args on non-W32 platforms.
[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 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 == '+')
158         {
159           sprintf (p, "%%%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 the default inquiry callback.  It mainly handles the
212    Pinentry notifications.  */
213 static int
214 default_inq_cb (void *opaque, const char *line)
215 {
216   (void)opaque;
217
218   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
219     {
220       /* There is no working server mode yet thus we use
221          AllowSetForegroundWindow window right here.  We might want to
222          do this anyway in case gpg is called on the console. */
223       gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
224       /* We do not pass errors to avoid breaking other code.  */
225     }
226   else
227     log_debug ("ignoring gpg-agent inquiry `%s'\n", line);
228
229   return 0;
230 }
231
232
233
234 /* Release the card info structure INFO. */
235 void
236 agent_release_card_info (struct agent_card_info_s *info)
237 {
238   if (!info)
239     return;
240
241   xfree (info->serialno); info->serialno = NULL;
242   xfree (info->disp_name); info->disp_name = NULL;
243   xfree (info->disp_lang); info->disp_lang = NULL;
244   xfree (info->pubkey_url); info->pubkey_url = NULL;
245   xfree (info->login_data); info->login_data = NULL;
246   info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
247   info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
248 }
249
250 static int
251 learn_status_cb (void *opaque, const char *line)
252 {
253   struct agent_card_info_s *parm = opaque;
254   const char *keyword = line;
255   int keywordlen;
256   int i;
257
258   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
259     ;
260   while (spacep (line))
261     line++;
262
263   if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
264     {
265       xfree (parm->serialno);
266       parm->serialno = store_serialno (line);
267       parm->is_v2 = (strlen (parm->serialno) >= 16 
268                      && xtoi_2 (parm->serialno+12) >= 2 );
269     }
270   else if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
271     {
272       xfree (parm->disp_name);
273       parm->disp_name = unescape_status_string (line);
274     }
275   else if (keywordlen == 9 && !memcmp (keyword, "DISP-LANG", keywordlen))
276     {
277       xfree (parm->disp_lang);
278       parm->disp_lang = unescape_status_string (line);
279     }
280   else if (keywordlen == 8 && !memcmp (keyword, "DISP-SEX", keywordlen))
281     {
282       parm->disp_sex = *line == '1'? 1 : *line == '2' ? 2: 0;
283     }
284   else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
285     {
286       xfree (parm->pubkey_url);
287       parm->pubkey_url = unescape_status_string (line);
288     }
289   else if (keywordlen == 10 && !memcmp (keyword, "LOGIN-DATA", keywordlen))
290     {
291       xfree (parm->login_data);
292       parm->login_data = unescape_status_string (line);
293     }
294   else if (keywordlen == 11 && !memcmp (keyword, "SIG-COUNTER", keywordlen))
295     {
296       parm->sig_counter = strtoul (line, NULL, 0);
297     }
298   else if (keywordlen == 10 && !memcmp (keyword, "CHV-STATUS", keywordlen))
299     {
300       char *p, *buf;
301
302       buf = p = unescape_status_string (line);
303       if (buf)
304         {
305           while (spacep (p))
306             p++;
307           parm->chv1_cached = atoi (p);
308           while (*p && !spacep (p))
309             p++;
310           while (spacep (p))
311             p++;
312           for (i=0; *p && i < 3; i++)
313             {
314               parm->chvmaxlen[i] = atoi (p);
315               while (*p && !spacep (p))
316                 p++;
317               while (spacep (p))
318                 p++;
319             }
320           for (i=0; *p && i < 3; i++)
321             {
322               parm->chvretry[i] = atoi (p);
323               while (*p && !spacep (p))
324                 p++;
325               while (spacep (p))
326                 p++;
327             }
328           xfree (buf);
329         }
330     }
331   else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
332     {
333       int no = atoi (line);
334       while (*line && !spacep (line))
335         line++;
336       while (spacep (line))
337         line++;
338       if (no == 1)
339         parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
340       else if (no == 2)
341         parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
342       else if (no == 3)
343         parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
344     }
345   else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
346     {
347       int no = atoi (line);
348       while (*line && !spacep (line))
349         line++;
350       while (spacep (line))
351         line++;
352       if (no == 1)
353         parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
354       else if (no == 2)
355         parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
356       else if (no == 3)
357         parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
358     }
359   
360   return 0;
361 }
362
363 /* Call the agent to learn about a smartcard */
364 int
365 agent_learn (struct agent_card_info_s *info)
366 {
367   int rc;
368
369   rc = start_agent ();
370   if (rc)
371     return rc;
372
373   memset (info, 0, sizeof *info);
374   rc = assuan_transact (agent_ctx, "LEARN --send",
375                         NULL, NULL, default_inq_cb, NULL,
376                         learn_status_cb, info);
377   
378   return rc;
379 }
380
381 /* Call the agent to retrieve a data object.  This function returns
382    the data in the same structure as used by the learn command.  It is
383    allowed to update such a structure using this commmand. */
384 int
385 agent_scd_getattr (const char *name, struct agent_card_info_s *info)
386 {
387   int rc;
388   char line[ASSUAN_LINELENGTH];
389
390   if (!*name)
391     return gpg_error (GPG_ERR_INV_VALUE);
392
393   /* We assume that NAME does not need escaping. */
394   if (12 + strlen (name) > DIM(line)-1)
395     return gpg_error (GPG_ERR_TOO_LARGE);
396   stpcpy (stpcpy (line, "SCD GETATTR "), name); 
397
398   rc = start_agent ();
399   if (rc)
400     return rc;
401
402   rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, NULL,
403                         learn_status_cb, info);
404   
405   return rc;
406 }
407
408 \f
409 /* Send an setattr command to the SCdaemon.  SERIALNO is not actually
410    used here but required by gpg 1.4's implementation of this code in
411    cardglue.c. */
412 int
413 agent_scd_setattr (const char *name,
414                    const unsigned char *value, size_t valuelen,
415                    const char *serialno)
416 {
417   int rc;
418   char line[ASSUAN_LINELENGTH];
419   char *p;
420
421   (void)serialno;
422
423   if (!*name || !valuelen)
424     return gpg_error (GPG_ERR_INV_VALUE);
425
426   /* We assume that NAME does not need escaping. */
427   if (12 + strlen (name) > DIM(line)-1)
428     return gpg_error (GPG_ERR_TOO_LARGE);
429       
430   p = stpcpy (stpcpy (line, "SCD SETATTR "), name); 
431   *p++ = ' ';
432   for (; valuelen; value++, valuelen--)
433     {
434       if (p >= line + DIM(line)-5 )
435         return gpg_error (GPG_ERR_TOO_LARGE);
436       if (*value < ' ' || *value == '+' || *value == '%')
437         {
438           sprintf (p, "%%%02X", *value);
439           p += 3;
440         }
441       else if (*value == ' ')
442         *p++ = '+';
443       else
444         *p++ = *value;
445     }
446   *p = 0;
447
448   rc = start_agent ();
449   if (rc)
450     return rc;
451
452   rc = assuan_transact (agent_ctx, line, NULL, NULL, 
453                         default_inq_cb, NULL, NULL, NULL);
454   return rc;
455 }
456
457
458 \f
459 /* Handle a CERTDATA inquiry.  Note, we only send the data,
460    assuan_transact takes care of flushing and writing the END
461    command. */
462 static int
463 inq_writecert_parms (void *opaque, const char *line)
464 {
465   int rc;
466   struct writecert_parm_s *parm = opaque; 
467
468   if (!strncmp (line, "CERTDATA", 8) && (line[8]==' '||!line[8]))
469     {
470       rc = assuan_send_data (parm->ctx, parm->certdata, parm->certdatalen);
471     }
472   else
473     rc = default_inq_cb (opaque, line);
474
475   return rc;
476 }
477
478
479 /* Send a WRITECERT command to the SCdaemon. */
480 int 
481 agent_scd_writecert (const char *certidstr,
482                      const unsigned char *certdata, size_t certdatalen)
483 {
484   int rc;
485   char line[ASSUAN_LINELENGTH];
486   struct writecert_parm_s parms;
487
488   rc = start_agent ();
489   if (rc)
490     return rc;
491
492   memset (&parms, 0, sizeof parms);
493
494   snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
495   line[DIM(line)-1] = 0;
496   parms.ctx = agent_ctx;
497   parms.certdata = certdata;
498   parms.certdatalen = certdatalen;
499   
500   rc = assuan_transact (agent_ctx, line, NULL, NULL,
501                         inq_writecert_parms, &parms, NULL, NULL);
502
503   return rc;
504 }
505
506
507
508 \f
509 /* Handle a KEYDATA inquiry.  Note, we only send the data,
510    assuan_transact takes care of flushing and writing the end */
511 static int
512 inq_writekey_parms (void *opaque, const char *line)
513 {
514   int rc;
515   struct writekey_parm_s *parm = opaque; 
516
517   if (!strncmp (line, "KEYDATA", 7) && (line[7]==' '||!line[7]))
518     {
519       rc = assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
520     }
521   else
522     rc = default_inq_cb (opaque, line);
523
524   return rc;
525 }
526
527
528 /* Send a WRITEKEY command to the SCdaemon. */
529 int 
530 agent_scd_writekey (int keyno, const char *serialno,
531                     const unsigned char *keydata, size_t keydatalen)
532 {
533   int rc;
534   char line[ASSUAN_LINELENGTH];
535   struct writekey_parm_s parms;
536
537   (void)serialno;
538
539   rc = start_agent ();
540   if (rc)
541     return rc;
542
543   memset (&parms, 0, sizeof parms);
544
545   snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
546   line[DIM(line)-1] = 0;
547   parms.ctx = agent_ctx;
548   parms.keydata = keydata;
549   parms.keydatalen = keydatalen;
550   
551   rc = assuan_transact (agent_ctx, line, NULL, NULL,
552                         inq_writekey_parms, &parms, NULL, NULL);
553
554   return rc;
555 }
556
557
558
559 \f
560 /* Status callback for the SCD GENKEY command. */
561 static int
562 scd_genkey_cb (void *opaque, const char *line)
563 {
564   struct agent_card_genkey_s *parm = opaque;
565   const char *keyword = line;
566   int keywordlen;
567   gpg_error_t rc;
568
569   log_debug ("got status line `%s'\n", line);
570   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
571     ;
572   while (spacep (line))
573     line++;
574
575   if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
576     {
577       parm->fprvalid = unhexify_fpr (line, parm->fpr);
578     }
579   if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
580     {
581       gcry_mpi_t a;
582       const char *name = line;
583
584       while (*line && !spacep (line))
585         line++;
586       while (spacep (line))
587         line++;
588
589       rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
590       if (rc)
591         log_error ("error parsing received key data: %s\n", gpg_strerror (rc));
592       else if (*name == 'n' && spacep (name+1))
593         parm->n = a;
594       else if (*name == 'e' && spacep (name+1))
595         parm->e = a;
596       else
597         {
598           log_info ("unknown parameter name in received key data\n");
599           gcry_mpi_release (a);
600         }
601     }
602   else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
603     {
604       parm->created_at = (u32)strtoul (line, NULL, 10);
605     }
606
607   return 0;
608 }
609
610 /* Send a GENKEY command to the SCdaemon.  SERIALNO is not used in
611    this implementation.  If CREATEDATE has been given, it will be
612    passed to SCDAEMON so that the key can be created with this
613    timestamp; note the user needs to use the returned timestamp as old
614    versions of scddaemon don't support this option.  */
615 int
616 agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
617                   const char *serialno, u32 createtime)
618 {
619   int rc;
620   char line[ASSUAN_LINELENGTH];
621   gnupg_isotime_t tbuf;
622
623   (void)serialno;
624
625   rc = start_agent ();
626   if (rc)
627     return rc;
628
629   if (createtime)
630     epoch2isotime (tbuf, createtime);
631   else
632     *tbuf = 0;
633
634   memset (info, 0, sizeof *info);
635   snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
636             *tbuf? "--timestamp=":"", tbuf,
637             force? "--force":"", 
638             keyno);
639   line[DIM(line)-1] = 0;
640
641   memset (info, 0, sizeof *info);
642   rc = assuan_transact (agent_ctx, line,
643                         NULL, NULL, default_inq_cb, NULL,
644                         scd_genkey_cb, info);
645   
646   return rc;
647 }
648
649 \f
650 static int
651 membuf_data_cb (void *opaque, const void *buffer, size_t length)
652 {
653   membuf_t *data = opaque;
654
655   if (buffer)
656     put_membuf (data, buffer, length);
657   return 0;
658 }
659   
660 /* Send a sign command to the scdaemon via gpg-agent's pass thru
661    mechanism. */
662 int
663 agent_scd_pksign (const char *serialno, int hashalgo,
664                   const unsigned char *indata, size_t indatalen,
665                   unsigned char **r_buf, size_t *r_buflen)
666 {
667   int rc, i;
668   char *p, line[ASSUAN_LINELENGTH];
669   membuf_t data;
670   size_t len;
671
672   /* Note, hashalgo is not yet used but hardwired to SHA1 in SCdaemon. */
673
674   *r_buf = NULL;
675   *r_buflen = 0;
676
677   rc = start_agent ();
678   if (rc)
679     return rc;
680
681   if (indatalen*2 + 50 > DIM(line))
682     return gpg_error (GPG_ERR_GENERAL);
683
684   sprintf (line, "SCD SETDATA ");
685   p = line + strlen (line);
686   for (i=0; i < indatalen ; i++, p += 2 )
687     sprintf (p, "%02X", indata[i]);
688   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
689   if (rc)
690     return rc;
691
692   init_membuf (&data, 1024);
693 #if 0
694   if (!hashalgo) /* Temporary test hack. */
695     snprintf (line, DIM(line)-1, "SCD PKAUTH %s", serialno);
696   else
697 #endif
698     snprintf (line, DIM(line)-1, "SCD PKSIGN %s%s",
699               hashalgo == GCRY_MD_RMD160? "--hash=rmd160 " : "",
700               serialno);
701   line[DIM(line)-1] = 0;
702   rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data,
703                         default_inq_cb, NULL, NULL, NULL);
704   if (rc)
705     {
706       xfree (get_membuf (&data, &len));
707       return rc;
708     }
709   *r_buf = get_membuf (&data, r_buflen);
710
711   return 0;
712 }
713
714
715 /* Decrypt INDATA of length INDATALEN using the card identified by
716    SERIALNO.  Return the plaintext in a nwly allocated buffer stored
717    at the address of R_BUF. 
718
719    Note, we currently support only RSA or more exactly algorithms
720    taking one input data element. */
721 int
722 agent_scd_pkdecrypt (const char *serialno,
723                      const unsigned char *indata, size_t indatalen,
724                      unsigned char **r_buf, size_t *r_buflen)
725 {
726   int rc, i;
727   char *p, line[ASSUAN_LINELENGTH];
728   membuf_t data;
729   size_t len;
730
731   *r_buf = NULL;
732   rc = start_agent ();
733   if (rc)
734     return rc;
735
736   /* FIXME: use secure memory where appropriate */
737   if (indatalen*2 + 50 > DIM(line))
738     return gpg_error (GPG_ERR_GENERAL);
739
740   sprintf (line, "SCD SETDATA ");
741   p = line + strlen (line);
742   for (i=0; i < indatalen ; i++, p += 2 )
743     sprintf (p, "%02X", indata[i]);
744   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
745   if (rc)
746     return rc;
747
748   init_membuf (&data, 1024);
749   snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
750   line[DIM(line)-1] = 0;
751   rc = assuan_transact (agent_ctx, line,
752                         membuf_data_cb, &data,
753                         default_inq_cb, NULL, NULL, NULL);
754   if (rc)
755     {
756       xfree (get_membuf (&data, &len));
757       return rc;
758     }
759   *r_buf = get_membuf (&data, r_buflen);
760   if (!*r_buf)
761     return gpg_error (GPG_ERR_ENOMEM);
762
763   return 0;
764 }
765
766
767 /* Change the PIN of an OpenPGP card or reset the retry counter.
768    CHVNO 1: Change the PIN
769          2: For v1 cards: Same as 1.
770             For v2 cards: Reset the PIN using the Reset Code.
771          3: Change the admin PIN
772        101: Set a new PIN and reset the retry counter
773        102: For v1 cars: Same as 101.
774             For v2 cards: Set a new Reset Code.
775    SERIALNO is not used.
776  */
777 int
778 agent_scd_change_pin (int chvno, const char *serialno)
779 {
780   int rc;
781   char line[ASSUAN_LINELENGTH];
782   const char *reset = "";
783
784   (void)serialno;
785
786   if (chvno >= 100)
787     reset = "--reset";
788   chvno %= 100;
789
790   rc = start_agent ();
791   if (rc)
792     return rc;
793
794   snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
795   line[DIM(line)-1] = 0;
796   rc = assuan_transact (agent_ctx, line, NULL, NULL,
797                         default_inq_cb, NULL, NULL, NULL);
798   return rc;
799 }
800
801
802 /* Perform a CHECKPIN operation.  SERIALNO should be the serial
803    number of the card - optionally followed by the fingerprint;
804    however the fingerprint is ignored here. */
805 int
806 agent_scd_checkpin  (const char *serialno)
807 {
808   int rc;
809   char line[ASSUAN_LINELENGTH];
810
811   rc = start_agent ();
812   if (rc)
813     return rc;
814
815   snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
816   line[DIM(line)-1] = 0;
817   return assuan_transact (agent_ctx, line,
818                           NULL, NULL,
819                           default_inq_cb, NULL, NULL, NULL);
820 }
821
822
823 /* Dummy function, only used by the gpg 1.4 implementation. */
824 void
825 agent_clear_pin_cache (const char *sn)
826 {
827   (void)sn;
828 }
829
830
831
832 \f
833 /* Note: All strings shall be UTF-8. On success the caller needs to
834    free the string stored at R_PASSPHRASE. On error NULL will be
835    stored at R_PASSPHRASE and an appropriate fpf error code
836    returned. */
837 gpg_error_t
838 agent_get_passphrase (const char *cache_id,
839                       const char *err_msg,
840                       const char *prompt,
841                       const char *desc_msg,
842                       char **r_passphrase)
843 {
844   int rc;
845   char *line, *p;
846   char cmd[] = "GET_PASSPHRASE --data -- ";
847   membuf_t data;
848
849   *r_passphrase = NULL;
850
851   rc = start_agent ();
852   if (rc)
853     return rc;
854
855   /* We allocate 3 times the needed space for the texts so that
856      there is enough space for escaping. */
857   line = xtrymalloc ( strlen (cmd) + 1
858                       + (cache_id? 3*strlen (cache_id): 1) + 1
859                       + (err_msg?  3*strlen (err_msg): 1) + 1
860                       + (prompt?   3*strlen (prompt): 1) + 1
861                       + (desc_msg? 3*strlen (desc_msg): 1) + 1
862                       + 1);
863   if (!line)
864     return gpg_error_from_syserror ();
865
866   p = stpcpy (line, cmd);
867   if (cache_id && *cache_id)
868     p = percent_plus_escape (p, cache_id);
869   else
870     *p++ = 'X';
871   *p++ = ' ';
872
873   if (err_msg && *err_msg)
874     p = percent_plus_escape (p, err_msg);
875   else
876     *p++ = 'X';
877   *p++ = ' ';
878
879   if (prompt && *prompt)
880     p = percent_plus_escape (p, prompt);
881   else
882     *p++ = 'X'; 
883   *p++ = ' ';
884
885   if (desc_msg && *desc_msg)
886     p = percent_plus_escape (p, desc_msg);
887   else
888     *p++ = 'X';
889   *p = 0;
890
891   init_membuf_secure (&data, 64);
892   rc = assuan_transact (agent_ctx, line, 
893                         membuf_data_cb, &data,
894                         default_inq_cb, NULL, NULL, NULL);
895
896   if (rc)
897     xfree (get_membuf (&data, NULL));
898   else 
899     {
900       put_membuf (&data, "", 1);
901       *r_passphrase = get_membuf (&data, NULL);
902       if (!*r_passphrase)
903         rc = gpg_error_from_syserror ();
904     }
905   xfree (line);
906   return rc;
907 }
908
909
910 gpg_error_t
911 agent_clear_passphrase (const char *cache_id)
912 {
913   int rc;
914   char line[ASSUAN_LINELENGTH];
915
916   if (!cache_id || !*cache_id)
917     return 0;
918
919   rc = start_agent ();
920   if (rc)
921     return rc;
922
923   snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
924   line[DIM(line)-1] = 0;
925   return assuan_transact (agent_ctx, line, NULL, NULL,
926                           default_inq_cb, NULL, NULL, NULL);
927 }