~siretart/cryptsetup/debian

« back to all changes in this revision

Viewing changes to lib/utils.c

  • Committer: Reinhard Tartler
  • Date: 2008-05-25 17:39:22 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: siretart@tauware.de-20080525173922-popbnh1gtbt3rxis
merge new upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
#include <unistd.h>
10
10
#include <sys/types.h>
11
11
#include <sys/stat.h>
 
12
#include <sys/ioctl.h>
12
13
#include <fcntl.h>
 
14
#include <termios.h>
13
15
 
14
16
#include "libcryptsetup.h"
15
17
#include "internal.h"
20
22
        char    data[1];
21
23
};
22
24
 
23
 
static char *error;
 
25
static char *error=NULL;
24
26
 
25
27
void set_error_va(const char *fmt, va_list va)
26
28
{
27
 
        int bufsize;
28
 
 
29
 
        bufsize = fmt ? (strlen(fmt) + 1) : 0;
30
 
        if (bufsize < 128)
31
 
                bufsize = 128;
32
 
 
33
 
        if (error)
34
 
                free(error);
35
 
        if (!fmt) {
36
 
                error = NULL;
37
 
                return;
38
 
        }
39
 
 
40
 
        error = malloc(bufsize);
41
 
 
42
 
        for(;;) {
43
 
                int n;
44
 
 
45
 
                n = vsnprintf(error, bufsize, fmt, va);
46
 
 
47
 
                if (n >= 0 && n < bufsize)
48
 
                        break;
49
 
 
50
 
                if (n >= 0)
51
 
                        bufsize = n + 1;
52
 
                else
53
 
                        bufsize *= 2;
54
 
 
55
 
                error = realloc(error, bufsize);
56
 
        }
 
29
 
 
30
        if(error) {
 
31
            free(error);
 
32
            error=NULL;
 
33
        }
 
34
 
 
35
        vasprintf(&error, fmt, va);
57
36
}
58
37
 
