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