~ubuntu-branches/debian/jessie/systemd/jessie

« back to all changes in this revision

Viewing changes to src/cryptsetup.c

  • Committer: Package Import Robot
  • Author(s): Tollef Fog Heen, Tollef Fog Heen, Michael Biebl
  • Date: 2012-04-03 19:59:17 UTC
  • mfrom: (1.1.10) (6.1.3 experimental)
  • Revision ID: package-import@ubuntu.com-20120403195917-l532urrbg4pkreas
Tags: 44-1
[ Tollef Fog Heen ]
* New upstream version.
  - Backport 3492207: journal: PAGE_SIZE is not known on ppc and other
    archs
  - Backport 5a2a2a1: journal: react with immediate rotation to a couple
    of more errors
  - Backport 693ce21: util: never follow symlinks in rm_rf_children()
    Fixes CVE-2012-1174, closes: #664364
* Drop output message from init-functions hook, it's pointless.
* Only rmdir /lib/init/rw if it exists.
* Explicitly order debian-fixup before sysinit.target to prevent a
  possible race condition with the creation of sockets.  Thanks to
  Michael Biebl for debugging this.
* Always restart the initctl socket on upgrades, to mask sysvinit
  removing it.

[ Michael Biebl ]
* Remove workaround for non-interactive sessions from pam config again.
* Create compat /dev/initctl symlink in case we are upgrading from a system
  running a newer version of sysvinit (using /run/initctl) and sysvinit is
  replaced with systemd-sysv during the upgrade. Closes: #663219
* Install new man pages.
* Build-Depend on valac (>= 0.12) instead of valac-0.12. Closes: #663323

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
 
 
3
 
/***
4
 
  This file is part of systemd.
5
 
 
6
 
  Copyright 2010 Lennart Poettering
7
 
 
8
 
  systemd is free software; you can redistribute it and/or modify it
9
 
  under the terms of the GNU General Public License as published by
10
 
  the Free Software Foundation; either version 2 of the License, or
11
 
  (at your option) any later version.
12
 
 
13
 
  systemd is distributed in the hope that it will be useful, but
14
 
  WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
 
  General Public License for more details.
17
 
 
18
 
  You should have received a copy of the GNU General Public License
19
 
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
20
 
***/
21
 
 
22
 
#include <string.h>
23
 
#include <errno.h>
24
 
#include <sys/mman.h>
25
 
#include <mntent.h>
26
 
 
27
 
#include <libcryptsetup.h>
28
 
#include <libudev.h>
29
 
 
30
 
#include "log.h"
31
 
#include "util.h"
32
 
#include "strv.h"
33
 
#include "ask-password-api.h"
34
 
#include "def.h"
35
 
 
36
 
static const char *opt_type = NULL; /* LUKS1 or PLAIN */
37
 
static char *opt_cipher = NULL;
38
 
static unsigned opt_key_size = 0;
39
 
static char *opt_hash = NULL;
40
 
static unsigned opt_tries = 0;
41
 
static bool opt_readonly = false;
42
 
static bool opt_verify = false;
43
 
static usec_t opt_timeout = DEFAULT_TIMEOUT_USEC;
44
 
 
45
 
/* Options Debian's crypttab knows we don't:
46
 
 
47
 
    offset=
48
 
    skip=
49
 
    precheck=
50
 
    check=
51
 
    checkargs=
52
 
    noearly=
53
 
    loud=
54
 
    keyscript=
55
 
*/
56
 
 
57
 
