* configure.ac: Require libksba 0.9.11.
[gnupg.git] / sm / call-dirmngr.c
1 /* call-dirmngr.c - communication with the dromngr 
2  *      Copyright (C) 2002, 2003, 2005 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
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 #include <ctype.h>
30
31 #include "gpgsm.h"
32 #include <gcrypt.h>
33 #include <assuan.h>
34
35 #include "i18n.h"
36 #include "keydb.h"
37
38 /* The name of the socket for a system daemon.  */
39 #define DEFAULT_SOCKET_NAME "/var/run/dirmngr/socket"
40
41 struct membuf {
42   size_t len;
43   size_t size;
44   char *buf;
45   int out_of_core;
46 };
47
48
49
50 static ASSUAN_CONTEXT dirmngr_ctx = NULL;
51 static int force_pipe_server = 0;
52
53 struct inq_certificate_parm_s {
54   ASSUAN_CONTEXT ctx;
55   ksba_cert_t cert;
56   ksba_cert_t issuer_cert;
57 };
58
59 struct isvalid_status_parm_s {
60   CTRL ctrl;
61   int seen;
62   unsigned char fpr[20];
63 };
64
65
66 struct lookup_parm_s {
67   CTRL ctrl;
68   ASSUAN_CONTEXT ctx;
69   void (*cb)(void *, ksba_cert_t);
70   void *cb_value;
71   struct membuf data;
72   int error;
73 };
74
75 struct run_command_parm_s {
76   ASSUAN_CONTEXT ctx;
77 };
78
79
80 /* A simple implementation of a dynamic buffer.  Use init_membuf() to
81    create a buffer, put_membuf to append bytes and get_membuf to
82    release and return the buffer.  Allocation errors are detected but
83    only returned at the final get_membuf(), this helps not to clutter
84    the code with out of core checks.  */
85
86 static void
87 init_membuf (struct membuf *mb, int initiallen)
88 {
89   mb->len = 0;
90   mb->size = initiallen;
91   mb->out_of_core = 0;
92   mb->buf = xtrymalloc (initiallen);
93   if (!mb->buf)
94       mb->out_of_core = 1;
95 }
96
97 static void
98 put_membuf (struct membuf *mb, const void *buf, size_t len)
99 {
100   if (mb->out_of_core)
101     return;
102
103   if (mb->len + len >= mb->size)
104     {
105       char *p;
106       
107       mb->size += len + 1024;
108       p = xtryrealloc (mb->buf, mb->size);
109       if (!p)
110         {
111           mb->out_of_core = 1;
112           return;
113         }
114       mb->buf = p;
115     }
116   memcpy (mb->buf + mb->len, buf, len);
117   mb->len += len;
118 }
119
120 static void *
121 get_membuf (struct membuf *mb, size_t *len)
122 {
123   char *p;
124
125   if (mb->out_of_core)
126     {
127       xfree (mb->buf);
128       mb->buf = NULL;
129       return NULL;
130     }
131
132   p = mb->buf;
133   *len = mb->len;
134   mb->buf = NULL;
135   mb->out_of_core = 1; /* don't allow a reuse */
136   return p;
137 }
138
139
140
141
142 \f
143 /* Try to connect to the agent via socket or fork it off and work by
144    pipes.  Handle the server's initial greeting */
145 static int
146 start_dirmngr (void)
147 {
148   int rc;
149   char *infostr, *p;
150   ASSUAN_CONTEXT ctx;
151   int try_default = 0;
152
153   if (dirmngr_ctx)
154     return 0; /* fixme: We need a context for each thread or serialize
155                  the access to the dirmngr */
156   /* Note: if you change this to multiple connections, you also need
157      to take care of the implicit option sending caching. */
158
159   infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
160   if (opt.prefer_system_dirmngr && !force_pipe_server
161       &&(!infostr || !*infostr))
162     {
163       infostr = DEFAULT_SOCKET_NAME;
164       try_default = 1;
165     }
166   if (!infostr || !*infostr)
167     {
168       const char *pgmname;
169       const char *argv[3];
170       int no_close_list[3];
171       int i;
172
173       if (opt.verbose)
174         log_info (_("no running dirmngr - starting one\n"));
175       
176       if (fflush (NULL))
177         {
178           gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
179           log_error ("error flushing pending output: %s\n", strerror (errno));
180           return tmperr;
181         }
182
183       if (!opt.dirmngr_program || !*opt.dirmngr_program)
184         opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
185       if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
186         pgmname = opt.dirmngr_program;
187       else
188         pgmname++;
189
190       argv[0] = pgmname;
191       argv[1] = "--server";
192       argv[2] = NULL;
193
194       i=0;
195       if (log_get_fd () != -1)
196         no_close_list[i++] = log_get_fd ();
197       no_close_list[i++] = fileno (stderr);
198       no_close_list[i] = -1;
199
200       /* connect to the agent and perform initial handshaking */
201       rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
202                                 no_close_list);
203     }
204   else
205     {
206       int prot;
207       int pid;
208
209       infostr = xstrdup (infostr);
210       if (!try_default && *infostr)
211         {
212           if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
213             {
214               log_error (_("malformed DIRMNGR_INFO environment variable\n"));
215               xfree (infostr);
216               force_pipe_server = 1;
217               return start_dirmngr ();
218             }
219           *p++ = 0;
220           pid = atoi (p);
221           while (*p && *p != PATHSEP_C)
222             p++;
223           prot = *p? atoi (p+1) : 0;
224           if (prot != 1)
225             {
226               log_error (_("dirmngr protocol version %d is not supported\n"),
227                          prot);
228               xfree (infostr);
229               force_pipe_server = 1;
230               return start_dirmngr ();
231             }
232         }
233       else
234         pid = -1;
235
236       rc = assuan_socket_connect (&ctx, infostr, pid);
237       xfree (infostr);
238       if (rc == ASSUAN_Connect_Failed)
239         {
240           log_error (_("can't connect to the dirmngr - trying fall back\n"));
241           force_pipe_server = 1;
242           return start_dirmngr ();
243         }
244     }
245
246   if (rc)
247     {
248       log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
249       return gpg_error (GPG_ERR_NO_DIRMNGR);
250     }
251   dirmngr_ctx = ctx;
252
253   if (DBG_ASSUAN)
254     log_debug ("connection to dirmngr established\n");
255   return 0;
256 }
257
258
259 \f
260 /* Handle a SENDCERT inquiry. */
261 static AssuanError
262 inq_certificate (void *opaque, const char *line)
263 {
264   struct inq_certificate_parm_s *parm = opaque;
265   AssuanError rc;
266   const unsigned char *der;
267   size_t derlen;
268   int issuer_mode = 0;
269   ksba_sexp_t ski = NULL;
270
271   if (!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]))
272     {
273       line += 8;
274     }
275   else if (!strncmp (line, "SENDCERT_SKI", 12) && (line[12]==' ' || !line[12]))
276     {
277       size_t n;
278
279       /* Send a certificate where a sourceKeyidentifier is included. */
280       line += 12;
281       while (*line == ' ')
282         line++;
283       ski = make_simple_sexp_from_hexstr (line, &n);
284       line += n;
285       while (*line == ' ')
286         line++;
287     }
288   else if (!strncmp (line, "SENDISSUERCERT", 14)
289            && (line[14] == ' ' || !line[14]))
290     {
291       line += 14;
292       issuer_mode = 1;
293     }
294   else
295     {
296       log_error ("unsupported inquiry `%s'\n", line);
297       return ASSUAN_Inquire_Unknown;
298     }
299
300   if (!*line)
301     { /* Send the current certificate. */
302       der = ksba_cert_get_image (issuer_mode? parm->issuer_cert : parm->cert,
303                                  &derlen);
304       if (!der)
305         rc = ASSUAN_Inquire_Error;
306       else
307         rc = assuan_send_data (parm->ctx, der, derlen);
308     }
309   else if (issuer_mode)
310     {
311       log_error ("sending specific issuer certificate back "
312                  "is not yet implemented\n");
313       rc = ASSUAN_Inquire_Error;
314     }
315   else 
316     { /* Send the given certificate. */
317       int err;
318       ksba_cert_t cert;
319
320
321       err = gpgsm_find_cert (line, ski, &cert);
322       if (err)
323         {
324           log_error ("certificate not found: %s\n", gpg_strerror (err));
325           rc = ASSUAN_Inquire_Error;
326         }
327       else
328         {
329           der = ksba_cert_get_image (cert, &derlen);
330           if (!der)
331             rc = ASSUAN_Inquire_Error;
332           else
333             rc = assuan_send_data (parm->ctx, der, derlen);
334           ksba_cert_release (cert);
335         }
336     }
337
338   xfree (ski);
339   return rc; 
340 }
341
342
343 /* Take a 20 byte hexencoded string and put it into the the provided
344    20 byte buffer FPR in binary format. */
345 static int
346 unhexify_fpr (const char *hexstr, unsigned char *fpr)
347 {
348   const char *s;
349   int n;
350
351   for (s=hexstr, n=0; hexdigitp (s); s++, n++)
352     ;
353   if (*s || (n != 40))
354     return 0; /* no fingerprint (invalid or wrong length). */
355   n /= 2;
356   for (s=hexstr, n=0; *s; s += 2, n++)
357     fpr[n] = xtoi_2 (s);
358   return 1; /* okay */
359 }
360
361
362 static assuan_error_t
363 isvalid_status_cb (void *opaque, const char *line)
364 {
365   struct isvalid_status_parm_s *parm = opaque;
366
367   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
368     {
369       if (parm->ctrl)
370         {
371           for (line += 8; *line == ' '; line++)
372             ;
373           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
374             return ASSUAN_Canceled;
375         }
376     }
377   else if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
378       && (line[24]==' ' || !line[24]))
379     {
380       parm->seen++;
381       if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
382         parm->seen++; /* Bumb it to indicate an error. */
383     }
384   return 0;
385 }
386
387
388
389 \f
390 /* Call the directory manager to check whether the certificate is valid
391    Returns 0 for valid or usually one of the errors:
392
393   GPG_ERR_CERTIFICATE_REVOKED
394   GPG_ERR_NO_CRL_KNOWN
395   GPG_ERR_CRL_TOO_OLD
396
397   With USE_OCSP set to true, the dirmngr is asked to do an OCSP
398   request first.
399  */
400 int
401 gpgsm_dirmngr_isvalid (ctrl_t ctrl,
402                        ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
403 {
404   static int did_options;
405   int rc;
406   char *certid;
407   char line[ASSUAN_LINELENGTH];
408   struct inq_certificate_parm_s parm;
409   struct isvalid_status_parm_s stparm;
410
411
412   rc = start_dirmngr ();
413   if (rc)
414     return rc;
415
416   if (use_ocsp)
417     {
418       certid = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
419     }
420   else
421     {
422       certid = gpgsm_get_certid (cert);
423       if (!certid)
424         {
425           log_error ("error getting the certificate ID\n");
426           return gpg_error (GPG_ERR_GENERAL);
427         }
428     }
429
430   if (opt.verbose > 1)
431     {
432       char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
433       log_info ("asking dirmngr about %s%s\n", fpr,
434                 use_ocsp? " (using OCSP)":"");
435       xfree (fpr);
436     }
437
438   parm.ctx = dirmngr_ctx;
439   parm.cert = cert;
440   parm.issuer_cert = issuer_cert;
441
442   stparm.ctrl = ctrl;
443   stparm.seen = 0;
444   memset (stparm.fpr, 0, 20);
445
446   /* FIXME: If --disable-crl-checks has been set, we should pass an
447      option to dirmngr, so that no fallback CRL check is done after an
448      ocsp check. */
449
450   /* It is sufficient to send the options only once because we have
451      one connection per process only. */
452   if (!did_options)
453     {
454       if (opt.force_crl_refresh)
455         assuan_transact (dirmngr_ctx, "OPTION force-crl-refresh=1",
456                          NULL, NULL, NULL, NULL, NULL, NULL);
457       did_options = 1;
458     }
459   snprintf (line, DIM(line)-1, "ISVALID %s", certid);
460   line[DIM(line)-1] = 0;
461   xfree (certid);
462
463   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
464                         inq_certificate, &parm,
465                         isvalid_status_cb, &stparm);
466   if (opt.verbose > 1)
467     log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
468   rc = map_assuan_err (rc);
469
470   if (!rc && stparm.seen)
471     {
472       /* Need to also check the certificate validity. */
473       if (stparm.seen != 1)
474         {
475           log_error ("communication problem with dirmngr detected\n");
476           rc = gpg_error (GPG_ERR_INV_CRL);
477         }
478       else
479         {
480           KEYDB_HANDLE kh;
481           ksba_cert_t rspcert = NULL;
482
483           /* Fixme: First try to get the certificate from the
484              dirmngr's cache - it should be there. */
485           kh = keydb_new (0);
486           if (!kh)
487             rc = gpg_error (GPG_ERR_ENOMEM);
488           if (!rc)
489             rc = keydb_search_fpr (kh, stparm.fpr);
490           if (!rc)
491             rc = keydb_get_cert (kh, &rspcert);
492           if (rc)
493             {
494               log_error ("unable to find the certificate used "
495                          "by the dirmngr: %s\n", gpg_strerror (rc));
496               rc = gpg_error (GPG_ERR_INV_CRL);
497             }
498           keydb_release (kh);
499
500           if (!rc)
501             {
502               rc = gpgsm_cert_use_ocsp_p (rspcert);
503               if (rc)
504                 rc = gpg_error (GPG_ERR_INV_CRL);
505               else
506                 {
507                   /* Note, the flag = 1: This avoids checking this
508                      certificate over and over again. */
509                   rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
510                   if (rc)
511                     {
512                       log_error ("invalid certificate used for CRL/OCSP: %s\n",
513                                  gpg_strerror (rc));
514                       rc = gpg_error (GPG_ERR_INV_CRL);
515                     }
516                 }
517             }
518           ksba_cert_release (rspcert);
519         }
520     }
521   return rc;
522 }
523
524
525 \f
526 /* Lookup helpers*/
527 static AssuanError
528 lookup_cb (void *opaque, const void *buffer, size_t length)
529 {
530   struct lookup_parm_s *parm = opaque;
531   size_t len;
532   char *buf;
533   ksba_cert_t cert;
534   int rc;
535
536   if (parm->error)
537     return 0;
538
539   if (buffer)
540     {
541       put_membuf (&parm->data, buffer, length);
542       return 0;
543     }
544   /* END encountered - process what we have */
545   buf = get_membuf (&parm->data, &len);
546   if (!buf)
547     {
548       parm->error = gpg_error (GPG_ERR_ENOMEM);
549       return 0;
550     }
551
552   rc = ksba_cert_new (&cert);
553   if (rc)
554     {
555       parm->error = rc;
556       return 0;
557     }
558   rc = ksba_cert_init_from_mem (cert, buf, len);
559   if (rc)
560     {
561       log_error ("failed to parse a certificate: %s\n", gpg_strerror (rc));
562     }
563   else
564     {
565       parm->cb (parm->cb_value, cert);
566     }
567
568   ksba_cert_release (cert);
569   init_membuf (&parm->data, 4096);
570   return 0;
571 }
572
573 /* Return a properly escaped pattern from NAMES.  The only error
574    return is NULL to indicate a malloc failure. */
575 static char *
576 pattern_from_strlist (STRLIST names)
577 {
578   STRLIST sl;
579   int n;
580   const char *s;
581   char *pattern, *p;
582
583   for (n=0, sl=names; sl; sl = sl->next)
584     {
585       for (s=sl->d; *s; s++, n++)
586         {
587           if (*s == '%' || *s == ' ' || *s == '+')
588             n += 2;
589         }
590       n++;
591     }
592
593   p = pattern = xtrymalloc (n+1);
594   if (!pattern)
595     return NULL;
596
597   for (n=0, sl=names; sl; sl = sl->next)
598     {
599       for (s=sl->d; *s; s++)
600         {
601           switch (*s)
602             {
603             case '%':
604               *p++ = '%';
605               *p++ = '2';
606               *p++ = '5';
607               break;
608             case ' ':
609               *p++ = '%';
610               *p++ = '2';
611               *p++ = '0';
612               break;
613             case '+':
614               *p++ = '%';
615               *p++ = '2';
616               *p++ = 'B';
617               break;
618             default:
619               *p++ = *s;
620               break;
621             }
622         }
623       *p++ = ' ';
624     }
625   if (p == pattern)
626     *pattern = 0; /* is empty */
627   else
628     p[-1] = '\0'; /* remove trailing blank */
629   
630   return pattern;
631 }
632
633 static AssuanError
634 lookup_status_cb (void *opaque, const char *line)
635 {
636   struct lookup_parm_s *parm = opaque;
637
638   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
639     {
640       if (parm->ctrl)
641         {
642           for (line += 8; *line == ' '; line++)
643             ;
644           if (gpgsm_status (parm->ctrl, STATUS_PROGRESS, line))
645             return ASSUAN_Canceled;
646         }
647     }
648   else if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
649     {
650       if (parm->ctrl)
651         {
652           for (line +=9; *line == ' '; line++)
653             ;
654           gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
655         }
656     }
657   return 0;
658 }
659
660
661 /* Run the Directroy Managers lookup command using the pattern
662    compiled from the strings given in NAMES.  The caller must provide
663    the callback CB which will be passed cert by cert.  Note that CTRL
664    is optional. */
665 int 
666 gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
667                       void (*cb)(void*, ksba_cert_t), void *cb_value)
668
669   int rc;
670   char *pattern;
671   char line[ASSUAN_LINELENGTH];
672   struct lookup_parm_s parm;
673   size_t len;
674
675   rc = start_dirmngr ();
676   if (rc)
677     return rc;
678
679   pattern = pattern_from_strlist (names);
680   if (!pattern)
681     return OUT_OF_CORE (errno);
682   snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
683   line[DIM(line)-1] = 0;
684   xfree (pattern);
685
686   parm.ctrl = ctrl;
687   parm.ctx = dirmngr_ctx;
688   parm.cb = cb;
689   parm.cb_value = cb_value;
690   parm.error = 0;
691   init_membuf (&parm.data, 4096);
692
693   rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
694                         NULL, NULL, lookup_status_cb, &parm);
695   xfree (get_membuf (&parm.data, &len));
696   if (rc)
697     return map_assuan_err (rc);
698   return parm.error;
699 }
700
701
702 \f
703 /* Run Command helpers*/
704
705 /* Fairly simple callback to write all output of dirmngr to stdout. */
706 static AssuanError
707 run_command_cb (void *opaque, const void *buffer, size_t length)
708 {
709   if (buffer)
710     {
711       if ( fwrite (buffer, length, 1, stdout) != 1 )
712         log_error ("error writing to stdout: %s\n", strerror (errno));
713     }
714   return 0;
715 }
716
717 /* Handle inquiries from the dirmngr COMMAND. */
718 static AssuanError
719 run_command_inq_cb (void *opaque, const char *line)
720 {
721   struct run_command_parm_s *parm = opaque;
722   AssuanError rc = 0;
723
724   if ( !strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8]) )
725     { /* send the given certificate */
726       int err;
727       ksba_cert_t cert;
728       const unsigned char *der;
729       size_t derlen;
730
731       line += 8;
732       if (!*line)
733         return ASSUAN_Inquire_Error;
734
735       err = gpgsm_find_cert (line, NULL, &cert);
736       if (err)
737         {
738           log_error ("certificate not found: %s\n", gpg_strerror (err));
739           rc = ASSUAN_Inquire_Error;
740         }
741       else
742         {
743           der = ksba_cert_get_image (cert, &derlen);
744           if (!der)
745             rc = ASSUAN_Inquire_Error;
746           else
747             rc = assuan_send_data (parm->ctx, der, derlen);
748           ksba_cert_release (cert);
749         }
750     }
751   else if ( !strncmp (line, "PRINTINFO", 9) && (line[9] == ' ' || !line[9]) )
752     { /* Simply show the message given in the argument. */
753       line += 9;
754       log_info ("dirmngr: %s\n", line);
755     }
756   else
757     {
758       log_error ("unsupported inquiry `%s'\n", line);
759       rc = ASSUAN_Inquire_Unknown;
760     }
761
762   return rc; 
763 }
764
765 static AssuanError
766 run_command_status_cb (void *opaque, const char *line)
767 {
768   ctrl_t ctrl = opaque;
769
770   if (opt.verbose)
771     {
772       log_info ("dirmngr status: %s\n", line);
773     }
774   if (!strncmp (line, "PROGRESS", 8) && (line[8]==' ' || !line[8]))
775     {
776       if (ctrl)
777         {
778           for (line += 8; *line == ' '; line++)
779             ;
780           if (gpgsm_status (ctrl, STATUS_PROGRESS, line))
781             return ASSUAN_Canceled;
782         }
783     }
784   return 0;
785 }
786
787
788
789 /* Pass COMMAND to dirmngr and print all output generated by Dirmngr
790    to stdout.  A couple of inquiries are defined (see above).  ARGC
791    arguments in ARGV are given to the Dirmngr.  Spaces, plus and
792    percent characters within the argument strings are percent escaped
793    so that blanks can act as delimiters. */
794 int
795 gpgsm_dirmngr_run_command (CTRL ctrl, const char *command,
796                            int argc, char **argv)
797
798   int rc;
799   int i;
800   const char *s;
801   char *line, *p;
802   size_t len;
803   struct run_command_parm_s parm;
804
805   rc = start_dirmngr ();
806   if (rc)
807     return rc;
808
809   parm.ctx = dirmngr_ctx;
810
811   len = strlen (command) + 1;
812   for (i=0; i < argc; i++)
813     len += 1 + 3*strlen (argv[i]); /* enough space for percent escaping */
814   line = xtrymalloc (len);
815   if (!line)
816     return OUT_OF_CORE (errno);
817
818   p = stpcpy (line, command);
819   for (i=0; i < argc; i++)
820     {
821       *p++ = ' ';
822       for (s=argv[i]; *s; s++)
823         {
824           if (!isascii (*s))
825             *p++ = *s;
826           else if (*s == ' ')
827             *p++ = '+';
828           else if (!isprint (*s) || *s == '+')
829             {
830               sprintf (p, "%%%02X", *s);
831               p += 3;
832             }
833           else
834             *p++ = *s;
835         }
836     }
837   *p = 0;
838
839   rc = assuan_transact (dirmngr_ctx, line,
840                         run_command_cb, NULL,
841                         run_command_inq_cb, &parm,
842                         run_command_status_cb, ctrl);
843   xfree (line);
844   log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
845   return map_assuan_err (rc);
846 }