Remove some compilation warnings.
[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 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <inttypes.h>
26 #include <popt.h>
27 #include <limits.h>
28 #include <sys/stat.h>
29
30 #include "cryptsetup.h"
31
32 #define PACKAGE_VERITY "veritysetup"
33
34 static int use_superblock = 1;
35
36 static const char *hash_algorithm = NULL;
37 static int hash_type = 1;
38 static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
39 static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
40 static uint64_t data_blocks = 0;
41 static const char *salt_string = NULL;
42 static uint64_t hash_start = 0;
43 static const char *opt_uuid = NULL;
44
45 static int opt_verbose = 0;
46 static int opt_debug = 0;
47 static int opt_version_mode = 0;
48
49 static const char **action_argv;
50 static int action_argc;
51
52 static size_t hex_to_bytes(const char *hex, char *result)
53 {
54         char buf[3] = "xx\0", *endp;
55         size_t i, len;
56
57         len = strlen(hex) / 2;
58         for (i = 0; i < len; i++) {
59                 memcpy(buf, &hex[i * 2], 2);
60                 result[i] = strtoul(buf, &endp, 16);
61                 if (endp != &buf[2])
62                         return -EINVAL;
63         }
64         return i;
65 }
66
67 __attribute__((format(printf, 5, 6)))
68 static void clogger(struct crypt_device *cd, int level, const char *file,
69                    int line, const char *format, ...)
70 {
71         va_list argp;
72         char *target = NULL;
73
74         va_start(argp, format);
75
76         if (vasprintf(&target, format, argp) > 0) {
77                 if (level >= 0) {
78                         crypt_log(cd, level, target);
79 #ifdef CRYPT_DEBUG
80                 } else if (opt_debug)
81                         printf("# %s:%d %s\n", file ?: "?", line, target);
82 #else
83                 } else if (opt_debug)
84                         printf("# %s\n", target);
85 #endif
86         }
87
88         va_end(argp);
89         free(target);
90 }
91
92 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
93 {
94         switch(level) {
95
96         case CRYPT_LOG_NORMAL:
97                 fputs(msg, stdout);
98                 break;
99         case CRYPT_LOG_VERBOSE:
100                 if (opt_verbose)
101                         fputs(msg, stdout);
102                 break;
103         case CRYPT_LOG_ERROR:
104                 fputs(msg, stderr);
105                 break;
106         case CRYPT_LOG_DEBUG:
107                 if (opt_debug)
108                         printf("# %s\n", msg);
109                 break;
110         default:
111                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
112                 break;
113         }
114 }
115
116 static int _prepare_format(struct crypt_params_verity *params,
117                            const char *data_device,
118                            uint32_t flags)
119 {
120         static char salt_bytes[512];
121
122         params->hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
123         params->data_device = data_device;
124
125         if (salt_string && !strcmp(salt_string, "-")) {
126                 params->salt_size = 0;
127                 params->salt = NULL;
128         } else if (salt_string) {
129                 params->salt_size = strlen(salt_string) / 2;
130                 if (hex_to_bytes(salt_string, salt_bytes) != params->salt_size)
131                         return -EINVAL;
132                 params->salt = salt_bytes;
133         } else
134                 params->salt_size = DEFAULT_VERITY_SALT_SIZE;
135
136         params->data_block_size = data_block_size;
137         params->hash_block_size = hash_block_size;
138         params->data_size = data_blocks;
139         params->hash_area_offset = hash_start;
140         params->hash_type = hash_type;
141         params->flags = flags;
142
143         return 0;
144 }
145
146 static int action_format(int arg)
147 {
148         struct crypt_device *cd = NULL;
149         struct crypt_params_verity params = {};
150         uint32_t flags = CRYPT_VERITY_CREATE_HASH;
151         int r;
152
153         if ((r = crypt_init(&cd, action_argv[1])))
154                 goto out;
155
156         if (!use_superblock)
157                 flags |= CRYPT_VERITY_NO_HEADER;
158
159         r = _prepare_format(&params, action_argv[0], flags);
160         if (r < 0)
161                 goto out;
162
163         r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, opt_uuid, NULL, 0, &params);
164         if (!r)
165                 crypt_dump(cd);
166 out:
167         crypt_free(cd);
168         return r;
169 }
170
171 static int _activate(const char *dm_device,
172                       const char *data_device,
173                       const char *hash_device,
174                       const char *root_hash,
175                       uint32_t flags)
176 {
177         struct crypt_device *cd = NULL;
178         struct crypt_params_verity params = {};
179         uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
180         char root_hash_bytes[128];
181         size_t hash_size;
182         int r;
183
184         if ((r = crypt_init(&cd, hash_device)))
185                 goto out;
186
187         if (use_superblock) {
188                 params.flags = flags;
189                 params.hash_area_offset = hash_start;
190                 r = crypt_load(cd, CRYPT_VERITY, &params);
191         } else {
192                 r = _prepare_format(&params, data_device, flags | CRYPT_VERITY_NO_HEADER);
193                 if (r < 0)
194                         goto out;
195                 r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, NULL, NULL, 0, &params);
196         }
197         if (r < 0)
198                 goto out;
199         r = crypt_set_data_device(cd, data_device);
200         if (r < 0)
201                 goto out;
202
203         hash_size = crypt_get_volume_key_size(cd);
204         if (hex_to_bytes(root_hash, root_hash_bytes) != hash_size) {
205                 r = -EINVAL;
206                 goto out;
207         }
208         r = crypt_activate_by_volume_key(cd, dm_device,
209                                          root_hash_bytes,
210                                          hash_size,
211                                          activate_flags);
212 out:
213         crypt_free(cd);
214         return r;
215 }
216
217 static int action_create(int arg)
218 {
219         return _activate(action_argv[0],
220                          action_argv[1],
221                          action_argv[2],
222                          action_argv[3], 0);
223 }
224
225 static int action_verify(int arg)
226 {
227         return _activate(NULL,
228                          action_argv[0],
229                          action_argv[1],
230                          action_argv[2],
231                          CRYPT_VERITY_CHECK_HASH);
232 }
233
234 static int action_remove(int arg)
235 {
236         struct crypt_device *cd = NULL;
237         int r;
238
239         r = crypt_init_by_name(&cd, action_argv[0]);
240         if (r == 0)
241                 r = crypt_deactivate(cd, action_argv[0]);
242
243         crypt_free(cd);
244         return r;
245 }
246
247 static int action_status(int arg)
248 {
249         crypt_status_info ci;
250         struct crypt_active_device cad;
251         struct crypt_params_verity vp = {};
252         struct crypt_device *cd = NULL;
253         struct stat st;
254         char *backing_file;
255         unsigned i, path = 0;
256         int r = 0;
257
258         /* perhaps a path, not a dm device name */
259         if (strchr(action_argv[0], '/') && !stat(action_argv[0], &st))
260                 path = 1;
261
262         ci = crypt_status(NULL, action_argv[0]);
263         switch (ci) {
264         case CRYPT_INVALID:
265                 r = -EINVAL;
266                 break;
267         case CRYPT_INACTIVE:
268                 if (path)
269                         log_std("%s is inactive.\n", action_argv[0]);
270                 else
271                         log_std("%s/%s is inactive.\n", crypt_get_dir(), action_argv[0]);
272                 r = -ENODEV;
273                 break;
274         case CRYPT_ACTIVE:
275         case CRYPT_BUSY:
276                 if (path)
277                         log_std("%s is active%s.\n", action_argv[0],
278                                 ci == CRYPT_BUSY ? " and is in use" : "");
279                 else
280                         log_std("%s/%s is active%s.\n", crypt_get_dir(), action_argv[0],
281                                 ci == CRYPT_BUSY ? " and is in use" : "");
282
283                 r = crypt_init_by_name_and_header(&cd, action_argv[0], NULL);
284                 if (r < 0 || !crypt_get_type(cd))
285                         goto out;
286
287                 log_std("  type:        %s\n", crypt_get_type(cd));
288
289                 r = crypt_get_active_device(cd, action_argv[0], &cad);
290                 if (r < 0)
291                         goto out;
292
293                 log_std("  status:      %s\n",
294                         cad.flags & CRYPT_ACTIVATE_CORRUPTED ? "corrupted" : "verified");
295
296                 r = crypt_get_verity_info(cd, &vp);
297                 if (r < 0)
298                         goto out;
299
300                 log_std("  hash type:   %u\n", vp.hash_type);
301                 log_std("  data block:  %u\n", vp.data_block_size);
302                 log_std("  hash block:  %u\n", vp.hash_block_size);
303                 log_std("  hash name:   %s\n", vp.hash_name);
304                 log_std("  salt:        ");
305                 if (vp.salt_size)
306                         for(i = 0; i < vp.salt_size; i++)
307                                 log_std("%02hhx", (const char)vp.salt[i]);
308                 else
309                         log_std("-");
310                 log_std("\n");
311
312                 log_std("  data device: %s\n", vp.data_device);
313                 if (crypt_loop_device(vp.data_device)) {
314                         backing_file = crypt_loop_backing_file(vp.data_device);
315                         log_std("  data loop:   %s\n", backing_file);
316                         free(backing_file);
317                 }
318                 log_std("  size:        %" PRIu64 " sectors\n", cad.size);
319                 log_std("  mode:        %s\n", cad.flags & CRYPT_ACTIVATE_READONLY ?
320                                            "readonly" : "read/write");
321
322                 log_std("  hash device: %s\n", vp.hash_device);
323                 if (crypt_loop_device(vp.hash_device)) {
324                         backing_file = crypt_loop_backing_file(vp.hash_device);
325                         log_std("  hash loop:   %s\n", backing_file);
326                         free(backing_file);
327                 }
328                 log_std("  hash offset: %" PRIu64 " sectors\n",
329                         vp.hash_area_offset * vp.hash_block_size / 512);
330         }
331 out:
332         crypt_free(cd);
333         if (r == -ENOTSUP)
334                 r = 0;
335         return r;
336 }
337
338 static int action_dump(int arg)
339 {
340         struct crypt_device *cd = NULL;
341         struct crypt_params_verity params = {};
342         int r;
343
344         if ((r = crypt_init(&cd, action_argv[0])))
345                 return r;
346
347         params.hash_area_offset = hash_start;
348         r = crypt_load(cd, CRYPT_VERITY, &params);
349         if (!r)
350                 crypt_dump(cd);
351         crypt_free(cd);
352         return r;
353 }
354
355 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
356                                              int exitcode, const char *error,
357                                              const char *more)
358 {
359         poptPrintUsage(popt_context, stderr, 0);
360         if (error)
361                 log_err("%s: %s\n", more, error);
362         poptFreeContext(popt_context);
363         exit(exitcode);
364 }
365
366 static void _dbg_version_and_cmd(int argc, const char **argv)
367 {
368         int i;
369
370         log_std("# %s %s processing \"", PACKAGE_VERITY, PACKAGE_VERSION);
371         for (i = 0; i < argc; i++) {
372                 if (i)
373                         log_std(" ");
374                 log_std("%s", argv[i]);
375         }
376         log_std("\"\n");
377 }
378
379 static struct action_type {
380         const char *type;
381         int (*handler)(int);
382         int required_action_argc;
383         const char *arg_desc;
384         const char *desc;
385 } action_types[] = {
386         { "format",     action_format, 2, N_("<data_device> <hash_device>"),N_("format device") },
387         { "verify",     action_verify, 3, N_("<data_device> <hash_device> <root_hash>"),N_("verify device") },
388         { "create",     action_create, 4, N_("<name> <data_device> <hash_device> <root_hash>"),N_("create active device") },
389         { "remove",     action_remove, 1, N_("<name>"),N_("remove (deactivate) device") },
390         { "status",     action_status, 1, N_("<name>"),N_("show active device status") },
391         { "dump",       action_dump,   1, N_("<hash_device>"),N_("show on-disk information") },
392         { NULL, NULL, 0, NULL, NULL }
393 };
394
395 static void help(poptContext popt_context,
396                  enum poptCallbackReason reason __attribute__((unused)),
397                  struct poptOption *key,
398                  const char *arg __attribute__((unused)),
399                  void *data __attribute__((unused)))
400 {
401         struct action_type *action;
402
403         if (key->shortName == '?') {
404                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
405                 poptPrintHelp(popt_context, stdout, 0);
406                 log_std(_("\n"
407                          "<action> is one of:\n"));
408                 for(action = action_types; action->type; action++)
409                         log_std("\t%s %s - %s\n", action->type, _(action->arg_desc), _(action->desc));
410                 log_std(_("\n"
411                          "<name> is the device to create under %s\n"
412                          "<data_device> is the data device\n"
413                          "<hash_device> is the device containing verification data\n"
414                          "<root_hash> hash of the root node on <hash_device>\n"),
415                         crypt_get_dir());
416
417                 log_std(_("\nDefault compiled-in dm-verity parameters:\n"
418                          "\tHash: %s, Data block (bytes): %u, "
419                          "Hash block (bytes): %u, Salt size: %u, Hash format: %u\n"),
420                         DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
421                         DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
422                         1);
423                 exit(EXIT_SUCCESS);
424         } else
425                 usage(popt_context, EXIT_SUCCESS, NULL, NULL);
426 }
427
428 static void show_status(int errcode)
429 {
430         char error[256], *error_;
431
432         if(!opt_verbose)
433                 return;
434
435         if(!errcode) {
436                 log_std(_("Command successful.\n"));
437                 return;
438         }
439
440         crypt_get_error(error, sizeof(error));
441
442         if (!error[0]) {
443                 error_ = strerror_r(-errcode, error, sizeof(error));
444                 if (error_ != error) {
445                         strncpy(error, error_, sizeof(error));
446                         error[sizeof(error) - 1] = '\0';
447                 }
448         }
449
450         log_err(_("Command failed with code %i"), -errcode);
451         if (*error)
452                 log_err(": %s\n", error);
453         else
454                 log_err(".\n");
455 }
456
457 static int run_action(struct action_type *action)
458 {
459         int r;
460
461         log_dbg("Running command %s.", action->type);
462
463         r = action->handler(0);
464
465         show_status(r);
466
467         /* Translate exit code to simple codes */
468         switch (r) {
469         case 0:         r = EXIT_SUCCESS; break;
470         case -EEXIST:
471         case -EBUSY:    r = 5; break;
472         case -ENOTBLK:
473         case -ENODEV:   r = 4; break;
474         case -ENOMEM:   r = 3; break;
475         case -EPERM:    r = 2; break;
476         case -EINVAL:
477         case -ENOENT:
478         case -ENOSYS:
479         default:        r = EXIT_FAILURE;
480         }
481         return r;
482 }
483
484 int main(int argc, const char **argv)
485 {
486         static char *popt_tmp;
487         static struct poptOption popt_help_options[] = {
488                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
489                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
490                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
491                 POPT_TABLEEND
492         };
493         static struct poptOption popt_options[] = {
494                 { NULL,              '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
495                 { "version",         '\0', POPT_ARG_NONE, &opt_version_mode, 0, N_("Print package version"), NULL },
496                 { "verbose",         'v',  POPT_ARG_NONE, &opt_verbose,      0, N_("Shows more detailed error messages"), NULL },
497                 { "debug",           '\0', POPT_ARG_NONE, &opt_debug,        0, N_("Show debug messages"), NULL },
498                 { "no-superblock",   0,    POPT_ARG_VAL,  &use_superblock,   0, N_("Do not use verity superblock"), NULL },
499                 { "format",          0,    POPT_ARG_INT,  &hash_type,        0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
500                 { "data-block-size", 0,    POPT_ARG_INT,  &data_block_size,  0, N_("Block size on the data device"), N_("bytes") },
501                 { "hash-block-size", 0,    POPT_ARG_INT,  &hash_block_size,  0, N_("Block size on the hash device"), N_("bytes") },
502                 { "data-blocks",     0,    POPT_ARG_STRING, &popt_tmp,       1, N_("The number of blocks in the data file"), N_("blocks") },
503                 { "hash-start",      0,    POPT_ARG_STRING, &popt_tmp,       2, N_("Starting block on the hash device"), N_("512-byte sectors") },
504                 { "hash",            'h',  POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
505                 { "salt",            's',  POPT_ARG_STRING, &salt_string,    0, N_("Salt"), N_("hex string") },
506                 { "uuid",            '\0', POPT_ARG_STRING, &opt_uuid,       0, N_("UUID for device to use."), NULL },
507                 POPT_TABLEEND
508         };
509
510         poptContext popt_context;
511         struct action_type *action;
512         const char *aname, *null_action_argv[] = {NULL};
513         int r;
514
515         crypt_set_log_callback(NULL, _log, NULL);
516
517         setlocale(LC_ALL, "");
518         bindtextdomain(PACKAGE, LOCALEDIR);
519         textdomain(PACKAGE);
520
521         popt_context = poptGetContext("verity", argc, argv, popt_options, 0);
522         poptSetOtherOptionHelp(popt_context,
523                                N_("[OPTION...] <action> <action-specific>"));
524
525         while((r = poptGetNextOpt(popt_context)) > 0) {
526                 unsigned long long ull_value;
527                 char *endp;
528
529                 errno = 0;
530                 ull_value = strtoull(popt_tmp, &endp, 0);
531                 if (*endp || !*popt_tmp ||
532                     (errno == ERANGE && ull_value == ULLONG_MAX) ||
533                     (errno != 0 && ull_value == 0))
534                         r = POPT_ERROR_BADNUMBER;
535
536                 switch(r) {
537                         case 1:
538                                 data_blocks = ull_value;
539                                 break;
540                         case 2:
541                                 hash_start = ull_value * 512;
542                                 break;
543                 }
544
545                 if (r < 0)
546                         break;
547         }
548
549         if (r < -1)
550                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
551                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
552
553         if (opt_version_mode) {
554                 log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
555                 poptFreeContext(popt_context);
556                 exit(EXIT_SUCCESS);
557         }
558
559         if (!(aname = poptGetArg(popt_context)))
560                 usage(popt_context, EXIT_FAILURE, _("Argument <action> missing."),
561                       poptGetInvocationName(popt_context));
562         for(action = action_types; action->type; action++)
563                 if (strcmp(action->type, aname) == 0)
564                         break;
565         if (!action->type)
566                 usage(popt_context, EXIT_FAILURE, _("Unknown action."),
567                       poptGetInvocationName(popt_context));
568
569         action_argc = 0;
570         action_argv = poptGetArgs(popt_context);
571         /* Make return values of poptGetArgs more consistent in case of remaining argc = 0 */
572         if(!action_argv)
573                 action_argv = null_action_argv;
574
575         /* Count args, somewhat unnice, change? */
576         while(action_argv[action_argc] != NULL)
577                 action_argc++;
578
579         if(action_argc < action->required_action_argc) {
580                 char buf[128];
581                 snprintf(buf, 128,_("%s: requires %s as arguments"), action->type, action->arg_desc);
582                 usage(popt_context, EXIT_FAILURE, buf,
583                       poptGetInvocationName(popt_context));
584         }
585
586         if (opt_debug) {
587                 opt_verbose = 1;
588                 crypt_set_debug_level(-1);
589                 _dbg_version_and_cmd(argc, argv);
590         }
591
592         r = run_action(action);
593         poptFreeContext(popt_context);
594         return r;
595 }