static int parse_one_option(const char *option) {
58
 
        assert(option);
59
 
 
60
 
        /* Handled outside of this tool */
61
 
        if (streq(option, "noauto"))
62
 
                return 0;
63
 
 
64
 
        if (startswith(option, "cipher=")) {
65
 
                char *t;
66
 
 
67
 
                if (!(t = strdup(option+7)))
68
 
                        return -ENOMEM;
69
 
 
70
 
                free(opt_cipher);
71
 
                opt_cipher = t;
72
 
 
73
 
        } else if (startswith(option, "size=")) {
74
 
 
75
 
                if (safe_atou(option+5, &opt_key_size) < 0) {
76
 
                        log_error("size= parse failure, ignoring.");
77
 
                        return 0;
78
 
                }
79
 
 
80
 
        } else if (startswith(option, "hash=")) {
81
 
                char *t;
82
 
 
83
 
                if (!(t = strdup(option+5)))
84
 
                        return -ENOMEM;
85
 
 
86
 
                free(opt_hash);
87
 
                opt_hash = t;
88
 
 
89
 
        } else if (startswith(option, "tries=")) {
90
 
 
91
 
                if (safe_atou(option+6, &opt_tries) < 0) {
92
 
                        log_error("tries= parse failure, ignoring.");
93
 
                        return 0;
94
 
                }
95
 
 
96
 
        } else if (streq(option, "readonly"))
97
 
                opt_readonly = true;
98
 
        else if (streq(option, "verify"))
99
 
                opt_verify = true;
100
 
        else if (streq(option, "luks"))
101
 
                opt_type = CRYPT_LUKS1;
102
 
        else if (streq(option, "plain") ||
103
 
                 streq(option, "swap") ||
104
 
                 streq(option, "tmp"))
105
 
                opt_type = CRYPT_PLAIN;
106
 
        else if (startswith(option, "timeout=")) {
107
 
 
108
 
                if (parse_usec(option+8, &opt_timeout) < 0) {
109
 
                        log_error("timeout= parse failure, ignoring.");
110
 
                        return 0;
111
 
                }
112
 
 
113
 
        } else if (!streq(option, "none"))
114
 
                log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
115
 
 
116
 
        return 0;
117
 
}
118
 
 
119
 
static int parse_options(const char *options) {
120
 
        char *state;
121
 
        char *w;
122
 
        size_t l;
123
 
 
124
 
        assert(options);
125
 
 
126
 
        FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
127
 
                char *o;
128
 
                int r;
129
 
 
130
 
                if (!(o = strndup(w, l)))
131
 
                        return -ENOMEM;
132
 
 
133
 
                r = parse_one_option(o);
134
 
                free(o);
135
 
 
136
 
                if (r < 0)
137
 
                        return r;
138
 
        }
139
 
 
140
 
        return 0;
141
 
}
142
 
 
143
 
static void log_glue(int level, const char *msg, void *usrptr) {
144
 
        log_debug("%s", msg);
145
 
}
146
 
 
147
 
static char *disk_description(const char *path) {
148
 
        struct udev *udev = NULL;
149
 
        struct udev_device *device = NULL;
150
 
        struct stat st;
151
 
        char *description = NULL;
152
 
        const char *model;
153
 
 
154
 
        assert(path);
155
 
 
156
 
        if (stat(path, &st) < 0)
157
 
                return NULL;
158
 
 
159
 
        if (!S_ISBLK(st.st_mode))
160
 
                return NULL;
161
 
 
162
 
        if (!(udev = udev_new()))
163
 
                return NULL;
164
 
 
165
 
        if (!(device = udev_device_new_from_devnum(udev, 'b', st.st_rdev)))
166
 
                goto finish;
167
 
 
168
 
        if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
169
 
            (model = udev_device_get_property_value(device, "ID_MODEL")) ||
170
 
            (model = udev_device_get_property_value(device, "DM_NAME")))
171
 
                description = strdup(model);
172
 
 
173
 
finish:
174
 
        if (device)
175
 
                udev_device_unref(device);
176
 
 
177
 
        if (udev)
178
 
                udev_unref(udev);
179
 
 
180
 
        return description;
181
 
}
182
 
 
183
 
