Bump to 2.4.3
[platform/upstream/gpg2.git] / g13 / sh-cmd.c
1 /* sh-cmd.c - The Assuan server for g13-syshelp
2  * Copyright (C) 2015 Werner Koch
3  *
4  * This file is part of GnuPG.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include "g13-syshelp.h"
29 #include <assuan.h>
30 #include "../common/i18n.h"
31 #include "../common/asshelp.h"
32 #include "keyblob.h"
33
34
35 /* Local data for this server module.  A pointer to this is stored in
36    the CTRL object of each connection.  */
37 struct server_local_s
38 {
39   /* The Assuan context we are working on.  */
40   assuan_context_t assuan_ctx;
41
42   /* The malloced name of the device.  */
43   char *devicename;
44
45   /* A stream open for read of the device set by the DEVICE command or
46      NULL if no DEVICE command has been used.  */
47   estream_t devicefp;
48 };
49
50
51
52 \f
53 /* Local prototypes.  */
54
55
56
57 \f
58 /*
59    Helper functions.
60  */
61
62 /* Set an error and a description.  */
63 #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
64 #define set_error_fail_cmd() set_error (GPG_ERR_NOT_INITIALIZED, \
65                                         "not called via userv or unknown user")
66
67
68 /* Skip over options.  Blanks after the options are also removed.  */
69 static char *
70 skip_options (const char *line)
71 {
72   while (spacep (line))
73     line++;
74   while ( *line == '-' && line[1] == '-' )
75     {
76       while (*line && !spacep (line))
77         line++;
78       while (spacep (line))
79         line++;
80     }
81   return (char*)line;
82 }
83
84
85 /* Check whether the option NAME appears in LINE.  */
86 /* static int */
87 /* has_option (const char *line, const char *name) */
88 /* { */
89 /*   const char *s; */
90 /*   int n = strlen (name); */
91
92 /*   s = strstr (line, name); */
93 /*   if (s && s >= skip_options (line)) */
94 /*     return 0; */
95 /*   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n))); */
96 /* } */
97
98
99 /* Helper to print a message while leaving a command.  */
100 static gpg_error_t
101 leave_cmd (assuan_context_t ctx, gpg_error_t err)
102 {
103   if (err)
104     {
105       const char *name = assuan_get_command_name (ctx);
106       if (!name)
107         name = "?";
108       if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
109         log_error ("command '%s' failed: %s\n", name,
110                    gpg_strerror (err));
111       else
112         log_error ("command '%s' failed: %s <%s>\n", name,
113                    gpg_strerror (err), gpg_strsource (err));
114     }
115   return err;
116 }
117
118
119
120 \f
121 /* The handler for Assuan OPTION commands.  */
122 static gpg_error_t
123 option_handler (assuan_context_t ctx, const char *key, const char *value)
124 {
125   ctrl_t ctrl = assuan_get_pointer (ctx);
126   gpg_error_t err = 0;
127
128   (void)ctrl;
129   (void)key;
130   (void)value;
131
132   if (ctrl->fail_all_cmds)
133     err = set_error_fail_cmd ();
134   else
135     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
136
137   return err;
138 }
139
140
141 /* The handler for an Assuan RESET command.  */
142 static gpg_error_t
143 reset_notify (assuan_context_t ctx, char *line)
144 {
145   ctrl_t ctrl = assuan_get_pointer (ctx);
146
147   (void)line;
148
149   xfree (ctrl->server_local->devicename);
150   ctrl->server_local->devicename = NULL;
151   es_fclose (ctrl->server_local->devicefp);
152   ctrl->server_local->devicefp = NULL;
153   ctrl->devti = NULL;
154
155   assuan_close_input_fd (ctx);
156   assuan_close_output_fd (ctx);
157   return 0;
158 }
159
160
161 static const char hlp_finddevice[] =
162   "FINDDEVICE <name>\n"
163   "\n"
164   "Find the device matching NAME.  NAME be any identifier from\n"
165   "g13tab permissible for the user.  The corresponding block\n"
166   "device is returned using a status line.";
167 static gpg_error_t
168 cmd_finddevice (assuan_context_t ctx, char *line)
169 {
170   ctrl_t ctrl = assuan_get_pointer (ctx);
171   gpg_error_t err = 0;
172   tab_item_t ti;
173   const char *s;
174   const char *name;
175
176   name = skip_options (line);
177
178   /* Are we allowed to use the given device?  We check several names:
179    *  1. The full block device
180    *  2. The label
181    *  3. The final part of the block device if NAME does not have a slash.
182    *  4. The mountpoint
183    */
184   for (ti=ctrl->client.tab; ti; ti = ti->next)
185     if (!strcmp (name, ti->blockdev))
186       break;
187   if (!ti)
188     {
189       for (ti=ctrl->client.tab; ti; ti = ti->next)
190         if (ti->label && !strcmp (name, ti->label))
191           break;
192     }
193   if (!ti && !strchr (name, '/'))
194     {
195       for (ti=ctrl->client.tab; ti; ti = ti->next)
196         {
197           s = strrchr (ti->blockdev, '/');
198           if (s && s[1] && !strcmp (name, s+1))
199             break;
200         }
201     }
202   if (!ti)
203     {
204       for (ti=ctrl->client.tab; ti; ti = ti->next)
205         if (ti->mountpoint && !strcmp (name, ti->mountpoint))
206           break;
207     }
208
209   if (!ti)
210     {
211       err = set_error (GPG_ERR_NOT_FOUND, "device not configured for user");
212       goto leave;
213     }
214
215   /* Check whether we have permissions to open the device.  */
216   {
217     estream_t fp = es_fopen (ti->blockdev, "rb");
218     if (!fp)
219       {
220         err = gpg_error_from_syserror ();
221         log_error ("error opening '%s': %s\n",
222                    ti->blockdev, gpg_strerror (err));
223         goto leave;
224       }
225     es_fclose (fp);
226   }
227
228   err = g13_status (ctrl, STATUS_BLOCKDEV, ti->blockdev, NULL);
229   if (err)
230     return err;
231
232  leave:
233   return leave_cmd (ctx, err);
234 }
235
236
237 static const char hlp_device[] =
238   "DEVICE <name>\n"
239   "\n"
240   "Set the device used by further commands.\n"
241   "A device name or a PARTUUID string may be used.\n"
242   "Access to that device (by the g13 system) is locked\n"
243   "until a new DEVICE command or end of this process\n";
244 static gpg_error_t
245 cmd_device (assuan_context_t ctx, char *line)
246 {
247   ctrl_t ctrl = assuan_get_pointer (ctx);
248   gpg_error_t err = 0;
249   tab_item_t ti;
250   estream_t fp = NULL;
251
252   line = skip_options (line);
253
254 /* # warning hardwired to /dev/sdb1 ! */
255 /*   if (strcmp (line, "/dev/sdb1")) */
256 /*     { */
257 /*       err = gpg_error (GPG_ERR_ENOENT); */
258 /*       goto leave; */
259 /*     } */
260
261   /* Always close an open device stream of this session. */
262   xfree (ctrl->server_local->devicename);
263   ctrl->server_local->devicename = NULL;
264   es_fclose (ctrl->server_local->devicefp);
265   ctrl->server_local->devicefp = NULL;
266
267   /* Are we allowed to use the given device?  */
268   for (ti=ctrl->client.tab; ti; ti = ti->next)
269     if (!strcmp (line, ti->blockdev))
270       break;
271   if (!ti)
272     {
273       err = set_error (GPG_ERR_EACCES, "device not configured for user");
274       goto leave;
275     }
276
277   ctrl->server_local->devicename = xtrystrdup (line);
278   if (!ctrl->server_local->devicename)
279     {
280       err = gpg_error_from_syserror ();
281       goto leave;
282     }
283
284
285   /* Check whether we have permissions to open the device and keep an
286      FD open.  */
287   fp = es_fopen (ctrl->server_local->devicename, "rb");
288   if (!fp)
289     {
290       err = gpg_error_from_syserror ();
291       log_error ("error opening '%s': %s\n",
292                  ctrl->server_local->devicename, gpg_strerror (err));
293       goto leave;
294     }
295
296   es_fclose (ctrl->server_local->devicefp);
297   ctrl->server_local->devicefp = fp;
298   fp = NULL;
299   ctrl->devti = ti;
300
301   /* Fixme: Take some kind of lock.  */
302
303  leave:
304   es_fclose (fp);
305   if (err)
306     {
307       xfree (ctrl->server_local->devicename);
308       ctrl->server_local->devicename = NULL;
309       ctrl->devti = NULL;
310     }
311   return leave_cmd (ctx, err);
312 }
313
314
315 static const char hlp_create[] =
316   "CREATE <type>\n"
317   "\n"
318   "Create a new encrypted partition on the current device.\n"
319   "<type> must be \"dm-crypt\" for now.";
320 static gpg_error_t
321 cmd_create (assuan_context_t ctx, char *line)
322 {
323   ctrl_t ctrl = assuan_get_pointer (ctx);
324   gpg_error_t err = 0;
325   estream_t fp = NULL;
326
327   line = skip_options (line);
328   if (strcmp (line, "dm-crypt"))
329     {
330       err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
331       goto leave;
332     }
333
334   if (!ctrl->server_local->devicename
335       || !ctrl->server_local->devicefp
336       || !ctrl->devti)
337     {
338       err = set_error (GPG_ERR_ENOENT, "No device has been set");
339       goto leave;
340     }
341
342   err = sh_is_empty_partition (ctrl->server_local->devicename);
343   if (err)
344     {
345       if (gpg_err_code (err) == GPG_ERR_FALSE)
346         err = gpg_error (GPG_ERR_CONFLICT);
347       err = assuan_set_error (ctx, err, "Partition is not empty");
348       goto leave;
349     }
350
351   /* We need a writeable stream to create the container.  */
352   fp = es_fopen (ctrl->server_local->devicename, "r+b");
353   if (!fp)
354     {
355       err = gpg_error_from_syserror ();
356       log_error ("error opening '%s': %s\n",
357                  ctrl->server_local->devicename, gpg_strerror (err));
358       goto leave;
359     }
360   if (es_setvbuf (fp, NULL, _IONBF, 0))
361     {
362       err = gpg_error_from_syserror ();
363       log_error ("error setting '%s' to _IONBF: %s\n",
364                  ctrl->server_local->devicename, gpg_strerror (err));
365       goto leave;
366     }
367
368   err = sh_dmcrypt_create_container (ctrl,
369                                      ctrl->server_local->devicename,
370                                      fp);
371   if (es_fclose (fp))
372     {
373       gpg_error_t err2 = gpg_error_from_syserror ();
374       log_error ("error closing '%s': %s\n",
375                  ctrl->server_local->devicename, gpg_strerror (err2));
376       if (!err)
377         err = err2;
378     }
379   fp = NULL;
380
381  leave:
382   es_fclose (fp);
383   return leave_cmd (ctx, err);
384 }
385
386
387 static const char hlp_getkeyblob[] =
388   "GETKEYBLOB\n"
389   "\n"
390   "Return the encrypted keyblob of the current device.";
391 static gpg_error_t
392 cmd_getkeyblob (assuan_context_t ctx, char *line)
393 {
394   ctrl_t ctrl = assuan_get_pointer (ctx);
395   gpg_error_t err;
396   void *enckeyblob = NULL;
397   size_t enckeybloblen;
398
399   line = skip_options (line);
400
401   if (!ctrl->server_local->devicename
402       || !ctrl->server_local->devicefp
403       || !ctrl->devti)
404     {
405       err = set_error (GPG_ERR_ENOENT, "No device has been set");
406       goto leave;
407     }
408
409   err = sh_is_empty_partition (ctrl->server_local->devicename);
410   if (!err)
411     {
412       err = gpg_error (GPG_ERR_ENODEV);
413       assuan_set_error (ctx, err, "Partition is empty");
414       goto leave;
415     }
416   err = 0;
417
418   err = g13_keyblob_read (ctrl->server_local->devicename,
419                           &enckeyblob, &enckeybloblen);
420   if (err)
421     goto leave;
422
423   err = assuan_send_data (ctx, enckeyblob, enckeybloblen);
424   if (!err)
425     err = assuan_send_data (ctx, NULL, 0); /* Flush  */
426
427  leave:
428   xfree (enckeyblob);
429   return leave_cmd (ctx, err);
430 }
431
432
433 static const char hlp_mount[] =
434   "MOUNT <type>\n"
435   "\n"
436   "Mount an encrypted partition on the current device.\n"
437   "<type> must be \"dm-crypt\" for now.";
438 static gpg_error_t
439 cmd_mount (assuan_context_t ctx, char *line)
440 {
441   ctrl_t ctrl = assuan_get_pointer (ctx);
442   gpg_error_t err = 0;
443   unsigned char *keyblob = NULL;
444   size_t keybloblen;
445   tupledesc_t tuples = NULL;
446
447   line = skip_options (line);
448
449   if (strcmp (line, "dm-crypt"))
450     {
451       err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
452       goto leave;
453     }
454
455   if (!ctrl->server_local->devicename
456       || !ctrl->server_local->devicefp
457       || !ctrl->devti)
458     {
459       err = set_error (GPG_ERR_ENOENT, "No device has been set");
460       goto leave;
461     }
462
463   err = sh_is_empty_partition (ctrl->server_local->devicename);
464   if (!err)
465     {
466       err = gpg_error (GPG_ERR_ENODEV);
467       assuan_set_error (ctx, err, "Partition is empty");
468       goto leave;
469     }
470   err = 0;
471
472   /* We expect that the client already decrypted the keyblob.
473    * Eventually we should move reading of the keyblob to here and ask
474    * the client to decrypt it.  */
475   assuan_begin_confidential (ctx);
476   err = assuan_inquire (ctx, "KEYBLOB",
477                         &keyblob, &keybloblen, 4 * 1024);
478   assuan_end_confidential (ctx);
479   if (err)
480     {
481       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
482       goto leave;
483     }
484   err = create_tupledesc (&tuples, keyblob, keybloblen);
485   if (!err)
486     keyblob = NULL;
487   else
488     {
489       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
490         log_error ("unknown keyblob version received\n");
491       goto leave;
492     }
493
494   err = sh_dmcrypt_mount_container (ctrl,
495                                     ctrl->server_local->devicename,
496                                     tuples);
497
498  leave:
499   destroy_tupledesc (tuples);
500   return leave_cmd (ctx, err);
501 }
502
503
504 static const char hlp_umount[] =
505   "UMOUNT <type>\n"
506   "\n"
507   "Unmount an encrypted partition and wipe the key.\n"
508   "<type> must be \"dm-crypt\" for now.";
509 static gpg_error_t
510 cmd_umount (assuan_context_t ctx, char *line)
511 {
512   ctrl_t ctrl = assuan_get_pointer (ctx);
513   gpg_error_t err = 0;
514
515   line = skip_options (line);
516
517   if (strcmp (line, "dm-crypt"))
518     {
519       err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
520       goto leave;
521     }
522
523   if (!ctrl->server_local->devicename
524       || !ctrl->server_local->devicefp
525       || !ctrl->devti)
526     {
527       err = set_error (GPG_ERR_ENOENT, "No device has been set");
528       goto leave;
529     }
530
531   err = sh_dmcrypt_umount_container (ctrl, ctrl->server_local->devicename);
532
533  leave:
534   return leave_cmd (ctx, err);
535 }
536
537
538 static const char hlp_suspend[] =
539   "SUSPEND <type>\n"
540   "\n"
541   "Suspend an encrypted partition and wipe the key.\n"
542   "<type> must be \"dm-crypt\" for now.";
543 static gpg_error_t
544 cmd_suspend (assuan_context_t ctx, char *line)
545 {
546   ctrl_t ctrl = assuan_get_pointer (ctx);
547   gpg_error_t err = 0;
548
549   line = skip_options (line);
550
551   if (strcmp (line, "dm-crypt"))
552     {
553       err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
554       goto leave;
555     }
556
557   if (!ctrl->server_local->devicename
558       || !ctrl->server_local->devicefp
559       || !ctrl->devti)
560     {
561       err = set_error (GPG_ERR_ENOENT, "No device has been set");
562       goto leave;
563     }
564
565   err = sh_is_empty_partition (ctrl->server_local->devicename);
566   if (!err)
567     {
568       err = gpg_error (GPG_ERR_ENODEV);
569       assuan_set_error (ctx, err, "Partition is empty");
570       goto leave;
571     }
572   err = 0;
573
574   err = sh_dmcrypt_suspend_container (ctrl, ctrl->server_local->devicename);
575
576  leave:
577   return leave_cmd (ctx, err);
578 }
579
580
581 static const char hlp_resume[] =
582   "RESUME <type>\n"
583   "\n"
584   "Resume an encrypted partition and set the key.\n"
585   "<type> must be \"dm-crypt\" for now.";
586 static gpg_error_t
587 cmd_resume (assuan_context_t ctx, char *line)
588 {
589   ctrl_t ctrl = assuan_get_pointer (ctx);
590   gpg_error_t err = 0;
591   unsigned char *keyblob = NULL;
592   size_t keybloblen;
593   tupledesc_t tuples = NULL;
594
595   line = skip_options (line);
596
597   if (strcmp (line, "dm-crypt"))
598     {
599       err = set_error (GPG_ERR_INV_ARG, "Type must be \"dm-crypt\"");
600       goto leave;
601     }
602
603   if (!ctrl->server_local->devicename
604       || !ctrl->server_local->devicefp
605       || !ctrl->devti)
606     {
607       err = set_error (GPG_ERR_ENOENT, "No device has been set");
608       goto leave;
609     }
610
611   err = sh_is_empty_partition (ctrl->server_local->devicename);
612   if (!err)
613     {
614       err = gpg_error (GPG_ERR_ENODEV);
615       assuan_set_error (ctx, err, "Partition is empty");
616       goto leave;
617     }
618   err = 0;
619
620   /* We expect that the client already decrypted the keyblob.
621    * Eventually we should move reading of the keyblob to here and ask
622    * the client to decrypt it.  */
623   assuan_begin_confidential (ctx);
624   err = assuan_inquire (ctx, "KEYBLOB",
625                         &keyblob, &keybloblen, 4 * 1024);
626   assuan_end_confidential (ctx);
627   if (err)
628     {
629       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
630       goto leave;
631     }
632   err = create_tupledesc (&tuples, keyblob, keybloblen);
633   if (!err)
634     keyblob = NULL;
635   else
636     {
637       if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
638         log_error ("unknown keyblob version received\n");
639       goto leave;
640     }
641
642   err = sh_dmcrypt_resume_container (ctrl,
643                                      ctrl->server_local->devicename,
644                                      tuples);
645
646  leave:
647   destroy_tupledesc (tuples);
648   return leave_cmd (ctx, err);
649 }
650
651
652 static const char hlp_getinfo[] =
653   "GETINFO <what>\n"
654   "\n"
655   "Multipurpose function to return a variety of information.\n"
656   "Supported values for WHAT are:\n"
657   "\n"
658   "  version     - Return the version of the program.\n"
659   "  pid         - Return the process id of the server.\n"
660   "  showtab     - Show the table for the user.";
661 static gpg_error_t
662 cmd_getinfo (assuan_context_t ctx, char *line)
663 {
664   ctrl_t ctrl = assuan_get_pointer (ctx);
665   gpg_error_t err = 0;
666   char *buf;
667
668   if (!strcmp (line, "version"))
669     {
670       const char *s = PACKAGE_VERSION;
671       err = assuan_send_data (ctx, s, strlen (s));
672     }
673   else if (!strcmp (line, "pid"))
674     {
675       char numbuf[50];
676
677       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
678       err = assuan_send_data (ctx, numbuf, strlen (numbuf));
679     }
680   else if (!strncmp (line, "getsz", 5))
681     {
682       unsigned long long nblocks;
683       err = sh_blockdev_getsz (line+6, &nblocks);
684       if (!err)
685         log_debug ("getsz=%llu\n", nblocks);
686     }
687   else if (!strcmp (line, "showtab"))
688     {
689       tab_item_t ti;
690
691       for (ti=ctrl->client.tab; !err && ti; ti = ti->next)
692         {
693           buf = es_bsprintf ("%s %s%s %s %s%s\n",
694                              ctrl->client.uname,
695                              *ti->blockdev=='/'? "":"partuuid=",
696                              ti->blockdev,
697                              ti->label? ti->label : "-",
698                              ti->mountpoint? " ":"",
699                              ti->mountpoint? ti->mountpoint:"");
700           if (!buf)
701             err = gpg_error_from_syserror ();
702           else
703             {
704               err = assuan_send_data (ctx, buf, strlen (buf));
705               if (!err)
706                 err = assuan_send_data (ctx, NULL, 0); /* Flush  */
707             }
708           xfree (buf);
709         }
710     }
711   else
712     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
713
714   return leave_cmd (ctx, err);
715 }
716
717
718 /* This command handler is used for all commands if this process has
719    not been started as expected.  */
720 static gpg_error_t
721 fail_command (assuan_context_t ctx, char *line)
722 {
723   gpg_error_t err;
724   const char *name = assuan_get_command_name (ctx);
725
726   (void)line;
727
728   if (!name)
729     name = "?";
730
731   err = set_error_fail_cmd ();
732   log_error ("command '%s' failed: %s\n", name, gpg_strerror (err));
733   return err;
734 }
735
736
737 /* Tell the Assuan library about our commands.  */
738 static int
739 register_commands (assuan_context_t ctx, int fail_all)
740 {
741   static struct {
742     const char *name;
743     assuan_handler_t handler;
744     const char * const help;
745   } table[] =  {
746     { "FINDDEVICE",    cmd_finddevice, hlp_finddevice },
747     { "DEVICE",        cmd_device, hlp_device },
748     { "CREATE",        cmd_create, hlp_create },
749     { "GETKEYBLOB",    cmd_getkeyblob,  hlp_getkeyblob },
750     { "MOUNT",         cmd_mount,  hlp_mount  },
751     { "UMOUNT",        cmd_umount, hlp_umount  },
752     { "SUSPEND",       cmd_suspend,hlp_suspend},
753     { "RESUME",        cmd_resume, hlp_resume },
754     { "INPUT",         NULL },
755     { "OUTPUT",        NULL },
756     { "GETINFO",       cmd_getinfo, hlp_getinfo },
757     { NULL }
758   };
759   gpg_error_t err;
760   int i;
761
762   for (i=0; table[i].name; i++)
763     {
764       err = assuan_register_command (ctx, table[i].name,
765                                      fail_all ? fail_command : table[i].handler,
766                                      table[i].help);
767       if (err)
768         return err;
769     }
770   return 0;
771 }
772
773
774 /* Startup the server.  */
775 gpg_error_t
776 syshelp_server (ctrl_t ctrl)
777 {
778   gpg_error_t err;
779   assuan_fd_t filedes[2];
780   assuan_context_t ctx = NULL;
781
782   /* We use a pipe based server so that we can work from scripts.
783      assuan_init_pipe_server will automagically detect when we are
784      called with a socketpair and ignore FILEDES in this case. */
785   filedes[0] = assuan_fdopen (0);
786   filedes[1] = assuan_fdopen (1);
787   err = assuan_new (&ctx);
788   if (err)
789     {
790       log_error ("failed to allocate an Assuan context: %s\n",
791                  gpg_strerror (err));
792       goto leave;
793     }
794
795   err = assuan_init_pipe_server (ctx, filedes);
796   if (err)
797     {
798       log_error ("failed to initialize the server: %s\n", gpg_strerror (err));
799       goto leave;
800     }
801
802   err = register_commands (ctx, 0 /*FIXME:ctrl->fail_all_cmds*/);
803   if (err)
804     {
805       log_error ("failed to the register commands with Assuan: %s\n",
806                  gpg_strerror (err));
807       goto leave;
808     }
809
810   assuan_set_pointer (ctx, ctrl);
811
812   {
813     char *tmp = xtryasprintf ("G13-syshelp %s ready to serve requests "
814                               "from %lu(%s)",
815                               PACKAGE_VERSION,
816                               (unsigned long)ctrl->client.uid,
817                               ctrl->client.uname);
818     if (tmp)
819       {
820         assuan_set_hello_line (ctx, tmp);
821         xfree (tmp);
822       }
823   }
824
825   assuan_register_reset_notify (ctx, reset_notify);
826   assuan_register_option_handler (ctx, option_handler);
827
828   ctrl->server_local = xtrycalloc (1, sizeof *ctrl->server_local);
829   if (!ctrl->server_local)
830     {
831       err = gpg_error_from_syserror ();
832       goto leave;
833     }
834   ctrl->server_local->assuan_ctx = ctx;
835
836   while ( !(err = assuan_accept (ctx)) )
837     {
838       err = assuan_process (ctx);
839       if (err)
840         log_info ("Assuan processing failed: %s\n", gpg_strerror (err));
841     }
842   if (err == -1)
843     err = 0;
844   else
845     log_info ("Assuan accept problem: %s\n", gpg_strerror (err));
846
847  leave:
848   reset_notify (ctx, NULL);  /* Release all items hold by SERVER_LOCAL.  */
849   if (ctrl->server_local)
850     {
851       xfree (ctrl->server_local);
852       ctrl->server_local = NULL;
853     }
854
855   assuan_release (ctx);
856   return err;
857 }
858
859
860 gpg_error_t
861 sh_encrypt_keyblob (ctrl_t ctrl, const void *keyblob, size_t keybloblen,
862                     char **r_enckeyblob, size_t *r_enckeybloblen)
863 {
864   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
865   gpg_error_t err;
866   unsigned char *enckeyblob;
867   size_t enckeybloblen;
868
869   *r_enckeyblob = NULL;
870
871   /* Send the plaintext.  */
872   err = g13_status (ctrl, STATUS_PLAINTEXT_FOLLOWS, NULL);
873   if (err)
874     return err;
875   assuan_begin_confidential (ctx);
876   err = assuan_send_data (ctx, keyblob, keybloblen);
877   if (!err)
878     err = assuan_send_data (ctx, NULL, 0);
879   assuan_end_confidential (ctx);
880   if (!err)
881     err = assuan_write_line (ctx, "END");
882   if (err)
883     {
884       log_error (_("error sending data: %s\n"), gpg_strerror (err));
885       return err;
886     }
887
888   /* Inquire the ciphertext.  */
889   err = assuan_inquire (ctx, "ENCKEYBLOB",
890                         &enckeyblob, &enckeybloblen, 16 * 1024);
891   if (err)
892     {
893       log_error (_("assuan_inquire failed: %s\n"), gpg_strerror (err));
894       return err;
895     }
896
897   *r_enckeyblob = enckeyblob;
898   *r_enckeybloblen = enckeybloblen;
899   return 0;
900 }
901
902
903 /* Send a status line with status ID NO.  The arguments are a list of
904    strings terminated by a NULL argument.  */
905 gpg_error_t
906 g13_status (ctrl_t ctrl, int no, ...)
907 {
908   gpg_error_t err;
909   va_list arg_ptr;
910
911   va_start (arg_ptr, no);
912
913   err = vprint_assuan_status_strings (ctrl->server_local->assuan_ctx,
914                                       get_status_string (no), arg_ptr);
915   va_end (arg_ptr);
916   return err;
917 }