Create a pkcs#10 request directly from a card.
[gnupg.git] / sm / server.c
blobdfd4f690fa11b25fe49c65a193dad3a687439294
1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006,
3 * 2007, 2008 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * GnuPG is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 #include <unistd.h>
30 #include <assuan.h>
32 #include "gpgsm.h"
33 #include "sysutils.h"
35 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
38 /* The filepointer for status message used in non-server mode */
39 static FILE *statusfp;
41 /* Data used to assuciate an Assuan context with local server data */
42 struct server_local_s {
43 assuan_context_t assuan_ctx;
44 int message_fd;
45 int list_internal;
46 int list_external;
47 int list_to_output; /* Write keylistings to the output fd. */
48 int enable_audit_log; /* Use an audit log. */
49 certlist_t recplist;
50 certlist_t signerlist;
51 certlist_t default_recplist; /* As set by main() - don't release. */
52 int allow_pinentry_notify; /* Set if pinentry notifications should
53 be passed back to the client. */
54 int no_encrypt_to; /* Local version of option. */
58 /* Cookie definition for assuan data line output. */
59 static ssize_t data_line_cookie_write (void *cookie,
60 const void *buffer, size_t size);
61 static int data_line_cookie_close (void *cookie);
62 static es_cookie_io_functions_t data_line_cookie_functions =
64 NULL,
65 data_line_cookie_write,
66 NULL,
67 data_line_cookie_close
73 /* Note that it is sufficient to allocate the target string D as
74 long as the source string S, i.e.: strlen(s)+1; */
75 static void
76 strcpy_escaped_plus (char *d, const char *s)
78 while (*s)
80 if (*s == '%' && s[1] && s[2])
82 s++;
83 *d++ = xtoi_2 (s);
84 s += 2;
86 else if (*s == '+')
87 *d++ = ' ', s++;
88 else
89 *d++ = *s++;
91 *d = 0;
95 /* Skip over options.
96 Blanks after the options are also removed. */
97 static char *
98 skip_options (const char *line)
100 while (spacep (line))
101 line++;
102 while ( *line == '-' && line[1] == '-' )
104 while (*line && !spacep (line))
105 line++;
106 while (spacep (line))
107 line++;
109 return (char*)line;
113 /* Check whether the option NAME appears in LINE */
114 static int
115 has_option (const char *line, const char *name)
117 const char *s;
118 int n = strlen (name);
120 s = strstr (line, name);
121 if (s && s >= skip_options (line))
122 return 0;
123 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
127 /* A write handler used by es_fopencookie to write assuan data
128 lines. */
129 static ssize_t
130 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
132 assuan_context_t ctx = cookie;
134 if (assuan_send_data (ctx, buffer, size))
136 errno = EIO;
137 return -1;
140 return size;
143 static int
144 data_line_cookie_close (void *cookie)
146 assuan_context_t ctx = cookie;
148 if (assuan_send_data (ctx, NULL, 0))
150 errno = EIO;
151 return -1;
154 return 0;
158 static void
159 close_message_fd (ctrl_t ctrl)
161 if (ctrl->server_local->message_fd != -1)
163 close (ctrl->server_local->message_fd);
164 ctrl->server_local->message_fd = -1;
169 /* Start a new audit session if this has been enabled. */
170 static gpg_error_t
171 start_audit_session (ctrl_t ctrl)
173 audit_release (ctrl->audit);
174 ctrl->audit = NULL;
175 if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
176 return gpg_error_from_syserror ();
178 return 0;
182 static int
183 option_handler (assuan_context_t ctx, const char *key, const char *value)
185 ctrl_t ctrl = assuan_get_pointer (ctx);
187 if (!strcmp (key, "include-certs"))
189 int i = *value? atoi (value) : -1;
190 if (ctrl->include_certs < -2)
191 return gpg_error (GPG_ERR_ASS_PARAMETER);
192 ctrl->include_certs = i;
194 else if (!strcmp (key, "display"))
196 if (opt.display)
197 free (opt.display);
198 opt.display = strdup (value);
199 if (!opt.display)
200 return out_of_core ();
202 else if (!strcmp (key, "ttyname"))
204 if (opt.ttyname)
205 free (opt.ttyname);
206 opt.ttyname = strdup (value);
207 if (!opt.ttyname)
208 return out_of_core ();
210 else if (!strcmp (key, "ttytype"))
212 if (opt.ttytype)
213 free (opt.ttytype);
214 opt.ttytype = strdup (value);
215 if (!opt.ttytype)
216 return out_of_core ();
218 else if (!strcmp (key, "lc-ctype"))
220 if (opt.lc_ctype)
221 free (opt.lc_ctype);
222 opt.lc_ctype = strdup (value);
223 if (!opt.lc_ctype)
224 return out_of_core ();
226 else if (!strcmp (key, "lc-messages"))
228 if (opt.lc_messages)
229 free (opt.lc_messages);
230 opt.lc_messages = strdup (value);
231 if (!opt.lc_messages)
232 return out_of_core ();
234 else if (!strcmp (key, "xauthority"))
236 if (opt.xauthority)
237 free (opt.xauthority);
238 opt.xauthority = strdup (value);
239 if (!opt.xauthority)
240 return out_of_core ();
242 else if (!strcmp (key, "pinentry-user-data"))
244 if (opt.pinentry_user_data)
245 free (opt.pinentry_user_data);
246 opt.pinentry_user_data = strdup (value);
247 if (!opt.pinentry_user_data)
248 return out_of_core ();
250 else if (!strcmp (key, "list-mode"))
252 int i = *value? atoi (value) : 0;
253 if (!i || i == 1) /* default and mode 1 */
255 ctrl->server_local->list_internal = 1;
256 ctrl->server_local->list_external = 0;
258 else if (i == 2)
260 ctrl->server_local->list_internal = 0;
261 ctrl->server_local->list_external = 1;
263 else if (i == 3)
265 ctrl->server_local->list_internal = 1;
266 ctrl->server_local->list_external = 1;
268 else
269 return gpg_error (GPG_ERR_ASS_PARAMETER);
271 else if (!strcmp (key, "list-to-output"))
273 int i = *value? atoi (value) : 0;
274 ctrl->server_local->list_to_output = i;
276 else if (!strcmp (key, "with-validation"))
278 int i = *value? atoi (value) : 0;
279 ctrl->with_validation = i;
281 else if (!strcmp (key, "validation-model"))
283 int i = gpgsm_parse_validation_model (value);
284 if ( i >= 0 && i <= 1 )
285 ctrl->validation_model = i;
286 else
287 return gpg_error (GPG_ERR_ASS_PARAMETER);
289 else if (!strcmp (key, "with-key-data"))
291 opt.with_key_data = 1;
293 else if (!strcmp (key, "enable-audit-log"))
295 int i = *value? atoi (value) : 0;
296 ctrl->server_local->enable_audit_log = i;
298 else if (!strcmp (key, "allow-pinentry-notify"))
299 ctrl->server_local->allow_pinentry_notify = 1;
300 else if (!strcmp (key, "with-ephemeral-keys"))
302 int i = *value? atoi (value) : 0;
303 ctrl->with_ephemeral_keys = i;
305 else if (!strcmp (key, "no-encrypt-to"))
307 ctrl->server_local->no_encrypt_to = 1;
309 else
310 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
312 return 0;
316 static void
317 reset_notify (assuan_context_t ctx)
319 ctrl_t ctrl = assuan_get_pointer (ctx);
321 gpgsm_release_certlist (ctrl->server_local->recplist);
322 gpgsm_release_certlist (ctrl->server_local->signerlist);
323 ctrl->server_local->recplist = NULL;
324 ctrl->server_local->signerlist = NULL;
325 close_message_fd (ctrl);
326 assuan_close_input_fd (ctx);
327 assuan_close_output_fd (ctx);
331 static void
332 input_notify (assuan_context_t ctx, const char *line)
334 ctrl_t ctrl = assuan_get_pointer (ctx);
336 ctrl->autodetect_encoding = 0;
337 ctrl->is_pem = 0;
338 ctrl->is_base64 = 0;
339 if (strstr (line, "--armor"))
340 ctrl->is_pem = 1;
341 else if (strstr (line, "--base64"))
342 ctrl->is_base64 = 1;
343 else if (strstr (line, "--binary"))
345 else
346 ctrl->autodetect_encoding = 1;
349 static void
350 output_notify (assuan_context_t ctx, const char *line)
352 ctrl_t ctrl = assuan_get_pointer (ctx);
354 ctrl->create_pem = 0;
355 ctrl->create_base64 = 0;
356 if (strstr (line, "--armor"))
357 ctrl->create_pem = 1;
358 else if (strstr (line, "--base64"))
359 ctrl->create_base64 = 1; /* just the raw output */
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 int
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 gpg_err_code_t r = gpg_err_code (rc);
392 gpgsm_status2 (ctrl, STATUS_INV_RECP,
393 r == -1? "1":
394 r == GPG_ERR_NO_PUBKEY? "1":
395 r == GPG_ERR_AMBIGUOUS_NAME? "2":
396 r == GPG_ERR_WRONG_KEY_USAGE? "3":
397 r == GPG_ERR_CERT_REVOKED? "4":
398 r == GPG_ERR_CERT_EXPIRED? "5":
399 r == GPG_ERR_NO_CRL_KNOWN? "6":
400 r == GPG_ERR_CRL_TOO_OLD? "7":
401 r == GPG_ERR_NO_POLICY_MATCH? "8":
402 r == GPG_ERR_MISSING_CERT? "11":
403 "0",
404 line, NULL);
407 return rc;
410 /* SIGNER <userID>
412 Set the signer's keys for the signature creation. <userID> should
413 be the internal representation of the key; the server may accept any
414 other way of specification [we will support this]. If this is a
415 valid and usable signing key the server does respond with OK,
416 otherwise it returns an ERR with the reason why the key can't be
417 used, the signing will then not be done for this key. If the policy
418 is not to sign at all if not all signer keys are valid, the client
419 has to take care of this. All SIGNER commands are cumulative until
420 a RESET but they are *not* reset by an SIGN command becuase it can
421 be expected that set of signers are used for more than one sign
422 operation.
424 Note that this command returns an INV_RECP status which is a bit
425 strange, but they are very similar. */
426 static int
427 cmd_signer (assuan_context_t ctx, char *line)
429 ctrl_t ctrl = assuan_get_pointer (ctx);
430 int rc;
432 rc = gpgsm_add_to_certlist (ctrl, line, 1,
433 &ctrl->server_local->signerlist, 0);
434 if (rc)
436 gpg_err_code_t r = gpg_err_code (rc);
437 gpgsm_status2 (ctrl, STATUS_INV_RECP,
438 r == -1? "1":
439 r == GPG_ERR_NO_PUBKEY? "1":
440 r == GPG_ERR_AMBIGUOUS_NAME? "2":
441 r == GPG_ERR_WRONG_KEY_USAGE? "3":
442 r == GPG_ERR_CERT_REVOKED? "4":
443 r == GPG_ERR_CERT_EXPIRED? "5":
444 r == GPG_ERR_NO_CRL_KNOWN? "6":
445 r == GPG_ERR_CRL_TOO_OLD? "7":
446 r == GPG_ERR_NO_POLICY_MATCH? "8":
447 r == GPG_ERR_NO_SECKEY? "9":
448 r == GPG_ERR_MISSING_CERT? "11":
449 "0",
450 line, NULL);
452 return rc;
456 /* ENCRYPT
458 Do the actual encryption process. Takes the plaintext from the INPUT
459 command, writes to the ciphertext to the file descriptor set with
460 the OUTPUT command, take the recipients form all the recipients set
461 so far. If this command fails the clients should try to delete all
462 output currently done or otherwise mark it as invalid. GPGSM does
463 ensure that there won't be any security problem with leftover data
464 on the output in this case.
466 This command should in general not fail, as all necessary checks
467 have been done while setting the recipients. The input and output
468 pipes are closed. */
469 static int
470 cmd_encrypt (assuan_context_t ctx, char *line)
472 ctrl_t ctrl = assuan_get_pointer (ctx);
473 certlist_t cl;
474 int inp_fd, out_fd;
475 FILE *out_fp;
476 int rc;
478 (void)line;
480 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
481 if (inp_fd == -1)
482 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
483 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
484 if (out_fd == -1)
485 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
487 out_fp = fdopen (dup (out_fd), "w");
488 if (!out_fp)
489 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
491 /* Now add all encrypt-to marked recipients from the default
492 list. */
493 rc = 0;
494 if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
496 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
497 if (cl->is_encrypt_to)
498 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
499 &ctrl->server_local->recplist, 1);
501 if (!rc)
502 rc = ctrl->audit? 0 : start_audit_session (ctrl);
503 if (!rc)
504 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
505 ctrl->server_local->recplist,
506 inp_fd, out_fp);
507 fclose (out_fp);
509 gpgsm_release_certlist (ctrl->server_local->recplist);
510 ctrl->server_local->recplist = NULL;
511 /* Close and reset the fd */
512 close_message_fd (ctrl);
513 assuan_close_input_fd (ctx);
514 assuan_close_output_fd (ctx);
515 return rc;
519 /* DECRYPT
521 This performs the decrypt operation after doing some check on the
522 internal state. (e.g. that only needed data has been set). Because
523 it utilizes the GPG-Agent for the session key decryption, there is
524 no need to ask the client for a protecting passphrase - GpgAgent
525 does take care of this by requesting this from the user. */
526 static int
527 cmd_decrypt (assuan_context_t ctx, char *line)
529 ctrl_t ctrl = assuan_get_pointer (ctx);
530 int inp_fd, out_fd;
531 FILE *out_fp;
532 int rc;
534 (void)line;
536 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
537 if (inp_fd == -1)
538 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
539 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
540 if (out_fd == -1)
541 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
543 out_fp = fdopen (dup(out_fd), "w");
544 if (!out_fp)
545 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
547 rc = start_audit_session (ctrl);
548 if (!rc)
549 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
550 fclose (out_fp);
552 /* close and reset the fd */
553 close_message_fd (ctrl);
554 assuan_close_input_fd (ctx);
555 assuan_close_output_fd (ctx);
557 return rc;
561 /* VERIFY
563 This does a verify operation on the message send to the input-FD.
564 The result is written out using status lines. If an output FD was
565 given, the signed text will be written to that.
567 If the signature is a detached one, the server will inquire about
568 the signed material and the client must provide it.
570 static int
571 cmd_verify (assuan_context_t ctx, char *line)
573 int rc;
574 ctrl_t ctrl = assuan_get_pointer (ctx);
575 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
576 int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
577 FILE *out_fp = NULL;
579 (void)line;
581 if (fd == -1)
582 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
584 if (out_fd != -1)
586 out_fp = fdopen ( dup(out_fd), "w");
587 if (!out_fp)
588 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
591 rc = start_audit_session (ctrl);
592 if (!rc)
593 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
594 ctrl->server_local->message_fd, out_fp);
595 if (out_fp)
596 fclose (out_fp);
598 /* close and reset the fd */
599 close_message_fd (ctrl);
600 assuan_close_input_fd (ctx);
601 assuan_close_output_fd (ctx);
603 return rc;
607 /* SIGN [--detached]
609 Sign the data set with the INPUT command and write it to the sink
610 set by OUTPUT. With "--detached" specified, a detached signature is
611 created (surprise). */
612 static int
613 cmd_sign (assuan_context_t ctx, char *line)
615 ctrl_t ctrl = assuan_get_pointer (ctx);
616 int inp_fd, out_fd;
617 FILE *out_fp;
618 int detached;
619 int rc;
621 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
622 if (inp_fd == -1)
623 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
624 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
625 if (out_fd == -1)
626 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
628 detached = has_option (line, "--detached");
630 out_fp = fdopen ( dup(out_fd), "w");
631 if (!out_fp)
632 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
634 rc = start_audit_session (ctrl);
635 if (!rc)
636 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
637 inp_fd, detached, out_fp);
638 fclose (out_fp);
640 /* close and reset the fd */
641 close_message_fd (ctrl);
642 assuan_close_input_fd (ctx);
643 assuan_close_output_fd (ctx);
645 return rc;
649 /* IMPORT
651 Import the certificates read form the input-fd, return status
652 message for each imported one. The import checks the validity of
653 the certificate but not of the entire chain. It is possible to
654 import expired certificates. */
655 static int
656 cmd_import (assuan_context_t ctx, char *line)
658 ctrl_t ctrl = assuan_get_pointer (ctx);
659 int rc;
660 int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
662 (void)line;
664 if (fd == -1)
665 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
667 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
669 /* close and reset the fd */
670 close_message_fd (ctrl);
671 assuan_close_input_fd (ctx);
672 assuan_close_output_fd (ctx);
674 return rc;
678 /* EXPORT [--data [--armor|--base64]] [--] pattern
682 static int
683 cmd_export (assuan_context_t ctx, char *line)
685 ctrl_t ctrl = assuan_get_pointer (ctx);
686 char *p;
687 strlist_t list, sl;
688 int use_data;
690 use_data = has_option (line, "--data");
692 if (use_data)
694 /* We need to override any possible setting done by an OUTPUT command. */
695 ctrl->create_pem = has_option (line, "--armor");
696 ctrl->create_base64 = has_option (line, "--base64");
699 line = skip_options (line);
701 /* Break the line down into an strlist_t. */
702 list = NULL;
703 for (p=line; *p; line = p)
705 while (*p && *p != ' ')
706 p++;
707 if (*p)
708 *p++ = 0;
709 if (*line)
711 sl = xtrymalloc (sizeof *sl + strlen (line));
712 if (!sl)
714 free_strlist (list);
715 return out_of_core ();
717 sl->flags = 0;
718 strcpy_escaped_plus (sl->d, line);
719 sl->next = list;
720 list = sl;
724 if (use_data)
726 estream_t stream;
728 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
729 if (!stream)
731 free_strlist (list);
732 return set_error (GPG_ERR_ASS_GENERAL,
733 "error setting up a data stream");
735 gpgsm_export (ctrl, list, NULL, stream);
736 es_fclose (stream);
738 else
740 int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
741 FILE *out_fp;
743 if (fd == -1)
745 free_strlist (list);
746 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
748 out_fp = fdopen ( dup(fd), "w");
749 if (!out_fp)
751 free_strlist (list);
752 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
755 gpgsm_export (ctrl, list, out_fp, NULL);
756 fclose (out_fp);
759 free_strlist (list);
760 /* Close and reset the fds. */
761 close_message_fd (ctrl);
762 assuan_close_input_fd (ctx);
763 assuan_close_output_fd (ctx);
764 return 0;
768 static int
769 cmd_delkeys (assuan_context_t ctx, char *line)
771 ctrl_t ctrl = assuan_get_pointer (ctx);
772 char *p;
773 strlist_t list, sl;
774 int rc;
776 /* break the line down into an strlist_t */
777 list = NULL;
778 for (p=line; *p; line = p)
780 while (*p && *p != ' ')
781 p++;
782 if (*p)
783 *p++ = 0;
784 if (*line)
786 sl = xtrymalloc (sizeof *sl + strlen (line));
787 if (!sl)
789 free_strlist (list);
790 return out_of_core ();
792 sl->flags = 0;
793 strcpy_escaped_plus (sl->d, line);
794 sl->next = list;
795 list = sl;
799 rc = gpgsm_delete (ctrl, list);
800 free_strlist (list);
802 /* close and reset the fd */
803 close_message_fd (ctrl);
804 assuan_close_input_fd (ctx);
805 assuan_close_output_fd (ctx);
807 return rc;
812 /* MESSAGE FD=<n>
814 Set the file descriptor to read a message which is used with
815 detached signatures */
816 static int
817 cmd_message (assuan_context_t ctx, char *line)
819 int rc;
820 gnupg_fd_t sysfd;
821 int fd;
822 ctrl_t ctrl = assuan_get_pointer (ctx);
824 rc = assuan_command_parse_fd (ctx, line, &sysfd);
825 if (rc)
826 return rc;
827 fd = translate_sys2libc_fd (sysfd, 0);
828 if (fd == -1)
829 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
830 ctrl->server_local->message_fd = fd;
831 return 0;
834 /* LISTKEYS [<patterns>]
835 DUMPKEYS [<patterns>]
836 LISTSECRETKEYS [<patterns>]
837 DUMPSECRETKEYS [<patterns>]
839 static int
840 do_listkeys (assuan_context_t ctx, char *line, int mode)
842 ctrl_t ctrl = assuan_get_pointer (ctx);
843 estream_t fp;
844 char *p;
845 strlist_t list, sl;
846 unsigned int listmode;
847 gpg_error_t err;
849 /* Break the line down into an strlist. */
850 list = NULL;
851 for (p=line; *p; line = p)
853 while (*p && *p != ' ')
854 p++;
855 if (*p)
856 *p++ = 0;
857 if (*line)
859 sl = xtrymalloc (sizeof *sl + strlen (line));
860 if (!sl)
862 free_strlist (list);
863 return out_of_core ();
865 sl->flags = 0;
866 strcpy_escaped_plus (sl->d, line);
867 sl->next = list;
868 list = sl;
872 if (ctrl->server_local->list_to_output)
874 int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
876 if ( outfd == -1 )
877 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
878 fp = es_fdopen ( dup (outfd), "w");
879 if (!fp)
880 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
882 else
884 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
885 if (!fp)
886 return set_error (GPG_ERR_ASS_GENERAL,
887 "error setting up a data stream");
890 ctrl->with_colons = 1;
891 listmode = mode;
892 if (ctrl->server_local->list_internal)
893 listmode |= (1<<6);
894 if (ctrl->server_local->list_external)
895 listmode |= (1<<7);
896 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
897 free_strlist (list);
898 es_fclose (fp);
899 if (ctrl->server_local->list_to_output)
900 assuan_close_output_fd (ctx);
901 return err;
904 static int
905 cmd_listkeys (assuan_context_t ctx, char *line)
907 return do_listkeys (ctx, line, 3);
910 static int
911 cmd_dumpkeys (assuan_context_t ctx, char *line)
913 return do_listkeys (ctx, line, 259);
916 static int
917 cmd_listsecretkeys (assuan_context_t ctx, char *line)
919 return do_listkeys (ctx, line, 2);
922 static int
923 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
925 return do_listkeys (ctx, line, 258);
929 /* GENKEY
931 Read the parameters in native format from the input fd and write a
932 certificate request to the output.
934 static int
935 cmd_genkey (assuan_context_t ctx, char *line)
937 ctrl_t ctrl = assuan_get_pointer (ctx);
938 int inp_fd, out_fd;
939 FILE *out_fp;
940 int rc;
941 estream_t in_stream;
943 (void)line;
945 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
946 if (inp_fd == -1)
947 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
948 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
949 if (out_fd == -1)
950 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
952 in_stream = es_fdopen_nc (inp_fd, "r");
953 if (!in_stream)
954 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
956 out_fp = fdopen ( dup(out_fd), "w");
957 if (!out_fp)
959 es_fclose (in_stream);
960 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
962 rc = gpgsm_genkey (ctrl, in_stream, out_fp);
963 fclose (out_fp);
965 /* close and reset the fds */
966 assuan_close_input_fd (ctx);
967 assuan_close_output_fd (ctx);
969 return rc;
974 /* GETAUDITLOG [--data] [--html]
976 !!!WORK in PROGRESS!!!
978 If --data is used, the output is send using D-lines and not to the
979 source given by an OUTPUT command.
981 If --html is used the output is formated as an XHTML block. This is
982 designed to be incorporated into a HTML document.
984 static int
985 cmd_getauditlog (assuan_context_t ctx, char *line)
987 ctrl_t ctrl = assuan_get_pointer (ctx);
988 int out_fd;
989 estream_t out_stream;
990 int opt_data, opt_html;
991 int rc;
993 opt_data = has_option (line, "--data");
994 opt_html = has_option (line, "--html");
995 line = skip_options (line);
997 if (!ctrl->audit)
998 return gpg_error (GPG_ERR_NO_DATA);
1000 if (opt_data)
1002 out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1003 if (!out_stream)
1004 return set_error (GPG_ERR_ASS_GENERAL,
1005 "error setting up a data stream");
1007 else
1009 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1010 if (out_fd == -1)
1011 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1013 out_stream = es_fdopen_nc ( dup (out_fd), "w");
1014 if (!out_stream)
1016 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1020 audit_print_result (ctrl->audit, out_stream, opt_html);
1021 rc = 0;
1023 es_fclose (out_stream);
1025 /* Close and reset the fd. */
1026 if (!opt_data)
1027 assuan_close_output_fd (ctx);
1028 return rc;
1032 /* GETINFO <what>
1034 Multipurpose function to return a variety of information.
1035 Supported values for WHAT are:
1037 version - Return the version of the program.
1038 pid - Return the process id of the server.
1039 agent-check - Return success if the agent is running.
1042 static int
1043 cmd_getinfo (assuan_context_t ctx, char *line)
1045 int rc;
1047 if (!strcmp (line, "version"))
1049 const char *s = VERSION;
1050 rc = assuan_send_data (ctx, s, strlen (s));
1052 else if (!strcmp (line, "pid"))
1054 char numbuf[50];
1056 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1057 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1059 else if (!strcmp (line, "agent-check"))
1061 ctrl_t ctrl = assuan_get_pointer (ctx);
1062 rc = gpgsm_agent_send_nop (ctrl);
1064 else
1065 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1066 return rc;
1071 /* Tell the assuan library about our commands */
1072 static int
1073 register_commands (assuan_context_t ctx)
1075 static struct {
1076 const char *name;
1077 int (*handler)(assuan_context_t, char *line);
1078 } table[] = {
1079 { "RECIPIENT", cmd_recipient },
1080 { "SIGNER", cmd_signer },
1081 { "ENCRYPT", cmd_encrypt },
1082 { "DECRYPT", cmd_decrypt },
1083 { "VERIFY", cmd_verify },
1084 { "SIGN", cmd_sign },
1085 { "IMPORT", cmd_import },
1086 { "EXPORT", cmd_export },
1087 { "INPUT", NULL },
1088 { "OUTPUT", NULL },
1089 { "MESSAGE", cmd_message },
1090 { "LISTKEYS", cmd_listkeys },
1091 { "DUMPKEYS", cmd_dumpkeys },
1092 { "LISTSECRETKEYS",cmd_listsecretkeys },
1093 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
1094 { "GENKEY", cmd_genkey },
1095 { "DELKEYS", cmd_delkeys },
1096 { "GETAUDITLOG", cmd_getauditlog },
1097 { "GETINFO", cmd_getinfo },
1098 { NULL }
1100 int i, rc;
1102 for (i=0; table[i].name; i++)
1104 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
1105 if (rc)
1106 return rc;
1108 return 0;
1111 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1112 set from the command line or config file. We only require those
1113 marked as encrypt-to. */
1114 void
1115 gpgsm_server (certlist_t default_recplist)
1117 int rc;
1118 int filedes[2];
1119 assuan_context_t ctx;
1120 struct server_control_s ctrl;
1121 static const char hello[] = ("GNU Privacy Guard's S/M server "
1122 VERSION " ready");
1124 memset (&ctrl, 0, sizeof ctrl);
1125 gpgsm_init_default_ctrl (&ctrl);
1127 /* We use a pipe based server so that we can work from scripts.
1128 assuan_init_pipe_server will automagically detect when we are
1129 called with a socketpair and ignore FIELDES in this case. */
1130 filedes[0] = 0;
1131 filedes[1] = 1;
1132 rc = assuan_init_pipe_server (&ctx, filedes);
1133 if (rc)
1135 log_error ("failed to initialize the server: %s\n",
1136 gpg_strerror (rc));
1137 gpgsm_exit (2);
1139 rc = register_commands (ctx);
1140 if (rc)
1142 log_error ("failed to the register commands with Assuan: %s\n",
1143 gpg_strerror(rc));
1144 gpgsm_exit (2);
1146 if (opt.verbose || opt.debug)
1148 char *tmp = NULL;
1149 const char *s1 = getenv ("GPG_AGENT_INFO");
1150 const char *s2 = getenv ("DIRMNGR_INFO");
1152 if (asprintf (&tmp,
1153 "Home: %s\n"
1154 "Config: %s\n"
1155 "AgentInfo: %s\n"
1156 "DirmngrInfo: %s\n"
1157 "%s",
1158 opt.homedir,
1159 opt.config_filename,
1160 s1?s1:"[not set]",
1161 s2?s2:"[not set]",
1162 hello) > 0)
1164 assuan_set_hello_line (ctx, tmp);
1165 free (tmp);
1168 else
1169 assuan_set_hello_line (ctx, hello);
1171 assuan_register_reset_notify (ctx, reset_notify);
1172 assuan_register_input_notify (ctx, input_notify);
1173 assuan_register_output_notify (ctx, output_notify);
1174 assuan_register_option_handler (ctx, option_handler);
1176 assuan_set_pointer (ctx, &ctrl);
1177 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1178 ctrl.server_local->assuan_ctx = ctx;
1179 ctrl.server_local->message_fd = -1;
1180 ctrl.server_local->list_internal = 1;
1181 ctrl.server_local->list_external = 0;
1182 ctrl.server_local->default_recplist = default_recplist;
1184 if (DBG_ASSUAN)
1185 assuan_set_log_stream (ctx, log_get_stream ());
1187 for (;;)
1189 rc = assuan_accept (ctx);
1190 if (rc == -1)
1192 break;
1194 else if (rc)
1196 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1197 break;
1200 rc = assuan_process (ctx);
1201 if (rc)
1203 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1204 continue;
1208 gpgsm_release_certlist (ctrl.server_local->recplist);
1209 ctrl.server_local->recplist = NULL;
1210 gpgsm_release_certlist (ctrl.server_local->signerlist);
1211 ctrl.server_local->signerlist = NULL;
1212 xfree (ctrl.server_local);
1214 audit_release (ctrl.audit);
1215 ctrl.audit = NULL;
1217 assuan_deinit_server (ctx);
1222 gpg_error_t
1223 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1225 gpg_error_t err = 0;
1226 va_list arg_ptr;
1227 const char *text;
1229 va_start (arg_ptr, no);
1231 if (ctrl->no_server && ctrl->status_fd == -1)
1232 ; /* No status wanted. */
1233 else if (ctrl->no_server)
1235 if (!statusfp)
1237 if (ctrl->status_fd == 1)
1238 statusfp = stdout;
1239 else if (ctrl->status_fd == 2)
1240 statusfp = stderr;
1241 else
1242 statusfp = fdopen (ctrl->status_fd, "w");
1244 if (!statusfp)
1246 log_fatal ("can't open fd %d for status output: %s\n",
1247 ctrl->status_fd, strerror(errno));
1251 fputs ("[GNUPG:] ", statusfp);
1252 fputs (get_status_string (no), statusfp);
1254 while ( (text = va_arg (arg_ptr, const char*) ))
1256 putc ( ' ', statusfp );
1257 for (; *text; text++)
1259 if (*text == '\n')
1260 fputs ( "\\n", statusfp );
1261 else if (*text == '\r')
1262 fputs ( "\\r", statusfp );
1263 else
1264 putc ( *(const byte *)text, statusfp );
1267 putc ('\n', statusfp);
1268 fflush (statusfp);
1270 else
1272 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1273 char buf[950], *p;
1274 size_t n;
1276 p = buf;
1277 n = 0;
1278 while ( (text = va_arg (arg_ptr, const char *)) )
1280 if (n)
1282 *p++ = ' ';
1283 n++;
1285 for ( ; *text && n < DIM (buf)-2; n++)
1286 *p++ = *text++;
1288 *p = 0;
1289 err = assuan_write_status (ctx, get_status_string (no), buf);
1292 va_end (arg_ptr);
1293 return err;
1296 gpg_error_t
1297 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1299 return gpgsm_status2 (ctrl, no, text, NULL);
1302 gpg_error_t
1303 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1304 gpg_err_code_t ec)
1306 char buf[30];
1308 sprintf (buf, "%u", (unsigned int)ec);
1309 if (text)
1310 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1311 else
1312 return gpgsm_status2 (ctrl, no, buf, NULL);
1316 /* Helper to notify the client about Pinentry events. Because that
1317 might disturb some older clients, this is only done when enabled
1318 via an option. Returns an gpg error code. */
1319 gpg_error_t
1320 gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1322 if (!ctrl || !ctrl->server_local
1323 || !ctrl->server_local->allow_pinentry_notify)
1324 return 0;
1325 return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);