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