Add gpgsm server command GETINFO agent-check.
[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   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
469   if (inp_fd == -1)
470     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
471   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
472   if (out_fd == -1)
473     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
474
475   out_fp = fdopen (dup (out_fd), "w");
476   if (!out_fp)
477     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
478   
479   /* Now add all encrypt-to marked recipients from the default
480      list. */
481   rc = 0;
482   if (!opt.no_encrypt_to)
483     {
484       for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
485         if (cl->is_encrypt_to)
486           rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
487                                            &ctrl->server_local->recplist, 1);
488     }
489   if (!rc)
490     rc = ctrl->audit? 0 : start_audit_session (ctrl);
491   if (!rc)
492     rc = gpgsm_encrypt (assuan_get_pointer (ctx),
493                         ctrl->server_local->recplist,
494                         inp_fd, out_fp);
495   fclose (out_fp);
496
497   gpgsm_release_certlist (ctrl->server_local->recplist);
498   ctrl->server_local->recplist = NULL;
499   /* Close and reset the fd */
500   close_message_fd (ctrl);
501   assuan_close_input_fd (ctx);
502   assuan_close_output_fd (ctx);
503   return rc;
504 }
505
506
507 /* DECRYPT
508
509   This performs the decrypt operation after doing some check on the
510   internal state. (e.g. that only needed data has been set).  Because
511   it utilizes the GPG-Agent for the session key decryption, there is
512   no need to ask the client for a protecting passphrase - GpgAgent
513   does take care of this by requesting this from the user. */
514 static int 
515 cmd_decrypt (assuan_context_t ctx, char *line)
516 {
517   ctrl_t ctrl = assuan_get_pointer (ctx);
518   int inp_fd, out_fd;
519   FILE *out_fp;
520   int rc;
521
522   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
523   if (inp_fd == -1)
524     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
525   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
526   if (out_fd == -1)
527     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
528
529   out_fp = fdopen (dup(out_fd), "w");
530   if (!out_fp)
531     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
532
533   rc = start_audit_session (ctrl);
534   if (!rc)
535     rc = gpgsm_decrypt (ctrl, inp_fd, out_fp); 
536   fclose (out_fp);
537
538   /* close and reset the fd */
539   close_message_fd (ctrl);
540   assuan_close_input_fd (ctx);
541   assuan_close_output_fd (ctx);
542
543   return rc;
544 }
545
546
547 /* VERIFY
548
549   This does a verify operation on the message send to the input-FD.
550   The result is written out using status lines.  If an output FD was
551   given, the signed text will be written to that.
552   
553   If the signature is a detached one, the server will inquire about
554   the signed material and the client must provide it.
555   */
556 static int 
557 cmd_verify (assuan_context_t ctx, char *line)
558 {
559   int rc;
560   ctrl_t ctrl = assuan_get_pointer (ctx);
561   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
562   int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
563   FILE *out_fp = NULL;
564
565   if (fd == -1)
566     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
567
568   if (out_fd != -1)
569     {
570       out_fp = fdopen ( dup(out_fd), "w");
571       if (!out_fp)
572         return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
573     }
574
575   rc = start_audit_session (ctrl);
576   if (!rc)
577     rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
578                        ctrl->server_local->message_fd, out_fp);
579   if (out_fp)
580     fclose (out_fp);
581
582   /* close and reset the fd */
583   close_message_fd (ctrl);
584   assuan_close_input_fd (ctx);
585   assuan_close_output_fd (ctx);
586
587   return rc;
588 }
589
590
591 /* SIGN [--detached]
592
593   Sign the data set with the INPUT command and write it to the sink
594   set by OUTPUT.  With "--detached" specified, a detached signature is
595   created (surprise).  */
596 static int 
597 cmd_sign (assuan_context_t ctx, char *line)
598 {
599   ctrl_t ctrl = assuan_get_pointer (ctx);
600   int inp_fd, out_fd;
601   FILE *out_fp;
602   int detached;
603   int rc;
604
605   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
606   if (inp_fd == -1)
607     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
608   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
609   if (out_fd == -1)
610     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
611
612   detached = has_option (line, "--detached"); 
613
614   out_fp = fdopen ( dup(out_fd), "w");
615   if (!out_fp)
616     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
617
618   rc = start_audit_session (ctrl);
619   if (!rc)
620     rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
621                      inp_fd, detached, out_fp);
622   fclose (out_fp);
623
624   /* close and reset the fd */
625   close_message_fd (ctrl);
626   assuan_close_input_fd (ctx);
627   assuan_close_output_fd (ctx);
628
629   return rc;
630 }
631
632
633 /* IMPORT
634
635   Import the certificates read form the input-fd, return status
636   message for each imported one.  The import checks the validity of
637   the certificate but not of the entire chain.  It is possible to
638   import expired certificates.  */
639 static int 
640 cmd_import (assuan_context_t ctx, char *line)
641 {
642   ctrl_t ctrl = assuan_get_pointer (ctx);
643   int rc;
644   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
645
646   if (fd == -1)
647     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
648
649   rc = gpgsm_import (assuan_get_pointer (ctx), fd);
650
651   /* close and reset the fd */
652   close_message_fd (ctrl);
653   assuan_close_input_fd (ctx);
654   assuan_close_output_fd (ctx);
655
656   return rc;
657 }
658
659
660 /* EXPORT [--data [--armor|--base64]] [--] pattern
661
662  */
663
664 static int 
665 cmd_export (assuan_context_t ctx, char *line)
666 {
667   ctrl_t ctrl = assuan_get_pointer (ctx);
668   char *p;
669   strlist_t list, sl;
670   int use_data;
671   
672   use_data = has_option (line, "--data");
673
674   if (use_data)
675     {
676       /* We need to override any possible setting done by an OUTPUT command. */
677       ctrl->create_pem = has_option (line, "--armor");
678       ctrl->create_base64 = has_option (line, "--base64");
679     }
680
681   line = skip_options (line);
682
683   /* Break the line down into an strlist_t. */
684   list = NULL;
685   for (p=line; *p; line = p)
686     {
687       while (*p && *p != ' ')
688         p++;
689       if (*p)
690         *p++ = 0;
691       if (*line)
692         {
693           sl = xtrymalloc (sizeof *sl + strlen (line));
694           if (!sl)
695             {
696               free_strlist (list);
697               return out_of_core ();
698             }
699           sl->flags = 0;
700           strcpy_escaped_plus (sl->d, line);
701           sl->next = list;
702           list = sl;
703         }
704     }
705
706   if (use_data)
707     {
708       estream_t stream;
709
710       stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
711       if (!stream)
712         {
713           free_strlist (list);
714           return set_error (GPG_ERR_ASS_GENERAL, 
715                             "error setting up a data stream");
716         }
717       gpgsm_export (ctrl, list, NULL, stream);
718       es_fclose (stream);
719     }
720   else
721     {
722       int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
723       FILE *out_fp;
724
725       if (fd == -1)
726         {
727           free_strlist (list);
728           return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
729         }
730       out_fp = fdopen ( dup(fd), "w");
731       if (!out_fp)
732         {
733           free_strlist (list);
734           return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
735         }
736       
737       gpgsm_export (ctrl, list, out_fp, NULL);
738       fclose (out_fp);
739     }
740
741   free_strlist (list);
742   /* Close and reset the fds. */
743   close_message_fd (ctrl);
744   assuan_close_input_fd (ctx);
745   assuan_close_output_fd (ctx);
746   return 0;
747 }
748
749
750 static int 
751 cmd_delkeys (assuan_context_t ctx, char *line)
752 {
753   ctrl_t ctrl = assuan_get_pointer (ctx);
754   char *p;
755   strlist_t list, sl;
756   int rc;
757
758   /* break the line down into an strlist_t */
759   list = NULL;
760   for (p=line; *p; line = p)
761     {
762       while (*p && *p != ' ')
763         p++;
764       if (*p)
765         *p++ = 0;
766       if (*line)
767         {
768           sl = xtrymalloc (sizeof *sl + strlen (line));
769           if (!sl)
770             {
771               free_strlist (list);
772               return out_of_core ();
773             }
774           sl->flags = 0;
775           strcpy_escaped_plus (sl->d, line);
776           sl->next = list;
777           list = sl;
778         }
779     }
780
781   rc = gpgsm_delete (ctrl, list);
782   free_strlist (list);
783
784   /* close and reset the fd */
785   close_message_fd (ctrl);
786   assuan_close_input_fd (ctx);
787   assuan_close_output_fd (ctx);
788
789   return rc;
790 }
791
792
793
794 /* MESSAGE FD=<n>
795
796    Set the file descriptor to read a message which is used with
797    detached signatures */
798 static int 
799 cmd_message (assuan_context_t ctx, char *line)
800 {
801   int rc;
802   gnupg_fd_t sysfd;
803   int fd;
804   ctrl_t ctrl = assuan_get_pointer (ctx);
805
806   rc = assuan_command_parse_fd (ctx, line, &sysfd);
807   if (rc)
808     return rc;
809   fd = translate_sys2libc_fd (sysfd, 0);
810   if (fd == -1)
811     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
812   ctrl->server_local->message_fd = fd;
813   return 0;
814 }
815
816 /* LISTKEYS [<patterns>]
817    DUMPKEYS [<patterns>]
818    LISTSECRETKEYS [<patterns>]
819    DUMPSECRETKEYS [<patterns>]
820 */
821 static int 
822 do_listkeys (assuan_context_t ctx, char *line, int mode)
823 {
824   ctrl_t ctrl = assuan_get_pointer (ctx);
825   estream_t fp;
826   char *p;
827   strlist_t list, sl;
828   unsigned int listmode;
829   gpg_error_t err;
830
831   /* Break the line down into an strlist. */
832   list = NULL;
833   for (p=line; *p; line = p)
834     {
835       while (*p && *p != ' ')
836         p++;
837       if (*p)
838         *p++ = 0;
839       if (*line)
840         {
841           sl = xtrymalloc (sizeof *sl + strlen (line));
842           if (!sl)
843             {
844               free_strlist (list);
845               return out_of_core ();
846             }
847           sl->flags = 0;
848           strcpy_escaped_plus (sl->d, line);
849           sl->next = list;
850           list = sl;
851         }
852     }
853
854   if (ctrl->server_local->list_to_output)
855     {
856       int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
857
858       if ( outfd == -1 )
859         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
860       fp = es_fdopen ( dup (outfd), "w");
861       if (!fp)
862         return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
863     }
864   else
865     {
866       fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
867       if (!fp)
868         return set_error (GPG_ERR_ASS_GENERAL, 
869                           "error setting up a data stream");
870     }
871   
872   ctrl->with_colons = 1;
873   listmode = mode; 
874   if (ctrl->server_local->list_internal)
875     listmode |= (1<<6);
876   if (ctrl->server_local->list_external)
877     listmode |= (1<<7);
878   err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
879   free_strlist (list);
880   es_fclose (fp);
881   if (ctrl->server_local->list_to_output)
882     assuan_close_output_fd (ctx);
883   return err;
884 }
885
886 static int 
887 cmd_listkeys (assuan_context_t ctx, char *line)
888 {
889   return do_listkeys (ctx, line, 3);
890 }
891
892 static int 
893 cmd_dumpkeys (assuan_context_t ctx, char *line)
894 {
895   return do_listkeys (ctx, line, 259);
896 }
897
898 static int 
899 cmd_listsecretkeys (assuan_context_t ctx, char *line)
900 {
901   return do_listkeys (ctx, line, 2);
902 }
903
904 static int 
905 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
906 {
907   return do_listkeys (ctx, line, 258);
908 }
909
910 \f
911 /* GENKEY
912
913    Read the parameters in native format from the input fd and write a
914    certificate request to the output.
915  */
916 static int 
917 cmd_genkey (assuan_context_t ctx, char *line)
918 {
919   ctrl_t ctrl = assuan_get_pointer (ctx);
920   int inp_fd, out_fd;
921   FILE *out_fp;
922   int rc;
923   estream_t in_stream;
924
925   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
926   if (inp_fd == -1)
927     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
928   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
929   if (out_fd == -1)
930     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
931
932   in_stream = es_fdopen_nc (inp_fd, "r");
933   if (!in_stream)
934     return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
935
936   out_fp = fdopen ( dup(out_fd), "w");
937   if (!out_fp)
938     {
939       es_fclose (in_stream);
940       return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
941     }
942   rc = gpgsm_genkey (ctrl, in_stream, out_fp);
943   fclose (out_fp);
944
945   /* close and reset the fds */
946   assuan_close_input_fd (ctx);
947   assuan_close_output_fd (ctx);
948
949   return rc;
950 }
951
952
953 \f
954 /* GETAUDITLOG [--data] [--html]
955
956    !!!WORK in PROGRESS!!!
957
958    If --data is used, the output is send using D-lines and not to the
959    source given by an OUTPUT command.
960
961    If --html is used the output is formated as an XHTML block. This is
962    designed to be incorporated into a HTML document.
963  */
964 static int 
965 cmd_getauditlog (assuan_context_t ctx, char *line)
966 {
967   ctrl_t ctrl = assuan_get_pointer (ctx);
968   int  out_fd;
969   estream_t out_stream;
970   int opt_data, opt_html;
971   int rc;
972
973   opt_data = has_option (line, "--data"); 
974   opt_html = has_option (line, "--html"); 
975   line = skip_options (line);
976
977   if (!ctrl->audit)
978     return gpg_error (GPG_ERR_NO_DATA);
979
980   if (opt_data)
981     {
982       out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
983       if (!out_stream)
984         return set_error (GPG_ERR_ASS_GENERAL, 
985                           "error setting up a data stream");
986     }
987   else
988     {
989       out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
990       if (out_fd == -1)
991         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
992       
993       out_stream = es_fdopen_nc ( dup (out_fd), "w");
994       if (!out_stream)
995         {
996           return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
997         }
998     }
999
1000   audit_print_result (ctrl->audit, out_stream, opt_html);
1001   rc = 0;
1002
1003   es_fclose (out_stream);
1004
1005   /* Close and reset the fd. */
1006   if (!opt_data)
1007     assuan_close_output_fd (ctx);
1008   return rc;
1009 }
1010
1011
1012 /* GETINFO <what>
1013
1014    Multipurpose function to return a variety of information.
1015    Supported values for WHAT are:
1016
1017      version     - Return the version of the program.
1018      pid         - Return the process id of the server.
1019      agent-check - Return success if the agent is running.
1020
1021  */
1022 static int
1023 cmd_getinfo (assuan_context_t ctx, char *line)
1024 {
1025   int rc;
1026
1027   if (!strcmp (line, "version"))
1028     {
1029       const char *s = VERSION;
1030       rc = assuan_send_data (ctx, s, strlen (s));
1031     }
1032   else if (!strcmp (line, "pid"))
1033     {
1034       char numbuf[50];
1035
1036       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1037       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1038     }
1039   else if (!strcmp (line, "agent-check"))
1040     {
1041       ctrl_t ctrl = assuan_get_pointer (ctx);
1042       rc = gpgsm_agent_send_nop (ctrl);
1043     }
1044   else
1045     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1046   return rc;
1047 }
1048
1049
1050 \f
1051 /* Tell the assuan library about our commands */
1052 static int
1053 register_commands (assuan_context_t ctx)
1054 {
1055   static struct {
1056     const char *name;
1057     int (*handler)(assuan_context_t, char *line);
1058   } table[] = {
1059     { "RECIPIENT",     cmd_recipient },
1060     { "SIGNER",        cmd_signer },
1061     { "ENCRYPT",       cmd_encrypt },
1062     { "DECRYPT",       cmd_decrypt },
1063     { "VERIFY",        cmd_verify },
1064     { "SIGN",          cmd_sign },
1065     { "IMPORT",        cmd_import },
1066     { "EXPORT",        cmd_export },
1067     { "INPUT",         NULL }, 
1068     { "OUTPUT",        NULL }, 
1069     { "MESSAGE",       cmd_message },
1070     { "LISTKEYS",      cmd_listkeys },
1071     { "DUMPKEYS",      cmd_dumpkeys },
1072     { "LISTSECRETKEYS",cmd_listsecretkeys },
1073     { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1074     { "GENKEY",        cmd_genkey },
1075     { "DELKEYS",       cmd_delkeys },
1076     { "GETAUDITLOG",   cmd_getauditlog },
1077     { "GETINFO",       cmd_getinfo },
1078     { NULL }
1079   };
1080   int i, rc;
1081
1082   for (i=0; table[i].name; i++)
1083     {
1084       rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1085       if (rc)
1086         return rc;
1087     } 
1088   return 0;
1089 }
1090
1091 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1092    set from the command line or config file.  We only require those
1093    marked as encrypt-to. */
1094 void
1095 gpgsm_server (certlist_t default_recplist)
1096 {
1097   int rc;
1098   int filedes[2];
1099   assuan_context_t ctx;
1100   struct server_control_s ctrl;
1101   static const char hello[] = ("GNU Privacy Guard's S/M server "
1102                                VERSION " ready");
1103
1104   memset (&ctrl, 0, sizeof ctrl);
1105   gpgsm_init_default_ctrl (&ctrl);
1106
1107   /* We use a pipe based server so that we can work from scripts.
1108      assuan_init_pipe_server will automagically detect when we are
1109      called with a socketpair and ignore FIELDES in this case. */
1110   filedes[0] = 0;
1111   filedes[1] = 1;
1112   rc = assuan_init_pipe_server (&ctx, filedes);
1113   if (rc)
1114     {
1115       log_error ("failed to initialize the server: %s\n",
1116                  gpg_strerror (rc));
1117       gpgsm_exit (2);
1118     }
1119   rc = register_commands (ctx);
1120   if (rc)
1121     {
1122       log_error ("failed to the register commands with Assuan: %s\n",
1123                  gpg_strerror(rc));
1124       gpgsm_exit (2);
1125     }
1126   if (opt.verbose || opt.debug)
1127     {
1128       char *tmp = NULL;
1129       const char *s1 = getenv ("GPG_AGENT_INFO");
1130       const char *s2 = getenv ("DIRMNGR_INFO");
1131
1132       if (asprintf (&tmp,
1133                     "Home: %s\n"
1134                     "Config: %s\n"
1135                     "AgentInfo: %s\n"
1136                     "DirmngrInfo: %s\n"
1137                     "%s",
1138                     opt.homedir,
1139                     opt.config_filename,
1140                     s1?s1:"[not set]",
1141                     s2?s2:"[not set]",
1142                     hello) > 0)
1143         {
1144           assuan_set_hello_line (ctx, tmp);
1145           free (tmp);
1146         }
1147     }
1148   else
1149     assuan_set_hello_line (ctx, hello);
1150
1151   assuan_register_reset_notify (ctx, reset_notify);
1152   assuan_register_input_notify (ctx, input_notify);
1153   assuan_register_output_notify (ctx, output_notify);
1154   assuan_register_option_handler (ctx, option_handler);
1155
1156   assuan_set_pointer (ctx, &ctrl);
1157   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1158   ctrl.server_local->assuan_ctx = ctx;
1159   ctrl.server_local->message_fd = -1;
1160   ctrl.server_local->list_internal = 1;
1161   ctrl.server_local->list_external = 0;
1162   ctrl.server_local->default_recplist = default_recplist;
1163
1164   if (DBG_ASSUAN)
1165     assuan_set_log_stream (ctx, log_get_stream ());
1166
1167   for (;;)
1168     {
1169       rc = assuan_accept (ctx);
1170       if (rc == -1)
1171         {
1172           break;
1173         }
1174       else if (rc)
1175         {
1176           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1177           break;
1178         }
1179       
1180       rc = assuan_process (ctx);
1181       if (rc)
1182         {
1183           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1184           continue;
1185         }
1186     }
1187
1188   gpgsm_release_certlist (ctrl.server_local->recplist);
1189   ctrl.server_local->recplist = NULL;
1190   gpgsm_release_certlist (ctrl.server_local->signerlist);
1191   ctrl.server_local->signerlist = NULL;
1192   xfree (ctrl.server_local);
1193
1194   audit_release (ctrl.audit);
1195   ctrl.audit = NULL;
1196
1197   assuan_deinit_server (ctx);
1198 }
1199
1200
1201
1202 gpg_error_t
1203 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1204 {
1205   gpg_error_t err = 0;
1206   va_list arg_ptr;
1207   const char *text;
1208
1209   va_start (arg_ptr, no);
1210
1211   if (ctrl->no_server && ctrl->status_fd == -1)
1212     ; /* No status wanted. */
1213   else if (ctrl->no_server)
1214     {
1215       if (!statusfp)
1216         {
1217           if (ctrl->status_fd == 1)
1218             statusfp = stdout;
1219           else if (ctrl->status_fd == 2)
1220             statusfp = stderr;
1221           else
1222             statusfp = fdopen (ctrl->status_fd, "w");
1223       
1224           if (!statusfp)
1225             {
1226               log_fatal ("can't open fd %d for status output: %s\n",
1227                          ctrl->status_fd, strerror(errno));
1228             }
1229         }
1230       
1231       fputs ("[GNUPG:] ", statusfp);
1232       fputs (get_status_string (no), statusfp);
1233     
1234       while ( (text = va_arg (arg_ptr, const char*) ))
1235         {
1236           putc ( ' ', statusfp );
1237           for (; *text; text++) 
1238             {
1239               if (*text == '\n')
1240                 fputs ( "\\n", statusfp );
1241               else if (*text == '\r')
1242                 fputs ( "\\r", statusfp );
1243               else 
1244                 putc ( *(const byte *)text,  statusfp );
1245             }
1246         }
1247       putc ('\n', statusfp);
1248       fflush (statusfp);
1249     }
1250   else 
1251     {
1252       assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1253       char buf[950], *p;
1254       size_t n;
1255
1256       p = buf; 
1257       n = 0;
1258       while ( (text = va_arg (arg_ptr, const char *)) )
1259         {
1260           if (n)
1261             {
1262               *p++ = ' ';
1263               n++;
1264             }
1265           for ( ; *text && n < DIM (buf)-2; n++)
1266             *p++ = *text++;
1267         }
1268       *p = 0;
1269       err = assuan_write_status (ctx, get_status_string (no), buf);
1270     }
1271
1272   va_end (arg_ptr);
1273   return err;
1274 }
1275
1276 gpg_error_t
1277 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1278 {
1279   return gpgsm_status2 (ctrl, no, text, NULL);
1280 }
1281
1282 gpg_error_t
1283 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1284                             gpg_err_code_t ec)
1285 {
1286   char buf[30];
1287
1288   sprintf (buf, "%u", (unsigned int)ec);
1289   if (text)
1290     return gpgsm_status2 (ctrl, no, text, buf, NULL);
1291   else
1292     return gpgsm_status2 (ctrl, no, buf, NULL);
1293 }
1294
1295
1296 /* Helper to notify the client about Pinentry events.  Because that
1297    might disturb some older clients, this is only done when enabled
1298    via an option.  Returns an gpg error code. */
1299 gpg_error_t
1300 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1301 {
1302   if (!ctrl || !ctrl->server_local 
1303       || !ctrl->server_local->allow_pinentry_notify)
1304     return 0;
1305   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
1306 }
1307
1308
1309