g13: Re-factor high level create code.
[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
274   /* First check whether we have a debug option on the commandline.  */
275   orig_argc = argc;
276   orig_argv = argv;
277   pargs.argc = &argc;
278   pargs.argv = &argv;
279   pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
280   while (arg_parse( &pargs, opts))
281     {
282       if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
283         parse_debug++;
284     }
285
286   /* Initialize the secure memory. */
287   gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
288   maybe_setuid = 0;
289
290   /*
291      Now we are now working under our real uid
292   */
293
294   /* Setup malloc hooks. */
295   {
296     struct assuan_malloc_hooks malloc_hooks;
297
298     malloc_hooks.malloc = gcry_malloc;
299     malloc_hooks.realloc = gcry_realloc;
300     malloc_hooks.free = gcry_free;
301     assuan_set_malloc_hooks (&malloc_hooks);
302   }
303
304   /* Prepare libassuan.  */
305   assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
306   /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
307   setup_libassuan_logging (&opt.debug);
308
309   /* Setup a default control structure for command line mode.  */
310   memset (&ctrl, 0, sizeof ctrl);
311   g13_syshelp_init_default_ctrl (&ctrl);
312   ctrl.no_server = 1;
313   ctrl.status_fd = -1; /* No status output. */
314
315   if (default_config )
316     configname = make_filename (gnupg_sysconfdir (),
317                                 G13_NAME"-syshelp.conf", NULL);
318
319   argc        = orig_argc;
320   argv        = orig_argv;
321   pargs.argc  = &argc;
322   pargs.argv  = &argv;
323   pargs.flags =  1;  /* Do not remove the args.  */
324
325  next_pass:
326   if (configname)
327     {
328       configlineno = 0;
329       configfp = fopen (configname, "r");
330       if (!configfp)
331         {
332           if (default_config)
333             {
334               if (parse_debug)
335                 log_info (_("NOTE: no default option file '%s'\n"), configname);
336             }
337           else
338             {
339               log_error (_("option file '%s': %s\n"),
340                          configname, strerror(errno));
341               g13_exit(2);
342             }
343           xfree (configname);
344           configname = NULL;
345         }
346       if (parse_debug && configname)
347         log_info (_("reading options from '%s'\n"), configname);
348       default_config = 0;
349     }
350
351   while (!no_more_options
352          && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
353     {
354       switch (pargs.r_opt)
355         {
356         case oQuiet: opt.quiet = 1; break;
357
358         case oDryRun: opt.dry_run = 1; break;
359
360         case oVerbose:
361           opt.verbose++;
362           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
363           break;
364         case oNoVerbose:
365           opt.verbose = 0;
366           gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
367           break;
368
369         case oLogFile: logfile = pargs.r.ret_str; break;
370         case oNoLogFile: logfile = NULL; break;
371
372         case oNoDetach: /*nodetach = 1; */break;
373
374         case oDebug:
375           if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
376             {
377               pargs.r_opt = ARGPARSE_INVALID_ARG;
378               pargs.err = ARGPARSE_PRINT_ERROR;
379             }
380             break;
381         case oDebugAll: debug_value = ~0; break;
382         case oDebugNone: debug_value = 0; break;
383         case oDebugLevel: debug_level = pargs.r.ret_str; break;
384         case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
385         case oDebugAllowCoreDump:
386           may_coredump = enable_core_dumps ();
387           break;
388
389         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
390         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
391
392         case oHomedir: opt.homedir = pargs.r.ret_str; break;
393
394         case oFakedSystemTime:
395           {
396             time_t faked_time = isotime2epoch (pargs.r.ret_str);
397             if (faked_time == (time_t)(-1))
398               faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
399             gnupg_set_time (faked_time, 0);
400           }
401           break;
402
403         case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;
404
405         case oNoRandomSeedFile: use_random_seed = 0; break;
406
407         default:
408           pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
409           break;
410         }
411     }
412
413   if (configfp)
414     {
415       fclose (configfp);
416       configfp = NULL;
417       /* Keep a copy of the config filename. */
418       opt.config_filename = configname;
419       configname = NULL;
420       goto next_pass;
421     }
422   xfree (configname);
423   configname = NULL;
424
425   if (!opt.config_filename)
426     opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
427
428   if (log_get_errorcount(0))
429     g13_exit(2);
430
431   /* Now that we have the options parsed we need to update the default
432      control structure.  */
433   g13_syshelp_init_default_ctrl (&ctrl);
434
435   if (may_coredump && !opt.quiet)
436     log_info (_("WARNING: program may create a core file!\n"));
437
438   if (logfile)
439     {
440       log_set_file (logfile);
441       log_set_prefix (NULL, 1|2|4);
442     }
443
444   if (gnupg_faked_time_p ())
445     {
446       gnupg_isotime_t tbuf;
447
448       log_info (_("WARNING: running with faked system time: "));
449       gnupg_get_isotime (tbuf);
450       dump_isotime (tbuf);
451       log_printf ("\n");
452     }
453
454   /* Print any pending secure memory warnings.  */
455   gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
456
457   /* Setup the debug flags for all subsystems.  */
458   set_debug ();
459
460   /* Install a regular exit handler to make real sure that the secure
461      memory gets wiped out.  */
462   g13_install_emergency_cleanup ();
463
464   /* Terminate if we found any error until now.  */
465   if (log_get_errorcount(0))
466     g13_exit (2);
467
468   /* Set the standard GnuPG random seed file.  */
469   if (use_random_seed)
470     {
471       char *p = make_filename (opt.homedir, "random_seed", NULL);
472       gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
473       xfree(p);
474     }
475
476   /* Get the UID of the caller.  */
477 #if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
478   {
479     const char *uidstr;
480     struct passwd *pwd = NULL;
481
482     uidstr = getenv ("USERV_UID");
483
484     /* Print a quick note if we are not started via userv.  */
485     if (!uidstr)
486       {
487         if (getuid ())
488           {
489             log_info ("WARNING: Not started via userv\n");
490             ctrl.fail_all_cmds = 1;
491           }
492         ctrl.client.uid = getuid ();
493       }
494     else
495       {
496         unsigned long myuid;
497
498         errno = 0;
499         myuid = strtoul (uidstr, NULL, 10);
500         if (myuid == ULONG_MAX && errno)
501           {
502             log_info ("WARNING: Started via broken userv: %s\n",
503                       strerror (errno));
504             ctrl.fail_all_cmds = 1;
505             ctrl.client.uid = getuid ();
506           }
507         else
508           ctrl.client.uid = (uid_t)myuid;
509       }
510
511       pwd = getpwuid (ctrl.client.uid);
512       if (!pwd || !*pwd->pw_name)
513         {
514           log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
515           ctrl.fail_all_cmds = 1;
516           ctrl.client.uname = xstrdup ("?");
517         }
518       else
519         ctrl.client.uname = xstrdup (pwd->pw_name);
520   }
521 #else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
522   log_info ("WARNING: System does not support required syscalls\n");
523   ctrl.fail_all_cmds = 1;
524   ctrl.client.uid = getuid ();
525   ctrl.client.uname = xstrdup ("?");
526 #endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/
527
528   /* Read the table entries for this user.  */
529   if (!ctrl.fail_all_cmds
530       && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
531     ctrl.fail_all_cmds = 1;
532
533   /* Start the server.  */
534   err = syshelp_server (&ctrl);
535   if (err)
536     log_error ("server exited with error: %s <%s>\n",
537                gpg_strerror (err), gpg_strsource (err));
538
539   /* Cleanup.  */
540   g13_syshelp_deinit_default_ctrl (&ctrl);
541   g13_exit (0);
542   return 8; /*NOTREACHED*/
543 }
544
545
546 /* Store defaults into the per-connection CTRL object.  */
547 void
548 g13_syshelp_init_default_ctrl (ctrl_t ctrl)
549 {
550   ctrl->conttype = CONTTYPE_DM_CRYPT;
551 }
552
553 /* Release all resources allocated by default in the CTRl object.  */
554 static void
555 g13_syshelp_deinit_default_ctrl (ctrl_t ctrl)
556 {
557   xfree (ctrl->client.uname);
558   release_tab_items (ctrl->client.tab);
559 }
560
561
562 /* Release the list of g13tab itejms at TAB.  */
563 static void
564 release_tab_items (tab_item_t tab)
565 {
566   while (tab)
567     {
568       tab_item_t next = tab->next;
569       xfree (tab->mountpoint);
570       xfree (tab);
571       tab = next;
572     }
573 }
574
575
576 /* Parse the /etc/gnupg/g13tab for user USERNAME.  Return a table for
577    the user on success.  Return NULL on error and print
578    diagnostics. */
579 static tab_item_t
580 parse_g13tab (const char *username)
581 {
582   gpg_error_t err;
583   int c, n;
584   char line[512];
585   char *p;
586   char *fname;
587   estream_t fp;
588   int lnr;
589   char **words = NULL;
590   tab_item_t table = NULL;
591   tab_item_t *tabletail, ti;
592
593   fname = make_filename (gnupg_sysconfdir (), G13_NAME"tab", NULL);
594   fp = es_fopen (fname, "r");
595   if (!fp)
596     {
597       err = gpg_error_from_syserror ();
598       log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
599       goto leave;
600     }
601
602   tabletail = &table;
603   err = 0;
604   lnr = 0;
605   while (es_fgets (line, DIM(line)-1, fp))
606     {
607       lnr++;
608       n = strlen (line);
609       if (!n || line[n-1] != '\n')
610         {
611           /* Eat until end of line. */
612           while ((c=es_getc (fp)) != EOF && c != '\n')
613             ;
614           err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
615                            : GPG_ERR_INCOMPLETE_LINE);
616           log_error (_("file '%s', line %d: %s\n"),
617                      fname, lnr, gpg_strerror (err));
618           continue;
619         }
620       line[--n] = 0; /* Chop the LF. */
621       if (n && line[n-1] == '\r')
622         line[--n] = 0; /* Chop an optional CR. */
623
624       /* Allow for empty lines and spaces */
625       for (p=line; spacep (p); p++)
626         ;
627       if (!*p || *p == '#')
628         continue;
629
630       /* Parse the line.  The format is
631        * <username> <blockdev> [<label>|"-" [<mountpoint>]]
632        */
633       xfree (words);
634       words = strtokenize (p, " \t");
635       if (!words)
636         {
637           err = gpg_error_from_syserror ();
638           break;
639         }
640       if (!words[0] || !words[1])
641         {
642           log_error (_("file '%s', line %d: %s\n"),
643                      fname, lnr, gpg_strerror (GPG_ERR_SYNTAX));
644           continue;
645         }
646       if (!(*words[1] == '/'
647             || !strncmp (words[1], "PARTUUID=", 9)
648             || !strncmp (words[1], "partuuid=", 9)))
649         {
650           log_error (_("file '%s', line %d: %s\n"),
651                      fname, lnr, "Invalid block device syntax");
652           continue;
653         }
654       if (words[2])
655         {
656           if (strlen (words[2]) > 16 || strchr (words[2], '/'))
657             {
658               log_error (_("file '%s', line %d: %s\n"),
659                          fname, lnr, "Label too long or invalid syntax");
660               continue;
661             }
662
663           if (words[3] && *words[3] != '/')
664             {
665               log_error (_("file '%s', line %d: %s\n"),
666                          fname, lnr, "Invalid mountpoint syntax");
667               continue;
668             }
669         }
670       if (strcmp (words[0], username))
671         continue; /* Skip entries for other usernames!  */
672
673       ti = xtrymalloc (sizeof *ti + strlen (words[1]));
674       if (!ti)
675         {
676           err = gpg_error_from_syserror ();
677           break;
678         }
679       ti->next = NULL;
680       ti->label = NULL;
681       ti->mountpoint = NULL;
682       strcpy (ti->blockdev, *words[1]=='/'? words[1] : words[1]+9);
683       if (words[2])
684         {
685           if (strcmp (words[2], "-")
686               && !(ti->label = xtrystrdup (words[2])))
687             {
688               err = gpg_error_from_syserror ();
689               xfree (ti);
690               break;
691             }
692           if (words[3] && !(ti->mountpoint = xtrystrdup (words[3])))
693             {
694               err = gpg_error_from_syserror ();
695               xfree (ti->label);
696               xfree (ti);
697               break;
698             }
699         }
700       *tabletail = ti;
701       tabletail = &ti->next;
702     }
703
704   if (!err && !es_feof (fp))
705     err = gpg_error_from_syserror ();
706   if (err)
707     log_error (_("error reading '%s', line %d: %s\n"),
708                fname, lnr, gpg_strerror (err));
709
710  leave:
711   xfree (words);
712   es_fclose (fp);
713   xfree (fname);
714   if (err)
715     {
716       release_tab_items (table);
717       return NULL;
718     }
719   return table;
720 }