1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3 * 2010 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 <https://www.gnu.org/licenses/>.
33 #include "server-help.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;
47 int list_to_output; /* Write keylistings to the output fd. */
48 int enable_audit_log; /* Use an audit log. */
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 gpgrt_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 =
65 data_line_cookie_write,
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; */
80 strcpy_escaped_plus (char *d, const char *s)
84 if (*s == '%' && s[1] && s[2])
99 /* A write handler used by es_fopencookie to write assuan data
102 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
104 assuan_context_t ctx = cookie;
106 if (assuan_send_data (ctx, buffer, size))
108 gpg_err_set_errno (EIO);
112 return (gpgrt_ssize_t)size;
116 data_line_cookie_close (void *cookie)
118 assuan_context_t ctx = cookie;
120 if (assuan_send_data (ctx, NULL, 0))
122 gpg_err_set_errno (EIO);
131 close_message_fd (ctrl_t ctrl)
133 if (ctrl->server_local->message_fd != -1)
135 #ifdef HAVE_W32CE_SYSTEM
136 #warning Is this correct for W32/W32CE?
138 close (ctrl->server_local->message_fd);
139 ctrl->server_local->message_fd = -1;
144 /* Start a new audit session if this has been enabled. */
146 start_audit_session (ctrl_t ctrl)
148 audit_release (ctrl->audit);
150 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
151 return gpg_error_from_syserror ();
158 option_handler (assuan_context_t ctx, const char *key, const char *value)
160 ctrl_t ctrl = assuan_get_pointer (ctx);
163 if (!strcmp (key, "putenv"))
165 /* Change the session's environment to be used for the
166 Pinentry. Valid values are:
167 <NAME> Delete envvar NAME
168 <KEY>= Set envvar NAME to the empty string
169 <KEY>=<VALUE> Set envvar NAME to VALUE
171 err = session_env_putenv (opt.session_env, value);
173 else if (!strcmp (key, "display"))
175 err = session_env_setenv (opt.session_env, "DISPLAY", value);
177 else if (!strcmp (key, "ttyname"))
179 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
181 else if (!strcmp (key, "ttytype"))
183 err = session_env_setenv (opt.session_env, "TERM", value);
185 else if (!strcmp (key, "lc-ctype"))
187 xfree (opt.lc_ctype);
188 opt.lc_ctype = xtrystrdup (value);
190 err = gpg_error_from_syserror ();
192 else if (!strcmp (key, "lc-messages"))
194 xfree (opt.lc_messages);
195 opt.lc_messages = xtrystrdup (value);
196 if (!opt.lc_messages)
197 err = gpg_error_from_syserror ();
199 else if (!strcmp (key, "xauthority"))
201 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
203 else if (!strcmp (key, "pinentry-user-data"))
205 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
207 else if (!strcmp (key, "include-certs"))
209 int i = *value? atoi (value) : -1;
210 if (ctrl->include_certs < -2)
211 err = gpg_error (GPG_ERR_ASS_PARAMETER);
213 ctrl->include_certs = i;
215 else if (!strcmp (key, "list-mode"))
217 int i = *value? atoi (value) : 0;
218 if (!i || i == 1) /* default and mode 1 */
220 ctrl->server_local->list_internal = 1;
221 ctrl->server_local->list_external = 0;
225 ctrl->server_local->list_internal = 0;
226 ctrl->server_local->list_external = 1;
230 ctrl->server_local->list_internal = 1;
231 ctrl->server_local->list_external = 1;
234 err = gpg_error (GPG_ERR_ASS_PARAMETER);
236 else if (!strcmp (key, "list-to-output"))
238 int i = *value? atoi (value) : 0;
239 ctrl->server_local->list_to_output = i;
241 else if (!strcmp (key, "with-validation"))
243 int i = *value? atoi (value) : 0;
244 ctrl->with_validation = i;
246 else if (!strcmp (key, "with-secret"))
248 int i = *value? atoi (value) : 0;
249 ctrl->with_secret = i;
251 else if (!strcmp (key, "validation-model"))
253 int i = gpgsm_parse_validation_model (value);
254 if ( i >= 0 && i <= 2 )
255 ctrl->validation_model = i;
257 err = gpg_error (GPG_ERR_ASS_PARAMETER);
259 else if (!strcmp (key, "with-key-data"))
261 opt.with_key_data = 1;
263 else if (!strcmp (key, "enable-audit-log"))
265 int i = *value? atoi (value) : 0;
266 ctrl->server_local->enable_audit_log = i;
268 else if (!strcmp (key, "allow-pinentry-notify"))
270 ctrl->server_local->allow_pinentry_notify = 1;
272 else if (!strcmp (key, "with-ephemeral-keys"))
274 int i = *value? atoi (value) : 0;
275 ctrl->with_ephemeral_keys = i;
277 else if (!strcmp (key, "no-encrypt-to"))
279 ctrl->server_local->no_encrypt_to = 1;
281 else if (!strcmp (key, "offline"))
283 /* We ignore this option if gpgsm has been started with
284 --disable-dirmngr (which also sets offline). */
285 if (!opt.disable_dirmngr)
287 int i = *value? !!atoi (value) : 1;
292 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
299 reset_notify (assuan_context_t ctx, char *line)
301 ctrl_t ctrl = assuan_get_pointer (ctx);
305 gpgsm_release_certlist (ctrl->server_local->recplist);
306 gpgsm_release_certlist (ctrl->server_local->signerlist);
307 ctrl->server_local->recplist = NULL;
308 ctrl->server_local->signerlist = NULL;
309 close_message_fd (ctrl);
310 assuan_close_input_fd (ctx);
311 assuan_close_output_fd (ctx);
317 input_notify (assuan_context_t ctx, char *line)
319 ctrl_t ctrl = assuan_get_pointer (ctx);
321 ctrl->autodetect_encoding = 0;
324 if (strstr (line, "--armor"))
326 else if (strstr (line, "--base64"))
328 else if (strstr (line, "--binary"))
331 ctrl->autodetect_encoding = 1;
336 output_notify (assuan_context_t ctx, char *line)
338 ctrl_t ctrl = assuan_get_pointer (ctx);
340 ctrl->create_pem = 0;
341 ctrl->create_base64 = 0;
342 if (strstr (line, "--armor"))
343 ctrl->create_pem = 1;
344 else if (strstr (line, "--base64"))
345 ctrl->create_base64 = 1; /* just the raw output */
350 static const char hlp_recipient[] =
351 "RECIPIENT <userID>\n"
353 "Set the recipient for the encryption. USERID shall be the\n"
354 "internal representation of the key; the server may accept any other\n"
355 "way of specification [we will support this]. If this is a valid and\n"
356 "trusted recipient the server does respond with OK, otherwise the\n"
357 "return is an ERR with the reason why the recipient can't be used,\n"
358 "the encryption will then not be done for this recipient. If the\n"
359 "policy is not to encrypt at all if not all recipients are valid, the\n"
360 "client has to take care of this. All RECIPIENT commands are\n"
361 "cumulative until a RESET or an successful ENCRYPT command.";
363 cmd_recipient (assuan_context_t ctx, char *line)
365 ctrl_t ctrl = assuan_get_pointer (ctx);
369 rc = start_audit_session (ctrl);
374 rc = gpgsm_add_to_certlist (ctrl, line, 0,
375 &ctrl->server_local->recplist, 0);
378 gpgsm_status2 (ctrl, STATUS_INV_RECP,
379 get_inv_recpsgnr_code (rc), line, NULL);
386 static const char hlp_signer[] =
389 "Set the signer's keys for the signature creation. USERID should\n"
390 "be the internal representation of the key; the server may accept any\n"
391 "other way of specification [we will support this]. If this is a\n"
392 "valid and usable signing key the server does respond with OK,\n"
393 "otherwise it returns an ERR with the reason why the key can't be\n"
394 "used, the signing will then not be done for this key. If the policy\n"
395 "is not to sign at all if not all signer keys are valid, the client\n"
396 "has to take care of this. All SIGNER commands are cumulative until\n"
397 "a RESET but they are *not* reset by an SIGN command because it can\n"
398 "be expected that set of signers are used for more than one sign\n"
401 cmd_signer (assuan_context_t ctx, char *line)
403 ctrl_t ctrl = assuan_get_pointer (ctx);
406 rc = gpgsm_add_to_certlist (ctrl, line, 1,
407 &ctrl->server_local->signerlist, 0);
410 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
411 get_inv_recpsgnr_code (rc), line, NULL);
412 /* For compatibiliy reasons we also issue the old code after the
414 gpgsm_status2 (ctrl, STATUS_INV_RECP,
415 get_inv_recpsgnr_code (rc), line, NULL);
421 static const char hlp_encrypt[] =
424 "Do the actual encryption process. Takes the plaintext from the INPUT\n"
425 "command, writes to the ciphertext to the file descriptor set with\n"
426 "the OUTPUT command, take the recipients form all the recipients set\n"
427 "so far. If this command fails the clients should try to delete all\n"
428 "output currently done or otherwise mark it as invalid. GPGSM does\n"
429 "ensure that there won't be any security problem with leftover data\n"
430 "on the output in this case.\n"
432 "This command should in general not fail, as all necessary checks\n"
433 "have been done while setting the recipients. The input and output\n"
436 cmd_encrypt (assuan_context_t ctx, char *line)
438 ctrl_t ctrl = assuan_get_pointer (ctx);
446 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
448 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
449 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
451 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
453 out_fp = es_fdopen_nc (out_fd, "w");
455 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
457 /* Now add all encrypt-to marked recipients from the default
460 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
462 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
463 if (cl->is_encrypt_to)
464 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
465 &ctrl->server_local->recplist, 1);
468 rc = ctrl->audit? 0 : start_audit_session (ctrl);
470 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
471 ctrl->server_local->recplist,
475 gpgsm_release_certlist (ctrl->server_local->recplist);
476 ctrl->server_local->recplist = NULL;
477 /* Close and reset the fd */
478 close_message_fd (ctrl);
479 assuan_close_input_fd (ctx);
480 assuan_close_output_fd (ctx);
485 static const char hlp_decrypt[] =
488 "This performs the decrypt operation after doing some check on the\n"
489 "internal state. (e.g. that only needed data has been set). Because\n"
490 "it utilizes the GPG-Agent for the session key decryption, there is\n"
491 "no need to ask the client for a protecting passphrase - GPG-Agent\n"
492 "does take care of this by requesting this from the user.";
494 cmd_decrypt (assuan_context_t ctx, char *line)
496 ctrl_t ctrl = assuan_get_pointer (ctx);
503 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
505 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
506 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
508 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
510 out_fp = es_fdopen_nc (out_fd, "w");
512 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
514 rc = start_audit_session (ctrl);
516 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
519 /* Close and reset the fds. */
520 close_message_fd (ctrl);
521 assuan_close_input_fd (ctx);
522 assuan_close_output_fd (ctx);
528 static const char hlp_verify[] =
531 "This does a verify operation on the message send to the input FD.\n"
532 "The result is written out using status lines. If an output FD was\n"
533 "given, the signed text will be written to that.\n"
535 "If the signature is a detached one, the server will inquire about\n"
536 "the signed material and the client must provide it.";
538 cmd_verify (assuan_context_t ctx, char *line)
541 ctrl_t ctrl = assuan_get_pointer (ctx);
542 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
543 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
544 estream_t out_fp = NULL;
549 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
553 out_fp = es_fdopen_nc (out_fd, "w");
555 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
558 rc = start_audit_session (ctrl);
560 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
561 ctrl->server_local->message_fd, out_fp);
564 /* Close and reset the fd. */
565 close_message_fd (ctrl);
566 assuan_close_input_fd (ctx);
567 assuan_close_output_fd (ctx);
573 static const char hlp_sign[] =
574 "SIGN [--detached]\n"
576 "Sign the data set with the INPUT command and write it to the sink\n"
577 "set by OUTPUT. With \"--detached\", a detached signature is\n"
578 "created (surprise).";
580 cmd_sign (assuan_context_t ctx, char *line)
582 ctrl_t ctrl = assuan_get_pointer (ctx);
588 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
590 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
591 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
593 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
595 detached = has_option (line, "--detached");
597 out_fp = es_fdopen_nc (out_fd, "w");
599 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
601 rc = start_audit_session (ctrl);
603 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
604 inp_fd, detached, out_fp);
607 /* close and reset the fd */
608 close_message_fd (ctrl);
609 assuan_close_input_fd (ctx);
610 assuan_close_output_fd (ctx);
616 static const char hlp_import[] =
617 "IMPORT [--re-import]\n"
619 "Import the certificates read form the input-fd, return status\n"
620 "message for each imported one. The import checks the validity of\n"
621 "the certificate but not of the entire chain. It is possible to\n"
622 "import expired certificates.\n"
624 "With the option --re-import the input data is expected to a be a LF\n"
625 "separated list of fingerprints. The command will re-import these\n"
626 "certificates, meaning that they are made permanent by removing\n"
627 "their ephemeral flag.";
629 cmd_import (assuan_context_t ctx, char *line)
631 ctrl_t ctrl = assuan_get_pointer (ctx);
633 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
634 int reimport = has_option (line, "--re-import");
639 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
641 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
643 /* close and reset the fd */
644 close_message_fd (ctrl);
645 assuan_close_input_fd (ctx);
646 assuan_close_output_fd (ctx);
652 static const char hlp_export[] =
653 "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
655 "Export the certificates selected by PATTERN. With --data the output\n"
656 "is returned using Assuan D lines; the default is to use the sink given\n"
657 "by the last \"OUTPUT\" command. The options --armor or --base64 encode \n"
658 "the output using the PEM respective a plain base-64 format; the default\n"
659 "is a binary format which is only suitable for a single certificate.\n"
660 "With --secret the secret key is exported using the PKCS#8 format,\n"
661 "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
663 cmd_export (assuan_context_t ctx, char *line)
665 ctrl_t ctrl = assuan_get_pointer (ctx);
673 use_data = has_option (line, "--data");
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");
680 opt_secret = has_option (line, "--secret");
683 opt_raw = has_option (line, "--raw");
684 opt_pkcs12 = has_option (line, "--pkcs12");
687 line = skip_options (line);
689 /* Break the line down into an strlist_t. */
691 for (p=line; *p; line = p)
693 while (*p && *p != ' ')
699 sl = xtrymalloc (sizeof *sl + strlen (line));
703 return out_of_core ();
706 strcpy_escaped_plus (sl->d, line);
714 if (!list || !*list->d)
715 return set_error (GPG_ERR_NO_DATA, "No key given");
717 return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
724 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
728 return set_error (GPG_ERR_ASS_GENERAL,
729 "error setting up a data stream");
732 gpgsm_p12_export (ctrl, list->d, stream,
733 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
735 gpgsm_export (ctrl, list, stream);
740 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
746 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
748 out_fp = es_fdopen_nc (fd, "w");
752 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
756 gpgsm_p12_export (ctrl, list->d, out_fp,
757 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
759 gpgsm_export (ctrl, list, out_fp);
764 /* Close and reset the fds. */
765 close_message_fd (ctrl);
766 assuan_close_input_fd (ctx);
767 assuan_close_output_fd (ctx);
773 static const char hlp_delkeys[] =
774 "DELKEYS <patterns>\n"
776 "Delete the certificates specified by PATTERNS. Each pattern shall be\n"
777 "a percent-plus escaped certificate specification. Usually a\n"
778 "fingerprint will be used for this.";
780 cmd_delkeys (assuan_context_t ctx, char *line)
782 ctrl_t ctrl = assuan_get_pointer (ctx);
787 /* break the line down into an strlist_t */
789 for (p=line; *p; line = p)
791 while (*p && *p != ' ')
797 sl = xtrymalloc (sizeof *sl + strlen (line));
801 return out_of_core ();
804 strcpy_escaped_plus (sl->d, line);
810 rc = gpgsm_delete (ctrl, list);
813 /* close and reset the fd */
814 close_message_fd (ctrl);
815 assuan_close_input_fd (ctx);
816 assuan_close_output_fd (ctx);
823 static const char hlp_output[] =
826 "Set the file descriptor to write the output data to N. If N is not\n"
827 "given and the operating system supports file descriptor passing, the\n"
828 "file descriptor currently in flight will be used. See also the\n"
829 "\"INPUT\" and \"MESSAGE\" commands.";
830 static const char hlp_input[] =
833 "Set the file descriptor to read the input data to N. If N is not\n"
834 "given and the operating system supports file descriptor passing, the\n"
835 "file descriptor currently in flight will be used. See also the\n"
836 "\"MESSAGE\" and \"OUTPUT\" commands.";
837 static const char hlp_message[] =
840 "Set the file descriptor to read the message for a detached\n"
841 "signatures to N. If N is not given and the operating system\n"
842 "supports file descriptor passing, the file descriptor currently in\n"
843 "flight will be used. See also the \"INPUT\" and \"OUTPUT\" commands.";
845 cmd_message (assuan_context_t ctx, char *line)
850 ctrl_t ctrl = assuan_get_pointer (ctx);
852 rc = assuan_command_parse_fd (ctx, line, &sysfd);
856 #ifdef HAVE_W32CE_SYSTEM
857 sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0);
858 if (sysfd == INVALID_HANDLE_VALUE)
859 return set_error (gpg_err_code_from_syserror (),
860 "rvid conversion failed");
863 fd = translate_sys2libc_fd (sysfd, 0);
865 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
866 ctrl->server_local->message_fd = fd;
872 static const char hlp_listkeys[] =
873 "LISTKEYS [<patterns>]\n"
874 "LISTSECRETKEYS [<patterns>]\n"
875 "DUMPKEYS [<patterns>]\n"
876 "DUMPSECRETKEYS [<patterns>]\n"
878 "List all certificates or only those specified by PATTERNS. Each\n"
879 "pattern shall be a percent-plus escaped certificate specification.\n"
880 "The \"SECRET\" versions of the command filter the output to include\n"
881 "only certificates where the secret key is available or a corresponding\n"
882 "smartcard has been registered. The \"DUMP\" versions of the command\n"
883 "are only useful for debugging. The output format is a percent escaped\n"
884 "colon delimited listing as described in the manual.\n"
886 "These \"OPTION\" command keys effect the output::\n"
888 " \"list-mode\" set to 0: List only local certificates (default).\n"
890 " 2: List only external certificates.\n"
891 " 3: List local and external certificates.\n"
893 " \"with-validation\" set to true: Validate each certificate.\n"
895 " \"with-ephemeral-key\" set to true: Always include ephemeral\n"
898 " \"list-to-output\" set to true: Write output to the file descriptor\n"
899 " given by the last \"OUTPUT\" command.";
901 do_listkeys (assuan_context_t ctx, char *line, int mode)
903 ctrl_t ctrl = assuan_get_pointer (ctx);
907 unsigned int listmode;
910 /* Break the line down into an strlist. */
912 for (p=line; *p; line = p)
914 while (*p && *p != ' ')
920 sl = xtrymalloc (sizeof *sl + strlen (line));
924 return out_of_core ();
927 strcpy_escaped_plus (sl->d, line);
933 if (ctrl->server_local->list_to_output)
935 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
938 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
939 fp = es_fdopen_nc (outfd, "w");
941 return set_error (gpg_err_code_from_syserror (), "es_fdopen() failed");
945 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
947 return set_error (GPG_ERR_ASS_GENERAL,
948 "error setting up a data stream");
951 ctrl->with_colons = 1;
953 if (ctrl->server_local->list_internal)
955 if (ctrl->server_local->list_external)
957 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
960 if (ctrl->server_local->list_to_output)
961 assuan_close_output_fd (ctx);
966 cmd_listkeys (assuan_context_t ctx, char *line)
968 return do_listkeys (ctx, line, 3);
972 cmd_dumpkeys (assuan_context_t ctx, char *line)
974 return do_listkeys (ctx, line, 259);
978 cmd_listsecretkeys (assuan_context_t ctx, char *line)
980 return do_listkeys (ctx, line, 2);
984 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
986 return do_listkeys (ctx, line, 258);
991 static const char hlp_genkey[] =
994 "Read the parameters in native format from the input fd and write a\n"
995 "certificate request to the output.";
997 cmd_genkey (assuan_context_t ctx, char *line)
999 ctrl_t ctrl = assuan_get_pointer (ctx);
1001 estream_t in_stream, out_stream;
1006 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
1008 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
1009 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1011 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1013 in_stream = es_fdopen_nc (inp_fd, "r");
1015 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
1017 out_stream = es_fdopen_nc (out_fd, "w");
1020 es_fclose (in_stream);
1021 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
1023 rc = gpgsm_genkey (ctrl, in_stream, out_stream);
1024 es_fclose (out_stream);
1025 es_fclose (in_stream);
1027 /* close and reset the fds */
1028 assuan_close_input_fd (ctx);
1029 assuan_close_output_fd (ctx);
1036 static const char hlp_getauditlog[] =
1037 "GETAUDITLOG [--data] [--html]\n"
1039 "If --data is used, the output is send using D-lines and not to the\n"
1040 "file descriptor given by an OUTPUT command.\n"
1042 "If --html is used the output is formatted as an XHTML block. This is\n"
1043 "designed to be incorporated into a HTML document.";
1045 cmd_getauditlog (assuan_context_t ctx, char *line)
1047 ctrl_t ctrl = assuan_get_pointer (ctx);
1049 estream_t out_stream;
1050 int opt_data, opt_html;
1053 opt_data = has_option (line, "--data");
1054 opt_html = has_option (line, "--html");
1055 /* Not needed: line = skip_options (line); */
1058 return gpg_error (GPG_ERR_NO_DATA);
1062 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1064 return set_error (GPG_ERR_ASS_GENERAL,
1065 "error setting up a data stream");
1069 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1071 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1073 out_stream = es_fdopen_nc (out_fd, "w");
1076 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1080 audit_print_result (ctrl->audit, out_stream, opt_html);
1083 es_fclose (out_stream);
1085 /* Close and reset the fd. */
1087 assuan_close_output_fd (ctx);
1091 static const char hlp_getinfo[] =
1094 "Multipurpose function to return a variety of information.\n"
1095 "Supported values for WHAT are:\n"
1097 " version - Return the version of the program.\n"
1098 " pid - Return the process id of the server.\n"
1099 " agent-check - Return success if the agent is running.\n"
1100 " cmd_has_option CMD OPT\n"
1101 " - Returns OK if the command CMD implements the option OPT.\n"
1102 " offline - Returns OK if the connection is in offline mode.";
1104 cmd_getinfo (assuan_context_t ctx, char *line)
1106 ctrl_t ctrl = assuan_get_pointer (ctx);
1109 if (!strcmp (line, "version"))
1111 const char *s = VERSION;
1112 rc = assuan_send_data (ctx, s, strlen (s));
1114 else if (!strcmp (line, "pid"))
1118 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1119 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1121 else if (!strcmp (line, "agent-check"))
1123 rc = gpgsm_agent_send_nop (ctrl);
1125 else if (!strncmp (line, "cmd_has_option", 14)
1126 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1130 while (*line == ' ' || *line == '\t')
1133 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1137 while (*line && (*line != ' ' && *line != '\t'))
1140 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1144 while (*line == ' ' || *line == '\t')
1147 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1151 if (!command_has_option (cmd, cmdopt))
1152 rc = gpg_error (GPG_ERR_GENERAL);
1157 else if (!strcmp (line, "offline"))
1159 rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL);
1162 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1168 static const char hlp_passwd[] =
1171 "Change the passphrase of the secret key for USERID.";
1173 cmd_passwd (assuan_context_t ctx, char *line)
1175 ctrl_t ctrl = assuan_get_pointer (ctx);
1177 ksba_cert_t cert = NULL;
1180 line = skip_options (line);
1182 err = gpgsm_find_cert (ctrl, line, NULL, &cert);
1185 else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
1186 err = gpg_error (GPG_ERR_INTERNAL);
1189 char *desc = gpgsm_format_keydesc (cert);
1190 err = gpgsm_agent_passwd (ctrl, grip, desc);
1195 ksba_cert_release (cert);
1202 /* Return true if the command CMD implements the option OPT. */
1204 command_has_option (const char *cmd, const char *cmdopt)
1206 if (!strcmp (cmd, "IMPORT"))
1208 if (!strcmp (cmdopt, "re-import"))
1216 /* Tell the assuan library about our commands */
1218 register_commands (assuan_context_t ctx)
1222 assuan_handler_t handler;
1223 const char * const help;
1225 { "RECIPIENT", cmd_recipient, hlp_recipient },
1226 { "SIGNER", cmd_signer, hlp_signer },
1227 { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1228 { "DECRYPT", cmd_decrypt, hlp_decrypt },
1229 { "VERIFY", cmd_verify, hlp_verify },
1230 { "SIGN", cmd_sign, hlp_sign },
1231 { "IMPORT", cmd_import, hlp_import },
1232 { "EXPORT", cmd_export, hlp_export },
1233 { "INPUT", NULL, hlp_input },
1234 { "OUTPUT", NULL, hlp_output },
1235 { "MESSAGE", cmd_message, hlp_message },
1236 { "LISTKEYS", cmd_listkeys, hlp_listkeys },
1237 { "DUMPKEYS", cmd_dumpkeys, hlp_listkeys },
1238 { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
1239 { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
1240 { "GENKEY", cmd_genkey, hlp_genkey },
1241 { "DELKEYS", cmd_delkeys, hlp_delkeys },
1242 { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
1243 { "GETINFO", cmd_getinfo, hlp_getinfo },
1244 { "PASSWD", cmd_passwd, hlp_passwd },
1249 for (i=0; table[i].name; i++)
1251 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1259 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1260 set from the command line or config file. We only require those
1261 marked as encrypt-to. */
1263 gpgsm_server (certlist_t default_recplist)
1266 assuan_fd_t filedes[2];
1267 assuan_context_t ctx;
1268 struct server_control_s ctrl;
1269 static const char hello[] = ("GNU Privacy Guard's S/M server "
1272 memset (&ctrl, 0, sizeof ctrl);
1273 gpgsm_init_default_ctrl (&ctrl);
1275 /* We use a pipe based server so that we can work from scripts.
1276 assuan_init_pipe_server will automagically detect when we are
1277 called with a socketpair and ignore FILEDES in this case. */
1278 #ifdef HAVE_W32CE_SYSTEM
1279 #define SERVER_STDIN es_fileno(es_stdin)
1280 #define SERVER_STDOUT es_fileno(es_stdout)
1282 #define SERVER_STDIN 0
1283 #define SERVER_STDOUT 1
1285 filedes[0] = assuan_fdopen (SERVER_STDIN);
1286 filedes[1] = assuan_fdopen (SERVER_STDOUT);
1287 rc = assuan_new (&ctx);
1290 log_error ("failed to allocate assuan context: %s\n",
1295 rc = assuan_init_pipe_server (ctx, filedes);
1298 log_error ("failed to initialize the server: %s\n",
1302 rc = register_commands (ctx);
1305 log_error ("failed to the register commands with Assuan: %s\n",
1309 if (opt.verbose || opt.debug)
1313 /* Fixme: Use the really used socket name. */
1320 opt.config_filename,
1321 dirmngr_socket_name (),
1324 assuan_set_hello_line (ctx, tmp);
1329 assuan_set_hello_line (ctx, hello);
1331 assuan_register_reset_notify (ctx, reset_notify);
1332 assuan_register_input_notify (ctx, input_notify);
1333 assuan_register_output_notify (ctx, output_notify);
1334 assuan_register_option_handler (ctx, option_handler);
1336 assuan_set_pointer (ctx, &ctrl);
1337 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1338 ctrl.server_local->assuan_ctx = ctx;
1339 ctrl.server_local->message_fd = -1;
1340 ctrl.server_local->list_internal = 1;
1341 ctrl.server_local->list_external = 0;
1342 ctrl.server_local->default_recplist = default_recplist;
1346 rc = assuan_accept (ctx);
1353 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1357 rc = assuan_process (ctx);
1360 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1365 gpgsm_release_certlist (ctrl.server_local->recplist);
1366 ctrl.server_local->recplist = NULL;
1367 gpgsm_release_certlist (ctrl.server_local->signerlist);
1368 ctrl.server_local->signerlist = NULL;
1369 xfree (ctrl.server_local);
1371 audit_release (ctrl.audit);
1374 assuan_release (ctx);
1380 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1382 gpg_error_t err = 0;
1386 va_start (arg_ptr, no);
1388 if (ctrl->no_server && ctrl->status_fd == -1)
1389 ; /* No status wanted. */
1390 else if (ctrl->no_server)
1394 if (ctrl->status_fd == 1)
1396 else if (ctrl->status_fd == 2)
1399 statusfp = fdopen (ctrl->status_fd, "w");
1403 log_fatal ("can't open fd %d for status output: %s\n",
1404 ctrl->status_fd, strerror(errno));
1408 fputs ("[GNUPG:] ", statusfp);
1409 fputs (get_status_string (no), statusfp);
1411 while ( (text = va_arg (arg_ptr, const char*) ))
1413 putc ( ' ', statusfp );
1414 for (; *text; text++)
1417 fputs ( "\\n", statusfp );
1418 else if (*text == '\r')
1419 fputs ( "\\r", statusfp );
1421 putc ( *(const byte *)text, statusfp );
1424 putc ('\n', statusfp);
1429 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1435 while ( (text = va_arg (arg_ptr, const char *)) )
1442 for ( ; *text && n < DIM (buf)-2; n++)
1446 err = assuan_write_status (ctx, get_status_string (no), buf);
1454 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1456 return gpgsm_status2 (ctrl, no, text, NULL);
1460 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1465 sprintf (buf, "%u", (unsigned int)ec);
1467 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1469 return gpgsm_status2 (ctrl, no, buf, NULL);
1473 gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
1478 snprintf (buf, sizeof buf, "%u", err);
1480 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1482 return gpgsm_status2 (ctrl, no, buf, NULL);
1486 /* Helper to notify the client about Pinentry events. Because that
1487 might disturb some older clients, this is only done when enabled
1488 via an option. Returns an gpg error code. */
1490 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1492 if (!ctrl || !ctrl->server_local
1493 || !ctrl->server_local->allow_pinentry_notify)
1495 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);