Avoid catch-22 with README.main not being distributed but having the
[gnupg.git] / sm / server.c
blobb88dc69e9964f99c1479331d43c610acf00fcc7d
1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3 * 2007, 2008, 2009 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
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.
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.
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/>.
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>
30 #include <assuan.h>
32 #include "gpgsm.h"
33 #include "sysutils.h"
35 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
38 /* The filepointer for status message used in non-server mode */
39 static FILE *statusfp;
41 /* Data used to assuciate an Assuan context with local server data */
42 struct server_local_s {
43 assuan_context_t assuan_ctx;
44 int message_fd;
45 int list_internal;
46 int list_external;
47 int list_to_output; /* Write keylistings to the output fd. */
48 int enable_audit_log; /* Use an audit log. */
49 certlist_t recplist;
50 certlist_t signerlist;
51 certlist_t default_recplist; /* As set by main() - don't release. */
52 int allow_pinentry_notify; /* Set if pinentry notifications should
53 be passed back to the client. */
54 int no_encrypt_to; /* Local version of option. */
58 /* Cookie definition for assuan data line output. */
59 static ssize_t data_line_cookie_write (void *cookie,
60 const void *buffer, size_t size);
61 static int data_line_cookie_close (void *cookie);
62 static es_cookie_io_functions_t data_line_cookie_functions =
64 NULL,
65 data_line_cookie_write,
66 NULL,
67 data_line_cookie_close
72 static int command_has_option (const char *cmd, const char *cmdopt);
77 /* Note that it is sufficient to allocate the target string D as
78 long as the source string S, i.e.: strlen(s)+1; */
79 static void
80 strcpy_escaped_plus (char *d, const char *s)
82 while (*s)
84 if (*s == '%' && s[1] && s[2])
86 s++;
87 *d++ = xtoi_2 (s);
88 s += 2;
90 else if (*s == '+')
91 *d++ = ' ', s++;
92 else
93 *d++ = *s++;
95 *d = 0;
99 /* Skip over options.
100 Blanks after the options are also removed. */
101 static char *
102 skip_options (const char *line)
104 while (spacep (line))
105 line++;
106 while ( *line == '-' && line[1] == '-' )
108 while (*line && !spacep (line))
109 line++;
110 while (spacep (line))
111 line++;
113 return (char*)line;
117 /* Check whether the option NAME appears in LINE */
118 static int
119 has_option (const char *line, const char *name)
121 const char *s;
122 int n = strlen (name);
124 s = strstr (line, name);
125 if (s && s >= skip_options (line))
126 return 0;
127 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
131 /* A write handler used by es_fopencookie to write assuan data
132 lines. */
133 static ssize_t
134 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
136 assuan_context_t ctx = cookie;
138 if (assuan_send_data (ctx, buffer, size))
140 errno = EIO;
141 return -1;
144 return size;
147 static int
148 data_line_cookie_close (void *cookie)
150 assuan_context_t ctx = cookie;
152 if (assuan_send_data (ctx, NULL, 0))
154 errno = EIO;
155 return -1;
158 return 0;
162 static void
163 close_message_fd (ctrl_t ctrl)
165 if (ctrl->server_local->message_fd != -1)
167 close (ctrl->server_local->message_fd);
168 ctrl->server_local->message_fd = -1;
173 /* Start a new audit session if this has been enabled. */
174 static gpg_error_t
175 start_audit_session (ctrl_t ctrl)
177 audit_release (ctrl->audit);
178 ctrl->audit = NULL;
179 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
180 return gpg_error_from_syserror ();
182 return 0;
186 static int
187 option_handler (assuan_context_t ctx, const char *key, const char *value)
189 ctrl_t ctrl = assuan_get_pointer (ctx);
190 gpg_error_t err = 0;
192 if (!strcmp (key, "putenv"))
194 /* Change the session's environment to be used for the
195 Pinentry. Valid values are:
196 <NAME> Delete envvar NAME
197 <KEY>= Set envvar NAME to the empty string
198 <KEY>=<VALUE> Set envvar NAME to VALUE
200 err = session_env_putenv (opt.session_env, value);
202 else if (!strcmp (key, "display"))
204 err = session_env_setenv (opt.session_env, "DISPLAY", value);
206 else if (!strcmp (key, "ttyname"))
208 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
210 else if (!strcmp (key, "ttytype"))
212 err = session_env_setenv (opt.session_env, "TERM", value);
214 else if (!strcmp (key, "lc-ctype"))
216 xfree (opt.lc_ctype);
217 opt.lc_ctype = xtrystrdup (value);
218 if (!opt.lc_ctype)
219 err = gpg_error_from_syserror ();
221 else if (!strcmp (key, "lc-messages"))
223 xfree (opt.lc_messages);
224 opt.lc_messages = xtrystrdup (value);
225 if (!opt.lc_messages)
226 err = gpg_error_from_syserror ();
228 else if (!strcmp (key, "xauthority"))
230 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
232 else if (!strcmp (key, "pinentry-user-data"))
234 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
236 else if (!strcmp (key, "include-certs"))
238 int i = *value? atoi (value) : -1;
239 if (ctrl->include_certs < -2)
240 err = gpg_error (GPG_ERR_ASS_PARAMETER);
241 else
242 ctrl->include_certs = i;
244 else if (!strcmp (key, "list-mode"))
246 int i = *value? atoi (value) : 0;
247 if (!i || i == 1) /* default and mode 1 */
249 ctrl->server_local->list_internal = 1;
250 ctrl->server_local->list_external = 0;
252 else if (i == 2)
254 ctrl->server_local->list_internal = 0;
255 ctrl->server_local->list_external = 1;
257 else if (i == 3)
259 ctrl->server_local->list_internal = 1;
260 ctrl->server_local->list_external = 1;
262 else
263 err = gpg_error (GPG_ERR_ASS_PARAMETER);
265 else if (!strcmp (key, "list-to-output"))
267 int i = *value? atoi (value) : 0;
268 ctrl->server_local->list_to_output = i;
270 else if (!strcmp (key, "with-validation"))
272 int i = *value? atoi (value) : 0;
273 ctrl->with_validation = i;
275 else if (!strcmp (key, "validation-model"))
277 int i = gpgsm_parse_validation_model (value);
278 if ( i >= 0 && i <= 1 )
279 ctrl->validation_model = i;
280 else
281 err = gpg_error (GPG_ERR_ASS_PARAMETER);
283 else if (!strcmp (key, "with-key-data"))
285 opt.with_key_data = 1;
287 else if (!strcmp (key, "enable-audit-log"))
289 int i = *value? atoi (value) : 0;
290 ctrl->server_local->enable_audit_log = i;
292 else if (!strcmp (key, "allow-pinentry-notify"))
294 ctrl->server_local->allow_pinentry_notify = 1;
296 else if (!strcmp (key, "with-ephemeral-keys"))
298 int i = *value? atoi (value) : 0;
299 ctrl->with_ephemeral_keys = i;
301 else if (!strcmp (key, "no-encrypt-to"))
303 ctrl->server_local->no_encrypt_to = 1;
305 else
306 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
308 return err;
312 static void
313 reset_notify (assuan_context_t ctx)
315 ctrl_t ctrl = assuan_get_pointer (ctx);
317 gpgsm_release_certlist (ctrl->server_local->recplist);
318 gpgsm_release_certlist (ctrl->server_local->signerlist);
319 ctrl->server_local->recplist = NULL;
320 ctrl->server_local->signerlist = NULL;
321 close_message_fd (ctrl);
322 assuan_close_input_fd (ctx);
323 assuan_close_output_fd (ctx);
327 static void
328 input_notify (assuan_context_t ctx, const char *line)
330 ctrl_t ctrl = assuan_get_pointer (ctx);
332 ctrl->autodetect_encoding = 0;
333 ctrl->is_pem = 0;
334 ctrl->is_base64 = 0;
335 if (strstr (line, "--armor"))
336 ctrl->is_pem = 1;
337 else if (strstr (line, "--base64"))
338 ctrl->is_base64 = 1;
339 else if (strstr (line, "--binary"))
341 else
342 ctrl->autodetect_encoding = 1;
345 static void
346 output_notify (assuan_context_t ctx, const char *line)
348 ctrl_t ctrl = assuan_get_pointer (ctx);
350 ctrl->create_pem = 0;
351 ctrl->create_base64 = 0;
352 if (strstr (line, "--armor"))
353 ctrl->create_pem = 1;
354 else if (strstr (line, "--base64"))
355 ctrl->create_base64 = 1; /* just the raw output */
360 /* RECIPIENT <userID>
362 Set the recipient for the encryption. <userID> should be the
363 internal representation of the key; the server may accept any other
364 way of specification [we will support this]. If this is a valid and
365 trusted recipient the server does respond with OK, otherwise the
366 return is an ERR with the reason why the recipient can't be used,
367 the encryption will then not be done for this recipient. If the
368 policy is not to encrypt at all if not all recipients are valid, the
369 client has to take care of this. All RECIPIENT commands are
370 cumulative until a RESET or an successful ENCRYPT command. */
371 static int
372 cmd_recipient (assuan_context_t ctx, char *line)
374 ctrl_t ctrl = assuan_get_pointer (ctx);
375 int rc;
377 if (!ctrl->audit)
378 rc = start_audit_session (ctrl);
379 else
380 rc = 0;
382 if (!rc)
383 rc = gpgsm_add_to_certlist (ctrl, line, 0,
384 &ctrl->server_local->recplist, 0);
385 if (rc)
387 gpgsm_status2 (ctrl, STATUS_INV_RECP,
388 get_inv_recpsgnr_code (rc), line, NULL);
391 return rc;
394 /* SIGNER <userID>
396 Set the signer's keys for the signature creation. <userID> should
397 be the internal representation of the key; the server may accept any
398 other way of specification [we will support this]. If this is a
399 valid and usable signing key the server does respond with OK,
400 otherwise it returns an ERR with the reason why the key can't be
401 used, the signing will then not be done for this key. If the policy
402 is not to sign at all if not all signer keys are valid, the client
403 has to take care of this. All SIGNER commands are cumulative until
404 a RESET but they are *not* reset by an SIGN command becuase it can
405 be expected that set of signers are used for more than one sign
406 operation. */
407 static int
408 cmd_signer (assuan_context_t ctx, char *line)
410 ctrl_t ctrl = assuan_get_pointer (ctx);
411 int rc;
413 rc = gpgsm_add_to_certlist (ctrl, line, 1,
414 &ctrl->server_local->signerlist, 0);
415 if (rc)
417 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
418 get_inv_recpsgnr_code (rc), line, NULL);
419 /* For compatibiliy reasons we also issue the old code after the
420 new one. */
421 gpgsm_status2 (ctrl, STATUS_INV_RECP,
422 get_inv_recpsgnr_code (rc), line, NULL);
424 return rc;
428 /* ENCRYPT
430 Do the actual encryption process. Takes the plaintext from the INPUT
431 command, writes to the ciphertext to the file descriptor set with
432 the OUTPUT command, take the recipients form all the recipients set
433 so far. If this command fails the clients should try to delete all
434 output currently done or otherwise mark it as invalid. GPGSM does
435 ensure that there won't be any security problem with leftover data
436 on the output in this case.
438 This command should in general not fail, as all necessary checks
439 have been done while setting the recipients. The input and output
440 pipes are closed. */
441 static int
442 cmd_encrypt (assuan_context_t ctx, char *line)
444 ctrl_t ctrl = assuan_get_pointer (ctx);
445 certlist_t cl;
446 int inp_fd, out_fd;
447 FILE *out_fp;
448 int rc;
450 (void)line;
452 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
453 if (inp_fd == -1)
454 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
455 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
456 if (out_fd == -1)
457 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
459 out_fp = fdopen (dup (out_fd), "w");
460 if (!out_fp)
461 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
463 /* Now add all encrypt-to marked recipients from the default
464 list. */
465 rc = 0;
466 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
468 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
469 if (cl->is_encrypt_to)
470 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
471 &ctrl->server_local->recplist, 1);
473 if (!rc)
474 rc = ctrl->audit? 0 : start_audit_session (ctrl);
475 if (!rc)
476 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
477 ctrl->server_local->recplist,
478 inp_fd, out_fp);
479 fclose (out_fp);
481 gpgsm_release_certlist (ctrl->server_local->recplist);
482 ctrl->server_local->recplist = NULL;
483 /* Close and reset the fd */
484 close_message_fd (ctrl);
485 assuan_close_input_fd (ctx);
486 assuan_close_output_fd (ctx);
487 return rc;
491 /* DECRYPT
493 This performs the decrypt operation after doing some check on the
494 internal state. (e.g. that only needed data has been set). Because
495 it utilizes the GPG-Agent for the session key decryption, there is
496 no need to ask the client for a protecting passphrase - GpgAgent
497 does take care of this by requesting this from the user. */
498 static int
499 cmd_decrypt (assuan_context_t ctx, char *line)
501 ctrl_t ctrl = assuan_get_pointer (ctx);
502 int inp_fd, out_fd;
503 FILE *out_fp;
504 int rc;
506 (void)line;
508 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
509 if (inp_fd == -1)
510 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
511 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
512 if (out_fd == -1)
513 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
515 out_fp = fdopen (dup(out_fd), "w");
516 if (!out_fp)
517 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
519 rc = start_audit_session (ctrl);
520 if (!rc)
521 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
522 fclose (out_fp);
524 /* close and reset the fd */
525 close_message_fd (ctrl);
526 assuan_close_input_fd (ctx);
527 assuan_close_output_fd (ctx);
529 return rc;
533 /* VERIFY
535 This does a verify operation on the message send to the input-FD.
536 The result is written out using status lines. If an output FD was
537 given, the signed text will be written to that.
539 If the signature is a detached one, the server will inquire about
540 the signed material and the client must provide it.
542 static int
543 cmd_verify (assuan_context_t ctx, char *line)
545 int rc;
546 ctrl_t ctrl = assuan_get_pointer (ctx);
547 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
548 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
549 FILE *out_fp = NULL;
551 (void)line;
553 if (fd == -1)
554 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
556 if (out_fd != -1)
558 out_fp = fdopen ( dup(out_fd), "w");
559 if (!out_fp)
560 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
563 rc = start_audit_session (ctrl);
564 if (!rc)
565 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
566 ctrl->server_local->message_fd, out_fp);
567 if (out_fp)
568 fclose (out_fp);
570 /* close and reset the fd */
571 close_message_fd (ctrl);
572 assuan_close_input_fd (ctx);
573 assuan_close_output_fd (ctx);
575 return rc;
579 /* SIGN [--detached]
581 Sign the data set with the INPUT command and write it to the sink
582 set by OUTPUT. With "--detached" specified, a detached signature is
583 created (surprise). */
584 static int
585 cmd_sign (assuan_context_t ctx, char *line)
587 ctrl_t ctrl = assuan_get_pointer (ctx);
588 int inp_fd, out_fd;
589 FILE *out_fp;
590 int detached;
591 int rc;
593 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
594 if (inp_fd == -1)
595 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
596 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
597 if (out_fd == -1)
598 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
600 detached = has_option (line, "--detached");
602 out_fp = fdopen ( dup(out_fd), "w");
603 if (!out_fp)
604 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
606 rc = start_audit_session (ctrl);
607 if (!rc)
608 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
609 inp_fd, detached, out_fp);
610 fclose (out_fp);
612 /* close and reset the fd */
613 close_message_fd (ctrl);
614 assuan_close_input_fd (ctx);
615 assuan_close_output_fd (ctx);
617 return rc;
621 /* IMPORT [--re-import]
623 Import the certificates read form the input-fd, return status
624 message for each imported one. The import checks the validity of
625 the certificate but not of the entire chain. It is possible to
626 import expired certificates.
628 With the option --re-import the input data is expected to a be a LF
629 separated list of fingerprints. The command will re-import these
630 certificates, meaning that they are made permanent by removing
631 their ephemeral flag. */
632 static int
633 cmd_import (assuan_context_t ctx, char *line)
635 ctrl_t ctrl = assuan_get_pointer (ctx);
636 int rc;
637 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
638 int reimport = has_option (line, "--re-import");
640 (void)line;
642 if (fd == -1)
643 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
645 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
647 /* close and reset the fd */
648 close_message_fd (ctrl);
649 assuan_close_input_fd (ctx);
650 assuan_close_output_fd (ctx);
652 return rc;
656 /* EXPORT [--data [--armor|--base64]] [--] pattern
660 static int
661 cmd_export (assuan_context_t ctx, char *line)
663 ctrl_t ctrl = assuan_get_pointer (ctx);
664 char *p;
665 strlist_t list, sl;
666 int use_data;
668 use_data = has_option (line, "--data");
670 if (use_data)
672 /* We need to override any possible setting done by an OUTPUT command. */
673 ctrl->create_pem = has_option (line, "--armor");
674 ctrl->create_base64 = has_option (line, "--base64");
677 line = skip_options (line);
679 /* Break the line down into an strlist_t. */
680 list = NULL;
681 for (p=line; *p; line = p)
683 while (*p && *p != ' ')
684 p++;
685 if (*p)
686 *p++ = 0;
687 if (*line)
689 sl = xtrymalloc (sizeof *sl + strlen (line));
690 if (!sl)
692 free_strlist (list);
693 return out_of_core ();
695 sl->flags = 0;
696 strcpy_escaped_plus (sl->d, line);
697 sl->next = list;
698 list = sl;
702 if (use_data)
704 estream_t stream;
706 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
707 if (!stream)
709 free_strlist (list);
710 return set_error (GPG_ERR_ASS_GENERAL,
711 "error setting up a data stream");
713 gpgsm_export (ctrl, list, NULL, stream);
714 es_fclose (stream);
716 else
718 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
719 FILE *out_fp;
721 if (fd == -1)
723 free_strlist (list);
724 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
726 out_fp = fdopen ( dup(fd), "w");
727 if (!out_fp)
729 free_strlist (list);
730 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
733 gpgsm_export (ctrl, list, out_fp, NULL);
734 fclose (out_fp);
737 free_strlist (list);
738 /* Close and reset the fds. */
739 close_message_fd (ctrl);
740 assuan_close_input_fd (ctx);
741 assuan_close_output_fd (ctx);
742 return 0;
746 static int
747 cmd_delkeys (assuan_context_t ctx, char *line)
749 ctrl_t ctrl = assuan_get_pointer (ctx);
750 char *p;
751 strlist_t list, sl;
752 int rc;
754 /* break the line down into an strlist_t */
755 list = NULL;
756 for (p=line; *p; line = p)
758 while (*p && *p != ' ')
759 p++;
760 if (*p)
761 *p++ = 0;
762 if (*line)
764 sl = xtrymalloc (sizeof *sl + strlen (line));
765 if (!sl)
767 free_strlist (list);
768 return out_of_core ();
770 sl->flags = 0;
771 strcpy_escaped_plus (sl->d, line);
772 sl->next = list;
773 list = sl;
777 rc = gpgsm_delete (ctrl, list);
778 free_strlist (list);
780 /* close and reset the fd */
781 close_message_fd (ctrl);
782 assuan_close_input_fd (ctx);
783 assuan_close_output_fd (ctx);
785 return rc;
790 /* MESSAGE FD=<n>
792 Set the file descriptor to read a message which is used with
793 detached signatures */
794 static int
795 cmd_message (assuan_context_t ctx, char *line)
797 int rc;
798 gnupg_fd_t sysfd;
799 int fd;
800 ctrl_t ctrl = assuan_get_pointer (ctx);
802 rc = assuan_command_parse_fd (ctx, line, &sysfd);
803 if (rc)
804 return rc;
805 fd = translate_sys2libc_fd (sysfd, 0);
806 if (fd == -1)
807 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
808 ctrl->server_local->message_fd = fd;
809 return 0;
812 /* LISTKEYS [<patterns>]
813 DUMPKEYS [<patterns>]
814 LISTSECRETKEYS [<patterns>]
815 DUMPSECRETKEYS [<patterns>]
817 static int
818 do_listkeys (assuan_context_t ctx, char *line, int mode)
820 ctrl_t ctrl = assuan_get_pointer (ctx);
821 estream_t fp;
822 char *p;
823 strlist_t list, sl;
824 unsigned int listmode;
825 gpg_error_t err;
827 /* Break the line down into an strlist. */
828 list = NULL;
829 for (p=line; *p; line = p)
831 while (*p && *p != ' ')
832 p++;
833 if (*p)
834 *p++ = 0;
835 if (*line)
837 sl = xtrymalloc (sizeof *sl + strlen (line));
838 if (!sl)
840 free_strlist (list);
841 return out_of_core ();
843 sl->flags = 0;
844 strcpy_escaped_plus (sl->d, line);
845 sl->next = list;
846 list = sl;
850 if (ctrl->server_local->list_to_output)
852 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
854 if ( outfd == -1 )
855 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
856 fp = es_fdopen ( dup (outfd), "w");
857 if (!fp)
858 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
860 else
862 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
863 if (!fp)
864 return set_error (GPG_ERR_ASS_GENERAL,
865 "error setting up a data stream");
868 ctrl->with_colons = 1;
869 listmode = mode;
870 if (ctrl->server_local->list_internal)
871 listmode |= (1<<6);
872 if (ctrl->server_local->list_external)
873 listmode |= (1<<7);
874 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
875 free_strlist (list);
876 es_fclose (fp);
877 if (ctrl->server_local->list_to_output)
878 assuan_close_output_fd (ctx);
879 return err;
882 static int
883 cmd_listkeys (assuan_context_t ctx, char *line)
885 return do_listkeys (ctx, line, 3);
888 static int
889 cmd_dumpkeys (assuan_context_t ctx, char *line)
891 return do_listkeys (ctx, line, 259);
894 static int
895 cmd_listsecretkeys (assuan_context_t ctx, char *line)
897 return do_listkeys (ctx, line, 2);
900 static int
901 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
903 return do_listkeys (ctx, line, 258);
907 /* GENKEY
909 Read the parameters in native format from the input fd and write a
910 certificate request to the output.
912 static int
913 cmd_genkey (assuan_context_t ctx, char *line)
915 ctrl_t ctrl = assuan_get_pointer (ctx);
916 int inp_fd, out_fd;
917 FILE *out_fp;
918 int rc;
919 estream_t in_stream;
921 (void)line;
923 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
924 if (inp_fd == -1)
925 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
926 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
927 if (out_fd == -1)
928 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
930 in_stream = es_fdopen_nc (inp_fd, "r");
931 if (!in_stream)
932 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
934 out_fp = fdopen ( dup(out_fd), "w");
935 if (!out_fp)
937 es_fclose (in_stream);
938 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
940 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
941 fclose (out_fp);
943 /* close and reset the fds */
944 assuan_close_input_fd (ctx);
945 assuan_close_output_fd (ctx);
947 return rc;
952 /* GETAUDITLOG [--data] [--html]
954 !!!WORK in PROGRESS!!!
956 If --data is used, the output is send using D-lines and not to the
957 source given by an OUTPUT command.
959 If --html is used the output is formated as an XHTML block. This is
960 designed to be incorporated into a HTML document.
962 static int
963 cmd_getauditlog (assuan_context_t ctx, char *line)
965 ctrl_t ctrl = assuan_get_pointer (ctx);
966 int out_fd;
967 estream_t out_stream;
968 int opt_data, opt_html;
969 int rc;
971 opt_data = has_option (line, "--data");
972 opt_html = has_option (line, "--html");
973 line = skip_options (line);
975 if (!ctrl->audit)
976 return gpg_error (GPG_ERR_NO_DATA);
978 if (opt_data)
980 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
981 if (!out_stream)
982 return set_error (GPG_ERR_ASS_GENERAL,
983 "error setting up a data stream");
985 else
987 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
988 if (out_fd == -1)
989 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
991 out_stream = es_fdopen_nc ( dup (out_fd), "w");
992 if (!out_stream)
994 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
998 audit_print_result (ctrl->audit, out_stream, opt_html);
999 rc = 0;
1001 es_fclose (out_stream);
1003 /* Close and reset the fd. */
1004 if (!opt_data)
1005 assuan_close_output_fd (ctx);
1006 return rc;
1010 /* GETINFO <what>
1012 Multipurpose function to return a variety of information.
1013 Supported values for WHAT are:
1015 version - Return the version of the program.
1016 pid - Return the process id of the server.
1017 agent-check - Return success if the agent is running.
1018 cmd_has_option CMD OPT
1019 - Returns OK if the command CMD implements the option OPT.
1022 static int
1023 cmd_getinfo (assuan_context_t ctx, char *line)
1025 int rc = 0;
1027 if (!strcmp (line, "version"))
1029 const char *s = VERSION;
1030 rc = assuan_send_data (ctx, s, strlen (s));
1032 else if (!strcmp (line, "pid"))
1034 char numbuf[50];
1036 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1037 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1039 else if (!strcmp (line, "agent-check"))
1041 ctrl_t ctrl = assuan_get_pointer (ctx);
1042 rc = gpgsm_agent_send_nop (ctrl);
1044 else if (!strncmp (line, "cmd_has_option", 14)
1045 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1047 char *cmd, *cmdopt;
1048 line += 14;
1049 while (*line == ' ' || *line == '\t')
1050 line++;
1051 if (!*line)
1052 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1053 else
1055 cmd = line;
1056 while (*line && (*line != ' ' && *line != '\t'))
1057 line++;
1058 if (!*line)
1059 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1060 else
1062 *line++ = 0;
1063 while (*line == ' ' || *line == '\t')
1064 line++;
1065 if (!*line)
1066 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1067 else
1069 cmdopt = line;
1070 if (!command_has_option (cmd, cmdopt))
1071 rc = gpg_error (GPG_ERR_GENERAL);
1076 else
1077 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1079 return rc;
1084 /* Return true if the command CMD implements the option OPT. */
1085 static int
1086 command_has_option (const char *cmd, const char *cmdopt)
1088 if (!strcmp (cmd, "IMPORT"))
1090 if (!strcmp (cmdopt, "re-import"))
1091 return 1;
1094 return 0;
1098 /* Tell the assuan library about our commands */
1099 static int
1100 register_commands (assuan_context_t ctx)
1102 static struct {
1103 const char *name;
1104 int (*handler)(assuan_context_t, char *line);
1105 } table[] = {
1106 { "RECIPIENT", cmd_recipient },
1107 { "SIGNER", cmd_signer },
1108 { "ENCRYPT", cmd_encrypt },
1109 { "DECRYPT", cmd_decrypt },
1110 { "VERIFY", cmd_verify },
1111 { "SIGN", cmd_sign },
1112 { "IMPORT", cmd_import },
1113 { "EXPORT", cmd_export },
1114 { "INPUT", NULL },
1115 { "OUTPUT", NULL },
1116 { "MESSAGE", cmd_message },
1117 { "LISTKEYS", cmd_listkeys },
1118 { "DUMPKEYS", cmd_dumpkeys },
1119 { "LISTSECRETKEYS",cmd_listsecretkeys },
1120 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1121 { "GENKEY", cmd_genkey },
1122 { "DELKEYS", cmd_delkeys },
1123 { "GETAUDITLOG", cmd_getauditlog },
1124 { "GETINFO", cmd_getinfo },
1125 { NULL }
1127 int i, rc;
1129 for (i=0; table[i].name; i++)
1131 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1132 if (rc)
1133 return rc;
1135 return 0;
1138 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1139 set from the command line or config file. We only require those
1140 marked as encrypt-to. */
1141 void
1142 gpgsm_server (certlist_t default_recplist)
1144 int rc;
1145 int filedes[2];
1146 assuan_context_t ctx;
1147 struct server_control_s ctrl;
1148 static const char hello[] = ("GNU Privacy Guard's S/M server "
1149 VERSION " ready");
1151 memset (&ctrl, 0, sizeof ctrl);
1152 gpgsm_init_default_ctrl (&ctrl);
1154 /* We use a pipe based server so that we can work from scripts.
1155 assuan_init_pipe_server will automagically detect when we are
1156 called with a socketpair and ignore FIELDES in this case. */
1157 filedes[0] = 0;
1158 filedes[1] = 1;
1159 rc = assuan_init_pipe_server (&ctx, filedes);
1160 if (rc)
1162 log_error ("failed to initialize the server: %s\n",
1163 gpg_strerror (rc));
1164 gpgsm_exit (2);
1166 rc = register_commands (ctx);
1167 if (rc)
1169 log_error ("failed to the register commands with Assuan: %s\n",
1170 gpg_strerror(rc));
1171 gpgsm_exit (2);
1173 if (opt.verbose || opt.debug)
1175 char *tmp = NULL;
1176 const char *s1 = getenv ("GPG_AGENT_INFO");
1177 const char *s2 = getenv ("DIRMNGR_INFO");
1179 if (asprintf (&tmp,
1180 "Home: %s\n"
1181 "Config: %s\n"
1182 "AgentInfo: %s\n"
1183 "DirmngrInfo: %s\n"
1184 "%s",
1185 opt.homedir,
1186 opt.config_filename,
1187 s1?s1:"[not set]",
1188 s2?s2:"[not set]",
1189 hello) > 0)
1191 assuan_set_hello_line (ctx, tmp);
1192 free (tmp);
1195 else
1196 assuan_set_hello_line (ctx, hello);
1198 assuan_register_reset_notify (ctx, reset_notify);
1199 assuan_register_input_notify (ctx, input_notify);
1200 assuan_register_output_notify (ctx, output_notify);
1201 assuan_register_option_handler (ctx, option_handler);
1203 assuan_set_pointer (ctx, &ctrl);
1204 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1205 ctrl.server_local->assuan_ctx = ctx;
1206 ctrl.server_local->message_fd = -1;
1207 ctrl.server_local->list_internal = 1;
1208 ctrl.server_local->list_external = 0;
1209 ctrl.server_local->default_recplist = default_recplist;
1211 if (DBG_ASSUAN)
1212 assuan_set_log_stream (ctx, log_get_stream ());
1214 for (;;)
1216 rc = assuan_accept (ctx);
1217 if (rc == -1)
1219 break;
1221 else if (rc)
1223 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1224 break;
1227 rc = assuan_process (ctx);
1228 if (rc)
1230 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1231 continue;
1235 gpgsm_release_certlist (ctrl.server_local->recplist);
1236 ctrl.server_local->recplist = NULL;
1237 gpgsm_release_certlist (ctrl.server_local->signerlist);
1238 ctrl.server_local->signerlist = NULL;
1239 xfree (ctrl.server_local);
1241 audit_release (ctrl.audit);
1242 ctrl.audit = NULL;
1244 assuan_deinit_server (ctx);
1249 gpg_error_t
1250 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1252 gpg_error_t err = 0;
1253 va_list arg_ptr;
1254 const char *text;
1256 va_start (arg_ptr, no);
1258 if (ctrl->no_server && ctrl->status_fd == -1)
1259 ; /* No status wanted. */
1260 else if (ctrl->no_server)
1262 if (!statusfp)
1264 if (ctrl->status_fd == 1)
1265 statusfp = stdout;
1266 else if (ctrl->status_fd == 2)
1267 statusfp = stderr;
1268 else
1269 statusfp = fdopen (ctrl->status_fd, "w");
1271 if (!statusfp)
1273 log_fatal ("can't open fd %d for status output: %s\n",
1274 ctrl->status_fd, strerror(errno));
1278 fputs ("[GNUPG:] ", statusfp);
1279 fputs (get_status_string (no), statusfp);
1281 while ( (text = va_arg (arg_ptr, const char*) ))
1283 putc ( ' ', statusfp );
1284 for (; *text; text++)
1286 if (*text == '\n')
1287 fputs ( "\\n", statusfp );
1288 else if (*text == '\r')
1289 fputs ( "\\r", statusfp );
1290 else
1291 putc ( *(const byte *)text, statusfp );
1294 putc ('\n', statusfp);
1295 fflush (statusfp);
1297 else
1299 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1300 char buf[950], *p;
1301 size_t n;
1303 p = buf;
1304 n = 0;
1305 while ( (text = va_arg (arg_ptr, const char *)) )
1307 if (n)
1309 *p++ = ' ';
1310 n++;
1312 for ( ; *text && n < DIM (buf)-2; n++)
1313 *p++ = *text++;
1315 *p = 0;
1316 err = assuan_write_status (ctx, get_status_string (no), buf);
1319 va_end (arg_ptr);
1320 return err;
1323 gpg_error_t
1324 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1326 return gpgsm_status2 (ctrl, no, text, NULL);
1329 gpg_error_t
1330 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1331 gpg_err_code_t ec)
1333 char buf[30];
1335 sprintf (buf, "%u", (unsigned int)ec);
1336 if (text)
1337 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1338 else
1339 return gpgsm_status2 (ctrl, no, buf, NULL);
1343 /* Helper to notify the client about Pinentry events. Because that
1344 might disturb some older clients, this is only done when enabled
1345 via an option. Returns an gpg error code. */
1346 gpg_error_t
1347 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1349 if (!ctrl || !ctrl->server_local
1350 || !ctrl->server_local->allow_pinentry_notify)
1351 return 0;
1352 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);