90778981d927591252d75ace4e03c077337f7146
[platform/upstream/cryptsetup.git] / src / crypt_reencrypt.c
1 /*
2  * crypt_reencrypt - crypt utility for offline reencryption
3  *
4  * Copyright (C) 2012 Milan Broz 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 /* The code works as follows:
21  *  - create backup (detached) headers fo old and new device
22  *  - mark original device unusable
23  *  - maps two devices, one with old header one with new onto
24  *    the _same_ underlying device
25  *  - with direct-io reads old device and copy to new device in defined steps
26  *  - keps simple off in file (allows restart)
27  *  - there is several windows when corruption can happen
28  *
29  * null target
30  * dmsetup create x --table "0 $(blockdev --getsz DEV) crypt cipher_null-ecb-null - 0 DEV 0"
31  */
32 #define _LARGEFILE64_SOURCE
33 #define _FILE_OFFSET_BITS 64
34
35 #include <string.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <inttypes.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <sys/stat.h>
44 #include <sys/ioctl.h>
45 #include <sys/time.h>
46 #include <linux/fs.h>
47 #include <fcntl.h>
48 #include <limits.h>
49 #include <signal.h>
50 #include <libcryptsetup.h>
51 #include <popt.h>
52
53 #include "cryptsetup.h"
54
55 static int opt_verbose = 0;
56 static int opt_debug = 0;
57 static const char *opt_cipher = NULL;
58 static const char *opt_hash = NULL;
59 static const char *opt_key_file = NULL;
60 static int opt_iteration_time = 1000;
61 static int opt_batch_mode = 0;
62 static int opt_version_mode = 0;
63 static int opt_random = 0;
64 static int opt_urandom = 0;
65 static int opt_bsize = 4;
66 static int opt_directio = 0;
67 static int opt_write_log = 0;
68
69 static const char **action_argv;
70
71 static volatile int quit = 0;
72
73 struct {
74         char *device;
75         char *device_uuid;
76         uint64_t device_size;
77         uint64_t device_offset;
78         uint64_t device_shift;
79
80         int in_progress:1;
81         enum { FORWARD = 0, BACKWARD = 1 } reencrypt_direction;
82
83         char header_file_org[PATH_MAX];
84         char header_file_new[PATH_MAX];
85         char log_file[PATH_MAX];
86
87         char crypt_path_org[PATH_MAX];
88         char crypt_path_new[PATH_MAX];
89         int log_fd;
90
91         char *password;
92         size_t passwordLen;
93         int keyslot;
94
95         struct timeval start_time, end_time;
96         uint64_t restart_bytest;
97 } rnc;
98
99 char MAGIC[]   = {'L','U','K','S', 0xba, 0xbe};
100 char NOMAGIC[] = {'L','U','K','S', 0xde, 0xad};
101 int  MAGIC_L = 6;
102
103 typedef enum {
104         MAKE_UNUSABLE,
105         MAKE_USABLE,
106         CHECK_UNUSABLE
107 } header_magic;
108
109 __attribute__((format(printf, 5, 6)))
110 static void clogger(struct crypt_device *cd, int level, const char *file,
111                    int line, const char *format, ...)
112 {
113         va_list argp;
114         char *target = NULL;
115
116         va_start(argp, format);
117
118         if (vasprintf(&target, format, argp) > 0) {
119                 if (level >= 0) {
120                         crypt_log(cd, level, target);
121                 } else if (opt_debug)
122                         printf("# %s\n", target);
123         }
124
125         va_end(argp);
126         free(target);
127 }
128
129 static void _log(int level, const char *msg, void *usrptr __attribute__((unused)))
130 {
131         switch(level) {
132
133         case CRYPT_LOG_NORMAL:
134                 fputs(msg, stdout);
135                 break;
136         case CRYPT_LOG_VERBOSE:
137                 if (opt_verbose)
138                         fputs(msg, stdout);
139                 break;
140         case CRYPT_LOG_ERROR:
141                 fputs(msg, stderr);
142                 break;
143         case CRYPT_LOG_DEBUG:
144                 if (opt_debug)
145                         printf("# %s\n", msg);
146                 break;
147         default:
148                 fprintf(stderr, "Internal error on logging class for msg: %s", msg);
149                 break;
150         }
151 }
152
153 static void _quiet_log(int level, const char *msg, void *usrptr)
154 {
155         if (!opt_verbose && (level == CRYPT_LOG_ERROR || level == CRYPT_LOG_NORMAL))
156                 level = CRYPT_LOG_VERBOSE;
157         _log(level, msg, usrptr);
158 }
159
160 static void int_handler(int sig __attribute__((__unused__)))
161 {
162         quit++;
163 }
164
165 static void set_int_block(int block)
166 {
167         sigset_t signals_open;
168
169         sigemptyset(&signals_open);
170         sigaddset(&signals_open, SIGINT);
171         sigaddset(&signals_open, SIGTERM);
172         sigprocmask(block ? SIG_SETMASK : SIG_UNBLOCK, &signals_open, NULL);
173 }
174
175 static void set_int_handler(void)
176 {
177         struct sigaction sigaction_open;
178
179         memset(&sigaction_open, 0, sizeof(struct sigaction));
180         sigaction_open.sa_handler = int_handler;
181         sigaction(SIGINT, &sigaction_open, 0);
182         sigaction(SIGTERM, &sigaction_open, 0);
183         set_int_block(0);
184 }
185
186 /* The difference in seconds between two times in "timeval" format. */
187 double time_diff(struct timeval start, struct timeval end)
188 {
189         return (end.tv_sec - start.tv_sec)
190                 + (end.tv_usec - start.tv_usec) / 1E6;
191 }
192
193 static int alignment(int fd)
194 {
195         int alignment;
196
197         alignment = fpathconf(fd, _PC_REC_XFER_ALIGN);
198         if (alignment < 0)
199                 alignment = 4096;
200         return alignment;
201 }
202
203 static int device_magic(header_magic set_magic)
204 {
205         char *buf = NULL;
206         size_t block_size = 512;
207         int r, devfd;
208         ssize_t s;
209
210         devfd = open(rnc.device, O_RDWR | O_DIRECT);
211         if (devfd == -1)
212                 return errno == EBUSY ? -EBUSY : -EINVAL;
213
214         if (posix_memalign((void *)&buf, alignment(devfd), block_size)) {
215                 r = -ENOMEM;
216                 goto out;
217         }
218
219         s = read(devfd, buf, block_size);
220         if (s < 0 || s != block_size) {
221                 log_verbose(_("Cannot read device %s.\n"), rnc.device);
222                 close(devfd);
223                 return -EIO;
224         }
225
226         if (set_magic == MAKE_UNUSABLE && !memcmp(buf, MAGIC, MAGIC_L)) {
227                 log_dbg("Marking LUKS device %s unusable.", rnc.device);
228                 memcpy(buf, NOMAGIC, MAGIC_L);
229                 r = 0;
230
231         } else if (set_magic == MAKE_USABLE && !memcmp(buf, NOMAGIC, MAGIC_L)) {
232                 log_dbg("Marking LUKS device %s usable.", rnc.device);
233                 memcpy(buf, MAGIC, MAGIC_L);
234                 r = 0;
235         } else if (set_magic == CHECK_UNUSABLE) {
236                 r = memcmp(buf, NOMAGIC, MAGIC_L) ? -EINVAL : 0;
237                 if (!r)
238                         rnc.device_uuid = strndup(&buf[0xa8], 40);
239                 goto out;
240         } else
241                 r = -EINVAL;
242
243         if (!r) {
244                 if (lseek(devfd, 0, SEEK_SET) == -1)
245                         goto out;
246                 s = write(devfd, buf, block_size);
247                 if (s < 0 || s != block_size) {
248                         log_verbose(_("Cannot write device %s.\n"), rnc.device);
249                         r = -EIO;
250                 }
251         } else
252                 log_dbg("LUKS signature check failed for %s.", rnc.device);
253 out:
254         if (buf)
255                 memset(buf, 0, block_size);
256         free(buf);
257         close(devfd);
258         return r;
259 }
260
261 static int create_empty_header(const char *new_file, const char *old_file)
262 {
263         struct stat st;
264         size_t size;
265         int fd, r = 0;
266         char *buf;
267
268         if (stat(old_file, &st) == -1 || (st.st_mode & S_IFMT) != S_IFREG)
269                 return -EINVAL;
270         size = st.st_size;
271
272         log_dbg("Creating empty file %s of size %lu.", new_file, (unsigned long)size);
273
274         if (!(buf = malloc(size)))
275                 return -ENOMEM;
276         memset(buf, 0, size);
277
278         fd = creat(new_file, S_IRUSR|S_IWUSR);
279         if(fd == -1) {
280                 free(buf);
281                 return -EINVAL;
282         }
283
284         if (write(fd, buf, size) < size)
285                 r = -EIO;
286
287         close(fd);
288         free(buf);
289         return r;
290 }
291
292 static int write_log(void)
293 {
294         static char buf[512];
295         ssize_t r;
296
297         //log_dbg("Updating LUKS reencryption log offset %" PRIu64 ".", offset);
298         memset(buf, 0, sizeof(buf));
299         snprintf(buf, sizeof(buf), "# LUKS reencryption log, DO NOT EDIT OR DELETE.\n"
300                 "version = %d\nUUID = %s\ndirection = %d\n"
301                 "offset = %" PRIu64 "\nshift = %" PRIu64 "\n# EOF\n",
302                 1, rnc.device_uuid, rnc.reencrypt_direction,
303                 rnc.device_offset, rnc.device_shift);
304
305         lseek(rnc.log_fd, 0, SEEK_SET);
306         r = write(rnc.log_fd, buf, sizeof(buf));
307         if (r < 0 || r != sizeof(buf))
308                 return -EIO;
309
310         return 0;
311 }
312
313 static int parse_line_log(const char *line)
314 {
315         uint64_t u64;
316         int i;
317         char s[64];
318
319         /* comment */
320         if (*line == '#')
321                 return 0;
322
323         if (sscanf(line, "version = %d", &i) == 1) {
324                 if (i != 1) {
325                         log_dbg("Log: Unexpected version = %i", i);
326                         return -EINVAL;
327                 }
328         } else if (sscanf(line, "UUID = %40s", s) == 1) {
329                 if (!rnc.device_uuid || strcmp(rnc.device_uuid, s)) {
330                         log_dbg("Log: Unexpected UUID %s", s);
331                         return -EINVAL;
332                 }
333         } else if (sscanf(line, "direction = %d", &i) == 1) {
334                 log_dbg("Log: direction = %i", i);
335                 rnc.reencrypt_direction = i;
336         } else if (sscanf(line, "offset = %" PRIu64, &u64) == 1) {
337                 log_dbg("Log: offset = %" PRIu64, u64);
338                 rnc.device_offset = u64;
339         } else if (sscanf(line, "shift = %" PRIu64, &u64) == 1) {
340                 log_dbg("Log: shift = %" PRIu64, u64);
341                 rnc.device_shift = u64;
342         } else
343                 return -EINVAL;
344
345         return 0;
346 }
347
348 static int parse_log(void)
349 {
350         static char buf[512];
351         char *start, *end;
352         ssize_t s;
353
354         s = read(rnc.log_fd, buf, sizeof(buf));
355         if (s == -1)
356                 return -EIO;
357
358         buf[511] = '\0';
359         start = buf;
360         do {
361                 end = strchr(start, '\n');
362                 if (end) {
363                         *end++ = '\0';
364                         if (parse_line_log(start)) {
365                                 log_err("Wrong log format.\n");
366                                 return -EINVAL;
367                         }
368                 }
369
370                 start = end;
371         } while (start);
372
373         return 0;
374 }
375
376 static int open_log(void)
377 {
378         int flags;
379         struct stat st;
380
381         if(stat(rnc.log_file, &st) < 0) {
382                 log_dbg("Creating LUKS reencryption log file %s.", rnc.log_file);
383
384                 // FIXME: move that somewhere else
385                 rnc.reencrypt_direction = BACKWARD;
386
387                 flags = opt_directio ? O_RDWR|O_CREAT|O_DIRECT : O_RDWR|O_CREAT;
388                 rnc.log_fd = open(rnc.log_file, flags, S_IRUSR|S_IWUSR);
389                 if (rnc.log_fd == -1)
390                         return -EINVAL;
391                 if (write_log() < 0)
392                         return -EIO;
393         } else {
394                 log_dbg("Log file %s exists, restarting.", rnc.log_file);
395                 flags = opt_directio ? O_RDWR|O_DIRECT : O_RDWR;
396                 rnc.log_fd = open(rnc.log_file, flags);
397                 if (rnc.log_fd == -1)
398                         return -EINVAL;
399                 rnc.in_progress = 1;
400         }
401
402         /* Be sure it is correct format */
403         return parse_log();
404 }
405
406 static void close_log(void)
407 {
408         log_dbg("Closing LUKS reencryption log file %s.", rnc.log_file);
409         if (rnc.log_fd != -1)
410                 close(rnc.log_fd);
411 }
412
413 static int activate_luks_headers(void)
414 {
415         struct crypt_device *cd = NULL, *cd_new = NULL;
416         int r;
417
418         log_dbg("Activating LUKS devices from headers.");
419
420         if ((r = crypt_init(&cd, rnc.header_file_org)) ||
421             (r = crypt_load(cd, CRYPT_LUKS1, NULL)) ||
422             (r = crypt_set_data_device(cd, rnc.device)))
423                 goto out;
424
425         if ((r = crypt_activate_by_passphrase(cd, rnc.header_file_org,
426                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen,
427                 CRYPT_ACTIVATE_READONLY|CRYPT_ACTIVATE_PRIVATE)) < 0)
428                 goto out;
429
430         if ((r = crypt_init(&cd_new, rnc.header_file_new)) ||
431             (r = crypt_load(cd_new, CRYPT_LUKS1, NULL)) ||
432             (r = crypt_set_data_device(cd_new, rnc.device)))
433                 goto out;
434
435         if ((r = crypt_activate_by_passphrase(cd_new, rnc.header_file_new,
436                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen,
437                 CRYPT_ACTIVATE_SHARED|CRYPT_ACTIVATE_PRIVATE)) < 0)
438                 goto out;
439 out:
440         crypt_free(cd);
441         crypt_free(cd_new);
442         return r;
443 }
444
445 static int backup_luks_headers(void)
446 {
447         struct crypt_device *cd = NULL, *cd_new = NULL;
448         struct crypt_params_luks1 params = {0};
449         char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
450         int r;
451
452         log_dbg("Creating LUKS header backup for device %s.", rnc.device);
453         if ((r = crypt_init(&cd, rnc.device)) ||
454             (r = crypt_load(cd, CRYPT_LUKS1, NULL)))
455                 goto out;
456
457         crypt_set_confirm_callback(cd, NULL, NULL);
458         if ((r = crypt_header_backup(cd, CRYPT_LUKS1, rnc.header_file_org)))
459                 goto out;
460
461         if ((r = create_empty_header(rnc.header_file_new, rnc.header_file_org)))
462                 goto out;
463
464         params.hash = opt_hash ?: DEFAULT_LUKS1_HASH;
465         params.data_alignment = crypt_get_data_offset(cd);
466         params.data_device = rnc.device;
467
468         if ((r = crypt_init(&cd_new, rnc.header_file_new)))
469                 goto out;
470
471         if (opt_random)
472                 crypt_set_rng_type(cd_new, CRYPT_RNG_RANDOM);
473         else if (opt_urandom)
474                 crypt_set_rng_type(cd_new, CRYPT_RNG_URANDOM);
475
476         if (opt_iteration_time)
477                 crypt_set_iteration_time(cd_new, opt_iteration_time);
478
479         if (opt_cipher) {
480                 r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
481                 if (r < 0) {
482                         log_err(_("No known cipher specification pattern detected.\n"));
483                         goto out;
484                 }
485         }
486
487         if ((r = crypt_format(cd_new, CRYPT_LUKS1,
488                         opt_cipher ? cipher : crypt_get_cipher(cd),
489                         opt_cipher ? cipher_mode : crypt_get_cipher_mode(cd),
490                         crypt_get_uuid(cd),
491                         NULL, crypt_get_volume_key_size(cd), &params)))
492                 goto out;
493
494         if ((r = crypt_keyslot_add_by_volume_key(cd_new, rnc.keyslot,
495                                 NULL, 0, rnc.password, rnc.passwordLen)) < 0)
496                 goto out;
497
498 out:
499         crypt_free(cd);
500         crypt_free(cd_new);
501         return r;
502 }
503
504 static void remove_headers(void)
505 {
506         struct crypt_device *cd = NULL;
507
508         if (crypt_init(&cd, NULL))
509                 return;
510         crypt_set_log_callback(cd, _quiet_log, NULL);
511         (void)crypt_deactivate(cd, rnc.header_file_org);
512         (void)crypt_deactivate(cd, rnc.header_file_new);
513         crypt_free(cd);
514 }
515
516 static int restore_luks_header(const char *backup)
517 {
518         struct crypt_device *cd = NULL;
519         int r;
520
521         r = crypt_init(&cd, rnc.device);
522
523         if (r == 0) {
524                 crypt_set_confirm_callback(cd, NULL, NULL);
525                 r = crypt_header_restore(cd, CRYPT_LUKS1, backup);
526         }
527
528         crypt_free(cd);
529         return r;
530 }
531
532 void print_progress(uint64_t bytes, int final)
533 {
534         uint64_t mbytes = (bytes - rnc.restart_bytest) / 1024 / 1024;
535         struct timeval now_time;
536         double tdiff;
537
538         gettimeofday(&now_time, NULL);
539         if (!final && time_diff(rnc.end_time, now_time) < 0.5)
540                 return;
541
542         rnc.end_time = now_time;
543
544         if (opt_batch_mode)
545                 return;
546
547         tdiff = time_diff(rnc.start_time, rnc.end_time);
548         if (!tdiff)
549                 return;
550
551         log_err("\33[2K\rProgress: %5.1f%%, time elapsed %3.1f seconds, %4"
552                 PRIu64 " MB written, speed %5.2f MB/s%s",
553                 (double)bytes / rnc.device_size * 100,
554                 time_diff(rnc.start_time, rnc.end_time),
555                 mbytes, (double)(mbytes) / tdiff,
556                 final ? "\n" :"");
557 }
558
559 static int copy_data_forward(int fd_old, int fd_new, size_t block_size, void *buf, uint64_t *bytes)
560 {
561         ssize_t s1, s2;
562
563         rnc.restart_bytest = *bytes = rnc.device_offset;
564         while (!quit && rnc.device_offset < rnc.device_size) {
565                 s1 = read(fd_old, buf, block_size);
566                 if (s1 < 0 || (s1 != block_size && (rnc.device_offset + s1) != rnc.device_size)) {
567                         log_err("Read error, expecting %d, got %d.\n", (int)block_size, (int)s1);
568                         return -EIO;
569                 }
570                 s2 = write(fd_new, buf, s1);
571                 if (s2 < 0) {
572                         log_err("Write error, expecting %d, got %d.\n", (int)block_size, (int)s2);
573                         return -EIO;
574                 }
575                 rnc.device_offset += s1;
576                 if (opt_write_log && write_log() < 0) {
577                         log_err("Log write error, some data are perhaps lost.\n");
578                         return -EIO;
579                 }
580
581                 *bytes += (uint64_t)s2;
582                 print_progress(*bytes, 0);
583         }
584
585         return quit ? -EAGAIN : 0;
586 }
587
588 static int copy_data_backward(int fd_old, int fd_new, size_t block_size, void *buf, uint64_t *bytes)
589 {
590         ssize_t s1, s2, working_block;
591         off64_t working_offset;
592
593         rnc.restart_bytest = *bytes = rnc.device_size - rnc.device_offset;
594         while (!quit && rnc.device_offset) {
595                 if (rnc.device_offset < block_size) {
596                         working_offset = 0;
597                         working_block = rnc.device_offset;
598                 } else {
599                         working_offset = rnc.device_offset - block_size;
600                         working_block = block_size;
601                 }
602
603                 if (lseek64(fd_old, working_offset, SEEK_SET) < 0 ||
604                     lseek64(fd_new, working_offset, SEEK_SET) < 0) {
605                         log_err("Cannot seek to device offset.\n");
606                         return -EIO;
607                 }
608
609                 s1 = read(fd_old, buf, working_block);
610                 if (s1 < 0 || (s1 != working_block)) {
611                         log_err("Read error, expecting %d, got %d.\n", (int)block_size, (int)s1);
612                         return -EIO;
613                 }
614                 s2 = write(fd_new, buf, working_block);
615                 if (s2 < 0) {
616                         log_err("Write error, expecting %d, got %d.\n", (int)block_size, (int)s2);
617                         return -EIO;
618                 }
619                 rnc.device_offset -= s1;
620                 if (opt_write_log && write_log() < 0) {
621                         log_err("Log write error, some data are perhaps lost.\n");
622                         return -EIO;
623                 }
624
625                 *bytes += (uint64_t)s2;
626                 print_progress(*bytes, 0);
627         }
628
629         return quit ? -EAGAIN : 0;
630 }
631
632 static int copy_data(void)
633 {
634         size_t block_size = opt_bsize * 1024 * 1024;
635         int fd_old = -1, fd_new = -1;
636         int r = -EINVAL;
637         void *buf = NULL;
638         uint64_t bytes = 0;
639
640         fd_old = open(rnc.crypt_path_org, O_RDONLY | (opt_directio ? O_DIRECT : 0));
641         if (fd_old == -1)
642                 goto out;
643
644         fd_new = open(rnc.crypt_path_new, O_WRONLY | (opt_directio ? O_DIRECT : 0));
645         if (fd_new == -1)
646                 goto out;
647
648         if (lseek(fd_old, rnc.device_offset, SEEK_SET) == -1)
649                 goto out;
650
651         if (lseek(fd_new, rnc.device_offset, SEEK_SET) == -1)
652                 goto out;
653
654         /* Check size */
655         if (ioctl(fd_old, BLKGETSIZE64, &rnc.device_size) < 0)
656                 goto out;
657
658         if (posix_memalign((void *)&buf, alignment(fd_new), block_size)) {
659                 r = -ENOMEM;
660                 goto out;
661         }
662
663         set_int_handler();
664         // FIXME: all this should be in init
665         if (!rnc.in_progress && rnc.reencrypt_direction == BACKWARD)
666                 rnc.device_offset = rnc.device_size;
667
668         gettimeofday(&rnc.start_time, NULL);
669
670         if (rnc.reencrypt_direction == FORWARD)
671                 r = copy_data_forward(fd_old, fd_new, block_size, buf, &bytes);
672         else
673                 r = copy_data_backward(fd_old, fd_new, block_size, buf, &bytes);
674
675         set_int_block(1);
676         print_progress(bytes, 1);
677
678         if (r < 0)
679                 log_err("ERROR during reencryption.\n");
680
681         if (write_log() < 0)
682                 log_err("Log write error, ignored.\n");
683
684 out:
685         if (fd_old != -1)
686                 close(fd_old);
687         if (fd_new != -1)
688                 close(fd_new);
689         free(buf);
690         return r;
691 }
692
693 static int initialize_uuid(void)
694 {
695         struct crypt_device *cd = NULL;
696         int r;
697
698         /* Try to load LUKS from device */
699         if ((r = crypt_init(&cd, rnc.device)))
700                 return r;
701         crypt_set_log_callback(cd, _quiet_log, NULL);
702         r = crypt_load(cd, CRYPT_LUKS1, NULL);
703         if (!r)
704                 rnc.device_uuid = strdup(crypt_get_uuid(cd));
705         else
706                 /* Reencryption already in progress - magic header? */
707                 r = device_magic(CHECK_UNUSABLE);
708
709         crypt_free(cd);
710         return r;
711 }
712
713 static int initialize_passphrase(const char *device)
714 {
715         struct crypt_device *cd = NULL;
716         int r;
717
718         if ((r = crypt_init(&cd, device)) ||
719             (r = crypt_load(cd, CRYPT_LUKS1, NULL)) ||
720             (r = crypt_set_data_device(cd, rnc.device)))
721                 goto out;
722
723         if ((r = crypt_get_key(_("Enter LUKS passphrase: "),
724                           &rnc.password, &rnc.passwordLen,
725                           0, 0, opt_key_file,
726                           0, 0, cd)) <0)
727                 goto out;
728
729         if ((r = crypt_activate_by_passphrase(cd, NULL,
730                 CRYPT_ANY_SLOT, rnc.password, rnc.passwordLen, 0) < 0))
731                 goto out;
732
733         if (r >= 0) {
734                 rnc.keyslot = r;
735                 r = 0;
736         }
737 out:
738         crypt_free(cd);
739         return r;
740 }
741
742 static int initialize_context(const char *device)
743 {
744         log_dbg("Initialising reencryption context.");
745
746         rnc.log_fd =-1;
747
748         if (!(rnc.device = strndup(device, PATH_MAX)))
749                 return -ENOMEM;
750
751         if (initialize_uuid()) {
752                 log_err("No header found on device.\n");
753                 return -EINVAL;
754         }
755
756         /* Prepare device names */
757         if (snprintf(rnc.log_file, PATH_MAX,
758                      "LUKS-%s.log", rnc.device_uuid) < 0)
759                 return -ENOMEM;
760         if (snprintf(rnc.header_file_org, PATH_MAX,
761                      "LUKS-%s.org", rnc.device_uuid) < 0)
762                 return -ENOMEM;
763         if (snprintf(rnc.header_file_new, PATH_MAX,
764                      "LUKS-%s.new", rnc.device_uuid) < 0)
765                 return -ENOMEM;
766
767         /* Paths to encrypted devices */
768         if (snprintf(rnc.crypt_path_org, PATH_MAX,
769                      "%s/%s", crypt_get_dir(), rnc.header_file_org) < 0)
770                 return -ENOMEM;
771         if (snprintf(rnc.crypt_path_new, PATH_MAX,
772                      "%s/%s", crypt_get_dir(), rnc.header_file_new) < 0)
773                 return -ENOMEM;
774
775         remove_headers();
776
777         return open_log();
778 }
779
780 static void destroy_context(void)
781 {
782         log_dbg("Destroying reencryption context.");
783
784         close_log();
785         remove_headers();
786
787         if ((rnc.reencrypt_direction == FORWARD &&
788              rnc.device_offset == rnc.device_size) ||
789              rnc.device_offset == 0) {
790                 unlink(rnc.log_file);
791                 unlink(rnc.header_file_org);
792                 unlink(rnc.header_file_new);
793         }
794
795         crypt_safe_free(rnc.password);
796
797         free(rnc.device);
798         free(rnc.device_uuid);
799 }
800
801 int run_reencrypt(const char *device)
802 {
803         int r = -EINVAL;
804         if (initialize_context(device))
805                 goto out;
806
807         log_dbg("Running reencryption.");
808
809         if (!rnc.in_progress) {
810                 if ((r = initialize_passphrase(rnc.device)) ||
811                     (r = backup_luks_headers()) ||
812                     (r = device_magic(MAKE_UNUSABLE)))
813                         goto out;
814         } else {
815                 if ((r = initialize_passphrase(rnc.header_file_org)))
816                         goto out;
817         }
818
819         if ((r = activate_luks_headers()))
820                 goto out;
821
822         if ((r = copy_data()))
823                 goto out;
824
825         r = restore_luks_header(rnc.header_file_new);
826 out:
827         destroy_context();
828         return r;
829 }
830
831 static __attribute__ ((noreturn)) void usage(poptContext popt_context,
832                                              int exitcode, const char *error,
833                                              const char *more)
834 {
835         poptPrintUsage(popt_context, stderr, 0);
836         if (error)
837                 log_err("%s: %s\n", more, error);
838         poptFreeContext(popt_context);
839         exit(exitcode);
840 }
841
842 static void help(poptContext popt_context,
843                  enum poptCallbackReason reason __attribute__((unused)),
844                  struct poptOption *key,
845                  const char *arg __attribute__((unused)),
846                  void *data __attribute__((unused)))
847 {
848         usage(popt_context, EXIT_SUCCESS, NULL, NULL);
849 }
850
851 static void _dbg_version_and_cmd(int argc, const char **argv)
852 {
853         int i;
854
855         log_std("# %s %s processing \"", PACKAGE_NAME, PACKAGE_VERSION);
856         for (i = 0; i < argc; i++) {
857                 if (i)
858                         log_std(" ");
859                 log_std("%s", argv[i]);
860         }
861         log_std("\"\n");
862 }
863
864 int main(int argc, const char **argv)
865 {
866         static struct poptOption popt_help_options[] = {
867                 { NULL,    '\0', POPT_ARG_CALLBACK, help, 0, NULL,                         NULL },
868                 { "help",  '?',  POPT_ARG_NONE,     NULL, 0, N_("Show this help message"), NULL },
869                 { "usage", '\0', POPT_ARG_NONE,     NULL, 0, N_("Display brief usage"),    NULL },
870                 POPT_TABLEEND
871         };
872         static struct poptOption popt_options[] = {
873                 { NULL,                '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
874                 { "version",           '\0', POPT_ARG_NONE, &opt_version_mode,          0, N_("Print package version"), NULL },
875                 { "verbose",           'v',  POPT_ARG_NONE, &opt_verbose,               0, N_("Shows more detailed error messages"), NULL },
876                 { "debug",             '\0', POPT_ARG_NONE, &opt_debug,                 0, N_("Show debug messages"), NULL },
877                 { "block-size",        'B',  POPT_ARG_INT, &opt_bsize,                  0, N_("Reencryption block size"), N_("MB") },
878                 { "cipher",            'c',  POPT_ARG_STRING, &opt_cipher,              0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
879                 { "hash",              'h',  POPT_ARG_STRING, &opt_hash,                0, N_("The hash used to create the encryption key from the passphrase"), NULL },
880                 { "key-file",          'd',  POPT_ARG_STRING, &opt_key_file,            0, N_("Read the key from a file."), NULL },
881                 { "iter-time",         'i',  POPT_ARG_INT, &opt_iteration_time,         0, N_("PBKDF2 iteration time for LUKS (in ms)"), N_("msecs") },
882                 { "batch-mode",        'q',  POPT_ARG_NONE, &opt_batch_mode,            0, N_("Do not ask for confirmation"), NULL },
883                 { "use-random",        '\0', POPT_ARG_NONE, &opt_random,                0, N_("Use /dev/random for generating volume key."), NULL },
884                 { "use-urandom",       '\0', POPT_ARG_NONE, &opt_urandom,               0, N_("Use /dev/urandom for generating volume key."), NULL },
885                 { "use-directio",      '\0', POPT_ARG_NONE, &opt_directio,              0, N_("Use direct-io when accesing devices."), NULL },
886                 { "write-log",         '\0', POPT_ARG_NONE, &opt_write_log,             0, N_("Update log file after every block."), NULL },
887                 POPT_TABLEEND
888         };
889         poptContext popt_context;
890         int r;
891
892         crypt_set_log_callback(NULL, _log, NULL);
893         log_err("WARNING: this is experimental code, it can completely break your data.\n");
894
895         set_int_block(1);
896
897         setlocale(LC_ALL, "");
898         bindtextdomain(PACKAGE, LOCALEDIR);
899         textdomain(PACKAGE);
900
901         popt_context = poptGetContext(PACKAGE, argc, argv, popt_options, 0);
902         poptSetOtherOptionHelp(popt_context,
903                                N_("[OPTION...] <device>]"));
904
905         while((r = poptGetNextOpt(popt_context)) > 0) {
906                 if (r < 0)
907                         break;
908         }
909
910         if (r < -1)
911                 usage(popt_context, EXIT_FAILURE, poptStrerror(r),
912                       poptBadOption(popt_context, POPT_BADOPTION_NOALIAS));
913         if (opt_version_mode) {
914                 log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
915                 poptFreeContext(popt_context);
916                 exit(EXIT_SUCCESS);
917         }
918
919         action_argv = poptGetArgs(popt_context);
920         if(!action_argv)
921                 usage(popt_context, EXIT_FAILURE, _("Argument required."),
922                       poptGetInvocationName(popt_context));
923
924         if (opt_random && opt_urandom)
925                 usage(popt_context, EXIT_FAILURE, _("Only one of --use-[u]random options is allowed."),
926                       poptGetInvocationName(popt_context));
927
928         if (opt_debug) {
929                 opt_verbose = 1;
930                 crypt_set_debug_level(-1);
931                 _dbg_version_and_cmd(argc, argv);
932         }
933
934         r = run_reencrypt(action_argv[0]);
935
936         poptFreeContext(popt_context);
937
938         /* Translate exit code to simple codes */
939         switch (r) {
940         case 0:         r = EXIT_SUCCESS; break;
941         case -EEXIST:
942         case -EBUSY:    r = 5; break;
943         case -ENOTBLK:
944         case -ENODEV:   r = 4; break;
945         case -ENOMEM:   r = 3; break;
946         case -EPERM:    r = 2; break;
947         case -EAGAIN: log_err(_("Interrupted by a signal.\n"));
948         case -EINVAL:
949         case -ENOENT:
950         case -ENOSYS:
951         default:        r = EXIT_FAILURE;
952         }
953         return r;
954 }