aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile2
-rw-r--r--README.md27
-rw-r--r--bin/Makefile10
-rw-r--r--bin/ykfde-cpio.c220
-rw-r--r--bin/ykfde.c3
-rw-r--r--mkinitcpio/ykfde-cpio15
-rw-r--r--systemd/ykfde.service11
8 files changed, 276 insertions, 13 deletions
diff --git a/.gitignore b/.gitignore
index 4da39b0..4809ce2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
README.html
bin/ykfde
+bin/ykfde-cpio
udev/ykfde
diff --git a/Makefile b/Makefile
index 7ae3bce..3fe4aeb 100644
--- a/Makefile
+++ b/Makefile
@@ -23,8 +23,8 @@ install-bin: bin/ykfde udev/ykfde
$(MAKE) -C bin install
$(MAKE) -C udev install
$(INSTALL) -D -m0644 conf/ykfde.conf $(DESTDIR)/etc/ykfde.conf
- $(INSTALL) -D -m0755 bin/ykfde $(DESTDIR)/usr/bin/ykfde
$(INSTALL) -D -m0644 mkinitcpio/ykfde $(DESTDIR)/usr/lib/initcpio/install/ykfde
+ $(INSTALL) -D -m0644 systemd/ykfde.service $(DESTDIR)/usr/lib/systemd/system/ykfde.service
$(INSTALL) -d -m0700 $(DESTDIR)/etc/ykfde.d/
install-doc: README.md README.html
diff --git a/README.md b/README.md
index 6f47e94..2380003 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@ To compile and use yubico full disk encryption you need:
* [mkinitcpio](https://projects.archlinux.org/mkinitcpio.git/) (Though
it may be easy to port this to any initramfs that uses systemd)
* [markdown](http://daringfireball.net/projects/markdown/) (HTML documentation)
+* [libarchive](http://www.libarchive.org/) (Update challenge on boot)
Additionally it is expected to have `make` and `pkg-config` around to
successfully compile.
@@ -64,24 +65,36 @@ After that run:
> ykfde
This will store a challenge in `/etc/ykfde.d/` and add a new slot to
-your LUKS device. Last add `ykfde` to your hook list in
-`/etc/mkinitcpio.conf` and rebuild your initramfs with:
+your LUKS device. Now you have two choices:
+
+### `ykfde` hook
+
+Last add `ykfde` to your hook list in `/etc/mkinitcpio.conf` and rebuild
+your initramfs with:
> mkinitcpio -p linux
Reboot and have fun!
+### `ykfde-cpio` hook
+
+Add `ykfde-cpio` to your hook list in `/etc/mkinitcpio.conf` and rebuild
+your initramfs with:
+
+> mkinitcpio -p linux
+
+Additionally enable `systemd` service `ykfde-cpio.service` and make your
+bootloader load the new `cpio` image `/boot/ykfde-challenges.img` (in
+addition to your usual initramfs).
+
+Reboot and have fun!
+
Limitation / TODO
-----------------
* At the moment this is specific to Arch Linux. Though everything should
run with upstream `systemd` just fine anybody has to hook things up with
[dracut](https://dracut.wiki.kernel.org/) or whatever.
-* The challenge is not updated on boot. The file is accessible read only in
- initramfs, but we have no easy way to write it to persistant storage.
- So probably this is a design limitation... However the install hook does
- update the challenge when building a new initramfs and and Yubikey is
- inserted.
### Upstream
diff --git a/bin/Makefile b/bin/Makefile
index daa77f2..4fcd6fb 100644
--- a/bin/Makefile
+++ b/bin/Makefile
@@ -5,13 +5,17 @@ RM := rm
# flags
CFLAGS += -std=c11 -O2 -fpic -pie -Wall -Werror
-all: ykfde
+all: ykfde ykfde-cpio
ykfde: ykfde.c
$(CC) $(CFLAGS) -lykpers-1 -lyubikey -liniparser -lcryptsetup $(LDFLAGS) -o ykfde ykfde.c
-install: ykfde
+ykfde-cpio: ykfde-cpio.c
+ $(CC) $(CFLAGS) -larchive $(LDFLAGS) -o ykfde-cpio ykfde-cpio.c
+
+install: ykfde ykfde-cpio
$(INSTALL) -D -m0755 ykfde $(DESTDIR)/usr/bin/ykfde
+ $(INSTALL) -D -m0755 ykfde-cpio $(DESTDIR)/usr/bin/ykfde-cpio
clean:
- $(RM) -f ykfde
+ $(RM) -f ykfde ykfde-cpio
diff --git a/bin/ykfde-cpio.c b/bin/ykfde-cpio.c
new file mode 100644
index 0000000..71a39db
--- /dev/null
+++ b/bin/ykfde-cpio.c
@@ -0,0 +1,220 @@
+/*
+ * (C) 2014 by Christian Hesse <mail@eworm.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ * compile with:
+ * $ gcc -o mkcpio mkcpio.c -larchive
+ */
+
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <archive.h>
+#include <archive_entry.h>
+
+#define CONFIGFILE "/etc/ykfde.conf"
+#define CHALLENGEDIR "/etc/ykfde.d/"
+#define CPIOFILE "/boot/ykfde-challenges.img"
+#define CPIOTMPFILE CPIOFILE "-XXXXXX"
+
+int add_dir(struct archive *archive, const char * path) {
+ struct stat st;
+ struct archive_entry *entry;
+ int8_t rc;
+
+ /* initialize struct stat for directories from root */
+ if ((rc = stat("/", &st)) < 0) {
+ perror("stat() failed");
+ goto out;
+ }
+
+ if ((entry = archive_entry_new()) == NULL) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_entry_new() failed");
+ goto out;
+ }
+
+ archive_entry_set_pathname(entry, path);
+ archive_entry_set_filetype(entry, AE_IFDIR);
+ archive_entry_copy_stat(entry, &st);
+ if (archive_write_header(archive, entry) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_header() failed");
+ goto out;
+ }
+ archive_entry_free(entry);
+
+ rc = EXIT_SUCCESS;
+
+out:
+ return rc;
+}
+
+int main(int argc, const char **argv) {
+ char cpiotmpfile[] = CPIOTMPFILE;
+ struct archive *archive;
+ struct archive_entry *entry;
+ struct stat st;
+ char buff[64];
+ int len, fdfile, fdarchive;
+ DIR * dir;
+ struct dirent * ent;
+ char * filename, * path;
+ off_t pathlength = 0;
+ int8_t rc = EXIT_FAILURE;
+
+ if ((rc = fdarchive = mkstemp(cpiotmpfile)) < 0) {
+ perror("mkstemp() failed");
+ goto out10;
+ }
+
+ if ((archive = archive_write_new()) == NULL) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_new() failed.\n");
+ goto out10;
+ }
+
+ if (archive_write_set_format_cpio_newc(archive) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_set_format_cpio_newc() failed.\n");
+ goto out10;
+ }
+
+ if (archive_write_open_fd(archive, fdarchive) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_open_fd() failed.\n");
+ goto out10;
+ }
+
+ if ((rc = add_dir(archive, ".")) < 0) {
+ fprintf(stderr, "add_dir() failed");
+ goto out10;
+ }
+
+ while (1) {
+ path = strdup(CHALLENGEDIR + 1);
+ if (strstr(path + pathlength, "/") == NULL)
+ break;
+ *strstr(path + pathlength, "/") = 0;
+ pathlength = strlen(path) + 1;
+
+ if ((rc = add_dir(archive, path)) < 0) {
+ fprintf(stderr, "add_dir() failed");
+ goto out10;
+ }
+
+ free(path);
+ }
+
+ if ((dir = opendir(CHALLENGEDIR)) != NULL) {
+ while ((ent = readdir(dir)) != NULL) {
+ filename = malloc(sizeof(CHALLENGEDIR) + strlen(ent->d_name) + 1);
+ sprintf(filename, CHALLENGEDIR "%s", ent->d_name);
+
+ if ((rc = stat(filename, &st)) < 0) {
+ perror("stat() failed");
+ goto out10;
+ }
+
+ if (S_ISREG(st.st_mode)) {
+ if ((entry = archive_entry_new()) == NULL) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_entry_new() failed.\n");
+ goto out10;
+ }
+
+ /* these do not return exit code */
+ archive_entry_set_pathname(entry, filename + 1);
+ archive_entry_set_size(entry, st.st_size);
+ archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_set_perm(entry, 0644);
+
+ if (archive_write_header(archive, entry) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_header() failed");
+ goto out10;
+ }
+
+ if ((rc = fdfile = open(filename, O_RDONLY)) < 0) {
+ perror("open() failed");
+ goto out10;
+ }
+
+ if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) {
+ perror("read() failed");
+ goto out10;
+ }
+
+ while (len > 0) {
+ if (( rc = archive_write_data(archive, buff, len)) < 0) {
+ fprintf(stderr, "archive_write_data() failed");
+ goto out10;
+ }
+
+ if ((rc = len = read(fdfile, buff, sizeof(buff))) < 0) {
+ perror("read() failed");
+ goto out10;
+ }
+ }
+
+ if ((rc = close(fdfile)) < 0) {
+ perror("close() failed");
+ goto out10;
+ }
+
+ archive_entry_free(entry);
+ }
+ free(filename);
+ }
+ if ((rc = closedir(dir)) < 0) {
+ perror("closedir() failed");
+ goto out10;
+ }
+ } else {
+ rc = EXIT_FAILURE;
+ perror("opendir() failed");
+ goto out10;
+ }
+
+ if (archive_write_close(archive) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_close() failed");
+ goto out10;
+ }
+
+ if (archive_write_free(archive) != ARCHIVE_OK) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "archive_write_free() failed");
+ goto out10;
+ }
+
+ if (access(CPIOFILE, F_OK) == 0 && (rc = unlink(CPIOFILE)) < 0) {
+ perror("unkink() failed");
+ goto out10;
+ }
+
+ if ((rc = rename(cpiotmpfile, CPIOFILE)) < 0) {
+ perror("rename() failed");
+ goto out10;
+ }
+
+ rc = EXIT_SUCCESS;
+
+out10:
+ if (access(cpiotmpfile, F_OK) == 0)
+ unlink(cpiotmpfile);
+
+ return rc;
+}
+
+// vim: set syntax=c:
diff --git a/bin/ykfde.c b/bin/ykfde.c
index 43735d5..77bb86b 100644
--- a/bin/ykfde.c
+++ b/bin/ykfde.c
@@ -241,9 +241,8 @@ out60:
close(challengefile);
if (challengefiletmp)
close(challengefiletmp);
- if (access(challengefiletmpname, F_OK ) == 0 ) {
+ if (access(challengefiletmpname, F_OK) == 0 )
unlink(challengefiletmpname);
- }
out50:
/* free crypt context */
diff --git a/mkinitcpio/ykfde-cpio b/mkinitcpio/ykfde-cpio
new file mode 100644
index 0000000..c055a6d
--- /dev/null
+++ b/mkinitcpio/ykfde-cpio
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+build() {
+ # install files to initramfs
+ add_binary /usr/lib/udev/ykfde
+ add_file /usr/lib/initcpio/udev/20-ykfde.rules /usr/lib/udev/rules.d/20-ykfde.rules
+ add_file /etc/ykfde.conf
+}
+
+help() {
+ echo "This hook adds support for opening LUKS devices with Yubico key."
+ echo "Please use command 'ykfde' to prepare."
+ echo "The hook ykfde-cpio does NOT include challenges! Please load"
+ echo "additional cpio archive with bootloader."
+}
diff --git a/systemd/ykfde.service b/systemd/ykfde.service
new file mode 100644
index 0000000..36566a1
--- /dev/null
+++ b/systemd/ykfde.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Yubikey full disk encryption
+
+[Service]
+Type=oneshot
+ExecStart=/usr/bin/ykfde
+ExecStart=/usr/bin/ykfde-cpio
+RemainAfterExit=yes
+
+[Install]
+WantedBy=multi-user.target