Line data Source code
1 : /* server.c - Server mode and main entry point
2 : * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3 : * 2010 Free Software Foundation, Inc.
4 : *
5 : * This file is part of GnuPG.
6 : *
7 : * GnuPG is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 3 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * GnuPG is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <config.h>
22 : #include <errno.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 : #include <stdarg.h>
27 : #include <ctype.h>
28 : #include <unistd.h>
29 :
30 : #include "gpgsm.h"
31 : #include <assuan.h>
32 : #include "sysutils.h"
33 :
34 : #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
35 :
36 :
37 : /* The filepointer for status message used in non-server mode */
38 : static FILE *statusfp;
39 :
40 : /* Data used to assuciate an Assuan context with local server data */
41 : struct server_local_s {
42 : assuan_context_t assuan_ctx;
43 : int message_fd;
44 : int list_internal;
45 : int list_external;
46 : int list_to_output; /* Write keylistings to the output fd. */
47 : int enable_audit_log; /* Use an audit log. */
48 : certlist_t recplist;
49 : certlist_t signerlist;
50 : certlist_t default_recplist; /* As set by main() - don't release. */
51 : int allow_pinentry_notify; /* Set if pinentry notifications should
52 : be passed back to the client. */
53 : int no_encrypt_to; /* Local version of option. */
54 : };
55 :
56 :
57 : /* Cookie definition for assuan data line output. */
58 : static ssize_t data_line_cookie_write (void *cookie,
59 : const void *buffer, size_t size);
60 : static int data_line_cookie_close (void *cookie);
61 : static es_cookie_io_functions_t data_line_cookie_functions =
62 : {
63 : NULL,
64 : data_line_cookie_write,
65 : NULL,
66 : data_line_cookie_close
67 : };
68 :
69 :
70 :
71 : static int command_has_option (const char *cmd, const char *cmdopt);
72 :
73 :
74 :
75 :
76 : /* Note that it is sufficient to allocate the target string D as
77 : long as the source string S, i.e.: strlen(s)+1; */
78 : static void
79 0 : strcpy_escaped_plus (char *d, const char *s)
80 : {
81 0 : while (*s)
82 : {
83 0 : if (*s == '%' && s[1] && s[2])
84 : {
85 0 : s++;
86 0 : *d++ = xtoi_2 (s);
87 0 : s += 2;
88 : }
89 0 : else if (*s == '+')
90 0 : *d++ = ' ', s++;
91 : else
92 0 : *d++ = *s++;
93 : }
94 0 : *d = 0;
95 0 : }
96 :
97 :
98 : /* Skip over options.
99 : Blanks after the options are also removed. */
100 : static char *
101 0 : skip_options (const char *line)
102 : {
103 0 : while (spacep (line))
104 0 : line++;
105 0 : while ( *line == '-' && line[1] == '-' )
106 : {
107 0 : while (*line && !spacep (line))
108 0 : line++;
109 0 : while (spacep (line))
110 0 : line++;
111 : }
112 0 : return (char*)line;
113 : }
114 :
115 :
116 : /* Check whether the option NAME appears in LINE */
117 : static int
118 0 : has_option (const char *line, const char *name)
119 : {
120 : const char *s;
121 0 : int n = strlen (name);
122 :
123 0 : s = strstr (line, name);
124 0 : if (s && s >= skip_options (line))
125 0 : return 0;
126 0 : return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
127 : }
128 :
129 :
130 : /* A write handler used by es_fopencookie to write assuan data
131 : lines. */
132 : static ssize_t
133 0 : data_line_cookie_write (void *cookie, const void *buffer, size_t size)
134 : {
135 0 : assuan_context_t ctx = cookie;
136 :
137 0 : if (assuan_send_data (ctx, buffer, size))
138 : {
139 0 : gpg_err_set_errno (EIO);
140 0 : return -1;
141 : }
142 :
143 0 : return size;
144 : }
145 :
146 : static int
147 0 : data_line_cookie_close (void *cookie)
148 : {
149 0 : assuan_context_t ctx = cookie;
150 :
151 0 : if (assuan_send_data (ctx, NULL, 0))
152 : {
153 0 : gpg_err_set_errno (EIO);
154 0 : return -1;
155 : }
156 :
157 0 : return 0;
158 : }
159 :
160 :
161 : static void
162 0 : close_message_fd (ctrl_t ctrl)
163 : {
164 0 : if (ctrl->server_local->message_fd != -1)
165 : {
166 : #ifdef HAVE_W32CE_SYSTEM
167 : #warning Is this correct for W32/W32CE?
168 : #endif
169 0 : close (ctrl->server_local->message_fd);
170 0 : ctrl->server_local->message_fd = -1;
171 : }
172 0 : }
173 :
174 :
175 : /* Start a new audit session if this has been enabled. */
176 : static gpg_error_t
177 0 : start_audit_session (ctrl_t ctrl)
178 : {
179 0 : audit_release (ctrl->audit);
180 0 : ctrl->audit = NULL;
181 0 : if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
182 0 : return gpg_error_from_syserror ();
183 :
184 0 : return 0;
185 : }
186 :
187 :
188 : static gpg_error_t
189 0 : option_handler (assuan_context_t ctx, const char *key, const char *value)
190 : {
191 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
192 0 : gpg_error_t err = 0;
193 :
194 0 : if (!strcmp (key, "putenv"))
195 : {
196 : /* Change the session's environment to be used for the
197 : Pinentry. Valid values are:
198 : <NAME> Delete envvar NAME
199 : <KEY>= Set envvar NAME to the empty string
200 : <KEY>=<VALUE> Set envvar NAME to VALUE
201 : */
202 0 : err = session_env_putenv (opt.session_env, value);
203 : }
204 0 : else if (!strcmp (key, "display"))
205 : {
206 0 : err = session_env_setenv (opt.session_env, "DISPLAY", value);
207 : }
208 0 : else if (!strcmp (key, "ttyname"))
209 : {
210 0 : err = session_env_setenv (opt.session_env, "GPG_TTY", value);
211 : }
212 0 : else if (!strcmp (key, "ttytype"))
213 : {
214 0 : err = session_env_setenv (opt.session_env, "TERM", value);
215 : }
216 0 : else if (!strcmp (key, "lc-ctype"))
217 : {
218 0 : xfree (opt.lc_ctype);
219 0 : opt.lc_ctype = xtrystrdup (value);
220 0 : if (!opt.lc_ctype)
221 0 : err = gpg_error_from_syserror ();
222 : }
223 0 : else if (!strcmp (key, "lc-messages"))
224 : {
225 0 : xfree (opt.lc_messages);
226 0 : opt.lc_messages = xtrystrdup (value);
227 0 : if (!opt.lc_messages)
228 0 : err = gpg_error_from_syserror ();
229 : }
230 0 : else if (!strcmp (key, "xauthority"))
231 : {
232 0 : err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
233 : }
234 0 : else if (!strcmp (key, "pinentry-user-data"))
235 : {
236 0 : err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
237 : }
238 0 : else if (!strcmp (key, "include-certs"))
239 : {
240 0 : int i = *value? atoi (value) : -1;
241 0 : if (ctrl->include_certs < -2)
242 0 : err = gpg_error (GPG_ERR_ASS_PARAMETER);
243 : else
244 0 : ctrl->include_certs = i;
245 : }
246 0 : else if (!strcmp (key, "list-mode"))
247 : {
248 0 : int i = *value? atoi (value) : 0;
249 0 : if (!i || i == 1) /* default and mode 1 */
250 : {
251 0 : ctrl->server_local->list_internal = 1;
252 0 : ctrl->server_local->list_external = 0;
253 : }
254 0 : else if (i == 2)
255 : {
256 0 : ctrl->server_local->list_internal = 0;
257 0 : ctrl->server_local->list_external = 1;
258 : }
259 0 : else if (i == 3)
260 : {
261 0 : ctrl->server_local->list_internal = 1;
262 0 : ctrl->server_local->list_external = 1;
263 : }
264 : else
265 0 : err = gpg_error (GPG_ERR_ASS_PARAMETER);
266 : }
267 0 : else if (!strcmp (key, "list-to-output"))
268 : {
269 0 : int i = *value? atoi (value) : 0;
270 0 : ctrl->server_local->list_to_output = i;
271 : }
272 0 : else if (!strcmp (key, "with-validation"))
273 : {
274 0 : int i = *value? atoi (value) : 0;
275 0 : ctrl->with_validation = i;
276 : }
277 0 : else if (!strcmp (key, "with-secret"))
278 : {
279 0 : int i = *value? atoi (value) : 0;
280 0 : ctrl->with_secret = i;
281 : }
282 0 : else if (!strcmp (key, "validation-model"))
283 : {
284 0 : int i = gpgsm_parse_validation_model (value);
285 0 : if ( i >= 0 && i <= 2 )
286 0 : ctrl->validation_model = i;
287 : else
288 0 : err = gpg_error (GPG_ERR_ASS_PARAMETER);
289 : }
290 0 : else if (!strcmp (key, "with-key-data"))
291 : {
292 0 : opt.with_key_data = 1;
293 : }
294 0 : else if (!strcmp (key, "enable-audit-log"))
295 : {
296 0 : int i = *value? atoi (value) : 0;
297 0 : ctrl->server_local->enable_audit_log = i;
298 : }
299 0 : else if (!strcmp (key, "allow-pinentry-notify"))
300 : {
301 0 : ctrl->server_local->allow_pinentry_notify = 1;
302 : }
303 0 : else if (!strcmp (key, "with-ephemeral-keys"))
304 : {
305 0 : int i = *value? atoi (value) : 0;
306 0 : ctrl->with_ephemeral_keys = i;
307 : }
308 0 : else if (!strcmp (key, "no-encrypt-to"))
309 : {
310 0 : ctrl->server_local->no_encrypt_to = 1;
311 : }
312 0 : else if (!strcmp (key, "offline"))
313 : {
314 : /* We ignore this option if gpgsm has been started with
315 : --disable-dirmngr (which also sets offline). */
316 0 : if (!opt.disable_dirmngr)
317 : {
318 0 : int i = *value? !!atoi (value) : 1;
319 0 : ctrl->offline = i;
320 : }
321 : }
322 : else
323 0 : err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
324 :
325 0 : return err;
326 : }
327 :
328 :
329 : static gpg_error_t
330 0 : reset_notify (assuan_context_t ctx, char *line)
331 : {
332 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
333 :
334 : (void) line;
335 :
336 0 : gpgsm_release_certlist (ctrl->server_local->recplist);
337 0 : gpgsm_release_certlist (ctrl->server_local->signerlist);
338 0 : ctrl->server_local->recplist = NULL;
339 0 : ctrl->server_local->signerlist = NULL;
340 0 : close_message_fd (ctrl);
341 0 : assuan_close_input_fd (ctx);
342 0 : assuan_close_output_fd (ctx);
343 0 : return 0;
344 : }
345 :
346 :
347 : static gpg_error_t
348 0 : input_notify (assuan_context_t ctx, char *line)
349 : {
350 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
351 :
352 0 : ctrl->autodetect_encoding = 0;
353 0 : ctrl->is_pem = 0;
354 0 : ctrl->is_base64 = 0;
355 0 : if (strstr (line, "--armor"))
356 0 : ctrl->is_pem = 1;
357 0 : else if (strstr (line, "--base64"))
358 0 : ctrl->is_base64 = 1;
359 0 : else if (strstr (line, "--binary"))
360 : ;
361 : else
362 0 : ctrl->autodetect_encoding = 1;
363 0 : return 0;
364 : }
365 :
366 : static gpg_error_t
367 0 : output_notify (assuan_context_t ctx, char *line)
368 : {
369 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
370 :
371 0 : ctrl->create_pem = 0;
372 0 : ctrl->create_base64 = 0;
373 0 : if (strstr (line, "--armor"))
374 0 : ctrl->create_pem = 1;
375 0 : else if (strstr (line, "--base64"))
376 0 : ctrl->create_base64 = 1; /* just the raw output */
377 0 : return 0;
378 : }
379 :
380 :
381 : static const char hlp_recipient[] =
382 : "RECIPIENT <userID>\n"
383 : "\n"
384 : "Set the recipient for the encryption. USERID shall be the\n"
385 : "internal representation of the key; the server may accept any other\n"
386 : "way of specification [we will support this]. If this is a valid and\n"
387 : "trusted recipient the server does respond with OK, otherwise the\n"
388 : "return is an ERR with the reason why the recipient can't be used,\n"
389 : "the encryption will then not be done for this recipient. If the\n"
390 : "policy is not to encrypt at all if not all recipients are valid, the\n"
391 : "client has to take care of this. All RECIPIENT commands are\n"
392 : "cumulative until a RESET or an successful ENCRYPT command.";
393 : static gpg_error_t
394 0 : cmd_recipient (assuan_context_t ctx, char *line)
395 : {
396 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
397 : int rc;
398 :
399 0 : if (!ctrl->audit)
400 0 : rc = start_audit_session (ctrl);
401 : else
402 0 : rc = 0;
403 :
404 0 : if (!rc)
405 0 : rc = gpgsm_add_to_certlist (ctrl, line, 0,
406 0 : &ctrl->server_local->recplist, 0);
407 0 : if (rc)
408 : {
409 0 : gpgsm_status2 (ctrl, STATUS_INV_RECP,
410 : get_inv_recpsgnr_code (rc), line, NULL);
411 : }
412 :
413 0 : return rc;
414 : }
415 :
416 :
417 : static const char hlp_signer[] =
418 : "SIGNER <userID>\n"
419 : "\n"
420 : "Set the signer's keys for the signature creation. USERID should\n"
421 : "be the internal representation of the key; the server may accept any\n"
422 : "other way of specification [we will support this]. If this is a\n"
423 : "valid and usable signing key the server does respond with OK,\n"
424 : "otherwise it returns an ERR with the reason why the key can't be\n"
425 : "used, the signing will then not be done for this key. If the policy\n"
426 : "is not to sign at all if not all signer keys are valid, the client\n"
427 : "has to take care of this. All SIGNER commands are cumulative until\n"
428 : "a RESET but they are *not* reset by an SIGN command becuase it can\n"
429 : "be expected that set of signers are used for more than one sign\n"
430 : "operation.";
431 : static gpg_error_t
432 0 : cmd_signer (assuan_context_t ctx, char *line)
433 : {
434 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
435 : int rc;
436 :
437 0 : rc = gpgsm_add_to_certlist (ctrl, line, 1,
438 0 : &ctrl->server_local->signerlist, 0);
439 0 : if (rc)
440 : {
441 0 : gpgsm_status2 (ctrl, STATUS_INV_SGNR,
442 : get_inv_recpsgnr_code (rc), line, NULL);
443 : /* For compatibiliy reasons we also issue the old code after the
444 : new one. */
445 0 : gpgsm_status2 (ctrl, STATUS_INV_RECP,
446 : get_inv_recpsgnr_code (rc), line, NULL);
447 : }
448 0 : return rc;
449 : }
450 :
451 :
452 : static const char hlp_encrypt[] =
453 : "ENCRYPT \n"
454 : "\n"
455 : "Do the actual encryption process. Takes the plaintext from the INPUT\n"
456 : "command, writes to the ciphertext to the file descriptor set with\n"
457 : "the OUTPUT command, take the recipients form all the recipients set\n"
458 : "so far. If this command fails the clients should try to delete all\n"
459 : "output currently done or otherwise mark it as invalid. GPGSM does\n"
460 : "ensure that there won't be any security problem with leftover data\n"
461 : "on the output in this case.\n"
462 : "\n"
463 : "This command should in general not fail, as all necessary checks\n"
464 : "have been done while setting the recipients. The input and output\n"
465 : "pipes are closed.";
466 : static gpg_error_t
467 0 : cmd_encrypt (assuan_context_t ctx, char *line)
468 : {
469 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
470 : certlist_t cl;
471 : int inp_fd, out_fd;
472 : estream_t out_fp;
473 : int rc;
474 :
475 : (void)line;
476 :
477 0 : inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
478 0 : if (inp_fd == -1)
479 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
480 0 : out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
481 0 : if (out_fd == -1)
482 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
483 :
484 0 : out_fp = es_fdopen_nc (out_fd, "w");
485 0 : if (!out_fp)
486 0 : return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
487 :
488 : /* Now add all encrypt-to marked recipients from the default
489 : list. */
490 0 : rc = 0;
491 0 : if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
492 : {
493 0 : for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
494 0 : if (cl->is_encrypt_to)
495 0 : rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
496 0 : &ctrl->server_local->recplist, 1);
497 : }
498 0 : if (!rc)
499 0 : rc = ctrl->audit? 0 : start_audit_session (ctrl);
500 0 : if (!rc)
501 0 : rc = gpgsm_encrypt (assuan_get_pointer (ctx),
502 0 : ctrl->server_local->recplist,
503 : inp_fd, out_fp);
504 0 : es_fclose (out_fp);
505 :
506 0 : gpgsm_release_certlist (ctrl->server_local->recplist);
507 0 : ctrl->server_local->recplist = NULL;
508 : /* Close and reset the fd */
509 0 : close_message_fd (ctrl);
510 0 : assuan_close_input_fd (ctx);
511 0 : assuan_close_output_fd (ctx);
512 0 : return rc;
513 : }
514 :
515 :
516 : static const char hlp_decrypt[] =
517 : "DECRYPT\n"
518 : "\n"
519 : "This performs the decrypt operation after doing some check on the\n"
520 : "internal state. (e.g. that only needed data has been set). Because\n"
521 : "it utilizes the GPG-Agent for the session key decryption, there is\n"
522 : "no need to ask the client for a protecting passphrase - GPG-Agent\n"
523 : "does take care of this by requesting this from the user.";
524 : static gpg_error_t
525 0 : cmd_decrypt (assuan_context_t ctx, char *line)
526 : {
527 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
528 : int inp_fd, out_fd;
529 : estream_t out_fp;
530 : int rc;
531 :
532 : (void)line;
533 :
534 0 : inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
535 0 : if (inp_fd == -1)
536 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
537 0 : out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
538 0 : if (out_fd == -1)
539 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
540 :
541 0 : out_fp = es_fdopen_nc (out_fd, "w");
542 0 : if (!out_fp)
543 0 : return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
544 :
545 0 : rc = start_audit_session (ctrl);
546 0 : if (!rc)
547 0 : rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
548 0 : es_fclose (out_fp);
549 :
550 : /* Close and reset the fds. */
551 0 : close_message_fd (ctrl);
552 0 : assuan_close_input_fd (ctx);
553 0 : assuan_close_output_fd (ctx);
554 :
555 0 : return rc;
556 : }
557 :
558 :
559 : static const char hlp_verify[] =
560 : "VERIFY\n"
561 : "\n"
562 : "This does a verify operation on the message send to the input FD.\n"
563 : "The result is written out using status lines. If an output FD was\n"
564 : "given, the signed text will be written to that.\n"
565 : "\n"
566 : "If the signature is a detached one, the server will inquire about\n"
567 : "the signed material and the client must provide it.";
568 : static gpg_error_t
569 0 : cmd_verify (assuan_context_t ctx, char *line)
570 : {
571 : int rc;
572 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
573 0 : int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
574 0 : int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
575 0 : estream_t out_fp = NULL;
576 :
577 : (void)line;
578 :
579 0 : if (fd == -1)
580 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
581 :
582 0 : if (out_fd != -1)
583 : {
584 0 : out_fp = es_fdopen_nc (out_fd, "w");
585 0 : if (!out_fp)
586 0 : return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
587 : }
588 :
589 0 : rc = start_audit_session (ctrl);
590 0 : if (!rc)
591 0 : rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
592 0 : ctrl->server_local->message_fd, out_fp);
593 0 : es_fclose (out_fp);
594 :
595 : /* Close and reset the fd. */
596 0 : close_message_fd (ctrl);
597 0 : assuan_close_input_fd (ctx);
598 0 : assuan_close_output_fd (ctx);
599 :
600 0 : return rc;
601 : }
602 :
603 :
604 : static const char hlp_sign[] =
605 : "SIGN [--detached]\n"
606 : "\n"
607 : "Sign the data set with the INPUT command and write it to the sink\n"
608 : "set by OUTPUT. With \"--detached\", a detached signature is\n"
609 : "created (surprise).";
610 : static gpg_error_t
611 0 : cmd_sign (assuan_context_t ctx, char *line)
612 : {
613 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
614 : int inp_fd, out_fd;
615 : estream_t out_fp;
616 : int detached;
617 : int rc;
618 :
619 0 : inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
620 0 : if (inp_fd == -1)
621 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
622 0 : out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
623 0 : if (out_fd == -1)
624 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
625 :
626 0 : detached = has_option (line, "--detached");
627 :
628 0 : out_fp = es_fdopen_nc (out_fd, "w");
629 0 : if (!out_fp)
630 0 : return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
631 :
632 0 : rc = start_audit_session (ctrl);
633 0 : if (!rc)
634 0 : rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
635 : inp_fd, detached, out_fp);
636 0 : es_fclose (out_fp);
637 :
638 : /* close and reset the fd */
639 0 : close_message_fd (ctrl);
640 0 : assuan_close_input_fd (ctx);
641 0 : assuan_close_output_fd (ctx);
642 :
643 0 : return rc;
644 : }
645 :
646 :
647 : static const char hlp_import[] =
648 : "IMPORT [--re-import]\n"
649 : "\n"
650 : "Import the certificates read form the input-fd, return status\n"
651 : "message for each imported one. The import checks the validity of\n"
652 : "the certificate but not of the entire chain. It is possible to\n"
653 : "import expired certificates.\n"
654 : "\n"
655 : "With the option --re-import the input data is expected to a be a LF\n"
656 : "separated list of fingerprints. The command will re-import these\n"
657 : "certificates, meaning that they are made permanent by removing\n"
658 : "their ephemeral flag.";
659 : static gpg_error_t
660 0 : cmd_import (assuan_context_t ctx, char *line)
661 : {
662 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
663 : int rc;
664 0 : int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
665 0 : int reimport = has_option (line, "--re-import");
666 :
667 : (void)line;
668 :
669 0 : if (fd == -1)
670 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
671 :
672 0 : rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
673 :
674 : /* close and reset the fd */
675 0 : close_message_fd (ctrl);
676 0 : assuan_close_input_fd (ctx);
677 0 : assuan_close_output_fd (ctx);
678 :
679 0 : return rc;
680 : }
681 :
682 :
683 : static const char hlp_export[] =
684 : "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
685 : "\n"
686 : "Export the certificates selected by PATTERN. With --data the output\n"
687 : "is returned using Assuan D lines; the default is to use the sink given\n"
688 : "by the last \"OUTPUT\" command. The options --armor or --base64 encode \n"
689 : "the output using the PEM respective a plain base-64 format; the default\n"
690 : "is a binary format which is only suitable for a single certificate.\n"
691 : "With --secret the secret key is exported using the PKCS#8 format,\n"
692 : "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
693 : static gpg_error_t
694 0 : cmd_export (assuan_context_t ctx, char *line)
695 : {
696 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
697 : char *p;
698 : strlist_t list, sl;
699 : int use_data;
700 : int opt_secret;
701 0 : int opt_raw = 0;
702 0 : int opt_pkcs12 = 0;
703 :
704 0 : use_data = has_option (line, "--data");
705 0 : if (use_data)
706 : {
707 : /* We need to override any possible setting done by an OUTPUT command. */
708 0 : ctrl->create_pem = has_option (line, "--armor");
709 0 : ctrl->create_base64 = has_option (line, "--base64");
710 : }
711 0 : opt_secret = has_option (line, "--secret");
712 0 : if (opt_secret)
713 : {
714 0 : opt_raw = has_option (line, "--raw");
715 0 : opt_pkcs12 = has_option (line, "--pkcs12");
716 : }
717 :
718 0 : line = skip_options (line);
719 :
720 : /* Break the line down into an strlist_t. */
721 0 : list = NULL;
722 0 : for (p=line; *p; line = p)
723 : {
724 0 : while (*p && *p != ' ')
725 0 : p++;
726 0 : if (*p)
727 0 : *p++ = 0;
728 0 : if (*line)
729 : {
730 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
731 0 : if (!sl)
732 : {
733 0 : free_strlist (list);
734 0 : return out_of_core ();
735 : }
736 0 : sl->flags = 0;
737 0 : strcpy_escaped_plus (sl->d, line);
738 0 : sl->next = list;
739 0 : list = sl;
740 : }
741 : }
742 :
743 0 : if (opt_secret)
744 : {
745 0 : if (!list || !*list->d)
746 0 : return set_error (GPG_ERR_NO_DATA, "No key given");
747 0 : if (list->next)
748 0 : return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
749 : }
750 :
751 0 : if (use_data)
752 : {
753 : estream_t stream;
754 :
755 0 : stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
756 0 : if (!stream)
757 : {
758 0 : free_strlist (list);
759 0 : return set_error (GPG_ERR_ASS_GENERAL,
760 : "error setting up a data stream");
761 : }
762 0 : if (opt_secret)
763 0 : gpgsm_p12_export (ctrl, list->d, stream,
764 0 : opt_raw? 2 : opt_pkcs12 ? 0 : 1);
765 : else
766 0 : gpgsm_export (ctrl, list, stream);
767 0 : es_fclose (stream);
768 : }
769 : else
770 : {
771 0 : int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
772 : estream_t out_fp;
773 :
774 0 : if (fd == -1)
775 : {
776 0 : free_strlist (list);
777 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
778 : }
779 0 : out_fp = es_fdopen_nc (fd, "w");
780 0 : if (!out_fp)
781 : {
782 0 : free_strlist (list);
783 0 : return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
784 : }
785 :
786 0 : if (opt_secret)
787 0 : gpgsm_p12_export (ctrl, list->d, out_fp,
788 0 : opt_raw? 2 : opt_pkcs12 ? 0 : 1);
789 : else
790 0 : gpgsm_export (ctrl, list, out_fp);
791 0 : es_fclose (out_fp);
792 : }
793 :
794 0 : free_strlist (list);
795 : /* Close and reset the fds. */
796 0 : close_message_fd (ctrl);
797 0 : assuan_close_input_fd (ctx);
798 0 : assuan_close_output_fd (ctx);
799 0 : return 0;
800 : }
801 :
802 :
803 :
804 : static const char hlp_delkeys[] =
805 : "DELKEYS <patterns>\n"
806 : "\n"
807 : "Delete the certificates specified by PATTERNS. Each pattern shall be\n"
808 : "a percent-plus escaped certificate specification. Usually a\n"
809 : "fingerprint will be used for this.";
810 : static gpg_error_t
811 0 : cmd_delkeys (assuan_context_t ctx, char *line)
812 : {
813 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
814 : char *p;
815 : strlist_t list, sl;
816 : int rc;
817 :
818 : /* break the line down into an strlist_t */
819 0 : list = NULL;
820 0 : for (p=line; *p; line = p)
821 : {
822 0 : while (*p && *p != ' ')
823 0 : p++;
824 0 : if (*p)
825 0 : *p++ = 0;
826 0 : if (*line)
827 : {
828 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
829 0 : if (!sl)
830 : {
831 0 : free_strlist (list);
832 0 : return out_of_core ();
833 : }
834 0 : sl->flags = 0;
835 0 : strcpy_escaped_plus (sl->d, line);
836 0 : sl->next = list;
837 0 : list = sl;
838 : }
839 : }
840 :
841 0 : rc = gpgsm_delete (ctrl, list);
842 0 : free_strlist (list);
843 :
844 : /* close and reset the fd */
845 0 : close_message_fd (ctrl);
846 0 : assuan_close_input_fd (ctx);
847 0 : assuan_close_output_fd (ctx);
848 :
849 0 : return rc;
850 : }
851 :
852 :
853 :
854 : static const char hlp_output[] =
855 : "OUTPUT FD[=<n>]\n"
856 : "\n"
857 : "Set the file descriptor to write the output data to N. If N is not\n"
858 : "given and the operating system supports file descriptor passing, the\n"
859 : "file descriptor currently in flight will be used. See also the\n"
860 : "\"INPUT\" and \"MESSAGE\" commands.";
861 : static const char hlp_input[] =
862 : "INPUT FD[=<n>]\n"
863 : "\n"
864 : "Set the file descriptor to read the input data to N. If N is not\n"
865 : "given and the operating system supports file descriptor passing, the\n"
866 : "file descriptor currently in flight will be used. See also the\n"
867 : "\"MESSAGE\" and \"OUTPUT\" commands.";
868 : static const char hlp_message[] =
869 : "MESSAGE FD[=<n>]\n"
870 : "\n"
871 : "Set the file descriptor to read the message for a detached\n"
872 : "signatures to N. If N is not given and the operating system\n"
873 : "supports file descriptor passing, the file descriptor currently in\n"
874 : "flight will be used. See also the \"INPUT\" and \"OUTPUT\" commands.";
875 : static gpg_error_t
876 0 : cmd_message (assuan_context_t ctx, char *line)
877 : {
878 : int rc;
879 : gnupg_fd_t sysfd;
880 : int fd;
881 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
882 :
883 0 : rc = assuan_command_parse_fd (ctx, line, &sysfd);
884 0 : if (rc)
885 0 : return rc;
886 :
887 : #ifdef HAVE_W32CE_SYSTEM
888 : sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0);
889 : if (sysfd == INVALID_HANDLE_VALUE)
890 : return set_error (gpg_err_code_from_syserror (),
891 : "rvid conversion failed");
892 : #endif
893 :
894 0 : fd = translate_sys2libc_fd (sysfd, 0);
895 0 : if (fd == -1)
896 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
897 0 : ctrl->server_local->message_fd = fd;
898 0 : return 0;
899 : }
900 :
901 :
902 :
903 : static const char hlp_listkeys[] =
904 : "LISTKEYS [<patterns>]\n"
905 : "LISTSECRETKEYS [<patterns>]\n"
906 : "DUMPKEYS [<patterns>]\n"
907 : "DUMPSECRETKEYS [<patterns>]\n"
908 : "\n"
909 : "List all certificates or only those specified by PATTERNS. Each\n"
910 : "pattern shall be a percent-plus escaped certificate specification.\n"
911 : "The \"SECRET\" versions of the command filter the output to include\n"
912 : "only certificates where the secret key is available or a corresponding\n"
913 : "smartcard has been registered. The \"DUMP\" versions of the command\n"
914 : "are only useful for debugging. The output format is a percent escaped\n"
915 : "colon delimited listing as described in the manual.\n"
916 : "\n"
917 : "These \"OPTION\" command keys effect the output::\n"
918 : "\n"
919 : " \"list-mode\" set to 0: List only local certificates (default).\n"
920 : " 1: Ditto.\n"
921 : " 2: List only external certificates.\n"
922 : " 3: List local and external certificates.\n"
923 : "\n"
924 : " \"with-validation\" set to true: Validate each certificate.\n"
925 : "\n"
926 : " \"with-ephemeral-key\" set to true: Always include ephemeral\n"
927 : " certificates.\n"
928 : "\n"
929 : " \"list-to-output\" set to true: Write output to the file descriptor\n"
930 : " given by the last \"OUTPUT\" command.";
931 : static int
932 0 : do_listkeys (assuan_context_t ctx, char *line, int mode)
933 : {
934 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
935 : estream_t fp;
936 : char *p;
937 : strlist_t list, sl;
938 : unsigned int listmode;
939 : gpg_error_t err;
940 :
941 : /* Break the line down into an strlist. */
942 0 : list = NULL;
943 0 : for (p=line; *p; line = p)
944 : {
945 0 : while (*p && *p != ' ')
946 0 : p++;
947 0 : if (*p)
948 0 : *p++ = 0;
949 0 : if (*line)
950 : {
951 0 : sl = xtrymalloc (sizeof *sl + strlen (line));
952 0 : if (!sl)
953 : {
954 0 : free_strlist (list);
955 0 : return out_of_core ();
956 : }
957 0 : sl->flags = 0;
958 0 : strcpy_escaped_plus (sl->d, line);
959 0 : sl->next = list;
960 0 : list = sl;
961 : }
962 : }
963 :
964 0 : if (ctrl->server_local->list_to_output)
965 : {
966 0 : int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
967 :
968 0 : if ( outfd == -1 )
969 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
970 0 : fp = es_fdopen_nc (outfd, "w");
971 0 : if (!fp)
972 0 : return set_error (gpg_err_code_from_syserror (), "es_fdopen() failed");
973 : }
974 : else
975 : {
976 0 : fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
977 0 : if (!fp)
978 0 : return set_error (GPG_ERR_ASS_GENERAL,
979 : "error setting up a data stream");
980 : }
981 :
982 0 : ctrl->with_colons = 1;
983 0 : listmode = mode;
984 0 : if (ctrl->server_local->list_internal)
985 0 : listmode |= (1<<6);
986 0 : if (ctrl->server_local->list_external)
987 0 : listmode |= (1<<7);
988 0 : err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
989 0 : free_strlist (list);
990 0 : es_fclose (fp);
991 0 : if (ctrl->server_local->list_to_output)
992 0 : assuan_close_output_fd (ctx);
993 0 : return err;
994 : }
995 :
996 : static gpg_error_t
997 0 : cmd_listkeys (assuan_context_t ctx, char *line)
998 : {
999 0 : return do_listkeys (ctx, line, 3);
1000 : }
1001 :
1002 : static gpg_error_t
1003 0 : cmd_dumpkeys (assuan_context_t ctx, char *line)
1004 : {
1005 0 : return do_listkeys (ctx, line, 259);
1006 : }
1007 :
1008 : static gpg_error_t
1009 0 : cmd_listsecretkeys (assuan_context_t ctx, char *line)
1010 : {
1011 0 : return do_listkeys (ctx, line, 2);
1012 : }
1013 :
1014 : static gpg_error_t
1015 0 : cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
1016 : {
1017 0 : return do_listkeys (ctx, line, 258);
1018 : }
1019 :
1020 :
1021 :
1022 : static const char hlp_genkey[] =
1023 : "GENKEY\n"
1024 : "\n"
1025 : "Read the parameters in native format from the input fd and write a\n"
1026 : "certificate request to the output.";
1027 : static gpg_error_t
1028 0 : cmd_genkey (assuan_context_t ctx, char *line)
1029 : {
1030 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1031 : int inp_fd, out_fd;
1032 : estream_t in_stream, out_stream;
1033 : int rc;
1034 :
1035 : (void)line;
1036 :
1037 0 : inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
1038 0 : if (inp_fd == -1)
1039 0 : return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
1040 0 : out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1041 0 : if (out_fd == -1)
1042 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1043 :
1044 0 : in_stream = es_fdopen_nc (inp_fd, "r");
1045 0 : if (!in_stream)
1046 0 : return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
1047 :
1048 0 : out_stream = es_fdopen_nc (out_fd, "w");
1049 0 : if (!out_stream)
1050 : {
1051 0 : es_fclose (in_stream);
1052 0 : return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
1053 : }
1054 0 : rc = gpgsm_genkey (ctrl, in_stream, out_stream);
1055 0 : es_fclose (out_stream);
1056 0 : es_fclose (in_stream);
1057 :
1058 : /* close and reset the fds */
1059 0 : assuan_close_input_fd (ctx);
1060 0 : assuan_close_output_fd (ctx);
1061 :
1062 0 : return rc;
1063 : }
1064 :
1065 :
1066 :
1067 : static const char hlp_getauditlog[] =
1068 : "GETAUDITLOG [--data] [--html]\n"
1069 : "\n"
1070 : "If --data is used, the output is send using D-lines and not to the\n"
1071 : "file descriptor given by an OUTPUT command.\n"
1072 : "\n"
1073 : "If --html is used the output is formated as an XHTML block. This is\n"
1074 : "designed to be incorporated into a HTML document.";
1075 : static gpg_error_t
1076 0 : cmd_getauditlog (assuan_context_t ctx, char *line)
1077 : {
1078 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1079 : int out_fd;
1080 : estream_t out_stream;
1081 : int opt_data, opt_html;
1082 : int rc;
1083 :
1084 0 : opt_data = has_option (line, "--data");
1085 0 : opt_html = has_option (line, "--html");
1086 0 : line = skip_options (line);
1087 :
1088 0 : if (!ctrl->audit)
1089 0 : return gpg_error (GPG_ERR_NO_DATA);
1090 :
1091 0 : if (opt_data)
1092 : {
1093 0 : out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
1094 0 : if (!out_stream)
1095 0 : return set_error (GPG_ERR_ASS_GENERAL,
1096 : "error setting up a data stream");
1097 : }
1098 : else
1099 : {
1100 0 : out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
1101 0 : if (out_fd == -1)
1102 0 : return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
1103 :
1104 0 : out_stream = es_fdopen_nc (out_fd, "w");
1105 0 : if (!out_stream)
1106 : {
1107 0 : return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
1108 : }
1109 : }
1110 :
1111 0 : audit_print_result (ctrl->audit, out_stream, opt_html);
1112 0 : rc = 0;
1113 :
1114 0 : es_fclose (out_stream);
1115 :
1116 : /* Close and reset the fd. */
1117 0 : if (!opt_data)
1118 0 : assuan_close_output_fd (ctx);
1119 0 : return rc;
1120 : }
1121 :
1122 : static const char hlp_getinfo[] =
1123 : "GETINFO <what>\n"
1124 : "\n"
1125 : "Multipurpose function to return a variety of information.\n"
1126 : "Supported values for WHAT are:\n"
1127 : "\n"
1128 : " version - Return the version of the program.\n"
1129 : " pid - Return the process id of the server.\n"
1130 : " agent-check - Return success if the agent is running.\n"
1131 : " cmd_has_option CMD OPT\n"
1132 : " - Returns OK if the command CMD implements the option OPT.\n"
1133 : " offline - Returns OK if the conenction is in offline mode.";
1134 : static gpg_error_t
1135 0 : cmd_getinfo (assuan_context_t ctx, char *line)
1136 : {
1137 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1138 0 : int rc = 0;
1139 :
1140 0 : if (!strcmp (line, "version"))
1141 : {
1142 0 : const char *s = VERSION;
1143 0 : rc = assuan_send_data (ctx, s, strlen (s));
1144 : }
1145 0 : else if (!strcmp (line, "pid"))
1146 : {
1147 : char numbuf[50];
1148 :
1149 0 : snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
1150 0 : rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
1151 : }
1152 0 : else if (!strcmp (line, "agent-check"))
1153 : {
1154 0 : rc = gpgsm_agent_send_nop (ctrl);
1155 : }
1156 0 : else if (!strncmp (line, "cmd_has_option", 14)
1157 0 : && (line[14] == ' ' || line[14] == '\t' || !line[14]))
1158 0 : {
1159 : char *cmd, *cmdopt;
1160 0 : line += 14;
1161 0 : while (*line == ' ' || *line == '\t')
1162 0 : line++;
1163 0 : if (!*line)
1164 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
1165 : else
1166 : {
1167 0 : cmd = line;
1168 0 : while (*line && (*line != ' ' && *line != '\t'))
1169 0 : line++;
1170 0 : if (!*line)
1171 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
1172 : else
1173 : {
1174 0 : *line++ = 0;
1175 0 : while (*line == ' ' || *line == '\t')
1176 0 : line++;
1177 0 : if (!*line)
1178 0 : rc = gpg_error (GPG_ERR_MISSING_VALUE);
1179 : else
1180 : {
1181 0 : cmdopt = line;
1182 0 : if (!command_has_option (cmd, cmdopt))
1183 0 : rc = gpg_error (GPG_ERR_GENERAL);
1184 : }
1185 : }
1186 : }
1187 : }
1188 0 : else if (!strcmp (line, "offline"))
1189 : {
1190 0 : rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL);
1191 : }
1192 : else
1193 0 : rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
1194 :
1195 0 : return rc;
1196 : }
1197 :
1198 :
1199 : static const char hlp_passwd[] =
1200 : "PASSWD <userID>\n"
1201 : "\n"
1202 : "Change the passphrase of the secret key for USERID.";
1203 : static gpg_error_t
1204 0 : cmd_passwd (assuan_context_t ctx, char *line)
1205 : {
1206 0 : ctrl_t ctrl = assuan_get_pointer (ctx);
1207 : gpg_error_t err;
1208 0 : ksba_cert_t cert = NULL;
1209 0 : char *grip = NULL;
1210 :
1211 0 : line = skip_options (line);
1212 :
1213 0 : err = gpgsm_find_cert (line, NULL, &cert);
1214 0 : if (err)
1215 : ;
1216 0 : else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
1217 0 : err = gpg_error (GPG_ERR_INTERNAL);
1218 : else
1219 : {
1220 0 : char *desc = gpgsm_format_keydesc (cert);
1221 0 : err = gpgsm_agent_passwd (ctrl, grip, desc);
1222 0 : xfree (desc);
1223 : }
1224 :
1225 0 : xfree (grip);
1226 0 : ksba_cert_release (cert);
1227 :
1228 0 : return err;
1229 : }
1230 :
1231 :
1232 :
1233 : /* Return true if the command CMD implements the option OPT. */
1234 : static int
1235 0 : command_has_option (const char *cmd, const char *cmdopt)
1236 : {
1237 0 : if (!strcmp (cmd, "IMPORT"))
1238 : {
1239 0 : if (!strcmp (cmdopt, "re-import"))
1240 0 : return 1;
1241 : }
1242 :
1243 0 : return 0;
1244 : }
1245 :
1246 :
1247 : /* Tell the assuan library about our commands */
1248 : static int
1249 0 : register_commands (assuan_context_t ctx)
1250 : {
1251 : static struct {
1252 : const char *name;
1253 : assuan_handler_t handler;
1254 : const char * const help;
1255 : } table[] = {
1256 : { "RECIPIENT", cmd_recipient, hlp_recipient },
1257 : { "SIGNER", cmd_signer, hlp_signer },
1258 : { "ENCRYPT", cmd_encrypt, hlp_encrypt },
1259 : { "DECRYPT", cmd_decrypt, hlp_decrypt },
1260 : { "VERIFY", cmd_verify, hlp_verify },
1261 : { "SIGN", cmd_sign, hlp_sign },
1262 : { "IMPORT", cmd_import, hlp_import },
1263 : { "EXPORT", cmd_export, hlp_export },
1264 : { "INPUT", NULL, hlp_input },
1265 : { "OUTPUT", NULL, hlp_output },
1266 : { "MESSAGE", cmd_message, hlp_message },
1267 : { "LISTKEYS", cmd_listkeys, hlp_listkeys },
1268 : { "DUMPKEYS", cmd_dumpkeys, hlp_listkeys },
1269 : { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
1270 : { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
1271 : { "GENKEY", cmd_genkey, hlp_genkey },
1272 : { "DELKEYS", cmd_delkeys, hlp_delkeys },
1273 : { "GETAUDITLOG", cmd_getauditlog, hlp_getauditlog },
1274 : { "GETINFO", cmd_getinfo, hlp_getinfo },
1275 : { "PASSWD", cmd_passwd, hlp_passwd },
1276 : { NULL }
1277 : };
1278 : int i, rc;
1279 :
1280 0 : for (i=0; table[i].name; i++)
1281 : {
1282 0 : rc = assuan_register_command (ctx, table[i].name, table[i].handler,
1283 : table[i].help);
1284 0 : if (rc)
1285 0 : return rc;
1286 : }
1287 0 : return 0;
1288 : }
1289 :
1290 : /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
1291 : set from the command line or config file. We only require those
1292 : marked as encrypt-to. */
1293 : void
1294 0 : gpgsm_server (certlist_t default_recplist)
1295 : {
1296 : int rc;
1297 : assuan_fd_t filedes[2];
1298 : assuan_context_t ctx;
1299 : struct server_control_s ctrl;
1300 : static const char hello[] = ("GNU Privacy Guard's S/M server "
1301 : VERSION " ready");
1302 :
1303 0 : memset (&ctrl, 0, sizeof ctrl);
1304 0 : gpgsm_init_default_ctrl (&ctrl);
1305 :
1306 : /* We use a pipe based server so that we can work from scripts.
1307 : assuan_init_pipe_server will automagically detect when we are
1308 : called with a socketpair and ignore FILEDES in this case. */
1309 : #ifdef HAVE_W32CE_SYSTEM
1310 : #define SERVER_STDIN es_fileno(es_stdin)
1311 : #define SERVER_STDOUT es_fileno(es_stdout)
1312 : #else
1313 : #define SERVER_STDIN 0
1314 : #define SERVER_STDOUT 1
1315 : #endif
1316 0 : filedes[0] = assuan_fdopen (SERVER_STDIN);
1317 0 : filedes[1] = assuan_fdopen (SERVER_STDOUT);
1318 0 : rc = assuan_new (&ctx);
1319 0 : if (rc)
1320 : {
1321 0 : log_error ("failed to allocate assuan context: %s\n",
1322 : gpg_strerror (rc));
1323 0 : gpgsm_exit (2);
1324 : }
1325 :
1326 0 : rc = assuan_init_pipe_server (ctx, filedes);
1327 0 : if (rc)
1328 : {
1329 0 : log_error ("failed to initialize the server: %s\n",
1330 : gpg_strerror (rc));
1331 0 : gpgsm_exit (2);
1332 : }
1333 0 : rc = register_commands (ctx);
1334 0 : if (rc)
1335 : {
1336 0 : log_error ("failed to the register commands with Assuan: %s\n",
1337 : gpg_strerror(rc));
1338 0 : gpgsm_exit (2);
1339 : }
1340 0 : if (opt.verbose || opt.debug)
1341 0 : {
1342 0 : char *tmp = NULL;
1343 :
1344 : /* Fixme: Use the really used socket name. */
1345 0 : if (asprintf (&tmp,
1346 : "Home: %s\n"
1347 : "Config: %s\n"
1348 : "DirmngrInfo: %s\n"
1349 : "%s",
1350 : opt.homedir,
1351 : opt.config_filename,
1352 0 : (dirmngr_user_socket_name ()
1353 : ? dirmngr_user_socket_name ()
1354 : : dirmngr_sys_socket_name ()),
1355 : hello) > 0)
1356 : {
1357 0 : assuan_set_hello_line (ctx, tmp);
1358 0 : free (tmp);
1359 : }
1360 : }
1361 : else
1362 0 : assuan_set_hello_line (ctx, hello);
1363 :
1364 0 : assuan_register_reset_notify (ctx, reset_notify);
1365 0 : assuan_register_input_notify (ctx, input_notify);
1366 0 : assuan_register_output_notify (ctx, output_notify);
1367 0 : assuan_register_option_handler (ctx, option_handler);
1368 :
1369 0 : assuan_set_pointer (ctx, &ctrl);
1370 0 : ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
1371 0 : ctrl.server_local->assuan_ctx = ctx;
1372 0 : ctrl.server_local->message_fd = -1;
1373 0 : ctrl.server_local->list_internal = 1;
1374 0 : ctrl.server_local->list_external = 0;
1375 0 : ctrl.server_local->default_recplist = default_recplist;
1376 :
1377 : for (;;)
1378 : {
1379 0 : rc = assuan_accept (ctx);
1380 0 : if (rc == -1)
1381 : {
1382 0 : break;
1383 : }
1384 0 : else if (rc)
1385 : {
1386 0 : log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
1387 0 : break;
1388 : }
1389 :
1390 0 : rc = assuan_process (ctx);
1391 0 : if (rc)
1392 : {
1393 0 : log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
1394 0 : continue;
1395 : }
1396 0 : }
1397 :
1398 0 : gpgsm_release_certlist (ctrl.server_local->recplist);
1399 0 : ctrl.server_local->recplist = NULL;
1400 0 : gpgsm_release_certlist (ctrl.server_local->signerlist);
1401 0 : ctrl.server_local->signerlist = NULL;
1402 0 : xfree (ctrl.server_local);
1403 :
1404 0 : audit_release (ctrl.audit);
1405 0 : ctrl.audit = NULL;
1406 :
1407 0 : assuan_release (ctx);
1408 0 : }
1409 :
1410 :
1411 :
1412 : gpg_error_t
1413 9 : gpgsm_status2 (ctrl_t ctrl, int no, ...)
1414 : {
1415 9 : gpg_error_t err = 0;
1416 : va_list arg_ptr;
1417 : const char *text;
1418 :
1419 9 : va_start (arg_ptr, no);
1420 :
1421 9 : if (ctrl->no_server && ctrl->status_fd == -1)
1422 : ; /* No status wanted. */
1423 0 : else if (ctrl->no_server)
1424 : {
1425 0 : if (!statusfp)
1426 : {
1427 0 : if (ctrl->status_fd == 1)
1428 0 : statusfp = stdout;
1429 0 : else if (ctrl->status_fd == 2)
1430 0 : statusfp = stderr;
1431 : else
1432 0 : statusfp = fdopen (ctrl->status_fd, "w");
1433 :
1434 0 : if (!statusfp)
1435 : {
1436 0 : log_fatal ("can't open fd %d for status output: %s\n",
1437 0 : ctrl->status_fd, strerror(errno));
1438 : }
1439 : }
1440 :
1441 0 : fputs ("[GNUPG:] ", statusfp);
1442 0 : fputs (get_status_string (no), statusfp);
1443 :
1444 0 : while ( (text = va_arg (arg_ptr, const char*) ))
1445 : {
1446 0 : putc ( ' ', statusfp );
1447 0 : for (; *text; text++)
1448 : {
1449 0 : if (*text == '\n')
1450 0 : fputs ( "\\n", statusfp );
1451 0 : else if (*text == '\r')
1452 0 : fputs ( "\\r", statusfp );
1453 : else
1454 0 : putc ( *(const byte *)text, statusfp );
1455 : }
1456 : }
1457 0 : putc ('\n', statusfp);
1458 0 : fflush (statusfp);
1459 : }
1460 : else
1461 : {
1462 0 : assuan_context_t ctx = ctrl->server_local->assuan_ctx;
1463 : char buf[950], *p;
1464 : size_t n;
1465 :
1466 0 : p = buf;
1467 0 : n = 0;
1468 0 : while ( (text = va_arg (arg_ptr, const char *)) )
1469 : {
1470 0 : if (n)
1471 : {
1472 0 : *p++ = ' ';
1473 0 : n++;
1474 : }
1475 0 : for ( ; *text && n < DIM (buf)-2; n++)
1476 0 : *p++ = *text++;
1477 : }
1478 0 : *p = 0;
1479 0 : err = assuan_write_status (ctx, get_status_string (no), buf);
1480 : }
1481 :
1482 9 : va_end (arg_ptr);
1483 9 : return err;
1484 : }
1485 :
1486 : gpg_error_t
1487 3 : gpgsm_status (ctrl_t ctrl, int no, const char *text)
1488 : {
1489 3 : return gpgsm_status2 (ctrl, no, text, NULL);
1490 : }
1491 :
1492 : gpg_error_t
1493 0 : gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
1494 : gpg_err_code_t ec)
1495 : {
1496 : char buf[30];
1497 :
1498 0 : sprintf (buf, "%u", (unsigned int)ec);
1499 0 : if (text)
1500 0 : return gpgsm_status2 (ctrl, no, text, buf, NULL);
1501 : else
1502 0 : return gpgsm_status2 (ctrl, no, buf, NULL);
1503 : }
1504 :
1505 :
1506 : /* Helper to notify the client about Pinentry events. Because that
1507 : might disturb some older clients, this is only done when enabled
1508 : via an option. Returns an gpg error code. */
1509 : gpg_error_t
1510 0 : gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
1511 : {
1512 0 : if (!ctrl || !ctrl->server_local
1513 0 : || !ctrl->server_local->allow_pinentry_notify)
1514 0 : return 0;
1515 0 : return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
1516 : }
|