59
38
void set_error(const char *fmt, ...)
172
151
{
173
152
        char *padbuf; char *padbuf_base;
174
153
        char *buf = (char *)orig_buf;
175
 
        int r;
 
154
        int r = 0;
176
155
        int hangover; int solid; int bsize;
177
156
 
178
157
        if ((bsize = sector_size(fd)) < 0)
212
191
ssize_t read_blockwise(int fd, void *orig_buf, size_t count) {
213
192
        char *padbuf; char *padbuf_base;
214
193
        char *buf = (char *)orig_buf;
215
 
        int r;
 
194
        int r = 0;
216
195
        int step;
217
196
        int bsize;
218
197
 
225
204
        while(count) {
226
205
                r = read(fd,padbuf,bsize);
227
206
                if(r < 0 || r != bsize) {
228
 
                        fprintf(stderr, "read failed in read_blockwise.\n");
 
207
                        set_error("read failed in read_blockwise.\n");
229
208
                        goto out;
230
209
                }
231
210
                step = count<bsize?count:bsize;
274
253
 
275
254
        return write_blockwise(fd, buf, count);
276
255
}
 
256
 
 
257
/* Password reading helpers */
 
258
 
 
259
static int untimed_read(int fd, char *pass, size_t maxlen)
 
260
{
 
261
        ssize_t i;
 
262
 
 
263
        i = read(fd, pass, maxlen);
 
264
        if (i > 0) {
 
265
                pass[i-1] = '\0';
 
266
                i = 0;
 
267
        } else if (i == 0) { /* EOF */
 
268
                *pass = 0;
 
269
                i = -1;
 
270
        }
 
271
        return i;
 
272
}
 
273
 
 
274
static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
 
275
{
 
276
        struct timeval t;
 
277
        fd_set fds;
 
278
        int failed = -1;
 
279
 
 
280
        FD_ZERO(&fds);
 
281
        FD_SET(fd, &fds);
 
282
        t.tv_sec = timeout;
 
283
        t.tv_usec = 0;
 
284
 
 
285
        if (select(fd+1, &fds, NULL, NULL, &t) > 0)
 
286
                failed = untimed_read(fd, pass, maxlen);
 
287
        else
 
288
                set_error("Operation timed out");
 
289
        return failed;
 
290
}
 
291
 
 
292
static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
 
293
                long timeout)
 
294
{
 
295
        struct termios orig, tmp;
 
296
        int failed = -1;
 
297
        int infd = STDIN_FILENO, outfd;
 
298
 
 
299
        if (maxlen < 1)
 
300
                goto out_err;
 
301
 
 
302
        /* Read and write to /dev/tty if available */
 
303
        if ((infd = outfd = open("/dev/tty", O_RDWR)) == -1) {
 
304
                infd = STDIN_FILENO;
 
305
                outfd = STDERR_FILENO;
 
306
        }
 
307
 
 
308
        if (tcgetattr(infd, &orig)) {
 
309
                set_error("Unable to get terminal");
 
310
                goto out_err;
 
311
        }
 
312
        memcpy(&tmp, &orig, sizeof(tmp));
 
313
        tmp.c_lflag &= ~ECHO;
 
314
 
 
315
        write(outfd, prompt, strlen(prompt));
 
316
        tcsetattr(infd, TCSAFLUSH, &tmp);
 
317
        if (timeout)
 
318
                failed = timed_read(infd, pass, maxlen, timeout);
 
319
        else
 
320
                failed = untimed_read(infd, pass, maxlen);
 
321
        tcsetattr(infd, TCSAFLUSH, &orig);
 
322
 
 
323
out_err:
 
324
        if (!failed)
 
325
                write(outfd, "\n", 1);
 
326
        if (infd != STDIN_FILENO)
 
327
                close(infd);
 
328
        return failed;
 
329
}
 
330
 
 
331
/*
 
332
 * Password reading behaviour matrix of get_key
 
333
 * 
 
334
 *                    p   v   n   h
 
335
 * -----------------+---+---+---+---
 
336
 * interactive      | Y | Y | Y | Inf
 
337
 * from fd          | N | N | Y | Inf
 
338
 * from binary file | N | N | N | Inf or options->key_size
 
339
 *
 
340
 * Legend: p..prompt, v..can verify, n..newline-stop, h..read horizon
 
341
 *
 
342
 * Note: --key-file=- is interpreted as a read from a binary file (stdin)
 
343
 *
 
344
 * Returns true when more keys are available (that is when password
 
345
 * reading can be retried as for interactive terminals).
 
346
 */
 
347
 
 
348
int get_key(char *prompt, char **key, int *passLen, int key_size, const char *key_file, int passphrase_fd, int timeout, int how2verify)
 
349
{
 
350
        int fd;
 
351
        const int verify = how2verify & CRYPT_FLAG_VERIFY;
 
352
        const int verify_if_possible = how2verify & CRYPT_FLAG_VERIFY_IF_POSSIBLE;
 
353
        char *pass = NULL;
 
354
        int newline_stop;
 
355
        int read_horizon;
 
356
 
 
357
        if(key_file && !strcmp(key_file, "-")) {
 
358
                /* Allow binary reading from stdin */
 
359
                fd = passphrase_fd;
 
360
                newline_stop = 0;
 
361
                read_horizon = 0;
 
362
        } else if (key_file) {
 
363
                fd = open(key_file, O_RDONLY);
 
364
                if (fd < 0) {
 
365
                        char buf[128];
 
366
                        set_error("Error opening key file: %s",
 
367
                                  strerror_r(errno, buf, 128));
 
368
                        goto out_err;
 
369
                }
 
370
                newline_stop = 0;
 
371
 
 
372
                /* This can either be 0 (LUKS) or the actually number
 
373
                 * of key bytes (default or passed by -s) */
 
374
                read_horizon = key_size;
 
375
        } else {
 
376
                fd = passphrase_fd;
 
377
                newline_stop = 1;
 
378
                read_horizon = 0;   /* Infinite, if read from terminal or fd */
 
379
        }       
 
380
 
 
381
        /* Interactive case */
 
382
        if(isatty(fd)) {
 
383
                int i;
 
384
 
 
385
                pass = safe_alloc(512);
 
386
                if (!pass || (i = interactive_pass(prompt, pass, 512, timeout))) {
 
387
                        set_error("Error reading passphrase");
 
388
                        goto out_err;
 
389
                }
 
390
                if (verify || verify_if_possible) {
 
391
                        char pass_verify[512];
 
392
                        i = interactive_pass("Verify passphrase: ", pass_verify, sizeof(pass_verify), timeout);
 
393
                        if (i || strcmp(pass, pass_verify) != 0) {
 
394
                                set_error("Passphrases do not match");
 
395
                                goto out_err;
 
396
                        }
 
397
                        memset(pass_verify, 0, sizeof(pass_verify));
 
398
                }
 
399
                *passLen = strlen(pass);
 
400
                *key = pass;
 
401
        } else {
 
402
                /* 
 
403
                 * This is either a fd-input or a file, in neither case we can verify the input,
 
404
                 * however we don't stop on new lines if it's a binary file.
 
405
                 */
 
406
                int buflen, i;
 
407
 
 
408
                if(verify) {
 
409
                        set_error("Can't do passphrase verification on non-tty inputs");
 
410
                        goto out_err;
 
411
                }
 
412
                /* The following for control loop does an exhausting
 
413
                 * read on the key material file, if requested with
 
414
                 * key_size == 0, as it's done by LUKS. However, we
 
415
                 * should warn the user, if it's a non-regular file,
 
416
                 * such as /dev/random, because in this case, the loop
 
417
                 * will read forever.
 
418
                 */ 
 
419
                if(key_file && strcmp(key_file, "-") && read_horizon == 0) {
 
420
                        struct stat st;
 
421
                        if(stat(key_file, &st) < 0) {
 
422
                                set_error("Can't stat key file");
 
423
                                goto out_err;
 
424
                        }
 
425
                        if(!S_ISREG(st.st_mode)) {
 
426
                                //                              set_error("Can't do exhausting read on non regular files");
 
427
                                // goto out_err;
 
428
                                fprintf(stderr,"Warning: exhausting read requested, but key file is not a regular file, function might never return.\n");
 
429
                        }
 
430
                }
 
431
                buflen = 0;
 
432
                for(i = 0; read_horizon == 0 || i < read_horizon; i++) {
 
433
                        if(i >= buflen - 1) {
 
434
                                buflen += 128;
 
435
                                pass = safe_realloc(pass, buflen);
 
436
                                if (!pass) {
 
437
                                        set_error("Not enough memory while "
 
438
                                                  "reading passphrase");
 
439
                                        goto out_err;
 
440
                                }
 
441
                        }
 
442
                        if(read(fd, pass + i, 1) != 1 || (newline_stop && pass[i] == '\n'))
 
443
                                break;
 
444
                }
 
445
                if(key_file)
 
446
                        close(fd);
 
447
                pass[i] = 0;
 
448
                *key = pass;
 
449
                *passLen = i;
 
450
        }
 
451
 
 
452
        return isatty(fd); /* Return true, when password reading can be tried on interactive fds */
 
453
 
 
454
out_err:
 
455
        if(pass)
 
456
                safe_free(pass);
 
457
        *key = NULL;
 
458
        *passLen = 0;
 
459
        return 0;
 
460
}
 
461