1 /* call-syshelp.c - Communication with g13-syshelp
2 * Copyright (C) 2015 Werner Koch
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
36 #include "call-syshelp.h"
39 /* Local data for this module. A pointer to this is stored in the
40 CTRL object of each connection. */
43 assuan_context_t assctx; /* The Assuan context for the current
44 g13-syshep connection. */
48 /* Parameter used with the CREATE command. */
54 unsigned int expect_plaintext:1;
55 unsigned int got_plaintext:1;
59 /* Parameter used with the MOUNT command. */
72 /* Fork off the syshelp tool if this has not already been done. On
73 success stores the current Assuan context for the syshelp tool at
76 start_syshelp (ctrl_t ctrl, assuan_context_t *r_ctx)
80 assuan_fd_t no_close_list[3];
85 if (ctrl->syshelp_local && (*r_ctx = ctrl->syshelp_local->assctx))
86 return 0; /* Already set. */
89 log_info ("starting a new syshelp\n");
91 if (!ctrl->syshelp_local)
93 ctrl->syshelp_local = xtrycalloc (1, sizeof *ctrl->syshelp_local);
94 if (!ctrl->syshelp_local)
95 return gpg_error_from_syserror ();
100 err = gpg_error_from_syserror ();
101 log_error ("error flushing pending output: %s\n", gpg_strerror (err));
106 if (log_get_fd () != -1)
107 no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
108 no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr));
109 no_close_list[i] = ASSUAN_INVALID_FD;
111 err = assuan_new (&ctx);
114 log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
118 /* Call userv to start g13-syshelp. This userv script needs to be
119 * installed under the name "gnupg-g13-syshelp":
121 * if ( glob service-user root
125 * execute /home/wk/b/gnupg/g13/g13-syshelp -v
127 * error Nothing to do for this service-user
136 argv[2] = "gnupg-g13-syshelp";
139 err = assuan_pipe_connect (ctx, "/usr/bin/userv", argv,
140 no_close_list, NULL, NULL, 0);
144 log_error ("can't connect to '%s': %s %s\n",
145 "g13-syshelp", gpg_strerror (err), gpg_strsource (err));
146 log_info ("(is userv and its gnupg-g13-syshelp script installed?)\n");
147 assuan_release (ctx);
151 *r_ctx = ctrl->syshelp_local->assctx = ctx;
154 log_debug ("connection to g13-syshelp established\n");
160 /* Release local resources associated with CTRL. */
162 call_syshelp_release (ctrl_t ctrl)
166 if (ctrl->syshelp_local)
168 assuan_release (ctrl->syshelp_local->assctx);
169 ctrl->syshelp_local->assctx = NULL;
170 xfree (ctrl->syshelp_local);
171 ctrl->syshelp_local = NULL;
177 /* Staus callback for call_syshelp_find_device. */
179 finddevice_status_cb (void *opaque, const char *line)
181 char **r_blockdev = opaque;
184 if ((p = has_leading_keyword (line, "BLOCKDEV")) && *p && !*r_blockdev)
186 *r_blockdev = xtrystrdup (p);
188 return gpg_error_from_syserror ();
195 /* Send the FINDDEVICE command to the syshelper. On success the name
196 * of the block device is stored at R_BLOCKDEV. */
198 call_syshelp_find_device (ctrl_t ctrl, const char *name, char **r_blockdev)
201 assuan_context_t ctx;
203 char *blockdev = NULL; /* The result. */
207 err = start_syshelp (ctrl, &ctx);
211 line = xtryasprintf ("FINDDEVICE %s", name);
214 err = gpg_error_from_syserror ();
217 err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL,
218 finddevice_status_cb, &blockdev);
223 log_error ("status line for successful FINDDEVICE missing\n");
224 err = gpg_error (GPG_ERR_UNEXPECTED);
227 *r_blockdev = blockdev;
239 getkeyblob_data_cb (void *opaque, const void *data, size_t datalen)
241 membuf_t *mb = opaque;
244 put_membuf (mb, data, datalen);
250 /* Send the GTEKEYBLOB command to the syshelper. On success the
251 * encrypted keyblpob is stored at (R_ENCKEYBLOB,R_ENCKEYBLOBLEN). */
253 call_syshelp_get_keyblob (ctrl_t ctrl,
254 void **r_enckeyblob, size_t *r_enckeybloblen)
257 assuan_context_t ctx;
260 *r_enckeyblob = NULL;
261 *r_enckeybloblen = 0;
262 init_membuf (&mb, 512);
264 err = start_syshelp (ctrl, &ctx);
268 err = assuan_transact (ctx, "GETKEYBLOB",
269 getkeyblob_data_cb, &mb,
270 NULL, NULL, NULL, NULL);
273 *r_enckeyblob = get_membuf (&mb, r_enckeybloblen);
275 err = gpg_error_from_syserror ();
278 xfree (get_membuf (&mb, NULL));
284 /* Send the DEVICE command to the syshelper. FNAME is the name of the
287 call_syshelp_set_device (ctrl_t ctrl, const char *fname)
290 assuan_context_t ctx;
293 err = start_syshelp (ctrl, &ctx);
297 line = xtryasprintf ("DEVICE %s", fname);
300 err = gpg_error_from_syserror ();
303 err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
313 create_status_cb (void *opaque, const char *line)
315 struct create_parm_s *parm = opaque;
317 if (has_leading_keyword (line, "PLAINTEXT_FOLLOWS"))
318 parm->expect_plaintext = 1;
325 create_data_cb (void *opaque, const void *data, size_t datalen)
327 struct create_parm_s *parm = opaque;
330 if (!parm->expect_plaintext)
332 log_error ("status line for data missing\n");
333 err = gpg_error (GPG_ERR_UNEXPECTED);
337 put_membuf (&parm->plaintext, data, datalen);
341 parm->expect_plaintext = 0;
342 parm->got_plaintext = 1;
350 create_inq_cb (void *opaque, const char *line)
352 struct create_parm_s *parm = opaque;
355 if (has_leading_keyword (line, "ENCKEYBLOB"))
360 if (!parm->got_plaintext)
361 err = gpg_error (GPG_ERR_UNEXPECTED);
362 else if (!(plaintext = get_membuf (&parm->plaintext, &plaintextlen)))
363 err = gpg_error_from_syserror ();
367 size_t ciphertextlen;
369 log_printhex ("plain", plaintext, plaintextlen);
370 err = g13_encrypt_keyblob (parm->ctrl,
371 plaintext, plaintextlen,
372 &ciphertext, &ciphertextlen);
373 wipememory (plaintext, plaintextlen);
376 log_error ("error encrypting keyblob: %s\n", gpg_strerror (err));
379 err = assuan_send_data (parm->ctx, ciphertext, ciphertextlen);
382 log_error ("sending ciphertext to g13-syshelp failed: %s\n",
388 err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
394 /* Run the CREATE command on the current device. CONTTYPES gives the
395 requested content type for the new container. */
397 call_syshelp_run_create (ctrl_t ctrl, int conttype)
400 assuan_context_t ctx;
401 struct create_parm_s parm;
403 memset (&parm, 0, sizeof parm);
405 err = start_syshelp (ctrl, &ctx);
409 /* tty_get ("waiting for debugger"); */
410 /* tty_kill_prompt (); */
414 init_membuf (&parm.plaintext, 512);
415 if (conttype == CONTTYPE_DM_CRYPT)
417 err = assuan_transact (ctx, "CREATE dm-crypt",
418 create_data_cb, &parm,
419 create_inq_cb, &parm,
420 create_status_cb, &parm);
424 log_error ("invalid backend type %d given\n", conttype);
425 err = GPG_ERR_INTERNAL;
430 xfree (get_membuf (&parm.plaintext, NULL));
437 mount_status_cb (void *opaque, const char *line)
439 struct mount_parm_s *parm = opaque;
441 /* Nothing right now. */
449 /* Inquire callback for MOUNT and RESUME. */
451 mount_inq_cb (void *opaque, const char *line)
453 struct mount_parm_s *parm = opaque;
456 if (has_leading_keyword (line, "KEYBLOB"))
458 int setconfidential = !assuan_get_flag (parm->ctx, ASSUAN_CONFIDENTIAL);
461 assuan_begin_confidential (parm->ctx);
462 err = assuan_send_data (parm->ctx, parm->keyblob, parm->keybloblen);
464 assuan_end_confidential (parm->ctx);
466 log_error ("sending keyblob to g13-syshelp failed: %s\n",
470 err = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
477 * Run the MOUNT command on the current device. CONTTYPES gives the
478 * requested content type for the new container. MOUNTPOINT the
479 * desired mount point or NULL for default.
482 call_syshelp_run_mount (ctrl_t ctrl, int conttype, const char *mountpoint,
486 assuan_context_t ctx;
487 struct mount_parm_s parm;
489 memset (&parm, 0, sizeof parm);
491 err = start_syshelp (ctrl, &ctx);
495 /* tty_get ("waiting for debugger"); */
496 /* tty_kill_prompt (); */
500 if (conttype == CONTTYPE_DM_CRYPT)
502 ref_tupledesc (tuples);
503 parm.keyblob = get_tupledesc_data (tuples, &parm.keybloblen);
504 err = assuan_transact (ctx, "MOUNT dm-crypt",
507 mount_status_cb, &parm);
508 unref_tupledesc (tuples);
512 (void)mountpoint; /* Not used. */
513 log_error ("invalid backend type %d given\n", conttype);
514 err = GPG_ERR_INTERNAL;
525 * Run the UMOUNT command on the current device. CONTTYPES gives the
526 * content type of the container (fixme: Do we really need this?).
529 call_syshelp_run_umount (ctrl_t ctrl, int conttype)
532 assuan_context_t ctx;
534 err = start_syshelp (ctrl, &ctx);
538 if (conttype == CONTTYPE_DM_CRYPT)
540 err = assuan_transact (ctx, "UMOUNT dm-crypt",
547 log_error ("invalid backend type %d given\n", conttype);
548 err = GPG_ERR_INTERNAL;
559 * Run the SUSPEND command on the current device. CONTTYPES gives the
560 * requested content type for the new container.
563 call_syshelp_run_suspend (ctrl_t ctrl, int conttype)
566 assuan_context_t ctx;
568 err = start_syshelp (ctrl, &ctx);
572 if (conttype == CONTTYPE_DM_CRYPT)
574 err = assuan_transact (ctx, "SUSPEND dm-crypt",
581 log_error ("invalid backend type %d given\n", conttype);
582 err = GPG_ERR_INTERNAL;
592 /* Run the RESUME command on the current device. CONTTYPES gives the
593 requested content type for the container. */
595 call_syshelp_run_resume (ctrl_t ctrl, int conttype, tupledesc_t tuples)
598 assuan_context_t ctx;
599 struct mount_parm_s parm;
601 memset (&parm, 0, sizeof parm);
603 err = start_syshelp (ctrl, &ctx);
607 /* tty_get ("waiting for debugger"); */
608 /* tty_kill_prompt (); */
612 if (conttype == CONTTYPE_DM_CRYPT)
614 ref_tupledesc (tuples);
615 parm.keyblob = get_tupledesc_data (tuples, &parm.keybloblen);
616 err = assuan_transact (ctx, "RESUME dm-crypt",
620 unref_tupledesc (tuples);
624 log_error ("invalid backend type %d given\n", conttype);
625 err = GPG_ERR_INTERNAL;