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