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/>.
35 #include "../common/sysutils.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. */
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. */
57 /* Helper to close the message fd if it is open. */
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. */
71 skip_options (const char *line
)
75 while ( *line
== '-' && line
[1] == '-' )
77 while (*line
&& !spacep (line
))
86 /* Check whether the option NAME appears in LINE. */
88 has_option (const char *line
, const char *name
)
91 int n
= strlen (name
);
93 s
= strstr (line
, name
);
94 if (s
&& s
>= skip_options (line
))
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
106 option_handler (assuan_context_t ctx
, const char *key
, const char *value
)
108 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
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. */
140 return gpg_error (GPG_ERR_UNKNOWN_OPTION
);
146 /* Called by libassuan for RESET commands. */
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. */
163 input_notify (assuan_context_t ctx
, const char *line
)
165 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
169 if (strstr (line
, "--armor"))
171 else if (strstr (line
, "--base64"))
173 else if (strstr (line
, "--binary"))
177 /* FIXME (autodetect encoding) */
182 /* Called by libassuan for OUTPUT commands. */
184 output_notify (assuan_context_t ctx
, const char *line
)
186 /* ctrl_t ctrl = assuan_get_pointer (ctx); */
190 if (strstr (line
, "--armor"))
192 else if (strstr (line
, "--base64"))
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. */
213 cmd_recipient (assuan_context_t ctx
, char *line
)
215 ctrl_t ctrl
= assuan_get_pointer (ctx
);
219 hidden
= has_option (line
,"--hidden");
220 line
= skip_options (line
);
222 /* FIXME: Expand groups
224 remusr = expand_group (rcpts);
229 err
= find_and_check_key (line
, PUBKEY_USAGE_ENC
, hidden
,
230 &ctrl
->server_local
->recplist
);
233 log_error ("command '%s' failed: %s\n", "RECIPIENT", gpg_strerror (err
));
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. */
255 cmd_signer (assuan_context_t ctx
, char *line
)
259 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
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
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
284 cmd_encrypt (assuan_context_t ctx
, char *line
)
286 ctrl_t ctrl
= assuan_get_pointer (ctx
);
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
);
299 inp_fd
= translate_sys2libc_fd (assuan_get_input_fd (ctx
), 0);
302 err
= set_error (GPG_ERR_ASS_NO_INPUT
, NULL
);
305 out_fd
= translate_sys2libc_fd (assuan_get_output_fd (ctx
), 1);
308 err
= set_error (GPG_ERR_ASS_NO_OUTPUT
, NULL
);
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
,
327 /* Release the recipient list on success. */
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
);
340 log_error ("command '%s' failed: %s\n", "ENCRYPT", gpg_strerror (err
));
348 This performs the decrypt operation. */
350 cmd_decrypt (assuan_context_t ctx
, char *line
)
352 ctrl_t ctrl
= assuan_get_pointer (ctx
);
356 (void)line
; /* LINE is not used. */
358 inp_fd
= translate_sys2libc_fd (assuan_get_input_fd (ctx
), 0);
360 return set_error (GPG_ERR_ASS_NO_INPUT
, NULL
);
361 out_fd
= translate_sys2libc_fd (assuan_get_output_fd (ctx
), 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
);
373 log_error ("command '%s' failed: %s\n", "DECRYPT", gpg_strerror (err
));
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.
389 cmd_verify (assuan_context_t ctx
, char *line
)
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
);
397 /* FIXME: Revamp this code it is nearly to 3 years old and was only
398 intended as a quick test. */
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");
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
,
419 dup ( FD2INT (ctrl
->server_local
->message_fd
)),
424 close_message_fd (ctrl
);
425 assuan_close_input_fd (ctx
);
426 assuan_close_output_fd (ctx
);
429 log_error ("command '%s' failed: %s\n", "VERIFY", gpg_strerror (rc
));
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
441 cmd_sign (assuan_context_t ctx
, char *line
)
445 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
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. */
455 cmd_import (assuan_context_t ctx
, char *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
475 cmd_export (assuan_context_t ctx
, char *line
)
479 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
489 cmd_delkeys (assuan_context_t ctx
, char *line
)
493 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
500 Set the file descriptor to read a message which is used with
501 detached signatures. */
503 cmd_message (assuan_context_t ctx
, char *line
)
507 ctrl_t ctrl
= assuan_get_pointer (ctx
);
509 rc
= assuan_command_parse_fd (ctx
, line
, &fd
);
512 if (fd
== GNUPG_INVALID_FD
)
513 return gpg_error (GPG_ERR_ASS_NO_INPUT
);
514 ctrl
->server_local
->message_fd
= fd
;
520 /* LISTKEYS [<patterns>]
521 LISTSECRETKEYS [<patterns>]
526 do_listkeys (assuan_context_t ctx
, char *line
, int mode
)
532 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
537 cmd_listkeys (assuan_context_t ctx
, char *line
)
539 return do_listkeys (ctx
, line
, 3);
544 cmd_listsecretkeys (assuan_context_t ctx
, char *line
)
546 return do_listkeys (ctx
, line
, 2);
553 Read the parameters in native format from the input fd and create a
557 cmd_genkey (assuan_context_t ctx
, char *line
)
561 return gpg_error (GPG_ERR_NOT_SUPPORTED
);
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.
575 cmd_getinfo (assuan_context_t ctx
, char *line
)
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"))
588 snprintf (numbuf
, sizeof numbuf
, "%lu", (unsigned long)getpid ());
589 rc
= assuan_send_data (ctx
, numbuf
, strlen (numbuf
));
592 rc
= set_error (GPG_ERR_ASS_PARAMETER
, "unknown value for WHAT");
598 /* Helper to register our commands with libassuan. */
600 register_commands (assuan_context_t ctx
)
605 gpg_error_t (*handler
)(assuan_context_t
, char *line
);
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
},
617 { "MESSAGE", cmd_message
},
618 { "LISTKEYS", cmd_listkeys
},
619 { "LISTSECRETKEYS",cmd_listsecretkeys
},
620 { "GENKEY", cmd_genkey
},
621 { "DELKEYS", cmd_delkeys
},
622 { "GETINFO", cmd_getinfo
},
627 for (i
=0; table
[i
].name
; i
++)
629 rc
= assuan_register_command (ctx
, table
[i
].name
, table
[i
].handler
);
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
)
646 assuan_context_t ctx
= NULL
;
647 static const char hello
[] = ("GNU Privacy Guard's OpenPGP server "
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. */
655 rc
= assuan_new (&ctx
);
658 log_error ("failed to allocate the assuan context: %s\n",
663 rc
= assuan_init_pipe_server (ctx
, filedes
);
666 log_error ("failed to initialize the server: %s\n", gpg_strerror (rc
));
670 rc
= register_commands (ctx
);
673 log_error ("failed to the register commands with Assuan: %s\n",
678 assuan_set_pointer (ctx
, ctrl
);
679 if (opt
.verbose
|| opt
.debug
)
682 const char *s1
= getenv ("GPG_AGENT_INFO");
684 tmp
= xtryasprintf ("Home: %s\n"
689 "fixme: need config filename",
694 assuan_set_hello_line (ctx
, tmp
);
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 ();
711 ctrl
->server_local
->assuan_ctx
= ctx
;
712 ctrl
->server_local
->message_fd
= GNUPG_INVALID_FD
;
715 assuan_set_log_stream (ctx
, log_get_stream ());
719 rc
= assuan_accept (ctx
);
727 log_info ("Assuan accept problem: %s\n", gpg_strerror (rc
));
731 rc
= assuan_process (ctx
);
734 log_info ("Assuan processing failed: %s\n", gpg_strerror (rc
));
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
);