1 /* 2 * Copyright (c) 2011 Alex Hornung <alex@alexhornung.com>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 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 14 * distribution. 15 * 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 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #if defined(__DragonFly__) 32 #include <sys/diskslice.h> 33 #elif defined(__linux__) 34 #include <linux/fs.h> 35 #include <sys/ioctl.h> 36 #endif 37 #include <sys/stat.h> 38 #include <sys/uio.h> 39 #include <sys/select.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <termios.h> 46 #include <unistd.h> 47 #include <signal.h> 48 49 #include "tcplay.h" 50 51 void * 52 read_to_safe_mem(const char *file, off_t offset, size_t *sz) 53 { 54 void *mem = NULL; 55 ssize_t r = 0; 56 int fd; 57 58 if ((fd = open(file, O_RDONLY)) < 0) { 59 tc_log(1, "Error opening file %s\n", file); 60 return NULL; 61 } 62 63 if ((mem = alloc_safe_mem(*sz)) == NULL) { 64 tc_log(1, "Error allocating memory\n"); 65 goto out; 66 } 67 68 if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { 69 tc_log(1, "Error seeking on file %s\n", file); 70 goto m_err; 71 } 72 73 if ((r = read(fd, mem, *sz)) <= 0) { 74 tc_log(1, "Error reading from file %s\n", file); 75 goto m_err; 76 } 77 78 out: 79 *sz = r; 80 close(fd); 81 return mem; 82 /* NOT REACHED */ 83 84 m_err: 85 free_safe_mem(mem); 86 close(fd); 87 return NULL; 88 } 89 90 static size_t get_random_total_bytes = 0; 91 static size_t get_random_read_bytes = 0; 92 93 94 float 95 get_random_read_progress(void) 96 { 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; 100 } 101 102 static 103 void 104 get_random_summary(void) 105 { 106 float pct_done = get_random_read_progress(); 107 108 tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done); 109 } 110 111 int 112 get_random(unsigned char *buf, size_t len, int weak) 113 { 114 int fd; 115 ssize_t r; 116 size_t rd = 0; 117 size_t sz; 118 struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */ 119 120 121 if ((fd = open((weak) ? "/dev/urandom" : "/dev/random", O_RDONLY)) < 0) { 122 tc_log(1, "Error opening /dev/random\n"); 123 return -1; 124 } 125 126 summary_fn = get_random_summary; 127 get_random_total_bytes = len; 128 tc_internal_state = STATE_GET_RANDOM; 129 130 /* Get random data in 16-byte chunks */ 131 sz = 16; 132 while (rd < len) { 133 get_random_read_bytes = rd; 134 135 if ((len - rd) < sz) 136 sz = (len - rd); 137 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)); 141 close(fd); 142 summary_fn = NULL; 143 tc_internal_state = STATE_UNKNOWN; 144 return -1; 145 } 146 rd += r; 147 nanosleep(&ts, NULL); 148 } 149 150 close(fd); 151 summary_fn = NULL; 152 153 tc_internal_state = STATE_UNKNOWN; 154 return 0; 155 } 156 157 static disksz_t secure_erase_total_bytes = 0; 158 static disksz_t secure_erase_erased_bytes = 0; 159 160 float 161 get_secure_erase_progress(void) 162 { 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; 166 } 167 168 static 169 void 170 secure_erase_summary(void) 171 { 172 float pct_done = get_secure_erase_progress(); 173 tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done); 174 } 175 176 int 177 secure_erase(const char *dev, disksz_t bytes, size_t blksz) 178 { 179 size_t erased = 0; 180 int fd_rand, fd; 181 char buf[ERASE_BUFFER_SIZE]; 182 ssize_t r, w; 183 size_t sz; 184 185 if (blksz > MAX_BLKSZ) { 186 tc_log(1, "blksz > MAX_BLKSZ\n"); 187 return -1; 188 } 189 190 if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) { 191 tc_log(1, "Error opening /dev/urandom\n"); 192 return -1; 193 } 194 195 if ((fd = open(dev, O_WRONLY)) < 0) { 196 close(fd_rand); 197 tc_log(1, "Error opening %s\n", dev); 198 return -1; 199 } 200 201 summary_fn = secure_erase_summary; 202 secure_erase_total_bytes = bytes; 203 204 tc_internal_state = STATE_ERASE; 205 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) 211 sz = blksz; 212 213 if ((r = read(fd_rand, buf, sz)) < 0) { 214 tc_log(1, "Error reading from /dev/urandom\n"); 215 close(fd); 216 close(fd_rand); 217 summary_fn = NULL; 218 tc_internal_state = STATE_UNKNOWN; 219 return -1; 220 } 221 222 if (r < (ssize_t)blksz) 223 continue; 224 225 if ((w = write(fd, buf, r)) < 0) { 226 tc_log(1, "Error writing to %s\n", dev); 227 close(fd); 228 close(fd_rand); 229 summary_fn = NULL; 230 tc_internal_state = STATE_UNKNOWN; 231 return -1; 232 } 233 234 erased += (size_t)w; 235 } 236 237 close(fd); 238 close(fd_rand); 239 240 summary_fn = NULL; 241 242 tc_internal_state = STATE_UNKNOWN; 243 return 0; 244 } 245 246 #if defined(__DragonFly__) 247 int 248 get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize) 249 { 250 struct partinfo pinfo; 251 int fd; 252 253 if ((fd = open(dev, O_RDONLY)) < 0) { 254 tc_log(1, "Error opening %s\n", dev); 255 return -1; 256 } 257 258 memset(&pinfo, 0, sizeof(struct partinfo)); 259 260 if (ioctl(fd, DIOCGPART, &pinfo) < 0) { 261 close(fd); 262 return -1; 263 } 264 265 *blocks = (disksz_t)pinfo.media_blocks; 266 *bsize = pinfo.media_blksize; 267 268 close(fd); 269 return 0; 270 } 271 #elif defined(__linux__) 272 int 273 get_disk_info(const char *dev, disksz_t *blocks, size_t *bsize) 274 { 275 uint64_t nbytes; 276 int blocksz; 277 int fd; 278 279 if ((fd = open(dev, O_RDONLY)) < 0) { 280 tc_log(1, "Error opening %s\n", dev); 281 return -1; 282 } 283 284 if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) { 285 close(fd); 286 return -1; 287 } 288 289 if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) { 290 close(fd); 291 return -1; 292 } 293 294 *blocks = (disksz_t)(nbytes / blocksz); 295 *bsize = (size_t)(blocksz); 296 297 close(fd); 298 return 0; 299 } 300 #endif 301 302 int 303 write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem, 304 size_t bytes) 305 { 306 unsigned char *mem_buf = NULL; 307 ssize_t w; 308 size_t sz; 309 off_t internal_off; 310 int fd; 311 312 /* Align to block sizes */ 313 internal_off = offset % blksz; 314 #ifdef DEBUG 315 printf("offset: %"PRIu64", internal offset: %"PRIu64"\n", 316 (uint64_t)offset, (uint64_t)internal_off); 317 #endif 318 offset = rounddown(offset, blksz); 319 320 if ((internal_off + bytes) > blksz) { 321 tc_log(1, "This should never happen: internal_off + bytes > " 322 "blksz (write_to_disk)\n"); 323 return -1; 324 } 325 326 if ((bytes < blksz) || (internal_off != 0)) { 327 sz = blksz; 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); 331 return -1; 332 } 333 334 memcpy(mem_buf + internal_off, mem, bytes); 335 } 336 337 if ((fd = open(dev, O_WRONLY)) < 0) { 338 tc_log(1, "Error opening device %s\n", dev); 339 return -1; 340 } 341 342 if ((lseek(fd, offset, (offset >= 0) ? SEEK_SET : SEEK_END) < 0)) { 343 tc_log(1, "Error seeking on device %s\n", dev); 344 close(fd); 345 return -1; 346 } 347 348 if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) { 349 tc_log(1, "Error writing to device %s\n", dev); 350 close(fd); 351 return -1; 352 } 353 354 close(fd); 355 356 if (mem_buf != NULL) 357 free_safe_mem(mem_buf); 358 return 0; 359 } 360 361 362 int 363 write_to_file(const char *file, void *mem, size_t bytes) 364 { 365 int fd; 366 ssize_t w; 367 368 if ((fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) < 0) { 369 tc_log(1, "Error opening file %s\n", file); 370 return -1; 371 } 372 373 if ((w = write(fd, mem, bytes)) < 0) { 374 tc_log(1, "Error writing to file %s\n", file); 375 close(fd); 376 return -1; 377 } 378 379 close(fd); 380 return 0; 381 } 382 383 384 static struct termios termios_old; 385 static int tty_fd; 386 387 static void sigint_termios(int sa) 388 { 389 tcsetattr(tty_fd, TCSAFLUSH, &termios_old); 390 exit(sa); 391 } 392 393 int 394 read_passphrase(const char *prompt, char *pass, size_t passlen, size_t bufsz, time_t timeout) 395 { 396 struct termios termios_new; 397 struct timeval to; 398 fd_set fds; 399 ssize_t n; 400 int fd = STDIN_FILENO, r = 0, nready; 401 struct sigaction act, old_act; 402 int is_tty = isatty(fd); 403 404 if (is_tty == 0) 405 errno = 0; 406 407 memset(pass, 0, bufsz); 408 409 printf("%s", prompt); 410 fflush(stdout); 411 412 /* If input is being provided by something which is not a terminal, don't 413 * change the settings. */ 414 if (is_tty) { 415 tcgetattr(fd, &termios_old); 416 memcpy(&termios_new, &termios_old, sizeof(termios_new)); 417 termios_new.c_lflag &= ~ECHO; 418 419 act.sa_handler = sigint_termios; 420 act.sa_flags = SA_RESETHAND; 421 sigemptyset(&act.sa_mask); 422 423 tty_fd = fd; 424 sigaction(SIGINT, &act, &old_act); 425 426 tcsetattr(fd, TCSAFLUSH, &termios_new); 427 } 428 429 if (timeout > 0) { 430 memset(&to, 0, sizeof(to)); 431 to.tv_sec = timeout; 432 433 FD_ZERO(&fds); 434 FD_SET(fd, &fds); 435 nready = select(fd + 1, &fds, NULL, NULL, &to); 436 if (nready <= 0) { 437 r = EINTR; 438 goto out; 439 } 440 } 441 442 n = read(fd, pass, bufsz-1); 443 if (n > 0) { 444 pass[n-1] = '\0'; /* Strip trailing \n */ 445 } else { 446 r = EIO; 447 } 448 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); 453 454 /* Cut off after passlen characters */ 455 pass[passlen] = '\0'; 456 457 out: 458 if (is_tty) { 459 tcsetattr(fd, TCSAFLUSH, &termios_old); 460 putchar('\n'); 461 462 sigaction(SIGINT, &old_act, NULL); 463 } 464 465 return r; 466 } 467