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 <http://www.gnu.org/licenses/>.
34 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
37 /* The filepointer for status message used in non-server mode */
38 static FILE *statusfp;
40 /* Data used to assuciate an Assuan context with local server data */
41 struct server_local_s {
42 assuan_context_t assuan_ctx;
46 int list_to_output; /* Write keylistings to the output fd. */
47 int enable_audit_log; /* Use an audit log. */
49 certlist_t signerlist;
50 certlist_t default_recplist; /* As set by main() - don't release. */
51 int allow_pinentry_notify; /* Set if pinentry notifications should
52 be passed back to the client. */
53 int no_encrypt_to; /* Local version of option. */
57 /* Cookie definition for assuan data line output. */
58 static ssize_t data_line_cookie_write (void *cookie,
59 const void *buffer, size_t size);
60 static int data_line_cookie_close (void *cookie);
61 static es_cookie_io_functions_t data_line_cookie_functions =
64 data_line_cookie_write,
66 data_line_cookie_close
71 static int command_has_option (const char *cmd, const char *cmdopt);
76 /* Note that it is sufficient to allocate the target string D as
77 long as the source string S, i.e.: strlen(s)+1; */
79 strcpy_escaped_plus (char *d, const char *s)
83 if (*s == '%' && s[1] && s[2])
99 Blanks after the options are also removed. */
101 skip_options (const char *line)
103 while (spacep (line))
105 while ( *line == '-' && line[1] == '-' )
107 while (*line && !spacep (line))
109 while (spacep (line))
116 /* Check whether the option NAME appears in LINE */
118 has_option (const char *line, const char *name)
121 int n = strlen (name);
123 s = strstr (line, name);
124 if (s && s >= skip_options (line))
126 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
130 /* A write handler used by es_fopencookie to write assuan data
133 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
135 assuan_context_t ctx = cookie;
137 if (assuan_send_data (ctx, buffer, size))
139 gpg_err_set_errno (EIO);
147 data_line_cookie_close (void *cookie)
149 assuan_context_t ctx = cookie;
151 if (assuan_send_data (ctx, NULL, 0))
153 gpg_err_set_errno (EIO);
162 close_message_fd (ctrl_t ctrl)
164 if (ctrl->server_local->message_fd != -1)
166 #ifdef HAVE_W32CE_SYSTEM
167 #warning Is this correct for W32/W32CE?
169 close (ctrl->server_local->message_fd);
170 ctrl->server_local->message_fd = -1;
175 /* Start a new audit session if this has been enabled. */
177 start_audit_session (ctrl_t ctrl)
179 audit_release (ctrl->audit);
181 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
182 return gpg_error_from_syserror ();
189 option_handler (assuan_context_t ctx, const char *key, const char *value)
191 ctrl_t ctrl = assuan_get_pointer (ctx);
194 if (!strcmp (key, "putenv"))
196 /* Change the session's environment to be used for the
197 Pinentry. Valid values are:
198 <NAME> Delete envvar NAME
199 <KEY>= Set envvar NAME to the empty string
200 <KEY>=<VALUE> Set envvar NAME to VALUE
202 err = session_env_putenv (opt.session_env, value);
204 else if (!strcmp (key, "display"))
206 err = session_env_setenv (opt.session_env, "DISPLAY", value);
208 else if (!strcmp (key, "ttyname"))
210 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
212 else if (!strcmp (key, "ttytype"))
214 err = session_env_setenv (opt.session_env, "TERM", value);
216 else if (!strcmp (key, "lc-ctype"))
218 xfree (opt.lc_ctype);
219 opt.lc_ctype = xtrystrdup (value);
221 err = gpg_error_from_syserror ();
223 else if (!strcmp (key, "lc-messages"))
225 xfree (opt.lc_messages);
226 opt.lc_messages = xtrystrdup (value);
227 if (!opt.lc_messages)
228 err = gpg_error_from_syserror ();
230 else if (!strcmp (key, "xauthority"))
232 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
234 else if (!strcmp (key, "pinentry-user-data"))
236 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
238 else if (!strcmp (key, "include-certs"))
240 int i = *value? atoi (value) : -1;
241 if (ctrl->include_certs < -2)
242 err = gpg_error (GPG_ERR_ASS_PARAMETER);
244 ctrl->include_certs = i;
246 else if (!strcmp (key, "list-mode"))
248 int i = *value? atoi (value) : 0;
249 if (!i || i == 1) /* default and mode 1 */
251 ctrl->server_local->list_internal = 1;
252 ctrl->server_local->list_external = 0;
256 ctrl->server_local->list_internal = 0;
257 ctrl->server_local->list_external = 1;
261 ctrl->server_local->list_internal = 1;
262 ctrl->server_local->list_external = 1;
265 err = gpg_error (GPG_ERR_ASS_PARAMETER);
267 else if (!strcmp (key, "list-to-output"))
269 int i = *value? atoi (value) : 0;
270 ctrl->server_local->list_to_output = i;
272 else if (!strcmp (key, "with-validation"))
274 int i = *value? atoi (value) : 0;
275 ctrl->with_validation = i;
277 else if (!strcmp (key, "with-secret"))
279 int i = *value? atoi (value) : 0;
280 ctrl->with_secret = i;
282 else if (!strcmp (key, "validation-model"))
284 int i = gpgsm_parse_validation_model (value);
285 if ( i >= 0 && i <= 2 )
286 ctrl->validation_model = i;
288 err = gpg_error (GPG_ERR_ASS_PARAMETER);
290 else if (!strcmp (key, "with-key-data"))
292 opt.with_key_data = 1;
294 else if (!strcmp (key, "enable-audit-log"))
296 int i = *value? atoi (value) : 0;
297 ctrl->server_local->enable_audit_log = i;
299 else if (!strcmp (key, "allow-pinentry-notify"))
301 ctrl->server_local->allow_pinentry_notify = 1;
303 else if (!strcmp (key, "with-ephemeral-keys"))
305 int i = *value? atoi (value) : 0;
306 ctrl->with_ephemeral_keys = i;
308 else if (!strcmp (key, "no-encrypt-to"))
310 ctrl->server_local->no_encrypt_to = 1;
312 else if (!strcmp (key, "offline"))
314 /* We ignore this option if gpgsm has been started with
315 --disable-dirmngr (which also sets offline). */
316 if (!opt.disable_dirmngr)
318 int i = *value? !!atoi (value) : 1;
323 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
330 reset_notify (assuan_context_t ctx, char *line)
332 ctrl_t ctrl = assuan_get_pointer (ctx);
336 gpgsm_release_certlist (ctrl->server_local->recplist);
337 gpgsm_release_certlist (ctrl->server_local->signerlist);
338 ctrl->server_local->recplist = NULL;
339 ctrl->server_local->signerlist = NULL;
340 close_message_fd (ctrl);
341 assuan_close_input_fd (ctx);
342 assuan_close_output_fd (ctx);
348 input_notify (assuan_context_t ctx, char *line)
350 ctrl_t ctrl = assuan_get_pointer (ctx);
352 ctrl->autodetect_encoding = 0;
355 if (strstr (line, "--armor"))
357 else if (strstr (line, "--base64"))
359 else if (strstr (line, "--binary"))
362 ctrl->autodetect_encoding = 1;
367 output_notify (assuan_context_t ctx, char *line)
369 ctrl_t ctrl = assuan_get_pointer (ctx);
371 ctrl->create_pem = 0;
372 ctrl->create_base64 = 0;
373 if (strstr (line, "--armor"))
374 ctrl->create_pem = 1;
375 else if (strstr (line, "--base64"))
376 ctrl->create_base64 = 1; /* just the raw output */
381 static const char hlp_recipient[] =
382 "RECIPIENT <userID>\n"
384 "Set the recipient for the encryption. USERID shall be the\n"
385 "internal representation of the key; the server may accept any other\n"
386 "way of specification [we will support this]. If this is a valid and\n"
387 "trusted recipient the server does respond with OK, otherwise the\n"
388 "return is an ERR with the reason why the recipient can't be used,\n"
389 "the encryption will then not be done for this recipient. If the\n"
390 "policy is not to encrypt at all if not all recipients are valid, the\n"
391 "client has to take care of this. All RECIPIENT commands are\n"
392 "cumulative until a RESET or an successful ENCRYPT command.";
394 cmd_recipient (assuan_context_t ctx, char *line)
396 ctrl_t ctrl = assuan_get_pointer (ctx);
400 rc = start_audit_session (ctrl);
405 rc = gpgsm_add_to_certlist (ctrl, line, 0,
406 &ctrl->server_local->recplist, 0);
409 gpgsm_status2 (ctrl, STATUS_INV_RECP,
410 get_inv_recpsgnr_code (rc), line, NULL);
417 static const char hlp_signer[] =
420 "Set the signer's keys for the signature creation. USERID should\n"
421 "be the internal representation of the key; the server may accept any\n"
422 "other way of specification [we will support this]. If this is a\n"
423 "valid and usable signing key the server does respond with OK,\n"
424 "otherwise it returns an ERR with the reason why the key can't be\n"
425 "used, the signing will then not be done for this key. If the policy\n"
426 "is not to sign at all if not all signer keys are valid, the client\n"
427 "has to take care of this. All SIGNER commands are cumulative until\n"
428 "a RESET but they are *not* reset by an SIGN command becuase it can\n"
429 "be expected that set of signers are used for more than one sign\n"
432 cmd_signer (assuan_context_t ctx, char *line)
434 ctrl_t ctrl = assuan_get_pointer (ctx);
437 rc = gpgsm_add_to_certlist (ctrl, line, 1,
438 &ctrl->server_local->signerlist, 0);
441 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
442 get_inv_recpsgnr_code (rc), line, NULL);
443 /* For compatibiliy reasons we also issue the old code after the
445 gpgsm_status2 (ctrl, STATUS_INV_RECP,
446 get_inv_recpsgnr_code (rc), line, NULL);
452 static const char hlp_encrypt[] =
455 "Do the actual encryption process. Takes the plaintext from the INPUT\n"
456 "command, writes to the ciphertext to the file descriptor set with\n"
457 "the OUTPUT command, take the recipients form all the recipients set\n"
458 "so far. If this command fails the clients should try to delete all\n"
459 "output currently done or otherwise mark it as invalid. GPGSM does\n"
460 "ensure that there won't be any security problem with leftover data\n"
461 "on the output in this case.\n"
463 "This command should in general not fail, as all necessary checks\n"
464 "have been done while setting the recipients. The input and output\n"
467 cmd_encrypt (assuan_context_t ctx, char *line)
469 ctrl_t ctrl = assuan_get_pointer (ctx);
477 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
479 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
480 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
482 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
484 out_fp = es_fdopen_nc (out_fd, "w");
486 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
488 /* Now add all encrypt-to marked recipients from the default
491 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
493 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
494 if (cl->is_encrypt_to)
495 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
496 &ctrl->server_local->recplist, 1);
499 rc = ctrl->audit? 0 : start_audit_session (ctrl);
501 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
502 ctrl->server_local->recplist,
506 gpgsm_release_certlist (ctrl->server_local->recplist);
507 ctrl->server_local->recplist = NULL;
508 /* Close and reset the fd */
509 close_message_fd (ctrl);
510 assuan_close_input_fd (ctx);
511 assuan_close_output_fd (ctx);
516 static const char hlp_decrypt[] =
519 "This performs the decrypt operation after doing some check on the\n"
520 "internal state. (e.g. that only needed data has been set). Because\n"
521 "it utilizes the GPG-Agent for the session key decryption, there is\n"
522 "no need to ask the client for a protecting passphrase - GPG-Agent\n"
523 "does take care of this by requesting this from the user.";
525 cmd_decrypt (assuan_context_t ctx, char *line)
527 ctrl_t ctrl = assuan_get_pointer (ctx);
534 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
536 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
537 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
539 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
541 out_fp = es_fdopen_nc (out_fd, "w");
543 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
545 rc = start_audit_session (ctrl);
547 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
550 /* Close and reset the fds. */
551 close_message_fd (ctrl);
552 assuan_close_input_fd (ctx);
553 assuan_close_output_fd (ctx);
559 static const char hlp_verify[] =
562 "This does a verify operation on the message send to the input FD.\n"
563 "The result is written out using status lines. If an output FD was\n"
564 "given, the signed text will be written to that.\n"
566 "If the signature is a detached one, the server will inquire about\n"
567 "the signed material and the client must provide it.";
569 cmd_verify (assuan_context_t ctx, char *line)
572 ctrl_t ctrl = assuan_get_pointer (ctx);
573 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
574 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
575 estream_t out_fp = NULL;
580 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
584 out_fp = es_fdopen_nc (out_fd, "w");
586 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
589 rc = start_audit_session (ctrl);
591 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
592 ctrl->server_local->message_fd, out_fp);
595 /* Close and reset the fd. */
596 close_message_fd (ctrl);
597 assuan_close_input_fd (ctx);
598 assuan_close_output_fd (ctx);
604 static const char hlp_sign[] =
605 "SIGN [--detached]\n"
607 "Sign the data set with the INPUT command and write it to the sink\n"
608 "set by OUTPUT. With \"--detached\", a detached signature is\n"
609 "created (surprise).";
611 cmd_sign (assuan_context_t ctx, char *line)
613 ctrl_t ctrl = assuan_get_pointer (ctx);
619 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
621 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
622 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
624 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
626 detached = has_option (line, "--detached");
628 out_fp = es_fdopen_nc (out_fd, "w");
630 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
632 rc = start_audit_session (ctrl);
634 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
635 inp_fd, detached, out_fp);
638 /* close and reset the fd */
639 close_message_fd (ctrl);
640 assuan_close_input_fd (ctx);
641 assuan_close_output_fd (ctx);
647 static const char hlp_import[] =
648 "IMPORT [--re-import]\n"
650 "Import the certificates read form the input-fd, return status\n"
651 "message for each imported one. The import checks the validity of\n"
652 "the certificate but not of the entire chain. It is possible to\n"
653 "import expired certificates.\n"
655 "With the option --re-import the input data is expected to a be a LF\n"
656 "separated list of fingerprints. The command will re-import these\n"
657 "certificates, meaning that they are made permanent by removing\n"
658 "their ephemeral flag.";
660 cmd_import (assuan_context_t ctx, char *line)
662 ctrl_t ctrl = assuan_get_pointer (ctx);
664 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
665 int reimport = has_option (line, "--re-import");
670 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
672 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
674 /* close and reset the fd */
675 close_message_fd (ctrl);
676 assuan_close_input_fd (ctx);
677 assuan_close_output_fd (ctx);
683 static const char hlp_export[] =
684 "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
686 "Export the certificates selected by PATTERN. With --data the output\n"
687 "is returned using Assuan D lines; the default is to use the sink given\n"
688 "by the last \"OUTPUT\" command. The options --armor or --base64 encode \n"
689 "the output using the PEM respective a plain base-64 format; the default\n"
690 "is a binary format which is only suitable for a single certificate.\n"
691 "With --secret the secret key is exported using the PKCS#8 format,\n"
692 "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
694 cmd_export (assuan_context_t ctx, char *line)
696 ctrl_t ctrl = assuan_get_pointer (ctx);
704 use_data = has_option (line, "--data");
707 /* We need to override any possible setting done by an OUTPUT command. */
708 ctrl->create_pem = has_option (line, "--armor");
709 ctrl->create_base64 = has_option (line, "--base64");
711 opt_secret = has_option (line, "--secret");
714 opt_raw = has_option (line, "--raw");
715 opt_pkcs12 = has_option (line, "--pkcs12");
718 line = skip_options (line);
720 /* Break the line down into an strlist_t. */
722 for (p=line; *p; line = p)
724 while (*p && *p != ' ')
730 sl = xtrymalloc (sizeof *sl + strlen (line));
734 return out_of_core ();
737 strcpy_escaped_plus (sl->d, line);
745 if (!list || !*list->d)
746 return set_error (GPG_ERR_NO_DATA, "No key given");
748 return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
755 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
759 return set_error (GPG_ERR_ASS_GENERAL,
760 "error setting up a data stream");
763 gpgsm_p12_export (ctrl, list->d, stream,
764 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
766 gpgsm_export (ctrl, list, stream);
771 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
777 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
779 out_fp = es_fdopen_nc (fd, "w");
783 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
787 gpgsm_p12_export (ctrl, list->d, out_fp,
788 opt_raw? 2 : opt_pkcs12 ? 0 : 1);
790 gpgsm_export (ctrl, list, out_fp);
795 /* Close and reset the fds. */
796 close_message_fd (ctrl);
797 assuan_close_input_fd (ctx);
798 assuan_close_output_fd (ctx);
804 static const char hlp_delkeys[] =
805 "DELKEYS <patterns>\n"
807 "Delete the certificates specified by PATTERNS. Each pattern shall be\n"
808 "a percent-plus escaped certificate specification. Usually a\n"
809 "fingerprint will be used for this.";
811 cmd_delkeys (assuan_context_t ctx, char *line)
813 ctrl_t ctrl = assuan_get_pointer (ctx);
818 /* break the line down into an strlist_t */
820 for (p=line; *p; line = p)
822 while (*p && *p != ' ')
828 sl = xtrymalloc (sizeof *sl + strlen (line));
832 return out_of_core ();
835 strcpy_escaped_plus (sl->d, line);
841 rc = gpgsm_delete (ctrl, list);
844 /* close and reset the fd */
845 close_message_fd (ctrl);
846 assuan_close_input_fd (ctx);
847 assuan_close_output_fd (ctx);
854 static const char hlp_output[] =
857 "Set the file descriptor to write the output data to N. If N is not\n"
858 "given and the operating system supports file descriptor passing, the\n"
859 "file descriptor currently in flight will be used. See also the\n"
860 "\"INPUT\" and \"MESSAGE\" commands.";
861 static const char hlp_input[] =
864 "Set the file descriptor to read the input data to N. If N is not\n"
865 "given and the operating system supports file descriptor passing, the\n"
866 "file descriptor currently in flight will be used. See also the\n"
867 "\"MESSAGE\" and \"OUTPUT\" commands.";
868 static const char hlp_message[] =
871 "Set the file descriptor to read the message for a detached\n"
872 "signatures to N. If N is not given and the operating system\n"
873 "supports file descriptor passing, the file descriptor currently in\n"
874 "flight will be used. See also the \"INPUT\" and \"OUTPUT\" commands.";
876 cmd_message (assuan_context_t ctx, char *line)
881 ctrl_t ctrl = assuan_get_pointer (ctx);
883 rc = assuan_command_parse_fd (ctx, line, &sysfd);
887 #ifdef HAVE_W32CE_SYSTEM
888 sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0);
889 if (sysfd == INVALID_HANDLE_VALUE)
890 return set_error (gpg_err_code_from_syserror (),
891 "rvid conversion failed");
894 fd = translate_sys2libc_fd (sysfd, 0);
896 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
897 ctrl->server_local->message_fd = fd;
903 static const char hlp_listkeys[] =
904 "LISTKEYS [<patterns>]\n"
905 "LISTSECRETKEYS [<patterns>]\n"
906 "DUMPKEYS [<patterns>]\n"
907 "DUMPSECRETKEYS [<patterns>]\n"
909 "List all certificates or only those specified by PATTERNS. Each\n"
910 "pattern shall be a percent-plus escaped certificate specification.\n"
911 "The \"SECRET\" versions of the command filter the output to include\n"
912 "only certificates where the secret key is available or a corresponding\n"
913 "smartcard has been registered. The \"DUMP\" versions of the command\n"
914 "are only useful for debugging. The output format is a percent escaped\n"
915 "colon delimited listing as described in the manual.\n"
917 "These \"OPTION\" command keys effect the output::\n"
919 " \"list-mode\" set to 0: List only local certificates (default).\n"
921 " 2: List only external certificates.\n"
922 " 3: List local and external certificates.\n"
924 " \"with-validation\" set to true: Validate each certificate.\n"
926 " \"with-ephemeral-key\" set to true: Always include ephemeral\n"
929 " \"list-to-output\" set to true: Write output to the file descriptor\n"
930 " given by the last \"OUTPUT\" command.";
932 do_listkeys (assuan_context_t ctx, char *line, int mode)
934 ctrl_t ctrl = assuan_get_pointer (ctx);
938 unsigned int listmode;
941 /* Break the line down into an strlist. */
943 for (p=line; *p; line = p)
945 while (*p && *p != ' ')
951 sl = xtrymalloc (sizeof *sl + strlen (line));
955 return out_of_core ();
958 strcpy_escaped_plus (sl->d, line);
964 if (ctrl->server_local->list_to_output)
966 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
969 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
970 fp = es_fdopen_nc (outfd, "w");
972 return set_error (gpg_err_code_from_syserror (), "es_fdopen() failed");
976 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
978 return set_error (GPG_ERR_ASS_GENERAL,
979 "error setting up a data stream");
982 ctrl->with_colons = 1;
984 if (ctrl->server_local->list_internal)
986 if (ctrl->server_local->list_external)
988 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
991 if (ctrl->server_local->list_to_output)
992 assuan_close_output_fd (ctx);
997 cmd_listkeys (assuan_context_t ctx, char *line)
999 return do_listkeys (ctx, line, 3);
1003 cmd_dumpkeys (assuan_context_t ctx, char *line)
1005 return do_listkeys (ctx, line, 259);
1009 cmd_listsecretkeys (assuan_context_t ctx, char *line)
1011 return do_listkeys (ctx, line, 2);
1015 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
1017 return do_listkeys (ctx, line, 258);
1022 static const char hlp_genkey[] =
1025 "Read the parameters in native format from the input fd and write a\n"
1026 "certificate request to the output.";
1028 cmd_genkey (assuan_context_t ctx, char *line)
1030 ctrl_t ctrl = assuan_get_pointer (ctx);
1032 estream_t in_stream, out_stream;
1037 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
1039 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
1040 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1042 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1044 in_stream = es_fdopen_nc (inp_fd, "r");
1046 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
1048 out_stream = es_fdopen_nc (out_fd, "w");
1051 es_fclose (in_stream);
1052 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
1054 rc = gpgsm_genkey (ctrl, in_stream, out_stream);
1055 es_fclose (out_stream);
1056 es_fclose (in_stream);
1058 /* close and reset the fds */
1059 assuan_close_input_fd (ctx);
1060 assuan_close_output_fd (ctx);
1067 static const char hlp_getauditlog[] =
1068 "GETAUDITLOG [--data] [--html]\n"
1070 "If --data is used, the output is send using D-lines and not to the\n"
1071 "file descriptor given by an OUTPUT command.\n"
1073 "If --html is used the output is formated as an XHTML block. This is\n"
1074 "designed to be incorporated into a HTML document.";
1076 cmd_getauditlog (assuan_context_t ctx, char *line)
1078 ctrl_t ctrl = assuan_get_pointer (ctx);
1080 estream_t out_stream;
1081 int opt_data, opt_html;
1084 opt_data = has_option (line, "--data");
1085 opt_html = has_option (line, "--html");
1086 line = skip_options (line);
1089 return gpg_error (GPG_ERR_NO_DATA);
1093 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1095 return set_error (GPG_ERR_ASS_GENERAL,
1096 "error setting up a data stream");
1100 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1102 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1104 out_stream = es_fdopen_nc (out_fd, "w");
1107 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1111 audit_print_result (ctrl->audit, out_stream, opt_html);
1114 es_fclose (out_stream);
1116 /* Close and reset the fd. */
1118 assuan_close_output_fd (ctx);
1122 static const char hlp_getinfo[] =
1125 "Multipurpose function to return a variety of information.\n"
1126 "Supported values for WHAT are:\n"
1128 " version - Return the version of the program.\n"
1129 " pid - Return the process id of the server.\n"
1130 " agent-check - Return success if the agent is running.\n"
1131 " cmd_has_option CMD OPT\n"
1132 " - Returns OK if the command CMD implements the option OPT.\n"
1133 " offline - Returns OK if the conenction is in offline mode.";
1135 cmd_getinfo (assuan_context_t ctx, char *line)
1137 ctrl_t ctrl = assuan_get_pointer (ctx);
1140 if (!strcmp (line, "version"))
1142 const char *s = VERSION;
1143 rc = assuan_send_data (ctx, s, strlen (s));
1145 else if (!strcmp (line, "pid"))
1149 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1150 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1152 else if (!strcmp (line, "agent-check"))
1154 rc = gpgsm_agent_send_nop (ctrl);
1156 else if (!strncmp (line, "cmd_has_option", 14)
1157 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1161 while (*line == ' ' || *line == '\t')
1164 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1168 while (*line && (*line != ' ' && *line != '\t'))
1171 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1175 while (*line == ' ' || *line == '\t')
1178 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1182 if (!command_has_option (cmd, cmdopt))
1183 rc = gpg_error (GPG_ERR_GENERAL);
1188 else if (!strcmp (line, "offline"))
1190 rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL);
1193 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1199 static const char hlp_passwd[] =
1202 "Change the passphrase of the secret key for USERID.";
1204 cmd_passwd (assuan_context_t ctx, char *line)
1206 ctrl_t ctrl = assuan_get_pointer (ctx);
1208 ksba_cert_t cert = NULL;
1211 line = skip_options (line);
1213 err = gpgsm_find_cert (line, NULL, &cert);
1216 else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
1217 err = gpg_error (GPG_ERR_INTERNAL);
1220 char *desc = gpgsm_format_keydesc (cert);
1221 err = gpgsm_agent_passwd (ctrl, grip, desc);
1226 ksba_cert_release (cert);
1233 /* Return true if the command CMD implements the option OPT. */
1235 command_has_option (const char *cmd, const char *cmdopt)
1237 if (!strcmp (cmd, "IMPORT"))
1239 if (!strcmp (cmdopt, "re-import"))
1247 /* Tell the assuan library about our commands */
1249 register_commands (assuan_context_t ctx)
1253 assuan_handler_t handler;
1254 const char * const help;
1256 { "RECIPIENT", cmd_recipient, hlp_recipient },
1257 { "SIGNER", cmd_signer, hlp_signer },
1258 { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1259 { "DECRYPT", cmd_decrypt, hlp_decrypt },
1260 { "VERIFY", cmd_verify, hlp_verify },
1261 { "SIGN", cmd_sign, hlp_sign },
1262 { "IMPORT", cmd_import, hlp_import },
1263 { "EXPORT", cmd_export, hlp_export },
1264 { "INPUT", NULL, hlp_input },
1265 { "OUTPUT", NULL, hlp_output },
1266 { "MESSAGE", cmd_message, hlp_message },
1267 { "LISTKEYS", cmd_listkeys, hlp_listkeys },
1268 { "DUMPKEYS", cmd_dumpkeys, hlp_listkeys },
1269 { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
1270 { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
1271 { "GENKEY", cmd_genkey, hlp_genkey },
1272 { "DELKEYS", cmd_delkeys, hlp_delkeys },
1273 { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
1274 { "GETINFO", cmd_getinfo, hlp_getinfo },
1275 { "PASSWD", cmd_passwd, hlp_passwd },
1280 for (i=0; table[i].name; i++)
1282 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1290 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1291 set from the command line or config file. We only require those
1292 marked as encrypt-to. */
1294 gpgsm_server (certlist_t default_recplist)
1297 assuan_fd_t filedes[2];
1298 assuan_context_t ctx;
1299 struct server_control_s ctrl;
1300 static const char hello[] = ("GNU Privacy Guard's S/M server "
1303 memset (&ctrl, 0, sizeof ctrl);
1304 gpgsm_init_default_ctrl (&ctrl);
1306 /* We use a pipe based server so that we can work from scripts.
1307 assuan_init_pipe_server will automagically detect when we are
1308 called with a socketpair and ignore FILEDES in this case. */
1309 #ifdef HAVE_W32CE_SYSTEM
1310 #define SERVER_STDIN es_fileno(es_stdin)
1311 #define SERVER_STDOUT es_fileno(es_stdout)
1313 #define SERVER_STDIN 0
1314 #define SERVER_STDOUT 1
1316 filedes[0] = assuan_fdopen (SERVER_STDIN);
1317 filedes[1] = assuan_fdopen (SERVER_STDOUT);
1318 rc = assuan_new (&ctx);
1321 log_error ("failed to allocate assuan context: %s\n",
1326 rc = assuan_init_pipe_server (ctx, filedes);
1329 log_error ("failed to initialize the server: %s\n",
1333 rc = register_commands (ctx);
1336 log_error ("failed to the register commands with Assuan: %s\n",
1340 if (opt.verbose || opt.debug)
1344 /* Fixme: Use the really used socket name. */
1351 opt.config_filename,
1352 (dirmngr_user_socket_name ()
1353 ? dirmngr_user_socket_name ()
1354 : dirmngr_sys_socket_name ()),
1357 assuan_set_hello_line (ctx, tmp);
1362 assuan_set_hello_line (ctx, hello);
1364 assuan_register_reset_notify (ctx, reset_notify);
1365 assuan_register_input_notify (ctx, input_notify);
1366 assuan_register_output_notify (ctx, output_notify);
1367 assuan_register_option_handler (ctx, option_handler);
1369 assuan_set_pointer (ctx, &ctrl);
1370 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1371 ctrl.server_local->assuan_ctx = ctx;
1372 ctrl.server_local->message_fd = -1;
1373 ctrl.server_local->list_internal = 1;
1374 ctrl.server_local->list_external = 0;
1375 ctrl.server_local->default_recplist = default_recplist;
1379 rc = assuan_accept (ctx);
1386 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1390 rc = assuan_process (ctx);
1393 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1398 gpgsm_release_certlist (ctrl.server_local->recplist);
1399 ctrl.server_local->recplist = NULL;
1400 gpgsm_release_certlist (ctrl.server_local->signerlist);
1401 ctrl.server_local->signerlist = NULL;
1402 xfree (ctrl.server_local);
1404 audit_release (ctrl.audit);
1407 assuan_release (ctx);
1413 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1415 gpg_error_t err = 0;
1419 va_start (arg_ptr, no);
1421 if (ctrl->no_server && ctrl->status_fd == -1)
1422 ; /* No status wanted. */
1423 else if (ctrl->no_server)
1427 if (ctrl->status_fd == 1)
1429 else if (ctrl->status_fd == 2)
1432 statusfp = fdopen (ctrl->status_fd, "w");
1436 log_fatal ("can't open fd %d for status output: %s\n",
1437 ctrl->status_fd, strerror(errno));
1441 fputs ("[GNUPG:] ", statusfp);
1442 fputs (get_status_string (no), statusfp);
1444 while ( (text = va_arg (arg_ptr, const char*) ))
1446 putc ( ' ', statusfp );
1447 for (; *text; text++)
1450 fputs ( "\\n", statusfp );
1451 else if (*text == '\r')
1452 fputs ( "\\r", statusfp );
1454 putc ( *(const byte *)text, statusfp );
1457 putc ('\n', statusfp);
1462 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1468 while ( (text = va_arg (arg_ptr, const char *)) )
1475 for ( ; *text && n < DIM (buf)-2; n++)
1479 err = assuan_write_status (ctx, get_status_string (no), buf);
1487 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1489 return gpgsm_status2 (ctrl, no, text, NULL);
1493 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1498 sprintf (buf, "%u", (unsigned int)ec);
1500 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1502 return gpgsm_status2 (ctrl, no, buf, NULL);
1506 /* Helper to notify the client about Pinentry events. Because that
1507 might disturb some older clients, this is only done when enabled
1508 via an option. Returns an gpg error code. */
1510 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1512 if (!ctrl || !ctrl->server_local
1513 || !ctrl->server_local->allow_pinentry_notify)
1515 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);