]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup-generator.c
8ac5ab730afe081d7fc1218ed89a5ff92694352b
2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include "alloc-util.h"
26 #include "fstab-util.h"
27 #include "generator.h"
31 #include "parse-util.h"
32 #include "path-util.h"
33 #include "proc-cmdline.h"
34 #include "string-util.h"
36 #include "unit-name.h"
39 typedef struct crypto_device
{
47 static const char *arg_dest
= "/tmp";
48 static bool arg_enabled
= true;
49 static bool arg_read_crypttab
= true;
50 static bool arg_whitelist
= false;
51 static Hashmap
*arg_disks
= NULL
;
52 static char *arg_default_options
= NULL
;
53 static char *arg_default_keyfile
= NULL
;
55 static int create_disk(
59 const char *options
) {
61 _cleanup_free_
char *p
= NULL
, *n
= NULL
, *d
= NULL
, *u
= NULL
, *to
= NULL
, *e
= NULL
,
63 _cleanup_fclose_
FILE *f
= NULL
;
64 bool noauto
, nofail
, tmp
, swap
;
71 noauto
= fstab_test_yes_no_option(options
, "noauto\0" "auto\0");
72 nofail
= fstab_test_yes_no_option(options
, "nofail\0" "fail\0");
73 tmp
= fstab_test_option(options
, "tmp\0");
74 swap
= fstab_test_option(options
, "swap\0");
77 log_error("Device '%s' cannot be both 'tmp' and 'swap'. Ignoring.", name
);
81 e
= unit_name_escape(name
);
85 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
87 return log_error_errno(r
, "Failed to generate unit name: %m");
89 p
= strjoin(arg_dest
, "/", n
, NULL
);
93 u
= fstab_node_to_udev_node(device
);
97 r
= unit_name_from_path(u
, ".device", &d
);
99 return log_error_errno(r
, "Failed to generate unit name: %m");
103 return log_error_errno(errno
, "Failed to create unit file %s: %m", p
);
106 "# Automatically generated by systemd-cryptsetup-generator\n\n"
108 "Description=Cryptography Setup for %I\n"
109 "Documentation=man:crypttab(5) man:systemd-cryptsetup-generator(8) man:systemd-cryptsetup@.service(8)\n"
110 "SourcePath=/etc/crypttab\n"
111 "DefaultDependencies=no\n"
112 "Conflicts=umount.target\n"
113 "BindsTo=dev-mapper-%i.device\n"
114 "IgnoreOnIsolate=true\n"
115 "After=cryptsetup-pre.target\n",
120 "Before=cryptsetup.target\n");
123 if (STR_IN_SET(password
, "/dev/urandom", "/dev/random", "/dev/hw_random"))
124 fputs("After=systemd-random-seed.service\n", f
);
125 else if (!streq(password
, "-") && !streq(password
, "none")) {
126 _cleanup_free_
char *uu
;
128 uu
= fstab_node_to_udev_node(password
);
132 if (!path_equal(uu
, "/dev/null")) {
134 if (is_device_path(uu
)) {
135 _cleanup_free_
char *dd
= NULL
;
137 r
= unit_name_from_path(uu
, ".device", &dd
);
139 return log_error_errno(r
, "Failed to generate unit name: %m");
141 fprintf(f
, "After=%1$s\nRequires=%1$s\n", dd
);
143 fprintf(f
, "RequiresMountsFor=%s\n", password
);
148 if (is_device_path(u
))
152 "Before=umount.target\n",
156 "RequiresMountsFor=%s\n",
159 r
= generator_write_timeouts(arg_dest
, device
, name
, options
, &filtered
);
166 "RemainAfterExit=yes\n"
167 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
168 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH
" attach '%s' '%s' '%s' '%s'\n"
169 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH
" detach '%s'\n",
170 name
, u
, strempty(password
), strempty(filtered
),
175 "ExecStartPost=/sbin/mke2fs '/dev/mapper/%s'\n",
180 "ExecStartPost=/sbin/mkswap '/dev/mapper/%s'\n",
183 r
= fflush_and_check(f
);
185 return log_error_errno(r
, "Failed to write file %s: %m", p
);
187 from
= strjoina("../", n
);
191 to
= strjoin(arg_dest
, "/", d
, ".wants/", n
, NULL
);
195 mkdir_parents_label(to
, 0755);
196 if (symlink(from
, to
) < 0)
197 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
201 to
= strjoin(arg_dest
, "/cryptsetup.target.requires/", n
, NULL
);
203 to
= strjoin(arg_dest
, "/cryptsetup.target.wants/", n
, NULL
);
207 mkdir_parents_label(to
, 0755);
208 if (symlink(from
, to
) < 0)
209 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
213 to
= strjoin(arg_dest
, "/dev-mapper-", e
, ".device.requires/", n
, NULL
);
217 mkdir_parents_label(to
, 0755);
218 if (symlink(from
, to
) < 0)
219 return log_error_errno(errno
, "Failed to create symlink %s: %m", to
);
221 if (!noauto
&& !nofail
) {
222 _cleanup_free_
char *dmname
;
223 dmname
= strjoin("dev-mapper-", e
, ".device", NULL
);
227 r
= write_drop_in(arg_dest
, dmname
, 90, "device-timeout",
228 "# Automatically generated by systemd-cryptsetup-generator \n\n"
229 "[Unit]\nJobTimeoutSec=0");
231 return log_error_errno(r
, "Failed to write device drop-in: %m");
237 static void free_arg_disks(void) {
240 while ((d
= hashmap_steal_first(arg_disks
))) {
248 hashmap_free(arg_disks
);
251 static crypto_device
*get_crypto_device(const char *uuid
) {
257 d
= hashmap_get(arg_disks
, uuid
);
259 d
= new0(struct crypto_device
, 1);
264 d
->keyfile
= d
->options
= d
->name
= NULL
;
266 d
->uuid
= strdup(uuid
);
272 r
= hashmap_put(arg_disks
, d
->uuid
, d
);
283 static int parse_proc_cmdline_item(const char *key
, const char *value
) {
286 _cleanup_free_
char *uuid
= NULL
, *uuid_value
= NULL
;
288 if (STR_IN_SET(key
, "luks", "rd.luks") && value
) {
290 r
= parse_boolean(value
);
292 log_warning("Failed to parse luks switch %s. Ignoring.", value
);
296 } else if (STR_IN_SET(key
, "luks.crypttab", "rd.luks.crypttab") && value
) {
298 r
= parse_boolean(value
);
300 log_warning("Failed to parse luks crypttab switch %s. Ignoring.", value
);
302 arg_read_crypttab
= r
;
304 } else if (STR_IN_SET(key
, "luks.uuid", "rd.luks.uuid") && value
) {
306 d
= get_crypto_device(startswith(value
, "luks-") ? value
+5 : value
);
310 d
->create
= arg_whitelist
= true;
312 } else if (STR_IN_SET(key
, "luks.options", "rd.luks.options") && value
) {
314 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
316 d
= get_crypto_device(uuid
);
321 d
->options
= uuid_value
;
323 } else if (free_and_strdup(&arg_default_options
, value
) < 0)
326 } else if (STR_IN_SET(key
, "luks.key", "rd.luks.key") && value
) {
328 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
330 d
= get_crypto_device(uuid
);
335 d
->keyfile
= uuid_value
;
337 } else if (free_and_strdup(&arg_default_keyfile
, value
) < 0)
340 } else if (STR_IN_SET(key
, "luks.name", "rd.luks.name") && value
) {
342 r
= sscanf(value
, "%m[0-9a-fA-F-]=%ms", &uuid
, &uuid_value
);
344 d
= get_crypto_device(uuid
);
348 d
->create
= arg_whitelist
= true;
351 d
->name
= uuid_value
;
354 log_warning("Failed to parse luks name switch %s. Ignoring.", value
);
361 static int add_crypttab_devices(void) {
363 unsigned crypttab_line
= 0;
364 _cleanup_fclose_
FILE *f
= NULL
;
366 if (!arg_read_crypttab
)
369 f
= fopen("/etc/crypttab", "re");
372 log_error_errno(errno
, "Failed to open /etc/crypttab: %m");
376 if (fstat(fileno(f
), &st
) < 0) {
377 log_error_errno(errno
, "Failed to stat /etc/crypttab: %m");
383 char line
[LINE_MAX
], *l
, *uuid
;
384 crypto_device
*d
= NULL
;
385 _cleanup_free_
char *name
= NULL
, *device
= NULL
, *keyfile
= NULL
, *options
= NULL
;
387 if (!fgets(line
, sizeof(line
), f
))
393 if (*l
== '#' || *l
== 0)
396 k
= sscanf(l
, "%ms %ms %ms %ms", &name
, &device
, &keyfile
, &options
);
397 if (k
< 2 || k
> 4) {
398 log_error("Failed to parse /etc/crypttab:%u, ignoring.", crypttab_line
);
402 uuid
= startswith(device
, "UUID=");
404 uuid
= path_startswith(device
, "/dev/disk/by-uuid/");
406 uuid
= startswith(name
, "luks-");
408 d
= hashmap_get(arg_disks
, uuid
);
410 if (arg_whitelist
&& !d
) {
411 log_info("Not creating device '%s' because it was not specified on the kernel command line.", name
);
415 r
= create_disk(name
, device
, keyfile
, (d
&& d
->options
) ? d
->options
: options
);
426 static int add_proc_cmdline_devices(void) {
431 HASHMAP_FOREACH(d
, arg_disks
, i
) {
433 _cleanup_free_
char *device
= NULL
;
439 d
->name
= strappend("luks-", d
->uuid
);
444 device
= strappend("UUID=", d
->uuid
);
449 options
= d
->options
;
450 else if (arg_default_options
)
451 options
= arg_default_options
;
453 options
= "timeout=0";
455 r
= create_disk(d
->name
, device
, d
->keyfile
?: arg_default_keyfile
, options
);
463 int main(int argc
, char *argv
[]) {
464 int r
= EXIT_FAILURE
;
466 if (argc
> 1 && argc
!= 4) {
467 log_error("This program takes three or no arguments.");
474 log_set_target(LOG_TARGET_SAFE
);
475 log_parse_environment();
480 arg_disks
= hashmap_new(&string_hash_ops
);
484 r
= parse_proc_cmdline(parse_proc_cmdline_item
);
486 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
495 if (add_crypttab_devices() < 0)
498 if (add_proc_cmdline_devices() < 0)
505 free(arg_default_options
);
506 free(arg_default_keyfile
);