Merged Dirmngr with GnuPG.
[gnupg.git] / dirmngr / server.c
1 /* dirmngr.c - LDAP access
2  *      Copyright (C) 2002 Klarälvdalens Datakonsult AB
3  *      Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 g10 Code GmbH
4  *
5  * This file is part of DirMngr.
6  *
7  * DirMngr is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * DirMngr is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 #define JNLIB_NEED_LOG_LOGV
33 #include "dirmngr.h"
34 #include <assuan.h>
35
36 #include "crlcache.h"
37 #include "crlfetch.h"
38 #include "ldapserver.h"
39 #include "ocsp.h"
40 #include "certcache.h"
41 #include "validate.h"
42 #include "misc.h"
43
44 /* To avoid DoS attacks we limit the size of a certificate to
45    something reasonable. */
46 #define MAX_CERT_LENGTH (8*1024)
47
48 #define PARM_ERROR(t) assuan_set_error (ctx, \
49                                         gpg_error (GPG_ERR_ASS_PARAMETER), (t))
50
51
52
53 /* Control structure per connection. */
54 struct server_local_s 
55 {
56   /* Data used to associate an Assuan context with local server data */
57   assuan_context_t assuan_ctx;
58
59   /* Per-session LDAP serfver.  */
60   ldap_server_t ldapservers;
61 };
62
63
64
65 \f
66 /* Accessor for the local ldapservers variable. */
67 ldap_server_t
68 get_ldapservers_from_ctrl (ctrl_t ctrl)
69 {
70   if (ctrl && ctrl->server_local)
71     return ctrl->server_local->ldapservers;
72   else
73     return NULL;
74 }
75
76
77
78 /* Copy the % and + escaped string S into the buffer D and replace the
79    escape sequences.  Note, that it is sufficient to allocate the
80    target string D as long as the source string S, i.e.: strlen(s)+1.
81    NOte further that If S contains an escaped binary nul the resulting
82    string D will contain the 0 as well as all other characters but it
83    will be impossible to know whether this is the original EOS or a
84    copied Nul. */
85 static void
86 strcpy_escaped_plus (char *d, const unsigned char *s)
87 {
88   while (*s)
89     {
90       if (*s == '%' && s[1] && s[2])
91         {
92           s++;
93           *d++ = xtoi_2 ( s);
94           s += 2;
95         }
96       else if (*s == '+')
97         *d++ = ' ', s++;
98       else
99         *d++ = *s++;
100     }
101   *d = 0;
102 }
103
104
105 /* Check whether the option NAME appears in LINE */
106 static int
107 has_option (const char *line, const char *name)
108 {
109   const char *s;
110   int n = strlen (name);
111
112   s = strstr (line, name);
113   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
114 }
115
116 /* Same as has_option but only considers options at the begin of the
117    line.  This is useful for commands which allow arbitrary strings on
118    the line.  */
119 static int
120 has_leading_option (const char *line, const char *name)
121 {
122   const char *s;
123   int n;
124
125   if (name[0] != '-' || name[1] != '-' || !name[2] || spacep (name+2))
126     return 0;
127   n = strlen (name);
128   while ( *line == '-' && line[1] == '-' )
129     {
130       s = line;
131       while (*line && !spacep (line))
132         line++;
133       if (n == (line - s) && !strncmp (s, name, n))
134         return 1;
135       while (spacep (line))
136         line++;
137     }
138   return 0;
139 }
140
141
142 /* Same as has_option but does only test for the name of the option
143    and ignores an argument, i.e. with NAME being "--hash" it would
144    return a pointer for "--hash" as well as for "--hash=foo".  If
145    thhere is no such option NULL is returned.  The pointer returned
146    points right behind the option name, this may be an equal sign, Nul
147    or a space.  */
148 /* static const char * */
149 /* has_option_name (const char *line, const char *name) */
150 /* { */
151 /*   const char *s; */
152 /*   int n = strlen (name); */
153
154 /*   s = strstr (line, name); */
155 /*   return (s && (s == line || spacep (s-1)) */
156 /*           && (!s[n] || spacep (s+n) || s[n] == '=')) ? (s+n) : NULL; */
157 /* } */
158
159
160 /* Skip over options.  It is assumed that leading spaces have been
161    removed (this is the case for lines passed to a handler from
162    assuan).  Blanks after the options are also removed. */
163 static char *
164 skip_options (char *line)
165 {
166   while ( *line == '-' && line[1] == '-' )
167     {
168       while (*line && !spacep (line))
169         line++;
170       while (spacep (line))
171         line++;
172     }
173   return line;
174 }
175
176
177 /* Common code for get_cert_local and get_issuer_cert_local. */
178 static ksba_cert_t 
179 do_get_cert_local (ctrl_t ctrl, const char *name, const char *command)
180 {
181   unsigned char *value;
182   size_t valuelen; 
183   int rc;
184   char *buf;
185   ksba_cert_t cert;
186
187   if (name)
188     {
189       buf = xmalloc ( strlen (command) + 1 + strlen(name) + 1);
190       strcpy (stpcpy (stpcpy (buf, command), " "), name);
191     }
192   else
193     buf = xstrdup (command);
194
195   rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
196                        &value, &valuelen, MAX_CERT_LENGTH);
197   xfree (buf);
198   if (rc)
199     {
200       log_error (_("assuan_inquire(%s) failed: %s\n"),
201                  command, gpg_strerror (rc));
202       return NULL;
203     }
204   
205   if (!valuelen)
206     {
207       xfree (value);
208       return NULL;
209     }
210
211   rc = ksba_cert_new (&cert);
212   if (!rc)
213     {
214       rc = ksba_cert_init_from_mem (cert, value, valuelen);
215       if (rc)
216         {
217           ksba_cert_release (cert);
218           cert = NULL;
219         }
220     }
221   xfree (value);
222   return cert;
223 }
224
225
226
227 /* Ask back to return a certificate for name, given as a regular
228    gpgsm certificate indentificates (e.g. fingerprint or one of the
229    other methods).  Alternatively, NULL may be used for NAME to
230    return the current target certificate. Either return the certificate
231    in a KSBA object or NULL if it is not available.
232 */
233 ksba_cert_t 
234 get_cert_local (ctrl_t ctrl, const char *name)
235 {
236   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
237     {
238       if (opt.debug)
239         log_debug ("get_cert_local called w/o context\n");
240       return NULL;
241     }
242   return do_get_cert_local (ctrl, name, "SENDCERT");
243
244 }
245        
246 /* Ask back to return the issuing certificate for name, given as a
247    regular gpgsm certificate indentificates (e.g. fingerprint or one
248    of the other methods).  Alternatively, NULL may be used for NAME to
249    return thecurrent target certificate. Either return the certificate
250    in a KSBA object or NULL if it is not available.
251    
252 */
253 ksba_cert_t 
254 get_issuing_cert_local (ctrl_t ctrl, const char *name)
255 {
256   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
257     {
258       if (opt.debug)
259         log_debug ("get_issuing_cert_local called w/o context\n");
260       return NULL;
261     }
262   return do_get_cert_local (ctrl, name, "SENDISSUERCERT");
263 }
264
265 /* Ask back to return a certificate with subject NAME and a
266    subjectKeyIdentifier of KEYID. */
267 ksba_cert_t 
268 get_cert_local_ski (ctrl_t ctrl, const char *name, ksba_sexp_t keyid)
269 {
270   unsigned char *value;
271   size_t valuelen; 
272   int rc;
273   char *buf;
274   ksba_cert_t cert;
275   char *hexkeyid;
276
277   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx)
278     {
279       if (opt.debug)
280         log_debug ("get_cert_local_ski called w/o context\n");
281       return NULL;
282     }
283   if (!name || !keyid)
284     {
285       log_debug ("get_cert_local_ski called with insufficient arguments\n");
286       return NULL;
287     }
288
289   hexkeyid = serial_hex (keyid);
290   if (!hexkeyid)
291     {
292       log_debug ("serial_hex() failed\n");
293       return NULL;
294     }
295
296   buf = xtrymalloc (15 + strlen (hexkeyid) + 2 + strlen(name) + 1);
297   if (!buf)
298     {
299
300       log_error ("can't allocate enough memory: %s\n", strerror (errno));
301       xfree (hexkeyid);
302       return NULL;
303     }
304   strcpy (stpcpy (stpcpy (stpcpy (buf, "SENDCERT_SKI "), hexkeyid)," /"),name);
305   xfree (hexkeyid);
306
307   rc = assuan_inquire (ctrl->server_local->assuan_ctx, buf,
308                        &value, &valuelen, MAX_CERT_LENGTH);
309   xfree (buf);
310   if (rc)
311     {
312       log_error (_("assuan_inquire(%s) failed: %s\n"), "SENDCERT_SKI",
313                  gpg_strerror (rc));
314       return NULL;
315     }
316   
317   if (!valuelen)
318     {
319       xfree (value);
320       return NULL;
321     }
322
323   rc = ksba_cert_new (&cert);
324   if (!rc)
325     {
326       rc = ksba_cert_init_from_mem (cert, value, valuelen);
327       if (rc)
328         {
329           ksba_cert_release (cert);
330           cert = NULL;
331         }
332     }
333   xfree (value);
334   return cert;
335 }
336
337
338 /* Ask the client via an inquiry to check the istrusted status of the
339    certificate specified by the hexified fingerprint HEXFPR.  Returns
340    0 if the certificate is trusted by the client or an error code.  */
341 gpg_error_t
342 get_istrusted_from_client (ctrl_t ctrl, const char *hexfpr)
343 {
344   unsigned char *value;
345   size_t valuelen; 
346   int rc;
347   char request[100];
348
349   if (!ctrl || !ctrl->server_local || !ctrl->server_local->assuan_ctx
350       || !hexfpr)
351     return gpg_error (GPG_ERR_INV_ARG);
352   
353   snprintf (request, sizeof request, "ISTRUSTED %s", hexfpr);
354   rc = assuan_inquire (ctrl->server_local->assuan_ctx, request,
355                        &value, &valuelen, 100);
356   if (rc)
357     {
358       log_error (_("assuan_inquire(%s) failed: %s\n"),
359                  request, gpg_strerror (rc));
360       return rc;
361     }
362   /* The expected data is: "1" or "1 cruft" (not a C-string).  */
363   if (valuelen && *value == '1' && (valuelen == 1 || spacep (value+1)))
364     rc = 0;
365   else
366     rc = gpg_error (GPG_ERR_NOT_TRUSTED);
367   xfree (value);
368   return rc;
369 }
370
371
372
373
374 /* Ask the client to return the certificate associated with the
375    current command. This is sometimes needed because the client usually
376    sends us just the cert ID, assuming that the request can be
377    satisfied from the cache, where the cert ID is used as key. */
378 static int
379 inquire_cert_and_load_crl (assuan_context_t ctx)
380 {
381   ctrl_t ctrl = assuan_get_pointer (ctx);
382   gpg_error_t err;
383   unsigned char *value = NULL;
384   size_t valuelen; 
385   ksba_cert_t cert = NULL;
386
387   err = assuan_inquire( ctx, "SENDCERT", &value, &valuelen, 0);
388   if (err)
389     return err;
390
391 /*   { */
392 /*     FILE *fp = fopen ("foo.der", "r"); */
393 /*     value = xmalloc (2000); */
394 /*     valuelen = fread (value, 1, 2000, fp); */
395 /*     fclose (fp); */
396 /*   } */
397
398   if (!valuelen) /* No data returned; return a comprehensible error. */
399     return gpg_error (GPG_ERR_MISSING_CERT);
400
401   err = ksba_cert_new (&cert);
402   if (err)
403     goto leave;
404   err = ksba_cert_init_from_mem (cert, value, valuelen);
405   if(err)
406     goto leave;
407   xfree (value); value = NULL;
408
409   err = crl_cache_reload_crl (ctrl, cert);
410
411  leave:
412   ksba_cert_release (cert);
413   xfree (value);
414   return err;
415 }
416
417
418 /* Handle OPTION commands. */
419 static gpg_error_t
420 option_handler (assuan_context_t ctx, const char *key, const char *value)
421 {
422   ctrl_t ctrl = assuan_get_pointer (ctx);
423
424   if (!strcmp (key, "force-crl-refresh"))
425     {
426       int i = *value? atoi (value) : 0;
427       ctrl->force_crl_refresh = i;
428     }
429   else if (!strcmp (key, "audit-events"))
430     {
431       int i = *value? atoi (value) : 0;
432       ctrl->audit_events = i;
433     }
434   else
435     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
436
437   return 0;
438 }
439
440 static const char hlp_ldapserver[] = 
441   "LDAPSERVER <data>\n"
442   "\n"
443   "Add a new LDAP server to the list of configured LDAP servers.\n"
444   "DATA is in the same format as expected in the configure file.";
445 static gpg_error_t
446 cmd_ldapserver (assuan_context_t ctx, char *line)
447 {
448   ctrl_t ctrl = assuan_get_pointer (ctx);
449   ldap_server_t server;
450   ldap_server_t *last_next_p;
451
452   while (spacep (line))
453     line++;
454   if (*line == '\0')
455     return PARM_ERROR (_("ldapserver missing"));
456
457   server = ldapserver_parse_one (line, "", 0);
458   if (! server)
459     return gpg_error (GPG_ERR_INV_ARG);
460
461   last_next_p = &ctrl->server_local->ldapservers;
462   while (*last_next_p)
463     last_next_p = &(*last_next_p)->next;
464   *last_next_p = server;
465   return 0;
466 }
467
468
469 static const char hlp_isvalid[] = 
470   "ISVALID [--only-ocsp] [--force-default-responder]"
471   " <certificate_id>|<certificate_fpr>\n"
472   "\n"
473   "This command checks whether the certificate identified by the\n"
474   "certificate_id is valid.  This is done by consulting CRLs or\n"
475   "whatever has been configured.  Note, that the returned error codes\n"
476   "are from gpg-error.h.  The command may callback using the inquire\n"
477   "function.  See the manual for details.\n"
478   "\n"
479   "The CERTIFICATE_ID is a hex encoded string consisting of two parts,\n"
480   "delimited by a single dot.  The first part is the SHA-1 hash of the\n"
481   "issuer name and the second part the serial number.\n"
482   "\n"
483   "Alternatively the certificate's fingerprint may be given in which\n"
484   "case an OCSP request is done before consulting the CRL.\n"
485   "\n"
486   "If the option --only-ocsp is given, no fallback to a CRL check will\n"
487   "be used.\n"
488   "\n"
489   "If the option --force-default-responder is given, only the default\n"
490   "OCSP responder will be used and any other methods of obtaining an\n"
491   "OCSP responder URL won't be used.";
492 static gpg_error_t
493 cmd_isvalid (assuan_context_t ctx, char *line)
494 {
495   ctrl_t ctrl = assuan_get_pointer (ctx);
496   char *issuerhash, *serialno;
497   gpg_error_t err;
498   int did_inquire = 0;
499   int ocsp_mode = 0;
500   int only_ocsp;
501   int force_default_responder;
502   
503   only_ocsp = has_option (line, "--only-ocsp");
504   force_default_responder = has_option (line, "--force-default-responder");
505   line = skip_options (line);
506
507   issuerhash = xstrdup (line); /* We need to work on a copy of the
508                                   line because that same Assuan
509                                   context may be used for an inquiry.
510                                   That is because Assuan reuses its
511                                   line buffer.
512                                    */
513
514   serialno = strchr (issuerhash, '.');
515   if (serialno)
516     *serialno++ = 0;
517   else
518     {
519       char *endp = strchr (issuerhash, ' ');
520       if (endp)
521         *endp = 0;
522       if (strlen (issuerhash) != 40)
523         {
524           xfree (issuerhash);
525           return PARM_ERROR (_("serialno missing in cert ID"));
526         }
527       ocsp_mode = 1;
528     }
529
530
531  again:
532   if (ocsp_mode)
533     {
534       /* Note, that we ignore the given issuer hash and instead rely
535          on the current certificate semantics used with this
536          command. */
537       if (!opt.allow_ocsp)
538         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
539       else
540         err = ocsp_isvalid (ctrl, NULL, NULL, force_default_responder);
541       /* Fixme: If we got no ocsp response and --only-ocsp is not used
542          we should fall back to CRL mode.  Thus we need to clear
543          OCSP_MODE, get the issuerhash and the serialno from the
544          current certificate and jump to again. */
545     }
546   else if (only_ocsp)
547     err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
548   else 
549     {
550       switch (crl_cache_isvalid (ctrl,
551                                  issuerhash, serialno,
552                                  ctrl->force_crl_refresh))
553         {
554         case CRL_CACHE_VALID:
555           err = 0;
556           break;
557         case CRL_CACHE_INVALID:
558           err = gpg_error (GPG_ERR_CERT_REVOKED);
559           break;
560         case CRL_CACHE_DONTKNOW: 
561           if (did_inquire)
562             err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
563           else if (!(err = inquire_cert_and_load_crl (ctx)))
564             {
565               did_inquire = 1;
566               goto again;
567             }
568           break;
569         case CRL_CACHE_CANTUSE: 
570           err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
571           break;
572         default:
573           log_fatal ("crl_cache_isvalid returned invalid code\n");
574         }
575     }
576
577   if (err)
578     log_error (_("command %s failed: %s\n"), "ISVALID", gpg_strerror (err));
579   xfree (issuerhash);
580   return err;
581 }
582
583
584 /* If the line contains a SHA-1 fingerprint as the first argument,
585    return the FPR vuffer on success.  The function checks that the
586    fingerprint consists of valid characters and prints and error
587    message if it does not and returns NULL.  Fingerprints are
588    considered optional and thus no explicit error is returned. NULL is
589    also returned if there is no fingerprint at all available. 
590    FPR must be a caller provided buffer of at least 20 bytes.
591
592    Note that colons within the fingerprint are allowed to separate 2
593    hex digits; this allows for easier cutting and pasting using the
594    usual fingerprint rendering.
595 */
596 static unsigned char *
597 get_fingerprint_from_line (const char *line, unsigned char *fpr)
598 {
599   const char *s;
600   int i;
601
602   for (s=line, i=0; *s && *s != ' '; s++ )
603     {
604       if ( hexdigitp (s) && hexdigitp (s+1) )
605         {
606           if ( i >= 20 )
607             return NULL;  /* Fingerprint too long.  */
608           fpr[i++] = xtoi_2 (s);
609           s++;
610         }
611       else if ( *s != ':' )
612         return NULL; /* Invalid.  */
613     }
614   if ( i != 20 )
615     return NULL; /* Fingerprint to short.  */
616   return fpr;
617 }
618
619
620
621 static const char hlp_checkcrl[] = 
622   "CHECKCRL [<fingerprint>]\n"
623   "\n"
624   "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
625   "entire X.509 certificate blob) is valid or not by consulting the\n"
626   "CRL responsible for this certificate.  If the fingerprint has not\n"
627   "been given or the certificate is not known, the function \n"
628   "inquires the certificate using an\n"
629   "\n"
630   "  INQUIRE TARGETCERT\n"
631   "\n"
632   "and the caller is expected to return the certificate for the\n"
633   "request (which should match FINGERPRINT) as a binary blob.\n"
634   "Processing then takes place without further interaction; in\n"
635   "particular dirmngr tries to locate other required certificate by\n"
636   "its own mechanism which includes a local certificate store as well\n"
637   "as a list of trusted root certificates.\n"
638   "\n"
639   "The return value is the usual gpg-error code or 0 for ducesss;\n"
640   "i.e. the certificate validity has been confirmed by a valid CRL.";
641 static gpg_error_t
642 cmd_checkcrl (assuan_context_t ctx, char *line)
643 {
644   ctrl_t ctrl = assuan_get_pointer (ctx);
645   gpg_error_t err;
646   unsigned char fprbuffer[20], *fpr;
647   ksba_cert_t cert;
648
649   fpr = get_fingerprint_from_line (line, fprbuffer);
650   cert = fpr? get_cert_byfpr (fpr) : NULL;
651   
652   if (!cert)
653     {
654       /* We do not have this certificate yet or the fingerprint has
655          not been given.  Inquire it from the client.  */
656       unsigned char *value = NULL;
657       size_t valuelen; 
658       
659       err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
660                            &value, &valuelen, MAX_CERT_LENGTH);
661       if (err)
662         {
663           log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
664           goto leave;
665         }
666   
667       if (!valuelen) /* No data returned; return a comprehensible error. */
668         err = gpg_error (GPG_ERR_MISSING_CERT);
669       else
670         {
671           err = ksba_cert_new (&cert);
672           if (!err)
673             err = ksba_cert_init_from_mem (cert, value, valuelen);
674         }
675       xfree (value);
676       if(err)
677         goto leave;
678     }
679
680   assert (cert);
681
682   err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
683   if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
684     {
685       err = crl_cache_reload_crl (ctrl, cert);
686       if (!err)
687         err = crl_cache_cert_isvalid (ctrl, cert, 0);
688     }
689
690  leave:
691   if (err)
692     log_error (_("command %s failed: %s\n"), "CHECKCRL", gpg_strerror (err));
693   ksba_cert_release (cert);
694   return err;
695 }
696
697
698 static const char hlp_checkocsp[] = 
699   "CHECKOCSP [--force-default-responder] [<fingerprint>]\n"
700   "\n"
701   "Check whether the certificate with FINGERPRINT (SHA-1 hash of the\n"
702   "entire X.509 certificate blob) is valid or not by asking an OCSP\n"
703   "responder responsible for this certificate.  The optional\n"
704   "fingerprint may be used for a quick check in case an OCSP check has\n"
705   "been done for this certificate recently (we always cache OCSP\n"
706   "responses for a couple of minutes). If the fingerprint has not been\n"
707   "given or there is no cached result, the function inquires the\n"
708   "certificate using an\n"
709   "\n"
710   "   INQUIRE TARGETCERT\n"
711   "\n"
712   "and the caller is expected to return the certificate for the\n"
713   "request (which should match FINGERPRINT) as a binary blob.\n"
714   "Processing then takes place without further interaction; in\n"
715   "particular dirmngr tries to locate other required certificates by\n"
716   "its own mechanism which includes a local certificate store as well\n"
717   "as a list of trusted root certifciates.\n"
718   "\n"
719   "If the option --force-default-responder is given, only the default\n"
720   "OCSP responder will be used and any other methods of obtaining an\n"
721   "OCSP responder URL won't be used.\n"
722   "\n"
723   "The return value is the usual gpg-error code or 0 for ducesss;\n"
724   "i.e. the certificate validity has been confirmed by a valid CRL.";
725 static gpg_error_t
726 cmd_checkocsp (assuan_context_t ctx, char *line)
727 {
728   ctrl_t ctrl = assuan_get_pointer (ctx);
729   gpg_error_t err;
730   unsigned char fprbuffer[20], *fpr;
731   ksba_cert_t cert;
732   int force_default_responder;
733   
734   force_default_responder = has_option (line, "--force-default-responder");
735   line = skip_options (line);
736
737   fpr = get_fingerprint_from_line (line, fprbuffer);
738   cert = fpr? get_cert_byfpr (fpr) : NULL;
739   
740   if (!cert)
741     {
742       /* We do not have this certificate yet or the fingerprint has
743          not been given.  Inquire it from the client.  */
744       unsigned char *value = NULL;
745       size_t valuelen; 
746       
747       err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
748                            &value, &valuelen, MAX_CERT_LENGTH);
749       if (err)
750         {
751           log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
752           goto leave;
753         }
754   
755       if (!valuelen) /* No data returned; return a comprehensible error. */
756         err = gpg_error (GPG_ERR_MISSING_CERT);
757       else
758         {
759           err = ksba_cert_new (&cert);
760           if (!err)
761             err = ksba_cert_init_from_mem (cert, value, valuelen);
762         }
763       xfree (value);
764       if(err)
765         goto leave;
766     }
767
768   assert (cert);
769
770   if (!opt.allow_ocsp)
771     err = gpg_error (GPG_ERR_NOT_SUPPORTED);
772   else
773     err = ocsp_isvalid (ctrl, cert, NULL, force_default_responder);
774
775  leave:
776   if (err)
777     log_error (_("command %s failed: %s\n"), "CHECKOCSP", gpg_strerror (err));
778   ksba_cert_release (cert);
779   return err;
780 }
781
782
783
784 static int
785 lookup_cert_by_url (assuan_context_t ctx, const char *url)
786 {
787   ctrl_t ctrl = assuan_get_pointer (ctx);
788   gpg_error_t err = 0;
789   unsigned char *value = NULL;
790   size_t valuelen; 
791
792   /* Fetch single certificate given it's URL.  */
793   err = fetch_cert_by_url (ctrl, url, &value, &valuelen);
794   if (err)
795     {
796       log_error (_("fetch_cert_by_url failed: %s\n"), gpg_strerror (err));
797       goto leave;
798     }
799
800   /* Send the data, flush the buffer and then send an END. */
801   err = assuan_send_data (ctx, value, valuelen);      
802   if (!err)
803     err = assuan_send_data (ctx, NULL, 0);
804   if (!err)
805     err = assuan_write_line (ctx, "END");
806   if (err) 
807     {
808       log_error (_("error sending data: %s\n"), gpg_strerror (err));
809       goto leave;
810     }
811
812  leave:
813
814   return err;
815 }
816
817
818 /* Send the certificate, flush the buffer and then send an END. */
819 static gpg_error_t
820 return_one_cert (void *opaque, ksba_cert_t cert)
821 {
822   assuan_context_t ctx = opaque;
823   gpg_error_t err;
824   const unsigned char *der;
825   size_t derlen;
826
827   der = ksba_cert_get_image (cert, &derlen);
828   if (!der)
829     err = gpg_error (GPG_ERR_INV_CERT_OBJ);
830   else
831     {
832       err = assuan_send_data (ctx, der, derlen);      
833       if (!err)
834         err = assuan_send_data (ctx, NULL, 0);
835       if (!err)
836         err = assuan_write_line (ctx, "END");
837     }
838   if (err) 
839     log_error (_("error sending data: %s\n"), gpg_strerror (err));
840   return err;
841 }
842
843
844 /* Lookup certificates from the internal cache or using the ldap
845    servers. */
846 static int
847 lookup_cert_by_pattern (assuan_context_t ctx, char *line, 
848                         int single, int cache_only)
849 {
850   ctrl_t ctrl = assuan_get_pointer (ctx);
851   gpg_error_t err = 0;
852   char *p;
853   strlist_t sl, list = NULL;
854   int truncated = 0, truncation_forced = 0;
855   int count = 0;
856   int local_count = 0;
857   unsigned char *value = NULL;
858   size_t valuelen; 
859   struct ldapserver_iter ldapserver_iter;
860   cert_fetch_context_t fetch_context;
861   int any_no_data = 0;
862
863   /* Break the line down into an STRLIST */
864   for (p=line; *p; line = p)
865     {
866       while (*p && *p != ' ')
867         p++;
868       if (*p) 
869         *p++ = 0;
870
871       if (*line)
872         {
873           sl = xtrymalloc (sizeof *sl + strlen (line));
874           if (!sl)
875             {
876               err = gpg_error_from_errno (errno);
877               goto leave;
878             }
879           memset (sl, 0, sizeof *sl);
880           strcpy_escaped_plus (sl->d, line);
881           sl->next = list;
882           list = sl;
883         }
884     }
885
886   /* First look through the internal cache.  The certifcates retruned
887      here are not counted towards the truncation limit.  */
888   if (single && !cache_only)
889     ; /* Do not read from the local cache in this case.  */
890   else
891     {
892       for (sl=list; sl; sl = sl->next)
893         {
894           err = get_certs_bypattern (sl->d, return_one_cert, ctx);
895           if (!err)
896             local_count++;
897           if (!err && single)
898             goto ready; 
899
900           if (gpg_err_code (err) == GPG_ERR_NO_DATA)
901             {
902               err = 0;
903               if (cache_only)
904                 any_no_data = 1;
905             }
906           else if (gpg_err_code (err) == GPG_ERR_INV_NAME && !cache_only)
907             {
908               /* No real fault because the internal pattern lookup
909                  can't yet cope with all types of pattern.  */
910               err = 0;
911             }
912           if (err)
913             goto ready;
914         }
915     }
916
917   /* Loop over all configured servers unless we want only the
918      certificates from the cache.  */
919   for (ldapserver_iter_begin (&ldapserver_iter, ctrl);
920        !cache_only && !ldapserver_iter_end_p (&ldapserver_iter)
921          && ldapserver_iter.server->host && !truncation_forced;
922        ldapserver_iter_next (&ldapserver_iter))
923     {
924       ldap_server_t ldapserver = ldapserver_iter.server;
925       
926       if (DBG_LOOKUP)
927         log_debug ("cmd_lookup: trying %s:%d base=%s\n", 
928                    ldapserver->host, ldapserver->port,
929                    ldapserver->base?ldapserver->base : "[default]");
930
931       /* Fetch certificates matching pattern */
932       err = start_cert_fetch (ctrl, &fetch_context, list, ldapserver);
933       if ( gpg_err_code (err) == GPG_ERR_NO_DATA )
934         {
935           if (DBG_LOOKUP)
936             log_debug ("cmd_lookup: no data\n");
937           err = 0;
938           any_no_data = 1;
939           continue;
940         }
941       if (err)
942         {
943           log_error (_("start_cert_fetch failed: %s\n"), gpg_strerror (err));
944           goto leave;
945         }
946
947       /* Fetch the certificates for this query. */
948       while (!truncation_forced)
949         {
950           xfree (value); value = NULL;
951           err = fetch_next_cert (fetch_context, &value, &valuelen);
952           if (gpg_err_code (err) == GPG_ERR_NO_DATA )
953             {
954               err = 0;
955               any_no_data = 1;
956               break; /* Ready. */
957             }
958           if (gpg_err_code (err) == GPG_ERR_TRUNCATED)
959             {
960               truncated = 1;
961               err = 0;
962               break;  /* Ready.  */
963             }
964           if (gpg_err_code (err) == GPG_ERR_EOF)
965             {
966               err = 0;
967               break; /* Ready. */
968             }
969           if (!err && !value)
970             {
971               err = gpg_error (GPG_ERR_BUG);
972               goto leave;
973             }
974           if (err)
975             {
976               log_error (_("fetch_next_cert failed: %s\n"),
977                          gpg_strerror (err));
978               end_cert_fetch (fetch_context);
979               goto leave;
980             }
981           
982           if (DBG_LOOKUP)
983             log_debug ("cmd_lookup: returning one cert%s\n",
984                        truncated? " (truncated)":"");
985           
986           /* Send the data, flush the buffer and then send an END line
987              as a certificate delimiter. */
988           err = assuan_send_data (ctx, value, valuelen);      
989           if (!err)
990             err = assuan_send_data (ctx, NULL, 0);
991           if (!err)
992             err = assuan_write_line (ctx, "END");
993           if (err) 
994             {
995               log_error (_("error sending data: %s\n"), gpg_strerror (err));
996               end_cert_fetch (fetch_context);
997               goto leave;
998             }
999           
1000           if (++count >= opt.max_replies )
1001             {
1002               truncation_forced = 1;
1003               log_info (_("max_replies %d exceeded\n"), opt.max_replies );
1004             }
1005           if (single)
1006             break;
1007         }
1008
1009       end_cert_fetch (fetch_context);
1010     }
1011
1012  ready:
1013   if (truncated || truncation_forced)
1014     {
1015       char str[50];
1016
1017       sprintf (str, "%d", count);
1018       assuan_write_status (ctx, "TRUNCATED", str);    
1019     }
1020
1021   if (!err && !count && !local_count && any_no_data)
1022     err = gpg_error (GPG_ERR_NO_DATA);
1023
1024  leave:
1025   free_strlist (list);
1026   return err;
1027 }
1028
1029
1030 static const char hlp_lookup[] = 
1031   "LOOKUP [--url] [--single] [--cache-only] <pattern>\n"
1032   "\n"
1033   "Lookup certificates matching PATTERN. With --url the pattern is\n"
1034   "expected to be one URL.\n"
1035   "\n"
1036   "If --url is not given:  To allow for multiple patterns (which are ORed)\n"
1037   "quoting is required: Spaces are translated to \"+\" or \"%20\";\n"
1038   "obviously this requires that the usual escape quoting rules are applied.\n"
1039   "\n"
1040   "If --url is given no special escaping is required because URLs are\n"
1041   "already escaped this way.\n"
1042   "\n"
1043   "If --single is given the first and only the first match will be\n"
1044   "returned.  If --cache-only is _not_ given, no local query will be\n"
1045   "done.\n"
1046   "\n"
1047   "If --cache-only is given no external lookup is done so that only\n"
1048   "certificates from the cache may get returned.";
1049 static gpg_error_t
1050 cmd_lookup (assuan_context_t ctx, char *line)
1051 {
1052   gpg_error_t err;
1053   int lookup_url, single, cache_only;
1054
1055   lookup_url = has_leading_option (line, "--url");
1056   single = has_leading_option (line, "--single");
1057   cache_only = has_leading_option (line, "--cache-only");
1058   line = skip_options (line);
1059
1060   if (lookup_url && cache_only)
1061     err = gpg_error (GPG_ERR_NOT_FOUND);
1062   else if (lookup_url && single)
1063     err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1064   else if (lookup_url)
1065     err = lookup_cert_by_url (ctx, line);
1066   else
1067     err = lookup_cert_by_pattern (ctx, line, single, cache_only);
1068
1069   if (err)
1070     log_error (_("command %s failed: %s\n"), "LOOKUP", gpg_strerror (err));
1071
1072   return err;
1073 }
1074
1075
1076 static const char hlp_loadcrl[] =
1077   "LOADCRL [--url] <filename|url>\n"
1078   "\n"
1079   "Load the CRL in the file with name FILENAME into our cache.  Note\n"
1080   "that FILENAME should be given with an absolute path because\n"
1081   "Dirmngrs cwd is not known.  With --url the CRL is directly loaded\n"
1082   "from the given URL.\n"
1083   "\n"
1084   "This command is usually used by gpgsm using the invocation \"gpgsm\n"
1085   "--call-dirmngr loadcrl <filename>\".  A direct invocation of Dirmngr\n"
1086   "is not useful because gpgsm might need to callback gpgsm to ask for\n"
1087   "the CA's certificate.";
1088 static gpg_error_t
1089 cmd_loadcrl (assuan_context_t ctx, char *line)
1090 {
1091   ctrl_t ctrl = assuan_get_pointer (ctx);
1092   gpg_error_t err = 0;
1093   int use_url = has_leading_option (line, "--url");
1094
1095   line = skip_options (line);
1096
1097   if (use_url)
1098     {
1099       ksba_reader_t reader;
1100
1101       err = crl_fetch (ctrl, line, &reader);
1102       if (err)
1103         log_error (_("fetching CRL from `%s' failed: %s\n"),
1104                    line, gpg_strerror (err));
1105       else
1106         {
1107           err = crl_cache_insert (ctrl, line, reader); 
1108           if (err)
1109             log_error (_("processing CRL from `%s' failed: %s\n"),
1110                        line, gpg_strerror (err));
1111           crl_close_reader (reader);
1112         }
1113     }
1114   else
1115     {
1116       char *buf;
1117
1118       buf = xtrymalloc (strlen (line)+1);
1119       if (!buf)
1120         err = gpg_error_from_syserror ();
1121       else
1122         {
1123           strcpy_escaped_plus (buf, line);
1124           err = crl_cache_load (ctrl, buf);
1125           xfree (buf);
1126         }
1127     }
1128
1129   if (err)
1130     log_error (_("command %s failed: %s\n"), "LOADCRL", gpg_strerror (err));
1131   return err;
1132 }
1133
1134
1135 static const char hlp_listcrls[] =
1136   "LISTCRLS\n"
1137   "\n"
1138   "List the content of all CRLs in a readable format.  This command is\n"
1139   "usually used by gpgsm using the invocation \"gpgsm --call-dirmngr\n"
1140   "listcrls\".  It may also be used directly using \"dirmngr\n"
1141   "--list-crls\".";
1142 static gpg_error_t
1143 cmd_listcrls (assuan_context_t ctx, char *line)
1144 {
1145   gpg_error_t err;
1146   FILE *fp = assuan_get_data_fp (ctx);
1147
1148   (void)line;
1149
1150   if (!fp)
1151     return PARM_ERROR (_("no data stream"));
1152
1153   err = crl_cache_list (fp);
1154   if (err)
1155     log_error (_("command %s failed: %s\n"), "LISTCRLS", gpg_strerror (err));
1156   return err;
1157 }
1158
1159
1160 static const char hlp_cachecert[] = 
1161   "CACHECERT\n"
1162   "\n"
1163   "Put a certificate into the internal cache.  This command might be\n"
1164   "useful if a client knows in advance certificates required for a\n"
1165   "test and wnats to make sure they get added to the internal cache.\n"
1166   "It is also helpful for debugging.  To get the actual certificate,\n"
1167   "this command immediately inquires it using\n"
1168   "\n"
1169   "  INQUIRE TARGETCERT\n"
1170   "\n"
1171   "and the caller is expected to return the certificate for the\n"
1172   "request as a binary blob.";
1173 static gpg_error_t
1174 cmd_cachecert (assuan_context_t ctx, char *line)
1175 {
1176   ctrl_t ctrl = assuan_get_pointer (ctx);
1177   gpg_error_t err;
1178   ksba_cert_t cert = NULL;
1179   unsigned char *value = NULL;
1180   size_t valuelen; 
1181
1182   (void)line;
1183       
1184   err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1185                        &value, &valuelen, MAX_CERT_LENGTH);
1186   if (err)
1187     {
1188       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1189       goto leave;
1190     }
1191   
1192   if (!valuelen) /* No data returned; return a comprehensible error. */
1193     err = gpg_error (GPG_ERR_MISSING_CERT);
1194   else
1195     {
1196       err = ksba_cert_new (&cert);
1197       if (!err)
1198         err = ksba_cert_init_from_mem (cert, value, valuelen);
1199     }
1200   xfree (value);
1201   if(err)
1202     goto leave;
1203
1204   err = cache_cert (cert);
1205
1206  leave:
1207   if (err)
1208     log_error (_("command %s failed: %s\n"), "CACHECERT", gpg_strerror (err));
1209   ksba_cert_release (cert);
1210   return err;
1211 }
1212
1213
1214 static const char hlp_validate[] =
1215   "VALIDATE\n"
1216   "\n"
1217   "Validate a certificate using the certificate validation function\n"
1218   "used internally by dirmngr.  This command is only useful for\n"
1219   "debugging.  To get the actual certificate, this command immediately\n"
1220   "inquires it using\n"
1221   "\n"
1222   "  INQUIRE TARGETCERT\n"
1223   "\n"
1224   "and the caller is expected to return the certificate for the\n"
1225   "request as a binary blob.";
1226 static gpg_error_t
1227 cmd_validate (assuan_context_t ctx, char *line)
1228 {
1229   ctrl_t ctrl = assuan_get_pointer (ctx);
1230   gpg_error_t err;
1231   ksba_cert_t cert = NULL;
1232   unsigned char *value = NULL;
1233   size_t valuelen; 
1234
1235   (void)line;
1236     
1237   err = assuan_inquire (ctrl->server_local->assuan_ctx, "TARGETCERT",
1238                        &value, &valuelen, MAX_CERT_LENGTH);
1239   if (err)
1240     {
1241       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
1242       goto leave;
1243     }
1244   
1245   if (!valuelen) /* No data returned; return a comprehensible error. */
1246     err = gpg_error (GPG_ERR_MISSING_CERT);
1247   else
1248     {
1249       err = ksba_cert_new (&cert);
1250       if (!err)
1251         err = ksba_cert_init_from_mem (cert, value, valuelen);
1252     }
1253   xfree (value);
1254   if(err)
1255     goto leave;
1256
1257   /* If we have this certificate already in our cache, use the cached
1258      version for validation because this will take care of any cached
1259      results. */
1260   { 
1261     unsigned char fpr[20];
1262     ksba_cert_t tmpcert;
1263
1264     cert_compute_fpr (cert, fpr);
1265     tmpcert = get_cert_byfpr (fpr);
1266     if (tmpcert)
1267       {
1268         ksba_cert_release (cert);
1269         cert = tmpcert;
1270       }
1271   }
1272
1273   err = validate_cert_chain (ctrl, cert, NULL, VALIDATE_MODE_CERT, NULL);
1274
1275  leave:
1276   if (err)
1277     log_error (_("command %s failed: %s\n"), "VALIDATE", gpg_strerror (err));
1278   ksba_cert_release (cert);
1279   return err;
1280 }
1281
1282
1283
1284 /* Tell the assuan library about our commands. */
1285 static int
1286 register_commands (assuan_context_t ctx)
1287 {
1288   static struct {
1289     const char *name;
1290     assuan_handler_t handler;
1291     const char * const help;
1292   } table[] = {
1293     { "LDAPSERVER", cmd_ldapserver, hlp_ldapserver },
1294     { "ISVALID",    cmd_isvalid,    hlp_isvalid },
1295     { "CHECKCRL",   cmd_checkcrl,   hlp_checkcrl },
1296     { "CHECKOCSP",  cmd_checkocsp,  hlp_checkocsp },
1297     { "LOOKUP",     cmd_lookup,     hlp_lookup },
1298     { "LOADCRL",    cmd_loadcrl,    hlp_loadcrl },
1299     { "LISTCRLS",   cmd_listcrls,   hlp_listcrls },
1300     { "CACHECERT",  cmd_cachecert,  hlp_cachecert },
1301     { "VALIDATE",   cmd_validate,   hlp_validate },
1302     { "INPUT",      NULL },
1303     { "OUTPUT",     NULL },
1304     { NULL, NULL }
1305   };
1306   int i, j, rc;
1307
1308   for (i=j=0; table[i].name; i++)
1309     {
1310       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1311                                     table[i].help);
1312       if (rc)
1313         return rc;
1314     }
1315   return 0;
1316 }
1317
1318
1319 static gpg_error_t
1320 reset_notify (assuan_context_t ctx, char *line)
1321 {
1322   ctrl_t ctrl = assuan_get_pointer (ctx);
1323   (void)line;
1324
1325   ldapserver_list_free (ctrl->server_local->ldapservers);
1326   ctrl->server_local->ldapservers = NULL;
1327   return 0;
1328 }
1329
1330
1331 /* Startup the server and run the main command loop.  With FD = -1
1332    used stdin/stdout. */
1333 void
1334 start_command_handler (assuan_fd_t fd)
1335 {
1336   static const char hello[] = "Dirmngr " VERSION " at your service";
1337   static char *hello_line;
1338   int rc;
1339   assuan_context_t ctx;
1340   ctrl_t ctrl;
1341
1342   ctrl = xtrycalloc (1, sizeof *ctrl);
1343   if (ctrl)
1344     ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
1345   if (!ctrl || !ctrl->server_local)
1346     {
1347       log_error (_("can't allocate control structure: %s\n"),
1348                  strerror (errno));
1349       xfree (ctrl);
1350       return;
1351     }
1352     
1353   dirmngr_init_default_ctrl (ctrl);
1354
1355   rc = assuan_new (&ctx);
1356   if (rc)
1357     {
1358       log_error (_("failed to allocate assuan context: %s\n"),
1359                  gpg_strerror (rc));
1360       dirmngr_exit (2);
1361     }
1362
1363   if (fd == ASSUAN_INVALID_FD)
1364     {
1365       assuan_fd_t filedes[2];
1366       
1367       filedes[0] = assuan_fdopen (0);
1368       filedes[1] = assuan_fdopen (1);
1369       rc = assuan_init_pipe_server (ctx, filedes);
1370     }
1371   else
1372     {
1373       rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
1374     }
1375
1376   if (rc)
1377     {
1378       assuan_release (ctx);
1379       log_error (_("failed to initialize the server: %s\n"),
1380                  gpg_strerror(rc));
1381       dirmngr_exit (2);
1382     }
1383
1384   rc = register_commands (ctx);
1385   if (rc)
1386     {
1387       log_error (_("failed to the register commands with Assuan: %s\n"),
1388                  gpg_strerror(rc));
1389       dirmngr_exit (2);
1390     }
1391
1392
1393   if (!hello_line)
1394     {
1395       size_t n;
1396       const char *cfgname;
1397
1398       cfgname = opt.config_filename? opt.config_filename : "[none]";
1399
1400       n = (30 + strlen (opt.homedir) + strlen (cfgname)
1401            + strlen (hello) + 1);
1402       hello_line = xmalloc (n+1);
1403       snprintf (hello_line, n,
1404                 "Home: %s\n"
1405                 "Config: %s\n"
1406                 "%s",
1407                 opt.homedir,
1408                 cfgname,
1409                 hello);
1410       hello_line[n] = 0;
1411     }
1412
1413   ctrl->server_local->assuan_ctx = ctx;
1414   assuan_set_pointer (ctx, ctrl);
1415
1416   assuan_set_hello_line (ctx, hello_line);
1417   assuan_register_option_handler (ctx, option_handler);
1418   assuan_register_reset_notify (ctx, reset_notify);
1419
1420   for (;;) 
1421     {
1422       rc = assuan_accept (ctx);
1423       if (rc == -1)
1424         break;
1425       if (rc)
1426         {
1427           log_info (_("Assuan accept problem: %s\n"), gpg_strerror (rc));
1428           break;
1429         }
1430
1431 #ifndef HAVE_W32_SYSTEM
1432       if (opt.verbose)
1433         {
1434           assuan_peercred_t peercred;
1435
1436           if (!assuan_get_peercred (ctx, &peercred))
1437             log_info ("connection from process %ld (%ld:%ld)\n",
1438                       (long)peercred->pid, (long)peercred->uid,
1439                       (long)peercred->gid);
1440         }
1441 #endif
1442
1443       rc = assuan_process (ctx);
1444       if (rc)
1445         {
1446           log_info (_("Assuan processing failed: %s\n"), gpg_strerror (rc));
1447           continue;
1448         }
1449     }
1450   
1451   ldap_wrapper_connection_cleanup (ctrl);
1452
1453   ldapserver_list_free (ctrl->server_local->ldapservers);
1454   ctrl->server_local->ldapservers = NULL;
1455
1456   ctrl->server_local->assuan_ctx = NULL;
1457   assuan_release (ctx);
1458
1459   if (ctrl->refcount)
1460     log_error ("oops: connection control structure still referenced (%d)\n",
1461                ctrl->refcount);
1462   else
1463     {
1464       release_ctrl_ocsp_certs (ctrl);
1465       xfree (ctrl->server_local);
1466       xfree (ctrl);
1467     }
1468 }
1469
1470
1471 /* Send a status line back to the client.  KEYWORD is the status
1472    keyword, the optioal string argumenst are blank separated added to
1473    the line, the last argument must be a NULL. */
1474 gpg_error_t
1475 dirmngr_status (ctrl_t ctrl, const char *keyword, ...)
1476 {
1477   gpg_error_t err = 0;
1478   va_list arg_ptr;
1479   const char *text;
1480
1481   va_start (arg_ptr, keyword);
1482
1483   if (ctrl->server_local)
1484     {
1485       assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1486       char buf[950], *p;
1487       size_t n;
1488       
1489       p = buf; 
1490       n = 0;
1491       while ( (text = va_arg (arg_ptr, const char *)) )
1492         {
1493           if (n)
1494             {
1495               *p++ = ' ';
1496               n++;
1497             }
1498           for ( ; *text && n < DIM (buf)-2; n++)
1499             *p++ = *text++;
1500         }
1501       *p = 0;
1502       err = assuan_write_status (ctx, keyword, buf);
1503     }
1504
1505   va_end (arg_ptr);
1506   return err;
1507 }
1508
1509
1510 /* Note, that we ignore CTRL for now but use the first connection to
1511    send the progress info back. */
1512 gpg_error_t
1513 dirmngr_tick (ctrl_t ctrl)
1514 {
1515   static time_t next_tick = 0;
1516   gpg_error_t err = 0;
1517   time_t now = time (NULL);
1518
1519   if (!next_tick)
1520     {
1521       next_tick = now + 1;
1522     }
1523   else if ( now > next_tick )
1524     {
1525       if (ctrl)
1526         {
1527           err = dirmngr_status (ctrl, "PROGRESS", "tick", "? 0 0", NULL);
1528           if (err)
1529             {
1530               /* Take this as in indication for a cancel request.  */
1531               err = gpg_error (GPG_ERR_CANCELED);
1532             }
1533           now = time (NULL);
1534         }
1535
1536       next_tick = now + 1;
1537     }
1538   return err;
1539 }