2006-12-21 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / sm / server.c
blobf922a0f2c83ffa2cdcbf1ebb62de68554e2da2b1
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <ctype.h>
29 #include <unistd.h>
31 #include <assuan.h>
33 #include "gpgsm.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 certlist_t recplist;
49 certlist_t signerlist;
50 certlist_t default_recplist; /* As set by main() - don't release. */
55 /* Note that it is sufficient to allocate the target string D as
56 long as the source string S, i.e.: strlen(s)+1; */
57 static void
58 strcpy_escaped_plus (char *d, const char *s)
60 while (*s)
62 if (*s == '%' && s[1] && s[2])
64 s++;
65 *d++ = xtoi_2 (s);
66 s += 2;
68 else if (*s == '+')
69 *d++ = ' ', s++;
70 else
71 *d++ = *s++;
73 *d = 0;
77 /* Skip over options.
78 Blanks after the options are also removed. */
79 static char *
80 skip_options (const char *line)
82 while (spacep (line))
83 line++;
84 while ( *line == '-' && line[1] == '-' )
86 while (*line && !spacep (line))
87 line++;
88 while (spacep (line))
89 line++;
91 return (char*)line;
95 /* Check whether the option NAME appears in LINE */
96 static int
97 has_option (const char *line, const char *name)
99 const char *s;
100 int n = strlen (name);
102 s = strstr (line, name);
103 if (s && s >= skip_options (line))
104 return 0;
105 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
109 static void
110 close_message_fd (ctrl_t ctrl)
112 if (ctrl->server_local->message_fd != -1)
114 close (ctrl->server_local->message_fd);
115 ctrl->server_local->message_fd = -1;
120 static int
121 option_handler (assuan_context_t ctx, const char *key, const char *value)
123 ctrl_t ctrl = assuan_get_pointer (ctx);
125 if (!strcmp (key, "include-certs"))
127 int i = *value? atoi (value) : -1;
128 if (ctrl->include_certs < -2)
129 return gpg_error (GPG_ERR_ASS_PARAMETER);
130 ctrl->include_certs = i;
132 else if (!strcmp (key, "display"))
134 if (opt.display)
135 free (opt.display);
136 opt.display = strdup (value);
137 if (!opt.display)
138 return out_of_core ();
140 else if (!strcmp (key, "ttyname"))
142 if (opt.ttyname)
143 free (opt.ttyname);
144 opt.ttyname = strdup (value);
145 if (!opt.ttyname)
146 return out_of_core ();
148 else if (!strcmp (key, "ttytype"))
150 if (opt.ttytype)
151 free (opt.ttytype);
152 opt.ttytype = strdup (value);
153 if (!opt.ttytype)
154 return out_of_core ();
156 else if (!strcmp (key, "lc-ctype"))
158 if (opt.lc_ctype)
159 free (opt.lc_ctype);
160 opt.lc_ctype = strdup (value);
161 if (!opt.lc_ctype)
162 return out_of_core ();
164 else if (!strcmp (key, "lc-messages"))
166 if (opt.lc_messages)
167 free (opt.lc_messages);
168 opt.lc_messages = strdup (value);
169 if (!opt.lc_messages)
170 return out_of_core ();
172 else if (!strcmp (key, "list-mode"))
174 int i = *value? atoi (value) : 0;
175 if (!i || i == 1) /* default and mode 1 */
177 ctrl->server_local->list_internal = 1;
178 ctrl->server_local->list_external = 0;
180 else if (i == 2)
182 ctrl->server_local->list_internal = 0;
183 ctrl->server_local->list_external = 1;
185 else if (i == 3)
187 ctrl->server_local->list_internal = 1;
188 ctrl->server_local->list_external = 1;
190 else
191 return gpg_error (GPG_ERR_ASS_PARAMETER);
193 else if (!strcmp (key, "list-to-output"))
195 int i = *value? atoi (value) : 0;
196 ctrl->server_local->list_to_output = i;
198 else if (!strcmp (key, "with-validation"))
200 int i = *value? atoi (value) : 0;
201 ctrl->with_validation = i;
203 else if (!strcmp (key, "with-key-data"))
205 opt.with_key_data = 1;
207 else
208 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
210 return 0;
216 static void
217 reset_notify (assuan_context_t ctx)
219 ctrl_t ctrl = assuan_get_pointer (ctx);
221 gpgsm_release_certlist (ctrl->server_local->recplist);
222 gpgsm_release_certlist (ctrl->server_local->signerlist);
223 ctrl->server_local->recplist = NULL;
224 ctrl->server_local->signerlist = NULL;
225 close_message_fd (ctrl);
226 assuan_close_input_fd (ctx);
227 assuan_close_output_fd (ctx);
231 static void
232 input_notify (assuan_context_t ctx, const char *line)
234 ctrl_t ctrl = assuan_get_pointer (ctx);
236 ctrl->autodetect_encoding = 0;
237 ctrl->is_pem = 0;
238 ctrl->is_base64 = 0;
239 if (strstr (line, "--armor"))
240 ctrl->is_pem = 1;
241 else if (strstr (line, "--base64"))
242 ctrl->is_base64 = 1;
243 else if (strstr (line, "--binary"))
245 else
246 ctrl->autodetect_encoding = 1;
249 static void
250 output_notify (assuan_context_t ctx, const char *line)
252 ctrl_t ctrl = assuan_get_pointer (ctx);
254 ctrl->create_pem = 0;
255 ctrl->create_base64 = 0;
256 if (strstr (line, "--armor"))
257 ctrl->create_pem = 1;
258 else if (strstr (line, "--base64"))
259 ctrl->create_base64 = 1; /* just the raw output */
264 /* RECIPIENT <userID>
266 Set the recipient for the encryption. <userID> should be the
267 internal representation of the key; the server may accept any other
268 way of specification [we will support this]. If this is a valid and
269 trusted recipient the server does respond with OK, otherwise the
270 return is an ERR with the reason why the recipient can't be used,
271 the encryption will then not be done for this recipient. If the
272 policy is not to encrypt at all if not all recipients are valid, the
273 client has to take care of this. All RECIPIENT commands are
274 cumulative until a RESET or an successful ENCRYPT command. */
275 static int
276 cmd_recipient (assuan_context_t ctx, char *line)
278 ctrl_t ctrl = assuan_get_pointer (ctx);
279 int rc;
281 rc = gpgsm_add_to_certlist (ctrl, line, 0, &ctrl->server_local->recplist, 0);
282 if (rc)
284 gpg_err_code_t r = gpg_err_code (rc);
285 gpgsm_status2 (ctrl, STATUS_INV_RECP,
286 r == -1? "1":
287 r == GPG_ERR_NO_PUBKEY? "1":
288 r == GPG_ERR_AMBIGUOUS_NAME? "2":
289 r == GPG_ERR_WRONG_KEY_USAGE? "3":
290 r == GPG_ERR_CERT_REVOKED? "4":
291 r == GPG_ERR_CERT_EXPIRED? "5":
292 r == GPG_ERR_NO_CRL_KNOWN? "6":
293 r == GPG_ERR_CRL_TOO_OLD? "7":
294 r == GPG_ERR_NO_POLICY_MATCH? "8":
295 "0",
296 line, NULL);
299 return rc;
302 /* SIGNER <userID>
304 Set the signer's keys for the signature creation. <userID> should
305 be the internal representation of the key; the server may accept any
306 other way of specification [we will support this]. If this is a
307 valid and usable signing key the server does respond with OK,
308 otherwise it returns an ERR with the reason why the key can't be
309 used, the signing will then not be done for this key. If the policy
310 is not to sign at all if not all signer keys are valid, the client
311 has to take care of this. All SIGNER commands are cumulative until
312 a RESET but they are *not* reset by an SIGN command becuase it can
313 be expected that set of signers are used for more than one sign
314 operation.
316 Note that this command returns an INV_RECP status which is a bit
317 strange, but they are very similar. */
318 static int
319 cmd_signer (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, 1,
325 &ctrl->server_local->signerlist, 0);
326 if (rc)
328 gpg_err_code_t r = gpg_err_code (rc);
329 gpgsm_status2 (ctrl, STATUS_INV_RECP,
330 r == -1? "1":
331 r == GPG_ERR_NO_PUBKEY? "1":
332 r == GPG_ERR_AMBIGUOUS_NAME? "2":
333 r == GPG_ERR_WRONG_KEY_USAGE? "3":
334 r == GPG_ERR_CERT_REVOKED? "4":
335 r == GPG_ERR_CERT_EXPIRED? "5":
336 r == GPG_ERR_NO_CRL_KNOWN? "6":
337 r == GPG_ERR_CRL_TOO_OLD? "7":
338 r == GPG_ERR_NO_POLICY_MATCH? "8":
339 r == GPG_ERR_NO_SECKEY? "9":
340 "0",
341 line, NULL);
343 return rc;
347 /* ENCRYPT
349 Do the actual encryption process. Takes the plaintext from the INPUT
350 command, writes to the ciphertext to the file descriptor set with
351 the OUTPUT command, take the recipients form all the recipients set
352 so far. If this command fails the clients should try to delete all
353 output currently done or otherwise mark it as invalid. GPGSM does
354 ensure that there won't be any security problem with leftover data
355 on the output in this case.
357 This command should in general not fail, as all necessary checks
358 have been done while setting the recipients. The input and output
359 pipes are closed. */
360 static int
361 cmd_encrypt (assuan_context_t ctx, char *line)
363 ctrl_t ctrl = assuan_get_pointer (ctx);
364 certlist_t cl;
365 int inp_fd, out_fd;
366 FILE *out_fp;
367 int rc;
369 inp_fd = assuan_get_input_fd (ctx);
370 if (inp_fd == -1)
371 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
372 out_fd = assuan_get_output_fd (ctx);
373 if (out_fd == -1)
374 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
376 out_fp = fdopen ( dup(out_fd), "w");
377 if (!out_fp)
378 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
380 /* Now add all encrypt-to marked recipients from the default
381 list. */
382 rc = 0;
383 if (!opt.no_encrypt_to)
385 for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
386 if (cl->is_encrypt_to)
387 rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
388 &ctrl->server_local->recplist, 1);
390 if (!rc)
391 rc = gpgsm_encrypt (assuan_get_pointer (ctx),
392 ctrl->server_local->recplist,
393 inp_fd, out_fp);
394 fclose (out_fp);
396 gpgsm_release_certlist (ctrl->server_local->recplist);
397 ctrl->server_local->recplist = NULL;
398 /* Close and reset the fd */
399 close_message_fd (ctrl);
400 assuan_close_input_fd (ctx);
401 assuan_close_output_fd (ctx);
402 return rc;
405 /* DECRYPT
407 This performs the decrypt operation after doing some check on the
408 internal state. (e.g. that only needed data has been set). Because
409 it utilizes the GPG-Agent for the session key decryption, there is
410 no need to ask the client for a protecting passphrase - GpgAgent
411 does take care of this by requesting this from the user. */
412 static int
413 cmd_decrypt (assuan_context_t ctx, char *line)
415 ctrl_t ctrl = assuan_get_pointer (ctx);
416 int inp_fd, out_fd;
417 FILE *out_fp;
418 int rc;
420 inp_fd = assuan_get_input_fd (ctx);
421 if (inp_fd == -1)
422 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
423 out_fd = assuan_get_output_fd (ctx);
424 if (out_fd == -1)
425 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
427 out_fp = fdopen ( dup(out_fd), "w");
428 if (!out_fp)
429 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
430 rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
431 fclose (out_fp);
433 /* close and reset the fd */
434 close_message_fd (ctrl);
435 assuan_close_input_fd (ctx);
436 assuan_close_output_fd (ctx);
438 return rc;
442 /* VERIFY
444 This does a verify operation on the message send to the input-FD.
445 The result is written out using status lines. If an output FD was
446 given, the signed text will be written to that.
448 If the signature is a detached one, the server will inquire about
449 the signed material and the client must provide it.
451 static int
452 cmd_verify (assuan_context_t ctx, char *line)
454 int rc;
455 ctrl_t ctrl = assuan_get_pointer (ctx);
456 int fd = assuan_get_input_fd (ctx);
457 int out_fd = assuan_get_output_fd (ctx);
458 FILE *out_fp = NULL;
460 if (fd == -1)
461 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
463 if (out_fd != -1)
465 out_fp = fdopen ( dup(out_fd), "w");
466 if (!out_fp)
467 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
470 rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
471 ctrl->server_local->message_fd, out_fp);
472 if (out_fp)
473 fclose (out_fp);
475 /* close and reset the fd */
476 close_message_fd (ctrl);
477 assuan_close_input_fd (ctx);
478 assuan_close_output_fd (ctx);
480 return rc;
484 /* SIGN [--detached]
486 Sign the data set with the INPUT command and write it to the sink
487 set by OUTPUT. With "--detached" specified, a detached signature is
488 created (surprise). */
489 static int
490 cmd_sign (assuan_context_t ctx, char *line)
492 ctrl_t ctrl = assuan_get_pointer (ctx);
493 int inp_fd, out_fd;
494 FILE *out_fp;
495 int detached;
496 int rc;
498 inp_fd = assuan_get_input_fd (ctx);
499 if (inp_fd == -1)
500 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
501 out_fd = assuan_get_output_fd (ctx);
502 if (out_fd == -1)
503 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
505 detached = has_option (line, "--detached");
507 out_fp = fdopen ( dup(out_fd), "w");
508 if (!out_fp)
509 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
511 rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
512 inp_fd, detached, out_fp);
513 fclose (out_fp);
515 /* close and reset the fd */
516 close_message_fd (ctrl);
517 assuan_close_input_fd (ctx);
518 assuan_close_output_fd (ctx);
520 return rc;
524 /* IMPORT
526 Import the certificates read form the input-fd, return status
527 message for each imported one. The import checks the validity of
528 the certificate but not of the entire chain. It is possible to
529 import expired certificates. */
530 static int
531 cmd_import (assuan_context_t ctx, char *line)
533 ctrl_t ctrl = assuan_get_pointer (ctx);
534 int rc;
535 int fd = assuan_get_input_fd (ctx);
537 if (fd == -1)
538 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
540 rc = gpgsm_import (assuan_get_pointer (ctx), fd);
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 /* EXPORT [--data [--armor|--base64]] [--] pattern
555 static int
556 cmd_export (assuan_context_t ctx, char *line)
558 ctrl_t ctrl = assuan_get_pointer (ctx);
559 int fd = assuan_get_output_fd (ctx);
560 FILE *out_fp;
561 char *p;
562 strlist_t list, sl;
563 int use_data;
565 use_data = has_option (line, "--data");
567 if (use_data)
569 /* We need to override any possible setting done by an OUTPUT command. */
570 ctrl->create_pem = has_option (line, "--armor");
571 ctrl->create_base64 = has_option (line, "--base64");
574 line = skip_options (line);
576 /* Break the line down into an strlist_t. */
577 list = NULL;
578 for (p=line; *p; line = p)
580 while (*p && *p != ' ')
581 p++;
582 if (*p)
583 *p++ = 0;
584 if (*line)
586 sl = xtrymalloc (sizeof *sl + strlen (line));
587 if (!sl)
589 free_strlist (list);
590 return out_of_core ();
592 sl->flags = 0;
593 strcpy_escaped_plus (sl->d, line);
594 sl->next = list;
595 list = sl;
599 if (use_data)
601 out_fp = assuan_get_data_fp (ctx);
602 if (!out_fp)
604 free_strlist (list);
605 return set_error (GPG_ERR_ASS_GENERAL, "no data stream");
607 gpgsm_export (ctrl, list, out_fp);
609 else
611 if (fd == -1)
613 free_strlist (list);
614 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
616 out_fp = fdopen ( dup(fd), "w");
617 if (!out_fp)
619 free_strlist (list);
620 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
623 gpgsm_export (ctrl, list, out_fp);
624 fclose (out_fp);
627 free_strlist (list);
628 /* Close and reset the fds. */
629 close_message_fd (ctrl);
630 assuan_close_input_fd (ctx);
631 assuan_close_output_fd (ctx);
632 return 0;
636 static int
637 cmd_delkeys (assuan_context_t ctx, char *line)
639 ctrl_t ctrl = assuan_get_pointer (ctx);
640 char *p;
641 strlist_t list, sl;
642 int rc;
644 /* break the line down into an strlist_t */
645 list = NULL;
646 for (p=line; *p; line = p)
648 while (*p && *p != ' ')
649 p++;
650 if (*p)
651 *p++ = 0;
652 if (*line)
654 sl = xtrymalloc (sizeof *sl + strlen (line));
655 if (!sl)
657 free_strlist (list);
658 return out_of_core ();
660 sl->flags = 0;
661 strcpy_escaped_plus (sl->d, line);
662 sl->next = list;
663 list = sl;
667 rc = gpgsm_delete (ctrl, list);
668 free_strlist (list);
670 /* close and reset the fd */
671 close_message_fd (ctrl);
672 assuan_close_input_fd (ctx);
673 assuan_close_output_fd (ctx);
675 return rc;
680 /* MESSAGE FD=<n>
682 Set the file descriptor to read a message which is used with
683 detached signatures */
684 static int
685 cmd_message (assuan_context_t ctx, char *line)
687 int rc;
688 int fd;
689 ctrl_t ctrl = assuan_get_pointer (ctx);
691 rc = assuan_command_parse_fd (ctx, line, &fd);
692 if (rc)
693 return rc;
694 if (fd == -1)
695 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
696 ctrl->server_local->message_fd = fd;
697 return 0;
700 /* LISTKEYS [<patterns>]
701 DUMPKEYS [<patterns>]
702 LISTSECRETKEYS [<patterns>]
703 DUMPSECRETKEYS [<patterns>]
705 static int
706 do_listkeys (assuan_context_t ctx, char *line, int mode)
708 ctrl_t ctrl = assuan_get_pointer (ctx);
709 FILE *fp;
710 char *p;
711 strlist_t list, sl;
712 unsigned int listmode;
713 gpg_error_t err;
715 /* Break the line down into an strlist. */
716 list = NULL;
717 for (p=line; *p; line = p)
719 while (*p && *p != ' ')
720 p++;
721 if (*p)
722 *p++ = 0;
723 if (*line)
725 sl = xtrymalloc (sizeof *sl + strlen (line));
726 if (!sl)
728 free_strlist (list);
729 return out_of_core ();
731 sl->flags = 0;
732 strcpy_escaped_plus (sl->d, line);
733 sl->next = list;
734 list = sl;
738 if (ctrl->server_local->list_to_output)
740 if ( assuan_get_output_fd (ctx) == -1 )
741 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
742 fp = fdopen (assuan_get_output_fd (ctx), "w");
743 if (!fp)
744 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
746 else
748 fp = assuan_get_data_fp (ctx);
749 if (!fp)
750 return set_error (GPG_ERR_ASS_GENERAL, "no data stream");
753 ctrl->with_colons = 1;
754 listmode = mode;
755 if (ctrl->server_local->list_internal)
756 listmode |= (1<<6);
757 if (ctrl->server_local->list_external)
758 listmode |= (1<<7);
759 err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
760 free_strlist (list);
761 if (ctrl->server_local->list_to_output)
763 fclose (fp);
764 assuan_close_output_fd (ctx);
766 return err;
769 static int
770 cmd_listkeys (assuan_context_t ctx, char *line)
772 return do_listkeys (ctx, line, 3);
775 static int
776 cmd_dumpkeys (assuan_context_t ctx, char *line)
778 return do_listkeys (ctx, line, 259);
781 static int
782 cmd_listsecretkeys (assuan_context_t ctx, char *line)
784 return do_listkeys (ctx, line, 2);
787 static int
788 cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
790 return do_listkeys (ctx, line, 258);
794 /* GENKEY
796 Read the parameters in native format from the input fd and write a
797 certificate request to the output.
799 static int
800 cmd_genkey (assuan_context_t ctx, char *line)
802 ctrl_t ctrl = assuan_get_pointer (ctx);
803 int inp_fd, out_fd;
804 FILE *out_fp;
805 int rc;
807 inp_fd = assuan_get_input_fd (ctx);
808 if (inp_fd == -1)
809 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
810 out_fd = assuan_get_output_fd (ctx);
811 if (out_fd == -1)
812 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
814 out_fp = fdopen ( dup(out_fd), "w");
815 if (!out_fp)
816 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
817 rc = gpgsm_genkey (ctrl, inp_fd, out_fp);
818 fclose (out_fp);
820 /* close and reset the fds */
821 assuan_close_input_fd (ctx);
822 assuan_close_output_fd (ctx);
824 return rc;
831 /* Tell the assuan library about our commands */
832 static int
833 register_commands (assuan_context_t ctx)
835 static struct {
836 const char *name;
837 int (*handler)(assuan_context_t, char *line);
838 } table[] = {
839 { "RECIPIENT", cmd_recipient },
840 { "SIGNER", cmd_signer },
841 { "ENCRYPT", cmd_encrypt },
842 { "DECRYPT", cmd_decrypt },
843 { "VERIFY", cmd_verify },
844 { "SIGN", cmd_sign },
845 { "IMPORT", cmd_import },
846 { "EXPORT", cmd_export },
847 { "INPUT", NULL },
848 { "OUTPUT", NULL },
849 { "MESSAGE", cmd_message },
850 { "LISTKEYS", cmd_listkeys },
851 { "DUMPKEYS", cmd_dumpkeys },
852 { "LISTSECRETKEYS",cmd_listsecretkeys },
853 { "DUMPSECRETKEYS",cmd_dumpsecretkeys },
854 { "GENKEY", cmd_genkey },
855 { "DELKEYS", cmd_delkeys },
856 { NULL }
858 int i, rc;
860 for (i=0; table[i].name; i++)
862 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
863 if (rc)
864 return rc;
866 return 0;
869 /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
870 set from the command line or config file. We only require those
871 marked as encrypt-to. */
872 void
873 gpgsm_server (certlist_t default_recplist)
875 int rc;
876 int filedes[2];
877 assuan_context_t ctx;
878 struct server_control_s ctrl;
879 static const char hello[] = ("GNU Privacy Guard's S/M server "
880 VERSION " ready");
882 memset (&ctrl, 0, sizeof ctrl);
883 gpgsm_init_default_ctrl (&ctrl);
885 /* We use a pipe based server so that we can work from scripts.
886 assuan_init_pipe_server will automagically detect when we are
887 called with a socketpair and ignore FIELDES in this case. */
888 filedes[0] = 0;
889 filedes[1] = 1;
890 rc = assuan_init_pipe_server (&ctx, filedes);
891 if (rc)
893 log_error ("failed to initialize the server: %s\n",
894 gpg_strerror (rc));
895 gpgsm_exit (2);
897 rc = register_commands (ctx);
898 if (rc)
900 log_error ("failed to the register commands with Assuan: %s\n",
901 gpg_strerror(rc));
902 gpgsm_exit (2);
904 if (opt.verbose || opt.debug)
906 char *tmp = NULL;
907 const char *s1 = getenv ("GPG_AGENT_INFO");
908 const char *s2 = getenv ("DIRMNGR_INFO");
910 if (asprintf (&tmp,
911 "Home: %s\n"
912 "Config: %s\n"
913 "AgentInfo: %s\n"
914 "DirmngrInfo: %s\n"
915 "%s",
916 opt.homedir,
917 opt.config_filename,
918 s1?s1:"[not set]",
919 s2?s2:"[not set]",
920 hello) > 0)
922 assuan_set_hello_line (ctx, tmp);
923 free (tmp);
926 else
927 assuan_set_hello_line (ctx, hello);
929 assuan_register_reset_notify (ctx, reset_notify);
930 assuan_register_input_notify (ctx, input_notify);
931 assuan_register_output_notify (ctx, output_notify);
932 assuan_register_option_handler (ctx, option_handler);
934 assuan_set_pointer (ctx, &ctrl);
935 ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
936 ctrl.server_local->assuan_ctx = ctx;
937 ctrl.server_local->message_fd = -1;
938 ctrl.server_local->list_internal = 1;
939 ctrl.server_local->list_external = 0;
940 ctrl.server_local->default_recplist = default_recplist;
942 if (DBG_ASSUAN)
943 assuan_set_log_stream (ctx, log_get_stream ());
945 for (;;)
947 rc = assuan_accept (ctx);
948 if (rc == -1)
950 break;
952 else if (rc)
954 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
955 break;
958 rc = assuan_process (ctx);
959 if (rc)
961 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
962 continue;
966 gpgsm_release_certlist (ctrl.server_local->recplist);
967 ctrl.server_local->recplist = NULL;
968 gpgsm_release_certlist (ctrl.server_local->signerlist);
969 ctrl.server_local->signerlist = NULL;
970 xfree (ctrl.server_local);
972 assuan_deinit_server (ctx);
976 static const char *
977 get_status_string ( int no )
979 const char *s;
981 switch (no)
983 case STATUS_ENTER : s = "ENTER"; break;
984 case STATUS_LEAVE : s = "LEAVE"; break;
985 case STATUS_ABORT : s = "ABORT"; break;
986 case STATUS_NEWSIG : s = "NEWSIG"; break;
987 case STATUS_GOODSIG: s = "GOODSIG"; break;
988 case STATUS_SIGEXPIRED: s = "SIGEXPIRED"; break;
989 case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
990 case STATUS_BADSIG : s = "BADSIG"; break;
991 case STATUS_ERRSIG : s = "ERRSIG"; break;
992 case STATUS_BADARMOR : s = "BADARMOR"; break;
993 case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
994 case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
995 case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
996 case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
997 case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
998 case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
999 case STATUS_GET_BOOL : s = "GET_BOOL"; break;
1000 case STATUS_GET_LINE : s = "GET_LINE"; break;
1001 case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
1002 case STATUS_GOT_IT : s = "GOT_IT"; break;
1003 case STATUS_SHM_INFO : s = "SHM_INFO"; break;
1004 case STATUS_SHM_GET : s = "SHM_GET"; break;
1005 case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
1006 case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
1007 case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
1008 case STATUS_VALIDSIG : s = "VALIDSIG"; break;
1009 case STATUS_SIG_ID : s = "SIG_ID"; break;
1010 case STATUS_ENC_TO : s = "ENC_TO"; break;
1011 case STATUS_NODATA : s = "NODATA"; break;
1012 case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
1013 case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
1014 case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
1015 case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
1016 case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
1017 case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
1018 case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
1019 case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
1020 case STATUS_GOODMDC : s = "GOODMDC"; break;
1021 case STATUS_BADMDC : s = "BADMDC"; break;
1022 case STATUS_ERRMDC : s = "ERRMDC"; break;
1023 case STATUS_IMPORTED : s = "IMPORTED"; break;
1024 case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
1025 case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
1026 case STATUS_FILE_START : s = "FILE_START"; break;
1027 case STATUS_FILE_DONE : s = "FILE_DONE"; break;
1028 case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
1029 case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
1030 case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
1031 case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
1032 case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
1033 case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
1034 case STATUS_PROGRESS : s = "PROGRESS"; break;
1035 case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
1036 case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
1037 case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
1038 case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
1039 case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
1040 case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
1041 case STATUS_END_STREAM : s = "END_STREAM"; break;
1042 case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
1043 case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
1044 case STATUS_INV_RECP : s = "INV_RECP"; break;
1045 case STATUS_NO_RECP : s = "NO_RECP"; break;
1046 case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
1047 case STATUS_EXPSIG : s = "EXPSIG"; break;
1048 case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
1049 case STATUS_TRUNCATED : s = "TRUNCATED"; break;
1050 case STATUS_ERROR : s = "ERROR"; break;
1051 case STATUS_IMPORT_PROBLEM : s = "IMPORT_PROBLEM"; break;
1052 default: s = "?"; break;
1054 return s;
1058 gpg_error_t
1059 gpgsm_status2 (ctrl_t ctrl, int no, ...)
1061 gpg_error_t err = 0;
1062 va_list arg_ptr;
1063 const char *text;
1065 va_start (arg_ptr, no);
1067 if (ctrl->no_server && ctrl->status_fd == -1)
1068 ; /* No status wanted. */
1069 else if (ctrl->no_server)
1071 if (!statusfp)
1073 if (ctrl->status_fd == 1)
1074 statusfp = stdout;
1075 else if (ctrl->status_fd == 2)
1076 statusfp = stderr;
1077 else
1078 statusfp = fdopen (ctrl->status_fd, "w");
1080 if (!statusfp)
1082 log_fatal ("can't open fd %d for status output: %s\n",
1083 ctrl->status_fd, strerror(errno));
1087 fputs ("[GNUPG:] ", statusfp);
1088 fputs (get_status_string (no), statusfp);
1090 while ( (text = va_arg (arg_ptr, const char*) ))
1092 putc ( ' ', statusfp );
1093 for (; *text; text++)
1095 if (*text == '\n')
1096 fputs ( "\\n", statusfp );
1097 else if (*text == '\r')
1098 fputs ( "\\r", statusfp );
1099 else
1100 putc ( *(const byte *)text, statusfp );
1103 putc ('\n', statusfp);
1104 fflush (statusfp);
1106 else
1108 assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1109 char buf[950], *p;
1110 size_t n;
1112 p = buf;
1113 n = 0;
1114 while ( (text = va_arg (arg_ptr, const char *)) )
1116 if (n)
1118 *p++ = ' ';
1119 n++;
1121 for ( ; *text && n < DIM (buf)-2; n++)
1122 *p++ = *text++;
1124 *p = 0;
1125 err = assuan_write_status (ctx, get_status_string (no), buf);
1128 va_end (arg_ptr);
1129 return err;
1132 gpg_error_t
1133 gpgsm_status (ctrl_t ctrl, int no, const char *text)
1135 return gpgsm_status2 (ctrl, no, text, NULL);
1138 gpg_error_t
1139 gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1140 gpg_err_code_t ec)
1142 char buf[30];
1144 sprintf (buf, "%u", (unsigned int)ec);
1145 if (text)
1146 return gpgsm_status2 (ctrl, no, text, buf, NULL);
1147 else
1148 return gpgsm_status2 (ctrl, no, buf, NULL);