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