Enhanced last patch.
[gnupg.git] / sm / server.c
blob9b0a04f18f7be0aa0e627d174738a996a2f1d022
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
300 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
302 return 0;
306 static void
307 reset_notify (assuan_context_t ctx)
309 ctrl_t ctrl = assuan_get_pointer (ctx);
311 gpgsm_release_certlist (ctrl->server_local->recplist);
312 gpgsm_release_certlist (ctrl->server_local->signerlist);
313 ctrl->server_local->recplist = NULL;
314 ctrl->server_local->signerlist = NULL;
315 close_message_fd (ctrl);
316 assuan_close_input_fd (ctx);
317 assuan_close_output_fd (ctx);
321 static void
322 input_notify (assuan_context_t ctx, const char *line)
324 ctrl_t ctrl = assuan_get_pointer (ctx);
326 ctrl->autodetect_encoding = 0;
327 ctrl->is_pem = 0;
328 ctrl->is_base64 = 0;
329 if (strstr (line, "--armor"))
330 ctrl->is_pem = 1;
331 else if (strstr (line, "--base64"))
332 ctrl->is_base64 = 1;
333 else if (strstr (line, "--binary"))
335 else
336 ctrl->autodetect_encoding = 1;
339 static void
340 output_notify (assuan_context_t ctx, const char *line)
342 ctrl_t ctrl = assuan_get_pointer (ctx);
344 ctrl->create_pem = 0;
345 ctrl->create_base64 = 0;
346 if (strstr (line, "--armor"))
347 ctrl->create_pem = 1;
348 else if (strstr (line, "--base64"))
349 ctrl->create_base64 = 1; /* just the raw output */
354 /* RECIPIENT <userID>
356 Set the recipient for the encryption. <userID> should be the
357 internal representation of the key; the server may accept any other
358 way of specification [we will support this]. If this is a valid and
359 trusted recipient the server does respond with OK, otherwise the
360 return is an ERR with the reason why the recipient can't be used,
361 the encryption will then not be done for this recipient. If the
362 policy is not to encrypt at all if not all recipients are valid, the
363 client has to take care of this. All RECIPIENT commands are
364 cumulative until a RESET or an successful ENCRYPT command. */
365 static int
366 cmd_recipient (assuan_context_t ctx, char *line)
368 ctrl_t ctrl = assuan_get_pointer (ctx);
369 int rc;
371 if (!ctrl->audit)
372 rc = start_audit_session (ctrl);
373 else
374 rc = 0;
376 if (!rc)
377 rc = gpgsm_add_to_certlist (ctrl, line, 0,
378 &ctrl->server_local->recplist, 0);
379 if (rc)
381 gpg_err_code_t r = gpg_err_code (rc);
382 gpgsm_status2 (ctrl, STATUS_INV_RECP,
383 r == -1? "1":
384 r == GPG_ERR_NO_PUBKEY? "1":
385 r == GPG_ERR_AMBIGUOUS_NAME? "2":
386 r == GPG_ERR_WRONG_KEY_USAGE? "3":
387 r == GPG_ERR_CERT_REVOKED? "4":
388 r == GPG_ERR_CERT_EXPIRED? "5":
389 r == GPG_ERR_NO_CRL_KNOWN? "6":
390 r == GPG_ERR_CRL_TOO_OLD? "7":
391 r == GPG_ERR_NO_POLICY_MATCH? "8":
392 r == GPG_ERR_MISSING_CERT? "11":
393 "0",
394 line, NULL);
397 return rc;
400 /* SIGNER <userID>
402 Set the signer's keys for the signature creation. <userID> should
403 be the internal representation of the key; the server may accept any
404 other way of specification [we will support this]. If this is a
405 valid and usable signing key the server does respond with OK,
406 otherwise it returns an ERR with the reason why the key can't be
407 used, the signing will then not be done for this key. If the policy
408 is not to sign at all if not all signer keys are valid, the client
409 has to take care of this. All SIGNER commands are cumulative until
410 a RESET but they are *not* reset by an SIGN command becuase it can
411 be expected that set of signers are used for more than one sign
412 operation.
414 Note that this command returns an INV_RECP status which is a bit
415 strange, but they are very similar. */
416 static int
417 cmd_signer (assuan_context_t ctx, char *line)
419 ctrl_t ctrl = assuan_get_pointer (ctx);
420 int rc;
422 rc = gpgsm_add_to_certlist (ctrl, line, 1,
423 &ctrl->server_local->signerlist, 0);
424 if (rc)
426 gpg_err_code_t r = gpg_err_code (rc);
427 gpgsm_status2 (ctrl, STATUS_INV_RECP,
428 r == -1? "1":
429 r == GPG_ERR_NO_PUBKEY? "1":
430 r == GPG_ERR_AMBIGUOUS_NAME? "2":
431 r == GPG_ERR_WRONG_KEY_USAGE? "3":
432 r == GPG_ERR_CERT_REVOKED? "4":
433 r == GPG_ERR_CERT_EXPIRED? "5":
434 r == GPG_ERR_NO_CRL_KNOWN? "6":
435 r == GPG_ERR_CRL_TOO_OLD? "7":
436 r == GPG_ERR_NO_POLICY_MATCH? "8":
437 r == GPG_ERR_NO_SECKEY? "9":
438 r == GPG_ERR_MISSING_CERT? "11":
439 "0",
440 line, NULL);
442 return rc;
446 /* ENCRYPT
448 Do the actual encryption process. Takes the plaintext from the INPUT
449 command, writes to the ciphertext to the file descriptor set with
450 the OUTPUT command, take the recipients form all the recipients set
451 so far. If this command fails the clients should try to delete all
452 output currently done or otherwise mark it as invalid. GPGSM does
453 ensure that there won't be any security problem with leftover data
454 on the output in this case.
456 This command should in general not fail, as all necessary checks
457 have been done while setting the recipients. The input and output
458 pipes are closed. */
459 static int
460 cmd_encrypt (assuan_context_t ctx, char *line)
462 ctrl_t ctrl = assuan_get_pointer (ctx);
463 certlist_t cl;
464 int inp_fd, out_fd;
465 FILE *out_fp;
466 int rc;
468 (void)line;
470 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
471 if (inp_fd == -1)
472 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
473 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
474 if (out_fd == -1)
475 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
477 out_fp = fdopen (dup (out_fd), "w");
478 if (!out_fp)
479 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
481 /* Now add all encrypt-to marked recipients from the default
482 list. */
483 rc = 0;
484 if (!opt.no_encrypt_to)
486 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
487 if (cl->is_encrypt_to)
488 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
489 &ctrl->server_local->recplist, 1);
491 if (!rc)
492 rc = ctrl->audit? 0 : start_audit_session (ctrl);
493 if (!rc)
494 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
495 ctrl->server_local->recplist,
496 inp_fd, out_fp);
497 fclose (out_fp);
499 gpgsm_release_certlist (ctrl->server_local->recplist);
500 ctrl->server_local->recplist = NULL;
501 /* Close and reset the fd */
502 close_message_fd (ctrl);
503 assuan_close_input_fd (ctx);
504 assuan_close_output_fd (ctx);
505 return rc;
509 /* DECRYPT
511 This performs the decrypt operation after doing some check on the
512 internal state. (e.g. that only needed data has been set). Because
513 it utilizes the GPG-Agent for the session key decryption, there is
514 no need to ask the client for a protecting passphrase - GpgAgent
515 does take care of this by requesting this from the user. */
516 static int
517 cmd_decrypt (assuan_context_t ctx, char *line)
519 ctrl_t ctrl = assuan_get_pointer (ctx);
520 int inp_fd, out_fd;
521 FILE *out_fp;
522 int rc;
524 (void)line;
526 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
527 if (inp_fd == -1)
528 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
529 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
530 if (out_fd == -1)
531 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
533 out_fp = fdopen (dup(out_fd), "w");
534 if (!out_fp)
535 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
537 rc = start_audit_session (ctrl);
538 if (!rc)
539 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
540 fclose (out_fp);
542 /* close and reset the fd */
543 close_message_fd (ctrl);
544 assuan_close_input_fd (ctx);
545 assuan_close_output_fd (ctx);
547 return rc;
551 /* VERIFY
553 This does a verify operation on the message send to the input-FD.
554 The result is written out using status lines. If an output FD was
555 given, the signed text will be written to that.
557 If the signature is a detached one, the server will inquire about
558 the signed material and the client must provide it.
560 static int
561 cmd_verify (assuan_context_t ctx, char *line)
563 int rc;
564 ctrl_t ctrl = assuan_get_pointer (ctx);
565 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
566 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
567 FILE *out_fp = NULL;
569 (void)line;
571 if (fd == -1)
572 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
574 if (out_fd != -1)
576 out_fp = fdopen ( dup(out_fd), "w");
577 if (!out_fp)
578 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
581 rc = start_audit_session (ctrl);
582 if (!rc)
583 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
584 ctrl->server_local->message_fd, out_fp);
585 if (out_fp)
586 fclose (out_fp);
588 /* close and reset the fd */
589 close_message_fd (ctrl);
590 assuan_close_input_fd (ctx);
591 assuan_close_output_fd (ctx);
593 return rc;
597 /* SIGN [--detached]
599 Sign the data set with the INPUT command and write it to the sink
600 set by OUTPUT. With "--detached" specified, a detached signature is
601 created (surprise). */
602 static int
603 cmd_sign (assuan_context_t ctx, char *line)
605 ctrl_t ctrl = assuan_get_pointer (ctx);
606 int inp_fd, out_fd;
607 FILE *out_fp;
608 int detached;
609 int rc;
611 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
612 if (inp_fd == -1)
613 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
614 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
615 if (out_fd == -1)
616 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
618 detached = has_option (line, "--detached");
620 out_fp = fdopen ( dup(out_fd), "w");
621 if (!out_fp)
622 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
624 rc = start_audit_session (ctrl);
625 if (!rc)
626 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
627 inp_fd, detached, out_fp);
628 fclose (out_fp);
630 /* close and reset the fd */
631 close_message_fd (ctrl);
632 assuan_close_input_fd (ctx);
633 assuan_close_output_fd (ctx);
635 return rc;
639 /* IMPORT
641 Import the certificates read form the input-fd, return status
642 message for each imported one. The import checks the validity of
643 the certificate but not of the entire chain. It is possible to
644 import expired certificates. */
645 static int
646 cmd_import (assuan_context_t ctx, char *line)
648 ctrl_t ctrl = assuan_get_pointer (ctx);
649 int rc;
650 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
652 (void)line;
654 if (fd == -1)
655 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
657 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
659 /* close and reset the fd */
660 close_message_fd (ctrl);
661 assuan_close_input_fd (ctx);
662 assuan_close_output_fd (ctx);
664 return rc;
668 /* EXPORT [--data [--armor|--base64]] [--] pattern
672 static int
673 cmd_export (assuan_context_t ctx, char *line)
675 ctrl_t ctrl = assuan_get_pointer (ctx);
676 char *p;
677 strlist_t list, sl;
678 int use_data;
680 use_data = has_option (line, "--data");
682 if (use_data)
684 /* We need to override any possible setting done by an OUTPUT command. */
685 ctrl->create_pem = has_option (line, "--armor");
686 ctrl->create_base64 = has_option (line, "--base64");
689 line = skip_options (line);
691 /* Break the line down into an strlist_t. */
692 list = NULL;
693 for (p=line; *p; line = p)
695 while (*p && *p != ' ')
696 p++;
697 if (*p)
698 *p++ = 0;
699 if (*line)
701 sl = xtrymalloc (sizeof *sl + strlen (line));
702 if (!sl)
704 free_strlist (list);
705 return out_of_core ();
707 sl->flags = 0;
708 strcpy_escaped_plus (sl->d, line);
709 sl->next = list;
710 list = sl;
714 if (use_data)
716 estream_t stream;
718 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
719 if (!stream)
721 free_strlist (list);
722 return set_error (GPG_ERR_ASS_GENERAL,
723 "error setting up a data stream");
725 gpgsm_export (ctrl, list, NULL, stream);
726 es_fclose (stream);
728 else
730 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
731 FILE *out_fp;
733 if (fd == -1)
735 free_strlist (list);
736 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
738 out_fp = fdopen ( dup(fd), "w");
739 if (!out_fp)
741 free_strlist (list);
742 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
745 gpgsm_export (ctrl, list, out_fp, NULL);
746 fclose (out_fp);
749 free_strlist (list);
750 /* Close and reset the fds. */
751 close_message_fd (ctrl);
752 assuan_close_input_fd (ctx);
753 assuan_close_output_fd (ctx);
754 return 0;
758 static int
759 cmd_delkeys (assuan_context_t ctx, char *line)
761 ctrl_t ctrl = assuan_get_pointer (ctx);
762 char *p;
763 strlist_t list, sl;
764 int rc;
766 /* break the line down into an strlist_t */
767 list = NULL;
768 for (p=line; *p; line = p)
770 while (*p && *p != ' ')
771 p++;
772 if (*p)
773 *p++ = 0;
774 if (*line)
776 sl = xtrymalloc (sizeof *sl + strlen (line));
777 if (!sl)
779 free_strlist (list);
780 return out_of_core ();
782 sl->flags = 0;
783 strcpy_escaped_plus (sl->d, line);
784 sl->next = list;
785 list = sl;
789 rc = gpgsm_delete (ctrl, list);
790 free_strlist (list);
792 /* close and reset the fd */
793 close_message_fd (ctrl);
794 assuan_close_input_fd (ctx);
795 assuan_close_output_fd (ctx);
797 return rc;
802 /* MESSAGE FD=<n>
804 Set the file descriptor to read a message which is used with
805 detached signatures */
806 static int
807 cmd_message (assuan_context_t ctx, char *line)
809 int rc;
810 gnupg_fd_t sysfd;
811 int fd;
812 ctrl_t ctrl = assuan_get_pointer (ctx);
814 rc = assuan_command_parse_fd (ctx, line, &sysfd);
815 if (rc)
816 return rc;
817 fd = translate_sys2libc_fd (sysfd, 0);
818 if (fd == -1)
819 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
820 ctrl->server_local->message_fd = fd;
821 return 0;
824 /* LISTKEYS [<patterns>]
825 DUMPKEYS [<patterns>]
826 LISTSECRETKEYS [<patterns>]
827 DUMPSECRETKEYS [<patterns>]
829 static int
830 do_listkeys (assuan_context_t ctx, char *line, int mode)
832 ctrl_t ctrl = assuan_get_pointer (ctx);
833 estream_t fp;
834 char *p;
835 strlist_t list, sl;
836 unsigned int listmode;
837 gpg_error_t err;
839 /* Break the line down into an strlist. */
840 list = NULL;
841 for (p=line; *p; line = p)
843 while (*p && *p != ' ')
844 p++;
845 if (*p)
846 *p++ = 0;
847 if (*line)
849 sl = xtrymalloc (sizeof *sl + strlen (line));
850 if (!sl)
852 free_strlist (list);
853 return out_of_core ();
855 sl->flags = 0;
856 strcpy_escaped_plus (sl->d, line);
857 sl->next = list;
858 list = sl;
862 if (ctrl->server_local->list_to_output)
864 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
866 if ( outfd == -1 )
867 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
868 fp = es_fdopen ( dup (outfd), "w");
869 if (!fp)
870 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
872 else
874 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
875 if (!fp)
876 return set_error (GPG_ERR_ASS_GENERAL,
877 "error setting up a data stream");
880 ctrl->with_colons = 1;
881 listmode = mode;
882 if (ctrl->server_local->list_internal)
883 listmode |= (1<<6);
884 if (ctrl->server_local->list_external)
885 listmode |= (1<<7);
886 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
887 free_strlist (list);
888 es_fclose (fp);
889 if (ctrl->server_local->list_to_output)
890 assuan_close_output_fd (ctx);
891 return err;
894 static int
895 cmd_listkeys (assuan_context_t ctx, char *line)
897 return do_listkeys (ctx, line, 3);
900 static int
901 cmd_dumpkeys (assuan_context_t ctx, char *line)
903 return do_listkeys (ctx, line, 259);
906 static int
907 cmd_listsecretkeys (assuan_context_t ctx, char *line)
909 return do_listkeys (ctx, line, 2);
912 static int
913 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
915 return do_listkeys (ctx, line, 258);
919 /* GENKEY
921 Read the parameters in native format from the input fd and write a
922 certificate request to the output.
924 static int
925 cmd_genkey (assuan_context_t ctx, char *line)
927 ctrl_t ctrl = assuan_get_pointer (ctx);
928 int inp_fd, out_fd;
929 FILE *out_fp;
930 int rc;
931 estream_t in_stream;
933 (void)line;
935 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
936 if (inp_fd == -1)
937 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
938 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
939 if (out_fd == -1)
940 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
942 in_stream = es_fdopen_nc (inp_fd, "r");
943 if (!in_stream)
944 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
946 out_fp = fdopen ( dup(out_fd), "w");
947 if (!out_fp)
949 es_fclose (in_stream);
950 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
952 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
953 fclose (out_fp);
955 /* close and reset the fds */
956 assuan_close_input_fd (ctx);
957 assuan_close_output_fd (ctx);
959 return rc;
964 /* GETAUDITLOG [--data] [--html]
966 !!!WORK in PROGRESS!!!
968 If --data is used, the output is send using D-lines and not to the
969 source given by an OUTPUT command.
971 If --html is used the output is formated as an XHTML block. This is
972 designed to be incorporated into a HTML document.
974 static int
975 cmd_getauditlog (assuan_context_t ctx, char *line)
977 ctrl_t ctrl = assuan_get_pointer (ctx);
978 int out_fd;
979 estream_t out_stream;
980 int opt_data, opt_html;
981 int rc;
983 opt_data = has_option (line, "--data");
984 opt_html = has_option (line, "--html");
985 line = skip_options (line);
987 if (!ctrl->audit)
988 return gpg_error (GPG_ERR_NO_DATA);
990 if (opt_data)
992 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
993 if (!out_stream)
994 return set_error (GPG_ERR_ASS_GENERAL,
995 "error setting up a data stream");
997 else
999 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1000 if (out_fd == -1)
1001 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1003 out_stream = es_fdopen_nc ( dup (out_fd), "w");
1004 if (!out_stream)
1006 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1010 audit_print_result (ctrl->audit, out_stream, opt_html);
1011 rc = 0;
1013 es_fclose (out_stream);
1015 /* Close and reset the fd. */
1016 if (!opt_data)
1017 assuan_close_output_fd (ctx);
1018 return rc;
1022 /* GETINFO <what>
1024 Multipurpose function to return a variety of information.
1025 Supported values for WHAT are:
1027 version - Return the version of the program.
1028 pid - Return the process id of the server.
1029 agent-check - Return success if the agent is running.
1032 static int
1033 cmd_getinfo (assuan_context_t ctx, char *line)
1035 int rc;
1037 if (!strcmp (line, "version"))
1039 const char *s = VERSION;
1040 rc = assuan_send_data (ctx, s, strlen (s));
1042 else if (!strcmp (line, "pid"))
1044 char numbuf[50];
1046 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1047 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1049 else if (!strcmp (line, "agent-check"))
1051 ctrl_t ctrl = assuan_get_pointer (ctx);
1052 rc = gpgsm_agent_send_nop (ctrl);
1054 else
1055 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1056 return rc;
1061 /* Tell the assuan library about our commands */
1062 static int
1063 register_commands (assuan_context_t ctx)
1065 static struct {
1066 const char *name;
1067 int (*handler)(assuan_context_t, char *line);
1068 } table[] = {
1069 { "RECIPIENT", cmd_recipient },
1070 { "SIGNER", cmd_signer },
1071 { "ENCRYPT", cmd_encrypt },
1072 { "DECRYPT", cmd_decrypt },
1073 { "VERIFY", cmd_verify },
1074 { "SIGN", cmd_sign },
1075 { "IMPORT", cmd_import },
1076 { "EXPORT", cmd_export },
1077 { "INPUT", NULL },
1078 { "OUTPUT", NULL },
1079 { "MESSAGE", cmd_message },
1080 { "LISTKEYS", cmd_listkeys },
1081 { "DUMPKEYS", cmd_dumpkeys },
1082 { "LISTSECRETKEYS",cmd_listsecretkeys },
1083 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1084 { "GENKEY", cmd_genkey },
1085 { "DELKEYS", cmd_delkeys },
1086 { "GETAUDITLOG", cmd_getauditlog },
1087 { "GETINFO", cmd_getinfo },
1088 { NULL }
1090 int i, rc;
1092 for (i=0; table[i].name; i++)
1094 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1095 if (rc)
1096 return rc;
1098 return 0;
1101 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1102 set from the command line or config file. We only require those
1103 marked as encrypt-to. */
1104 void
1105 gpgsm_server (certlist_t default_recplist)
1107 int rc;
1108 int filedes[2];
1109 assuan_context_t ctx;
1110 struct server_control_s ctrl;
1111 static const char hello[] = ("GNU Privacy Guard's S/M server "
1112 VERSION " ready");
1114 memset (&ctrl, 0, sizeof ctrl);
1115 gpgsm_init_default_ctrl (&ctrl);
1117 /* We use a pipe based server so that we can work from scripts.
1118 assuan_init_pipe_server will automagically detect when we are
1119 called with a socketpair and ignore FIELDES in this case. */
1120 filedes[0] = 0;
1121 filedes[1] = 1;
1122 rc = assuan_init_pipe_server (&ctx, filedes);
1123 if (rc)
1125 log_error ("failed to initialize the server: %s\n",
1126 gpg_strerror (rc));
1127 gpgsm_exit (2);
1129 rc = register_commands (ctx);
1130 if (rc)
1132 log_error ("failed to the register commands with Assuan: %s\n",
1133 gpg_strerror(rc));
1134 gpgsm_exit (2);
1136 if (opt.verbose || opt.debug)
1138 char *tmp = NULL;
1139 const char *s1 = getenv ("GPG_AGENT_INFO");
1140 const char *s2 = getenv ("DIRMNGR_INFO");
1142 if (asprintf (&tmp,
1143 "Home: %s\n"
1144 "Config: %s\n"
1145 "AgentInfo: %s\n"
1146 "DirmngrInfo: %s\n"
1147 "%s",
1148 opt.homedir,
1149 opt.config_filename,
1150 s1?s1:"[not set]",
1151 s2?s2:"[not set]",
1152 hello) > 0)
1154 assuan_set_hello_line (ctx, tmp);
1155 free (tmp);
1158 else
1159 assuan_set_hello_line (ctx, hello);
1161 assuan_register_reset_notify (ctx, reset_notify);
1162 assuan_register_input_notify (ctx, input_notify);
1163 assuan_register_output_notify (ctx, output_notify);
1164 assuan_register_option_handler (ctx, option_handler);
1166 assuan_set_pointer (ctx, &ctrl);
1167 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1168 ctrl.server_local->assuan_ctx = ctx;
1169 ctrl.server_local->message_fd = -1;
1170 ctrl.server_local->list_internal = 1;
1171 ctrl.server_local->list_external = 0;
1172 ctrl.server_local->default_recplist = default_recplist;
1174 if (DBG_ASSUAN)
1175 assuan_set_log_stream (ctx, log_get_stream ());
1177 for (;;)
1179 rc = assuan_accept (ctx);
1180 if (rc == -1)
1182 break;
1184 else if (rc)
1186 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1187 break;
1190 rc = assuan_process (ctx);
1191 if (rc)
1193 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1194 continue;
1198 gpgsm_release_certlist (ctrl.server_local->recplist);
1199 ctrl.server_local->recplist = NULL;
1200 gpgsm_release_certlist (ctrl.server_local->signerlist);
1201 ctrl.server_local->signerlist = NULL;
1202 xfree (ctrl.server_local);
1204 audit_release (ctrl.audit);
1205 ctrl.audit = NULL;
1207 assuan_deinit_server (ctx);
1212 gpg_error_t
1213 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1215 gpg_error_t err = 0;
1216 va_list arg_ptr;
1217 const char *text;
1219 va_start (arg_ptr, no);
1221 if (ctrl->no_server && ctrl->status_fd == -1)
1222 ; /* No status wanted. */
1223 else if (ctrl->no_server)
1225 if (!statusfp)
1227 if (ctrl->status_fd == 1)
1228 statusfp = stdout;
1229 else if (ctrl->status_fd == 2)
1230 statusfp = stderr;
1231 else
1232 statusfp = fdopen (ctrl->status_fd, "w");
1234 if (!statusfp)
1236 log_fatal ("can't open fd %d for status output: %s\n",
1237 ctrl->status_fd, strerror(errno));
1241 fputs ("[GNUPG:] ", statusfp);
1242 fputs (get_status_string (no), statusfp);
1244 while ( (text = va_arg (arg_ptr, const char*) ))
1246 putc ( ' ', statusfp );
1247 for (; *text; text++)
1249 if (*text == '\n')
1250 fputs ( "\\n", statusfp );
1251 else if (*text == '\r')
1252 fputs ( "\\r", statusfp );
1253 else
1254 putc ( *(const byte *)text, statusfp );
1257 putc ('\n', statusfp);
1258 fflush (statusfp);
1260 else
1262 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1263 char buf[950], *p;
1264 size_t n;
1266 p = buf;
1267 n = 0;
1268 while ( (text = va_arg (arg_ptr, const char *)) )
1270 if (n)
1272 *p++ = ' ';
1273 n++;
1275 for ( ; *text && n < DIM (buf)-2; n++)
1276 *p++ = *text++;
1278 *p = 0;
1279 err = assuan_write_status (ctx, get_status_string (no), buf);
1282 va_end (arg_ptr);
1283 return err;
1286 gpg_error_t
1287 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1289 return gpgsm_status2 (ctrl, no, text, NULL);
1292 gpg_error_t
1293 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1294 gpg_err_code_t ec)
1296 char buf[30];
1298 sprintf (buf, "%u", (unsigned int)ec);
1299 if (text)
1300 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1301 else
1302 return gpgsm_status2 (ctrl, no, buf, NULL);
1306 /* Helper to notify the client about Pinentry events. Because that
1307 might disturb some older clients, this is only done when enabled
1308 via an option. Returns an gpg error code. */
1309 gpg_error_t
1310 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1312 if (!ctrl || !ctrl->server_local
1313 || !ctrl->server_local->allow_pinentry_notify)
1314 return 0;
1315 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);