2007-07-05 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / server.c
blob6f11b27344b38503779f24863a9c417f45271875
1 /* server.c - Server mode and main entry point
2 * Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <ctype.h>
27 #include <unistd.h>
29 #include <assuan.h>
31 #include "gpgsm.h"
33 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
36 /* The filepointer for status message used in non-server mode */
37 static FILE *statusfp;
39 /* Data used to assuciate an Assuan context with local server data */
40 struct server_local_s {
41 assuan_context_t assuan_ctx;
42 int message_fd;
43 int list_internal;
44 int list_external;
45 int list_to_output; /* Write keylistings to the output fd. */
46 certlist_t recplist;
47 certlist_t signerlist;
48 certlist_t default_recplist; /* As set by main() - don't release. */
52 /* Cookie definition for assuan data line output. */
53 static ssize_t data_line_cookie_write (void *cookie,
54 const void *buffer, size_t size);
55 static int data_line_cookie_close (void *cookie);
56 static es_cookie_io_functions_t data_line_cookie_functions =
58 NULL,
59 data_line_cookie_write,
60 NULL,
61 data_line_cookie_close
67 /* Note that it is sufficient to allocate the target string D as
68 long as the source string S, i.e.: strlen(s)+1; */
69 static void
70 strcpy_escaped_plus (char *d, const char *s)
72 while (*s)
74 if (*s == '%' && s[1] && s[2])
76 s++;
77 *d++ = xtoi_2 (s);
78 s += 2;
80 else if (*s == '+')
81 *d++ = ' ', s++;
82 else
83 *d++ = *s++;
85 *d = 0;
89 /* Skip over options.
90 Blanks after the options are also removed. */
91 static char *
92 skip_options (const char *line)
94 while (spacep (line))
95 line++;
96 while ( *line == '-' && line[1] == '-' )
98 while (*line && !spacep (line))
99 line++;
100 while (spacep (line))
101 line++;
103 return (char*)line;
107 /* Check whether the option NAME appears in LINE */
108 static int
109 has_option (const char *line, const char *name)
111 const char *s;
112 int n = strlen (name);
114 s = strstr (line, name);
115 if (s && s >= skip_options (line))
116 return 0;
117 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
121 /* A write handler used by es_fopencookie to write assuan data
122 lines. */
123 static ssize_t
124 data_line_cookie_write (void *cookie, const void *buffer, size_t size)
126 assuan_context_t ctx = cookie;
128 if (assuan_send_data (ctx, buffer, size))
130 errno = EIO;
131 return -1;
134 return size;
137 static int
138 data_line_cookie_close (void *cookie)
140 assuan_context_t ctx = cookie;
142 if (assuan_send_data (ctx, NULL, 0))
144 errno = EIO;
145 return -1;
148 return 0;
152 static void
153 close_message_fd (ctrl_t ctrl)
155 if (ctrl->server_local->message_fd != -1)
157 close (ctrl->server_local->message_fd);
158 ctrl->server_local->message_fd = -1;
163 static int
164 option_handler (assuan_context_t ctx, const char *key, const char *value)
166 ctrl_t ctrl = assuan_get_pointer (ctx);
168 if (!strcmp (key, "include-certs"))
170 int i = *value? atoi (value) : -1;
171 if (ctrl->include_certs < -2)
172 return gpg_error (GPG_ERR_ASS_PARAMETER);
173 ctrl->include_certs = i;
175 else if (!strcmp (key, "display"))
177 if (opt.display)
178 free (opt.display);
179 opt.display = strdup (value);
180 if (!opt.display)
181 return out_of_core ();
183 else if (!strcmp (key, "ttyname"))
185 if (opt.ttyname)
186 free (opt.ttyname);
187 opt.ttyname = strdup (value);
188 if (!opt.ttyname)
189 return out_of_core ();
191 else if (!strcmp (key, "ttytype"))
193 if (opt.ttytype)
194 free (opt.ttytype);
195 opt.ttytype = strdup (value);
196 if (!opt.ttytype)
197 return out_of_core ();
199 else if (!strcmp (key, "lc-ctype"))
201 if (opt.lc_ctype)
202 free (opt.lc_ctype);
203 opt.lc_ctype = strdup (value);
204 if (!opt.lc_ctype)
205 return out_of_core ();
207 else if (!strcmp (key, "lc-messages"))
209 if (opt.lc_messages)
210 free (opt.lc_messages);
211 opt.lc_messages = strdup (value);
212 if (!opt.lc_messages)
213 return out_of_core ();
215 else if (!strcmp (key, "list-mode"))
217 int i = *value? atoi (value) : 0;
218 if (!i || i == 1) /* default and mode 1 */
220 ctrl->server_local->list_internal = 1;
221 ctrl->server_local->list_external = 0;
223 else if (i == 2)
225 ctrl->server_local->list_internal = 0;
226 ctrl->server_local->list_external = 1;
228 else if (i == 3)
230 ctrl->server_local->list_internal = 1;
231 ctrl->server_local->list_external = 1;
233 else
234 return gpg_error (GPG_ERR_ASS_PARAMETER);
236 else if (!strcmp (key, "list-to-output"))
238 int i = *value? atoi (value) : 0;
239 ctrl->server_local->list_to_output = i;
241 else if (!strcmp (key, "with-validation"))
243 int i = *value? atoi (value) : 0;
244 ctrl->with_validation = i;
246 else if (!strcmp (key, "with-key-data"))
248 opt.with_key_data = 1;
250 else
251 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
253 return 0;
259 static void
260 reset_notify (assuan_context_t ctx)
262 ctrl_t ctrl = assuan_get_pointer (ctx);
264 gpgsm_release_certlist (ctrl->server_local->recplist);
265 gpgsm_release_certlist (ctrl->server_local->signerlist);
266 ctrl->server_local->recplist = NULL;
267 ctrl->server_local->signerlist = NULL;
268 close_message_fd (ctrl);
269 assuan_close_input_fd (ctx);
270 assuan_close_output_fd (ctx);
274 static void
275 input_notify (assuan_context_t ctx, const char *line)
277 ctrl_t ctrl = assuan_get_pointer (ctx);
279 ctrl->autodetect_encoding = 0;
280 ctrl->is_pem = 0;
281 ctrl->is_base64 = 0;
282 if (strstr (line, "--armor"))
283 ctrl->is_pem = 1;
284 else if (strstr (line, "--base64"))
285 ctrl->is_base64 = 1;
286 else if (strstr (line, "--binary"))
288 else
289 ctrl->autodetect_encoding = 1;
292 static void
293 output_notify (assuan_context_t ctx, const char *line)
295 ctrl_t ctrl = assuan_get_pointer (ctx);
297 ctrl->create_pem = 0;
298 ctrl->create_base64 = 0;
299 if (strstr (line, "--armor"))
300 ctrl->create_pem = 1;
301 else if (strstr (line, "--base64"))
302 ctrl->create_base64 = 1; /* just the raw output */
307 /* RECIPIENT <userID>
309 Set the recipient for the encryption. <userID> should be the
310 internal representation of the key; the server may accept any other
311 way of specification [we will support this]. If this is a valid and
312 trusted recipient the server does respond with OK, otherwise the
313 return is an ERR with the reason why the recipient can't be used,
314 the encryption will then not be done for this recipient. If the
315 policy is not to encrypt at all if not all recipients are valid, the
316 client has to take care of this. All RECIPIENT commands are
317 cumulative until a RESET or an successful ENCRYPT command. */
318 static int
319 cmd_recipient (assuan_context_t ctx, char *line)
321 ctrl_t ctrl = assuan_get_pointer (ctx);
322 int rc;
324 rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist, 0);
325 if (rc)
327 gpg_err_code_t r = gpg_err_code (rc);
328 gpgsm_status2 (ctrl, STATUS_INV_RECP,
329 r == -1? "1":
330 r == GPG_ERR_NO_PUBKEY? "1":
331 r == GPG_ERR_AMBIGUOUS_NAME? "2":
332 r == GPG_ERR_WRONG_KEY_USAGE? "3":
333 r == GPG_ERR_CERT_REVOKED? "4":
334 r == GPG_ERR_CERT_EXPIRED? "5":
335 r == GPG_ERR_NO_CRL_KNOWN? "6":
336 r == GPG_ERR_CRL_TOO_OLD? "7":
337 r == GPG_ERR_NO_POLICY_MATCH? "8":
338 "0",
339 line, NULL);
342 return rc;
345 /* SIGNER <userID>
347 Set the signer's keys for the signature creation. <userID> should
348 be the internal representation of the key; the server may accept any
349 other way of specification [we will support this]. If this is a
350 valid and usable signing key the server does respond with OK,
351 otherwise it returns an ERR with the reason why the key can't be
352 used, the signing will then not be done for this key. If the policy
353 is not to sign at all if not all signer keys are valid, the client
354 has to take care of this. All SIGNER commands are cumulative until
355 a RESET but they are *not* reset by an SIGN command becuase it can
356 be expected that set of signers are used for more than one sign
357 operation.
359 Note that this command returns an INV_RECP status which is a bit
360 strange, but they are very similar. */
361 static int
362 cmd_signer (assuan_context_t ctx, char *line)
364 ctrl_t ctrl = assuan_get_pointer (ctx);
365 int rc;
367 rc = gpgsm_add_to_certlist (ctrl, line, 1,
368 &ctrl->server_local->signerlist, 0);
369 if (rc)
371 gpg_err_code_t r = gpg_err_code (rc);
372 gpgsm_status2 (ctrl, STATUS_INV_RECP,
373 r == -1? "1":
374 r == GPG_ERR_NO_PUBKEY? "1":
375 r == GPG_ERR_AMBIGUOUS_NAME? "2":
376 r == GPG_ERR_WRONG_KEY_USAGE? "3":
377 r == GPG_ERR_CERT_REVOKED? "4":
378 r == GPG_ERR_CERT_EXPIRED? "5":
379 r == GPG_ERR_NO_CRL_KNOWN? "6":
380 r == GPG_ERR_CRL_TOO_OLD? "7":
381 r == GPG_ERR_NO_POLICY_MATCH? "8":
382 r == GPG_ERR_NO_SECKEY? "9":
383 "0",
384 line, NULL);
386 return rc;
390 /* ENCRYPT
392 Do the actual encryption process. Takes the plaintext from the INPUT
393 command, writes to the ciphertext to the file descriptor set with
394 the OUTPUT command, take the recipients form all the recipients set
395 so far. If this command fails the clients should try to delete all
396 output currently done or otherwise mark it as invalid. GPGSM does
397 ensure that there won't be any security problem with leftover data
398 on the output in this case.
400 This command should in general not fail, as all necessary checks
401 have been done while setting the recipients. The input and output
402 pipes are closed. */
403 static int
404 cmd_encrypt (assuan_context_t ctx, char *line)
406 ctrl_t ctrl = assuan_get_pointer (ctx);
407 certlist_t cl;
408 int inp_fd, out_fd;
409 FILE *out_fp;
410 int rc;
412 inp_fd = assuan_get_input_fd (ctx);
413 if (inp_fd == -1)
414 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
415 out_fd = assuan_get_output_fd (ctx);
416 if (out_fd == -1)
417 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
419 out_fp = fdopen ( dup(out_fd), "w");
420 if (!out_fp)
421 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
423 /* Now add all encrypt-to marked recipients from the default
424 list. */
425 rc = 0;
426 if (!opt.no_encrypt_to)
428 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
429 if (cl->is_encrypt_to)
430 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
431 &ctrl->server_local->recplist, 1);
433 if (!rc)
434 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
435 ctrl->server_local->recplist,
436 inp_fd, out_fp);
437 fclose (out_fp);
439 gpgsm_release_certlist (ctrl->server_local->recplist);
440 ctrl->server_local->recplist = NULL;
441 /* Close and reset the fd */
442 close_message_fd (ctrl);
443 assuan_close_input_fd (ctx);
444 assuan_close_output_fd (ctx);
445 return rc;
448 /* DECRYPT
450 This performs the decrypt operation after doing some check on the
451 internal state. (e.g. that only needed data has been set). Because
452 it utilizes the GPG-Agent for the session key decryption, there is
453 no need to ask the client for a protecting passphrase - GpgAgent
454 does take care of this by requesting this from the user. */
455 static int
456 cmd_decrypt (assuan_context_t ctx, char *line)
458 ctrl_t ctrl = assuan_get_pointer (ctx);
459 int inp_fd, out_fd;
460 FILE *out_fp;
461 int rc;
463 inp_fd = assuan_get_input_fd (ctx);
464 if (inp_fd == -1)
465 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
466 out_fd = assuan_get_output_fd (ctx);
467 if (out_fd == -1)
468 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
470 out_fp = fdopen ( dup(out_fd), "w");
471 if (!out_fp)
472 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
473 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
474 fclose (out_fp);
476 /* close and reset the fd */
477 close_message_fd (ctrl);
478 assuan_close_input_fd (ctx);
479 assuan_close_output_fd (ctx);
481 return rc;
485 /* VERIFY
487 This does a verify operation on the message send to the input-FD.
488 The result is written out using status lines. If an output FD was
489 given, the signed text will be written to that.
491 If the signature is a detached one, the server will inquire about
492 the signed material and the client must provide it.
494 static int
495 cmd_verify (assuan_context_t ctx, char *line)
497 int rc;
498 ctrl_t ctrl = assuan_get_pointer (ctx);
499 int fd = assuan_get_input_fd (ctx);
500 int out_fd = assuan_get_output_fd (ctx);
501 FILE *out_fp = NULL;
503 if (fd == -1)
504 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
506 if (out_fd != -1)
508 out_fp = fdopen ( dup(out_fd), "w");
509 if (!out_fp)
510 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
513 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
514 ctrl->server_local->message_fd, out_fp);
515 if (out_fp)
516 fclose (out_fp);
518 /* close and reset the fd */
519 close_message_fd (ctrl);
520 assuan_close_input_fd (ctx);
521 assuan_close_output_fd (ctx);
523 return rc;
527 /* SIGN [--detached]
529 Sign the data set with the INPUT command and write it to the sink
530 set by OUTPUT. With "--detached" specified, a detached signature is
531 created (surprise). */
532 static int
533 cmd_sign (assuan_context_t ctx, char *line)
535 ctrl_t ctrl = assuan_get_pointer (ctx);
536 int inp_fd, out_fd;
537 FILE *out_fp;
538 int detached;
539 int rc;
541 inp_fd = assuan_get_input_fd (ctx);
542 if (inp_fd == -1)
543 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
544 out_fd = assuan_get_output_fd (ctx);
545 if (out_fd == -1)
546 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
548 detached = has_option (line, "--detached");
550 out_fp = fdopen ( dup(out_fd), "w");
551 if (!out_fp)
552 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
554 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
555 inp_fd, detached, out_fp);
556 fclose (out_fp);
558 /* close and reset the fd */
559 close_message_fd (ctrl);
560 assuan_close_input_fd (ctx);
561 assuan_close_output_fd (ctx);
563 return rc;
567 /* IMPORT
569 Import the certificates read form the input-fd, return status
570 message for each imported one. The import checks the validity of
571 the certificate but not of the entire chain. It is possible to
572 import expired certificates. */
573 static int
574 cmd_import (assuan_context_t ctx, char *line)
576 ctrl_t ctrl = assuan_get_pointer (ctx);
577 int rc;
578 int fd = assuan_get_input_fd (ctx);
580 if (fd == -1)
581 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
583 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
585 /* close and reset the fd */
586 close_message_fd (ctrl);
587 assuan_close_input_fd (ctx);
588 assuan_close_output_fd (ctx);
590 return rc;
594 /* EXPORT [--data [--armor|--base64]] [--] pattern
598 static int
599 cmd_export (assuan_context_t ctx, char *line)
601 ctrl_t ctrl = assuan_get_pointer (ctx);
602 char *p;
603 strlist_t list, sl;
604 int use_data;
606 use_data = has_option (line, "--data");
608 if (use_data)
610 /* We need to override any possible setting done by an OUTPUT command. */
611 ctrl->create_pem = has_option (line, "--armor");
612 ctrl->create_base64 = has_option (line, "--base64");
615 line = skip_options (line);
617 /* Break the line down into an strlist_t. */
618 list = NULL;
619 for (p=line; *p; line = p)
621 while (*p && *p != ' ')
622 p++;
623 if (*p)
624 *p++ = 0;
625 if (*line)
627 sl = xtrymalloc (sizeof *sl + strlen (line));
628 if (!sl)
630 free_strlist (list);
631 return out_of_core ();
633 sl->flags = 0;
634 strcpy_escaped_plus (sl->d, line);
635 sl->next = list;
636 list = sl;
640 if (use_data)
642 estream_t stream;
644 stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
645 if (!stream)
647 free_strlist (list);
648 return set_error (GPG_ERR_ASS_GENERAL,
649 "error setting up a data stream");
651 gpgsm_export (ctrl, list, NULL, stream);
652 es_fclose (stream);
654 else
656 int fd = assuan_get_output_fd (ctx);
657 FILE *out_fp;
659 if (fd == -1)
661 free_strlist (list);
662 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
664 out_fp = fdopen ( dup(fd), "w");
665 if (!out_fp)
667 free_strlist (list);
668 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
671 gpgsm_export (ctrl, list, out_fp, NULL);
672 fclose (out_fp);
675 free_strlist (list);
676 /* Close and reset the fds. */
677 close_message_fd (ctrl);
678 assuan_close_input_fd (ctx);
679 assuan_close_output_fd (ctx);
680 return 0;
684 static int
685 cmd_delkeys (assuan_context_t ctx, char *line)
687 ctrl_t ctrl = assuan_get_pointer (ctx);
688 char *p;
689 strlist_t list, sl;
690 int rc;
692 /* break the line down into an strlist_t */
693 list = NULL;
694 for (p=line; *p; line = p)
696 while (*p && *p != ' ')
697 p++;
698 if (*p)
699 *p++ = 0;
700 if (*line)
702 sl = xtrymalloc (sizeof *sl + strlen (line));
703 if (!sl)
705 free_strlist (list);
706 return out_of_core ();
708 sl->flags = 0;
709 strcpy_escaped_plus (sl->d, line);
710 sl->next = list;
711 list = sl;
715 rc = gpgsm_delete (ctrl, list);
716 free_strlist (list);
718 /* close and reset the fd */
719 close_message_fd (ctrl);
720 assuan_close_input_fd (ctx);
721 assuan_close_output_fd (ctx);
723 return rc;
728 /* MESSAGE FD=<n>
730 Set the file descriptor to read a message which is used with
731 detached signatures */
732 static int
733 cmd_message (assuan_context_t ctx, char *line)
735 int rc;
736 int fd;
737 ctrl_t ctrl = assuan_get_pointer (ctx);
739 rc = assuan_command_parse_fd (ctx, line, &fd);
740 if (rc)
741 return rc;
742 if (fd == -1)
743 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
744 ctrl->server_local->message_fd = fd;
745 return 0;
748 /* LISTKEYS [<patterns>]
749 DUMPKEYS [<patterns>]
750 LISTSECRETKEYS [<patterns>]
751 DUMPSECRETKEYS [<patterns>]
753 static int
754 do_listkeys (assuan_context_t ctx, char *line, int mode)
756 ctrl_t ctrl = assuan_get_pointer (ctx);
757 estream_t fp;
758 char *p;
759 strlist_t list, sl;
760 unsigned int listmode;
761 gpg_error_t err;
763 /* Break the line down into an strlist. */
764 list = NULL;
765 for (p=line; *p; line = p)
767 while (*p && *p != ' ')
768 p++;
769 if (*p)
770 *p++ = 0;
771 if (*line)
773 sl = xtrymalloc (sizeof *sl + strlen (line));
774 if (!sl)
776 free_strlist (list);
777 return out_of_core ();
779 sl->flags = 0;
780 strcpy_escaped_plus (sl->d, line);
781 sl->next = list;
782 list = sl;
786 if (ctrl->server_local->list_to_output)
788 int outfd = assuan_get_output_fd (ctx);
790 if ( outfd == -1 )
791 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
792 fp = es_fdopen ( dup (outfd), "w");
793 if (!fp)
794 return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
796 else
798 fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
799 if (!fp)
800 return set_error (GPG_ERR_ASS_GENERAL,
801 "error setting up a data stream");
804 ctrl->with_colons = 1;
805 listmode = mode;
806 if (ctrl->server_local->list_internal)
807 listmode |= (1<<6);
808 if (ctrl->server_local->list_external)
809 listmode |= (1<<7);
810 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
811 free_strlist (list);
812 es_fclose (fp);
813 if (ctrl->server_local->list_to_output)
814 assuan_close_output_fd (ctx);
815 return err;
818 static int
819 cmd_listkeys (assuan_context_t ctx, char *line)
821 return do_listkeys (ctx, line, 3);
824 static int
825 cmd_dumpkeys (assuan_context_t ctx, char *line)
827 return do_listkeys (ctx, line, 259);
830 static int
831 cmd_listsecretkeys (assuan_context_t ctx, char *line)
833 return do_listkeys (ctx, line, 2);
836 static int
837 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
839 return do_listkeys (ctx, line, 258);
843 /* GENKEY
845 Read the parameters in native format from the input fd and write a
846 certificate request to the output.
848 static int
849 cmd_genkey (assuan_context_t ctx, char *line)
851 ctrl_t ctrl = assuan_get_pointer (ctx);
852 int inp_fd, out_fd;
853 FILE *out_fp;
854 int rc;
856 inp_fd = assuan_get_input_fd (ctx);
857 if (inp_fd == -1)
858 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
859 out_fd = assuan_get_output_fd (ctx);
860 if (out_fd == -1)
861 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
863 out_fp = fdopen ( dup(out_fd), "w");
864 if (!out_fp)
865 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
866 rc = gpgsm_genkey (ctrl, inp_fd, NULL, out_fp);
867 fclose (out_fp);
869 /* close and reset the fds */
870 assuan_close_input_fd (ctx);
871 assuan_close_output_fd (ctx);
873 return rc;
880 /* Tell the assuan library about our commands */
881 static int
882 register_commands (assuan_context_t ctx)
884 static struct {
885 const char *name;
886 int (*handler)(assuan_context_t, char *line);
887 } table[] = {
888 { "RECIPIENT", cmd_recipient },
889 { "SIGNER", cmd_signer },
890 { "ENCRYPT", cmd_encrypt },
891 { "DECRYPT", cmd_decrypt },
892 { "VERIFY", cmd_verify },
893 { "SIGN", cmd_sign },
894 { "IMPORT", cmd_import },
895 { "EXPORT", cmd_export },
896 { "INPUT", NULL },
897 { "OUTPUT", NULL },
898 { "MESSAGE", cmd_message },
899 { "LISTKEYS", cmd_listkeys },
900 { "DUMPKEYS", cmd_dumpkeys },
901 { "LISTSECRETKEYS",cmd_listsecretkeys },
902 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
903 { "GENKEY", cmd_genkey },
904 { "DELKEYS", cmd_delkeys },
905 { NULL }
907 int i, rc;
909 for (i=0; table[i].name; i++)
911 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
912 if (rc)
913 return rc;
915 return 0;
918 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
919 set from the command line or config file. We only require those
920 marked as encrypt-to. */
921 void
922 gpgsm_server (certlist_t default_recplist)
924 int rc;
925 int filedes[2];
926 assuan_context_t ctx;
927 struct server_control_s ctrl;
928 static const char hello[] = ("GNU Privacy Guard's S/M server "
929 VERSION " ready");
931 memset (&ctrl, 0, sizeof ctrl);
932 gpgsm_init_default_ctrl (&ctrl);
934 /* We use a pipe based server so that we can work from scripts.
935 assuan_init_pipe_server will automagically detect when we are
936 called with a socketpair and ignore FIELDES in this case. */
937 filedes[0] = 0;
938 filedes[1] = 1;
939 rc = assuan_init_pipe_server (&ctx, filedes);
940 if (rc)
942 log_error ("failed to initialize the server: %s\n",
943 gpg_strerror (rc));
944 gpgsm_exit (2);
946 rc = register_commands (ctx);
947 if (rc)
949 log_error ("failed to the register commands with Assuan: %s\n",
950 gpg_strerror(rc));
951 gpgsm_exit (2);
953 if (opt.verbose || opt.debug)
955 char *tmp = NULL;
956 const char *s1 = getenv ("GPG_AGENT_INFO");
957 const char *s2 = getenv ("DIRMNGR_INFO");
959 if (asprintf (&tmp,
960 "Home: %s\n"
961 "Config: %s\n"
962 "AgentInfo: %s\n"
963 "DirmngrInfo: %s\n"
964 "%s",
965 opt.homedir,
966 opt.config_filename,
967 s1?s1:"[not set]",
968 s2?s2:"[not set]",
969 hello) > 0)
971 assuan_set_hello_line (ctx, tmp);
972 free (tmp);
975 else
976 assuan_set_hello_line (ctx, hello);
978 assuan_register_reset_notify (ctx, reset_notify);
979 assuan_register_input_notify (ctx, input_notify);
980 assuan_register_output_notify (ctx, output_notify);
981 assuan_register_option_handler (ctx, option_handler);
983 assuan_set_pointer (ctx, &ctrl);
984 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
985 ctrl.server_local->assuan_ctx = ctx;
986 ctrl.server_local->message_fd = -1;
987 ctrl.server_local->list_internal = 1;
988 ctrl.server_local->list_external = 0;
989 ctrl.server_local->default_recplist = default_recplist;
991 if (DBG_ASSUAN)
992 assuan_set_log_stream (ctx, log_get_stream ());
994 for (;;)
996 rc = assuan_accept (ctx);
997 if (rc == -1)
999 break;
1001 else if (rc)
1003 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1004 break;
1007 rc = assuan_process (ctx);
1008 if (rc)
1010 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1011 continue;
1015 gpgsm_release_certlist (ctrl.server_local->recplist);
1016 ctrl.server_local->recplist = NULL;
1017 gpgsm_release_certlist (ctrl.server_local->signerlist);
1018 ctrl.server_local->signerlist = NULL;
1019 xfree (ctrl.server_local);
1021 assuan_deinit_server (ctx);
1025 static const char *
1026 get_status_string ( int no )
1028 const char *s;
1030 switch (no)
1032 case STATUS_ENTER : s = "ENTER"; break;
1033 case STATUS_LEAVE : s = "LEAVE"; break;
1034 case STATUS_ABORT : s = "ABORT"; break;
1035 case STATUS_NEWSIG : s = "NEWSIG"; break;
1036 case STATUS_GOODSIG: s = "GOODSIG"; break;
1037 case STATUS_SIGEXPIRED: s = "SIGEXPIRED"; break;
1038 case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
1039 case STATUS_BADSIG : s = "BADSIG"; break;
1040 case STATUS_ERRSIG : s = "ERRSIG"; break;
1041 case STATUS_BADARMOR : s = "BADARMOR"; break;
1042 case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
1043 case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
1044 case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
1045 case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
1046 case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
1047 case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
1048 case STATUS_GET_BOOL : s = "GET_BOOL"; break;
1049 case STATUS_GET_LINE : s = "GET_LINE"; break;
1050 case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
1051 case STATUS_GOT_IT : s = "GOT_IT"; break;
1052 case STATUS_SHM_INFO : s = "SHM_INFO"; break;
1053 case STATUS_SHM_GET : s = "SHM_GET"; break;
1054 case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
1055 case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
1056 case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
1057 case STATUS_VALIDSIG : s = "VALIDSIG"; break;
1058 case STATUS_SIG_ID : s = "SIG_ID"; break;
1059 case STATUS_ENC_TO : s = "ENC_TO"; break;
1060 case STATUS_NODATA : s = "NODATA"; break;
1061 case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
1062 case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
1063 case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
1064 case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
1065 case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
1066 case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
1067 case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
1068 case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
1069 case STATUS_GOODMDC : s = "GOODMDC"; break;
1070 case STATUS_BADMDC : s = "BADMDC"; break;
1071 case STATUS_ERRMDC : s = "ERRMDC"; break;
1072 case STATUS_IMPORTED : s = "IMPORTED"; break;
1073 case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
1074 case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
1075 case STATUS_FILE_START : s = "FILE_START"; break;
1076 case STATUS_FILE_DONE : s = "FILE_DONE"; break;
1077 case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
1078 case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
1079 case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
1080 case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
1081 case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
1082 case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
1083 case STATUS_PROGRESS : s = "PROGRESS"; break;
1084 case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
1085 case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
1086 case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
1087 case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
1088 case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
1089 case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
1090 case STATUS_END_STREAM : s = "END_STREAM"; break;
1091 case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
1092 case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
1093 case STATUS_INV_RECP : s = "INV_RECP"; break;
1094 case STATUS_NO_RECP : s = "NO_RECP"; break;
1095 case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
1096 case STATUS_EXPSIG : s = "EXPSIG"; break;
1097 case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
1098 case STATUS_TRUNCATED : s = "TRUNCATED"; break;
1099 case STATUS_ERROR : s = "ERROR"; break;
1100 case STATUS_IMPORT_PROBLEM : s = "IMPORT_PROBLEM"; break;
1101 default: s = "?"; break;
1103 return s;
1107 gpg_error_t
1108 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1110 gpg_error_t err = 0;
1111 va_list arg_ptr;
1112 const char *text;
1114 va_start (arg_ptr, no);
1116 if (ctrl->no_server && ctrl->status_fd == -1)
1117 ; /* No status wanted. */
1118 else if (ctrl->no_server)
1120 if (!statusfp)
1122 if (ctrl->status_fd == 1)
1123 statusfp = stdout;
1124 else if (ctrl->status_fd == 2)
1125 statusfp = stderr;
1126 else
1127 statusfp = fdopen (ctrl->status_fd, "w");
1129 if (!statusfp)
1131 log_fatal ("can't open fd %d for status output: %s\n",
1132 ctrl->status_fd, strerror(errno));
1136 fputs ("[GNUPG:] ", statusfp);
1137 fputs (get_status_string (no), statusfp);
1139 while ( (text = va_arg (arg_ptr, const char*) ))
1141 putc ( ' ', statusfp );
1142 for (; *text; text++)
1144 if (*text == '\n')
1145 fputs ( "\\n", statusfp );
1146 else if (*text == '\r')
1147 fputs ( "\\r", statusfp );
1148 else
1149 putc ( *(const byte *)text, statusfp );
1152 putc ('\n', statusfp);
1153 fflush (statusfp);
1155 else
1157 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1158 char buf[950], *p;
1159 size_t n;
1161 p = buf;
1162 n = 0;
1163 while ( (text = va_arg (arg_ptr, const char *)) )
1165 if (n)
1167 *p++ = ' ';
1168 n++;
1170 for ( ; *text && n < DIM (buf)-2; n++)
1171 *p++ = *text++;
1173 *p = 0;
1174 err = assuan_write_status (ctx, get_status_string (no), buf);
1177 va_end (arg_ptr);
1178 return err;
1181 gpg_error_t
1182 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1184 return gpgsm_status2 (ctrl, no, text, NULL);
1187 gpg_error_t
1188 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1189 gpg_err_code_t ec)
1191 char buf[30];
1193 sprintf (buf, "%u", (unsigned int)ec);
1194 if (text)
1195 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1196 else
1197 return gpgsm_status2 (ctrl, no, buf, NULL);