Fix bug 1045.
[gnupg.git] / sm / server.c
blob6b9eeb82d0d34f94387b0dc6bda132cf2194fd7e
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. */
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
72 /* Note that it is sufficient to allocate the target string D as
73 long as the source string S, i.e.: strlen(s)+1; */
74 static void
75 strcpy_escaped_plus (char *d, const char *s)
77 while (*s)
79 if (*s == '%' && s[1] && s[2])
81 s++;
82 *d++ = xtoi_2 (s);
83 s += 2;
85 else if (*s == '+')
86 *d++ = ' ', s++;
87 else
88 *d++ = *s++;
90 *d = 0;
94 /* Skip over options.
95 Blanks after the options are also removed. */
96 static char *
97 skip_options (const char *line)
99 while (spacep (line))
100 line++;
101 while ( *line == '-' && line[1] == '-' )
103 while (*line && !spacep (line))
104 line++;
105 while (spacep (line))
106 line++;
108 return (char*)line;
112 /* Check whether the option NAME appears in LINE */
113 static int
114 has_option (const char *line, const char *name)
116 const char *s;
117 int n = strlen (name);
119 s = strstr (line, name);
120 if (s && s >= skip_options (line))
121 return 0;
122 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
126 /* A write handler used by es_fopencookie to write assuan data
127 lines. */
128 static ssize_t
129 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
131 assuan_context_t ctx = cookie;
133 if (assuan_send_data (ctx, buffer, size))
135 errno = EIO;
136 return -1;
139 return size;
142 static int
143 data_line_cookie_close (void *cookie)
145 assuan_context_t ctx = cookie;
147 if (assuan_send_data (ctx, NULL, 0))
149 errno = EIO;
150 return -1;
153 return 0;
157 static void
158 close_message_fd (ctrl_t ctrl)
160 if (ctrl->server_local->message_fd != -1)
162 close (ctrl->server_local->message_fd);
163 ctrl->server_local->message_fd = -1;
168 /* Start a new audit session if this has been enabled. */
169 static gpg_error_t
170 start_audit_session (ctrl_t ctrl)
172 audit_release (ctrl->audit);
173 ctrl->audit = NULL;
174 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
175 return gpg_error_from_syserror ();
177 return 0;
181 static int
182 option_handler (assuan_context_t ctx, const char *key, const char *value)
184 ctrl_t ctrl = assuan_get_pointer (ctx);
186 if (!strcmp (key, "include-certs"))
188 int i = *value? atoi (value) : -1;
189 if (ctrl->include_certs < -2)
190 return gpg_error (GPG_ERR_ASS_PARAMETER);
191 ctrl->include_certs = i;
193 else if (!strcmp (key, "display"))
195 if (opt.display)
196 free (opt.display);
197 opt.display = strdup (value);
198 if (!opt.display)
199 return out_of_core ();
201 else if (!strcmp (key, "ttyname"))
203 if (opt.ttyname)
204 free (opt.ttyname);
205 opt.ttyname = strdup (value);
206 if (!opt.ttyname)
207 return out_of_core ();
209 else if (!strcmp (key, "ttytype"))
211 if (opt.ttytype)
212 free (opt.ttytype);
213 opt.ttytype = strdup (value);
214 if (!opt.ttytype)
215 return out_of_core ();
217 else if (!strcmp (key, "lc-ctype"))
219 if (opt.lc_ctype)
220 free (opt.lc_ctype);
221 opt.lc_ctype = strdup (value);
222 if (!opt.lc_ctype)
223 return out_of_core ();
225 else if (!strcmp (key, "lc-messages"))
227 if (opt.lc_messages)
228 free (opt.lc_messages);
229 opt.lc_messages = strdup (value);
230 if (!opt.lc_messages)
231 return out_of_core ();
233 else if (!strcmp (key, "xauthority"))
235 if (opt.xauthority)
236 free (opt.xauthority);
237 opt.xauthority = strdup (value);
238 if (!opt.xauthority)
239 return out_of_core ();
241 else if (!strcmp (key, "pinentry-user-data"))
243 if (opt.pinentry_user_data)
244 free (opt.pinentry_user_data);
245 opt.pinentry_user_data = strdup (value);
246 if (!opt.pinentry_user_data)
247 return out_of_core ();
249 else if (!strcmp (key, "list-mode"))
251 int i = *value? atoi (value) : 0;
252 if (!i || i == 1) /* default and mode 1 */
254 ctrl->server_local->list_internal = 1;
255 ctrl->server_local->list_external = 0;
257 else if (i == 2)
259 ctrl->server_local->list_internal = 0;
260 ctrl->server_local->list_external = 1;
262 else if (i == 3)
264 ctrl->server_local->list_internal = 1;
265 ctrl->server_local->list_external = 1;
267 else
268 return gpg_error (GPG_ERR_ASS_PARAMETER);
270 else if (!strcmp (key, "list-to-output"))
272 int i = *value? atoi (value) : 0;
273 ctrl->server_local->list_to_output = i;
275 else if (!strcmp (key, "with-validation"))
277 int i = *value? atoi (value) : 0;
278 ctrl->with_validation = i;
280 else if (!strcmp (key, "validation-model"))
282 int i = gpgsm_parse_validation_model (value);
283 if ( i >= 0 && i <= 1 )
284 ctrl->validation_model = i;
285 else
286 return gpg_error (GPG_ERR_ASS_PARAMETER);
288 else if (!strcmp (key, "with-key-data"))
290 opt.with_key_data = 1;
292 else if (!strcmp (key, "enable-audit-log"))
294 int i = *value? atoi (value) : 0;
295 ctrl->server_local->enable_audit_log = i;
297 else if (!strcmp (key, "allow-pinentry-notify"))
298 ctrl->server_local->allow_pinentry_notify = 1;
299 else if (!strcmp (key, "with-ephemeral-keys"))
301 int i = *value? atoi (value) : 0;
302 ctrl->with_ephemeral_keys = i;
304 else
305 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
307 return 0;
311 static void
312 reset_notify (assuan_context_t ctx)
314 ctrl_t ctrl = assuan_get_pointer (ctx);
316 gpgsm_release_certlist (ctrl->server_local->recplist);
317 gpgsm_release_certlist (ctrl->server_local->signerlist);
318 ctrl->server_local->recplist = NULL;
319 ctrl->server_local->signerlist = NULL;
320 close_message_fd (ctrl);
321 assuan_close_input_fd (ctx);
322 assuan_close_output_fd (ctx);
326 static void
327 input_notify (assuan_context_t ctx, const char *line)
329 ctrl_t ctrl = assuan_get_pointer (ctx);
331 ctrl->autodetect_encoding = 0;
332 ctrl->is_pem = 0;
333 ctrl->is_base64 = 0;
334 if (strstr (line, "--armor"))
335 ctrl->is_pem = 1;
336 else if (strstr (line, "--base64"))
337 ctrl->is_base64 = 1;
338 else if (strstr (line, "--binary"))
340 else
341 ctrl->autodetect_encoding = 1;
344 static void
345 output_notify (assuan_context_t ctx, const char *line)
347 ctrl_t ctrl = assuan_get_pointer (ctx);
349 ctrl->create_pem = 0;
350 ctrl->create_base64 = 0;
351 if (strstr (line, "--armor"))
352 ctrl->create_pem = 1;
353 else if (strstr (line, "--base64"))
354 ctrl->create_base64 = 1; /* just the raw output */
359 /* RECIPIENT <userID>
361 Set the recipient for the encryption. <userID> should be the
362 internal representation of the key; the server may accept any other
363 way of specification [we will support this]. If this is a valid and
364 trusted recipient the server does respond with OK, otherwise the
365 return is an ERR with the reason why the recipient can't be used,
366 the encryption will then not be done for this recipient. If the
367 policy is not to encrypt at all if not all recipients are valid, the
368 client has to take care of this. All RECIPIENT commands are
369 cumulative until a RESET or an successful ENCRYPT command. */
370 static int
371 cmd_recipient (assuan_context_t ctx, char *line)
373 ctrl_t ctrl = assuan_get_pointer (ctx);
374 int rc;
376 if (!ctrl->audit)
377 rc = start_audit_session (ctrl);
378 else
379 rc = 0;
381 if (!rc)
382 rc = gpgsm_add_to_certlist (ctrl, line, 0,
383 &ctrl->server_local->recplist, 0);
384 if (rc)
386 gpg_err_code_t r = gpg_err_code (rc);
387 gpgsm_status2 (ctrl, STATUS_INV_RECP,
388 r == -1? "1":
389 r == GPG_ERR_NO_PUBKEY? "1":
390 r == GPG_ERR_AMBIGUOUS_NAME? "2":
391 r == GPG_ERR_WRONG_KEY_USAGE? "3":
392 r == GPG_ERR_CERT_REVOKED? "4":
393 r == GPG_ERR_CERT_EXPIRED? "5":
394 r == GPG_ERR_NO_CRL_KNOWN? "6":
395 r == GPG_ERR_CRL_TOO_OLD? "7":
396 r == GPG_ERR_NO_POLICY_MATCH? "8":
397 r == GPG_ERR_MISSING_CERT? "11":
398 "0",
399 line, NULL);
402 return rc;
405 /* SIGNER <userID>
407 Set the signer's keys for the signature creation. <userID> should
408 be the internal representation of the key; the server may accept any
409 other way of specification [we will support this]. If this is a
410 valid and usable signing key the server does respond with OK,
411 otherwise it returns an ERR with the reason why the key can't be
412 used, the signing will then not be done for this key. If the policy
413 is not to sign at all if not all signer keys are valid, the client
414 has to take care of this. All SIGNER commands are cumulative until
415 a RESET but they are *not* reset by an SIGN command becuase it can
416 be expected that set of signers are used for more than one sign
417 operation.
419 Note that this command returns an INV_RECP status which is a bit
420 strange, but they are very similar. */
421 static int
422 cmd_signer (assuan_context_t ctx, char *line)
424 ctrl_t ctrl = assuan_get_pointer (ctx);
425 int rc;
427 rc = gpgsm_add_to_certlist (ctrl, line, 1,
428 &ctrl->server_local->signerlist, 0);
429 if (rc)
431 gpg_err_code_t r = gpg_err_code (rc);
432 gpgsm_status2 (ctrl, STATUS_INV_RECP,
433 r == -1? "1":
434 r == GPG_ERR_NO_PUBKEY? "1":
435 r == GPG_ERR_AMBIGUOUS_NAME? "2":
436 r == GPG_ERR_WRONG_KEY_USAGE? "3":
437 r == GPG_ERR_CERT_REVOKED? "4":
438 r == GPG_ERR_CERT_EXPIRED? "5":
439 r == GPG_ERR_NO_CRL_KNOWN? "6":
440 r == GPG_ERR_CRL_TOO_OLD? "7":
441 r == GPG_ERR_NO_POLICY_MATCH? "8":
442 r == GPG_ERR_NO_SECKEY? "9":
443 r == GPG_ERR_MISSING_CERT? "11":
444 "0",
445 line, NULL);
447 return rc;
451 /* ENCRYPT
453 Do the actual encryption process. Takes the plaintext from the INPUT
454 command, writes to the ciphertext to the file descriptor set with
455 the OUTPUT command, take the recipients form all the recipients set
456 so far. If this command fails the clients should try to delete all
457 output currently done or otherwise mark it as invalid. GPGSM does
458 ensure that there won't be any security problem with leftover data
459 on the output in this case.
461 This command should in general not fail, as all necessary checks
462 have been done while setting the recipients. The input and output
463 pipes are closed. */
464 static int
465 cmd_encrypt (assuan_context_t ctx, char *line)
467 ctrl_t ctrl = assuan_get_pointer (ctx);
468 certlist_t cl;
469 int inp_fd, out_fd;
470 FILE *out_fp;
471 int rc;
473 (void)line;
475 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
476 if (inp_fd == -1)
477 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
478 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
479 if (out_fd == -1)
480 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
482 out_fp = fdopen (dup (out_fd), "w");
483 if (!out_fp)
484 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
486 /* Now add all encrypt-to marked recipients from the default
487 list. */
488 rc = 0;
489 if (!opt.no_encrypt_to)
491 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
492 if (cl->is_encrypt_to)
493 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
494 &ctrl->server_local->recplist, 1);
496 if (!rc)
497 rc = ctrl->audit? 0 : start_audit_session (ctrl);
498 if (!rc)
499 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
500 ctrl->server_local->recplist,
501 inp_fd, out_fp);
502 fclose (out_fp);
504 gpgsm_release_certlist (ctrl->server_local->recplist);
505 ctrl->server_local->recplist = NULL;
506 /* Close and reset the fd */
507 close_message_fd (ctrl);
508 assuan_close_input_fd (ctx);
509 assuan_close_output_fd (ctx);
510 return rc;
514 /* DECRYPT
516 This performs the decrypt operation after doing some check on the
517 internal state. (e.g. that only needed data has been set). Because
518 it utilizes the GPG-Agent for the session key decryption, there is
519 no need to ask the client for a protecting passphrase - GpgAgent
520 does take care of this by requesting this from the user. */
521 static int
522 cmd_decrypt (assuan_context_t ctx, char *line)
524 ctrl_t ctrl = assuan_get_pointer (ctx);
525 int inp_fd, out_fd;
526 FILE *out_fp;
527 int rc;
529 (void)line;
531 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
532 if (inp_fd == -1)
533 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
534 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
535 if (out_fd == -1)
536 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
538 out_fp = fdopen (dup(out_fd), "w");
539 if (!out_fp)
540 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
542 rc = start_audit_session (ctrl);
543 if (!rc)
544 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
545 fclose (out_fp);
547 /* close and reset the fd */
548 close_message_fd (ctrl);
549 assuan_close_input_fd (ctx);
550 assuan_close_output_fd (ctx);
552 return rc;
556 /* VERIFY
558 This does a verify operation on the message send to the input-FD.
559 The result is written out using status lines. If an output FD was
560 given, the signed text will be written to that.
562 If the signature is a detached one, the server will inquire about
563 the signed material and the client must provide it.
565 static int
566 cmd_verify (assuan_context_t ctx, char *line)
568 int rc;
569 ctrl_t ctrl = assuan_get_pointer (ctx);
570 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
571 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
572 FILE *out_fp = NULL;
574 (void)line;
576 if (fd == -1)
577 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
579 if (out_fd != -1)
581 out_fp = fdopen ( dup(out_fd), "w");
582 if (!out_fp)
583 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
586 rc = start_audit_session (ctrl);
587 if (!rc)
588 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
589 ctrl->server_local->message_fd, out_fp);
590 if (out_fp)
591 fclose (out_fp);
593 /* close and reset the fd */
594 close_message_fd (ctrl);
595 assuan_close_input_fd (ctx);
596 assuan_close_output_fd (ctx);
598 return rc;
602 /* SIGN [--detached]
604 Sign the data set with the INPUT command and write it to the sink
605 set by OUTPUT. With "--detached" specified, a detached signature is
606 created (surprise). */
607 static int
608 cmd_sign (assuan_context_t ctx, char *line)
610 ctrl_t ctrl = assuan_get_pointer (ctx);
611 int inp_fd, out_fd;
612 FILE *out_fp;
613 int detached;
614 int rc;
616 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
617 if (inp_fd == -1)
618 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
619 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
620 if (out_fd == -1)
621 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
623 detached = has_option (line, "--detached");
625 out_fp = fdopen ( dup(out_fd), "w");
626 if (!out_fp)
627 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
629 rc = start_audit_session (ctrl);
630 if (!rc)
631 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
632 inp_fd, detached, out_fp);
633 fclose (out_fp);
635 /* close and reset the fd */
636 close_message_fd (ctrl);
637 assuan_close_input_fd (ctx);
638 assuan_close_output_fd (ctx);
640 return rc;
644 /* IMPORT
646 Import the certificates read form the input-fd, return status
647 message for each imported one. The import checks the validity of
648 the certificate but not of the entire chain. It is possible to
649 import expired certificates. */
650 static int
651 cmd_import (assuan_context_t ctx, char *line)
653 ctrl_t ctrl = assuan_get_pointer (ctx);
654 int rc;
655 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
657 (void)line;
659 if (fd == -1)
660 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
662 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
664 /* close and reset the fd */
665 close_message_fd (ctrl);
666 assuan_close_input_fd (ctx);
667 assuan_close_output_fd (ctx);
669 return rc;
673 /* EXPORT [--data [--armor|--base64]] [--] pattern
677 static int
678 cmd_export (assuan_context_t ctx, char *line)
680 ctrl_t ctrl = assuan_get_pointer (ctx);
681 char *p;
682 strlist_t list, sl;
683 int use_data;
685 use_data = has_option (line, "--data");
687 if (use_data)
689 /* We need to override any possible setting done by an OUTPUT command. */
690 ctrl->create_pem = has_option (line, "--armor");
691 ctrl->create_base64 = has_option (line, "--base64");
694 line = skip_options (line);
696 /* Break the line down into an strlist_t. */
697 list = NULL;
698 for (p=line; *p; line = p)
700 while (*p && *p != ' ')
701 p++;
702 if (*p)
703 *p++ = 0;
704 if (*line)
706 sl = xtrymalloc (sizeof *sl + strlen (line));
707 if (!sl)
709 free_strlist (list);
710 return out_of_core ();
712 sl->flags = 0;
713 strcpy_escaped_plus (sl->d, line);
714 sl->next = list;
715 list = sl;
719 if (use_data)
721 estream_t stream;
723 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
724 if (!stream)
726 free_strlist (list);
727 return set_error (GPG_ERR_ASS_GENERAL,
728 "error setting up a data stream");
730 gpgsm_export (ctrl, list, NULL, stream);
731 es_fclose (stream);
733 else
735 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
736 FILE *out_fp;
738 if (fd == -1)
740 free_strlist (list);
741 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
743 out_fp = fdopen ( dup(fd), "w");
744 if (!out_fp)
746 free_strlist (list);
747 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
750 gpgsm_export (ctrl, list, out_fp, NULL);
751 fclose (out_fp);
754 free_strlist (list);
755 /* Close and reset the fds. */
756 close_message_fd (ctrl);
757 assuan_close_input_fd (ctx);
758 assuan_close_output_fd (ctx);
759 return 0;
763 static int
764 cmd_delkeys (assuan_context_t ctx, char *line)
766 ctrl_t ctrl = assuan_get_pointer (ctx);
767 char *p;
768 strlist_t list, sl;
769 int rc;
771 /* break the line down into an strlist_t */
772 list = NULL;
773 for (p=line; *p; line = p)
775 while (*p && *p != ' ')
776 p++;
777 if (*p)
778 *p++ = 0;
779 if (*line)
781 sl = xtrymalloc (sizeof *sl + strlen (line));
782 if (!sl)
784 free_strlist (list);
785 return out_of_core ();
787 sl->flags = 0;
788 strcpy_escaped_plus (sl->d, line);
789 sl->next = list;
790 list = sl;
794 rc = gpgsm_delete (ctrl, list);
795 free_strlist (list);
797 /* close and reset the fd */
798 close_message_fd (ctrl);
799 assuan_close_input_fd (ctx);
800 assuan_close_output_fd (ctx);
802 return rc;
807 /* MESSAGE FD=<n>
809 Set the file descriptor to read a message which is used with
810 detached signatures */
811 static int
812 cmd_message (assuan_context_t ctx, char *line)
814 int rc;
815 gnupg_fd_t sysfd;
816 int fd;
817 ctrl_t ctrl = assuan_get_pointer (ctx);
819 rc = assuan_command_parse_fd (ctx, line, &sysfd);
820 if (rc)
821 return rc;
822 fd = translate_sys2libc_fd (sysfd, 0);
823 if (fd == -1)
824 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
825 ctrl->server_local->message_fd = fd;
826 return 0;
829 /* LISTKEYS [<patterns>]
830 DUMPKEYS [<patterns>]
831 LISTSECRETKEYS [<patterns>]
832 DUMPSECRETKEYS [<patterns>]
834 static int
835 do_listkeys (assuan_context_t ctx, char *line, int mode)
837 ctrl_t ctrl = assuan_get_pointer (ctx);
838 estream_t fp;
839 char *p;
840 strlist_t list, sl;
841 unsigned int listmode;
842 gpg_error_t err;
844 /* Break the line down into an strlist. */
845 list = NULL;
846 for (p=line; *p; line = p)
848 while (*p && *p != ' ')
849 p++;
850 if (*p)
851 *p++ = 0;
852 if (*line)
854 sl = xtrymalloc (sizeof *sl + strlen (line));
855 if (!sl)
857 free_strlist (list);
858 return out_of_core ();
860 sl->flags = 0;
861 strcpy_escaped_plus (sl->d, line);
862 sl->next = list;
863 list = sl;
867 if (ctrl->server_local->list_to_output)
869 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
871 if ( outfd == -1 )
872 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
873 fp = es_fdopen ( dup (outfd), "w");
874 if (!fp)
875 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
877 else
879 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
880 if (!fp)
881 return set_error (GPG_ERR_ASS_GENERAL,
882 "error setting up a data stream");
885 ctrl->with_colons = 1;
886 listmode = mode;
887 if (ctrl->server_local->list_internal)
888 listmode |= (1<<6);
889 if (ctrl->server_local->list_external)
890 listmode |= (1<<7);
891 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
892 free_strlist (list);
893 es_fclose (fp);
894 if (ctrl->server_local->list_to_output)
895 assuan_close_output_fd (ctx);
896 return err;
899 static int
900 cmd_listkeys (assuan_context_t ctx, char *line)
902 return do_listkeys (ctx, line, 3);
905 static int
906 cmd_dumpkeys (assuan_context_t ctx, char *line)
908 return do_listkeys (ctx, line, 259);
911 static int
912 cmd_listsecretkeys (assuan_context_t ctx, char *line)
914 return do_listkeys (ctx, line, 2);
917 static int
918 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
920 return do_listkeys (ctx, line, 258);
924 /* GENKEY
926 Read the parameters in native format from the input fd and write a
927 certificate request to the output.
929 static int
930 cmd_genkey (assuan_context_t ctx, char *line)
932 ctrl_t ctrl = assuan_get_pointer (ctx);
933 int inp_fd, out_fd;
934 FILE *out_fp;
935 int rc;
936 estream_t in_stream;
938 (void)line;
940 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
941 if (inp_fd == -1)
942 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
943 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
944 if (out_fd == -1)
945 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
947 in_stream = es_fdopen_nc (inp_fd, "r");
948 if (!in_stream)
949 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
951 out_fp = fdopen ( dup(out_fd), "w");
952 if (!out_fp)
954 es_fclose (in_stream);
955 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
957 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
958 fclose (out_fp);
960 /* close and reset the fds */
961 assuan_close_input_fd (ctx);
962 assuan_close_output_fd (ctx);
964 return rc;
969 /* GETAUDITLOG [--data] [--html]
971 !!!WORK in PROGRESS!!!
973 If --data is used, the output is send using D-lines and not to the
974 source given by an OUTPUT command.
976 If --html is used the output is formated as an XHTML block. This is
977 designed to be incorporated into a HTML document.
979 static int
980 cmd_getauditlog (assuan_context_t ctx, char *line)
982 ctrl_t ctrl = assuan_get_pointer (ctx);
983 int out_fd;
984 estream_t out_stream;
985 int opt_data, opt_html;
986 int rc;
988 opt_data = has_option (line, "--data");
989 opt_html = has_option (line, "--html");
990 line = skip_options (line);
992 if (!ctrl->audit)
993 return gpg_error (GPG_ERR_NO_DATA);
995 if (opt_data)
997 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
998 if (!out_stream)
999 return set_error (GPG_ERR_ASS_GENERAL,
1000 "error setting up a data stream");
1002 else
1004 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1005 if (out_fd == -1)
1006 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1008 out_stream = es_fdopen_nc ( dup (out_fd), "w");
1009 if (!out_stream)
1011 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1015 audit_print_result (ctrl->audit, out_stream, opt_html);
1016 rc = 0;
1018 es_fclose (out_stream);
1020 /* Close and reset the fd. */
1021 if (!opt_data)
1022 assuan_close_output_fd (ctx);
1023 return rc;
1027 /* GETINFO <what>
1029 Multipurpose function to return a variety of information.
1030 Supported values for WHAT are:
1032 version - Return the version of the program.
1033 pid - Return the process id of the server.
1034 agent-check - Return success if the agent is running.
1037 static int
1038 cmd_getinfo (assuan_context_t ctx, char *line)
1040 int rc;
1042 if (!strcmp (line, "version"))
1044 const char *s = VERSION;
1045 rc = assuan_send_data (ctx, s, strlen (s));
1047 else if (!strcmp (line, "pid"))
1049 char numbuf[50];
1051 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1052 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1054 else if (!strcmp (line, "agent-check"))
1056 ctrl_t ctrl = assuan_get_pointer (ctx);
1057 rc = gpgsm_agent_send_nop (ctrl);
1059 else
1060 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1061 return rc;
1066 /* Tell the assuan library about our commands */
1067 static int
1068 register_commands (assuan_context_t ctx)
1070 static struct {
1071 const char *name;
1072 int (*handler)(assuan_context_t, char *line);
1073 } table[] = {
1074 { "RECIPIENT", cmd_recipient },
1075 { "SIGNER", cmd_signer },
1076 { "ENCRYPT", cmd_encrypt },
1077 { "DECRYPT", cmd_decrypt },
1078 { "VERIFY", cmd_verify },
1079 { "SIGN", cmd_sign },
1080 { "IMPORT", cmd_import },
1081 { "EXPORT", cmd_export },
1082 { "INPUT", NULL },
1083 { "OUTPUT", NULL },
1084 { "MESSAGE", cmd_message },
1085 { "LISTKEYS", cmd_listkeys },
1086 { "DUMPKEYS", cmd_dumpkeys },
1087 { "LISTSECRETKEYS",cmd_listsecretkeys },
1088 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1089 { "GENKEY", cmd_genkey },
1090 { "DELKEYS", cmd_delkeys },
1091 { "GETAUDITLOG", cmd_getauditlog },
1092 { "GETINFO", cmd_getinfo },
1093 { NULL }
1095 int i, rc;
1097 for (i=0; table[i].name; i++)
1099 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1100 if (rc)
1101 return rc;
1103 return 0;
1106 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1107 set from the command line or config file. We only require those
1108 marked as encrypt-to. */
1109 void
1110 gpgsm_server (certlist_t default_recplist)
1112 int rc;
1113 int filedes[2];
1114 assuan_context_t ctx;
1115 struct server_control_s ctrl;
1116 static const char hello[] = ("GNU Privacy Guard's S/M server "
1117 VERSION " ready");
1119 memset (&ctrl, 0, sizeof ctrl);
1120 gpgsm_init_default_ctrl (&ctrl);
1122 /* We use a pipe based server so that we can work from scripts.
1123 assuan_init_pipe_server will automagically detect when we are
1124 called with a socketpair and ignore FIELDES in this case. */
1125 filedes[0] = 0;
1126 filedes[1] = 1;
1127 rc = assuan_init_pipe_server (&ctx, filedes);
1128 if (rc)
1130 log_error ("failed to initialize the server: %s\n",
1131 gpg_strerror (rc));
1132 gpgsm_exit (2);
1134 rc = register_commands (ctx);
1135 if (rc)
1137 log_error ("failed to the register commands with Assuan: %s\n",
1138 gpg_strerror(rc));
1139 gpgsm_exit (2);
1141 if (opt.verbose || opt.debug)
1143 char *tmp = NULL;
1144 const char *s1 = getenv ("GPG_AGENT_INFO");
1145 const char *s2 = getenv ("DIRMNGR_INFO");
1147 if (asprintf (&tmp,
1148 "Home: %s\n"
1149 "Config: %s\n"
1150 "AgentInfo: %s\n"
1151 "DirmngrInfo: %s\n"
1152 "%s",
1153 opt.homedir,
1154 opt.config_filename,
1155 s1?s1:"[not set]",
1156 s2?s2:"[not set]",
1157 hello) > 0)
1159 assuan_set_hello_line (ctx, tmp);
1160 free (tmp);
1163 else
1164 assuan_set_hello_line (ctx, hello);
1166 assuan_register_reset_notify (ctx, reset_notify);
1167 assuan_register_input_notify (ctx, input_notify);
1168 assuan_register_output_notify (ctx, output_notify);
1169 assuan_register_option_handler (ctx, option_handler);
1171 assuan_set_pointer (ctx, &ctrl);
1172 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1173 ctrl.server_local->assuan_ctx = ctx;
1174 ctrl.server_local->message_fd = -1;
1175 ctrl.server_local->list_internal = 1;
1176 ctrl.server_local->list_external = 0;
1177 ctrl.server_local->default_recplist = default_recplist;
1179 if (DBG_ASSUAN)
1180 assuan_set_log_stream (ctx, log_get_stream ());
1182 for (;;)
1184 rc = assuan_accept (ctx);
1185 if (rc == -1)
1187 break;
1189 else if (rc)
1191 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1192 break;
1195 rc = assuan_process (ctx);
1196 if (rc)
1198 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1199 continue;
1203 gpgsm_release_certlist (ctrl.server_local->recplist);
1204 ctrl.server_local->recplist = NULL;
1205 gpgsm_release_certlist (ctrl.server_local->signerlist);
1206 ctrl.server_local->signerlist = NULL;
1207 xfree (ctrl.server_local);
1209 audit_release (ctrl.audit);
1210 ctrl.audit = NULL;
1212 assuan_deinit_server (ctx);
1217 gpg_error_t
1218 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1220 gpg_error_t err = 0;
1221 va_list arg_ptr;
1222 const char *text;
1224 va_start (arg_ptr, no);
1226 if (ctrl->no_server && ctrl->status_fd == -1)
1227 ; /* No status wanted. */
1228 else if (ctrl->no_server)
1230 if (!statusfp)
1232 if (ctrl->status_fd == 1)
1233 statusfp = stdout;
1234 else if (ctrl->status_fd == 2)
1235 statusfp = stderr;
1236 else
1237 statusfp = fdopen (ctrl->status_fd, "w");
1239 if (!statusfp)
1241 log_fatal ("can't open fd %d for status output: %s\n",
1242 ctrl->status_fd, strerror(errno));
1246 fputs ("[GNUPG:] ", statusfp);
1247 fputs (get_status_string (no), statusfp);
1249 while ( (text = va_arg (arg_ptr, const char*) ))
1251 putc ( ' ', statusfp );
1252 for (; *text; text++)
1254 if (*text == '\n')
1255 fputs ( "\\n", statusfp );
1256 else if (*text == '\r')
1257 fputs ( "\\r", statusfp );
1258 else
1259 putc ( *(const byte *)text, statusfp );
1262 putc ('\n', statusfp);
1263 fflush (statusfp);
1265 else
1267 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1268 char buf[950], *p;
1269 size_t n;
1271 p = buf;
1272 n = 0;
1273 while ( (text = va_arg (arg_ptr, const char *)) )
1275 if (n)
1277 *p++ = ' ';
1278 n++;
1280 for ( ; *text && n < DIM (buf)-2; n++)
1281 *p++ = *text++;
1283 *p = 0;
1284 err = assuan_write_status (ctx, get_status_string (no), buf);
1287 va_end (arg_ptr);
1288 return err;
1291 gpg_error_t
1292 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1294 return gpgsm_status2 (ctrl, no, text, NULL);
1297 gpg_error_t
1298 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1299 gpg_err_code_t ec)
1301 char buf[30];
1303 sprintf (buf, "%u", (unsigned int)ec);
1304 if (text)
1305 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1306 else
1307 return gpgsm_status2 (ctrl, no, buf, NULL);
1311 /* Helper to notify the client about Pinentry events. Because that
1312 might disturb some older clients, this is only done when enabled
1313 via an option. Returns an gpg error code. */
1314 gpg_error_t
1315 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1317 if (!ctrl || !ctrl->server_local
1318 || !ctrl->server_local->allow_pinentry_notify)
1319 return 0;
1320 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);