Use action names in veritysetup (similar to cryptsetup).
[platform/upstream/cryptsetup.git] / src / veritysetup.c
1 /*
2  * veritysetup - setup cryptographic volumes for dm-verity
3  *
4  * Copyright (C) 2012, Red Hat, Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 /* TODO:
21  * - support device without superblock
22  * - extend superblock (UUID)
23  * - add api tests
24  * - salt string "-"
25  * - man page
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <popt.h>
34 #include <limits.h>
35
36 #include "cryptsetup.h"
37
38 #define PACKAGE_VERITY "veritysetup"
39
40 static int use_superblock = 1; /* FIXME: no superblock not supported */
41
42 static const char *hash_algorithm = NULL;
43 static int version = 1;
44 static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
45 static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
46 static uint64_t data_blocks = 0;
47 static const char *salt_string = NULL;
48 static uint64_t hash_start = 0;
49
50 static int opt_verbose = 0;
51 static int opt_debug = 0;
52 static int opt_version_mode = 0;
53
54 static const char **action_argv;
55 static int action_argc;
56
57 static int hex_to_bytes(const char *hex, char *result)
58 {
59         char buf[3] = "xx\0", *endp;
60         int i, len;
61
62         len = strlen(hex) / 2;
63         for (i = 0; i < len; i++) {
64                 memcpy(buf, &hex[i * 2], 2);
65                 result[i] = strtoul(buf, &endp, 16);
66                 if (endp != &buf[2])
67                         return -EINVAL;
68         }
69         return i;
70 }
71
72 __attribute__((format(printf, 5, 6)))
73 static void clogger(struct crypt_device *cd, int level, const char *file,
74                    int line, const char *format, ...)
75 {
76         va_list argp;
77         char *target = NULL;
78
79         va_start(argp, format);
80
81         if (vasprintf(&target, format, argp) > 0) {
82                 if (level >= 0) {
83                         crypt_log(cd, level, target);
84 #ifdef CRYPT_DEBUG
85                 } else if (opt_debug)
86                         printf("# %s:%d %s\n", file ?: "?", line, target);
87 #else
88                 } else if (opt_debug)
89                         printf("# %s\n", target);
90 #endif
91         }
92
93         va_end(argp);
94         free(target);
95 }
96
97 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
98 {
99         switch(level) {
100
101         case CRYPT_LOG_NORMAL:
102                 fputs(msg, stdout);
103                 break;
104         case CRYPT_LOG_VERBOSE:
105                 if (opt_verbose)
106                         fputs(msg, stdout);
107                 break;
108         case CRYPT_LOG_ERROR:
109                 fputs(msg, stderr);
110                 break;
111         case CRYPT_LOG_DEBUG:
112                 if (opt_debug)
113                         printf("# %s\n", msg);
114                 break;
115         default:
116                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
117                 break;
118         }
119 }
120
121 static int action_format(int arg)
122 {
123         struct crypt_device *cd = NULL;
124         struct crypt_params_verity params = {};
125         char salt_bytes[512];
126         int r;
127
128         if ((r = crypt_init(&cd, action_argv[1])))
129                 goto out;
130
131         params.hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
132         params.data_device = action_argv[0];
133
134         if (salt_string) {
135                 params.salt_size = strlen(salt_string) / 2;
136                 if (hex_to_bytes(salt_string, salt_bytes) != params.salt_size) {
137                         r = -EINVAL;
138                         goto out;
139                 }
140                 params.salt = salt_bytes;
141         } else
142                 params.salt_size = DEFAULT_VERITY_SALT_SIZE;
143
144         params.data_block_size = data_block_size;
145         params.hash_block_size = hash_block_size;
146         params.data_size = data_blocks;
147         params.hash_area_offset = hash_start;
148         params.version = version;
149         params.flags = CRYPT_VERITY_CREATE_HASH;
150         if (!use_superblock)
151                 params.flags |= CRYPT_VERITY_NO_HEADER;
152
153         r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
154         if (!r)
155                 crypt_dump(cd);
156 out:
157         crypt_free(cd);
158         return r;
159 }
160
161 static int _activate(const char *dm_device,
162                       const char *data_device,
163                       const char *hash_device,
164                       const char *root_hash,
165                       uint32_t flags)
166 {
167         struct crypt_device *cd = NULL;
168         struct crypt_params_verity params = {};
169         uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
170         char root_hash_bytes[128];
171         int r;
172
173         if ((r = crypt_init(&cd, hash_device)))
174                 goto out;
175
176         params.flags |= flags;
177
178         if (use_superblock) {
179                 params.hash_area_offset = hash_start;
180                 r = crypt_load(cd, CRYPT_VERITY, &params);
181         } else {/*
182                 params.hash_name = hash_algorithm;
183                 params.salt = salt_bytes;
184                 params.salt_size = salt_size;
185                 params.data_block_size = data_block_size;
186                 params.hash_block_size = hash_block_size;
187
188                 params.data_size = data_blocks * data_block_size / 512;
189                 params.version = version;
190                 params.flags |= CRYPT_VERITY_NO_HEADER;
191                 r = crypt_load(cd, CRYPT_VERITY, &params);
192                 crypt_format(); */
193                 r = -EINVAL;
194                 goto out;
195         }
196         if (r < 0)
197                 goto out;
198         r = crypt_set_data_device(cd, data_device);
199         if (r < 0)
200                 goto out;
201
202         if (hex_to_bytes(root_hash, root_hash_bytes) !=
203             crypt_get_volume_key_size(cd)) {
204                 r = -EINVAL;
205                 goto out;
206         }
207         r = crypt_activate_by_volume_key(cd, dm_device,
208                                          root_hash_bytes,
209                                          crypt_get_volume_key_size(cd),
210                                          activate_flags);
211 out:
212         if (!r)
213                 crypt_dump(cd);
214         crypt_free(cd);
215         return r;
216 }
217
218 static int action_create(int arg)
219 {
220         return _activate(action_argv[0],
221                          action_argv[1],
222                          action_argv[2],
223                          action_argv[3], 0);
224 }
225
226 static int action_verify(int arg)
227 {
228         return _activate(NULL,
229                          action_argv[0],
230                          action_argv[1],
231                          action_argv[2],
232                          CRYPT_VERITY_CHECK_HASH);
233 }
234
235 static int action_remove(int arg)
236 {
237         struct crypt_device *cd = NULL;
238         int r;
239
240         r = crypt_init_by_name(&cd, action_argv[0]);
241         if (r == 0)
242                 r = crypt_deactivate(cd, action_argv[0]);
243
244         crypt_free(cd);
245         return r;
246 }
247
248 static int action_status(int arg)
249 {
250         struct crypt_device *cd = NULL;
251         int r;
252
253         r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
254         if (!r)
255                 r = crypt_dump(cd);
256         crypt_free(cd);
257         return r;
258 }
259
260 static int action_dump(int arg)
261 {
262         struct crypt_device *cd = NULL;
263         struct crypt_params_verity params = {};
264         int r;
265
266         if ((r = crypt_init(&cd, action_argv[0])))
267                 return r;
268
269         params.hash_area_offset = hash_start;
270         r = crypt_load(cd, CRYPT_VERITY, &params);
271         if (!r)
272                 crypt_dump(cd);
273         crypt_free(cd);
274         return r;
275 }
276
277 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
278                                              int exitcode, const char *error,
279                                              const char *more)
280 {
281         poptPrintUsage(popt_context, stderr, 0);
282         if (error)
283                 log_err("%s: %s\n", more, error);
284         poptFreeContext(popt_context);
285         exit(exitcode);
286 }
287
288 static void _dbg_version_and_cmd(int argc, const char **argv)
289 {
290         int i;
291
292         log_std("# %s %s processing \"", PACKAGE_VERITY, PACKAGE_VERSION);
293         for (i = 0; i < argc; i++) {
294                 if (i)
295                         log_std(" ");
296                 log_std("%s", argv[i]);
297         }
298         log_std("\"\n");
299 }
300
301 static struct action_type {
302         const char *type;
303         int (*handler)(int);
304         int required_action_argc;
305         const char *arg_desc;
306         const char *desc;
307 } action_types[] = {
308         { "format",     action_format, 2, N_("<data_device> <hash_device>"),N_("format device") },
309         { "verify",     action_verify, 3, N_("<data_device> <hash_device> <root_hash>"),N_("verify device") },
310         { "create",     action_create, 4, N_("<name> <data_device> <hash_device> <root_hash>"),N_("create active device") },
311         { "remove",     action_remove, 1, N_("<name>"),N_("remove (deactivate) device") },
312         { "status",     action_status, 1, N_("<name>"),N_("show active device status") },
313         { "dump",       action_dump,   1, N_("<hash_device>"),N_("show on-disk information") },
314         { NULL, NULL, 0, NULL, NULL }
315 };
316
317 static void help(poptContext popt_context,
318                  enum poptCallbackReason reason __attribute__((unused)),
319                  struct poptOption *key,
320                  const char *arg __attribute__((unused)),
321                  void *data __attribute__((unused)))
322 {
323         struct action_type *action;
324
325         if (key->shortName == '?') {
326                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
327                 poptPrintHelp(popt_context, stdout, 0);
328                 log_std(_("\n"
329                          "<action> is one of:\n"));
330                 for(action = action_types; action->type; action++)
331                         log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
332                 log_std(_("\n"
333                          "<name> is the device to create under %s\n"
334                          "<data_device> is the data device\n"
335                          "<hash_device> is the device containing verification data\n"
336                          "<root_hash> hash of the root node on <hash_device>\n"),
337                         crypt_get_dir());
338
339                 log_std(_("\nDefault compiled-in dm-verity parameters:\n"
340                          "\tHash: %s, Data block (bytes): %u, "
341                          "Hash block (bytes): %u, Salt size: %u, Hash format: %u\n"),
342                         DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
343                         DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
344                         1);
345                 exit(EXIT_SUCCESS);
346         } else
347                 usage(popt_context, EXIT_SUCCESS, NULL, NULL);
348 }
349
350 static void show_status(int errcode)
351 {
352         char error[256], *error_;
353
354         if(!opt_verbose)
355                 return;
356
357         if(!errcode) {
358                 log_std(_("Command successful.\n"));
359                 return;
360         }
361
362         crypt_get_error(error, sizeof(error));
363
364         if (!error[0]) {
365                 error_ = strerror_r(-errcode, error, sizeof(error));
366                 if (error_ != error) {
367                         strncpy(error, error_, sizeof(error));
368                         error[sizeof(error) - 1] = '\0';
369                 }
370         }
371
372         log_err(_("Command failed with code %i"), -errcode);
373         if (*error)
374                 log_err(": %s\n", error);
375         else
376                 log_err(".\n");
377 }
378
379 static int run_action(struct action_type *action)
380 {
381         int r;
382
383         log_dbg("Running command %s.", action->type);
384
385         r = action->handler(0);
386
387         show_status(r);
388
389         /* Translate exit code to simple codes */
390         switch (r) {
391         case 0:         r = EXIT_SUCCESS; break;
392         case -EEXIST:
393         case -EBUSY:    r = 5; break;
394         case -ENOTBLK:
395         case -ENODEV:   r = 4; break;
396         case -ENOMEM:   r = 3; break;
397         case -EPERM:    r = 2; break;
398         case -EINVAL:
399         case -ENOENT:
400         case -ENOSYS:
401         default:        r = EXIT_FAILURE;
402         }
403         return r;
404 }
405
406 int main(int argc, const char **argv)
407 {
408         static char *popt_tmp;
409         static struct poptOption popt_help_options[] = {
410                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
411                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
412                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
413                 POPT_TABLEEND
414         };
415         static struct poptOption popt_options[] = {
416                 { NULL,              '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
417                 { "version",         '\0', POPT_ARG_NONE, &opt_version_mode, 0, N_("Print package version"), NULL },
418                 { "verbose",         'v',  POPT_ARG_NONE, &opt_verbose,      0, N_("Shows more detailed error messages"), NULL },
419                 { "debug",           '\0', POPT_ARG_NONE, &opt_debug,        0, N_("Show debug messages"), NULL },
420                 { "no-superblock",   0,    POPT_ARG_VAL,  &use_superblock,   0, N_("Do not use verity superblock"), NULL },
421                 { "format",          0,    POPT_ARG_INT,  &version,          0, N_("Format type (1 - normal, 0 - original Chromium OS)"), N_("number") },
422                 { "data-block-size", 0,    POPT_ARG_INT,  &data_block_size,  0, N_("Block size on the data device"), N_("bytes") },
423                 { "hash-block-size", 0,    POPT_ARG_INT,  &hash_block_size,  0, N_("Block size on the hash device"), N_("bytes") },
424                 { "data-blocks",     0,    POPT_ARG_STRING, &popt_tmp,       1, N_("The number of blocks in the data file"), N_("blocks") },
425                 { "hash-start",      0,    POPT_ARG_STRING, &popt_tmp,       2, N_("Starting block on the hash device"), N_("512-byte sectors") },
426                 { "algorithm",       'h',  POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
427                 { "salt",            's',  POPT_ARG_STRING, &salt_string,    0, N_("Salt"), N_("hex string") },
428                 POPT_TABLEEND
429         };
430
431         poptContext popt_context;
432         struct action_type *action;
433         const char *aname, *null_action_argv[] = {NULL};
434         int r;
435
436         crypt_set_log_callback(NULL, _log, NULL);
437
438         setlocale(LC_ALL, "");
439         bindtextdomain(PACKAGE, LOCALEDIR);
440         textdomain(PACKAGE);
441
442         popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
443         poptSetOtherOptionHelp(popt_context,
444                                N_("[OPTION...] <action> <action-specific>"));
445
446         while((r = poptGetNextOpt(popt_context)) > 0) {
447                 unsigned long long ull_value;
448                 char *endp;
449
450                 errno = 0;
451                 ull_value = strtoull(popt_tmp, &endp, 0);
452                 if (*endp || !*popt_tmp ||
453                     (errno == ERANGE && ull_value == ULLONG_MAX) ||
454                     (errno != 0 && ull_value == 0))
455                         r = POPT_ERROR_BADNUMBER;
456
457                 switch(r) {
458                         case 1:
459                                 data_blocks = ull_value;
460                                 break;
461                         case 2:
462                                 hash_start = ull_value * 512;
463                                 break;
464                 }
465
466                 if (r < 0)
467                         break;
468         }
469
470         if (r < -1)
471                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
472                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
473
474         if (opt_version_mode) {
475                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
476                 poptFreeContext(popt_context);
477                 exit(EXIT_SUCCESS);
478         }
479
480         if (!(aname = poptGetArg(popt_context)))
481                 usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
482                       poptGetInvocationName(popt_context));
483         for(action = action_types; action->type; action++)
484                 if (strcmp(action->type, aname) == 0)
485                         break;
486         if (!action->type)
487                 usage(popt_context, EXIT_FAILURE, _("Unknown action."),
488                       poptGetInvocationName(popt_context));
489
490         action_argc = 0;
491         action_argv = poptGetArgs(popt_context);
492         /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
493         if(!action_argv)
494                 action_argv = null_action_argv;
495
496         /* Count args, somewhat unnice, change? */
497         while(action_argv[action_argc] != NULL)
498                 action_argc++;
499
500         if(action_argc < action->required_action_argc) {
501                 char buf[128];
502                 snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
503                 usage(popt_context, EXIT_FAILURE, buf,
504                       poptGetInvocationName(popt_context));
505         }
506
507         if (opt_debug) {
508                 opt_verbose = 1;
509                 crypt_set_debug_level(-1);
510                 _dbg_version_and_cmd(argc, argv);
511         }
512
513         r = run_action(action);
514         poptFreeContext(popt_context);
515         return r;
516 }