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