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))
147 data_line_cookie_close (void *cookie)
149 assuan_context_t ctx = cookie;
151 if (assuan_send_data (ctx, NULL, 0))
162 close_message_fd (ctrl_t ctrl)
164 if (ctrl->server_local->message_fd != -1)
166 close (ctrl->server_local->message_fd);
167 ctrl->server_local->message_fd = -1;
172 /* Start a new audit session if this has been enabled. */
174 start_audit_session (ctrl_t ctrl)
176 audit_release (ctrl->audit);
178 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
179 return gpg_error_from_syserror ();
186 option_handler (assuan_context_t ctx, const char *key, const char *value)
188 ctrl_t ctrl = assuan_get_pointer (ctx);
191 if (!strcmp (key, "putenv"))
193 /* Change the session's environment to be used for the
194 Pinentry. Valid values are:
195 <NAME> Delete envvar NAME
196 <KEY>= Set envvar NAME to the empty string
197 <KEY>=<VALUE> Set envvar NAME to VALUE
199 err = session_env_putenv (opt.session_env, value);
201 else if (!strcmp (key, "display"))
203 err = session_env_setenv (opt.session_env, "DISPLAY", value);
205 else if (!strcmp (key, "ttyname"))
207 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
209 else if (!strcmp (key, "ttytype"))
211 err = session_env_setenv (opt.session_env, "TERM", value);
213 else if (!strcmp (key, "lc-ctype"))
215 xfree (opt.lc_ctype);
216 opt.lc_ctype = xtrystrdup (value);
218 err = gpg_error_from_syserror ();
220 else if (!strcmp (key, "lc-messages"))
222 xfree (opt.lc_messages);
223 opt.lc_messages = xtrystrdup (value);
224 if (!opt.lc_messages)
225 err = gpg_error_from_syserror ();
227 else if (!strcmp (key, "xauthority"))
229 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
231 else if (!strcmp (key, "pinentry-user-data"))
233 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
235 else if (!strcmp (key, "include-certs"))
237 int i = *value? atoi (value) : -1;
238 if (ctrl->include_certs < -2)
239 err = gpg_error (GPG_ERR_ASS_PARAMETER);
241 ctrl->include_certs = i;
243 else if (!strcmp (key, "list-mode"))
245 int i = *value? atoi (value) : 0;
246 if (!i || i == 1) /* default and mode 1 */
248 ctrl->server_local->list_internal = 1;
249 ctrl->server_local->list_external = 0;
253 ctrl->server_local->list_internal = 0;
254 ctrl->server_local->list_external = 1;
258 ctrl->server_local->list_internal = 1;
259 ctrl->server_local->list_external = 1;
262 err = gpg_error (GPG_ERR_ASS_PARAMETER);
264 else if (!strcmp (key, "list-to-output"))
266 int i = *value? atoi (value) : 0;
267 ctrl->server_local->list_to_output = i;
269 else if (!strcmp (key, "with-validation"))
271 int i = *value? atoi (value) : 0;
272 ctrl->with_validation = i;
274 else if (!strcmp (key, "validation-model"))
276 int i = gpgsm_parse_validation_model (value);
277 if ( i >= 0 && i <= 1 )
278 ctrl->validation_model = i;
280 err = gpg_error (GPG_ERR_ASS_PARAMETER);
282 else if (!strcmp (key, "with-key-data"))
284 opt.with_key_data = 1;
286 else if (!strcmp (key, "enable-audit-log"))
288 int i = *value? atoi (value) : 0;
289 ctrl->server_local->enable_audit_log = i;
291 else if (!strcmp (key, "allow-pinentry-notify"))
293 ctrl->server_local->allow_pinentry_notify = 1;
295 else if (!strcmp (key, "with-ephemeral-keys"))
297 int i = *value? atoi (value) : 0;
298 ctrl->with_ephemeral_keys = i;
300 else if (!strcmp (key, "no-encrypt-to"))
302 ctrl->server_local->no_encrypt_to = 1;
305 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
312 reset_notify (assuan_context_t ctx, char *line)
314 ctrl_t ctrl = assuan_get_pointer (ctx);
318 gpgsm_release_certlist (ctrl->server_local->recplist);
319 gpgsm_release_certlist (ctrl->server_local->signerlist);
320 ctrl->server_local->recplist = NULL;
321 ctrl->server_local->signerlist = NULL;
322 close_message_fd (ctrl);
323 assuan_close_input_fd (ctx);
324 assuan_close_output_fd (ctx);
330 input_notify (assuan_context_t ctx, char *line)
332 ctrl_t ctrl = assuan_get_pointer (ctx);
334 ctrl->autodetect_encoding = 0;
337 if (strstr (line, "--armor"))
339 else if (strstr (line, "--base64"))
341 else if (strstr (line, "--binary"))
344 ctrl->autodetect_encoding = 1;
349 output_notify (assuan_context_t ctx, char *line)
351 ctrl_t ctrl = assuan_get_pointer (ctx);
353 ctrl->create_pem = 0;
354 ctrl->create_base64 = 0;
355 if (strstr (line, "--armor"))
356 ctrl->create_pem = 1;
357 else if (strstr (line, "--base64"))
358 ctrl->create_base64 = 1; /* just the raw output */
363 static const char hlp_recipient[] =
364 "RECIPIENT <userID>\n"
366 "Set the recipient for the encryption. USERID shall be the\n"
367 "internal representation of the key; the server may accept any other\n"
368 "way of specification [we will support this]. If this is a valid and\n"
369 "trusted recipient the server does respond with OK, otherwise the\n"
370 "return is an ERR with the reason why the recipient can't be used,\n"
371 "the encryption will then not be done for this recipient. If the\n"
372 "policy is not to encrypt at all if not all recipients are valid, the\n"
373 "client has to take care of this. All RECIPIENT commands are\n"
374 "cumulative until a RESET or an successful ENCRYPT command.";
376 cmd_recipient (assuan_context_t ctx, char *line)
378 ctrl_t ctrl = assuan_get_pointer (ctx);
382 rc = start_audit_session (ctrl);
387 rc = gpgsm_add_to_certlist (ctrl, line, 0,
388 &ctrl->server_local->recplist, 0);
391 gpgsm_status2 (ctrl, STATUS_INV_RECP,
392 get_inv_recpsgnr_code (rc), line, NULL);
399 static const char hlp_signer[] =
402 "Set the signer's keys for the signature creation. USERID should\n"
403 "be the internal representation of the key; the server may accept any\n"
404 "other way of specification [we will support this]. If this is a\n"
405 "valid and usable signing key the server does respond with OK,\n"
406 "otherwise it returns an ERR with the reason why the key can't be\n"
407 "used, the signing will then not be done for this key. If the policy\n"
408 "is not to sign at all if not all signer keys are valid, the client\n"
409 "has to take care of this. All SIGNER commands are cumulative until\n"
410 "a RESET but they are *not* reset by an SIGN command becuase it can\n"
411 "be expected that set of signers are used for more than one sign\n"
414 cmd_signer (assuan_context_t ctx, char *line)
416 ctrl_t ctrl = assuan_get_pointer (ctx);
419 rc = gpgsm_add_to_certlist (ctrl, line, 1,
420 &ctrl->server_local->signerlist, 0);
423 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
424 get_inv_recpsgnr_code (rc), line, NULL);
425 /* For compatibiliy reasons we also issue the old code after the
427 gpgsm_status2 (ctrl, STATUS_INV_RECP,
428 get_inv_recpsgnr_code (rc), line, NULL);
434 static const char hlp_encrypt[] =
437 "Do the actual encryption process. Takes the plaintext from the INPUT\n"
438 "command, writes to the ciphertext to the file descriptor set with\n"
439 "the OUTPUT command, take the recipients form all the recipients set\n"
440 "so far. If this command fails the clients should try to delete all\n"
441 "output currently done or otherwise mark it as invalid. GPGSM does\n"
442 "ensure that there won't be any security problem with leftover data\n"
443 "on the output in this case.\n"
445 "This command should in general not fail, as all necessary checks\n"
446 "have been done while setting the recipients. The input and output\n"
449 cmd_encrypt (assuan_context_t ctx, char *line)
451 ctrl_t ctrl = assuan_get_pointer (ctx);
459 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
461 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
462 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
464 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
466 out_fp = es_fdopen_nc (out_fd, "w");
468 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
470 /* Now add all encrypt-to marked recipients from the default
473 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
475 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
476 if (cl->is_encrypt_to)
477 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
478 &ctrl->server_local->recplist, 1);
481 rc = ctrl->audit? 0 : start_audit_session (ctrl);
483 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
484 ctrl->server_local->recplist,
488 gpgsm_release_certlist (ctrl->server_local->recplist);
489 ctrl->server_local->recplist = NULL;
490 /* Close and reset the fd */
491 close_message_fd (ctrl);
492 assuan_close_input_fd (ctx);
493 assuan_close_output_fd (ctx);
498 static const char hlp_decrypt[] =
501 "This performs the decrypt operation after doing some check on the\n"
502 "internal state. (e.g. that only needed data has been set). Because\n"
503 "it utilizes the GPG-Agent for the session key decryption, there is\n"
504 "no need to ask the client for a protecting passphrase - GPG-Agent\n"
505 "does take care of this by requesting this from the user.";
507 cmd_decrypt (assuan_context_t ctx, char *line)
509 ctrl_t ctrl = assuan_get_pointer (ctx);
516 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
518 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
519 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
521 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
523 out_fp = es_fdopen_nc (out_fd, "w");
525 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
527 rc = start_audit_session (ctrl);
529 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
532 /* Close and reset the fds. */
533 close_message_fd (ctrl);
534 assuan_close_input_fd (ctx);
535 assuan_close_output_fd (ctx);
541 static const char hlp_verify[] =
544 "This does a verify operation on the message send to the input FD.\n"
545 "The result is written out using status lines. If an output FD was\n"
546 "given, the signed text will be written to that.\n"
548 "If the signature is a detached one, the server will inquire about\n"
549 "the signed material and the client must provide it.";
551 cmd_verify (assuan_context_t ctx, char *line)
554 ctrl_t ctrl = assuan_get_pointer (ctx);
555 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
556 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
557 estream_t out_fp = NULL;
562 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
566 out_fp = es_fdopen_nc (out_fd, "w");
568 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
571 rc = start_audit_session (ctrl);
573 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
574 ctrl->server_local->message_fd, out_fp);
577 /* Close and reset the fd. */
578 close_message_fd (ctrl);
579 assuan_close_input_fd (ctx);
580 assuan_close_output_fd (ctx);
586 static const char hlp_sign[] =
587 "SIGN [--detached]\n"
589 "Sign the data set with the INPUT command and write it to the sink\n"
590 "set by OUTPUT. With \"--detached\", a detached signature is\n"
591 "created (surprise).";
593 cmd_sign (assuan_context_t ctx, char *line)
595 ctrl_t ctrl = assuan_get_pointer (ctx);
601 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
603 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
604 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
606 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
608 detached = has_option (line, "--detached");
610 out_fp = es_fdopen_nc (out_fd, "w");
612 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
614 rc = start_audit_session (ctrl);
616 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
617 inp_fd, detached, out_fp);
620 /* close and reset the fd */
621 close_message_fd (ctrl);
622 assuan_close_input_fd (ctx);
623 assuan_close_output_fd (ctx);
629 static const char hlp_import[] =
630 "IMPORT [--re-import]\n"
632 "Import the certificates read form the input-fd, return status\n"
633 "message for each imported one. The import checks the validity of\n"
634 "the certificate but not of the entire chain. It is possible to\n"
635 "import expired certificates.\n"
637 "With the option --re-import the input data is expected to a be a LF\n"
638 "separated list of fingerprints. The command will re-import these\n"
639 "certificates, meaning that they are made permanent by removing\n"
640 "their ephemeral flag.";
642 cmd_import (assuan_context_t ctx, char *line)
644 ctrl_t ctrl = assuan_get_pointer (ctx);
646 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
647 int reimport = has_option (line, "--re-import");
652 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
654 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
656 /* close and reset the fd */
657 close_message_fd (ctrl);
658 assuan_close_input_fd (ctx);
659 assuan_close_output_fd (ctx);
665 static const char hlp_export[] =
666 "EXPORT [--data [--armor|--base64]] [--] <pattern>\n"
668 "Export the certificates selected by PATTERN. With --data the output\n"
669 "is returned using Assuan D lines; the default is to use the sink given\n"
670 "by the last \"OUTPUT\" command. The options --armor or --base64 encode \n"
671 "the output using the PEM respective a plain base-64 format; the default\n"
672 "is a binary format which is only suitable for a single certificate.";
674 cmd_export (assuan_context_t ctx, char *line)
676 ctrl_t ctrl = assuan_get_pointer (ctx);
681 use_data = has_option (line, "--data");
685 /* We need to override any possible setting done by an OUTPUT command. */
686 ctrl->create_pem = has_option (line, "--armor");
687 ctrl->create_base64 = has_option (line, "--base64");
690 line = skip_options (line);
692 /* Break the line down into an strlist_t. */
694 for (p=line; *p; line = p)
696 while (*p && *p != ' ')
702 sl = xtrymalloc (sizeof *sl + strlen (line));
706 return out_of_core ();
709 strcpy_escaped_plus (sl->d, line);
719 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
723 return set_error (GPG_ERR_ASS_GENERAL,
724 "error setting up a data stream");
726 gpgsm_export (ctrl, list, stream);
731 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
737 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
739 out_fp = es_fdopen_nc (fd, "w");
743 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
746 gpgsm_export (ctrl, list, out_fp);
751 /* Close and reset the fds. */
752 close_message_fd (ctrl);
753 assuan_close_input_fd (ctx);
754 assuan_close_output_fd (ctx);
760 static const char hlp_delkeys[] =
761 "DELKEYS <patterns>\n"
763 "Delete the certificates specified by PATTERNS. Each pattern shall be\n"
764 "a percent-plus escaped certificate specification. Usually a\n"
765 "fingerprint will be used for this.";
767 cmd_delkeys (assuan_context_t ctx, char *line)
769 ctrl_t ctrl = assuan_get_pointer (ctx);
774 /* break the line down into an strlist_t */
776 for (p=line; *p; line = p)
778 while (*p && *p != ' ')
784 sl = xtrymalloc (sizeof *sl + strlen (line));
788 return out_of_core ();
791 strcpy_escaped_plus (sl->d, line);
797 rc = gpgsm_delete (ctrl, list);
800 /* close and reset the fd */
801 close_message_fd (ctrl);
802 assuan_close_input_fd (ctx);
803 assuan_close_output_fd (ctx);
810 static const char hlp_output[] =
813 "Set the file descriptor to write the output data to N. If N is not\n"
814 "given and the operating system supports file descriptor passing, the\n"
815 "file descriptor currently in flight will be used. See also the\n"
816 "\"INPUT\" and \"MESSAGE\" commands.";
817 static const char hlp_input[] =
820 "Set the file descriptor to read the input data to N. If N is not\n"
821 "given and the operating system supports file descriptor passing, the\n"
822 "file descriptor currently in flight will be used. See also the\n"
823 "\"MESSAGE\" and \"OUTPUT\" commands.";
824 static const char hlp_message[] =
827 "Set the file descriptor to read the message for a detached\n"
828 "signatures to N. If N is not given and the operating system\n"
829 "supports file descriptor passing, the file descriptor currently in\n"
830 "flight will be used. See also the \"INPUT\" and \"OUTPUT\" commands.";
832 cmd_message (assuan_context_t ctx, char *line)
837 ctrl_t ctrl = assuan_get_pointer (ctx);
839 rc = assuan_command_parse_fd (ctx, line, &sysfd);
842 fd = translate_sys2libc_fd (sysfd, 0);
844 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
845 ctrl->server_local->message_fd = fd;
851 static const char hlp_listkeys[] =
852 "LISTKEYS [<patterns>]\n"
853 "LISTSECRETKEYS [<patterns>]\n"
854 "DUMPKEYS [<patterns>]\n"
855 "DUMPSECRETKEYS [<patterns>]\n"
857 "List all certificates or only those specified by PATTERNS. Each\n"
858 "pattern shall be a percent-plus escaped certificate specification.\n"
859 "The \"SECRET\" versions of the command filter the output to include\n"
860 "only certificates where the secret key is available or a corresponding\n"
861 "smartcard has been registered. The \"DUMP\" versions of the command\n"
862 "are only useful for debugging. The output format is a percent escaped\n"
863 "colon delimited listing as described in the manual.\n"
865 "These \"OPTION\" command keys effect the output::\n"
867 " \"list-mode\" set to 0: List only local certificates (default).\n"
869 " 2: List only external certificates.\n"
870 " 3: List local and external certificates.\n"
872 " \"with-validation\" set to true: Validate each certificate.\n"
874 " \"with-ephemeral-key\" set to true: Always include ephemeral\n"
877 " \"list-to-output\" set to true: Write output to the file descriptor\n"
878 " given by the last \"OUTPUT\" command.";
880 do_listkeys (assuan_context_t ctx, char *line, int mode)
882 ctrl_t ctrl = assuan_get_pointer (ctx);
886 unsigned int listmode;
889 /* Break the line down into an strlist. */
891 for (p=line; *p; line = p)
893 while (*p && *p != ' ')
899 sl = xtrymalloc (sizeof *sl + strlen (line));
903 return out_of_core ();
906 strcpy_escaped_plus (sl->d, line);
912 if (ctrl->server_local->list_to_output)
914 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
917 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
918 fp = es_fdopen_nc (outfd, "w");
920 return set_error (gpg_err_code_from_syserror (), "es_fdopen() failed");
924 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
926 return set_error (GPG_ERR_ASS_GENERAL,
927 "error setting up a data stream");
930 ctrl->with_colons = 1;
932 if (ctrl->server_local->list_internal)
934 if (ctrl->server_local->list_external)
936 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
939 if (ctrl->server_local->list_to_output)
940 assuan_close_output_fd (ctx);
945 cmd_listkeys (assuan_context_t ctx, char *line)
947 return do_listkeys (ctx, line, 3);
951 cmd_dumpkeys (assuan_context_t ctx, char *line)
953 return do_listkeys (ctx, line, 259);
957 cmd_listsecretkeys (assuan_context_t ctx, char *line)
959 return do_listkeys (ctx, line, 2);
963 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
965 return do_listkeys (ctx, line, 258);
970 static const char hlp_genkey[] =
973 "Read the parameters in native format from the input fd and write a\n"
974 "certificate request to the output.";
976 cmd_genkey (assuan_context_t ctx, char *line)
978 ctrl_t ctrl = assuan_get_pointer (ctx);
980 estream_t in_stream, out_stream;
985 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
987 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
988 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
990 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
992 in_stream = es_fdopen_nc (inp_fd, "r");
994 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
996 out_stream = es_fdopen_nc (out_fd, "w");
999 es_fclose (in_stream);
1000 return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
1002 rc = gpgsm_genkey (ctrl, in_stream, out_stream);
1003 es_fclose (out_stream);
1004 es_fclose (in_stream);
1006 /* close and reset the fds */
1007 assuan_close_input_fd (ctx);
1008 assuan_close_output_fd (ctx);
1015 static const char hlp_getauditlog[] =
1016 "GETAUDITLOG [--data] [--html]\n"
1018 "If --data is used, the output is send using D-lines and not to the\n"
1019 "file descriptor given by an OUTPUT command.\n"
1021 "If --html is used the output is formated as an XHTML block. This is\n"
1022 "designed to be incorporated into a HTML document.";
1024 cmd_getauditlog (assuan_context_t ctx, char *line)
1026 ctrl_t ctrl = assuan_get_pointer (ctx);
1028 estream_t out_stream;
1029 int opt_data, opt_html;
1032 opt_data = has_option (line, "--data");
1033 opt_html = has_option (line, "--html");
1034 line = skip_options (line);
1037 return gpg_error (GPG_ERR_NO_DATA);
1041 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1043 return set_error (GPG_ERR_ASS_GENERAL,
1044 "error setting up a data stream");
1048 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1050 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1052 out_stream = es_fdopen_nc (out_fd, "w");
1055 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1059 audit_print_result (ctrl->audit, out_stream, opt_html);
1062 es_fclose (out_stream);
1064 /* Close and reset the fd. */
1066 assuan_close_output_fd (ctx);
1070 static const char hlp_getinfo[] =
1073 "Multipurpose function to return a variety of information.\n"
1074 "Supported values for WHAT are:\n"
1076 " version - Return the version of the program.\n"
1077 " pid - Return the process id of the server.\n"
1078 " agent-check - Return success if the agent is running.\n"
1079 " cmd_has_option CMD OPT\n"
1080 " - Returns OK if the command CMD implements the option OPT.";
1082 cmd_getinfo (assuan_context_t ctx, char *line)
1086 if (!strcmp (line, "version"))
1088 const char *s = VERSION;
1089 rc = assuan_send_data (ctx, s, strlen (s));
1091 else if (!strcmp (line, "pid"))
1095 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1096 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1098 else if (!strcmp (line, "agent-check"))
1100 ctrl_t ctrl = assuan_get_pointer (ctx);
1101 rc = gpgsm_agent_send_nop (ctrl);
1103 else if (!strncmp (line, "cmd_has_option", 14)
1104 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1108 while (*line == ' ' || *line == '\t')
1111 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1115 while (*line && (*line != ' ' && *line != '\t'))
1118 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1122 while (*line == ' ' || *line == '\t')
1125 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1129 if (!command_has_option (cmd, cmdopt))
1130 rc = gpg_error (GPG_ERR_GENERAL);
1136 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1142 static const char hlp_passwd[] =
1145 "Change the passphrase of the secret key for USERID.";
1147 cmd_passwd (assuan_context_t ctx, char *line)
1149 ctrl_t ctrl = assuan_get_pointer (ctx);
1151 ksba_cert_t cert = NULL;
1154 line = skip_options (line);
1156 err = gpgsm_find_cert (line, NULL, &cert);
1159 else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
1160 err = gpg_error (GPG_ERR_INTERNAL);
1163 char *desc = gpgsm_format_keydesc (cert);
1164 err = gpgsm_agent_passwd (ctrl, grip, desc);
1169 ksba_cert_release (cert);
1176 /* Return true if the command CMD implements the option OPT. */
1178 command_has_option (const char *cmd, const char *cmdopt)
1180 if (!strcmp (cmd, "IMPORT"))
1182 if (!strcmp (cmdopt, "re-import"))
1190 /* Tell the assuan library about our commands */
1192 register_commands (assuan_context_t ctx)
1196 assuan_handler_t handler;
1197 const char * const help;
1199 { "RECIPIENT", cmd_recipient, hlp_recipient },
1200 { "SIGNER", cmd_signer, hlp_signer },
1201 { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1202 { "DECRYPT", cmd_decrypt, hlp_decrypt },
1203 { "VERIFY", cmd_verify, hlp_verify },
1204 { "SIGN", cmd_sign, hlp_sign },
1205 { "IMPORT", cmd_import, hlp_import },
1206 { "EXPORT", cmd_export, hlp_export },
1207 { "INPUT", NULL, hlp_input },
1208 { "OUTPUT", NULL, hlp_output },
1209 { "MESSAGE", cmd_message, hlp_message },
1210 { "LISTKEYS", cmd_listkeys, hlp_listkeys },
1211 { "DUMPKEYS", cmd_dumpkeys, hlp_listkeys },
1212 { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
1213 { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
1214 { "GENKEY", cmd_genkey, hlp_genkey },
1215 { "DELKEYS", cmd_delkeys, hlp_delkeys },
1216 { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
1217 { "GETINFO", cmd_getinfo, hlp_getinfo },
1218 { "PASSWD", cmd_passwd, hlp_passwd },
1223 for (i=0; table[i].name; i++)
1225 rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1233 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1234 set from the command line or config file. We only require those
1235 marked as encrypt-to. */
1237 gpgsm_server (certlist_t default_recplist)
1240 assuan_fd_t filedes[2];
1241 assuan_context_t ctx;
1242 struct server_control_s ctrl;
1243 static const char hello[] = ("GNU Privacy Guard's S/M server "
1246 memset (&ctrl, 0, sizeof ctrl);
1247 gpgsm_init_default_ctrl (&ctrl);
1249 /* We use a pipe based server so that we can work from scripts.
1250 assuan_init_pipe_server will automagically detect when we are
1251 called with a socketpair and ignore FIELDES in this case. */
1252 filedes[0] = assuan_fdopen (0);
1253 filedes[1] = assuan_fdopen (1);
1254 rc = assuan_new (&ctx);
1257 log_error ("failed to allocate assuan context: %s\n",
1262 rc = assuan_init_pipe_server (ctx, filedes);
1265 log_error ("failed to initialize the server: %s\n",
1269 rc = register_commands (ctx);
1272 log_error ("failed to the register commands with Assuan: %s\n",
1276 if (opt.verbose || opt.debug)
1279 const char *s1 = getenv ("GPG_AGENT_INFO");
1280 const char *s2 = getenv ("DIRMNGR_INFO");
1289 opt.config_filename,
1294 assuan_set_hello_line (ctx, tmp);
1299 assuan_set_hello_line (ctx, hello);
1301 assuan_register_reset_notify (ctx, reset_notify);
1302 assuan_register_input_notify (ctx, input_notify);
1303 assuan_register_output_notify (ctx, output_notify);
1304 assuan_register_option_handler (ctx, option_handler);
1306 assuan_set_pointer (ctx, &ctrl);
1307 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1308 ctrl.server_local->assuan_ctx = ctx;
1309 ctrl.server_local->message_fd = -1;
1310 ctrl.server_local->list_internal = 1;
1311 ctrl.server_local->list_external = 0;
1312 ctrl.server_local->default_recplist = default_recplist;
1315 assuan_set_log_stream (ctx, log_get_stream ());
1319 rc = assuan_accept (ctx);
1326 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1330 rc = assuan_process (ctx);
1333 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1338 gpgsm_release_certlist (ctrl.server_local->recplist);
1339 ctrl.server_local->recplist = NULL;
1340 gpgsm_release_certlist (ctrl.server_local->signerlist);
1341 ctrl.server_local->signerlist = NULL;
1342 xfree (ctrl.server_local);
1344 audit_release (ctrl.audit);
1347 assuan_release (ctx);
1353 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1355 gpg_error_t err = 0;
1359 va_start (arg_ptr, no);
1361 if (ctrl->no_server && ctrl->status_fd == -1)
1362 ; /* No status wanted. */
1363 else if (ctrl->no_server)
1367 if (ctrl->status_fd == 1)
1369 else if (ctrl->status_fd == 2)
1372 statusfp = fdopen (ctrl->status_fd, "w");
1376 log_fatal ("can't open fd %d for status output: %s\n",
1377 ctrl->status_fd, strerror(errno));
1381 fputs ("[GNUPG:] ", statusfp);
1382 fputs (get_status_string (no), statusfp);
1384 while ( (text = va_arg (arg_ptr, const char*) ))
1386 putc ( ' ', statusfp );
1387 for (; *text; text++)
1390 fputs ( "\\n", statusfp );
1391 else if (*text == '\r')
1392 fputs ( "\\r", statusfp );
1394 putc ( *(const byte *)text, statusfp );
1397 putc ('\n', statusfp);
1402 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1408 while ( (text = va_arg (arg_ptr, const char *)) )
1415 for ( ; *text && n < DIM (buf)-2; n++)
1419 err = assuan_write_status (ctx, get_status_string (no), buf);
1427 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1429 return gpgsm_status2 (ctrl, no, text, NULL);
1433 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1438 sprintf (buf, "%u", (unsigned int)ec);
1440 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1442 return gpgsm_status2 (ctrl, no, buf, NULL);
1446 /* Helper to notify the client about Pinentry events. Because that
1447 might disturb some older clients, this is only done when enabled
1448 via an option. Returns an gpg error code. */
1450 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1452 if (!ctrl || !ctrl->server_local
1453 || !ctrl->server_local->allow_pinentry_notify)
1455 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);