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