static char *disk_mount_point(const char *label) {
184
 
        char *mp = NULL, *device = NULL;
185
 
        FILE *f = NULL;
186
 
        struct mntent *m;
187
 
 
188
 
        /* Yeah, we don't support native systemd unit files here for now */
189
 
 
190
 
        if (asprintf(&device, "/dev/mapper/%s", label) < 0)
191
 
                goto finish;
192
 
 
193
 
        if (!(f = setmntent("/etc/fstab", "r")))
194
 
                goto finish;
195
 
 
196
 
        while ((m = getmntent(f)))
197
 
                if (path_equal(m->mnt_fsname, device)) {
198
 
                        mp = strdup(m->mnt_dir);
199
 
                        break;
200
 
                }
201
 
 
202
 
finish:
203
 
        if (f)
204
 
                endmntent(f);
205
 
 
206
 
        free(device);
207
 
 
208
 
        return mp;
209
 
}
210
 
 
211
 
static int help(void) {
212
 
 
213
 
        printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
214
 
               "%s detach VOLUME\n\n"
215
 
               "Attaches or detaches an encrypted block device.\n",
216
 
               program_invocation_short_name,
217
 
               program_invocation_short_name);
218
 
 
219
 
        return 0;
220
 
}
221
 
 
222
 
int main(int argc, char *argv[]) {
223
 
        int r = EXIT_FAILURE;
224
 
        struct crypt_device *cd = NULL;
225
 
        char **passwords = NULL, *truncated_cipher = NULL;
226
 
        const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
227
 
        char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
228
 
        unsigned keyfile_size = 0;
229
 
 
230
 
        if (argc <= 1) {
231
 
                help();
232
 
                return EXIT_SUCCESS;
233
 
        }
234
 
 
235
 
        if (argc < 3) {
236
 
                log_error("This program requires at least two arguments.");
237
 
                return EXIT_FAILURE;
238
 
        }
239
 
 
240
 
        log_set_target(LOG_TARGET_AUTO);
241
 
        log_parse_environment();
242
 
        log_open();
243
 
 
244
 
        umask(0022);
245
 
 
246
 
        if (streq(argv[1], "attach")) {
247
 
                uint32_t flags = 0;
248
 
                int k;
249
 
                unsigned try;
250
 
                const char *key_file = NULL;
251
 
                usec_t until;
252
 
                crypt_status_info status;
253
 
 
254
 
                /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
255
 
 
256
 
                if (argc < 4) {
257
 
                        log_error("attach requires at least two arguments.");
258
 
                        goto finish;
259
 
                }
260
 
 
261
 
                if (argc >= 5 &&
262
 
                    argv[4][0] &&
263
 
                    !streq(argv[4], "-") &&
264
 
                    !streq(argv[4], "none")) {
265
 
 
266
 
                        if (!path_is_absolute(argv[4]))
267
 
                                log_error("Password file path %s is not absolute. Ignoring.", argv[4]);
268
 
                        else
269
 
                                key_file = argv[4];
270
 
                }
271
 
 
272
 
                if (argc >= 6 && argv[5][0] && !streq(argv[5], "-"))
273
 
                        parse_options(argv[5]);
274
 
 
275
 
                /* A delicious drop of snake oil */
276
 
                mlockall(MCL_FUTURE);
277
 
 
278
 
                description = disk_description(argv[3]);
279
 
                mount_point = disk_mount_point(argv[2]);
280
 
 
281
 
                if (description && streq(argv[2], description)) {
282
 
                        /* If the description string is simply the
283
 
                         * volume name, then let's not show this
284
 
                         * twice */
285
 
                        free(description);
286
 
                        description = NULL;
287
 
                }
288
 
 
289
 
                if (mount_point && description)
290
 
                        asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
291
 
                else if (mount_point)
292
 
                        asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
293
 
                else if (description)
294
 
                        asprintf(&name_buffer, "%s (%s)", description, argv[2]);
295
 
 
296
 
                name = name_buffer ? name_buffer : argv[2];
297
 
 
298
 
                if ((k = crypt_init(&cd, argv[3]))) {
299
 
                        log_error("crypt_init() failed: %s", strerror(-k));
300
 
                        goto finish;
301
 
                }
302
 
 
303
 
                crypt_set_log_callback(cd, log_glue, NULL);
304
 
 
305
 
                status = crypt_status(cd, argv[2]);
306
 
                if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
307
 
                        log_info("Volume %s already active.", argv[2]);
308
 
                        r = EXIT_SUCCESS;
309
 
                        goto finish;
310
 
                }
311
 
 
312
 
                if (opt_readonly)
313
 
                        flags |= CRYPT_ACTIVATE_READONLY;
314
 
 
315
 
                if (opt_timeout > 0)
316
 
                        until = now(CLOCK_MONOTONIC) + opt_timeout;
317
 
                else
318
 
                        until = 0;
319
 
 
320
 
                opt_tries = opt_tries > 0 ? opt_tries : 3;
321
 
                opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
322
 
                hash = opt_hash ? opt_hash : "ripemd160";
323
 
 
324
 
                if (opt_cipher) {
325
 
                        size_t l;
326
 
 
327
 
                        l = strcspn(opt_cipher, "-");
328
 
 
329
 
                        if (!(truncated_cipher = strndup(opt_cipher, l))) {
330
 
                                log_error("Out of memory");
331
 
                                goto finish;
332
 
                        }
333
 
 
334
 
                        cipher = truncated_cipher;
335
 
                        cipher_mode = opt_cipher[l] ? opt_cipher+l+1 : "plain";
336
 
                } else {
337
 
                        cipher = "aes";
338
 
                        cipher_mode = "cbc-essiv:sha256";
339
 
                }
340
 
 
341
 
                for (try = 0; try < opt_tries; try++) {
342
 
                        bool pass_volume_key = false;
343
 
 
344
 
                        strv_free(passwords);
345
 
                        passwords = NULL;
346
 
 
347
 
                        if (!key_file) {
348
 
                                char *text;
349
 
                                char **p;
350
 
 
351
 
                                if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
352
 
                                        log_error("Out of memory");
353
 
                                        goto finish;
354
 
                                }
355
 
 
356
 
                                k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
357
 
                                free(text);
358
 
 
359
 
                                if (k < 0) {
360
 
                                        log_error("Failed to query password: %s", strerror(-k));
361
 
                                        goto finish;
362
 
                                }
363
 
 
364
 
                                if (opt_verify) {
365
 
                                        char **passwords2 = NULL;
366
 
 
367
 
                                        assert(strv_length(passwords) == 1);
368
 
 
369
 
                                        if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
370
 
                                                log_error("Out of memory");
371
 
                                                goto finish;
372
 
                                        }
373
 
 
374
 
                                        k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
375
 
                                        free(text);
376
 
 
377
 
                                        if (k < 0) {
378
 
                                                log_error("Failed to query verification password: %s", strerror(-k));
379
 
                                                goto finish;
380
 
                                        }
381
 
 
382
 
                                        assert(strv_length(passwords2) == 1);
383
 
 
384
 
                                        if (!streq(passwords[0], passwords2[0])) {
385
 
                                                log_warning("Passwords did not match, retrying.");
386
 
                                                strv_free(passwords2);
387
 
                                                continue;
388
 
                                        }
389
 
 
390
 
                                        strv_free(passwords2);
391
 
                                }
392
 
 
393
 
                                strv_uniq(passwords);
394
 
 
395
 
                                STRV_FOREACH(p, passwords) {
396
 
                                        char *c;
397
 
 
398
 
                                        if (strlen(*p)+1 >= opt_key_size)
399
 
                                                continue;
400
 
 
401
 
                                        /* Pad password if necessary */
402
 
                                        if (!(c = new(char, opt_key_size))) {
403
 
                                                log_error("Out of memory.");
404
 
                                                goto finish;
405
 
                                        }
406
 
 
407
 
                                        strncpy(c, *p, opt_key_size);
408
 
                                        free(*p);
409
 
                                        *p = c;
410
 
                                }
411
 
                        }
