1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001-2010 Free Software Foundation, Inc.
3 * Copyright (C) 2001-2011, 2013-2020 g10 Code GmbH
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/>.
32 #include "../common/sysutils.h"
33 #include "../common/server-help.h"
34 #include "../common/asshelp.h"
35 #include "../common/shareddefs.h"
37 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
40 /* The filepointer for status message used in non-server mode */
41 static FILE *statusfp;
43 /* Data used to assuciate an Assuan context with local server data */
44 struct server_local_s {
45 assuan_context_t assuan_ctx;
49 int list_to_output; /* Write keylistings to the output fd. */
50 int enable_audit_log; /* Use an audit log. */
52 certlist_t signerlist;
53 certlist_t default_recplist; /* As set by main() - don't release. */
54 int allow_pinentry_notify; /* Set if pinentry notifications should
55 be passed back to the client. */
56 int no_encrypt_to; /* Local version of option. */
60 /* Cookie definition for assuan data line output. */
61 static gpgrt_ssize_t data_line_cookie_write (void *cookie,
62 const void *buffer, size_t size);
63 static int data_line_cookie_close (void *cookie);
64 static es_cookie_io_functions_t data_line_cookie_functions =
67 data_line_cookie_write,
69 data_line_cookie_close
74 static int command_has_option (const char *cmd, const char *cmdopt);
79 /* Note that it is sufficient to allocate the target string D as
80 long as the source string S, i.e.: strlen(s)+1; */
82 strcpy_escaped_plus (char *d, const char *s)
86 if (*s == '%' && s[1] && s[2])
101 /* A write handler used by es_fopencookie to write assuan data
104 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
106 assuan_context_t ctx = cookie;
108 if (assuan_send_data (ctx, buffer, size))
110 gpg_err_set_errno (EIO);
114 return (gpgrt_ssize_t)size;
118 data_line_cookie_close (void *cookie)
120 assuan_context_t ctx = cookie;
122 if (assuan_send_data (ctx, NULL, 0))
124 gpg_err_set_errno (EIO);
133 close_message_fd (ctrl_t ctrl)
135 if (ctrl->server_local->message_fd != -1)
137 close (ctrl->server_local->message_fd);
138 ctrl->server_local->message_fd = -1;
143 /* Start a new audit session if this has been enabled. */
145 start_audit_session (ctrl_t ctrl)
147 audit_release (ctrl->audit);
149 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
150 return gpg_error_from_syserror ();
157 option_handler (assuan_context_t ctx, const char *key, const char *value)
159 ctrl_t ctrl = assuan_get_pointer (ctx);
162 if (!strcmp (key, "putenv"))
164 /* Change the session's environment to be used for the
165 Pinentry. Valid values are:
166 <NAME> Delete envvar NAME
167 <KEY>= Set envvar NAME to the empty string
168 <KEY>=<VALUE> Set envvar NAME to VALUE
170 err = session_env_putenv (opt.session_env, value);
172 else if (!strcmp (key, "display"))
174 err = session_env_setenv (opt.session_env, "DISPLAY", value);
176 else if (!strcmp (key, "ttyname"))
178 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
180 else if (!strcmp (key, "ttytype"))
182 err = session_env_setenv (opt.session_env, "TERM", value);
184 else if (!strcmp (key, "lc-ctype"))
186 xfree (opt.lc_ctype);
187 opt.lc_ctype = xtrystrdup (value);
189 err = gpg_error_from_syserror ();
191 else if (!strcmp (key, "lc-messages"))
193 xfree (opt.lc_messages);
194 opt.lc_messages = xtrystrdup (value);
195 if (!opt.lc_messages)
196 err = gpg_error_from_syserror ();
198 else if (!strcmp (key, "xauthority"))
200 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
202 else if (!strcmp (key, "pinentry-user-data"))
204 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
206 else if (!strcmp (key, "include-certs"))
208 int i = *value? atoi (value) : -1;
209 if (ctrl->include_certs < -2)
210 err = gpg_error (GPG_ERR_ASS_PARAMETER);
212 ctrl->include_certs = i;
214 else if (!strcmp (key, "list-mode"))
216 int i = *value? atoi (value) : 0;
217 if (!i || i == 1) /* default and mode 1 */
219 ctrl->server_local->list_internal = 1;
220 ctrl->server_local->list_external = 0;
224 ctrl->server_local->list_internal = 0;
225 ctrl->server_local->list_external = 1;
229 ctrl->server_local->list_internal = 1;
230 ctrl->server_local->list_external = 1;
233 err = gpg_error (GPG_ERR_ASS_PARAMETER);
235 else if (!strcmp (key, "list-to-output"))
237 int i = *value? atoi (value) : 0;
238 ctrl->server_local->list_to_output = i;
240 else if (!strcmp (key, "with-validation"))
242 int i = *value? atoi (value) : 0;
243 ctrl->with_validation = i;
245 else if (!strcmp (key, "with-secret"))
247 int i = *value? atoi (value) : 0;
248 ctrl->with_secret = i;
250 else if (!strcmp (key, "validation-model"))
252 int i = gpgsm_parse_validation_model (value);
253 if ( i >= 0 && i <= 2 )
254 ctrl->validation_model = i;
256 err = gpg_error (GPG_ERR_ASS_PARAMETER);
258 else if (!strcmp (key, "with-key-data"))
260 opt.with_key_data = 1;
262 else if (!strcmp (key, "enable-audit-log"))
264 int i = *value? atoi (value) : 0;
265 ctrl->server_local->enable_audit_log = i;
267 else if (!strcmp (key, "allow-pinentry-notify"))
269 ctrl->server_local->allow_pinentry_notify = 1;
271 else if (!strcmp (key, "with-ephemeral-keys"))
273 int i = *value? atoi (value) : 0;
274 ctrl->with_ephemeral_keys = i;
276 else if (!strcmp (key, "no-encrypt-to"))
278 ctrl->server_local->no_encrypt_to = 1;
280 else if (!strcmp (key, "offline"))
282 /* We ignore this option if gpgsm has been started with
283 --disable-dirmngr (which also sets offline). */
284 if (!opt.disable_dirmngr)
286 int i = *value? !!atoi (value) : 1;
290 else if (!strcmp (key, "request-origin"))
292 if (!opt.request_origin)
294 int i = parse_request_origin (value);
296 err = gpg_error (GPG_ERR_INV_VALUE);
298 opt.request_origin = i;
301 else if (!strcmp (key, "input-size-hint"))
303 ctrl->input_size_hint = string_to_u64 (value);
306 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
313 reset_notify (assuan_context_t ctx, char *line)
315 ctrl_t ctrl = assuan_get_pointer (ctx);
319 gpgsm_release_certlist (ctrl->server_local->recplist);
320 gpgsm_release_certlist (ctrl->server_local->signerlist);
321 ctrl->server_local->recplist = NULL;
322 ctrl->server_local->signerlist = NULL;
323 close_message_fd (ctrl);
324 assuan_close_input_fd (ctx);
325 assuan_close_output_fd (ctx);
331 input_notify (assuan_context_t ctx, char *line)
333 ctrl_t ctrl = assuan_get_pointer (ctx);
335 ctrl->autodetect_encoding = 0;
338 if (strstr (line, "--armor"))
340 else if (strstr (line, "--base64"))
342 else if (strstr (line, "--binary"))
345 ctrl->autodetect_encoding = 1;
350 output_notify (assuan_context_t ctx, char *line)
352 ctrl_t ctrl = assuan_get_pointer (ctx);
354 ctrl->create_pem = 0;
355 ctrl->create_base64 = 0;
356 if (strstr (line, "--armor"))
357 ctrl->create_pem = 1;
358 else if (strstr (line, "--base64"))
359 ctrl->create_base64 = 1; /* just the raw output */
364 static const char hlp_recipient[] =
365 "RECIPIENT <userID>\n"
367 "Set the recipient for the encryption. USERID shall be the\n"
368 "internal representation of the key; the server may accept any other\n"
369 "way of specification [we will support this]. If this is a valid and\n"
370 "trusted recipient the server does respond with OK, otherwise the\n"
371 "return is an ERR with the reason why the recipient can't be used,\n"
372 "the encryption will then not be done for this recipient. If the\n"
373 "policy is not to encrypt at all if not all recipients are valid, the\n"
374 "client has to take care of this. All RECIPIENT commands are\n"
375 "cumulative until a RESET or an successful ENCRYPT command.";
377 cmd_recipient (assuan_context_t ctx, char *line)
379 ctrl_t ctrl = assuan_get_pointer (ctx);
383 rc = start_audit_session (ctrl);
388 rc = gpgsm_add_to_certlist (ctrl, line, 0,
389 &ctrl->server_local->recplist, 0);
392 gpgsm_status2 (ctrl, STATUS_INV_RECP,
393 get_inv_recpsgnr_code (rc), line, NULL);
400 static const char hlp_signer[] =
403 "Set the signer's keys for the signature creation. USERID should\n"
404 "be the internal representation of the key; the server may accept any\n"
405 "other way of specification [we will support this]. If this is a\n"
406 "valid and usable signing key the server does respond with OK,\n"
407 "otherwise it returns an ERR with the reason why the key can't be\n"
408 "used, the signing will then not be done for this key. If the policy\n"
409 "is not to sign at all if not all signer keys are valid, the client\n"
410 "has to take care of this. All SIGNER commands are cumulative until\n"
411 "a RESET but they are *not* reset by an SIGN command because it can\n"
412 "be expected that set of signers are used for more than one sign\n"
415 cmd_signer (assuan_context_t ctx, char *line)
417 ctrl_t ctrl = assuan_get_pointer (ctx);
420 rc = gpgsm_add_to_certlist (ctrl, line, 1,
421 &ctrl->server_local->signerlist, 0);
424 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
425 get_inv_recpsgnr_code (rc), line, NULL);
426 /* For compatibility reasons we also issue the old code after the
428 gpgsm_status2 (ctrl, STATUS_INV_RECP,
429 get_inv_recpsgnr_code (rc), line, NULL);
435 static const char hlp_encrypt[] =
438 "Do the actual encryption process. Takes the plaintext from the INPUT\n"
439 "command, writes to the ciphertext to the file descriptor set with\n"
440 "the OUTPUT command, take the recipients form all the recipients set\n"
441 "so far. If this command fails the clients should try to delete all\n"
442 "output currently done or otherwise mark it as invalid. GPGSM does\n"
443 "ensure that there won't be any security problem with leftover data\n"
444 "on the output in this case.\n"
446 "This command should in general not fail, as all necessary checks\n"
447 "have been done while setting the recipients. The input and output\n"
450 cmd_encrypt (assuan_context_t ctx, char *line)
452 ctrl_t ctrl = assuan_get_pointer (ctx);
460 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
462 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
463 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
465 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
467 out_fp = es_fdopen_nc (out_fd, "w");
469 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
471 /* Now add all encrypt-to marked recipients from the default
474 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
476 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
477 if (cl->is_encrypt_to)
478 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
479 &ctrl->server_local->recplist, 1);
482 rc = ctrl->audit? 0 : start_audit_session (ctrl);
484 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
485 ctrl->server_local->recplist,
489 gpgsm_release_certlist (ctrl->server_local->recplist);
490 ctrl->server_local->recplist = NULL;
491 /* Close and reset the fd */
492 close_message_fd (ctrl);
493 assuan_close_input_fd (ctx);
494 assuan_close_output_fd (ctx);
499 static const char hlp_decrypt[] =
502 "This performs the decrypt operation after doing some check on the\n"
503 "internal state. (e.g. that only needed data has been set). Because\n"
504 "it utilizes the GPG-Agent for the session key decryption, there is\n"
505 "no need to ask the client for a protecting passphrase - GPG-Agent\n"
506 "does take care of this by requesting this from the user.";
508 cmd_decrypt (assuan_context_t ctx, char *line)
510 ctrl_t ctrl = assuan_get_pointer (ctx);
517 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
519 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
520 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
522 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
524 out_fp = es_fdopen_nc (out_fd, "w");
526 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
528 rc = start_audit_session (ctrl);
530 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
533 /* Close and reset the fds. */
534 close_message_fd (ctrl);
535 assuan_close_input_fd (ctx);
536 assuan_close_output_fd (ctx);
542 static const char hlp_verify[] =
545 "This does a verify operation on the message send to the input FD.\n"
546 "The result is written out using status lines. If an output FD was\n"
547 "given, the signed text will be written to that.\n"
549 "If the signature is a detached one, the server will inquire about\n"
550 "the signed material and the client must provide it.";
552 cmd_verify (assuan_context_t ctx, char *line)
555 ctrl_t ctrl = assuan_get_pointer (ctx);
556 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
557 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
558 estream_t out_fp = NULL;
563 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
567 out_fp = es_fdopen_nc (out_fd, "w");
569 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
572 rc = start_audit_session (ctrl);
574 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
575 ctrl->server_local->message_fd, out_fp);
578 /* Close and reset the fd. */
579 close_message_fd (ctrl);
580 assuan_close_input_fd (ctx);
581 assuan_close_output_fd (ctx);
587 static const char hlp_sign[] =
588 "SIGN [--detached]\n"
590 "Sign the data set with the INPUT command and write it to the sink\n"
591 "set by OUTPUT. With \"--detached\", a detached signature is\n"
592 "created (surprise).";
594 cmd_sign (assuan_context_t ctx, char *line)
596 ctrl_t ctrl = assuan_get_pointer (ctx);
602 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
604 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
605 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
607 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
609 detached = has_option (line, "--detached");
611 out_fp = es_fdopen_nc (out_fd, "w");
613 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
615 rc = start_audit_session (ctrl);
617 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
618 inp_fd, detached, out_fp);
621 /* close and reset the fd */
622 close_message_fd (ctrl);
623 assuan_close_input_fd (ctx);
624 assuan_close_output_fd (ctx);
630 static const char hlp_import[] =
631 "IMPORT [--re-import]\n"
633 "Import the certificates read form the input-fd, return status\n"
634 "message for each imported one. The import checks the validity of\n"
635 "the certificate but not of the entire chain. It is possible to\n"
636 "import expired certificates.\n"
638 "With the option --re-import the input data is expected to a be a LF\n"
639 "separated list of fingerprints. The command will re-import these\n"
640 "certificates, meaning that they are made permanent by removing\n"
641 "their ephemeral flag.";
643 cmd_import (assuan_context_t ctx, char *line)
645 ctrl_t ctrl = assuan_get_pointer (ctx);
647 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
648 int reimport = has_option (line, "--re-import");
653 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
655 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
657 /* close and reset the fd */
658 close_message_fd (ctrl);
659 assuan_close_input_fd (ctx);
660 assuan_close_output_fd (ctx);
666 static const char hlp_export[] =
667 "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
669 "Export the certificates selected by PATTERN. With --data the output\n"
670 "is returned using Assuan D lines; the default is to use the sink given\n"
671 "by the last \"OUTPUT\" command. The options --armor or --base64 encode \n"
672 "the output using the PEM respective a plain base-64 format; the default\n"
673 "is a binary format which is only suitable for a single certificate.\n"
674 "With --secret the secret key is exported using the PKCS#8 format,\n"
675 "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
677 cmd_export (assuan_context_t ctx, char *line)
679 ctrl_t ctrl = assuan_get_pointer (ctx);
687 use_data = has_option (line, "--data");
690 /* We need to override any possible setting done by an OUTPUT command. */
691 ctrl->create_pem = has_option (line, "--armor");
692 ctrl->create_base64 = has_option (line, "--base64");
694 opt_secret = has_option (line, "--secret");
697 opt_raw = has_option (line, "--raw");
698 opt_pkcs12 = has_option (line, "--pkcs12");
701 line = skip_options (line);
703 /* Break the line down into an strlist_t. */
705 for (p=line; *p; line = p)
707 while (*p && *p != ' ')
713 sl = xtrymalloc (sizeof *sl + strlen (line));
717 return out_of_core ();
720 strcpy_escaped_plus (sl->d, line);
729 return set_error (GPG_ERR_NO_DATA, "No key given");
733 return set_error (GPG_ERR_NO_DATA, "No key given");
736 return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
743 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
747 return set_error (GPG_ERR_ASS_GENERAL,
748 "error setting up a data stream");
751 gpgsm_p12_export (ctrl, list->d, stream,
752 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
754 gpgsm_export (ctrl, list, stream);
759 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
765 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
767 out_fp = es_fdopen_nc (fd, "w");
771 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
775 gpgsm_p12_export (ctrl, list->d, out_fp,
776 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
778 gpgsm_export (ctrl, list, out_fp);
783 /* Close and reset the fds. */
784 close_message_fd (ctrl);
785 assuan_close_input_fd (ctx);
786 assuan_close_output_fd (ctx);
792 static const char hlp_delkeys[] =
793 "DELKEYS <patterns>\n"
795 "Delete the certificates specified by PATTERNS. Each pattern shall be\n"
796 "a percent-plus escaped certificate specification. Usually a\n"
797 "fingerprint will be used for this.";
799 cmd_delkeys (assuan_context_t ctx, char *line)
801 ctrl_t ctrl = assuan_get_pointer (ctx);
806 /* break the line down into an strlist_t */
808 for (p=line; *p; line = p)
810 while (*p && *p != ' ')
816 sl = xtrymalloc (sizeof *sl + strlen (line));
820 return out_of_core ();
823 strcpy_escaped_plus (sl->d, line);
829 rc = gpgsm_delete (ctrl, list);
832 /* close and reset the fd */
833 close_message_fd (ctrl);
834 assuan_close_input_fd (ctx);
835 assuan_close_output_fd (ctx);
842 static const char hlp_output[] =
845 "Set the file descriptor to write the output data to N. If N is not\n"
846 "given and the operating system supports file descriptor passing, the\n"
847 "file descriptor currently in flight will be used. See also the\n"
848 "\"INPUT\" and \"MESSAGE\" commands.";
849 static const char hlp_input[] =
852 "Set the file descriptor to read the input data to N. If N is not\n"
853 "given and the operating system supports file descriptor passing, the\n"
854 "file descriptor currently in flight will be used. See also the\n"
855 "\"MESSAGE\" and \"OUTPUT\" commands.";
856 static const char hlp_message[] =
859 "Set the file descriptor to read the message for a detached\n"
860 "signatures to N. If N is not given and the operating system\n"
861 "supports file descriptor passing, the file descriptor currently in\n"
862 "flight will be used. See also the \"INPUT\" and \"OUTPUT\" commands.";
864 cmd_message (assuan_context_t ctx, char *line)
869 ctrl_t ctrl = assuan_get_pointer (ctx);
871 rc = assuan_command_parse_fd (ctx, line, &sysfd);
876 fd = translate_sys2libc_fd (sysfd, 0);
878 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
879 ctrl->server_local->message_fd = fd;
885 static const char hlp_listkeys[] =
886 "LISTKEYS [<options>] [<patterns>]\n"
887 "LISTSECRETKEYS [<options>] [<patterns>]\n"
888 "DUMPKEYS [<options>] [<patterns>]\n"
889 "DUMPSECRETKEYS [<options>] [<patterns>]\n"
891 "List all certificates or only those specified by PATTERNS. Each\n"
892 "pattern shall be a percent-plus escaped certificate specification.\n"
893 "The \"SECRET\" versions of the command filter the output to include\n"
894 "only certificates where the secret key is available or a corresponding\n"
895 "smartcard has been registered. The \"DUMP\" versions of the command\n"
896 "are only useful for debugging. The output format is a percent escaped\n"
897 "colon delimited listing as described in the manual.\n"
898 "Supported values for OPTIONS are:\n"
899 " -- Stop option processing\n"
900 " --issuer-der PATTERN is a DER of the serialnumber as hexstring;\n"
901 " the issuer is then inquired with \"ISSUER_DER\".\n"
903 "These Assuan \"OPTION\" command keys effect the output::\n"
905 " \"list-mode\" set to 0: List only local certificates (default).\n"
907 " 2: List only external certificates.\n"
908 " 3: List local and external certificates.\n"
910 " \"with-validation\" set to true: Validate each certificate.\n"
912 " \"with-ephemeral-key\" set to true: Always include ephemeral\n"
915 " \"list-to-output\" set to true: Write output to the file descriptor\n"
916 " given by the last \"OUTPUT\" command.";
918 do_listkeys (assuan_context_t ctx, char *line, int mode)
920 ctrl_t ctrl = assuan_get_pointer (ctx);
925 unsigned int listmode;
929 opt_issuer_der = has_option (line, "--issuer-der");
930 line = skip_options (line);
932 /* Break the line down into an strlist. */
934 for (p=line; *p; line = p)
936 while (*p && *p != ' ')
942 sl = xtrymalloc (sizeof *sl + strlen (line));
946 return out_of_core ();
949 strcpy_escaped_plus (sl->d, line);
954 if (opt_issuer_der && (!list || list->next))
957 return set_error (GPG_ERR_INV_ARG,
958 "only one arg for --issuer-der please");
963 unsigned char *value = NULL;
967 err = assuan_inquire (ctx, "ISSUER_DER", &value, &valuelen, 0);
977 return gpg_error (GPG_ERR_MISSING_VALUE);
979 err = ksba_dn_der2str (value, valuelen, &issuer);
986 /* ksba_dn_der2str seems to always append "\\0A". Trim that. */
988 if (n > 3 && !strcmp (issuer + n - 3, "\\0A"))
991 p = strconcat ("#", list->d, "/", issuer, NULL);
994 err = gpg_error_from_syserror ();
1000 free_strlist (list);
1002 if (!add_to_strlist_try (&list, p))
1004 err = gpg_error_from_syserror ();
1012 if (ctrl->server_local->list_to_output)
1014 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1018 free_strlist (list);
1019 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1021 fp = es_fdopen_nc (outfd, "w");
1024 free_strlist (list);
1025 return set_error (gpg_err_code_from_syserror (),
1026 "es_fdopen() failed");
1031 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
1034 free_strlist (list);
1035 return set_error (GPG_ERR_ASS_GENERAL,
1036 "error setting up a data stream");
1040 ctrl->with_colons = 1;
1042 if (ctrl->server_local->list_internal)
1044 if (ctrl->server_local->list_external)
1046 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
1048 free_strlist (list);
1050 if (ctrl->server_local->list_to_output)
1051 assuan_close_output_fd (ctx);
1056 cmd_listkeys (assuan_context_t ctx, char *line)
1058 return do_listkeys (ctx, line, 3);
1062 cmd_dumpkeys (assuan_context_t ctx, char *line)
1064 return do_listkeys (ctx, line, 259);
1068 cmd_listsecretkeys (assuan_context_t ctx, char *line)
1070 return do_listkeys (ctx, line, 2);
1074 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
1076 return do_listkeys (ctx, line, 258);
1081 static const char hlp_genkey[] =
1084 "Read the parameters in native format from the input fd and write a\n"
1085 "certificate request to the output.";
1087 cmd_genkey (assuan_context_t ctx, char *line)
1089 ctrl_t ctrl = assuan_get_pointer (ctx);
1091 estream_t in_stream, out_stream;
1096 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
1098 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
1099 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1101 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1103 in_stream = es_fdopen_nc (inp_fd, "r");
1105 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
1107 out_stream = es_fdopen_nc (out_fd, "w");
1110 es_fclose (in_stream);
1111 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
1113 rc = gpgsm_genkey (ctrl, in_stream, out_stream);
1114 es_fclose (out_stream);
1115 es_fclose (in_stream);
1117 /* close and reset the fds */
1118 assuan_close_input_fd (ctx);
1119 assuan_close_output_fd (ctx);
1126 static const char hlp_getauditlog[] =
1127 "GETAUDITLOG [--data] [--html]\n"
1129 "If --data is used, the output is send using D-lines and not to the\n"
1130 "file descriptor given by an OUTPUT command.\n"
1132 "If --html is used the output is formatted as an XHTML block. This is\n"
1133 "designed to be incorporated into a HTML document.";
1135 cmd_getauditlog (assuan_context_t ctx, char *line)
1137 ctrl_t ctrl = assuan_get_pointer (ctx);
1139 estream_t out_stream;
1140 int opt_data, opt_html;
1143 opt_data = has_option (line, "--data");
1144 opt_html = has_option (line, "--html");
1145 /* Not needed: line = skip_options (line); */
1148 return gpg_error (GPG_ERR_NO_DATA);
1152 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1154 return set_error (GPG_ERR_ASS_GENERAL,
1155 "error setting up a data stream");
1159 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1161 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1163 out_stream = es_fdopen_nc (out_fd, "w");
1166 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1170 audit_print_result (ctrl->audit, out_stream, opt_html);
1173 es_fclose (out_stream);
1175 /* Close and reset the fd. */
1177 assuan_close_output_fd (ctx);
1181 static const char hlp_getinfo[] =
1184 "Multipurpose function to return a variety of information.\n"
1185 "Supported values for WHAT are:\n"
1187 " version - Return the version of the program.\n"
1188 " pid - Return the process id of the server.\n"
1189 " agent-check - Return success if the agent is running.\n"
1190 " cmd_has_option CMD OPT\n"
1191 " - Returns OK if the command CMD implements the option OPT.\n"
1192 " offline - Returns OK if the connection is in offline mode.";
1194 cmd_getinfo (assuan_context_t ctx, char *line)
1196 ctrl_t ctrl = assuan_get_pointer (ctx);
1199 if (!strcmp (line, "version"))
1201 const char *s = VERSION;
1202 rc = assuan_send_data (ctx, s, strlen (s));
1204 else if (!strcmp (line, "pid"))
1208 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1209 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1211 else if (!strcmp (line, "agent-check"))
1213 rc = gpgsm_agent_send_nop (ctrl);
1215 else if (!strncmp (line, "cmd_has_option", 14)
1216 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1220 while (*line == ' ' || *line == '\t')
1223 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1227 while (*line && (*line != ' ' && *line != '\t'))
1230 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1234 while (*line == ' ' || *line == '\t')
1237 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1241 if (!command_has_option (cmd, cmdopt))
1242 rc = gpg_error (GPG_ERR_FALSE);
1247 else if (!strcmp (line, "offline"))
1249 rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE);
1252 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1258 static const char hlp_passwd[] =
1261 "Change the passphrase of the secret key for USERID.";
1263 cmd_passwd (assuan_context_t ctx, char *line)
1265 ctrl_t ctrl = assuan_get_pointer (ctx);
1267 ksba_cert_t cert = NULL;
1270 line = skip_options (line);
1272 err = gpgsm_find_cert (ctrl, line, NULL, &cert, 0);
1275 else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
1276 err = gpg_error (GPG_ERR_INTERNAL);
1279 char *desc = gpgsm_format_keydesc (cert);
1280 err = gpgsm_agent_passwd (ctrl, grip, desc);
1285 ksba_cert_release (cert);
1292 /* Return true if the command CMD implements the option OPT. */
1294 command_has_option (const char *cmd, const char *cmdopt)
1296 if (!strcmp (cmd, "IMPORT"))
1298 if (!strcmp (cmdopt, "re-import"))
1306 /* Tell the assuan library about our commands */
1308 register_commands (assuan_context_t ctx)
1312 assuan_handler_t handler;
1313 const char * const help;
1315 { "RECIPIENT", cmd_recipient, hlp_recipient },
1316 { "SIGNER", cmd_signer, hlp_signer },
1317 { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1318 { "DECRYPT", cmd_decrypt, hlp_decrypt },
1319 { "VERIFY", cmd_verify, hlp_verify },
1320 { "SIGN", cmd_sign, hlp_sign },
1321 { "IMPORT", cmd_import, hlp_import },
1322 { "EXPORT", cmd_export, hlp_export },
1323 { "INPUT", NULL, hlp_input },
1324 { "OUTPUT", NULL, hlp_output },
1325 { "MESSAGE", cmd_message, hlp_message },
1326 { "LISTKEYS", cmd_listkeys, hlp_listkeys },
1327 { "DUMPKEYS", cmd_dumpkeys, hlp_listkeys },
1328 { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
1329 { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
1330 { "GENKEY", cmd_genkey, hlp_genkey },
1331 { "DELKEYS", cmd_delkeys, hlp_delkeys },
1332 { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
1333 { "GETINFO", cmd_getinfo, hlp_getinfo },
1334 { "PASSWD", cmd_passwd, hlp_passwd },
1339 for (i=0; table[i].name; i++)
1341 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1349 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1350 set from the command line or config file. We only require those
1351 marked as encrypt-to. */
1353 gpgsm_server (certlist_t default_recplist)
1356 assuan_fd_t filedes[2];
1357 assuan_context_t ctx;
1358 struct server_control_s ctrl;
1359 static const char hello[] = ("GNU Privacy Guard's S/M server "
1362 memset (&ctrl, 0, sizeof ctrl);
1363 gpgsm_init_default_ctrl (&ctrl);
1365 /* We use a pipe based server so that we can work from scripts.
1366 assuan_init_pipe_server will automagically detect when we are
1367 called with a socketpair and ignore FILEDES in this case. */
1368 #define SERVER_STDIN 0
1369 #define SERVER_STDOUT 1
1371 filedes[0] = assuan_fdopen (SERVER_STDIN);
1372 filedes[1] = assuan_fdopen (SERVER_STDOUT);
1373 rc = assuan_new (&ctx);
1376 log_error ("failed to allocate assuan context: %s\n",
1381 rc = assuan_init_pipe_server (ctx, filedes);
1384 log_error ("failed to initialize the server: %s\n",
1388 rc = register_commands (ctx);
1391 log_error ("failed to the register commands with Assuan: %s\n",
1395 if (opt.verbose || opt.debug)
1399 /* Fixme: Use the really used socket name. */
1406 opt.config_filename,
1407 dirmngr_socket_name (),
1410 assuan_set_hello_line (ctx, tmp);
1415 assuan_set_hello_line (ctx, hello);
1417 assuan_register_reset_notify (ctx, reset_notify);
1418 assuan_register_input_notify (ctx, input_notify);
1419 assuan_register_output_notify (ctx, output_notify);
1420 assuan_register_option_handler (ctx, option_handler);
1422 assuan_set_pointer (ctx, &ctrl);
1423 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1424 ctrl.server_local->assuan_ctx = ctx;
1425 ctrl.server_local->message_fd = -1;
1426 ctrl.server_local->list_internal = 1;
1427 ctrl.server_local->list_external = 0;
1428 ctrl.server_local->default_recplist = default_recplist;
1432 rc = assuan_accept (ctx);
1439 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1443 rc = assuan_process (ctx);
1446 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1451 gpgsm_release_certlist (ctrl.server_local->recplist);
1452 ctrl.server_local->recplist = NULL;
1453 gpgsm_release_certlist (ctrl.server_local->signerlist);
1454 ctrl.server_local->signerlist = NULL;
1455 xfree (ctrl.server_local);
1457 audit_release (ctrl.audit);
1460 gpgsm_deinit_default_ctrl (&ctrl);
1462 assuan_release (ctx);
1468 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1470 gpg_error_t err = 0;
1474 va_start (arg_ptr, no);
1476 if (ctrl->no_server && ctrl->status_fd == -1)
1477 ; /* No status wanted. */
1478 else if (ctrl->no_server)
1482 if (ctrl->status_fd == 1)
1484 else if (ctrl->status_fd == 2)
1487 statusfp = fdopen (ctrl->status_fd, "w");
1491 log_fatal ("can't open fd %d for status output: %s\n",
1492 ctrl->status_fd, strerror(errno));
1496 fputs ("[GNUPG:] ", statusfp);
1497 fputs (get_status_string (no), statusfp);
1499 while ( (text = va_arg (arg_ptr, const char*) ))
1501 putc ( ' ', statusfp );
1502 for (; *text; text++)
1505 fputs ( "\\n", statusfp );
1506 else if (*text == '\r')
1507 fputs ( "\\r", statusfp );
1509 putc ( *(const byte *)text, statusfp );
1512 putc ('\n', statusfp);
1513 if (ferror (statusfp))
1514 err = gpg_error_from_syserror ();
1518 if (ferror (statusfp))
1519 err = gpg_error_from_syserror ();
1524 err = vprint_assuan_status_strings (ctrl->server_local->assuan_ctx,
1525 get_status_string (no), arg_ptr);
1533 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1535 return gpgsm_status2 (ctrl, no, text, NULL);
1539 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1544 snprintf (buf, sizeof buf, "%u", (unsigned int)ec);
1546 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1548 return gpgsm_status2 (ctrl, no, buf, NULL);
1552 gpgsm_status_with_error (ctrl_t ctrl, int no, const char *text,
1557 snprintf (buf, sizeof buf, "%u", err);
1559 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1561 return gpgsm_status2 (ctrl, no, buf, NULL);
1565 /* This callback is used to emit progress status lines. */
1567 gpgsm_progress_cb (ctrl_t ctrl, uint64_t current, uint64_t total)
1570 char units[] = "BKMGTPEZY?";
1575 if (current > total)
1578 while (total > 1024*1024)
1587 while (current > 1024*1024)
1597 snprintf (buffer, sizeof buffer, "? %lu %lu %c%s",
1598 (unsigned long)current, (unsigned long)total,
1599 units[unitidx], unitidx? "iB" : "");
1600 return gpgsm_status2 (ctrl, STATUS_PROGRESS, "?", buffer, NULL);
1604 /* Helper to notify the client about Pinentry events. Because that
1605 might disturb some older clients, this is only done when enabled
1606 via an option. Returns an gpg error code. */
1608 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1610 if (!ctrl || !ctrl->server_local
1611 || !ctrl->server_local->allow_pinentry_notify)
1613 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);