From e23a0ce8badd09aefa961a3a576bfe85f6ebbad7 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 7 Nov 2010 23:02:45 -0500 Subject: [PATCH] cryptsetup: minimal cryptsetup unit generator --- .gitignore | 2 + Makefile.am | 24 +++- src/cryptsetup-generator.c | 239 +++++++++++++++++++++++++++++++++++++ src/cryptsetup.c | 53 ++++++++ src/mount.c | 50 -------- src/util.c | 51 ++++++++ src/util.h | 4 +- 7 files changed, 371 insertions(+), 52 deletions(-) create mode 100644 src/cryptsetup-generator.c create mode 100644 src/cryptsetup.c diff --git a/.gitignore b/.gitignore index 2a30fab7..42237888 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +systemd-cryptsetup +systemd-cryptsetup-generator systemd-tty-ask-password-agent systemd-fsck systemd-quotacheck diff --git a/Makefile.am b/Makefile.am index 456553fa..3371c597 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,7 @@ AM_CPPFLAGS = \ -DRUNTIME_DIR=\"$(localstatedir)/run\" \ -DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \ -DKEXEC_BINARY_PATH=\"/sbin/kexec\" \ + -DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \ -I $(top_srcdir)/src if TARGET_GENTOO @@ -112,7 +113,9 @@ rootlibexec_PROGRAMS = \ systemd-tmpfiles \ systemd-user-sessions \ systemd-fsck \ - systemd-quotacheck + systemd-quotacheck \ + systemd-cryptsetup \ + systemd-cryptsetup-generator noinst_PROGRAMS = \ test-engine \ @@ -711,6 +714,25 @@ systemd_quotacheck_CFLAGS = \ systemd_quotacheck_LDADD = \ libsystemd-basic.la +systemd_cryptsetup_SOURCES = \ + src/cryptsetup.c + +systemd_cryptsetup_CFLAGS = \ + $(AM_CFLAGS) + +systemd_cryptsetup_LDADD = \ + libsystemd-basic.la + +systemd_cryptsetup_generator_SOURCES = \ + src/cryptsetup-generator.c \ + src/unit-name.c + +systemd_cryptsetup_generator_CFLAGS = \ + $(AM_CFLAGS) + +systemd_cryptsetup_generator_LDADD = \ + libsystemd-basic.la + systemd_user_sessions_SOURCES = \ src/user-sessions.c \ src/cgroup-util.c diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c new file mode 100644 index 00000000..792c1f52 --- /dev/null +++ b/src/cryptsetup-generator.c @@ -0,0 +1,239 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "log.h" +#include "util.h" +#include "unit-name.h" + +const char *arg_dest = "/tmp"; + +static bool has_option(const char *haystack, const char *needle) { + const char *f = haystack; + size_t l; + + l = strlen(needle); + + while ((f = strstr(f, needle))) { + + if (f > haystack && f[-1] != ',') { + f++; + continue; + } + + if (f[l] != 0 && f[l] == ',') { + f++; + continue; + } + + return true; + } + + return false; +} + +static int create_disk( + const char *name, + const char *device, + const char *password, + const char *options) { + + char *p = NULL, *n = NULL, *d = NULL, *u = NULL, *from = NULL, *to = NULL; + int r; + FILE *f = NULL; + + assert(name); + assert(device); + + if (!(n = unit_name_build_escape("cryptsetup", name, ".service"))) { + r = -ENOMEM; + log_error("Failed to allocate unit name."); + goto fail; + } + + if (asprintf(&p, "%s/%s", arg_dest, n) < 0) { + r = -ENOMEM; + log_error("Failed to allocate unit file name."); + goto fail; + } + + if (!(u = fstab_node_to_udev_node(device))) { + r = -ENOMEM; + log_error("Failed to allocate device node."); + goto fail; + } + + if (!(d = unit_name_from_path(u, ".device"))) { + r = -ENOMEM; + log_error("Failed to allocate device name."); + goto fail; + } + + if (!(f = fopen(p, "wxe"))) { + r = -errno; + log_error("Failed to create unit file: %m"); + goto fail; + } + + fprintf(f, + "[Unit]\n" + "Description=Cryptography Setup for %%f\n" + "DefaultDependencies=no\n" + "BindTo=%s\n" + "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n" + "Before=dev-mapper-%%f.device shutdown.target\n", + d, d); + + if (password && (streq(password, "/dev/urandom") || + streq(password, "/dev/random") || + streq(password, "/dev/hw_random"))) + fprintf(f, + "After=systemd-random-seed-load.service\n"); + + fprintf(f, + "\n[Service]\n" + "Type=oneshot\n" + "RemainAfterExit=yes\n" + "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " %s '%s' '%s' '%s' '%s'\n" + "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " remove '%s'\n", + options && has_option(options, "swap") ? "format" : "create", + name, u, strempty(password), strempty(options), + name); + + if (options && has_option(options, "tmp")) + fprintf(f, + "ExecStartPost=/sbin/mke2fs '%s'", + u); + + if (options && has_option(options, "swap")) + fprintf(f, + "ExecStartPost=/sbin/mkswap '%s'", + u); + + fflush(f); + + if (ferror(f)) { + r = -errno; + log_error("Failed to write file: %m"); + goto fail; + } + + if (!options || !has_option(options, "noauto")) { + + if (asprintf(&to, "%s/%s.wants/%s", arg_dest, d, n) < 0) { + r = -ENOMEM; + goto fail; + } + + if (asprintf(&from, "../%s", n) < 0) { + r = -ENOMEM; + goto fail; + } + + mkdir_parents(to, 0755); + + if (symlink(from, to) < 0) { + log_error("Failed to create symlink '%s' to '%s': %m", from, to); + r = -errno; + goto fail; + } + } + + r = 0; + +fail: + free(p); + free(n); + free(d); + + free(from); + free(to); + + if (f) + fclose(f); + + return r; +} + +int main(int argc, char *argv[]) { + FILE *f; + int r = EXIT_SUCCESS; + unsigned n = 0; + + if (argc > 2) { + log_error("This program takes one or no arguments."); + return EXIT_FAILURE; + } + + arg_dest = argv[1]; + + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_parse_environment(); + log_open(); + + if (!(f = fopen("/etc/crypttab", "re"))) { + + if (errno == ENOENT) + r = EXIT_SUCCESS; + else { + r = EXIT_FAILURE; + log_error("Failed to open /etc/crypttab: %m"); + } + + goto finish; + } + + for (;;) { + char line[LINE_MAX], *l; + char *name = NULL, *device = NULL, *password = NULL, *options = NULL; + int k; + + if (!(fgets(line, sizeof(line), f))) + break; + + n++; + + l = strstrip(line); + if (*l == '#' || *l == 0) + continue; + + if ((k = sscanf(l, "%ms %ms %ms %ms", &name, &device, &password, &options)) < 2 || k > 4) { + log_error("Failed to parse /etc/crypttab:%u, ignoring.", n); + r = EXIT_FAILURE; + goto next; + } + + if (create_disk(name, device, password, options) < 0) + r = EXIT_FAILURE; + + next: + free(name); + free(device); + free(password); + free(options); + } + +finish: + return r; +} diff --git a/src/cryptsetup.c b/src/cryptsetup.c new file mode 100644 index 00000000..22312477 --- /dev/null +++ b/src/cryptsetup.c @@ -0,0 +1,53 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with systemd; If not, see . +***/ + +#include + +#include "log.h" +#include "util.h" + +int main(int argc, char *argv[]) { + int r = EXIT_SUCCESS; + + if (argc < 3) { + log_error("This program requires at least two arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_parse_environment(); + log_open(); + + if (streq(argv[1], "create")) { + + } else if (streq(argv[1], "format")) { + + + } else if (streq(argv[1], "remove")) { + + } else { + log_error("Unknown verb %s.", argv[1]); + goto finish; + } + +finish: + return r; +} diff --git a/src/mount.c b/src/mount.c index 781c7a87..5d4944ab 100644 --- a/src/mount.c +++ b/src/mount.c @@ -1297,56 +1297,6 @@ fail: return r; } -static char *fstab_node_to_udev_node(char *p) { - char *dn, *t, *u; - int r; - - /* FIXME: to follow udev's logic 100% we need to leave valid - * UTF8 chars unescaped */ - - if (startswith(p, "LABEL=")) { - - if (!(u = unquote(p+6, "\"\'"))) - return NULL; - - t = xescape(u, "/ "); - free(u); - - if (!t) - return NULL; - - r = asprintf(&dn, "/dev/disk/by-label/%s", t); - free(t); - - if (r < 0) - return NULL; - - return dn; - } - - if (startswith(p, "UUID=")) { - - if (!(u = unquote(p+5, "\"\'"))) - return NULL; - - t = xescape(u, "/ "); - free(u); - - if (!t) - return NULL; - - r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t)); - free(t); - - if (r < 0) - return NULL; - - return dn; - } - - return strdup(p); -} - static int mount_find_pri(char *options) { char *end, *pri; unsigned long r; diff --git a/src/util.c b/src/util.c index fecdee12..6f9399b4 100644 --- a/src/util.c +++ b/src/util.c @@ -3566,6 +3566,57 @@ void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { } } + +char *fstab_node_to_udev_node(const char *p) { + char *dn, *t, *u; + int r; + + /* FIXME: to follow udev's logic 100% we need to leave valid + * UTF8 chars unescaped */ + + if (startswith(p, "LABEL=")) { + + if (!(u = unquote(p+6, "\"\'"))) + return NULL; + + t = xescape(u, "/ "); + free(u); + + if (!t) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-label/%s", t); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + if (startswith(p, "UUID=")) { + + if (!(u = unquote(p+5, "\"\'"))) + return NULL; + + t = xescape(u, "/ "); + free(u); + + if (!t) + return NULL; + + r = asprintf(&dn, "/dev/disk/by-uuid/%s", ascii_strlower(t)); + free(t); + + if (r < 0) + return NULL; + + return dn; + } + + return strdup(p); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index b469009b..b7ef51e2 100644 --- a/src/util.h +++ b/src/util.h @@ -370,7 +370,9 @@ int ask_password_tty(const char *message, usec_t until, const char *flag_file, c void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); void dual_timestamp_deserialize(const char *value, dual_timestamp *t); -#define NULSTR_FOREACH(i, l) \ +char *fstab_node_to_udev_node(const char *p); + +#define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) #define NULSTR_FOREACH_PAIR(i, j, l) \ -- 2.39.5