412
 
 
413
 
                        k = 0;
414
 
 
415
 
                        if (!opt_type || streq(opt_type, CRYPT_LUKS1))
416
 
                                k = crypt_load(cd, CRYPT_LUKS1, NULL);
417
 
 
418
 
                        if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
419
 
                                struct crypt_params_plain params;
420
 
 
421
 
                                zero(params);
422
 
                                params.hash = hash;
423
 
 
424
 
                                /* In contrast to what the name
425
 
                                 * crypt_setup() might suggest this
426
 
                                 * doesn't actually format anything,
427
 
                                 * it just configures encryption
428
 
                                 * parameters when used for plain
429
 
                                 * mode. */
430
 
                                k = crypt_format(cd, CRYPT_PLAIN,
431
 
                                                 cipher,
432
 
                                                 cipher_mode,
433
 
                                                 NULL,
434
 
                                                 NULL,
435
 
                                                 opt_key_size / 8,
436
 
                                                 &params);
437
 
 
438
 
                                pass_volume_key = streq(hash, "plain");
439
 
 
440
 
                               /* for CRYPT_PLAIN limit reads
441
 
                                * from keyfile to key length */
442
 
                                keyfile_size = opt_key_size / 8;
443
 
                        }
444
 
 
445
 
                        if (k < 0) {
446
 
                                log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
447
 
                                goto finish;
448
 
                        }
