Re-indentation
[gnupg.git] / g10 / server.c
blob33f9bb6edc7e9c6a437209e8d5b5a4a3f95c1e79
1 /* server.c - server mode for gpg
2 * Copyright (C) 2006, 2008 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>
30 #include "gpg.h"
31 #include <assuan.h>
32 #include "util.h"
33 #include "i18n.h"
34 #include "options.h"
35 #include "../common/sysutils.h"
36 #include "status.h"
39 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
42 /* Data used to associate an Assuan context with local server data. */
43 struct server_local_s
45 /* Our current Assuan context. */
46 assuan_context_t assuan_ctx;
47 /* File descriptor as set by the MESSAGE command. */
48 gnupg_fd_t message_fd;
50 /* List of prepared recipients. */
51 pk_list_t recplist;
57 /* Helper to close the message fd if it is open. */
58 static void
59 close_message_fd (ctrl_t ctrl)
61 if (ctrl->server_local->message_fd != GNUPG_INVALID_FD)
63 assuan_sock_close (ctrl->server_local->message_fd);
64 ctrl->server_local->message_fd = GNUPG_INVALID_FD;
69 /* Skip over options. Blanks after the options are also removed. */
70 static char *
71 skip_options (const char *line)
73 while (spacep (line))
74 line++;
75 while ( *line == '-' && line[1] == '-' )
77 while (*line && !spacep (line))
78 line++;
79 while (spacep (line))
80 line++;
82 return (char*)line;
86 /* Check whether the option NAME appears in LINE. */
87 static int
88 has_option (const char *line, const char *name)
90 const char *s;
91 int n = strlen (name);
93 s = strstr (line, name);
94 if (s && s >= skip_options (line))
95 return 0;
96 return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
103 /* Called by libassuan for Assuan options. See the Assuan manual for
104 details. */
105 static gpg_error_t
106 option_handler (assuan_context_t ctx, const char *key, const char *value)
108 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
110 (void)ctx;
111 (void)value;
113 /* Fixme: Implement the tty and locale args. */
114 if (!strcmp (key, "display"))
117 else if (!strcmp (key, "ttyname"))
120 else if (!strcmp (key, "ttytype"))
123 else if (!strcmp (key, "lc-ctype"))
126 else if (!strcmp (key, "lc-messages"))
129 else if (!strcmp (key, "xauthority"))
132 else if (!strcmp (key, "pinentry_user_data"))
135 else if (!strcmp (key, "list-mode"))
137 /* This is for now a dummy option. */
139 else
140 return gpg_error (GPG_ERR_UNKNOWN_OPTION);
142 return 0;
146 /* Called by libassuan for RESET commands. */
147 static void
148 reset_notify (assuan_context_t ctx)
150 ctrl_t ctrl = assuan_get_pointer (ctx);
152 release_pk_list (ctrl->server_local->recplist);
153 ctrl->server_local->recplist = NULL;
155 close_message_fd (ctrl);
156 assuan_close_input_fd (ctx);
157 assuan_close_output_fd (ctx);
161 /* Called by libassuan for INPUT commands. */
162 static void
163 input_notify (assuan_context_t ctx, const char *line)
165 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
167 (void)ctx;
169 if (strstr (line, "--armor"))
170 ; /* FIXME */
171 else if (strstr (line, "--base64"))
172 ; /* FIXME */
173 else if (strstr (line, "--binary"))
175 else
177 /* FIXME (autodetect encoding) */
182 /* Called by libassuan for OUTPUT commands. */
183 static void
184 output_notify (assuan_context_t ctx, const char *line)
186 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
188 (void)ctx;
190 if (strstr (line, "--armor"))
191 ; /* FIXME */
192 else if (strstr (line, "--base64"))
194 /* FIXME */
201 /* RECIPIENT [--hidden] <userID>
203 Set the recipient for the encryption. <userID> should be the
204 internal representation of the key; the server may accept any other
205 way of specification. If this is a valid and trusted recipient the
206 server does respond with OK, otherwise the return is an ERR with
207 the reason why the recipient can't be used, the encryption will
208 then not be done for this recipient. If the policy is not to
209 encrypt at all if not all recipients are valid, the client has to
210 take care of this. All RECIPIENT commands are cumulative until a
211 RESET or an successful ENCRYPT command. */
212 static gpg_error_t
213 cmd_recipient (assuan_context_t ctx, char *line)
215 ctrl_t ctrl = assuan_get_pointer (ctx);
216 gpg_error_t err;
217 int hidden;
219 hidden = has_option (line,"--hidden");
220 line = skip_options (line);
222 /* FIXME: Expand groups
223 if (opt.grouplist)
224 remusr = expand_group (rcpts);
225 else
226 remusr = rcpts;
229 err = find_and_check_key (line, PUBKEY_USAGE_ENC, hidden,
230 &ctrl->server_local->recplist);
232 if (err)
233 log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err));
234 return err;
239 /* SIGNER <userID>
241 Set the signer's keys for the signature creation. <userID> should
242 be the internal representation of the key; the server may accept
243 any other way of specification. If this is a valid and usable
244 signing key the server does respond with OK, otherwise it returns
245 an ERR with the reason why the key can't be used, the signing will
246 then not be done for this key. If the policy is not to sign at all
247 if not all signer keys are valid, the client has to take care of
248 this. All SIGNER commands are cumulative until a RESET but they
249 are *not* reset by an SIGN command becuase it can be expected that
250 set of signers are used for more than one sign operation.
252 Note that this command returns an INV_RECP status which is a bit
253 strange, but they are very similar. */
254 static gpg_error_t
255 cmd_signer (assuan_context_t ctx, char *line)
257 (void)ctx;
258 (void)line;
259 return gpg_error (GPG_ERR_NOT_SUPPORTED);
264 /* ENCRYPT
266 Do the actual encryption process. Takes the plaintext from the
267 INPUT command, writes the ciphertext to the file descriptor set
268 with the OUTPUT command, take the recipients from all the
269 recipients set so far with RECIPIENTS.
271 If this command fails the clients should try to delete all output
272 currently done or otherwise mark it as invalid. GPG does ensure
273 that there won't be any security problem with leftover data on the
274 output in this case.
276 In most cases this command won't fail because most necessary checks
277 have been done while setting the recipients. However some checks
278 can only be done right here and thus error may occur anyway (for
279 example, no recipients at all).
281 The input, output and message pipes are closed after this
282 command. */
283 static gpg_error_t
284 cmd_encrypt (assuan_context_t ctx, char *line)
286 ctrl_t ctrl = assuan_get_pointer (ctx);
287 gpg_error_t err;
288 int inp_fd, out_fd;
290 (void)line; /* LINE is not used. */
292 if ( !ctrl->server_local->recplist )
294 write_status_text (STATUS_NO_RECP, "0");
295 err = gpg_error (GPG_ERR_NO_USER_ID);
296 goto leave;
299 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
300 if (inp_fd == -1)
302 err = set_error (GPG_ERR_ASS_NO_INPUT, NULL);
303 goto leave;
305 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
306 if (out_fd == -1)
308 err = set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
309 goto leave;
312 /* Fixme: Check that we are using real files and not pipes if in
313 PGP-2 mode. Do all the other checks we do in gpg.c for aEncr.
314 Maybe we should drop the PGP2 compatibility. */
317 /* FIXME: GPGSM does this here: Add all encrypt-to marked recipients
318 from the default list. */
320 /* fixme: err = ctrl->audit? 0 : start_audit_session (ctrl);*/
322 err = encrypt_crypt (inp_fd, NULL, NULL, 0,
323 ctrl->server_local->recplist,
324 out_fd);
326 leave:
327 /* Release the recipient list on success. */
328 if (!err)
330 release_pk_list (ctrl->server_local->recplist);
331 ctrl->server_local->recplist = NULL;
334 /* Close and reset the fds. */
335 close_message_fd (ctrl);
336 assuan_close_input_fd (ctx);
337 assuan_close_output_fd (ctx);
339 if (err)
340 log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err));
341 return err;
346 /* DECRYPT
348 This performs the decrypt operation. */
349 static gpg_error_t
350 cmd_decrypt (assuan_context_t ctx, char *line)
352 ctrl_t ctrl = assuan_get_pointer (ctx);
353 gpg_error_t err;
354 int inp_fd, out_fd;
356 (void)line; /* LINE is not used. */
358 inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
359 if (inp_fd == -1)
360 return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
361 out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
362 if (out_fd == -1)
363 return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
365 err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
367 /* Close and reset the fds. */
368 close_message_fd (ctrl);
369 assuan_close_input_fd (ctx);
370 assuan_close_output_fd (ctx);
372 if (err)
373 log_error ("command '%s' failed: %s\n", "DECRYPT", gpg_strerror (err));
374 return err;
379 /* VERIFY
381 This does a verify operation on the message send to the input-FD.
382 The result is written out using status lines. If an output FD was
383 given, the signed text will be written to that.
385 If the signature is a detached one, the server will inquire about
386 the signed material and the client must provide it.
388 static gpg_error_t
389 cmd_verify (assuan_context_t ctx, char *line)
391 int rc;
392 ctrl_t ctrl = assuan_get_pointer (ctx);
393 gnupg_fd_t fd = assuan_get_input_fd (ctx);
394 gnupg_fd_t out_fd = assuan_get_output_fd (ctx);
395 FILE *out_fp = NULL;
397 /* FIXME: Revamp this code it is nearly to 3 years old and was only
398 intended as a quick test. */
400 (void)line;
402 if (fd == GNUPG_INVALID_FD)
403 return gpg_error (GPG_ERR_ASS_NO_INPUT);
405 if (out_fd != GNUPG_INVALID_FD)
407 out_fp = fdopen ( dup (FD2INT (out_fd)), "w");
408 if (!out_fp)
409 return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
412 log_debug ("WARNING: The server mode is WORK "
413 "iN PROGRESS and not ready for use\n");
415 /* Need to dup it because it might get closed and libassuan won't
416 know about it then. */
417 rc = gpg_verify (ctrl,
418 dup ( FD2INT (fd)),
419 dup ( FD2INT (ctrl->server_local->message_fd)),
420 out_fp);
422 if (out_fp)
423 fclose (out_fp);
424 close_message_fd (ctrl);
425 assuan_close_input_fd (ctx);
426 assuan_close_output_fd (ctx);
428 if (rc)
429 log_error ("command '%s' failed: %s\n", "VERIFY", gpg_strerror (rc));
430 return rc;
435 /* SIGN [--detached]
437 Sign the data set with the INPUT command and write it to the sink
438 set by OUTPUT. With "--detached" specified, a detached signature
439 is created. */
440 static gpg_error_t
441 cmd_sign (assuan_context_t ctx, char *line)
443 (void)ctx;
444 (void)line;
445 return gpg_error (GPG_ERR_NOT_SUPPORTED);
450 /* IMPORT
452 Import keys as read from the input-fd, return status message for
453 each imported one. The import checks the validity of the key. */
454 static gpg_error_t
455 cmd_import (assuan_context_t ctx, char *line)
457 (void)ctx;
458 (void)line;
459 return gpg_error (GPG_ERR_NOT_SUPPORTED);
464 /* EXPORT [--data [--armor|--base64]] [--] pattern
466 Similar to the --export command line command, this command exports
467 public keys matching PATTERN. The output is send to the output fd
468 unless the --data option has been used in which case the output
469 gets send inline using regular data lines. The options "--armor"
470 and "--base" ospecify an output format if "--data" has been used.
471 Recall that in general the output format is set with the OUTPUT
472 command.
474 static gpg_error_t
475 cmd_export (assuan_context_t ctx, char *line)
477 (void)ctx;
478 (void)line;
479 return gpg_error (GPG_ERR_NOT_SUPPORTED);
484 /* DELKEYS
486 Fixme
488 static gpg_error_t
489 cmd_delkeys (assuan_context_t ctx, char *line)
491 (void)ctx;
492 (void)line;
493 return gpg_error (GPG_ERR_NOT_SUPPORTED);
498 /* MESSAGE FD[=<n>]
500 Set the file descriptor to read a message which is used with
501 detached signatures. */
502 static gpg_error_t
503 cmd_message (assuan_context_t ctx, char *line)
505 int rc;
506 gnupg_fd_t fd;
507 ctrl_t ctrl = assuan_get_pointer (ctx);
509 rc = assuan_command_parse_fd (ctx, line, &fd);
510 if (rc)
511 return rc;
512 if (fd == GNUPG_INVALID_FD)
513 return gpg_error (GPG_ERR_ASS_NO_INPUT);
514 ctrl->server_local->message_fd = fd;
515 return 0;
520 /* LISTKEYS [<patterns>]
521 LISTSECRETKEYS [<patterns>]
523 fixme
525 static gpg_error_t
526 do_listkeys (assuan_context_t ctx, char *line, int mode)
528 (void)ctx;
529 (void)line;
530 (void)mode;
532 return gpg_error (GPG_ERR_NOT_SUPPORTED);
536 static gpg_error_t
537 cmd_listkeys (assuan_context_t ctx, char *line)
539 return do_listkeys (ctx, line, 3);
543 static gpg_error_t
544 cmd_listsecretkeys (assuan_context_t ctx, char *line)
546 return do_listkeys (ctx, line, 2);
551 /* GENKEY
553 Read the parameters in native format from the input fd and create a
554 new OpenPGP key.
556 static gpg_error_t
557 cmd_genkey (assuan_context_t ctx, char *line)
559 (void)ctx;
560 (void)line;
561 return gpg_error (GPG_ERR_NOT_SUPPORTED);
565 /* GETINFO <what>
567 Multipurpose function to return a variety of information.
568 Supported values for WHAT are:
570 version - Return the version of the program.
571 pid - Return the process id of the server.
574 static gpg_error_t
575 cmd_getinfo (assuan_context_t ctx, char *line)
577 int rc;
579 if (!strcmp (line, "version"))
581 const char *s = VERSION;
582 rc = assuan_send_data (ctx, s, strlen (s));
584 else if (!strcmp (line, "pid"))
586 char numbuf[50];
588 snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
589 rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
591 else
592 rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
593 return rc;
598 /* Helper to register our commands with libassuan. */
599 static int
600 register_commands (assuan_context_t ctx)
602 static struct
604 const char *name;
605 gpg_error_t (*handler)(assuan_context_t, char *line);
606 } table[] = {
607 { "RECIPIENT", cmd_recipient },
608 { "SIGNER", cmd_signer },
609 { "ENCRYPT", cmd_encrypt },
610 { "DECRYPT", cmd_decrypt },
611 { "VERIFY", cmd_verify },
612 { "SIGN", cmd_sign },
613 { "IMPORT", cmd_import },
614 { "EXPORT", cmd_export },
615 { "INPUT", NULL },
616 { "OUTPUT", NULL },
617 { "MESSAGE", cmd_message },
618 { "LISTKEYS", cmd_listkeys },
619 { "LISTSECRETKEYS",cmd_listsecretkeys },
620 { "GENKEY", cmd_genkey },
621 { "DELKEYS", cmd_delkeys },
622 { "GETINFO", cmd_getinfo },
623 { NULL }
625 int i, rc;
627 for (i=0; table[i].name; i++)
629 rc = assuan_register_command (ctx, table[i].name, table[i].handler);
630 if (rc)
631 return rc;
633 return 0;
639 /* Startup the server. CTRL must have been allocated by the caller
640 and set to the default values. */
642 gpg_server (ctrl_t ctrl)
644 int rc;
645 int filedes[2];
646 assuan_context_t ctx = NULL;
647 static const char hello[] = ("GNU Privacy Guard's OpenPGP server "
648 VERSION " ready");
650 /* We use a pipe based server so that we can work from scripts.
651 assuan_init_pipe_server will automagically detect when we are
652 called with a socketpair and ignore FILEDES in this case. */
653 filedes[0] = 0;
654 filedes[1] = 1;
655 rc = assuan_new (&ctx);
656 if (rc)
658 log_error ("failed to allocate the assuan context: %s\n",
659 gpg_strerror (rc));
660 goto leave;
663 rc = assuan_init_pipe_server (ctx, filedes);
664 if (rc)
666 log_error ("failed to initialize the server: %s\n", gpg_strerror (rc));
667 goto leave;
670 rc = register_commands (ctx);
671 if (rc)
673 log_error ("failed to the register commands with Assuan: %s\n",
674 gpg_strerror(rc));
675 goto leave;
678 assuan_set_pointer (ctx, ctrl);
679 if (opt.verbose || opt.debug)
681 char *tmp = NULL;
682 const char *s1 = getenv ("GPG_AGENT_INFO");
684 tmp = xtryasprintf ("Home: %s\n"
685 "Config: %s\n"
686 "AgentInfo: %s\n"
687 "%s",
688 opt.homedir,
689 "fixme: need config filename",
690 s1?s1:"[not set]",
691 hello);
692 if (tmp)
694 assuan_set_hello_line (ctx, tmp);
695 xfree (tmp);
698 else
699 assuan_set_hello_line (ctx, hello);
700 assuan_register_reset_notify (ctx, reset_notify);
701 assuan_register_input_notify (ctx, input_notify);
702 assuan_register_output_notify (ctx, output_notify);
703 assuan_register_option_handler (ctx, option_handler);
705 ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
706 if (!ctrl->server_local)
708 rc = gpg_error_from_syserror ();
709 goto leave;
711 ctrl->server_local->assuan_ctx = ctx;
712 ctrl->server_local->message_fd = GNUPG_INVALID_FD;
714 if (DBG_ASSUAN)
715 assuan_set_log_stream (ctx, log_get_stream ());
717 for (;;)
719 rc = assuan_accept (ctx);
720 if (rc == -1)
722 rc = 0;
723 break;
725 else if (rc)
727 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
728 break;
731 rc = assuan_process (ctx);
732 if (rc)
734 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
735 continue;
739 leave:
740 if (ctrl->server_local)
742 release_pk_list (ctrl->server_local->recplist);
744 xfree (ctrl->server_local);
745 ctrl->server_local = NULL;
747 assuan_release (ctx);
748 return rc;