New gpgsm server option no-encrypt-to.
[gnupg.git] / sm / server.c
1 /* server.c - Server mode and main entry point 
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3  *               2007, 2008 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG 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 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG 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 <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <unistd.h>
29
30 #include <assuan.h>
31
32 #include "gpgsm.h"
33 #include "sysutils.h"
34
35 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
36
37
38 /* The filepointer for status message used in non-server mode */
39 static FILE *statusfp;
40
41 /* Data used to assuciate an Assuan context with local server data */
42 struct server_local_s {
43   assuan_context_t assuan_ctx;
44   int message_fd;
45   int list_internal;
46   int list_external;
47   int list_to_output;           /* Write keylistings to the output fd. */
48   int enable_audit_log;         /* Use an audit log.  */
49   certlist_t recplist;
50   certlist_t signerlist;
51   certlist_t default_recplist; /* As set by main() - don't release. */
52   int allow_pinentry_notify;   /* Set if pinentry notifications should
53                                   be passed back to the client. */
54   int no_encrypt_to;           /* Local version of option.  */
55 };
56
57
58 /* Cookie definition for assuan data line output.  */
59 static ssize_t data_line_cookie_write (void *cookie,
60                                        const void *buffer, size_t size);
61 static int data_line_cookie_close (void *cookie);
62 static es_cookie_io_functions_t data_line_cookie_functions =
63   {
64     NULL,
65     data_line_cookie_write,
66     NULL,
67     data_line_cookie_close
68   };
69
70
71
72 \f
73 /* Note that it is sufficient to allocate the target string D as
74    long as the source string S, i.e.: strlen(s)+1; */
75 static void
76 strcpy_escaped_plus (char *d, const char *s)
77 {
78   while (*s)
79     {
80       if (*s == '%' && s[1] && s[2])
81         { 
82           s++;
83           *d++ = xtoi_2 (s);
84           s += 2;
85         }
86       else if (*s == '+')
87         *d++ = ' ', s++;
88       else
89         *d++ = *s++;
90     }
91   *d = 0; 
92 }
93
94
95 /* Skip over options.  
96    Blanks after the options are also removed. */
97 static char *
98 skip_options (const char *line)
99 {
100   while (spacep (line))
101     line++;
102   while ( *line == '-' && line[1] == '-' )
103     {
104       while (*line && !spacep (line))
105         line++;
106       while (spacep (line))
107         line++;
108     }
109   return (char*)line;
110 }
111
112
113 /* Check whether the option NAME appears in LINE */
114 static int
115 has_option (const char *line, const char *name)
116 {
117   const char *s;
118   int n = strlen (name);
119
120   s = strstr (line, name);
121   if (s && s >= skip_options (line))
122     return 0;
123   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
124 }
125
126
127 /* A write handler used by es_fopencookie to write assuan data
128    lines.  */
129 static ssize_t
130 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
131 {
132   assuan_context_t ctx = cookie;
133
134   if (assuan_send_data (ctx, buffer, size))
135     {
136       errno = EIO;
137       return -1;
138     }
139
140   return size;
141 }
142
143 static int
144 data_line_cookie_close (void *cookie)
145 {
146   assuan_context_t ctx = cookie;
147
148   if (assuan_send_data (ctx, NULL, 0))
149     {
150       errno = EIO;
151       return -1;
152     }
153
154   return 0;
155 }
156
157
158 static void 
159 close_message_fd (ctrl_t ctrl)
160 {
161   if (ctrl->server_local->message_fd != -1)
162     {
163       close (ctrl->server_local->message_fd);
164       ctrl->server_local->message_fd = -1;
165     }
166 }
167
168
169 /* Start a new audit session if this has been enabled.  */
170 static gpg_error_t
171 start_audit_session (ctrl_t ctrl)
172 {
173   audit_release (ctrl->audit);
174   ctrl->audit = NULL;
175   if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
176     return gpg_error_from_syserror ();
177   
178   return 0;
179 }
180
181
182 static int
183 option_handler (assuan_context_t ctx, const char *key, const char *value)
184 {
185   ctrl_t ctrl = assuan_get_pointer (ctx);
186
187   if (!strcmp (key, "include-certs"))
188     {
189       int i = *value? atoi (value) : -1;
190       if (ctrl->include_certs < -2)
191         return gpg_error (GPG_ERR_ASS_PARAMETER);
192       ctrl->include_certs = i;
193     }
194   else if (!strcmp (key, "display"))
195     {
196       if (opt.display)
197         free (opt.display);
198       opt.display = strdup (value);
199       if (!opt.display)
200         return out_of_core ();
201     }
202   else if (!strcmp (key, "ttyname"))
203     {
204       if (opt.ttyname)
205         free (opt.ttyname);
206       opt.ttyname = strdup (value);
207       if (!opt.ttyname)
208         return out_of_core ();
209     }
210   else if (!strcmp (key, "ttytype"))
211     {
212       if (opt.ttytype)
213         free (opt.ttytype);
214       opt.ttytype = strdup (value);
215       if (!opt.ttytype)
216         return out_of_core ();
217     }
218   else if (!strcmp (key, "lc-ctype"))
219     {
220       if (opt.lc_ctype)
221         free (opt.lc_ctype);
222       opt.lc_ctype = strdup (value);
223       if (!opt.lc_ctype)
224         return out_of_core ();
225     }
226   else if (!strcmp (key, "lc-messages"))
227     {
228       if (opt.lc_messages)
229         free (opt.lc_messages);
230       opt.lc_messages = strdup (value);
231       if (!opt.lc_messages)
232         return out_of_core ();
233     }
234   else if (!strcmp (key, "xauthority"))
235     {
236       if (opt.xauthority)
237         free (opt.xauthority);
238       opt.xauthority = strdup (value);
239       if (!opt.xauthority)
240         return out_of_core ();
241     }
242   else if (!strcmp (key, "pinentry-user-data"))
243     {
244       if (opt.pinentry_user_data)
245         free (opt.pinentry_user_data);
246       opt.pinentry_user_data = strdup (value);
247       if (!opt.pinentry_user_data)
248         return out_of_core ();
249     }
250   else if (!strcmp (key, "list-mode"))
251     {
252       int i = *value? atoi (value) : 0;
253       if (!i || i == 1) /* default and mode 1 */
254         {
255           ctrl->server_local->list_internal = 1;
256           ctrl->server_local->list_external = 0;
257         }
258       else if (i == 2)
259         {
260           ctrl->server_local->list_internal = 0;
261           ctrl->server_local->list_external = 1;
262         }
263       else if (i == 3)
264         {
265           ctrl->server_local->list_internal = 1;
266           ctrl->server_local->list_external = 1;
267         }
268       else
269         return gpg_error (GPG_ERR_ASS_PARAMETER);
270     }
271   else if (!strcmp (key, "list-to-output"))
272     {
273       int i = *value? atoi (value) : 0;
274       ctrl->server_local->list_to_output = i;
275     }
276   else if (!strcmp (key, "with-validation"))
277     {
278       int i = *value? atoi (value) : 0;
279       ctrl->with_validation = i;
280     }
281   else if (!strcmp (key, "validation-model"))
282     {
283       int i = gpgsm_parse_validation_model (value);
284       if ( i >= 0 && i <= 1 )
285         ctrl->validation_model = i;
286       else
287         return gpg_error (GPG_ERR_ASS_PARAMETER);
288     }
289   else if (!strcmp (key, "with-key-data"))
290     {
291       opt.with_key_data = 1;
292     }
293   else if (!strcmp (key, "enable-audit-log"))
294     {
295       int i = *value? atoi (value) : 0;
296       ctrl->server_local->enable_audit_log = i;
297     }
298   else if (!strcmp (key, "allow-pinentry-notify"))
299     ctrl->server_local->allow_pinentry_notify = 1;
300   else if (!strcmp (key, "with-ephemeral-keys"))
301     {
302       int i = *value? atoi (value) : 0;
303       ctrl->with_ephemeral_keys = i;
304     }
305   else if (!strcmp (key, "no-encrypt-to"))
306     {
307       ctrl->server_local->no_encrypt_to = 1;
308     }
309   else
310     return gpg_error (GPG_ERR_UNKNOWN_OPTION);
311
312   return 0;
313 }
314
315
316 static void
317 reset_notify (assuan_context_t ctx)
318 {
319   ctrl_t ctrl = assuan_get_pointer (ctx);
320
321   gpgsm_release_certlist (ctrl->server_local->recplist);
322   gpgsm_release_certlist (ctrl->server_local->signerlist);
323   ctrl->server_local->recplist = NULL;
324   ctrl->server_local->signerlist = NULL;
325   close_message_fd (ctrl);
326   assuan_close_input_fd (ctx);
327   assuan_close_output_fd (ctx);
328 }
329
330
331 static void
332 input_notify (assuan_context_t ctx, const char *line)
333 {
334   ctrl_t ctrl = assuan_get_pointer (ctx);
335
336   ctrl->autodetect_encoding = 0;
337   ctrl->is_pem = 0;
338   ctrl->is_base64 = 0;
339   if (strstr (line, "--armor"))
340     ctrl->is_pem = 1;  
341   else if (strstr (line, "--base64"))
342     ctrl->is_base64 = 1; 
343   else if (strstr (line, "--binary"))
344     ;
345   else
346     ctrl->autodetect_encoding = 1;
347 }
348
349 static void
350 output_notify (assuan_context_t ctx, const char *line)
351 {
352   ctrl_t ctrl = assuan_get_pointer (ctx);
353
354   ctrl->create_pem = 0;
355   ctrl->create_base64 = 0;
356   if (strstr (line, "--armor"))
357     ctrl->create_pem = 1;  
358   else if (strstr (line, "--base64"))
359     ctrl->create_base64 = 1; /* just the raw output */
360 }
361
362
363
364 /*  RECIPIENT <userID>
365
366   Set the recipient for the encryption.  <userID> should be the
367   internal representation of the key; the server may accept any other
368   way of specification [we will support this].  If this is a valid and
369   trusted recipient the server does respond with OK, otherwise the
370   return is an ERR with the reason why the recipient can't be used,
371   the encryption will then not be done for this recipient.  If the
372   policy is not to encrypt at all if not all recipients are valid, the
373   client has to take care of this.  All RECIPIENT commands are
374   cumulative until a RESET or an successful ENCRYPT command.  */
375 static int 
376 cmd_recipient (assuan_context_t ctx, char *line)
377 {
378   ctrl_t ctrl = assuan_get_pointer (ctx);
379   int rc;
380
381   if (!ctrl->audit)
382     rc = start_audit_session (ctrl);
383   else
384     rc = 0;
385
386   if (!rc)
387     rc = gpgsm_add_to_certlist (ctrl, line, 0,
388                                 &ctrl->server_local->recplist, 0);
389   if (rc)
390     {
391       gpg_err_code_t r = gpg_err_code (rc);
392       gpgsm_status2 (ctrl, STATUS_INV_RECP,
393                    r == -1? "1":
394                    r == GPG_ERR_NO_PUBKEY?       "1":
395                    r == GPG_ERR_AMBIGUOUS_NAME?  "2":
396                    r == GPG_ERR_WRONG_KEY_USAGE? "3":
397                    r == GPG_ERR_CERT_REVOKED?    "4":
398                    r == GPG_ERR_CERT_EXPIRED?    "5":
399                    r == GPG_ERR_NO_CRL_KNOWN?    "6":
400                    r == GPG_ERR_CRL_TOO_OLD?     "7":
401                    r == GPG_ERR_NO_POLICY_MATCH? "8":
402                    r == GPG_ERR_MISSING_CERT?   "11":
403                    "0",
404                    line, NULL);
405     }
406
407   return rc;
408 }
409
410 /*  SIGNER <userID>
411
412   Set the signer's keys for the signature creation.  <userID> should
413   be the internal representation of the key; the server may accept any
414   other way of specification [we will support this].  If this is a
415   valid and usable signing key the server does respond with OK,
416   otherwise it returns an ERR with the reason why the key can't be
417   used, the signing will then not be done for this key.  If the policy
418   is not to sign at all if not all signer keys are valid, the client
419   has to take care of this.  All SIGNER commands are cumulative until
420   a RESET but they are *not* reset by an SIGN command becuase it can
421   be expected that set of signers are used for more than one sign
422   operation.  
423
424   Note that this command returns an INV_RECP status which is a bit
425   strange, but they are very similar.  */
426 static int 
427 cmd_signer (assuan_context_t ctx, char *line)
428 {
429   ctrl_t ctrl = assuan_get_pointer (ctx);
430   int rc;
431
432   rc = gpgsm_add_to_certlist (ctrl, line, 1,
433                               &ctrl->server_local->signerlist, 0);
434   if (rc)
435     {
436       gpg_err_code_t r = gpg_err_code (rc);
437       gpgsm_status2 (ctrl, STATUS_INV_RECP,
438                    r == -1?                          "1":
439                    r == GPG_ERR_NO_PUBKEY?           "1":
440                    r == GPG_ERR_AMBIGUOUS_NAME?      "2":
441                    r == GPG_ERR_WRONG_KEY_USAGE?     "3":
442                    r == GPG_ERR_CERT_REVOKED?        "4":
443                    r == GPG_ERR_CERT_EXPIRED?        "5":
444                    r == GPG_ERR_NO_CRL_KNOWN?        "6":
445                    r == GPG_ERR_CRL_TOO_OLD?         "7":
446                    r == GPG_ERR_NO_POLICY_MATCH?     "8":
447                    r == GPG_ERR_NO_SECKEY?           "9":
448                    r == GPG_ERR_MISSING_CERT?       "11":
449                    "0",
450                   line, NULL);
451     }
452   return rc;
453 }
454
455
456 /* ENCRYPT 
457
458   Do the actual encryption process. Takes the plaintext from the INPUT
459   command, writes to the ciphertext to the file descriptor set with
460   the OUTPUT command, take the recipients form all the recipients set
461   so far.  If this command fails the clients should try to delete all
462   output currently done or otherwise mark it as invalid.  GPGSM does
463   ensure that there won't be any security problem with leftover data
464   on the output in this case.
465
466   This command should in general not fail, as all necessary checks
467   have been done while setting the recipients.  The input and output
468   pipes are closed. */
469 static int 
470 cmd_encrypt (assuan_context_t ctx, char *line)
471 {
472   ctrl_t ctrl = assuan_get_pointer (ctx);
473   certlist_t cl;
474   int inp_fd, out_fd;
475   FILE *out_fp;
476   int rc;
477
478   (void)line;
479
480   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
481   if (inp_fd == -1)
482     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
483   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
484   if (out_fd == -1)
485     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
486
487   out_fp = fdopen (dup (out_fd), "w");
488   if (!out_fp)
489     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
490   
491   /* Now add all encrypt-to marked recipients from the default
492      list. */
493   rc = 0;
494   if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
495     {
496       for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
497         if (cl->is_encrypt_to)
498           rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
499                                            &ctrl->server_local->recplist, 1);
500     }
501   if (!rc)
502     rc = ctrl->audit? 0 : start_audit_session (ctrl);
503   if (!rc)
504     rc = gpgsm_encrypt (assuan_get_pointer (ctx),
505                         ctrl->server_local->recplist,
506                         inp_fd, out_fp);
507   fclose (out_fp);
508
509   gpgsm_release_certlist (ctrl->server_local->recplist);
510   ctrl->server_local->recplist = NULL;
511   /* Close and reset the fd */
512   close_message_fd (ctrl);
513   assuan_close_input_fd (ctx);
514   assuan_close_output_fd (ctx);
515   return rc;
516 }
517
518
519 /* DECRYPT
520
521   This performs the decrypt operation after doing some check on the
522   internal state. (e.g. that only needed data has been set).  Because
523   it utilizes the GPG-Agent for the session key decryption, there is
524   no need to ask the client for a protecting passphrase - GpgAgent
525   does take care of this by requesting this from the user. */
526 static int 
527 cmd_decrypt (assuan_context_t ctx, char *line)
528 {
529   ctrl_t ctrl = assuan_get_pointer (ctx);
530   int inp_fd, out_fd;
531   FILE *out_fp;
532   int rc;
533
534   (void)line;
535
536   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
537   if (inp_fd == -1)
538     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
539   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
540   if (out_fd == -1)
541     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
542
543   out_fp = fdopen (dup(out_fd), "w");
544   if (!out_fp)
545     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
546
547   rc = start_audit_session (ctrl);
548   if (!rc)
549     rc = gpgsm_decrypt (ctrl, inp_fd, out_fp); 
550   fclose (out_fp);
551
552   /* close and reset the fd */
553   close_message_fd (ctrl);
554   assuan_close_input_fd (ctx);
555   assuan_close_output_fd (ctx);
556
557   return rc;
558 }
559
560
561 /* VERIFY
562
563   This does a verify operation on the message send to the input-FD.
564   The result is written out using status lines.  If an output FD was
565   given, the signed text will be written to that.
566   
567   If the signature is a detached one, the server will inquire about
568   the signed material and the client must provide it.
569   */
570 static int 
571 cmd_verify (assuan_context_t ctx, char *line)
572 {
573   int rc;
574   ctrl_t ctrl = assuan_get_pointer (ctx);
575   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
576   int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
577   FILE *out_fp = NULL;
578
579   (void)line;
580
581   if (fd == -1)
582     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
583
584   if (out_fd != -1)
585     {
586       out_fp = fdopen ( dup(out_fd), "w");
587       if (!out_fp)
588         return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
589     }
590
591   rc = start_audit_session (ctrl);
592   if (!rc)
593     rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
594                        ctrl->server_local->message_fd, out_fp);
595   if (out_fp)
596     fclose (out_fp);
597
598   /* close and reset the fd */
599   close_message_fd (ctrl);
600   assuan_close_input_fd (ctx);
601   assuan_close_output_fd (ctx);
602
603   return rc;
604 }
605
606
607 /* SIGN [--detached]
608
609   Sign the data set with the INPUT command and write it to the sink
610   set by OUTPUT.  With "--detached" specified, a detached signature is
611   created (surprise).  */
612 static int 
613 cmd_sign (assuan_context_t ctx, char *line)
614 {
615   ctrl_t ctrl = assuan_get_pointer (ctx);
616   int inp_fd, out_fd;
617   FILE *out_fp;
618   int detached;
619   int rc;
620
621   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
622   if (inp_fd == -1)
623     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
624   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
625   if (out_fd == -1)
626     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
627
628   detached = has_option (line, "--detached"); 
629
630   out_fp = fdopen ( dup(out_fd), "w");
631   if (!out_fp)
632     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
633
634   rc = start_audit_session (ctrl);
635   if (!rc)
636     rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
637                      inp_fd, detached, out_fp);
638   fclose (out_fp);
639
640   /* close and reset the fd */
641   close_message_fd (ctrl);
642   assuan_close_input_fd (ctx);
643   assuan_close_output_fd (ctx);
644
645   return rc;
646 }
647
648
649 /* IMPORT
650
651   Import the certificates read form the input-fd, return status
652   message for each imported one.  The import checks the validity of
653   the certificate but not of the entire chain.  It is possible to
654   import expired certificates.  */
655 static int 
656 cmd_import (assuan_context_t ctx, char *line)
657 {
658   ctrl_t ctrl = assuan_get_pointer (ctx);
659   int rc;
660   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
661
662   (void)line;
663
664   if (fd == -1)
665     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
666
667   rc = gpgsm_import (assuan_get_pointer (ctx), fd);
668
669   /* close and reset the fd */
670   close_message_fd (ctrl);
671   assuan_close_input_fd (ctx);
672   assuan_close_output_fd (ctx);
673
674   return rc;
675 }
676
677
678 /* EXPORT [--data [--armor|--base64]] [--] pattern
679
680  */
681
682 static int 
683 cmd_export (assuan_context_t ctx, char *line)
684 {
685   ctrl_t ctrl = assuan_get_pointer (ctx);
686   char *p;
687   strlist_t list, sl;
688   int use_data;
689   
690   use_data = has_option (line, "--data");
691
692   if (use_data)
693     {
694       /* We need to override any possible setting done by an OUTPUT command. */
695       ctrl->create_pem = has_option (line, "--armor");
696       ctrl->create_base64 = has_option (line, "--base64");
697     }
698
699   line = skip_options (line);
700
701   /* Break the line down into an strlist_t. */
702   list = NULL;
703   for (p=line; *p; line = p)
704     {
705       while (*p && *p != ' ')
706         p++;
707       if (*p)
708         *p++ = 0;
709       if (*line)
710         {
711           sl = xtrymalloc (sizeof *sl + strlen (line));
712           if (!sl)
713             {
714               free_strlist (list);
715               return out_of_core ();
716             }
717           sl->flags = 0;
718           strcpy_escaped_plus (sl->d, line);
719           sl->next = list;
720           list = sl;
721         }
722     }
723
724   if (use_data)
725     {
726       estream_t stream;
727
728       stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
729       if (!stream)
730         {
731           free_strlist (list);
732           return set_error (GPG_ERR_ASS_GENERAL, 
733                             "error setting up a data stream");
734         }
735       gpgsm_export (ctrl, list, NULL, stream);
736       es_fclose (stream);
737     }
738   else
739     {
740       int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
741       FILE *out_fp;
742
743       if (fd == -1)
744         {
745           free_strlist (list);
746           return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
747         }
748       out_fp = fdopen ( dup(fd), "w");
749       if (!out_fp)
750         {
751           free_strlist (list);
752           return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
753         }
754       
755       gpgsm_export (ctrl, list, out_fp, NULL);
756       fclose (out_fp);
757     }
758
759   free_strlist (list);
760   /* Close and reset the fds. */
761   close_message_fd (ctrl);
762   assuan_close_input_fd (ctx);
763   assuan_close_output_fd (ctx);
764   return 0;
765 }
766
767
768 static int 
769 cmd_delkeys (assuan_context_t ctx, char *line)
770 {
771   ctrl_t ctrl = assuan_get_pointer (ctx);
772   char *p;
773   strlist_t list, sl;
774   int rc;
775
776   /* break the line down into an strlist_t */
777   list = NULL;
778   for (p=line; *p; line = p)
779     {
780       while (*p && *p != ' ')
781         p++;
782       if (*p)
783         *p++ = 0;
784       if (*line)
785         {
786           sl = xtrymalloc (sizeof *sl + strlen (line));
787           if (!sl)
788             {
789               free_strlist (list);
790               return out_of_core ();
791             }
792           sl->flags = 0;
793           strcpy_escaped_plus (sl->d, line);
794           sl->next = list;
795           list = sl;
796         }
797     }
798
799   rc = gpgsm_delete (ctrl, list);
800   free_strlist (list);
801
802   /* close and reset the fd */
803   close_message_fd (ctrl);
804   assuan_close_input_fd (ctx);
805   assuan_close_output_fd (ctx);
806
807   return rc;
808 }
809
810
811
812 /* MESSAGE FD=<n>
813
814    Set the file descriptor to read a message which is used with
815    detached signatures */
816 static int 
817 cmd_message (assuan_context_t ctx, char *line)
818 {
819   int rc;
820   gnupg_fd_t sysfd;
821   int fd;
822   ctrl_t ctrl = assuan_get_pointer (ctx);
823
824   rc = assuan_command_parse_fd (ctx, line, &sysfd);
825   if (rc)
826     return rc;
827   fd = translate_sys2libc_fd (sysfd, 0);
828   if (fd == -1)
829     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
830   ctrl->server_local->message_fd = fd;
831   return 0;
832 }
833
834 /* LISTKEYS [<patterns>]
835    DUMPKEYS [<patterns>]
836    LISTSECRETKEYS [<patterns>]
837    DUMPSECRETKEYS [<patterns>]
838 */
839 static int 
840 do_listkeys (assuan_context_t ctx, char *line, int mode)
841 {
842   ctrl_t ctrl = assuan_get_pointer (ctx);
843   estream_t fp;
844   char *p;
845   strlist_t list, sl;
846   unsigned int listmode;
847   gpg_error_t err;
848
849   /* Break the line down into an strlist. */
850   list = NULL;
851   for (p=line; *p; line = p)
852     {
853       while (*p && *p != ' ')
854         p++;
855       if (*p)
856         *p++ = 0;
857       if (*line)
858         {
859           sl = xtrymalloc (sizeof *sl + strlen (line));
860           if (!sl)
861             {
862               free_strlist (list);
863               return out_of_core ();
864             }
865           sl->flags = 0;
866           strcpy_escaped_plus (sl->d, line);
867           sl->next = list;
868           list = sl;
869         }
870     }
871
872   if (ctrl->server_local->list_to_output)
873     {
874       int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
875
876       if ( outfd == -1 )
877         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
878       fp = es_fdopen ( dup (outfd), "w");
879       if (!fp)
880         return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
881     }
882   else
883     {
884       fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
885       if (!fp)
886         return set_error (GPG_ERR_ASS_GENERAL, 
887                           "error setting up a data stream");
888     }
889   
890   ctrl->with_colons = 1;
891   listmode = mode; 
892   if (ctrl->server_local->list_internal)
893     listmode |= (1<<6);
894   if (ctrl->server_local->list_external)
895     listmode |= (1<<7);
896   err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
897   free_strlist (list);
898   es_fclose (fp);
899   if (ctrl->server_local->list_to_output)
900     assuan_close_output_fd (ctx);
901   return err;
902 }
903
904 static int 
905 cmd_listkeys (assuan_context_t ctx, char *line)
906 {
907   return do_listkeys (ctx, line, 3);
908 }
909
910 static int 
911 cmd_dumpkeys (assuan_context_t ctx, char *line)
912 {
913   return do_listkeys (ctx, line, 259);
914 }
915
916 static int 
917 cmd_listsecretkeys (assuan_context_t ctx, char *line)
918 {
919   return do_listkeys (ctx, line, 2);
920 }
921
922 static int 
923 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
924 {
925   return do_listkeys (ctx, line, 258);
926 }
927
928 \f
929 /* GENKEY
930
931    Read the parameters in native format from the input fd and write a
932    certificate request to the output.
933  */
934 static int 
935 cmd_genkey (assuan_context_t ctx, char *line)
936 {
937   ctrl_t ctrl = assuan_get_pointer (ctx);
938   int inp_fd, out_fd;
939   FILE *out_fp;
940   int rc;
941   estream_t in_stream;
942
943   (void)line;
944
945   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
946   if (inp_fd == -1)
947     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
948   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
949   if (out_fd == -1)
950     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
951
952   in_stream = es_fdopen_nc (inp_fd, "r");
953   if (!in_stream)
954     return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
955
956   out_fp = fdopen ( dup(out_fd), "w");
957   if (!out_fp)
958     {
959       es_fclose (in_stream);
960       return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
961     }
962   rc = gpgsm_genkey (ctrl, in_stream, out_fp);
963   fclose (out_fp);
964
965   /* close and reset the fds */
966   assuan_close_input_fd (ctx);
967   assuan_close_output_fd (ctx);
968
969   return rc;
970 }
971
972
973 \f
974 /* GETAUDITLOG [--data] [--html]
975
976    !!!WORK in PROGRESS!!!
977
978    If --data is used, the output is send using D-lines and not to the
979    source given by an OUTPUT command.
980
981    If --html is used the output is formated as an XHTML block. This is
982    designed to be incorporated into a HTML document.
983  */
984 static int 
985 cmd_getauditlog (assuan_context_t ctx, char *line)
986 {
987   ctrl_t ctrl = assuan_get_pointer (ctx);
988   int  out_fd;
989   estream_t out_stream;
990   int opt_data, opt_html;
991   int rc;
992
993   opt_data = has_option (line, "--data"); 
994   opt_html = has_option (line, "--html"); 
995   line = skip_options (line);
996
997   if (!ctrl->audit)
998     return gpg_error (GPG_ERR_NO_DATA);
999
1000   if (opt_data)
1001     {
1002       out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1003       if (!out_stream)
1004         return set_error (GPG_ERR_ASS_GENERAL, 
1005                           "error setting up a data stream");
1006     }
1007   else
1008     {
1009       out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1010       if (out_fd == -1)
1011         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1012       
1013       out_stream = es_fdopen_nc ( dup (out_fd), "w");
1014       if (!out_stream)
1015         {
1016           return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1017         }
1018     }
1019
1020   audit_print_result (ctrl->audit, out_stream, opt_html);
1021   rc = 0;
1022
1023   es_fclose (out_stream);
1024
1025   /* Close and reset the fd. */
1026   if (!opt_data)
1027     assuan_close_output_fd (ctx);
1028   return rc;
1029 }
1030
1031
1032 /* GETINFO <what>
1033
1034    Multipurpose function to return a variety of information.
1035    Supported values for WHAT are:
1036
1037      version     - Return the version of the program.
1038      pid         - Return the process id of the server.
1039      agent-check - Return success if the agent is running.
1040
1041  */
1042 static int
1043 cmd_getinfo (assuan_context_t ctx, char *line)
1044 {
1045   int rc;
1046
1047   if (!strcmp (line, "version"))
1048     {
1049       const char *s = VERSION;
1050       rc = assuan_send_data (ctx, s, strlen (s));
1051     }
1052   else if (!strcmp (line, "pid"))
1053     {
1054       char numbuf[50];
1055
1056       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1057       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1058     }
1059   else if (!strcmp (line, "agent-check"))
1060     {
1061       ctrl_t ctrl = assuan_get_pointer (ctx);
1062       rc = gpgsm_agent_send_nop (ctrl);
1063     }
1064   else
1065     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1066   return rc;
1067 }
1068
1069
1070 \f
1071 /* Tell the assuan library about our commands */
1072 static int
1073 register_commands (assuan_context_t ctx)
1074 {
1075   static struct {
1076     const char *name;
1077     int (*handler)(assuan_context_t, char *line);
1078   } table[] = {
1079     { "RECIPIENT",     cmd_recipient },
1080     { "SIGNER",        cmd_signer },
1081     { "ENCRYPT",       cmd_encrypt },
1082     { "DECRYPT",       cmd_decrypt },
1083     { "VERIFY",        cmd_verify },
1084     { "SIGN",          cmd_sign },
1085     { "IMPORT",        cmd_import },
1086     { "EXPORT",        cmd_export },
1087     { "INPUT",         NULL }, 
1088     { "OUTPUT",        NULL }, 
1089     { "MESSAGE",       cmd_message },
1090     { "LISTKEYS",      cmd_listkeys },
1091     { "DUMPKEYS",      cmd_dumpkeys },
1092     { "LISTSECRETKEYS",cmd_listsecretkeys },
1093     { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1094     { "GENKEY",        cmd_genkey },
1095     { "DELKEYS",       cmd_delkeys },
1096     { "GETAUDITLOG",   cmd_getauditlog },
1097     { "GETINFO",       cmd_getinfo },
1098     { NULL }
1099   };
1100   int i, rc;
1101
1102   for (i=0; table[i].name; i++)
1103     {
1104       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1105       if (rc)
1106         return rc;
1107     } 
1108   return 0;
1109 }
1110
1111 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1112    set from the command line or config file.  We only require those
1113    marked as encrypt-to. */
1114 void
1115 gpgsm_server (certlist_t default_recplist)
1116 {
1117   int rc;
1118   int filedes[2];
1119   assuan_context_t ctx;
1120   struct server_control_s ctrl;
1121   static const char hello[] = ("GNU Privacy Guard's S/M server "
1122                                VERSION " ready");
1123
1124   memset (&ctrl, 0, sizeof ctrl);
1125   gpgsm_init_default_ctrl (&ctrl);
1126
1127   /* We use a pipe based server so that we can work from scripts.
1128      assuan_init_pipe_server will automagically detect when we are
1129      called with a socketpair and ignore FIELDES in this case. */
1130   filedes[0] = 0;
1131   filedes[1] = 1;
1132   rc = assuan_init_pipe_server (&ctx, filedes);
1133   if (rc)
1134     {
1135       log_error ("failed to initialize the server: %s\n",
1136                  gpg_strerror (rc));
1137       gpgsm_exit (2);
1138     }
1139   rc = register_commands (ctx);
1140   if (rc)
1141     {
1142       log_error ("failed to the register commands with Assuan: %s\n",
1143                  gpg_strerror(rc));
1144       gpgsm_exit (2);
1145     }
1146   if (opt.verbose || opt.debug)
1147     {
1148       char *tmp = NULL;
1149       const char *s1 = getenv ("GPG_AGENT_INFO");
1150       const char *s2 = getenv ("DIRMNGR_INFO");
1151
1152       if (asprintf (&tmp,
1153                     "Home: %s\n"
1154                     "Config: %s\n"
1155                     "AgentInfo: %s\n"
1156                     "DirmngrInfo: %s\n"
1157                     "%s",
1158                     opt.homedir,
1159                     opt.config_filename,
1160                     s1?s1:"[not set]",
1161                     s2?s2:"[not set]",
1162                     hello) > 0)
1163         {
1164           assuan_set_hello_line (ctx, tmp);
1165           free (tmp);
1166         }
1167     }
1168   else
1169     assuan_set_hello_line (ctx, hello);
1170
1171   assuan_register_reset_notify (ctx, reset_notify);
1172   assuan_register_input_notify (ctx, input_notify);
1173   assuan_register_output_notify (ctx, output_notify);
1174   assuan_register_option_handler (ctx, option_handler);
1175
1176   assuan_set_pointer (ctx, &ctrl);
1177   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1178   ctrl.server_local->assuan_ctx = ctx;
1179   ctrl.server_local->message_fd = -1;
1180   ctrl.server_local->list_internal = 1;
1181   ctrl.server_local->list_external = 0;
1182   ctrl.server_local->default_recplist = default_recplist;
1183
1184   if (DBG_ASSUAN)
1185     assuan_set_log_stream (ctx, log_get_stream ());
1186
1187   for (;;)
1188     {
1189       rc = assuan_accept (ctx);
1190       if (rc == -1)
1191         {
1192           break;
1193         }
1194       else if (rc)
1195         {
1196           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1197           break;
1198         }
1199       
1200       rc = assuan_process (ctx);
1201       if (rc)
1202         {
1203           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1204           continue;
1205         }
1206     }
1207
1208   gpgsm_release_certlist (ctrl.server_local->recplist);
1209   ctrl.server_local->recplist = NULL;
1210   gpgsm_release_certlist (ctrl.server_local->signerlist);
1211   ctrl.server_local->signerlist = NULL;
1212   xfree (ctrl.server_local);
1213
1214   audit_release (ctrl.audit);
1215   ctrl.audit = NULL;
1216
1217   assuan_deinit_server (ctx);
1218 }
1219
1220
1221
1222 gpg_error_t
1223 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1224 {
1225   gpg_error_t err = 0;
1226   va_list arg_ptr;
1227   const char *text;
1228
1229   va_start (arg_ptr, no);
1230
1231   if (ctrl->no_server && ctrl->status_fd == -1)
1232     ; /* No status wanted. */
1233   else if (ctrl->no_server)
1234     {
1235       if (!statusfp)
1236         {
1237           if (ctrl->status_fd == 1)
1238             statusfp = stdout;
1239           else if (ctrl->status_fd == 2)
1240             statusfp = stderr;
1241           else
1242             statusfp = fdopen (ctrl->status_fd, "w");
1243       
1244           if (!statusfp)
1245             {
1246               log_fatal ("can't open fd %d for status output: %s\n",
1247                          ctrl->status_fd, strerror(errno));
1248             }
1249         }
1250       
1251       fputs ("[GNUPG:] ", statusfp);
1252       fputs (get_status_string (no), statusfp);
1253     
1254       while ( (text = va_arg (arg_ptr, const char*) ))
1255         {
1256           putc ( ' ', statusfp );
1257           for (; *text; text++) 
1258             {
1259               if (*text == '\n')
1260                 fputs ( "\\n", statusfp );
1261               else if (*text == '\r')
1262                 fputs ( "\\r", statusfp );
1263               else 
1264                 putc ( *(const byte *)text,  statusfp );
1265             }
1266         }
1267       putc ('\n', statusfp);
1268       fflush (statusfp);
1269     }
1270   else 
1271     {
1272       assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1273       char buf[950], *p;
1274       size_t n;
1275
1276       p = buf; 
1277       n = 0;
1278       while ( (text = va_arg (arg_ptr, const char *)) )
1279         {
1280           if (n)
1281             {
1282               *p++ = ' ';
1283               n++;
1284             }
1285           for ( ; *text && n < DIM (buf)-2; n++)
1286             *p++ = *text++;
1287         }
1288       *p = 0;
1289       err = assuan_write_status (ctx, get_status_string (no), buf);
1290     }
1291
1292   va_end (arg_ptr);
1293   return err;
1294 }
1295
1296 gpg_error_t
1297 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1298 {
1299   return gpgsm_status2 (ctrl, no, text, NULL);
1300 }
1301
1302 gpg_error_t
1303 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1304                             gpg_err_code_t ec)
1305 {
1306   char buf[30];
1307
1308   sprintf (buf, "%u", (unsigned int)ec);
1309   if (text)
1310     return gpgsm_status2 (ctrl, no, text, buf, NULL);
1311   else
1312     return gpgsm_status2 (ctrl, no, buf, NULL);
1313 }
1314
1315
1316 /* Helper to notify the client about Pinentry events.  Because that
1317    might disturb some older clients, this is only done when enabled
1318    via an option.  Returns an gpg error code. */
1319 gpg_error_t
1320 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1321 {
1322   if (!ctrl || !ctrl->server_local 
1323       || !ctrl->server_local->allow_pinentry_notify)
1324     return 0;
1325   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
1326 }
1327
1328
1329