Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 414 lines (337 sloc) 8.513 kB
dedd95c @bwalex major refactoring, bugfixes
authored
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 */
34165ed @bwalex first step to porting to linux; can be broken :)
authored
29
dedd95c @bwalex major refactoring, bugfixes
authored
30 #include <sys/types.h>
34165ed @bwalex first step to porting to linux; can be broken :)
authored
31 #if defined(__DragonFly__)
dedd95c @bwalex major refactoring, bugfixes
authored
32 #include <sys/diskslice.h>
34165ed @bwalex first step to porting to linux; can be broken :)
authored
33 #elif defined(__linux__)
34 #include <linux/fs.h>
35 #include <sys/ioctl.h>
36 #endif
dedd95c @bwalex major refactoring, bugfixes
authored
37 #include <sys/uio.h>
46f7fdb @bwalex add prompt timeout support
authored
38 #include <sys/select.h>
dedd95c @bwalex major refactoring, bugfixes
authored
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>
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
46 #include <signal.h>
dedd95c @bwalex major refactoring, bugfixes
authored
47
1af29c1 @bwalex rename tc-play => tcplay
authored
48 #include "tcplay.h"
dedd95c @bwalex major refactoring, bugfixes
authored
49
50 void *
51 read_to_safe_mem(const char *file, off_t offset, size_t *sz)
52 {
53 void *mem = NULL;
345e21f @bwalex minor fixes
authored
54 ssize_t r = 0;
dedd95c @bwalex major refactoring, bugfixes
authored
55 int fd;
56
57 if ((fd = open(file, O_RDONLY)) < 0) {
05bf0a1 @bwalex Start C API work
authored
58 tc_log(1, "Error opening file %s\n", file);
dedd95c @bwalex major refactoring, bugfixes
authored
59 return NULL;
60 }
61
62 if ((mem = alloc_safe_mem(*sz)) == NULL) {
05bf0a1 @bwalex Start C API work
authored
63 tc_log(1, "Error allocating memory\n");
dedd95c @bwalex major refactoring, bugfixes
authored
64 goto out;
65 }
66
67 if ((lseek(fd, offset, SEEK_SET) < 0)) {
05bf0a1 @bwalex Start C API work
authored
68 tc_log(1, "Error seeking on file %s\n", file);
dedd95c @bwalex major refactoring, bugfixes
authored
69 goto m_err;
70 }
71
72 if ((r = read(fd, mem, *sz)) <= 0) {
05bf0a1 @bwalex Start C API work
authored
73 tc_log(1, "Error reading from file %s\n", file);
dedd95c @bwalex major refactoring, bugfixes
authored
74 goto m_err;
75 }
76
77 out:
78 *sz = r;
79 close(fd);
80 return mem;
81 /* NOT REACHED */
82
83 m_err:
84 free_safe_mem(mem);
85 close(fd);
86 return NULL;
87 }
88
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
89 static size_t get_random_total_bytes = 0;
90 static size_t get_random_read_bytes = 0;
91
92 static
93 void
94 get_random_summary(void)
95 {
96 float pct_done;
97
98 pct_done = (1.0 * get_random_read_bytes) /
99 (1.0 * get_random_total_bytes) * 100.0;
100 tc_log(0, "Gathering true randomness, %.0f%% done.\n", pct_done);
101 }
102
dedd95c @bwalex major refactoring, bugfixes
authored
103 int
104 get_random(unsigned char *buf, size_t len)
105 {
106 int fd;
107 ssize_t r;
108 size_t rd = 0;
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
109 size_t sz;
dedd95c @bwalex major refactoring, bugfixes
authored
110 struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; /* 10 ms */
111
112
113 if ((fd = open("/dev/random", O_RDONLY)) < 0) {
05bf0a1 @bwalex Start C API work
authored
114 tc_log(1, "Error opening /dev/random\n");
dedd95c @bwalex major refactoring, bugfixes
authored
115 return -1;
116 }
117
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
118 summary_fn = get_random_summary;
119 get_random_total_bytes = len;
120
121 /* Get random data in 16-byte chunks */
122 sz = 16;
dedd95c @bwalex major refactoring, bugfixes
authored
123 while (rd < len) {
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
124 get_random_read_bytes = rd;
125
126 if ((len - rd) < sz)
127 sz = (len - rd);
128
129 if ((r = read(fd, buf+rd, sz)) < 0) {
8e1782a @bwalex make memory deallocation less lazy; ...
authored
130 tc_log(1, "Error reading from /dev/random(%d): %s\n",
131 fd, strerror(errno));
dedd95c @bwalex major refactoring, bugfixes
authored
132 close(fd);
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
133 summary_fn = NULL;
dedd95c @bwalex major refactoring, bugfixes
authored
134 return -1;
135 }
136 rd += r;
137 nanosleep(&ts, NULL);
138 }
139
140 close(fd);
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
141 summary_fn = NULL;
142
dedd95c @bwalex major refactoring, bugfixes
authored
143 return 0;
144 }
145
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
146 static size_t secure_erase_total_bytes = 0;
147 static size_t secure_erase_erased_bytes = 0;
148
149 static
150 void
151 secure_erase_summary(void)
152 {
153 float pct_done;
154
155 pct_done = (1.0 * secure_erase_erased_bytes) /
156 (1.0 * secure_erase_total_bytes) * 100.0;
157 tc_log(0, "Securely erasing, %.0f%% done.\n", pct_done);
158 }
159
dedd95c @bwalex major refactoring, bugfixes
authored
160 int
161 secure_erase(const char *dev, size_t bytes, size_t blksz)
162 {
163 size_t erased = 0;
164 int fd_rand, fd;
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
165 char buf[ERASE_BUFFER_SIZE];
dedd95c @bwalex major refactoring, bugfixes
authored
166 ssize_t r, w;
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
167 size_t sz;
dedd95c @bwalex major refactoring, bugfixes
authored
168
169 if (blksz > MAX_BLKSZ) {
05bf0a1 @bwalex Start C API work
authored
170 tc_log(1, "blksz > MAX_BLKSZ\n");
dedd95c @bwalex major refactoring, bugfixes
authored
171 return -1;
172 }
173
174 if ((fd_rand = open("/dev/urandom", O_RDONLY)) < 0) {
05bf0a1 @bwalex Start C API work
authored
175 tc_log(1, "Error opening /dev/urandom\n");
dedd95c @bwalex major refactoring, bugfixes
authored
176 return -1;
177 }
178
179 if ((fd = open(dev, O_WRONLY)) < 0) {
180 close(fd_rand);
05bf0a1 @bwalex Start C API work
authored
181 tc_log(1, "Error opening %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
182 return -1;
183 }
184
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
185 summary_fn = secure_erase_summary;
186 secure_erase_total_bytes = bytes;
187
188 sz = ERASE_BUFFER_SIZE;
dedd95c @bwalex major refactoring, bugfixes
authored
189 while (erased < bytes) {
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
190 secure_erase_erased_bytes = erased;
191 /* Switch to block size when not much is remaining */
192 if ((bytes - erased) <= ERASE_BUFFER_SIZE)
193 sz = blksz;
194
195 if ((r = read(fd_rand, buf, sz)) < 0) {
05bf0a1 @bwalex Start C API work
authored
196 tc_log(1, "Error reading from /dev/urandom\n");
dedd95c @bwalex major refactoring, bugfixes
authored
197 close(fd);
198 close(fd_rand);
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
199 summary_fn = NULL;
dedd95c @bwalex major refactoring, bugfixes
authored
200 return -1;
201 }
202
0c6d6a0 @bwalex big warning cleanup
authored
203 if (r < (ssize_t)blksz)
dedd95c @bwalex major refactoring, bugfixes
authored
204 continue;
205
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
206 if ((w = write(fd, buf, r)) < 0) {
05bf0a1 @bwalex Start C API work
authored
207 tc_log(1, "Error writing to %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
208 close(fd);
209 close(fd_rand);
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
210 summary_fn = NULL;
dedd95c @bwalex major refactoring, bugfixes
authored
211 return -1;
212 }
213
214 erased += (size_t)w;
215 }
216
217 close(fd);
218 close(fd_rand);
219
69686eb @bwalex improve secure_erase speed; add SIGINFO support
authored
220 summary_fn = NULL;
221
dedd95c @bwalex major refactoring, bugfixes
authored
222 return 0;
223 }
224
34165ed @bwalex first step to porting to linux; can be broken :)
authored
225 #if defined(__DragonFly__)
dedd95c @bwalex major refactoring, bugfixes
authored
226 int
227 get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
228 {
229 struct partinfo pinfo;
230 int fd;
231
232 if ((fd = open(dev, O_RDONLY)) < 0) {
05bf0a1 @bwalex Start C API work
authored
233 tc_log(1, "Error opening %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
234 return -1;
235 }
236
237 memset(&pinfo, 0, sizeof(struct partinfo));
238
239 if (ioctl(fd, DIOCGPART, &pinfo) < 0) {
240 close(fd);
241 return -1;
242 }
243
244 *blocks = pinfo.media_blocks;
245 *bsize = pinfo.media_blksize;
246
247 close(fd);
248 return 0;
249 }
34165ed @bwalex first step to porting to linux; can be broken :)
authored
250 #elif defined(__linux__)
251 int
252 get_disk_info(const char *dev, size_t *blocks, size_t *bsize)
253 {
254 uint64_t nbytes;
255 int blocksz;
256 int fd;
257
258 if ((fd = open(dev, O_RDONLY)) < 0) {
259 tc_log(1, "Error opening %s\n", dev);
260 return -1;
261 }
262
263 if ((ioctl(fd, BLKSSZGET, &blocksz)) < 0) {
264 close(fd);
265 return -1;
266 }
267
268 if ((ioctl(fd, BLKGETSIZE64, &nbytes)) < 0) {
269 close(fd);
270 return -1;
271 }
272
273 *blocks = (size_t)(nbytes / blocksz);
274 *bsize = (size_t)(blocksz);
275
276 close(fd);
277 return 0;
278 }
279 #endif
dedd95c @bwalex major refactoring, bugfixes
authored
280
281 int
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
282 write_to_disk(const char *dev, off_t offset, size_t blksz, void *mem,
0c6d6a0 @bwalex big warning cleanup
authored
283 size_t bytes)
dedd95c @bwalex major refactoring, bugfixes
authored
284 {
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
285 unsigned char *mem_buf = NULL;
dedd95c @bwalex major refactoring, bugfixes
authored
286 ssize_t w;
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
287 size_t sz;
288 off_t internal_off;
dedd95c @bwalex major refactoring, bugfixes
authored
289 int fd;
290
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
291 /* Align to block sizes */
292 internal_off = offset % blksz;
293 #ifdef DEBUG
294 printf("offset: %"PRIu64", internal offset: %"PRIu64"\n",
295 (uint64_t)offset, (uint64_t)internal_off);
296 #endif
297 offset = (offset/blksz) * blksz;
298
299 if ((internal_off + bytes) > blksz) {
300 tc_log(1, "This should never happen: internal_off + bytes > "
301 "blksz (write_to_disk)\n");
302 return -1;
303 }
304
305 if ((bytes < blksz) || (internal_off != 0)) {
306 sz = blksz;
307 if ((mem_buf = read_to_safe_mem(dev, offset, &sz)) == NULL) {
308 tc_log(1, "Error buffering data on "
309 "write_to_disk(%s)\n", dev);
310 return -1;
311 }
312
313 memcpy(mem_buf + internal_off, mem, bytes);
314 }
315
dedd95c @bwalex major refactoring, bugfixes
authored
316 if ((fd = open(dev, O_WRONLY)) < 0) {
05bf0a1 @bwalex Start C API work
authored
317 tc_log(1, "Error opening device %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
318 return -1;
319 }
320
321 if ((lseek(fd, offset, SEEK_SET) < 0)) {
05bf0a1 @bwalex Start C API work
authored
322 tc_log(1, "Error seeking on device %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
323 close(fd);
324 return -1;
325 }
326
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
327 if ((w = write(fd, (mem_buf != NULL) ? mem_buf : mem, bytes)) <= 0) {
05bf0a1 @bwalex Start C API work
authored
328 tc_log(1, "Error writing to device %s\n", dev);
dedd95c @bwalex major refactoring, bugfixes
authored
329 close(fd);
330 return -1;
331 }
332
333 close(fd);
92f96b8 @bwalex make blksz agnostic, fix volume size
authored
334
335 if (mem_buf != NULL)
336 free_safe_mem(mem_buf);
dedd95c @bwalex major refactoring, bugfixes
authored
337 return 0;
338 }
339
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
340
341 static struct termios termios_old;
342 static int tty_fd;
343
344 static void sigint_termios(int sa)
345 {
346 tcsetattr(tty_fd, TCSAFLUSH, &termios_old);
347 exit(sa);
348 }
349
dedd95c @bwalex major refactoring, bugfixes
authored
350 int
46f7fdb @bwalex add prompt timeout support
authored
351 read_passphrase(const char *prompt, char *pass, size_t passlen, time_t timeout)
dedd95c @bwalex major refactoring, bugfixes
authored
352 {
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
353 struct termios termios_new;
46f7fdb @bwalex add prompt timeout support
authored
354 struct timeval to;
355 fd_set fds;
dedd95c @bwalex major refactoring, bugfixes
authored
356 ssize_t n;
46f7fdb @bwalex add prompt timeout support
authored
357 int fd, r = 0, cfd = 0, nready;
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
358 struct sigaction act, old_act;
dedd95c @bwalex major refactoring, bugfixes
authored
359
360 if ((fd = open("/dev/tty", O_RDONLY)) == -1) {
361 fd = STDIN_FILENO;
362 cfd = 1;
363 }
364
5205e14 @bwalex Fix build on some linux distros & fix generic bug
authored
365 printf("%s", prompt);
dedd95c @bwalex major refactoring, bugfixes
authored
366 fflush(stdout);
367
368 memset(pass, 0, passlen);
369
370 tcgetattr(fd, &termios_old);
371 memcpy(&termios_new, &termios_old, sizeof(termios_new));
372 termios_new.c_lflag &= ~ECHO;
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
373
374 act.sa_handler = sigint_termios;
375 act.sa_flags = SA_RESETHAND;
376 sigemptyset(&act.sa_mask);
377
378 tty_fd = fd;
379 sigaction(SIGINT, &act, &old_act);
380
dedd95c @bwalex major refactoring, bugfixes
authored
381 tcsetattr(fd, TCSAFLUSH, &termios_new);
382
46f7fdb @bwalex add prompt timeout support
authored
383 if (timeout > 0) {
384 memset(&to, 0, sizeof(to));
385 to.tv_sec = timeout;
386
387 FD_ZERO(&fds);
388 FD_SET(fd, &fds);
389 nready = select(fd + 1, &fds, NULL, NULL, &to);
390 if (nready <= 0) {
391 r = EINTR;
392 goto out;
393 }
394 }
395
dedd95c @bwalex major refactoring, bugfixes
authored
396 n = read(fd, pass, passlen-1);
397 if (n > 0) {
398 pass[n-1] = '\0'; /* Strip trailing \n */
399 } else {
400 r = EIO;
401 }
402
46f7fdb @bwalex add prompt timeout support
authored
403 out:
dedd95c @bwalex major refactoring, bugfixes
authored
404 if (cfd)
405 close(fd);
406
407 tcsetattr(fd, TCSAFLUSH, &termios_old);
408 putchar('\n');
409
cfa6a39 @jmesmon Clean up termios when a SIGINT is recieved.
jmesmon authored
410 sigaction(SIGINT, &old_act, NULL);
411
dedd95c @bwalex major refactoring, bugfixes
authored
412 return r;
413 }
Something went wrong with that request. Please try again.