Make use of the card's extended capabilities.
[gnupg.git] / sm / server.c
blobf6c8af99d35ee1ab7fb82545f9319a724216d6c5
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 gpg_err_code_t r = gpg_err_code (rc);
388 gpgsm_status2 (ctrl, STATUS_INV_RECP,
389 r == -1? "1":
390 r == GPG_ERR_NO_PUBKEY? "1":
391 r == GPG_ERR_AMBIGUOUS_NAME? "2":
392 r == GPG_ERR_WRONG_KEY_USAGE? "3":
393 r == GPG_ERR_CERT_REVOKED? "4":
394 r == GPG_ERR_CERT_EXPIRED? "5":
395 r == GPG_ERR_NO_CRL_KNOWN? "6":
396 r == GPG_ERR_CRL_TOO_OLD? "7":
397 r == GPG_ERR_NO_POLICY_MATCH? "8":
398 r == GPG_ERR_MISSING_CERT? "11":
399 "0",
400 line, NULL);
403 return rc;
406 /* SIGNER <userID>
408 Set the signer's keys for the signature creation. <userID> should
409 be the internal representation of the key; the server may accept any
410 other way of specification [we will support this]. If this is a
411 valid and usable signing key the server does respond with OK,
412 otherwise it returns an ERR with the reason why the key can't be
413 used, the signing will then not be done for this key. If the policy
414 is not to sign at all if not all signer keys are valid, the client
415 has to take care of this. All SIGNER commands are cumulative until
416 a RESET but they are *not* reset by an SIGN command becuase it can
417 be expected that set of signers are used for more than one sign
418 operation.
420 Note that this command returns an INV_RECP status which is a bit
421 strange, but they are very similar. */
422 static int
423 cmd_signer (assuan_context_t ctx, char *line)
425 ctrl_t ctrl = assuan_get_pointer (ctx);
426 int rc;
428 rc = gpgsm_add_to_certlist (ctrl, line, 1,
429 &ctrl->server_local->signerlist, 0);
430 if (rc)
432 gpg_err_code_t r = gpg_err_code (rc);
433 gpgsm_status2 (ctrl, STATUS_INV_RECP,
434 r == -1? "1":
435 r == GPG_ERR_NO_PUBKEY? "1":
436 r == GPG_ERR_AMBIGUOUS_NAME? "2":
437 r == GPG_ERR_WRONG_KEY_USAGE? "3":
438 r == GPG_ERR_CERT_REVOKED? "4":
439 r == GPG_ERR_CERT_EXPIRED? "5":
440 r == GPG_ERR_NO_CRL_KNOWN? "6":
441 r == GPG_ERR_CRL_TOO_OLD? "7":
442 r == GPG_ERR_NO_POLICY_MATCH? "8":
443 r == GPG_ERR_NO_SECKEY? "9":
444 r == GPG_ERR_MISSING_CERT? "11":
445 "0",
446 line, NULL);
448 return rc;
452 /* ENCRYPT
454 Do the actual encryption process. Takes the plaintext from the INPUT
455 command, writes to the ciphertext to the file descriptor set with
456 the OUTPUT command, take the recipients form all the recipients set
457 so far. If this command fails the clients should try to delete all
458 output currently done or otherwise mark it as invalid. GPGSM does
459 ensure that there won't be any security problem with leftover data
460 on the output in this case.
462 This command should in general not fail, as all necessary checks
463 have been done while setting the recipients. The input and output
464 pipes are closed. */
465 static int
466 cmd_encrypt (assuan_context_t ctx, char *line)
468 ctrl_t ctrl = assuan_get_pointer (ctx);
469 certlist_t cl;
470 int inp_fd, out_fd;
471 FILE *out_fp;
472 int rc;
474 (void)line;
476 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
477 if (inp_fd == -1)
478 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
479 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
480 if (out_fd == -1)
481 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
483 out_fp = fdopen (dup (out_fd), "w");
484 if (!out_fp)
485 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
487 /* Now add all encrypt-to marked recipients from the default
488 list. */
489 rc = 0;
490 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
492 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
493 if (cl->is_encrypt_to)
494 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
495 &ctrl->server_local->recplist, 1);
497 if (!rc)
498 rc = ctrl->audit? 0 : start_audit_session (ctrl);
499 if (!rc)
500 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
501 ctrl->server_local->recplist,
502 inp_fd, out_fp);
503 fclose (out_fp);
505 gpgsm_release_certlist (ctrl->server_local->recplist);
506 ctrl->server_local->recplist = NULL;
507 /* Close and reset the fd */
508 close_message_fd (ctrl);
509 assuan_close_input_fd (ctx);
510 assuan_close_output_fd (ctx);
511 return rc;
515 /* DECRYPT
517 This performs the decrypt operation after doing some check on the
518 internal state. (e.g. that only needed data has been set). Because
519 it utilizes the GPG-Agent for the session key decryption, there is
520 no need to ask the client for a protecting passphrase - GpgAgent
521 does take care of this by requesting this from the user. */
522 static int
523 cmd_decrypt (assuan_context_t ctx, char *line)
525 ctrl_t ctrl = assuan_get_pointer (ctx);
526 int inp_fd, out_fd;
527 FILE *out_fp;
528 int rc;
530 (void)line;
532 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
533 if (inp_fd == -1)
534 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
535 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
536 if (out_fd == -1)
537 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
539 out_fp = fdopen (dup(out_fd), "w");
540 if (!out_fp)
541 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
543 rc = start_audit_session (ctrl);
544 if (!rc)
545 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
546 fclose (out_fp);
548 /* close and reset the fd */
549 close_message_fd (ctrl);
550 assuan_close_input_fd (ctx);
551 assuan_close_output_fd (ctx);
553 return rc;
557 /* VERIFY
559 This does a verify operation on the message send to the input-FD.
560 The result is written out using status lines. If an output FD was
561 given, the signed text will be written to that.
563 If the signature is a detached one, the server will inquire about
564 the signed material and the client must provide it.
566 static int
567 cmd_verify (assuan_context_t ctx, char *line)
569 int rc;
570 ctrl_t ctrl = assuan_get_pointer (ctx);
571 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
572 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
573 FILE *out_fp = NULL;
575 (void)line;
577 if (fd == -1)
578 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
580 if (out_fd != -1)
582 out_fp = fdopen ( dup(out_fd), "w");
583 if (!out_fp)
584 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
587 rc = start_audit_session (ctrl);
588 if (!rc)
589 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
590 ctrl->server_local->message_fd, out_fp);
591 if (out_fp)
592 fclose (out_fp);
594 /* close and reset the fd */
595 close_message_fd (ctrl);
596 assuan_close_input_fd (ctx);
597 assuan_close_output_fd (ctx);
599 return rc;
603 /* SIGN [--detached]
605 Sign the data set with the INPUT command and write it to the sink
606 set by OUTPUT. With "--detached" specified, a detached signature is
607 created (surprise). */
608 static int
609 cmd_sign (assuan_context_t ctx, char *line)
611 ctrl_t ctrl = assuan_get_pointer (ctx);
612 int inp_fd, out_fd;
613 FILE *out_fp;
614 int detached;
615 int rc;
617 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
618 if (inp_fd == -1)
619 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
620 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
621 if (out_fd == -1)
622 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
624 detached = has_option (line, "--detached");
626 out_fp = fdopen ( dup(out_fd), "w");
627 if (!out_fp)
628 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
630 rc = start_audit_session (ctrl);
631 if (!rc)
632 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
633 inp_fd, detached, out_fp);
634 fclose (out_fp);
636 /* close and reset the fd */
637 close_message_fd (ctrl);
638 assuan_close_input_fd (ctx);
639 assuan_close_output_fd (ctx);
641 return rc;
645 /* IMPORT [--re-import]
647 Import the certificates read form the input-fd, return status
648 message for each imported one. The import checks the validity of
649 the certificate but not of the entire chain. It is possible to
650 import expired certificates.
652 With the option --re-import the input data is expected to a be a LF
653 separated list of fingerprints. The command will re-import these
654 certificates, meaning that they are made permanent by removing
655 their ephemeral flag. */
656 static int
657 cmd_import (assuan_context_t ctx, char *line)
659 ctrl_t ctrl = assuan_get_pointer (ctx);
660 int rc;
661 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
662 int reimport = has_option (line, "--re-import");
664 (void)line;
666 if (fd == -1)
667 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
669 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
671 /* close and reset the fd */
672 close_message_fd (ctrl);
673 assuan_close_input_fd (ctx);
674 assuan_close_output_fd (ctx);
676 return rc;
680 /* EXPORT [--data [--armor|--base64]] [--] pattern
684 static int
685 cmd_export (assuan_context_t ctx, char *line)
687 ctrl_t ctrl = assuan_get_pointer (ctx);
688 char *p;
689 strlist_t list, sl;
690 int use_data;
692 use_data = has_option (line, "--data");
694 if (use_data)
696 /* We need to override any possible setting done by an OUTPUT command. */
697 ctrl->create_pem = has_option (line, "--armor");
698 ctrl->create_base64 = has_option (line, "--base64");
701 line = skip_options (line);
703 /* Break the line down into an strlist_t. */
704 list = NULL;
705 for (p=line; *p; line = p)
707 while (*p && *p != ' ')
708 p++;
709 if (*p)
710 *p++ = 0;
711 if (*line)
713 sl = xtrymalloc (sizeof *sl + strlen (line));
714 if (!sl)
716 free_strlist (list);
717 return out_of_core ();
719 sl->flags = 0;
720 strcpy_escaped_plus (sl->d, line);
721 sl->next = list;
722 list = sl;
726 if (use_data)
728 estream_t stream;
730 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
731 if (!stream)
733 free_strlist (list);
734 return set_error (GPG_ERR_ASS_GENERAL,
735 "error setting up a data stream");
737 gpgsm_export (ctrl, list, NULL, stream);
738 es_fclose (stream);
740 else
742 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
743 FILE *out_fp;
745 if (fd == -1)
747 free_strlist (list);
748 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
750 out_fp = fdopen ( dup(fd), "w");
751 if (!out_fp)
753 free_strlist (list);
754 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
757 gpgsm_export (ctrl, list, out_fp, NULL);
758 fclose (out_fp);
761 free_strlist (list);
762 /* Close and reset the fds. */
763 close_message_fd (ctrl);
764 assuan_close_input_fd (ctx);
765 assuan_close_output_fd (ctx);
766 return 0;
770 static int
771 cmd_delkeys (assuan_context_t ctx, char *line)
773 ctrl_t ctrl = assuan_get_pointer (ctx);
774 char *p;
775 strlist_t list, sl;
776 int rc;
778 /* break the line down into an strlist_t */
779 list = NULL;
780 for (p=line; *p; line = p)
782 while (*p && *p != ' ')
783 p++;
784 if (*p)
785 *p++ = 0;
786 if (*line)
788 sl = xtrymalloc (sizeof *sl + strlen (line));
789 if (!sl)
791 free_strlist (list);
792 return out_of_core ();
794 sl->flags = 0;
795 strcpy_escaped_plus (sl->d, line);
796 sl->next = list;
797 list = sl;
801 rc = gpgsm_delete (ctrl, list);
802 free_strlist (list);
804 /* close and reset the fd */
805 close_message_fd (ctrl);
806 assuan_close_input_fd (ctx);
807 assuan_close_output_fd (ctx);
809 return rc;
814 /* MESSAGE FD=<n>
816 Set the file descriptor to read a message which is used with
817 detached signatures */
818 static int
819 cmd_message (assuan_context_t ctx, char *line)
821 int rc;
822 gnupg_fd_t sysfd;
823 int fd;
824 ctrl_t ctrl = assuan_get_pointer (ctx);
826 rc = assuan_command_parse_fd (ctx, line, &sysfd);
827 if (rc)
828 return rc;
829 fd = translate_sys2libc_fd (sysfd, 0);
830 if (fd == -1)
831 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
832 ctrl->server_local->message_fd = fd;
833 return 0;
836 /* LISTKEYS [<patterns>]
837 DUMPKEYS [<patterns>]
838 LISTSECRETKEYS [<patterns>]
839 DUMPSECRETKEYS [<patterns>]
841 static int
842 do_listkeys (assuan_context_t ctx, char *line, int mode)
844 ctrl_t ctrl = assuan_get_pointer (ctx);
845 estream_t fp;
846 char *p;
847 strlist_t list, sl;
848 unsigned int listmode;
849 gpg_error_t err;
851 /* Break the line down into an strlist. */
852 list = NULL;
853 for (p=line; *p; line = p)
855 while (*p && *p != ' ')
856 p++;
857 if (*p)
858 *p++ = 0;
859 if (*line)
861 sl = xtrymalloc (sizeof *sl + strlen (line));
862 if (!sl)
864 free_strlist (list);
865 return out_of_core ();
867 sl->flags = 0;
868 strcpy_escaped_plus (sl->d, line);
869 sl->next = list;
870 list = sl;
874 if (ctrl->server_local->list_to_output)
876 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
878 if ( outfd == -1 )
879 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
880 fp = es_fdopen ( dup (outfd), "w");
881 if (!fp)
882 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
884 else
886 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
887 if (!fp)
888 return set_error (GPG_ERR_ASS_GENERAL,
889 "error setting up a data stream");
892 ctrl->with_colons = 1;
893 listmode = mode;
894 if (ctrl->server_local->list_internal)
895 listmode |= (1<<6);
896 if (ctrl->server_local->list_external)
897 listmode |= (1<<7);
898 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
899 free_strlist (list);
900 es_fclose (fp);
901 if (ctrl->server_local->list_to_output)
902 assuan_close_output_fd (ctx);
903 return err;
906 static int
907 cmd_listkeys (assuan_context_t ctx, char *line)
909 return do_listkeys (ctx, line, 3);
912 static int
913 cmd_dumpkeys (assuan_context_t ctx, char *line)
915 return do_listkeys (ctx, line, 259);
918 static int
919 cmd_listsecretkeys (assuan_context_t ctx, char *line)
921 return do_listkeys (ctx, line, 2);
924 static int
925 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
927 return do_listkeys (ctx, line, 258);
931 /* GENKEY
933 Read the parameters in native format from the input fd and write a
934 certificate request to the output.
936 static int
937 cmd_genkey (assuan_context_t ctx, char *line)
939 ctrl_t ctrl = assuan_get_pointer (ctx);
940 int inp_fd, out_fd;
941 FILE *out_fp;
942 int rc;
943 estream_t in_stream;
945 (void)line;
947 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
948 if (inp_fd == -1)
949 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
950 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
951 if (out_fd == -1)
952 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
954 in_stream = es_fdopen_nc (inp_fd, "r");
955 if (!in_stream)
956 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
958 out_fp = fdopen ( dup(out_fd), "w");
959 if (!out_fp)
961 es_fclose (in_stream);
962 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
964 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
965 fclose (out_fp);
967 /* close and reset the fds */
968 assuan_close_input_fd (ctx);
969 assuan_close_output_fd (ctx);
971 return rc;
976 /* GETAUDITLOG [--data] [--html]
978 !!!WORK in PROGRESS!!!
980 If --data is used, the output is send using D-lines and not to the
981 source given by an OUTPUT command.
983 If --html is used the output is formated as an XHTML block. This is
984 designed to be incorporated into a HTML document.
986 static int
987 cmd_getauditlog (assuan_context_t ctx, char *line)
989 ctrl_t ctrl = assuan_get_pointer (ctx);
990 int out_fd;
991 estream_t out_stream;
992 int opt_data, opt_html;
993 int rc;
995 opt_data = has_option (line, "--data");
996 opt_html = has_option (line, "--html");
997 line = skip_options (line);
999 if (!ctrl->audit)
1000 return gpg_error (GPG_ERR_NO_DATA);
1002 if (opt_data)
1004 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1005 if (!out_stream)
1006 return set_error (GPG_ERR_ASS_GENERAL,
1007 "error setting up a data stream");
1009 else
1011 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1012 if (out_fd == -1)
1013 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1015 out_stream = es_fdopen_nc ( dup (out_fd), "w");
1016 if (!out_stream)
1018 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1022 audit_print_result (ctrl->audit, out_stream, opt_html);
1023 rc = 0;
1025 es_fclose (out_stream);
1027 /* Close and reset the fd. */
1028 if (!opt_data)
1029 assuan_close_output_fd (ctx);
1030 return rc;
1034 /* GETINFO <what>
1036 Multipurpose function to return a variety of information.
1037 Supported values for WHAT are:
1039 version - Return the version of the program.
1040 pid - Return the process id of the server.
1041 agent-check - Return success if the agent is running.
1042 cmd_has_option CMD OPT
1043 - Returns OK if the command CMD implements the option OPT.
1046 static int
1047 cmd_getinfo (assuan_context_t ctx, char *line)
1049 int rc = 0;
1051 if (!strcmp (line, "version"))
1053 const char *s = VERSION;
1054 rc = assuan_send_data (ctx, s, strlen (s));
1056 else if (!strcmp (line, "pid"))
1058 char numbuf[50];
1060 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1061 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1063 else if (!strcmp (line, "agent-check"))
1065 ctrl_t ctrl = assuan_get_pointer (ctx);
1066 rc = gpgsm_agent_send_nop (ctrl);
1068 else if (!strncmp (line, "cmd_has_option", 14)
1069 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1071 char *cmd, *cmdopt;
1072 line += 14;
1073 while (*line == ' ' || *line == '\t')
1074 line++;
1075 if (!*line)
1076 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1077 else
1079 cmd = line;
1080 while (*line && (*line != ' ' && *line != '\t'))
1081 line++;
1082 if (!*line)
1083 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1084 else
1086 *line++ = 0;
1087 while (*line == ' ' || *line == '\t')
1088 line++;
1089 if (!*line)
1090 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1091 else
1093 cmdopt = line;
1094 if (!command_has_option (cmd, cmdopt))
1095 rc = gpg_error (GPG_ERR_GENERAL);
1100 else
1101 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1103 return rc;
1108 /* Return true if the command CMD implements the option OPT. */
1109 static int
1110 command_has_option (const char *cmd, const char *cmdopt)
1112 if (!strcmp (cmd, "IMPORT"))
1114 if (!strcmp (cmdopt, "re-import"))
1115 return 1;
1118 return 0;
1122 /* Tell the assuan library about our commands */
1123 static int
1124 register_commands (assuan_context_t ctx)
1126 static struct {
1127 const char *name;
1128 int (*handler)(assuan_context_t, char *line);
1129 } table[] = {
1130 { "RECIPIENT", cmd_recipient },
1131 { "SIGNER", cmd_signer },
1132 { "ENCRYPT", cmd_encrypt },
1133 { "DECRYPT", cmd_decrypt },
1134 { "VERIFY", cmd_verify },
1135 { "SIGN", cmd_sign },
1136 { "IMPORT", cmd_import },
1137 { "EXPORT", cmd_export },
1138 { "INPUT", NULL },
1139 { "OUTPUT", NULL },
1140 { "MESSAGE", cmd_message },
1141 { "LISTKEYS", cmd_listkeys },
1142 { "DUMPKEYS", cmd_dumpkeys },
1143 { "LISTSECRETKEYS",cmd_listsecretkeys },
1144 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1145 { "GENKEY", cmd_genkey },
1146 { "DELKEYS", cmd_delkeys },
1147 { "GETAUDITLOG", cmd_getauditlog },
1148 { "GETINFO", cmd_getinfo },
1149 { NULL }
1151 int i, rc;
1153 for (i=0; table[i].name; i++)
1155 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1156 if (rc)
1157 return rc;
1159 return 0;
1162 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1163 set from the command line or config file. We only require those
1164 marked as encrypt-to. */
1165 void
1166 gpgsm_server (certlist_t default_recplist)
1168 int rc;
1169 int filedes[2];
1170 assuan_context_t ctx;
1171 struct server_control_s ctrl;
1172 static const char hello[] = ("GNU Privacy Guard's S/M server "
1173 VERSION " ready");
1175 memset (&ctrl, 0, sizeof ctrl);
1176 gpgsm_init_default_ctrl (&ctrl);
1178 /* We use a pipe based server so that we can work from scripts.
1179 assuan_init_pipe_server will automagically detect when we are
1180 called with a socketpair and ignore FIELDES in this case. */
1181 filedes[0] = 0;
1182 filedes[1] = 1;
1183 rc = assuan_init_pipe_server (&ctx, filedes);
1184 if (rc)
1186 log_error ("failed to initialize the server: %s\n",
1187 gpg_strerror (rc));
1188 gpgsm_exit (2);
1190 rc = register_commands (ctx);
1191 if (rc)
1193 log_error ("failed to the register commands with Assuan: %s\n",
1194 gpg_strerror(rc));
1195 gpgsm_exit (2);
1197 if (opt.verbose || opt.debug)
1199 char *tmp = NULL;
1200 const char *s1 = getenv ("GPG_AGENT_INFO");
1201 const char *s2 = getenv ("DIRMNGR_INFO");
1203 if (asprintf (&tmp,
1204 "Home: %s\n"
1205 "Config: %s\n"
1206 "AgentInfo: %s\n"
1207 "DirmngrInfo: %s\n"
1208 "%s",
1209 opt.homedir,
1210 opt.config_filename,
1211 s1?s1:"[not set]",
1212 s2?s2:"[not set]",
1213 hello) > 0)
1215 assuan_set_hello_line (ctx, tmp);
1216 free (tmp);
1219 else
1220 assuan_set_hello_line (ctx, hello);
1222 assuan_register_reset_notify (ctx, reset_notify);
1223 assuan_register_input_notify (ctx, input_notify);
1224 assuan_register_output_notify (ctx, output_notify);
1225 assuan_register_option_handler (ctx, option_handler);
1227 assuan_set_pointer (ctx, &ctrl);
1228 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1229 ctrl.server_local->assuan_ctx = ctx;
1230 ctrl.server_local->message_fd = -1;
1231 ctrl.server_local->list_internal = 1;
1232 ctrl.server_local->list_external = 0;
1233 ctrl.server_local->default_recplist = default_recplist;
1235 if (DBG_ASSUAN)
1236 assuan_set_log_stream (ctx, log_get_stream ());
1238 for (;;)
1240 rc = assuan_accept (ctx);
1241 if (rc == -1)
1243 break;
1245 else if (rc)
1247 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1248 break;
1251 rc = assuan_process (ctx);
1252 if (rc)
1254 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1255 continue;
1259 gpgsm_release_certlist (ctrl.server_local->recplist);
1260 ctrl.server_local->recplist = NULL;
1261 gpgsm_release_certlist (ctrl.server_local->signerlist);
1262 ctrl.server_local->signerlist = NULL;
1263 xfree (ctrl.server_local);
1265 audit_release (ctrl.audit);
1266 ctrl.audit = NULL;
1268 assuan_deinit_server (ctx);
1273 gpg_error_t
1274 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1276 gpg_error_t err = 0;
1277 va_list arg_ptr;
1278 const char *text;
1280 va_start (arg_ptr, no);
1282 if (ctrl->no_server && ctrl->status_fd == -1)
1283 ; /* No status wanted. */
1284 else if (ctrl->no_server)
1286 if (!statusfp)
1288 if (ctrl->status_fd == 1)
1289 statusfp = stdout;
1290 else if (ctrl->status_fd == 2)
1291 statusfp = stderr;
1292 else
1293 statusfp = fdopen (ctrl->status_fd, "w");
1295 if (!statusfp)
1297 log_fatal ("can't open fd %d for status output: %s\n",
1298 ctrl->status_fd, strerror(errno));
1302 fputs ("[GNUPG:] ", statusfp);
1303 fputs (get_status_string (no), statusfp);
1305 while ( (text = va_arg (arg_ptr, const char*) ))
1307 putc ( ' ', statusfp );
1308 for (; *text; text++)
1310 if (*text == '\n')
1311 fputs ( "\\n", statusfp );
1312 else if (*text == '\r')
1313 fputs ( "\\r", statusfp );
1314 else
1315 putc ( *(const byte *)text, statusfp );
1318 putc ('\n', statusfp);
1319 fflush (statusfp);
1321 else
1323 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1324 char buf[950], *p;
1325 size_t n;
1327 p = buf;
1328 n = 0;
1329 while ( (text = va_arg (arg_ptr, const char *)) )
1331 if (n)
1333 *p++ = ' ';
1334 n++;
1336 for ( ; *text && n < DIM (buf)-2; n++)
1337 *p++ = *text++;
1339 *p = 0;
1340 err = assuan_write_status (ctx, get_status_string (no), buf);
1343 va_end (arg_ptr);
1344 return err;
1347 gpg_error_t
1348 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1350 return gpgsm_status2 (ctrl, no, text, NULL);
1353 gpg_error_t
1354 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1355 gpg_err_code_t ec)
1357 char buf[30];
1359 sprintf (buf, "%u", (unsigned int)ec);
1360 if (text)
1361 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1362 else
1363 return gpgsm_status2 (ctrl, no, buf, NULL);
1367 /* Helper to notify the client about Pinentry events. Because that
1368 might disturb some older clients, this is only done when enabled
1369 via an option. Returns an gpg error code. */
1370 gpg_error_t
1371 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1373 if (!ctrl || !ctrl->server_local
1374 || !ctrl->server_local->allow_pinentry_notify)
1375 return 0;
1376 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);