Reworked passing of envars to Pinentry.
[gnupg.git] / sm / server.c
blob7ba5b683ed2a5622684709ff66cb57a3e4a1f9ab
1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3 * 2007, 2008 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <unistd.h>
30 #include <assuan.h>
32 #include "gpgsm.h"
33 #include "sysutils.h"
35 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
38 /* The filepointer for status message used in non-server mode */
39 static FILE *statusfp;
41 /* Data used to assuciate an Assuan context with local server data */
42 struct server_local_s {
43 assuan_context_t assuan_ctx;
44 int message_fd;
45 int list_internal;
46 int list_external;
47 int list_to_output; /* Write keylistings to the output fd. */
48 int enable_audit_log; /* Use an audit log. */
49 certlist_t recplist;
50 certlist_t signerlist;
51 certlist_t default_recplist; /* As set by main() - don't release. */
52 int allow_pinentry_notify; /* Set if pinentry notifications should
53 be passed back to the client. */
54 int no_encrypt_to; /* Local version of option. */
58 /* Cookie definition for assuan data line output. */
59 static ssize_t data_line_cookie_write (void *cookie,
60 const void *buffer, size_t size);
61 static int data_line_cookie_close (void *cookie);
62 static es_cookie_io_functions_t data_line_cookie_functions =
64 NULL,
65 data_line_cookie_write,
66 NULL,
67 data_line_cookie_close
73 /* Note that it is sufficient to allocate the target string D as
74 long as the source string S, i.e.: strlen(s)+1; */
75 static void
76 strcpy_escaped_plus (char *d, const char *s)
78 while (*s)
80 if (*s == '%' && s[1] && s[2])
82 s++;
83 *d++ = xtoi_2 (s);
84 s += 2;
86 else if (*s == '+')
87 *d++ = ' ', s++;
88 else
89 *d++ = *s++;
91 *d = 0;
95 /* Skip over options.
96 Blanks after the options are also removed. */
97 static char *
98 skip_options (const char *line)
100 while (spacep (line))
101 line++;
102 while ( *line == '-' && line[1] == '-' )
104 while (*line && !spacep (line))
105 line++;
106 while (spacep (line))
107 line++;
109 return (char*)line;
113 /* Check whether the option NAME appears in LINE */
114 static int
115 has_option (const char *line, const char *name)
117 const char *s;
118 int n = strlen (name);
120 s = strstr (line, name);
121 if (s && s >= skip_options (line))
122 return 0;
123 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
127 /* A write handler used by es_fopencookie to write assuan data
128 lines. */
129 static ssize_t
130 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
132 assuan_context_t ctx = cookie;
134 if (assuan_send_data (ctx, buffer, size))
136 errno = EIO;
137 return -1;
140 return size;
143 static int
144 data_line_cookie_close (void *cookie)
146 assuan_context_t ctx = cookie;
148 if (assuan_send_data (ctx, NULL, 0))
150 errno = EIO;
151 return -1;
154 return 0;
158 static void
159 close_message_fd (ctrl_t ctrl)
161 if (ctrl->server_local->message_fd != -1)
163 close (ctrl->server_local->message_fd);
164 ctrl->server_local->message_fd = -1;
169 /* Start a new audit session if this has been enabled. */
170 static gpg_error_t
171 start_audit_session (ctrl_t ctrl)
173 audit_release (ctrl->audit);
174 ctrl->audit = NULL;
175 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
176 return gpg_error_from_syserror ();
178 return 0;
182 static int
183 option_handler (assuan_context_t ctx, const char *key, const char *value)
185 ctrl_t ctrl = assuan_get_pointer (ctx);
186 gpg_error_t err = 0;
188 if (!strcmp (key, "putenv"))
190 /* Change the session's environment to be used for the
191 Pinentry. Valid values are:
192 <NAME> Delete envvar NAME
193 <KEY>= Set envvar NAME to the empty string
194 <KEY>=<VALUE> Set envvar NAME to VALUE
196 err = session_env_putenv (opt.session_env, value);
198 else if (!strcmp (key, "display"))
200 err = session_env_setenv (opt.session_env, "DISPLAY", value);
202 else if (!strcmp (key, "ttyname"))
204 err = session_env_setenv (opt.session_env, "GPG_TTY", value);
206 else if (!strcmp (key, "ttytype"))
208 err = session_env_setenv (opt.session_env, "TERM", value);
210 else if (!strcmp (key, "lc-ctype"))
212 xfree (opt.lc_ctype);
213 opt.lc_ctype = xtrystrdup (value);
214 if (!opt.lc_ctype)
215 err = gpg_error_from_syserror ();
217 else if (!strcmp (key, "lc-messages"))
219 xfree (opt.lc_messages);
220 opt.lc_messages = xtrystrdup (value);
221 if (!opt.lc_messages)
222 err = gpg_error_from_syserror ();
224 else if (!strcmp (key, "xauthority"))
226 err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
228 else if (!strcmp (key, "pinentry-user-data"))
230 err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
232 else if (!strcmp (key, "include-certs"))
234 int i = *value? atoi (value) : -1;
235 if (ctrl->include_certs < -2)
236 err = gpg_error (GPG_ERR_ASS_PARAMETER);
237 else
238 ctrl->include_certs = i;
240 else if (!strcmp (key, "list-mode"))
242 int i = *value? atoi (value) : 0;
243 if (!i || i == 1) /* default and mode 1 */
245 ctrl->server_local->list_internal = 1;
246 ctrl->server_local->list_external = 0;
248 else if (i == 2)
250 ctrl->server_local->list_internal = 0;
251 ctrl->server_local->list_external = 1;
253 else if (i == 3)
255 ctrl->server_local->list_internal = 1;
256 ctrl->server_local->list_external = 1;
258 else
259 err = gpg_error (GPG_ERR_ASS_PARAMETER);
261 else if (!strcmp (key, "list-to-output"))
263 int i = *value? atoi (value) : 0;
264 ctrl->server_local->list_to_output = i;
266 else if (!strcmp (key, "with-validation"))
268 int i = *value? atoi (value) : 0;
269 ctrl->with_validation = i;
271 else if (!strcmp (key, "validation-model"))
273 int i = gpgsm_parse_validation_model (value);
274 if ( i >= 0 && i <= 1 )
275 ctrl->validation_model = i;
276 else
277 err = gpg_error (GPG_ERR_ASS_PARAMETER);
279 else if (!strcmp (key, "with-key-data"))
281 opt.with_key_data = 1;
283 else if (!strcmp (key, "enable-audit-log"))
285 int i = *value? atoi (value) : 0;
286 ctrl->server_local->enable_audit_log = i;
288 else if (!strcmp (key, "allow-pinentry-notify"))
290 ctrl->server_local->allow_pinentry_notify = 1;
292 else if (!strcmp (key, "with-ephemeral-keys"))
294 int i = *value? atoi (value) : 0;
295 ctrl->with_ephemeral_keys = i;
297 else if (!strcmp (key, "no-encrypt-to"))
299 ctrl->server_local->no_encrypt_to = 1;
301 else
302 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
304 return err;
308 static void
309 reset_notify (assuan_context_t ctx)
311 ctrl_t ctrl = assuan_get_pointer (ctx);
313 gpgsm_release_certlist (ctrl->server_local->recplist);
314 gpgsm_release_certlist (ctrl->server_local->signerlist);
315 ctrl->server_local->recplist = NULL;
316 ctrl->server_local->signerlist = NULL;
317 close_message_fd (ctrl);
318 assuan_close_input_fd (ctx);
319 assuan_close_output_fd (ctx);
323 static void
324 input_notify (assuan_context_t ctx, const char *line)
326 ctrl_t ctrl = assuan_get_pointer (ctx);
328 ctrl->autodetect_encoding = 0;
329 ctrl->is_pem = 0;
330 ctrl->is_base64 = 0;
331 if (strstr (line, "--armor"))
332 ctrl->is_pem = 1;
333 else if (strstr (line, "--base64"))
334 ctrl->is_base64 = 1;
335 else if (strstr (line, "--binary"))
337 else
338 ctrl->autodetect_encoding = 1;
341 static void
342 output_notify (assuan_context_t ctx, const char *line)
344 ctrl_t ctrl = assuan_get_pointer (ctx);
346 ctrl->create_pem = 0;
347 ctrl->create_base64 = 0;
348 if (strstr (line, "--armor"))
349 ctrl->create_pem = 1;
350 else if (strstr (line, "--base64"))
351 ctrl->create_base64 = 1; /* just the raw output */
356 /* RECIPIENT <userID>
358 Set the recipient for the encryption. <userID> should be the
359 internal representation of the key; the server may accept any other
360 way of specification [we will support this]. If this is a valid and
361 trusted recipient the server does respond with OK, otherwise the
362 return is an ERR with the reason why the recipient can't be used,
363 the encryption will then not be done for this recipient. If the
364 policy is not to encrypt at all if not all recipients are valid, the
365 client has to take care of this. All RECIPIENT commands are
366 cumulative until a RESET or an successful ENCRYPT command. */
367 static int
368 cmd_recipient (assuan_context_t ctx, char *line)
370 ctrl_t ctrl = assuan_get_pointer (ctx);
371 int rc;
373 if (!ctrl->audit)
374 rc = start_audit_session (ctrl);
375 else
376 rc = 0;
378 if (!rc)
379 rc = gpgsm_add_to_certlist (ctrl, line, 0,
380 &ctrl->server_local->recplist, 0);
381 if (rc)
383 gpg_err_code_t r = gpg_err_code (rc);
384 gpgsm_status2 (ctrl, STATUS_INV_RECP,
385 r == -1? "1":
386 r == GPG_ERR_NO_PUBKEY? "1":
387 r == GPG_ERR_AMBIGUOUS_NAME? "2":
388 r == GPG_ERR_WRONG_KEY_USAGE? "3":
389 r == GPG_ERR_CERT_REVOKED? "4":
390 r == GPG_ERR_CERT_EXPIRED? "5":
391 r == GPG_ERR_NO_CRL_KNOWN? "6":
392 r == GPG_ERR_CRL_TOO_OLD? "7":
393 r == GPG_ERR_NO_POLICY_MATCH? "8":
394 r == GPG_ERR_MISSING_CERT? "11":
395 "0",
396 line, NULL);
399 return rc;
402 /* SIGNER <userID>
404 Set the signer's keys for the signature creation. <userID> should
405 be the internal representation of the key; the server may accept any
406 other way of specification [we will support this]. If this is a
407 valid and usable signing key the server does respond with OK,
408 otherwise it returns an ERR with the reason why the key can't be
409 used, the signing will then not be done for this key. If the policy
410 is not to sign at all if not all signer keys are valid, the client
411 has to take care of this. All SIGNER commands are cumulative until
412 a RESET but they are *not* reset by an SIGN command becuase it can
413 be expected that set of signers are used for more than one sign
414 operation.
416 Note that this command returns an INV_RECP status which is a bit
417 strange, but they are very similar. */
418 static int
419 cmd_signer (assuan_context_t ctx, char *line)
421 ctrl_t ctrl = assuan_get_pointer (ctx);
422 int rc;
424 rc = gpgsm_add_to_certlist (ctrl, line, 1,
425 &ctrl->server_local->signerlist, 0);
426 if (rc)
428 gpg_err_code_t r = gpg_err_code (rc);
429 gpgsm_status2 (ctrl, STATUS_INV_RECP,
430 r == -1? "1":
431 r == GPG_ERR_NO_PUBKEY? "1":
432 r == GPG_ERR_AMBIGUOUS_NAME? "2":
433 r == GPG_ERR_WRONG_KEY_USAGE? "3":
434 r == GPG_ERR_CERT_REVOKED? "4":
435 r == GPG_ERR_CERT_EXPIRED? "5":
436 r == GPG_ERR_NO_CRL_KNOWN? "6":
437 r == GPG_ERR_CRL_TOO_OLD? "7":
438 r == GPG_ERR_NO_POLICY_MATCH? "8":
439 r == GPG_ERR_NO_SECKEY? "9":
440 r == GPG_ERR_MISSING_CERT? "11":
441 "0",
442 line, NULL);
444 return rc;
448 /* ENCRYPT
450 Do the actual encryption process. Takes the plaintext from the INPUT
451 command, writes to the ciphertext to the file descriptor set with
452 the OUTPUT command, take the recipients form all the recipients set
453 so far. If this command fails the clients should try to delete all
454 output currently done or otherwise mark it as invalid. GPGSM does
455 ensure that there won't be any security problem with leftover data
456 on the output in this case.
458 This command should in general not fail, as all necessary checks
459 have been done while setting the recipients. The input and output
460 pipes are closed. */
461 static int
462 cmd_encrypt (assuan_context_t ctx, char *line)
464 ctrl_t ctrl = assuan_get_pointer (ctx);
465 certlist_t cl;
466 int inp_fd, out_fd;
467 FILE *out_fp;
468 int rc;
470 (void)line;
472 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
473 if (inp_fd == -1)
474 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
475 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
476 if (out_fd == -1)
477 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
479 out_fp = fdopen (dup (out_fd), "w");
480 if (!out_fp)
481 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
483 /* Now add all encrypt-to marked recipients from the default
484 list. */
485 rc = 0;
486 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
488 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
489 if (cl->is_encrypt_to)
490 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
491 &ctrl->server_local->recplist, 1);
493 if (!rc)
494 rc = ctrl->audit? 0 : start_audit_session (ctrl);
495 if (!rc)
496 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
497 ctrl->server_local->recplist,
498 inp_fd, out_fp);
499 fclose (out_fp);
501 gpgsm_release_certlist (ctrl->server_local->recplist);
502 ctrl->server_local->recplist = NULL;
503 /* Close and reset the fd */
504 close_message_fd (ctrl);
505 assuan_close_input_fd (ctx);
506 assuan_close_output_fd (ctx);
507 return rc;
511 /* DECRYPT
513 This performs the decrypt operation after doing some check on the
514 internal state. (e.g. that only needed data has been set). Because
515 it utilizes the GPG-Agent for the session key decryption, there is
516 no need to ask the client for a protecting passphrase - GpgAgent
517 does take care of this by requesting this from the user. */
518 static int
519 cmd_decrypt (assuan_context_t ctx, char *line)
521 ctrl_t ctrl = assuan_get_pointer (ctx);
522 int inp_fd, out_fd;
523 FILE *out_fp;
524 int rc;
526 (void)line;
528 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
529 if (inp_fd == -1)
530 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
531 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
532 if (out_fd == -1)
533 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
535 out_fp = fdopen (dup(out_fd), "w");
536 if (!out_fp)
537 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
539 rc = start_audit_session (ctrl);
540 if (!rc)
541 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
542 fclose (out_fp);
544 /* close and reset the fd */
545 close_message_fd (ctrl);
546 assuan_close_input_fd (ctx);
547 assuan_close_output_fd (ctx);
549 return rc;
553 /* VERIFY
555 This does a verify operation on the message send to the input-FD.
556 The result is written out using status lines. If an output FD was
557 given, the signed text will be written to that.
559 If the signature is a detached one, the server will inquire about
560 the signed material and the client must provide it.
562 static int
563 cmd_verify (assuan_context_t ctx, char *line)
565 int rc;
566 ctrl_t ctrl = assuan_get_pointer (ctx);
567 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
568 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
569 FILE *out_fp = NULL;
571 (void)line;
573 if (fd == -1)
574 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
576 if (out_fd != -1)
578 out_fp = fdopen ( dup(out_fd), "w");
579 if (!out_fp)
580 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
583 rc = start_audit_session (ctrl);
584 if (!rc)
585 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
586 ctrl->server_local->message_fd, out_fp);
587 if (out_fp)
588 fclose (out_fp);
590 /* close and reset the fd */
591 close_message_fd (ctrl);
592 assuan_close_input_fd (ctx);
593 assuan_close_output_fd (ctx);
595 return rc;
599 /* SIGN [--detached]
601 Sign the data set with the INPUT command and write it to the sink
602 set by OUTPUT. With "--detached" specified, a detached signature is
603 created (surprise). */
604 static int
605 cmd_sign (assuan_context_t ctx, char *line)
607 ctrl_t ctrl = assuan_get_pointer (ctx);
608 int inp_fd, out_fd;
609 FILE *out_fp;
610 int detached;
611 int rc;
613 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
614 if (inp_fd == -1)
615 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
616 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
617 if (out_fd == -1)
618 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
620 detached = has_option (line, "--detached");
622 out_fp = fdopen ( dup(out_fd), "w");
623 if (!out_fp)
624 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
626 rc = start_audit_session (ctrl);
627 if (!rc)
628 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
629 inp_fd, detached, out_fp);
630 fclose (out_fp);
632 /* close and reset the fd */
633 close_message_fd (ctrl);
634 assuan_close_input_fd (ctx);
635 assuan_close_output_fd (ctx);
637 return rc;
641 /* IMPORT
643 Import the certificates read form the input-fd, return status
644 message for each imported one. The import checks the validity of
645 the certificate but not of the entire chain. It is possible to
646 import expired certificates. */
647 static int
648 cmd_import (assuan_context_t ctx, char *line)
650 ctrl_t ctrl = assuan_get_pointer (ctx);
651 int rc;
652 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
654 (void)line;
656 if (fd == -1)
657 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
659 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
661 /* close and reset the fd */
662 close_message_fd (ctrl);
663 assuan_close_input_fd (ctx);
664 assuan_close_output_fd (ctx);
666 return rc;
670 /* EXPORT [--data [--armor|--base64]] [--] pattern
674 static int
675 cmd_export (assuan_context_t ctx, char *line)
677 ctrl_t ctrl = assuan_get_pointer (ctx);
678 char *p;
679 strlist_t list, sl;
680 int use_data;
682 use_data = has_option (line, "--data");
684 if (use_data)
686 /* We need to override any possible setting done by an OUTPUT command. */
687 ctrl->create_pem = has_option (line, "--armor");
688 ctrl->create_base64 = has_option (line, "--base64");
691 line = skip_options (line);
693 /* Break the line down into an strlist_t. */
694 list = NULL;
695 for (p=line; *p; line = p)
697 while (*p && *p != ' ')
698 p++;
699 if (*p)
700 *p++ = 0;
701 if (*line)
703 sl = xtrymalloc (sizeof *sl + strlen (line));
704 if (!sl)
706 free_strlist (list);
707 return out_of_core ();
709 sl->flags = 0;
710 strcpy_escaped_plus (sl->d, line);
711 sl->next = list;
712 list = sl;
716 if (use_data)
718 estream_t stream;
720 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
721 if (!stream)
723 free_strlist (list);
724 return set_error (GPG_ERR_ASS_GENERAL,
725 "error setting up a data stream");
727 gpgsm_export (ctrl, list, NULL, stream);
728 es_fclose (stream);
730 else
732 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
733 FILE *out_fp;
735 if (fd == -1)
737 free_strlist (list);
738 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
740 out_fp = fdopen ( dup(fd), "w");
741 if (!out_fp)
743 free_strlist (list);
744 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
747 gpgsm_export (ctrl, list, out_fp, NULL);
748 fclose (out_fp);
751 free_strlist (list);
752 /* Close and reset the fds. */
753 close_message_fd (ctrl);
754 assuan_close_input_fd (ctx);
755 assuan_close_output_fd (ctx);
756 return 0;
760 static int
761 cmd_delkeys (assuan_context_t ctx, char *line)
763 ctrl_t ctrl = assuan_get_pointer (ctx);
764 char *p;
765 strlist_t list, sl;
766 int rc;
768 /* break the line down into an strlist_t */
769 list = NULL;
770 for (p=line; *p; line = p)
772 while (*p && *p != ' ')
773 p++;
774 if (*p)
775 *p++ = 0;
776 if (*line)
778 sl = xtrymalloc (sizeof *sl + strlen (line));
779 if (!sl)
781 free_strlist (list);
782 return out_of_core ();
784 sl->flags = 0;
785 strcpy_escaped_plus (sl->d, line);
786 sl->next = list;
787 list = sl;
791 rc = gpgsm_delete (ctrl, list);
792 free_strlist (list);
794 /* close and reset the fd */
795 close_message_fd (ctrl);
796 assuan_close_input_fd (ctx);
797 assuan_close_output_fd (ctx);
799 return rc;
804 /* MESSAGE FD=<n>
806 Set the file descriptor to read a message which is used with
807 detached signatures */
808 static int
809 cmd_message (assuan_context_t ctx, char *line)
811 int rc;
812 gnupg_fd_t sysfd;
813 int fd;
814 ctrl_t ctrl = assuan_get_pointer (ctx);
816 rc = assuan_command_parse_fd (ctx, line, &sysfd);
817 if (rc)
818 return rc;
819 fd = translate_sys2libc_fd (sysfd, 0);
820 if (fd == -1)
821 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
822 ctrl->server_local->message_fd = fd;
823 return 0;
826 /* LISTKEYS [<patterns>]
827 DUMPKEYS [<patterns>]
828 LISTSECRETKEYS [<patterns>]
829 DUMPSECRETKEYS [<patterns>]
831 static int
832 do_listkeys (assuan_context_t ctx, char *line, int mode)
834 ctrl_t ctrl = assuan_get_pointer (ctx);
835 estream_t fp;
836 char *p;
837 strlist_t list, sl;
838 unsigned int listmode;
839 gpg_error_t err;
841 /* Break the line down into an strlist. */
842 list = NULL;
843 for (p=line; *p; line = p)
845 while (*p && *p != ' ')
846 p++;
847 if (*p)
848 *p++ = 0;
849 if (*line)
851 sl = xtrymalloc (sizeof *sl + strlen (line));
852 if (!sl)
854 free_strlist (list);
855 return out_of_core ();
857 sl->flags = 0;
858 strcpy_escaped_plus (sl->d, line);
859 sl->next = list;
860 list = sl;
864 if (ctrl->server_local->list_to_output)
866 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
868 if ( outfd == -1 )
869 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
870 fp = es_fdopen ( dup (outfd), "w");
871 if (!fp)
872 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
874 else
876 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
877 if (!fp)
878 return set_error (GPG_ERR_ASS_GENERAL,
879 "error setting up a data stream");
882 ctrl->with_colons = 1;
883 listmode = mode;
884 if (ctrl->server_local->list_internal)
885 listmode |= (1<<6);
886 if (ctrl->server_local->list_external)
887 listmode |= (1<<7);
888 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
889 free_strlist (list);
890 es_fclose (fp);
891 if (ctrl->server_local->list_to_output)
892 assuan_close_output_fd (ctx);
893 return err;
896 static int
897 cmd_listkeys (assuan_context_t ctx, char *line)
899 return do_listkeys (ctx, line, 3);
902 static int
903 cmd_dumpkeys (assuan_context_t ctx, char *line)
905 return do_listkeys (ctx, line, 259);
908 static int
909 cmd_listsecretkeys (assuan_context_t ctx, char *line)
911 return do_listkeys (ctx, line, 2);
914 static int
915 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
917 return do_listkeys (ctx, line, 258);
921 /* GENKEY
923 Read the parameters in native format from the input fd and write a
924 certificate request to the output.
926 static int
927 cmd_genkey (assuan_context_t ctx, char *line)
929 ctrl_t ctrl = assuan_get_pointer (ctx);
930 int inp_fd, out_fd;
931 FILE *out_fp;
932 int rc;
933 estream_t in_stream;
935 (void)line;
937 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
938 if (inp_fd == -1)
939 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
940 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
941 if (out_fd == -1)
942 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
944 in_stream = es_fdopen_nc (inp_fd, "r");
945 if (!in_stream)
946 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
948 out_fp = fdopen ( dup(out_fd), "w");
949 if (!out_fp)
951 es_fclose (in_stream);
952 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
954 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
955 fclose (out_fp);
957 /* close and reset the fds */
958 assuan_close_input_fd (ctx);
959 assuan_close_output_fd (ctx);
961 return rc;
966 /* GETAUDITLOG [--data] [--html]
968 !!!WORK in PROGRESS!!!
970 If --data is used, the output is send using D-lines and not to the
971 source given by an OUTPUT command.
973 If --html is used the output is formated as an XHTML block. This is
974 designed to be incorporated into a HTML document.
976 static int
977 cmd_getauditlog (assuan_context_t ctx, char *line)
979 ctrl_t ctrl = assuan_get_pointer (ctx);
980 int out_fd;
981 estream_t out_stream;
982 int opt_data, opt_html;
983 int rc;
985 opt_data = has_option (line, "--data");
986 opt_html = has_option (line, "--html");
987 line = skip_options (line);
989 if (!ctrl->audit)
990 return gpg_error (GPG_ERR_NO_DATA);
992 if (opt_data)
994 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
995 if (!out_stream)
996 return set_error (GPG_ERR_ASS_GENERAL,
997 "error setting up a data stream");
999 else
1001 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1002 if (out_fd == -1)
1003 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1005 out_stream = es_fdopen_nc ( dup (out_fd), "w");
1006 if (!out_stream)
1008 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1012 audit_print_result (ctrl->audit, out_stream, opt_html);
1013 rc = 0;
1015 es_fclose (out_stream);
1017 /* Close and reset the fd. */
1018 if (!opt_data)
1019 assuan_close_output_fd (ctx);
1020 return rc;
1024 /* GETINFO <what>
1026 Multipurpose function to return a variety of information.
1027 Supported values for WHAT are:
1029 version - Return the version of the program.
1030 pid - Return the process id of the server.
1031 agent-check - Return success if the agent is running.
1034 static int
1035 cmd_getinfo (assuan_context_t ctx, char *line)
1037 int rc;
1039 if (!strcmp (line, "version"))
1041 const char *s = VERSION;
1042 rc = assuan_send_data (ctx, s, strlen (s));
1044 else if (!strcmp (line, "pid"))
1046 char numbuf[50];
1048 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1049 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1051 else if (!strcmp (line, "agent-check"))
1053 ctrl_t ctrl = assuan_get_pointer (ctx);
1054 rc = gpgsm_agent_send_nop (ctrl);
1056 else
1057 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1058 return rc;
1063 /* Tell the assuan library about our commands */
1064 static int
1065 register_commands (assuan_context_t ctx)
1067 static struct {
1068 const char *name;
1069 int (*handler)(assuan_context_t, char *line);
1070 } table[] = {
1071 { "RECIPIENT", cmd_recipient },
1072 { "SIGNER", cmd_signer },
1073 { "ENCRYPT", cmd_encrypt },
1074 { "DECRYPT", cmd_decrypt },
1075 { "VERIFY", cmd_verify },
1076 { "SIGN", cmd_sign },
1077 { "IMPORT", cmd_import },
1078 { "EXPORT", cmd_export },
1079 { "INPUT", NULL },
1080 { "OUTPUT", NULL },
1081 { "MESSAGE", cmd_message },
1082 { "LISTKEYS", cmd_listkeys },
1083 { "DUMPKEYS", cmd_dumpkeys },
1084 { "LISTSECRETKEYS",cmd_listsecretkeys },
1085 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1086 { "GENKEY", cmd_genkey },
1087 { "DELKEYS", cmd_delkeys },
1088 { "GETAUDITLOG", cmd_getauditlog },
1089 { "GETINFO", cmd_getinfo },
1090 { NULL }
1092 int i, rc;
1094 for (i=0; table[i].name; i++)
1096 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1097 if (rc)
1098 return rc;
1100 return 0;
1103 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1104 set from the command line or config file. We only require those
1105 marked as encrypt-to. */
1106 void
1107 gpgsm_server (certlist_t default_recplist)
1109 int rc;
1110 int filedes[2];
1111 assuan_context_t ctx;
1112 struct server_control_s ctrl;
1113 static const char hello[] = ("GNU Privacy Guard's S/M server "
1114 VERSION " ready");
1116 memset (&ctrl, 0, sizeof ctrl);
1117 gpgsm_init_default_ctrl (&ctrl);
1119 /* We use a pipe based server so that we can work from scripts.
1120 assuan_init_pipe_server will automagically detect when we are
1121 called with a socketpair and ignore FIELDES in this case. */
1122 filedes[0] = 0;
1123 filedes[1] = 1;
1124 rc = assuan_init_pipe_server (&ctx, filedes);
1125 if (rc)
1127 log_error ("failed to initialize the server: %s\n",
1128 gpg_strerror (rc));
1129 gpgsm_exit (2);
1131 rc = register_commands (ctx);
1132 if (rc)
1134 log_error ("failed to the register commands with Assuan: %s\n",
1135 gpg_strerror(rc));
1136 gpgsm_exit (2);
1138 if (opt.verbose || opt.debug)
1140 char *tmp = NULL;
1141 const char *s1 = getenv ("GPG_AGENT_INFO");
1142 const char *s2 = getenv ("DIRMNGR_INFO");
1144 if (asprintf (&tmp,
1145 "Home: %s\n"
1146 "Config: %s\n"
1147 "AgentInfo: %s\n"
1148 "DirmngrInfo: %s\n"
1149 "%s",
1150 opt.homedir,
1151 opt.config_filename,
1152 s1?s1:"[not set]",
1153 s2?s2:"[not set]",
1154 hello) > 0)
1156 assuan_set_hello_line (ctx, tmp);
1157 free (tmp);
1160 else
1161 assuan_set_hello_line (ctx, hello);
1163 assuan_register_reset_notify (ctx, reset_notify);
1164 assuan_register_input_notify (ctx, input_notify);
1165 assuan_register_output_notify (ctx, output_notify);
1166 assuan_register_option_handler (ctx, option_handler);
1168 assuan_set_pointer (ctx, &ctrl);
1169 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1170 ctrl.server_local->assuan_ctx = ctx;
1171 ctrl.server_local->message_fd = -1;
1172 ctrl.server_local->list_internal = 1;
1173 ctrl.server_local->list_external = 0;
1174 ctrl.server_local->default_recplist = default_recplist;
1176 if (DBG_ASSUAN)
1177 assuan_set_log_stream (ctx, log_get_stream ());
1179 for (;;)
1181 rc = assuan_accept (ctx);
1182 if (rc == -1)
1184 break;
1186 else if (rc)
1188 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1189 break;
1192 rc = assuan_process (ctx);
1193 if (rc)
1195 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1196 continue;
1200 gpgsm_release_certlist (ctrl.server_local->recplist);
1201 ctrl.server_local->recplist = NULL;
1202 gpgsm_release_certlist (ctrl.server_local->signerlist);
1203 ctrl.server_local->signerlist = NULL;
1204 xfree (ctrl.server_local);
1206 audit_release (ctrl.audit);
1207 ctrl.audit = NULL;
1209 assuan_deinit_server (ctx);
1214 gpg_error_t
1215 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1217 gpg_error_t err = 0;
1218 va_list arg_ptr;
1219 const char *text;
1221 va_start (arg_ptr, no);
1223 if (ctrl->no_server && ctrl->status_fd == -1)
1224 ; /* No status wanted. */
1225 else if (ctrl->no_server)
1227 if (!statusfp)
1229 if (ctrl->status_fd == 1)
1230 statusfp = stdout;
1231 else if (ctrl->status_fd == 2)
1232 statusfp = stderr;
1233 else
1234 statusfp = fdopen (ctrl->status_fd, "w");
1236 if (!statusfp)
1238 log_fatal ("can't open fd %d for status output: %s\n",
1239 ctrl->status_fd, strerror(errno));
1243 fputs ("[GNUPG:] ", statusfp);
1244 fputs (get_status_string (no), statusfp);
1246 while ( (text = va_arg (arg_ptr, const char*) ))
1248 putc ( ' ', statusfp );
1249 for (; *text; text++)
1251 if (*text == '\n')
1252 fputs ( "\\n", statusfp );
1253 else if (*text == '\r')
1254 fputs ( "\\r", statusfp );
1255 else
1256 putc ( *(const byte *)text, statusfp );
1259 putc ('\n', statusfp);
1260 fflush (statusfp);
1262 else
1264 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1265 char buf[950], *p;
1266 size_t n;
1268 p = buf;
1269 n = 0;
1270 while ( (text = va_arg (arg_ptr, const char *)) )
1272 if (n)
1274 *p++ = ' ';
1275 n++;
1277 for ( ; *text && n < DIM (buf)-2; n++)
1278 *p++ = *text++;
1280 *p = 0;
1281 err = assuan_write_status (ctx, get_status_string (no), buf);
1284 va_end (arg_ptr);
1285 return err;
1288 gpg_error_t
1289 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1291 return gpgsm_status2 (ctrl, no, text, NULL);
1294 gpg_error_t
1295 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1296 gpg_err_code_t ec)
1298 char buf[30];
1300 sprintf (buf, "%u", (unsigned int)ec);
1301 if (text)
1302 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1303 else
1304 return gpgsm_status2 (ctrl, no, buf, NULL);
1308 /* Helper to notify the client about Pinentry events. Because that
1309 might disturb some older clients, this is only done when enabled
1310 via an option. Returns an gpg error code. */
1311 gpg_error_t
1312 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1314 if (!ctrl || !ctrl->server_local
1315 || !ctrl->server_local->allow_pinentry_notify)
1316 return 0;
1317 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);