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/types.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/uio.h> 38 #include <sys/select.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <termios.h> 45 #include <unistd.h> 46 47 #include "tcplay.h" 48 49 void * 50 read_to_safe_mem(const char *file, off_t offset, size_t *sz) 51 { 52 void *mem = NULL; 53 ssize_t r = 0; 54 int fd; 55 56 if ((fd = open(file, O_RDONLY)) < 0) { 57 tc_log(1, "Error opening file %s\n", file); 58 return NULL; 59 } 60 61 if ((mem = alloc_safe_mem(*sz)) == NULL) { 62 tc_log(1, "Error allocating memory\n"); 63 goto out; 64 } 65 66 if ((lseek(fd, offset, SEEK_SET) < 0)) { 67 tc_log(1, "Error seeking on file %s\n", file); 68 goto m_err; 69 } 70 71 if ((r = read(fd, mem, *sz)) <= 0) { 72 tc_log(1, "Error reading from file %s\n", file); 73 goto m_err; 74 } 75 76 out: 77 *sz = r; 78 close(fd); 79 return mem; 80 /* NOT REACHED */ 81 82 m_err: 83 free_safe_mem(mem); 84 close(fd); 85 return NULL; 86 } 87 88 static size_t get_random_total_bytes = 0; 89 static size_t get_random_read_bytes = 0; 90 91 static 92 void 93 get_random_summary(void) 94 { 95 float pct_done; 96 97 pct_done = (1.0 * get_random_read_bytes) / 98 (1.0 * get_random_total_bytes) * 100.0; 99 tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done); 100 } 101 102 int 103 get_random(unsigned char *buf, size_t len) 104 { 105 int fd; 106 ssize_t r; 107 size_t rd = 0; 108 size_t sz; 109 struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */ 110 111 112 if ((fd = open("/dev/random", O_RDONLY)) < 0) { 113 tc_log(1, "Error opening /dev/random\n"); 114 return -1; 115 } 116 117 summary_fn = get_random_summary; 118 get_random_total_bytes = len; 119 120 /* Get random data in 16-byte chunks */ 121 sz = 16; 122 while (rd < len) { 123 get_random_read_bytes = rd; 124 125 if ((len - rd) < sz) 126 sz = (len - rd); 127 128 if ((r = read(fd, buf+rd, sz)) < 0) { 129 tc_log(1, "Error reading from /dev/random(%d): %s\n", 130 fd, strerror(errno)); 131 close(fd); 132 summary_fn = NULL; 133 return -1; 134 } 135 rd += r; 136 nanosleep(&ts, NULL); 137 } 138 139 close(fd); 140 summary_fn = NULL; 141 142 return 0; 143 } 144 145 static size_t secure_erase_total_bytes = 0; 146 static size_t secure_erase_erased_bytes = 0; 147 148 static 149 void 150 secure_erase_summary(void) 151 { 152 float pct_done; 153 154 pct_done = (1.0 * secure_erase_erased_bytes) / 155 (1.0 * secure_erase_total_bytes) * 100.0; 156 tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done); 157 } 158 159 int 160 secure_erase(const char *dev, size_t bytes, size_t blksz) 161 { 162 size_t erased = 0; 163 int fd_rand, fd; 164 char buf[ERASE_BUFFER_SIZE]; 165 ssize_t r, w; 166 size_t sz; 167 168 if (blksz > MAX_BLKSZ) { 169 tc_log(1, "blksz > MAX_BLKSZ\n"); 170 return -1; 171 } 172 173 if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) { 174 tc_log(1, "Error opening /dev/urandom\n"); 175 return -1; 176 } 177 178 if ((fd = open(dev, O_WRONLY)) < 0) { 179 close(fd_rand); 180 tc_log(1, "Error opening %s\n", dev); 181 return -1; 182 } 183 184 summary_fn = secure_erase_summary; 185 secure_erase_total_bytes = bytes; 186 187 sz = ERASE_BUFFER_SIZE; 188 while (erased < bytes) { 189 secure_erase_erased_bytes = erased; 190 /* Switch to block size when not much is remaining */ 191 if ((bytes - erased) <= ERASE_BUFFER_SIZE) 192 sz = blksz; 193 194 if ((r = read(fd_rand, buf, sz)) < 0) { 195 tc_log(1, "Error reading from /dev/urandom\n"); 196 close(fd); 197 close(fd_rand); 198 summary_fn = NULL; 199 return -1; 200 } 201 202 if (r < (ssize_t)blksz) 203 continue; 204 205 if ((w = write(fd, buf, r)) < 0) { 206 tc_log(1, "Error writing to %s\n", dev); 207 close(fd); 208 close(fd_rand); 209 summary_fn = NULL; 210 return -1; 211 } 212 213 erased += (size_t)w; 214 } 215 216 close(fd); 217 close(fd_rand); 218 219 summary_fn = NULL; 220 221 return 0; 222 } 223 224 #if defined(__DragonFly__) 225 int 226 get_disk_info(const char *dev, size_t *blocks, size_t *bsize) 227 { 228 struct partinfo pinfo; 229 int fd; 230 231 if ((fd = open(dev, O_RDONLY)) < 0) { 232 tc_log(1, "Error opening %s\n", dev); 233 return -1; 234 } 235 236 memset(&pinfo, 0, sizeof(struct partinfo)); 237 238 if (ioctl(fd, DIOCGPART, &pinfo) < 0) { 239 close(fd); 240 return -1; 241 } 242 243 *blocks = pinfo.media_blocks; 244 *bsize = pinfo.media_blksize; 245 246 close(fd); 247 return 0; 248 } 249 #elif defined(__linux__) 250 int 251 get_disk_info(const char *dev, size_t *blocks, size_t *bsize) 252 { 253 uint64_t nbytes; 254 int blocksz; 255 int fd; 256 257 if ((fd = open(dev, O_RDONLY)) < 0) { 258 tc_log(1, "Error opening %s\n", dev); 259 return -1; 260 } 261 262 if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) { 263 close(fd); 264 return -1; 265 } 266 267 if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) { 268 close(fd); 269 return -1; 270 } 271 272 *blocks = (size_t)(nbytes / blocksz); 273 *bsize = (size_t)(blocksz); 274 275 close(fd); 276 return 0; 277 } 278 #endif 279 280 int 281 write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem, 282 size_t bytes) 283 { 284 unsigned char *mem_buf = NULL; 285 ssize_t w; 286 size_t sz; 287 off_t internal_off; 288 int fd; 289 290 /* Align to block sizes */ 291 internal_off = offset % blksz; 292 #ifdef DEBUG 293 printf("offset: %"PRIu64", internal offset: %"PRIu64"\n", 294 (uint64_t)offset, (uint64_t)internal_off); 295 #endif 296 offset = (offset/blksz) * blksz; 297 298 if ((internal_off + bytes) > blksz) { 299 tc_log(1, "This should never happen: internal_off + bytes > " 300 "blksz (write_to_disk)\n"); 301 return -1; 302 } 303 304 if ((bytes < blksz) || (internal_off != 0)) { 305 sz = blksz; 306 if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) { 307 tc_log(1, "Error buffering data on " 308 "write_to_disk(%s)\n", dev); 309 return -1; 310 } 311 312 memcpy(mem_buf + internal_off, mem, bytes); 313 } 314 315 if ((fd = open(dev, O_WRONLY)) < 0) { 316 tc_log(1, "Error opening device %s\n", dev); 317 return -1; 318 } 319 320 if ((lseek(fd, offset, SEEK_SET) < 0)) { 321 tc_log(1, "Error seeking on device %s\n", dev); 322 close(fd); 323 return -1; 324 } 325 326 if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) { 327 tc_log(1, "Error writing to device %s\n", dev); 328 close(fd); 329 return -1; 330 } 331 332 close(fd); 333 334 if (mem_buf != NULL) 335 free_safe_mem(mem_buf); 336 return 0; 337 } 338 339 int 340 read_passphrase(const char *prompt, char *pass, size_t passlen, time_t timeout) 341 { 342 struct termios termios_old, termios_new; 343 struct timeval to; 344 fd_set fds; 345 ssize_t n; 346 int fd, r = 0, cfd = 0, nready; 347 348 if ((fd = open("/dev/tty", O_RDONLY)) == -1) { 349 fd = STDIN_FILENO; 350 cfd = 1; 351 } 352 353 printf("%s", prompt); 354 fflush(stdout); 355 356 memset(pass, 0, passlen); 357 358 tcgetattr(fd, &termios_old); 359 memcpy(&termios_new, &termios_old, sizeof(termios_new)); 360 termios_new.c_lflag &= ~ECHO; 361 tcsetattr(fd, TCSAFLUSH, &termios_new); 362 363 if (timeout > 0) { 364 memset(&to, 0, sizeof(to)); 365 to.tv_sec = timeout; 366 367 FD_ZERO(&fds); 368 FD_SET(fd, &fds); 369 nready = select(fd + 1, &fds, NULL, NULL, &to); 370 if (nready <= 0) { 371 r = EINTR; 372 goto out; 373 } 374 } 375 376 n = read(fd, pass, passlen-1); 377 if (n > 0) { 378 pass[n-1] = '\0'; /* Strip trailing \n */ 379 } else { 380 r = EIO; 381 } 382 383 out: 384 if (cfd) 385 close(fd); 386 387 tcsetattr(fd, TCSAFLUSH, &termios_old); 388 putchar('\n'); 389 390 return r; 391 } 392