47bcfe123725e8a969bc4a7cacd6c252bcddabb8
[platform/upstream/cryptsetup.git] / src / utils_tools.c
1 /*
2  * cryptsetup - setup cryptographic volumes for dm-crypt
3  *
4  * Copyright (C) 2004 Jana Saout <jana@saout.de>
5  * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
6  * Copyright (C) 2009-2020 Red Hat, Inc. All rights reserved.
7  * Copyright (C) 2009-2020 Milan Broz
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "cryptsetup.h"
25 #include <math.h>
26 #include <signal.h>
27
28 int opt_verbose = 0;
29 int opt_debug = 0;
30 int opt_debug_json = 0;
31 int opt_batch_mode = 0;
32 int opt_progress_frequency = 0;
33
34 /* interrupt handling */
35 volatile int quit = 0;
36 static int signals_blocked = 0;
37
38 static void int_handler(int sig __attribute__((__unused__)))
39 {
40         quit++;
41 }
42
43 int tools_signals_blocked(void)
44 {
45         return signals_blocked;
46 }
47
48 void set_int_block(int block)
49 {
50         sigset_t signals_open;
51
52         log_dbg("%slocking interruption on signal.", block ? "B" : "Unb");
53
54         sigemptyset(&signals_open);
55         sigaddset(&signals_open, SIGINT);
56         sigaddset(&signals_open, SIGTERM);
57         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
58         signals_blocked = block;
59         quit = 0;
60 }
61
62 void set_int_handler(int block)
63 {
64         struct sigaction sigaction_open;
65
66         log_dbg("Installing SIGINT/SIGTERM handler.");
67         memset(&sigaction_open, 0, sizeof(struct sigaction));
68         sigaction_open.sa_handler = int_handler;
69         sigaction(SIGINT, &sigaction_open, 0);
70         sigaction(SIGTERM, &sigaction_open, 0);
71         set_int_block(block);
72 }
73
74 void check_signal(int *r)
75 {
76         if (quit && !*r)
77                 *r = -EINTR;
78 }
79
80 #define LOG_MAX_LEN 4096
81
82 __attribute__((format(printf, 5, 6)))
83 void clogger(struct crypt_device *cd, int level, const char *file, int line,
84              const char *format, ...)
85 {
86         va_list argp;
87         char target[LOG_MAX_LEN + 2];
88
89         va_start(argp, format);
90
91         if (vsnprintf(&target[0], LOG_MAX_LEN, format, argp) > 0) {
92                 /* All verbose and error messages in tools end with EOL. */
93                 if (level == CRYPT_LOG_VERBOSE || level == CRYPT_LOG_ERROR ||
94                     level == CRYPT_LOG_DEBUG || level == CRYPT_LOG_DEBUG_JSON)
95                         strncat(target, "\n", LOG_MAX_LEN);
96
97                 crypt_log(cd, level, target);
98         }
99
100         va_end(argp);
101 }
102
103 void tool_log(int level, const char *msg, void *usrptr __attribute__((unused)))
104 {
105         switch(level) {
106
107         case CRYPT_LOG_NORMAL:
108                 fprintf(stdout, "%s", msg);
109                 break;
110         case CRYPT_LOG_VERBOSE:
111                 if (opt_verbose)
112                         fprintf(stdout, "%s", msg);
113                 break;
114         case CRYPT_LOG_ERROR:
115                 fprintf(stderr, "%s", msg);
116                 break;
117         case CRYPT_LOG_DEBUG_JSON:
118         case CRYPT_LOG_DEBUG:
119                 if (opt_debug)
120                         fprintf(stdout, "# %s", msg);
121                 break;
122         }
123 }
124
125 void quiet_log(int level, const char *msg, void *usrptr)
126 {
127         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
128                 level = CRYPT_LOG_VERBOSE;
129         tool_log(level, msg, usrptr);
130 }
131
132 static int _dialog(const char *msg, void *usrptr, int default_answer)
133 {
134         const char *fail_msg = (const char *)usrptr;
135         char *answer = NULL;
136         size_t size = 0;
137         int r = default_answer, block;
138
139         block = tools_signals_blocked();
140         if (block)
141                 set_int_block(0);
142
143         if (isatty(STDIN_FILENO) && !opt_batch_mode) {
144                 log_std("\nWARNING!\n========\n");
145                 log_std("%s\n\nAre you sure? (Type 'yes' in capital letters): ", msg);
146                 fflush(stdout);
147                 if(getline(&answer, &size, stdin) == -1) {
148                         r = 0;
149                         /* Aborted by signal */
150                         if (!quit)
151                                 log_err(_("Error reading response from terminal."));
152                         else
153                                 log_dbg("Query interrupted on signal.");
154                 } else {
155                         r = !strcmp(answer, "YES\n");
156                         if (!r && fail_msg)
157                                 log_err("%s", fail_msg);
158                 }
159         }
160
161         if (block && !quit)
162                 set_int_block(1);
163
164         free(answer);
165         return r;
166 }
167
168 int yesDialog(const char *msg, void *usrptr)
169 {
170         return _dialog(msg, usrptr, 1);
171 }
172
173 int noDialog(const char *msg, void *usrptr)
174 {
175         return _dialog(msg, usrptr, 0);
176 }
177
178 void show_status(int errcode)
179 {
180         char *crypt_error;
181
182         if(!opt_verbose)
183                 return;
184
185         if(!errcode) {
186                 log_std(_("Command successful.\n"));
187                 return;
188         }
189
190         if (errcode < 0)
191                 errcode = translate_errno(errcode);
192
193         if (errcode == 1)
194                 crypt_error = _("wrong or missing parameters");
195         else if (errcode == 2)
196                 crypt_error = _("no permission or bad passphrase");
197         else if (errcode == 3)
198                 crypt_error = _("out of memory");
199         else if (errcode == 4)
200                 crypt_error = _("wrong device or file specified");
201         else if (errcode == 5)
202                 crypt_error = _("device already exists or device is busy");
203         else
204                 crypt_error = _("unknown error");
205
206         log_std(_("Command failed with code %i (%s).\n"), -errcode, crypt_error);
207 }
208
209 const char *uuid_or_device(const char *spec)
210 {
211         static char device[PATH_MAX];
212         char s, *ptr;
213         int i = 0, uuid_len = 5;
214
215         /* Check if it is correct UUID=<LUKS_UUID> format */
216         if (spec && !strncmp(spec, "UUID=", uuid_len)) {
217                 strcpy(device, "/dev/disk/by-uuid/");
218                 ptr = &device[strlen(device)];
219                 i = uuid_len;
220                 while ((s = spec[i++]) && i < (PATH_MAX - 13)) {
221                         if (!isxdigit(s) && s != '-')
222                                 return spec; /* Bail it out */
223                         if (isalpha(s))
224                                 s = tolower(s);
225                         *ptr++ = s;
226                 }
227                 *ptr = '\0';
228                 return device;
229         }
230
231         return spec;
232 }
233
234 __attribute__ ((noreturn)) void usage(poptContext popt_context,
235                                              int exitcode, const char *error,
236                                              const char *more)
237 {
238         poptPrintUsage(popt_context, stderr, 0);
239         if (error)
240                 log_err("%s: %s", more, error);
241         poptFreeContext(popt_context);
242         exit(exitcode);
243 }
244
245 void dbg_version_and_cmd(int argc, const char **argv)
246 {
247         int i;
248
249         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
250         for (i = 0; i < argc; i++) {
251                 if (i)
252                         log_std(" ");
253                 log_std("%s", argv[i]);
254         }
255         log_std("\"\n");
256 }
257
258 /* Translate exit code to simple codes */
259 int translate_errno(int r)
260 {
261         switch (r) {
262         case 0:         r = EXIT_SUCCESS; break;
263         case -EEXIST:
264         case -EBUSY:    r = 5; break;
265         case -ENOTBLK:
266         case -ENODEV:   r = 4; break;
267         case -ENOMEM:   r = 3; break;
268         case -EPERM:    r = 2; break;
269         case -EINVAL:
270         case -ENOENT:
271         case -ENOSYS:
272         default:        r = EXIT_FAILURE;
273         }
274         return r;
275 }
276
277 void tools_keyslot_msg(int keyslot, crypt_object_op op)
278 {
279         if (keyslot < 0)
280                 return;
281
282         if (op == CREATED)
283                 log_verbose(_("Key slot %i created."), keyslot);
284         else if (op == UNLOCKED)
285                 log_verbose(_("Key slot %i unlocked."), keyslot);
286         else if (op == REMOVED)
287                 log_verbose(_("Key slot %i removed."), keyslot);
288 }
289
290 void tools_token_msg(int token, crypt_object_op op)
291 {
292         if (token < 0)
293                 return;
294
295         if (op == CREATED)
296                 log_verbose(_("Token %i created."), token);
297         else if (op == REMOVED)
298                 log_verbose(_("Token %i removed."), token);
299 }
300
301 /*
302  * Device size string parsing, suffixes:
303  * s|S - 512 bytes sectors
304  * k  |K  |m  |M  |g  |G  |t  |T   - 1024 base
305  * kiB|KiB|miB|MiB|giB|GiB|tiB|TiB - 1024 base
306  * kb |KB |mM |MB |gB |GB |tB |TB  - 1000 base
307  */
308 int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
309 {
310         char *endp = NULL;
311         size_t len;
312         uint64_t mult_base, mult, tmp;
313
314         *size = strtoull(s, &endp, 10);
315         if (!isdigit(s[0]) ||
316             (errno == ERANGE && *size == ULLONG_MAX) ||
317             (errno != 0 && *size == 0))
318                 return -EINVAL;
319
320         if (!endp || !*endp)
321                 return 0;
322
323         len = strlen(endp);
324         /* Allow "B" and "iB" suffixes */
325         if (len > 3 ||
326            (len == 3 && (endp[1] != 'i' || endp[2] != 'B')) ||
327            (len == 2 && endp[1] != 'B'))
328                 return -EINVAL;
329
330         if (len == 1 || len == 3)
331                 mult_base = 1024;
332         else
333                 mult_base = 1000;
334
335         mult = 1;
336         switch (endp[0]) {
337         case 's':
338         case 'S': mult = 512;
339                 break;
340         case 't':
341         case 'T': mult *= mult_base;
342                  /* Fall through */
343         case 'g':
344         case 'G': mult *= mult_base;
345                  /* Fall through */
346         case 'm':
347         case 'M': mult *= mult_base;
348                  /* Fall through */
349         case 'k':
350         case 'K': mult *= mult_base;
351                 break;
352         default:
353                 return -EINVAL;
354         }
355
356         tmp = *size * mult;
357         if (*size && (tmp / *size) != mult) {
358                 log_dbg("Device size overflow.");
359                 return -EINVAL;
360         }
361
362         *size = tmp;
363         return 0;
364 }
365
366 /* Time progress helper */
367
368 /* The difference in seconds between two times in "timeval" format. */
369 static double time_diff(struct timeval *start, struct timeval *end)
370 {
371         return (end->tv_sec - start->tv_sec)
372                 + (end->tv_usec - start->tv_usec) / 1E6;
373 }
374
375 void tools_clear_line(void)
376 {
377         if (opt_progress_frequency)
378                 return;
379         /* vt100 code clear line */
380         log_std("\33[2K\r");
381 }
382
383 static void tools_time_progress(uint64_t device_size, uint64_t bytes, uint64_t *start_bytes,
384                          struct timeval *start_time, struct timeval *end_time)
385 {
386         struct timeval now_time;
387         unsigned long long mbytes, eta;
388         double tdiff, uib, frequency;
389         int final = (bytes == device_size);
390         const char *eol, *ustr = "";
391
392         if (opt_batch_mode)
393                 return;
394
395         gettimeofday(&now_time, NULL);
396         if (start_time->tv_sec == 0 && start_time->tv_usec == 0) {
397                 *start_time = now_time;
398                 *end_time = now_time;
399                 *start_bytes = bytes;
400                 return;
401         }
402
403         if (opt_progress_frequency) {
404                 frequency = (double)opt_progress_frequency;
405                 eol = "\n";
406         } else {
407                 frequency = 0.5;
408                 eol = "";
409         }
410
411         if (!final && time_diff(end_time, &now_time) < frequency)
412                 return;
413
414         *end_time = now_time;
415
416         tdiff = time_diff(start_time, end_time);
417         if (!tdiff)
418                 return;
419
420         mbytes = bytes  / 1024 / 1024;
421         uib = (double)(bytes - *start_bytes) / tdiff;
422
423         /* FIXME: calculate this from last minute only. */
424         eta = (unsigned long long)(device_size / uib - tdiff);
425
426         if (uib > 1073741824.0f) {
427                 uib /= 1073741824.0f;
428                 ustr = "Gi";
429         } else if (uib > 1048576.0f) {
430                 uib /= 1048576.0f;
431                 ustr = "Mi";
432         } else if (uib > 1024.0f) {
433                 uib /= 1024.0f;
434                 ustr = "Ki";
435         }
436
437         tools_clear_line();
438         if (final)
439                 log_std("Finished, time %02llu:%02llu.%03llu, "
440                         "%4llu MiB written, speed %5.1f %sB/s\n",
441                         (unsigned long long)tdiff / 60,
442                         (unsigned long long)tdiff % 60,
443                         (unsigned long long)((tdiff - floor(tdiff)) * 1000.0),
444                         mbytes, uib, ustr);
445         else
446                 log_std("Progress: %5.1f%%, ETA %02llu:%02llu, "
447                         "%4llu MiB written, speed %5.1f %sB/s%s",
448                         (double)bytes / device_size * 100,
449                         eta / 60, eta % 60, mbytes, uib, ustr, eol);
450         fflush(stdout);
451 }
452
453 int tools_wipe_progress(uint64_t size, uint64_t offset, void *usrptr)
454 {
455         static struct timeval start_time = {}, end_time = {};
456         static uint64_t start_offset = 0;
457         int r = 0;
458
459         tools_time_progress(size, offset, &start_offset, &start_time, &end_time);
460
461         check_signal(&r);
462         if (r) {
463                 tools_clear_line();
464                 log_err(_("\nWipe interrupted."));
465         }
466
467         return r;
468 }
469
470 static void report_partition(const char *value, const char *device)
471 {
472         if (opt_batch_mode)
473                 log_dbg("Device %s already contains a '%s' partition signature.", device, value);
474         else
475                 log_std(_("WARNING: Device %s already contains a '%s' partition signature.\n"), device, value);
476 }
477
478 static void report_superblock(const char *value, const char *device)
479 {
480         if (opt_batch_mode)
481                 log_dbg("Device %s already contains a '%s' superblock signature.", device, value);
482         else
483                 log_std(_("WARNING: Device %s already contains a '%s' superblock signature.\n"), device, value);
484 }
485
486 int tools_detect_signatures(const char *device, int ignore_luks, size_t *count)
487 {
488         int r;
489         size_t tmp_count;
490         struct blkid_handle *h;
491         blk_probe_status pr;
492
493         if (!count)
494                 count = &tmp_count;
495
496         *count = 0;
497
498         if (!blk_supported()) {
499                 log_dbg("Blkid support disabled.");
500                 return 0;
501         }
502
503         if ((r = blk_init_by_path(&h, device))) {
504                 log_err(_("Failed to initialize device signature probes."));
505                 return -EINVAL;
506         }
507
508         blk_set_chains_for_full_print(h);
509
510         if (ignore_luks && blk_superblocks_filter_luks(h)) {
511                 r = -EINVAL;
512                 goto out;
513         }
514
515         while ((pr = blk_probe(h)) < PRB_EMPTY) {
516                 if (blk_is_partition(h))
517                         report_partition(blk_get_partition_type(h), device);
518                 else if (blk_is_superblock(h))
519                         report_superblock(blk_get_superblock_type(h), device);
520                 else {
521                         log_dbg("Internal tools_detect_signatures() error.");
522                         r = -EINVAL;
523                         goto out;
524                 }
525                 (*count)++;
526         }
527
528         if (pr == PRB_FAIL)
529                 r = -EINVAL;
530 out:
531         blk_free(h);
532         return r;
533 }
534
535 int tools_wipe_all_signatures(const char *path)
536 {
537         int fd, flags, r;
538         blk_probe_status pr;
539         struct stat st;
540         struct blkid_handle *h = NULL;
541
542         if (!blk_supported()) {
543                 log_dbg("Blkid support disabled.");
544                 return 0;
545         }
546
547         if (stat(path, &st)) {
548                 log_err(_("Failed to stat device %s."), path);
549                 return -EINVAL;
550         }
551
552         flags = O_RDWR;
553         if (S_ISBLK(st.st_mode))
554                 flags |= O_EXCL;
555
556         /* better than opening regular file with O_EXCL (undefined) */
557         /* coverity[toctou] */
558         fd = open(path, flags);
559         if (fd < 0) {
560                 if (errno == EBUSY)
561                         log_err(_("Device %s is in use. Can not proceed with format operation."), path);
562                 else
563                         log_err(_("Failed to open file %s in read/write mode."), path);
564                 return -EINVAL;
565         }
566
567         if ((r = blk_init_by_fd(&h, fd))) {
568                 log_err(_("Failed to initialize device signature probes."));
569                 r = -EINVAL;
570                 goto out;
571         }
572
573         blk_set_chains_for_wipes(h);
574
575         while ((pr = blk_probe(h)) < PRB_EMPTY) {
576                 if (blk_is_partition(h))
577                         log_verbose(_("Existing '%s' partition signature (offset: %" PRIi64 " bytes) on device %s will be wiped."),
578                                     blk_get_partition_type(h), blk_get_offset(h), path);
579                 if (blk_is_superblock(h))
580                         log_verbose(_("Existing '%s' superblock signature (offset: %" PRIi64 " bytes) on device %s will be wiped."),
581                                     blk_get_superblock_type(h), blk_get_offset(h), path);
582                 if (blk_do_wipe(h)) {
583                         log_err(_("Failed to wipe device signature."));
584                         r = -EINVAL;
585                         goto out;
586                 }
587         }
588
589         if (pr != PRB_EMPTY) {
590                 log_err(_("Failed to probe device %s for a signature."), path);
591                 r = -EINVAL;
592         }
593 out:
594         close(fd);
595         blk_free(h);
596         return r;
597 }
598
599 int tools_is_cipher_null(const char *cipher)
600 {
601         if (!cipher)
602                 return 0;
603
604         return !strcmp(cipher, "cipher_null") ? 1 : 0;
605 }
606
607 /*
608  * Keyfile - is standard input treated as a binary file (no EOL handling).
609  */
610 int tools_is_stdin(const char *key_file)
611 {
612         if (!key_file)
613                 return 1;
614
615         return strcmp(key_file, "-") ? 0 : 1;
616 }
617
618 int tools_reencrypt_progress(uint64_t size, uint64_t offset, void *usrptr)
619 {
620         static struct timeval start_time = {}, end_time = {};
621         static uint64_t start_offset = 0;
622         int r = 0;
623
624         tools_time_progress(size, offset, &start_offset, &start_time, &end_time);
625
626         check_signal(&r);
627         if (r) {
628                 tools_clear_line();
629                 log_err(_("\nReencryption interrupted."));
630         }
631
632         return r;
633 }