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