Add help strings for all commands.
[gnupg.git] / sm / server.c
blob1f12a166cc969214d9b1b860f03f11a33da88f9d
1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3 * 2007, 2008, 2009 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 "gpgsm.h"
31 #include <assuan.h>
32 #include "sysutils.h"
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;
43 int message_fd;
44 int list_internal;
45 int list_external;
46 int list_to_output; /* Write keylistings to the output fd. */
47 int enable_audit_log; /* Use an audit log. */
48 certlist_t recplist;
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 =
63 NULL,
64 data_line_cookie_write,
65 NULL,
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; */
78 static void
79 strcpy_escaped_plus (char *d, const char *s)
81 while (*s)
83 if (*s == '%' && s[1] && s[2])
85 s++;
86 *d++ = xtoi_2 (s);
87 s += 2;
89 else if (*s == '+')
90 *d++ = ' ', s++;
91 else
92 *d++ = *s++;
94 *d = 0;
98 /* Skip over options.
99 Blanks after the options are also removed. */
100 static char *
101 skip_options (const char *line)
103 while (spacep (line))
104 line++;
105 while ( *line == '-' && line[1] == '-' )
107 while (*line && !spacep (line))
108 line++;
109 while (spacep (line))
110 line++;
112 return (char*)line;
116 /* Check whether the option NAME appears in LINE */
117 static int
118 has_option (const char *line, const char *name)
120 const char *s;
121 int n = strlen (name);
123 s = strstr (line, name);
124 if (s && s >= skip_options (line))
125 return 0;
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
131 lines. */
132 static ssize_t
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 errno = EIO;
140 return -1;
143 return size;
146 static int
147 data_line_cookie_close (void *cookie)
149 assuan_context_t ctx = cookie;
151 if (assuan_send_data (ctx, NULL, 0))
153 errno = EIO;
154 return -1;
157 return 0;
161 static void
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. */
173 static gpg_error_t
174 start_audit_session (ctrl_t ctrl)
176 audit_release (ctrl->audit);
177 ctrl->audit = NULL;
178 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
179 return gpg_error_from_syserror ();
181 return 0;
185 static gpg_error_t
186 option_handler (assuan_context_t ctx, const char *key, const char *value)
188 ctrl_t ctrl = assuan_get_pointer (ctx);
189 gpg_error_t err = 0;
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);
217 if (!opt.lc_ctype)
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);
240 else
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;
251 else if (i == 2)
253 ctrl->server_local->list_internal = 0;
254 ctrl->server_local->list_external = 1;
256 else if (i == 3)
258 ctrl->server_local->list_internal = 1;
259 ctrl->server_local->list_external = 1;
261 else
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;
279 else
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;
304 else
305 err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
307 return err;
311 static gpg_error_t
312 reset_notify (assuan_context_t ctx, char *line)
314 ctrl_t ctrl = assuan_get_pointer (ctx);
316 (void) line;
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);
325 return 0;
329 static gpg_error_t
330 input_notify (assuan_context_t ctx, char *line)
332 ctrl_t ctrl = assuan_get_pointer (ctx);
334 ctrl->autodetect_encoding = 0;
335 ctrl->is_pem = 0;
336 ctrl->is_base64 = 0;
337 if (strstr (line, "--armor"))
338 ctrl->is_pem = 1;
339 else if (strstr (line, "--base64"))
340 ctrl->is_base64 = 1;
341 else if (strstr (line, "--binary"))
343 else
344 ctrl->autodetect_encoding = 1;
345 return 0;
348 static gpg_error_t
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 */
359 return 0;
364 /* RECIPIENT <userID>
366 Set the recipient for the encryption. <userID> should be the
367 internal representation of the key; the server may accept any other
368 way of specification [we will support this]. If this is a valid and
369 trusted recipient the server does respond with OK, otherwise the
370 return is an ERR with the reason why the recipient can't be used,
371 the encryption will then not be done for this recipient. If the
372 policy is not to encrypt at all if not all recipients are valid, the
373 client has to take care of this. All RECIPIENT commands are
374 cumulative until a RESET or an successful ENCRYPT command. */
375 static gpg_error_t
376 cmd_recipient (assuan_context_t ctx, char *line)
378 ctrl_t ctrl = assuan_get_pointer (ctx);
379 int rc;
381 if (!ctrl->audit)
382 rc = start_audit_session (ctrl);
383 else
384 rc = 0;
386 if (!rc)
387 rc = gpgsm_add_to_certlist (ctrl, line, 0,
388 &ctrl->server_local->recplist, 0);
389 if (rc)
391 gpgsm_status2 (ctrl, STATUS_INV_RECP,
392 get_inv_recpsgnr_code (rc), line, NULL);
395 return rc;
398 /* SIGNER <userID>
400 Set the signer's keys for the signature creation. <userID> should
401 be the internal representation of the key; the server may accept any
402 other way of specification [we will support this]. If this is a
403 valid and usable signing key the server does respond with OK,
404 otherwise it returns an ERR with the reason why the key can't be
405 used, the signing will then not be done for this key. If the policy
406 is not to sign at all if not all signer keys are valid, the client
407 has to take care of this. All SIGNER commands are cumulative until
408 a RESET but they are *not* reset by an SIGN command becuase it can
409 be expected that set of signers are used for more than one sign
410 operation. */
411 static gpg_error_t
412 cmd_signer (assuan_context_t ctx, char *line)
414 ctrl_t ctrl = assuan_get_pointer (ctx);
415 int rc;
417 rc = gpgsm_add_to_certlist (ctrl, line, 1,
418 &ctrl->server_local->signerlist, 0);
419 if (rc)
421 gpgsm_status2 (ctrl, STATUS_INV_SGNR,
422 get_inv_recpsgnr_code (rc), line, NULL);
423 /* For compatibiliy reasons we also issue the old code after the
424 new one. */
425 gpgsm_status2 (ctrl, STATUS_INV_RECP,
426 get_inv_recpsgnr_code (rc), line, NULL);
428 return rc;
432 /* ENCRYPT
434 Do the actual encryption process. Takes the plaintext from the INPUT
435 command, writes to the ciphertext to the file descriptor set with
436 the OUTPUT command, take the recipients form all the recipients set
437 so far. If this command fails the clients should try to delete all
438 output currently done or otherwise mark it as invalid. GPGSM does
439 ensure that there won't be any security problem with leftover data
440 on the output in this case.
442 This command should in general not fail, as all necessary checks
443 have been done while setting the recipients. The input and output
444 pipes are closed. */
445 static gpg_error_t
446 cmd_encrypt (assuan_context_t ctx, char *line)
448 ctrl_t ctrl = assuan_get_pointer (ctx);
449 certlist_t cl;
450 int inp_fd, out_fd;
451 FILE *out_fp;
452 int rc;
454 (void)line;
456 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
457 if (inp_fd == -1)
458 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
459 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
460 if (out_fd == -1)
461 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
463 out_fp = fdopen (dup (out_fd), "w");
464 if (!out_fp)
465 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
467 /* Now add all encrypt-to marked recipients from the default
468 list. */
469 rc = 0;
470 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
472 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
473 if (cl->is_encrypt_to)
474 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
475 &ctrl->server_local->recplist, 1);
477 if (!rc)
478 rc = ctrl->audit? 0 : start_audit_session (ctrl);
479 if (!rc)
480 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
481 ctrl->server_local->recplist,
482 inp_fd, out_fp);
483 fclose (out_fp);
485 gpgsm_release_certlist (ctrl->server_local->recplist);
486 ctrl->server_local->recplist = NULL;
487 /* Close and reset the fd */
488 close_message_fd (ctrl);
489 assuan_close_input_fd (ctx);
490 assuan_close_output_fd (ctx);
491 return rc;
495 /* DECRYPT
497 This performs the decrypt operation after doing some check on the
498 internal state. (e.g. that only needed data has been set). Because
499 it utilizes the GPG-Agent for the session key decryption, there is
500 no need to ask the client for a protecting passphrase - GpgAgent
501 does take care of this by requesting this from the user. */
502 static gpg_error_t
503 cmd_decrypt (assuan_context_t ctx, char *line)
505 ctrl_t ctrl = assuan_get_pointer (ctx);
506 int inp_fd, out_fd;
507 FILE *out_fp;
508 int rc;
510 (void)line;
512 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
513 if (inp_fd == -1)
514 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
515 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
516 if (out_fd == -1)
517 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
519 out_fp = fdopen (dup(out_fd), "w");
520 if (!out_fp)
521 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
523 rc = start_audit_session (ctrl);
524 if (!rc)
525 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
526 fclose (out_fp);
528 /* close and reset the fd */
529 close_message_fd (ctrl);
530 assuan_close_input_fd (ctx);
531 assuan_close_output_fd (ctx);
533 return rc;
537 /* VERIFY
539 This does a verify operation on the message send to the input-FD.
540 The result is written out using status lines. If an output FD was
541 given, the signed text will be written to that.
543 If the signature is a detached one, the server will inquire about
544 the signed material and the client must provide it.
546 static gpg_error_t
547 cmd_verify (assuan_context_t ctx, char *line)
549 int rc;
550 ctrl_t ctrl = assuan_get_pointer (ctx);
551 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
552 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
553 FILE *out_fp = NULL;
555 (void)line;
557 if (fd == -1)
558 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
560 if (out_fd != -1)
562 out_fp = fdopen ( dup(out_fd), "w");
563 if (!out_fp)
564 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
567 rc = start_audit_session (ctrl);
568 if (!rc)
569 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
570 ctrl->server_local->message_fd, out_fp);
571 if (out_fp)
572 fclose (out_fp);
574 /* close and reset the fd */
575 close_message_fd (ctrl);
576 assuan_close_input_fd (ctx);
577 assuan_close_output_fd (ctx);
579 return rc;
583 /* SIGN [--detached]
585 Sign the data set with the INPUT command and write it to the sink
586 set by OUTPUT. With "--detached" specified, a detached signature is
587 created (surprise). */
588 static gpg_error_t
589 cmd_sign (assuan_context_t ctx, char *line)
591 ctrl_t ctrl = assuan_get_pointer (ctx);
592 int inp_fd, out_fd;
593 FILE *out_fp;
594 int detached;
595 int rc;
597 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
598 if (inp_fd == -1)
599 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
600 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
601 if (out_fd == -1)
602 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
604 detached = has_option (line, "--detached");
606 out_fp = fdopen ( dup(out_fd), "w");
607 if (!out_fp)
608 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
610 rc = start_audit_session (ctrl);
611 if (!rc)
612 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
613 inp_fd, detached, out_fp);
614 fclose (out_fp);
616 /* close and reset the fd */
617 close_message_fd (ctrl);
618 assuan_close_input_fd (ctx);
619 assuan_close_output_fd (ctx);
621 return rc;
625 /* IMPORT [--re-import]
627 Import the certificates read form the input-fd, return status
628 message for each imported one. The import checks the validity of
629 the certificate but not of the entire chain. It is possible to
630 import expired certificates.
632 With the option --re-import the input data is expected to a be a LF
633 separated list of fingerprints. The command will re-import these
634 certificates, meaning that they are made permanent by removing
635 their ephemeral flag. */
636 static gpg_error_t
637 cmd_import (assuan_context_t ctx, char *line)
639 ctrl_t ctrl = assuan_get_pointer (ctx);
640 int rc;
641 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
642 int reimport = has_option (line, "--re-import");
644 (void)line;
646 if (fd == -1)
647 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
649 rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
651 /* close and reset the fd */
652 close_message_fd (ctrl);
653 assuan_close_input_fd (ctx);
654 assuan_close_output_fd (ctx);
656 return rc;
660 /* EXPORT [--data [--armor|--base64]] [--] pattern
664 static gpg_error_t
665 cmd_export (assuan_context_t ctx, char *line)
667 ctrl_t ctrl = assuan_get_pointer (ctx);
668 char *p;
669 strlist_t list, sl;
670 int use_data;
672 use_data = has_option (line, "--data");
674 if (use_data)
676 /* We need to override any possible setting done by an OUTPUT command. */
677 ctrl->create_pem = has_option (line, "--armor");
678 ctrl->create_base64 = has_option (line, "--base64");
681 line = skip_options (line);
683 /* Break the line down into an strlist_t. */
684 list = NULL;
685 for (p=line; *p; line = p)
687 while (*p && *p != ' ')
688 p++;
689 if (*p)
690 *p++ = 0;
691 if (*line)
693 sl = xtrymalloc (sizeof *sl + strlen (line));
694 if (!sl)
696 free_strlist (list);
697 return out_of_core ();
699 sl->flags = 0;
700 strcpy_escaped_plus (sl->d, line);
701 sl->next = list;
702 list = sl;
706 if (use_data)
708 estream_t stream;
710 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
711 if (!stream)
713 free_strlist (list);
714 return set_error (GPG_ERR_ASS_GENERAL,
715 "error setting up a data stream");
717 gpgsm_export (ctrl, list, NULL, stream);
718 es_fclose (stream);
720 else
722 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
723 FILE *out_fp;
725 if (fd == -1)
727 free_strlist (list);
728 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
730 out_fp = fdopen ( dup(fd), "w");
731 if (!out_fp)
733 free_strlist (list);
734 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
737 gpgsm_export (ctrl, list, out_fp, NULL);
738 fclose (out_fp);
741 free_strlist (list);
742 /* Close and reset the fds. */
743 close_message_fd (ctrl);
744 assuan_close_input_fd (ctx);
745 assuan_close_output_fd (ctx);
746 return 0;
750 static gpg_error_t
751 cmd_delkeys (assuan_context_t ctx, char *line)
753 ctrl_t ctrl = assuan_get_pointer (ctx);
754 char *p;
755 strlist_t list, sl;
756 int rc;
758 /* break the line down into an strlist_t */
759 list = NULL;
760 for (p=line; *p; line = p)
762 while (*p && *p != ' ')
763 p++;
764 if (*p)
765 *p++ = 0;
766 if (*line)
768 sl = xtrymalloc (sizeof *sl + strlen (line));
769 if (!sl)
771 free_strlist (list);
772 return out_of_core ();
774 sl->flags = 0;
775 strcpy_escaped_plus (sl->d, line);
776 sl->next = list;
777 list = sl;
781 rc = gpgsm_delete (ctrl, list);
782 free_strlist (list);
784 /* close and reset the fd */
785 close_message_fd (ctrl);
786 assuan_close_input_fd (ctx);
787 assuan_close_output_fd (ctx);
789 return rc;
794 /* MESSAGE FD=<n>
796 Set the file descriptor to read a message which is used with
797 detached signatures */
798 static gpg_error_t
799 cmd_message (assuan_context_t ctx, char *line)
801 int rc;
802 gnupg_fd_t sysfd;
803 int fd;
804 ctrl_t ctrl = assuan_get_pointer (ctx);
806 rc = assuan_command_parse_fd (ctx, line, &sysfd);
807 if (rc)
808 return rc;
809 fd = translate_sys2libc_fd (sysfd, 0);
810 if (fd == -1)
811 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
812 ctrl->server_local->message_fd = fd;
813 return 0;
816 /* LISTKEYS [<patterns>]
817 DUMPKEYS [<patterns>]
818 LISTSECRETKEYS [<patterns>]
819 DUMPSECRETKEYS [<patterns>]
821 static int
822 do_listkeys (assuan_context_t ctx, char *line, int mode)
824 ctrl_t ctrl = assuan_get_pointer (ctx);
825 estream_t fp;
826 char *p;
827 strlist_t list, sl;
828 unsigned int listmode;
829 gpg_error_t err;
831 /* Break the line down into an strlist. */
832 list = NULL;
833 for (p=line; *p; line = p)
835 while (*p && *p != ' ')
836 p++;
837 if (*p)
838 *p++ = 0;
839 if (*line)
841 sl = xtrymalloc (sizeof *sl + strlen (line));
842 if (!sl)
844 free_strlist (list);
845 return out_of_core ();
847 sl->flags = 0;
848 strcpy_escaped_plus (sl->d, line);
849 sl->next = list;
850 list = sl;
854 if (ctrl->server_local->list_to_output)
856 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
858 if ( outfd == -1 )
859 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
860 fp = es_fdopen ( dup (outfd), "w");
861 if (!fp)
862 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
864 else
866 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
867 if (!fp)
868 return set_error (GPG_ERR_ASS_GENERAL,
869 "error setting up a data stream");
872 ctrl->with_colons = 1;
873 listmode = mode;
874 if (ctrl->server_local->list_internal)
875 listmode |= (1<<6);
876 if (ctrl->server_local->list_external)
877 listmode |= (1<<7);
878 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
879 free_strlist (list);
880 es_fclose (fp);
881 if (ctrl->server_local->list_to_output)
882 assuan_close_output_fd (ctx);
883 return err;
886 static gpg_error_t
887 cmd_listkeys (assuan_context_t ctx, char *line)
889 return do_listkeys (ctx, line, 3);
892 static gpg_error_t
893 cmd_dumpkeys (assuan_context_t ctx, char *line)
895 return do_listkeys (ctx, line, 259);
898 static gpg_error_t
899 cmd_listsecretkeys (assuan_context_t ctx, char *line)
901 return do_listkeys (ctx, line, 2);
904 static gpg_error_t
905 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
907 return do_listkeys (ctx, line, 258);
911 /* GENKEY
913 Read the parameters in native format from the input fd and write a
914 certificate request to the output.
916 static gpg_error_t
917 cmd_genkey (assuan_context_t ctx, char *line)
919 ctrl_t ctrl = assuan_get_pointer (ctx);
920 int inp_fd, out_fd;
921 FILE *out_fp;
922 int rc;
923 estream_t in_stream;
925 (void)line;
927 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
928 if (inp_fd == -1)
929 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
930 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
931 if (out_fd == -1)
932 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
934 in_stream = es_fdopen_nc (inp_fd, "r");
935 if (!in_stream)
936 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
938 out_fp = fdopen ( dup(out_fd), "w");
939 if (!out_fp)
941 es_fclose (in_stream);
942 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
944 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
945 fclose (out_fp);
947 /* close and reset the fds */
948 assuan_close_input_fd (ctx);
949 assuan_close_output_fd (ctx);
951 return rc;
956 /* GETAUDITLOG [--data] [--html]
958 !!!WORK in PROGRESS!!!
960 If --data is used, the output is send using D-lines and not to the
961 source given by an OUTPUT command.
963 If --html is used the output is formated as an XHTML block. This is
964 designed to be incorporated into a HTML document.
966 static gpg_error_t
967 cmd_getauditlog (assuan_context_t ctx, char *line)
969 ctrl_t ctrl = assuan_get_pointer (ctx);
970 int out_fd;
971 estream_t out_stream;
972 int opt_data, opt_html;
973 int rc;
975 opt_data = has_option (line, "--data");
976 opt_html = has_option (line, "--html");
977 line = skip_options (line);
979 if (!ctrl->audit)
980 return gpg_error (GPG_ERR_NO_DATA);
982 if (opt_data)
984 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
985 if (!out_stream)
986 return set_error (GPG_ERR_ASS_GENERAL,
987 "error setting up a data stream");
989 else
991 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
992 if (out_fd == -1)
993 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
995 out_stream = es_fdopen_nc ( dup (out_fd), "w");
996 if (!out_stream)
998 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1002 audit_print_result (ctrl->audit, out_stream, opt_html);
1003 rc = 0;
1005 es_fclose (out_stream);
1007 /* Close and reset the fd. */
1008 if (!opt_data)
1009 assuan_close_output_fd (ctx);
1010 return rc;
1014 /* GETINFO <what>
1016 Multipurpose function to return a variety of information.
1017 Supported values for WHAT are:
1019 version - Return the version of the program.
1020 pid - Return the process id of the server.
1021 agent-check - Return success if the agent is running.
1022 cmd_has_option CMD OPT
1023 - Returns OK if the command CMD implements the option OPT.
1026 static gpg_error_t
1027 cmd_getinfo (assuan_context_t ctx, char *line)
1029 int rc = 0;
1031 if (!strcmp (line, "version"))
1033 const char *s = VERSION;
1034 rc = assuan_send_data (ctx, s, strlen (s));
1036 else if (!strcmp (line, "pid"))
1038 char numbuf[50];
1040 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1041 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1043 else if (!strcmp (line, "agent-check"))
1045 ctrl_t ctrl = assuan_get_pointer (ctx);
1046 rc = gpgsm_agent_send_nop (ctrl);
1048 else if (!strncmp (line, "cmd_has_option", 14)
1049 && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1051 char *cmd, *cmdopt;
1052 line += 14;
1053 while (*line == ' ' || *line == '\t')
1054 line++;
1055 if (!*line)
1056 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1057 else
1059 cmd = line;
1060 while (*line && (*line != ' ' && *line != '\t'))
1061 line++;
1062 if (!*line)
1063 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1064 else
1066 *line++ = 0;
1067 while (*line == ' ' || *line == '\t')
1068 line++;
1069 if (!*line)
1070 rc = gpg_error (GPG_ERR_MISSING_VALUE);
1071 else
1073 cmdopt = line;
1074 if (!command_has_option (cmd, cmdopt))
1075 rc = gpg_error (GPG_ERR_GENERAL);
1080 else
1081 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1083 return rc;
1088 /* Return true if the command CMD implements the option OPT. */
1089 static int
1090 command_has_option (const char *cmd, const char *cmdopt)
1092 if (!strcmp (cmd, "IMPORT"))
1094 if (!strcmp (cmdopt, "re-import"))
1095 return 1;
1098 return 0;
1102 /* Tell the assuan library about our commands */
1103 static int
1104 register_commands (assuan_context_t ctx)
1106 static struct {
1107 const char *name;
1108 assuan_handler_t handler;
1109 } table[] = {
1110 { "RECIPIENT", cmd_recipient },
1111 { "SIGNER", cmd_signer },
1112 { "ENCRYPT", cmd_encrypt },
1113 { "DECRYPT", cmd_decrypt },
1114 { "VERIFY", cmd_verify },
1115 { "SIGN", cmd_sign },
1116 { "IMPORT", cmd_import },
1117 { "EXPORT", cmd_export },
1118 { "INPUT", NULL },
1119 { "OUTPUT", NULL },
1120 { "MESSAGE", cmd_message },
1121 { "LISTKEYS", cmd_listkeys },
1122 { "DUMPKEYS", cmd_dumpkeys },
1123 { "LISTSECRETKEYS",cmd_listsecretkeys },
1124 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1125 { "GENKEY", cmd_genkey },
1126 { "DELKEYS", cmd_delkeys },
1127 { "GETAUDITLOG", cmd_getauditlog },
1128 { "GETINFO", cmd_getinfo },
1129 { NULL }
1131 int i, rc;
1133 for (i=0; table[i].name; i++)
1135 rc = assuan_register_command (ctx, table[i].name, table[i].handler, NULL);
1136 if (rc)
1137 return rc;
1139 return 0;
1142 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1143 set from the command line or config file. We only require those
1144 marked as encrypt-to. */
1145 void
1146 gpgsm_server (certlist_t default_recplist)
1148 int rc;
1149 int filedes[2];
1150 assuan_context_t ctx;
1151 struct server_control_s ctrl;
1152 static const char hello[] = ("GNU Privacy Guard's S/M server "
1153 VERSION " ready");
1155 memset (&ctrl, 0, sizeof ctrl);
1156 gpgsm_init_default_ctrl (&ctrl);
1158 /* We use a pipe based server so that we can work from scripts.
1159 assuan_init_pipe_server will automagically detect when we are
1160 called with a socketpair and ignore FIELDES in this case. */
1161 filedes[0] = 0;
1162 filedes[1] = 1;
1163 rc = assuan_new (&ctx);
1164 if (rc)
1166 log_error ("failed to allocate assuan context: %s\n",
1167 gpg_strerror (rc));
1168 gpgsm_exit (2);
1171 rc = assuan_init_pipe_server (ctx, filedes);
1172 if (rc)
1174 log_error ("failed to initialize the server: %s\n",
1175 gpg_strerror (rc));
1176 gpgsm_exit (2);
1178 rc = register_commands (ctx);
1179 if (rc)
1181 log_error ("failed to the register commands with Assuan: %s\n",
1182 gpg_strerror(rc));
1183 gpgsm_exit (2);
1185 if (opt.verbose || opt.debug)
1187 char *tmp = NULL;
1188 const char *s1 = getenv ("GPG_AGENT_INFO");
1189 const char *s2 = getenv ("DIRMNGR_INFO");
1191 if (asprintf (&tmp,
1192 "Home: %s\n"
1193 "Config: %s\n"
1194 "AgentInfo: %s\n"
1195 "DirmngrInfo: %s\n"
1196 "%s",
1197 opt.homedir,
1198 opt.config_filename,
1199 s1?s1:"[not set]",
1200 s2?s2:"[not set]",
1201 hello) > 0)
1203 assuan_set_hello_line (ctx, tmp);
1204 free (tmp);
1207 else
1208 assuan_set_hello_line (ctx, hello);
1210 assuan_register_reset_notify (ctx, reset_notify);
1211 assuan_register_input_notify (ctx, input_notify);
1212 assuan_register_output_notify (ctx, output_notify);
1213 assuan_register_option_handler (ctx, option_handler);
1215 assuan_set_pointer (ctx, &ctrl);
1216 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1217 ctrl.server_local->assuan_ctx = ctx;
1218 ctrl.server_local->message_fd = -1;
1219 ctrl.server_local->list_internal = 1;
1220 ctrl.server_local->list_external = 0;
1221 ctrl.server_local->default_recplist = default_recplist;
1223 if (DBG_ASSUAN)
1224 assuan_set_log_stream (ctx, log_get_stream ());
1226 for (;;)
1228 rc = assuan_accept (ctx);
1229 if (rc == -1)
1231 break;
1233 else if (rc)
1235 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1236 break;
1239 rc = assuan_process (ctx);
1240 if (rc)
1242 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1243 continue;
1247 gpgsm_release_certlist (ctrl.server_local->recplist);
1248 ctrl.server_local->recplist = NULL;
1249 gpgsm_release_certlist (ctrl.server_local->signerlist);
1250 ctrl.server_local->signerlist = NULL;
1251 xfree (ctrl.server_local);
1253 audit_release (ctrl.audit);
1254 ctrl.audit = NULL;
1256 assuan_release (ctx);
1261 gpg_error_t
1262 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1264 gpg_error_t err = 0;
1265 va_list arg_ptr;
1266 const char *text;
1268 va_start (arg_ptr, no);
1270 if (ctrl->no_server && ctrl->status_fd == -1)
1271 ; /* No status wanted. */
1272 else if (ctrl->no_server)
1274 if (!statusfp)
1276 if (ctrl->status_fd == 1)
1277 statusfp = stdout;
1278 else if (ctrl->status_fd == 2)
1279 statusfp = stderr;
1280 else
1281 statusfp = fdopen (ctrl->status_fd, "w");
1283 if (!statusfp)
1285 log_fatal ("can't open fd %d for status output: %s\n",
1286 ctrl->status_fd, strerror(errno));
1290 fputs ("[GNUPG:] ", statusfp);
1291 fputs (get_status_string (no), statusfp);
1293 while ( (text = va_arg (arg_ptr, const char*) ))
1295 putc ( ' ', statusfp );
1296 for (; *text; text++)
1298 if (*text == '\n')
1299 fputs ( "\\n", statusfp );
1300 else if (*text == '\r')
1301 fputs ( "\\r", statusfp );
1302 else
1303 putc ( *(const byte *)text, statusfp );
1306 putc ('\n', statusfp);
1307 fflush (statusfp);
1309 else
1311 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1312 char buf[950], *p;
1313 size_t n;
1315 p = buf;
1316 n = 0;
1317 while ( (text = va_arg (arg_ptr, const char *)) )
1319 if (n)
1321 *p++ = ' ';
1322 n++;
1324 for ( ; *text && n < DIM (buf)-2; n++)
1325 *p++ = *text++;
1327 *p = 0;
1328 err = assuan_write_status (ctx, get_status_string (no), buf);
1331 va_end (arg_ptr);
1332 return err;
1335 gpg_error_t
1336 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1338 return gpgsm_status2 (ctrl, no, text, NULL);
1341 gpg_error_t
1342 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1343 gpg_err_code_t ec)
1345 char buf[30];
1347 sprintf (buf, "%u", (unsigned int)ec);
1348 if (text)
1349 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1350 else
1351 return gpgsm_status2 (ctrl, no, buf, NULL);
1355 /* Helper to notify the client about Pinentry events. Because that
1356 might disturb some older clients, this is only done when enabled
1357 via an option. Returns an gpg error code. */
1358 gpg_error_t
1359 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1361 if (!ctrl || !ctrl->server_local
1362 || !ctrl->server_local->allow_pinentry_notify)
1363 return 0;
1364 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);