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