449
 
 
450
 
                        log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
451
 
                                 crypt_get_cipher(cd),
452
 
                                 crypt_get_cipher_mode(cd),
453
 
                                 crypt_get_volume_key_size(cd)*8,
454
 
                                 argv[3]);
455
 
 
456
 
                        if (key_file)
457
 
                                k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, keyfile_size, flags);
458
 
                        else {
459
 
                                char **p;
460
 
 
461
 
                                STRV_FOREACH(p, passwords) {
462
 
 
463
 
                                        if (pass_volume_key)
464
 
                                                k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
465
 
                                        else
466
 
                                                k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
467
 
 
468
 
                                        if (k >= 0)
469
 
                                                break;
470
 
                                }
471
 
                        }
472
 
 
473
 
                        if (k >= 0)
474
 
                                break;
475
 
 
476
 
                        if (k != -EPERM) {
477
 
                                log_error("Failed to activate: %s", strerror(-k));
478
 
                                goto finish;
479
 
                        }
480
 
 
481
 
                        log_warning("Invalid passphrase.");
482
 
                }
483
 
 
484
 
                if (try >= opt_tries) {
485
 
                        log_error("Too many attempts.");
486
 
                        r = EXIT_FAILURE;
487
 
                        goto finish;
488
 
                }
489
 
 
490
 
        } else if (streq(argv[1], "detach")) {
491
 
                int k;
492
 
 
493
 
                if ((k = crypt_init_by_name(&cd, argv[2]))) {
494
 
                        log_error("crypt_init() failed: %s", strerror(-k));
495
 
                        goto finish;
496
 
                }
497
 
 
498
 
                crypt_set_log_callback(cd, log_glue, NULL);
499
 
 
500
 
                if ((k = crypt_deactivate(cd, argv[2])) < 0) {
501
 
                        log_error("Failed to deactivate: %s", strerror(-k));
502
 
                        goto finish;
503
 
                }
504
 
 
505
 
        } else {
506
 
                log_error("Unknown verb %s.", argv[1]);
507
 
                goto finish;
508
 
        }
509
 
 
510
 
        r = EXIT_SUCCESS;
511
 
 
512
 
finish:
513
 
 
514
 
        if (cd)
515
 
                crypt_free(cd);
516
 
 
517
 
        free(opt_cipher);
518
 
        free(opt_hash);
519
 
 
520
 
        free(truncated_cipher);
521
 
 
522
 
        strv_free(passwords);
523
 
 
524
 
        free(description);
525
 
        free(mount_point);
526
 
        free(name_buffer);
527
 
 
528
 
        return r;
529
 
}