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