2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/types.h>
31 #if defined(__DragonFly__)
32 #include <sys/diskslice.h>
33 #elif defined(__linux__)
35 #include <sys/ioctl.h>
39 #include <sys/select.h>
52 read_to_safe_mem(const char *file
, off_t offset
, size_t *sz
)
58 if ((fd
= open(file
, O_RDONLY
)) < 0) {
59 tc_log(1, "Error opening file %s\n", file
);
63 if ((mem
= alloc_safe_mem(*sz
)) == NULL
) {
64 tc_log(1, "Error allocating memory\n");
68 if ((lseek(fd
, offset
, (offset
>= 0) ? SEEK_SET
: SEEK_END
) < 0)) {
69 tc_log(1, "Error seeking on file %s\n", file
);
73 if ((r
= read(fd
, mem
, *sz
)) <= 0) {
74 tc_log(1, "Error reading from file %s\n", file
);
90 static size_t get_random_total_bytes
= 0;
91 static size_t get_random_read_bytes
= 0;
95 get_random_read_progress(void)
97 return (get_random_total_bytes
== 0) ? 0.0 :
98 (1.0 * get_random_read_bytes
) /
99 (1.0 * get_random_total_bytes
) * 100.0;
104 get_random_summary(void)
106 float pct_done
= get_random_read_progress();
108 tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done
);
112 get_random(unsigned char *buf
, size_t len
, int weak
)
118 struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= 10000000 }; /* 10 ms */
121 if ((fd
= open((weak
) ? "/dev/urandom" : "/dev/random", O_RDONLY
)) < 0) {
122 tc_log(1, "Error opening /dev/random\n");
126 summary_fn
= get_random_summary
;
127 get_random_total_bytes
= len
;
128 tc_internal_state
= STATE_GET_RANDOM
;
130 /* Get random data in 16-byte chunks */
133 get_random_read_bytes
= rd
;
138 if ((r
= read(fd
, buf
+rd
, sz
)) < 0) {
139 tc_log(1, "Error reading from /dev/random(%d): %s\n",
140 fd
, strerror(errno
));
143 tc_internal_state
= STATE_UNKNOWN
;
147 nanosleep(&ts
, NULL
);
153 tc_internal_state
= STATE_UNKNOWN
;
157 static disksz_t secure_erase_total_bytes
= 0;
158 static disksz_t secure_erase_erased_bytes
= 0;
161 get_secure_erase_progress(void)
163 return (secure_erase_total_bytes
== 0) ? 0.0 :
164 (1.0 * secure_erase_erased_bytes
) /
165 (1.0 * secure_erase_total_bytes
) * 100.0;
170 secure_erase_summary(void)
172 float pct_done
= get_secure_erase_progress();
173 tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done
);
177 secure_erase(const char *dev
, disksz_t bytes
, size_t blksz
)
181 char buf
[ERASE_BUFFER_SIZE
];
185 if (blksz
> MAX_BLKSZ
) {
186 tc_log(1, "blksz > MAX_BLKSZ\n");
190 if ((fd_rand
= open("/dev/urandom", O_RDONLY
)) < 0) {
191 tc_log(1, "Error opening /dev/urandom\n");
195 if ((fd
= open(dev
, O_WRONLY
)) < 0) {
197 tc_log(1, "Error opening %s\n", dev
);
201 summary_fn
= secure_erase_summary
;
202 secure_erase_total_bytes
= bytes
;
204 tc_internal_state
= STATE_ERASE
;
206 sz
= ERASE_BUFFER_SIZE
;
207 while (erased
< bytes
) {
208 secure_erase_erased_bytes
= erased
;
209 /* Switch to block size when not much is remaining */
210 if ((bytes
- erased
) <= ERASE_BUFFER_SIZE
)
213 if ((r
= read(fd_rand
, buf
, sz
)) < 0) {
214 tc_log(1, "Error reading from /dev/urandom\n");
218 tc_internal_state
= STATE_UNKNOWN
;
222 if (r
< (ssize_t
)blksz
)
225 if ((w
= write(fd
, buf
, r
)) < 0) {
226 tc_log(1, "Error writing to %s\n", dev
);
230 tc_internal_state
= STATE_UNKNOWN
;
242 tc_internal_state
= STATE_UNKNOWN
;
246 #if defined(__DragonFly__)
248 get_disk_info(const char *dev
, disksz_t
*blocks
, size_t *bsize
)
250 struct partinfo pinfo
;
253 if ((fd
= open(dev
, O_RDONLY
)) < 0) {
254 tc_log(1, "Error opening %s\n", dev
);
258 memset(&pinfo
, 0, sizeof(struct partinfo
));
260 if (ioctl(fd
, DIOCGPART
, &pinfo
) < 0) {
265 *blocks
= (disksz_t
)pinfo
.media_blocks
;
266 *bsize
= pinfo
.media_blksize
;
271 #elif defined(__linux__)
273 get_disk_info(const char *dev
, disksz_t
*blocks
, size_t *bsize
)
279 if ((fd
= open(dev
, O_RDONLY
)) < 0) {
280 tc_log(1, "Error opening %s\n", dev
);
284 if ((ioctl(fd
, BLKSSZGET
, &blocksz
)) < 0) {
289 if ((ioctl(fd
, BLKGETSIZE64
, &nbytes
)) < 0) {
294 *blocks
= (disksz_t
)(nbytes
/ blocksz
);
295 *bsize
= (size_t)(blocksz
);
303 write_to_disk(const char *dev
, off_t offset
, size_t blksz
, void *mem
,
306 unsigned char *mem_buf
= NULL
;
312 /* Align to block sizes */
313 internal_off
= offset
% blksz
;
315 printf("offset: %"PRIu64
", internal offset: %"PRIu64
"\n",
316 (uint64_t)offset
, (uint64_t)internal_off
);
318 offset
= (offset
/blksz
) * blksz
;
320 if ((internal_off
+ bytes
) > blksz
) {
321 tc_log(1, "This should never happen: internal_off + bytes > "
322 "blksz (write_to_disk)\n");
326 if ((bytes
< blksz
) || (internal_off
!= 0)) {
328 if ((mem_buf
= read_to_safe_mem(dev
, offset
, &sz
)) == NULL
) {
329 tc_log(1, "Error buffering data on "
330 "write_to_disk(%s)\n", dev
);
334 memcpy(mem_buf
+ internal_off
, mem
, bytes
);
337 if ((fd
= open(dev
, O_WRONLY
)) < 0) {
338 tc_log(1, "Error opening device %s\n", dev
);
342 if ((lseek(fd
, offset
, (offset
>= 0) ? SEEK_SET
: SEEK_END
) < 0)) {
343 tc_log(1, "Error seeking on device %s\n", dev
);
348 if ((w
= write(fd
, (mem_buf
!= NULL
) ? mem_buf
: mem
, bytes
)) <= 0) {
349 tc_log(1, "Error writing to device %s\n", dev
);
357 free_safe_mem(mem_buf
);
363 write_to_file(const char *file
, void *mem
, size_t bytes
)
368 if ((fd
= open(file
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
)) < 0) {
369 tc_log(1, "Error opening file %s\n", file
);
373 if ((w
= write(fd
, mem
, bytes
)) < 0) {
374 tc_log(1, "Error writing to file %s\n", file
);
384 static struct termios termios_old
;
387 static void sigint_termios(int sa
)
389 tcsetattr(tty_fd
, TCSAFLUSH
, &termios_old
);
394 read_passphrase(const char *prompt
, char *pass
, size_t passlen
, size_t bufsz
, time_t timeout
)
396 struct termios termios_new
;
400 int fd
= STDIN_FILENO
, r
= 0, nready
;
401 struct sigaction act
, old_act
;
402 int is_tty
= isatty(fd
);
407 memset(pass
, 0, bufsz
);
409 printf("%s", prompt
);
412 /* If input is being provided by something which is not a terminal, don't
413 * change the settings. */
415 tcgetattr(fd
, &termios_old
);
416 memcpy(&termios_new
, &termios_old
, sizeof(termios_new
));
417 termios_new
.c_lflag
&= ~ECHO
;
419 act
.sa_handler
= sigint_termios
;
420 act
.sa_flags
= SA_RESETHAND
;
421 sigemptyset(&act
.sa_mask
);
424 sigaction(SIGINT
, &act
, &old_act
);
426 tcsetattr(fd
, TCSAFLUSH
, &termios_new
);
430 memset(&to
, 0, sizeof(to
));
435 nready
= select(fd
+ 1, &fds
, NULL
, NULL
, &to
);
442 n
= read(fd
, pass
, bufsz
-1);
444 pass
[n
-1] = '\0'; /* Strip trailing \n */
449 /* Warn about passphrase trimming */
450 if (strlen(pass
) > MAX_PASSSZ
)
451 tc_log(0, "WARNING: Passphrase is being trimmed to %zu "
452 "characters, discarding rest.\n", passlen
);
454 /* Cut off after passlen characters */
455 pass
[passlen
] = '\0';
459 tcsetattr(fd
, TCSAFLUSH
, &termios_old
);
462 sigaction(SIGINT
, &old_act
, NULL
);