g13: Require a confirmation before g13 is used for DM-Crypt.
[gnupg.git] / g13 / g13-syshelp.c
1 /* g13-syshelp.c - Helper for disk key management with GnuPG
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 <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <limits.h>
29 #ifdef HAVE_PWD_H
30 # include <pwd.h>
31 #endif
32 #include <unistd.h>
33
34 #include "g13-syshelp.h"
35
36 #include <gcrypt.h>
37 #include <assuan.h>
38
39 #include "i18n.h"
40 #include "sysutils.h"
41 #include "asshelp.h"
42 #include "../common/init.h"
43 #include "keyblob.h"
44
45
46 enum cmd_and_opt_values {
47   aNull = 0,
48   oQuiet        = 'q',
49   oVerbose      = 'v',
50   oRecipient    = 'r',
51
52   aGPGConfList  = 500,
53
54   oDebug,
55   oDebugLevel,
56   oDebugAll,
57   oDebugNone,
58   oDebugWait,
59   oDebugAllowCoreDump,
60   oLogFile,
61   oNoLogFile,
62   oAuditLog,
63
64   oOutput,
65
66   oAgentProgram,
67   oGpgProgram,
68   oType,
69
70   oDisplay,
71   oTTYname,
72   oTTYtype,
73   oLCctype,
74   oLCmessages,
75   oXauthority,
76
77   oStatusFD,
78   oLoggerFD,
79
80   oNoVerbose,
81   oNoSecmemWarn,
82   oHomedir,
83   oDryRun,
84   oNoDetach,
85
86   oNoRandomSeedFile,
87   oFakedSystemTime
88  };
89
90
91 static ARGPARSE_OPTS opts[] = {
92
93   ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
94
95   ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
96   ARGPARSE_s_n (oQuiet, "quiet",  N_("be somewhat more quiet")),
97
98   ARGPARSE_s_s (oDebug, "debug", "@"),
99   ARGPARSE_s_s (oDebugLevel, "debug-level",
100                 N_("|LEVEL|set the debugging level to LEVEL")),
101   ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
102   ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
103   ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
104   ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
105
106   ARGPARSE_end ()
107 };
108
109
110 /* The list of supported debug flags.  */
111 static struct debug_flags_s debug_flags [] =
112   {
113     { DBG_MOUNT_VALUE  , "mount"  },
114     { DBG_CRYPTO_VALUE , "crypto"  },
115     { DBG_MEMORY_VALUE , "memory"  },
116     { DBG_MEMSTAT_VALUE, "memstat" },
117     { DBG_IPC_VALUE    , "ipc"     },
118     { 0, NULL }
119   };
120
121
122 /* The timer tick interval used by the idle task.  */
123 #define TIMERTICK_INTERVAL_SEC     (1)
124
125 /* It is possible that we are currently running under setuid permissions.  */
126 static int maybe_setuid = 1;
127
128 /* Helper to implement --debug-level and --debug.  */
129 static const char *debug_level;
130 static unsigned int debug_value;
131
132
133 /* Local prototypes.  */
134 static void g13_syshelp_deinit_default_ctrl (ctrl_t ctrl);
135 static void release_tab_items (tab_item_t tab);
136 static tab_item_t parse_g13tab (const char *username);
137
138
139 \f
140 static const char *
141 my_strusage( int level )
142 {
143   const char *p;
144
145   switch (level)
146     {
147     case 11: p = "@G13@-syshelp (@GNUPG@)";
148       break;
149     case 13: p = VERSION; break;
150     case 17: p = PRINTABLE_OS_NAME; break;
151     case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
152       break;
153     case 1:
154     case 40: p = _("Usage: @G13@-syshelp [options] [files] (-h for help)");
155       break;
156     case 41:
157       p = _("Syntax: @G13@-syshelp [options] [files]\n"
158             "Helper to perform root-only tasks for g13\n");
159       break;
160
161     case 31: p = "\nHome: "; break;
162     case 32: p = opt.homedir; break;
163
164     default: p = NULL; break;
165     }
166   return p;
167 }
168
169
170 /* Setup the debugging.  With a DEBUG_LEVEL of NULL only the active
171    debug flags are propagated to the subsystems.  With DEBUG_LEVEL
172    set, a specific set of debug flags is set; and individual debugging
173    flags will be added on top.  */
174 static void
175 set_debug (void)
176 {
177   int numok = (debug_level && digitp (debug_level));
178   int numlvl = numok? atoi (debug_level) : 0;
179
180   if (!debug_level)
181     ;
182   else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
183     opt.debug = 0;
184   else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
185     opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
186   else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
187     opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
188   else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
189     opt.debug = (DBG_IPC_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
190   else if (!strcmp (debug_level, "guru") || numok)
191     {
192       opt.debug = ~0;
193       /* if (numok) */
194       /*   opt.debug &= ~(DBG_HASHING_VALUE); */
195     }
196   else
197     {
198       log_error (_("invalid debug-level '%s' given\n"), debug_level);
199       g13_exit(2);
200     }
201
202   opt.debug |= debug_value;
203
204   if (opt.debug && !opt.verbose)
205     opt.verbose = 1;
206   if (opt.debug)
207     opt.quiet = 0;
208
209   if (opt.debug & DBG_CRYPTO_VALUE )
210     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
211   gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
212
213   if (opt.debug)
214     parse_debug_flag (NULL, &opt.debug, debug_flags);
215 }
216
217
218 int
219 main ( int argc, char **argv)
220 {
221   ARGPARSE_ARGS pargs;
222   int orig_argc;
223   char **orig_argv;
224   gpg_error_t err = 0;
225   /* const char *fname; */
226   int may_coredump;
227   FILE *configfp = NULL;
228   char *configname = NULL;
229   unsigned configlineno;
230   int parse_debug = 0;
231   int no_more_options = 0;
232   int default_config =1;
233   char *logfile = NULL;
234   /* int debug_wait = 0; */
235   int use_random_seed = 1;
236   /* int nodetach = 0; */
237   /* int nokeysetup = 0; */
238   struct server_control_s ctrl;
239
240   /*mtrace();*/
241
242   early_system_init ();
243   gnupg_reopen_std (G13_NAME "-syshelp");
244   set_strusage (my_strusage);
245   gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
246
247   log_set_prefix (G13_NAME "-syshelp", 1);
248
249   /* Make sure that our subsystems are ready.  */
250   i18n_init ();
251   init_common_subsystems (&argc, &argv);
252
253   /* Check that the Libgcrypt is suitable.  */
254   if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
255     log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
256                NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
257
258   /* Take extra care of the random pool.  */
259   gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
260
261   may_coredump = disable_core_dumps ();
262
263   g13_init_signals ();
264
265   dotlock_create (NULL, 0); /* Register locking cleanup.  */
266
267   opt.session_env = session_env_new ();
268   if (!opt.session_env)
269     log_fatal ("error allocating session environment block: %s\n",
270                strerror (errno));
271
272   opt.homedir = default_homedir ();
273   /* Fixme: We enable verbose mode here because there is currently no
274      way to do this when starting g13-syshelp.  To fix that we should
275      add a g13-syshelp.conf file in /etc/gnupg.  */
276   opt.verbose = 1;
277
278   /* First check whether we have a debug option on the commandline.  */
279   orig_argc = argc;
280   orig_argv = argv;
281   pargs.argc = &argc;
282   pargs.argv = &argv;
283   pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
284   while (arg_parse( &pargs, opts))
285     {
286       if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
287         parse_debug++;
288     }
289
290   /* Initialize the secure memory. */
291   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
292   maybe_setuid = 0;
293
294   /*
295      Now we are now working under our real uid
296   */
297
298   /* Setup malloc hooks. */
299   {
300     struct assuan_malloc_hooks malloc_hooks;
301
302     malloc_hooks.malloc = gcry_malloc;
303     malloc_hooks.realloc = gcry_realloc;
304     malloc_hooks.free = gcry_free;
305     assuan_set_malloc_hooks (&malloc_hooks);
306   }
307
308   /* Prepare libassuan.  */
309   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
310   /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
311   setup_libassuan_logging (&opt.debug);
312
313   /* Setup a default control structure for command line mode.  */
314   memset (&ctrl, 0, sizeof ctrl);
315   g13_syshelp_init_default_ctrl (&ctrl);
316   ctrl.no_server = 1;
317   ctrl.status_fd = -1; /* No status output. */
318
319   if (default_config )
320     configname = make_filename (gnupg_sysconfdir (),
321                                 G13_NAME"-syshelp.conf", NULL);
322
323   argc        = orig_argc;
324   argv        = orig_argv;
325   pargs.argc  = &argc;
326   pargs.argv  = &argv;
327   pargs.flags =  1;  /* Do not remove the args.  */
328
329  next_pass:
330   if (configname)
331     {
332       configlineno = 0;
333       configfp = fopen (configname, "r");
334       if (!configfp)
335         {
336           if (default_config)
337             {
338               if (parse_debug)
339                 log_info (_("NOTE: no default option file '%s'\n"), configname);
340             }
341           else
342             {
343               log_error (_("option file '%s': %s\n"),
344                          configname, strerror(errno));
345               g13_exit(2);
346             }
347           xfree (configname);
348           configname = NULL;
349         }
350       if (parse_debug && configname)
351         log_info (_("reading options from '%s'\n"), configname);
352       default_config = 0;
353     }
354
355   while (!no_more_options
356          && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
357     {
358       switch (pargs.r_opt)
359         {
360         case oQuiet: opt.quiet = 1; break;
361
362         case oDryRun: opt.dry_run = 1; break;
363
364         case oVerbose:
365           opt.verbose++;
366           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
367           break;
368         case oNoVerbose:
369           opt.verbose = 0;
370           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
371           break;
372
373         case oLogFile: logfile = pargs.r.ret_str; break;
374         case oNoLogFile: logfile = NULL; break;
375
376         case oNoDetach: /*nodetach = 1; */break;
377
378         case oDebug:
379           if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
380             {
381               pargs.r_opt = ARGPARSE_INVALID_ARG;
382               pargs.err = ARGPARSE_PRINT_ERROR;
383             }
384             break;
385         case oDebugAll: debug_value = ~0; break;
386         case oDebugNone: debug_value = 0; break;
387         case oDebugLevel: debug_level = pargs.r.ret_str; break;
388         case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
389         case oDebugAllowCoreDump:
390           may_coredump = enable_core_dumps ();
391           break;
392
393         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
394         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
395
396         case oHomedir: opt.homedir = pargs.r.ret_str; break;
397
398         case oFakedSystemTime:
399           {
400             time_t faked_time = isotime2epoch (pargs.r.ret_str);
401             if (faked_time == (time_t)(-1))
402               faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
403             gnupg_set_time (faked_time, 0);
404           }
405           break;
406
407         case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;
408
409         case oNoRandomSeedFile: use_random_seed = 0; break;
410
411         default:
412           pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
413           break;
414         }
415     }
416
417   if (configfp)
418     {
419       fclose (configfp);
420       configfp = NULL;
421       /* Keep a copy of the config filename. */
422       opt.config_filename = configname;
423       configname = NULL;
424       goto next_pass;
425     }
426   xfree (configname);
427   configname = NULL;
428
429   if (!opt.config_filename)
430     opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
431
432   if (log_get_errorcount(0))
433     g13_exit(2);
434
435   /* Now that we have the options parsed we need to update the default
436      control structure.  */
437   g13_syshelp_init_default_ctrl (&ctrl);
438
439   if (may_coredump && !opt.quiet)
440     log_info (_("WARNING: program may create a core file!\n"));
441
442   if (logfile)
443     {
444       log_set_file (logfile);
445       log_set_prefix (NULL, 1|2|4);
446     }
447
448   if (gnupg_faked_time_p ())
449     {
450       gnupg_isotime_t tbuf;
451
452       log_info (_("WARNING: running with faked system time: "));
453       gnupg_get_isotime (tbuf);
454       dump_isotime (tbuf);
455       log_printf ("\n");
456     }
457
458   /* Print any pending secure memory warnings.  */
459   gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
460
461   /* Setup the debug flags for all subsystems.  */
462   set_debug ();
463
464   /* Install a regular exit handler to make real sure that the secure
465      memory gets wiped out.  */
466   g13_install_emergency_cleanup ();
467
468   /* Terminate if we found any error until now.  */
469   if (log_get_errorcount(0))
470     g13_exit (2);
471
472   /* Set the standard GnuPG random seed file.  */
473   if (use_random_seed)
474     {
475       char *p = make_filename (opt.homedir, "random_seed", NULL);
476       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
477       xfree(p);
478     }
479
480   /* Get the UID of the caller.  */
481 #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
482   {
483     const char *uidstr;
484     struct passwd *pwd = NULL;
485
486     uidstr = getenv ("USERV_UID");
487
488     /* Print a quick note if we are not started via userv.  */
489     if (!uidstr)
490       {
491         if (getuid ())
492           {
493             log_info ("WARNING: Not started via userv\n");
494             ctrl.fail_all_cmds = 1;
495           }
496         ctrl.client.uid = getuid ();
497       }
498     else
499       {
500         unsigned long myuid;
501
502         errno = 0;
503         myuid = strtoul (uidstr, NULL, 10);
504         if (myuid == ULONG_MAX && errno)
505           {
506             log_info ("WARNING: Started via broken userv: %s\n",
507                       strerror (errno));
508             ctrl.fail_all_cmds = 1;
509             ctrl.client.uid = getuid ();
510           }
511         else
512           ctrl.client.uid = (uid_t)myuid;
513       }
514
515       pwd = getpwuid (ctrl.client.uid);
516       if (!pwd || !*pwd->pw_name)
517         {
518           log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
519           ctrl.fail_all_cmds = 1;
520           ctrl.client.uname = xstrdup ("?");
521         }
522       else
523         ctrl.client.uname = xstrdup (pwd->pw_name);
524   }
525 #else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
526   log_info ("WARNING: System does not support required syscalls\n");
527   ctrl.fail_all_cmds = 1;
528   ctrl.client.uid = getuid ();
529   ctrl.client.uname = xstrdup ("?");
530 #endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/
531
532   /* Read the table entries for this user.  */
533   if (!ctrl.fail_all_cmds
534       && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
535     ctrl.fail_all_cmds = 1;
536
537   /* Start the server.  */
538   err = syshelp_server (&ctrl);
539   if (err)
540     log_error ("server exited with error: %s <%s>\n",
541                gpg_strerror (err), gpg_strsource (err));
542
543   /* Cleanup.  */
544   g13_syshelp_deinit_default_ctrl (&ctrl);
545   g13_exit (0);
546   return 8; /*NOTREACHED*/
547 }
548
549
550 /* Store defaults into the per-connection CTRL object.  */
551 void
552 g13_syshelp_init_default_ctrl (ctrl_t ctrl)
553 {
554   ctrl->conttype = CONTTYPE_DM_CRYPT;
555 }
556
557 /* Release all resources allocated by default in the CTRl object.  */
558 static void
559 g13_syshelp_deinit_default_ctrl (ctrl_t ctrl)
560 {
561   xfree (ctrl->client.uname);
562   release_tab_items (ctrl->client.tab);
563 }
564
565
566 /* Release the list of g13tab itejms at TAB.  */
567 static void
568 release_tab_items (tab_item_t tab)
569 {
570   while (tab)
571     {
572       tab_item_t next = tab->next;
573       xfree (tab->mountpoint);
574       xfree (tab);
575       tab = next;
576     }
577 }
578
579
580 void
581 g13_syshelp_i_know_what_i_am_doing (void)
582 {
583   const char * const yesfile = "Yes-g13-I-know-what-I-am-doing";
584   char *fname;
585
586   fname = make_filename (gnupg_sysconfdir (), yesfile, NULL);
587   if (access (fname, F_OK))
588     {
589       log_info ("*******************************************************\n");
590       log_info ("* The G13 support for DM-Crypt is new and not matured.\n");
591       log_info ("* Bugs or improper use may delete all your disks!\n");
592       log_info ("* To confirm that you are ware of this risk, create\n");
593       log_info ("* the file '%s'.\n", fname);
594       log_info ("*******************************************************\n");
595       exit (1);
596     }
597   xfree (fname);
598 }
599
600
601 /* Parse the /etc/gnupg/g13tab for user USERNAME.  Return a table for
602    the user on success.  Return NULL on error and print
603    diagnostics. */
604 static tab_item_t
605 parse_g13tab (const char *username)
606 {
607   gpg_error_t err;
608   int c, n;
609   char line[512];
610   char *p;
611   char *fname;
612   estream_t fp;
613   int lnr;
614   char **words = NULL;
615   tab_item_t table = NULL;
616   tab_item_t *tabletail, ti;
617
618   fname = make_filename (gnupg_sysconfdir (), G13_NAME"tab", NULL);
619   fp = es_fopen (fname, "r");
620   if (!fp)
621     {
622       err = gpg_error_from_syserror ();
623       log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
624       goto leave;
625     }
626
627   tabletail = &table;
628   err = 0;
629   lnr = 0;
630   while (es_fgets (line, DIM(line)-1, fp))
631     {
632       lnr++;
633       n = strlen (line);
634       if (!n || line[n-1] != '\n')
635         {
636           /* Eat until end of line. */
637           while ((c=es_getc (fp)) != EOF && c != '\n')
638             ;
639           err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
640                            : GPG_ERR_INCOMPLETE_LINE);
641           log_error (_("file '%s', line %d: %s\n"),
642                      fname, lnr, gpg_strerror (err));
643           continue;
644         }
645       line[--n] = 0; /* Chop the LF. */
646       if (n && line[n-1] == '\r')
647         line[--n] = 0; /* Chop an optional CR. */
648
649       /* Allow for empty lines and spaces */
650       for (p=line; spacep (p); p++)
651         ;
652       if (!*p || *p == '#')
653         continue;
654
655       /* Parse the line.  The format is
656        * <username> <blockdev> [<label>|"-" [<mountpoint>]]
657        */
658       xfree (words);
659       words = strtokenize (p, " \t");
660       if (!words)
661         {
662           err = gpg_error_from_syserror ();
663           break;
664         }
665       if (!words[0] || !words[1])
666         {
667           log_error (_("file '%s', line %d: %s\n"),
668                      fname, lnr, gpg_strerror (GPG_ERR_SYNTAX));
669           continue;
670         }
671       if (!(*words[1] == '/'
672             || !strncmp (words[1], "PARTUUID=", 9)
673             || !strncmp (words[1], "partuuid=", 9)))
674         {
675           log_error (_("file '%s', line %d: %s\n"),
676                      fname, lnr, "Invalid block device syntax");
677           continue;
678         }
679       if (words[2])
680         {
681           if (strlen (words[2]) > 16 || strchr (words[2], '/'))
682             {
683               log_error (_("file '%s', line %d: %s\n"),
684                          fname, lnr, "Label too long or invalid syntax");
685               continue;
686             }
687
688           if (words[3] && *words[3] != '/')
689             {
690               log_error (_("file '%s', line %d: %s\n"),
691                          fname, lnr, "Invalid mountpoint syntax");
692               continue;
693             }
694         }
695       if (strcmp (words[0], username))
696         continue; /* Skip entries for other usernames!  */
697
698       ti = xtrymalloc (sizeof *ti + strlen (words[1]));
699       if (!ti)
700         {
701           err = gpg_error_from_syserror ();
702           break;
703         }
704       ti->next = NULL;
705       ti->label = NULL;
706       ti->mountpoint = NULL;
707       strcpy (ti->blockdev, *words[1]=='/'? words[1] : words[1]+9);
708       if (words[2])
709         {
710           if (strcmp (words[2], "-")
711               && !(ti->label = xtrystrdup (words[2])))
712             {
713               err = gpg_error_from_syserror ();
714               xfree (ti);
715               break;
716             }
717           if (words[3] && !(ti->mountpoint = xtrystrdup (words[3])))
718             {
719               err = gpg_error_from_syserror ();
720               xfree (ti->label);
721               xfree (ti);
722               break;
723             }
724         }
725       *tabletail = ti;
726       tabletail = &ti->next;
727     }
728
729   if (!err && !es_feof (fp))
730     err = gpg_error_from_syserror ();
731   if (err)
732     log_error (_("error reading '%s', line %d: %s\n"),
733                fname, lnr, gpg_strerror (err));
734
735  leave:
736   xfree (words);
737   es_fclose (fp);
738   xfree (fname);
739   if (err)
740     {
741       release_tab_items (table);
742       return NULL;
743     }
744   return table;
745 }