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