summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Christian Hesse <mail@eworm.de>2014-12-22 22:03:21 +0100
committerGravatar Christian Hesse <mail@eworm.de>2014-12-22 23:20:10 +0100
commit0498dd512161b7fb07e703e03bc9b8ca8b3dd400 (patch)
tree0ced97f5e7015af52d712c53cf312adfa6c2dfa7
parentebcce373b196cd4ad44667a05c856ed0f4b472b5 (diff)
downloadmkinitcpio-ykfde-0498dd512161b7fb07e703e03bc9b8ca8b3dd400.tar.gz
mkinitcpio-ykfde-0498dd512161b7fb07e703e03bc9b8ca8b3dd400.tar.zst
replace shell script with C code, and many more
* place bin/ykfde with C source code bin/ykfde.c * challenge/response can be updated in place WARNING: This required config file syntax change! * updates and simplification to udev/ykfde * a lot more... Signed-off-by: Christian Hesse <mail@eworm.de>
-rw-r--r--.gitignore1
-rw-r--r--Makefile11
-rw-r--r--README.md30
-rw-r--r--bin/Makefile17
-rwxr-xr-xbin/ykfde74
-rw-r--r--bin/ykfde.c280
-rw-r--r--conf/ykfde.conf20
-rw-r--r--mkinitcpio/ykfde (renamed from install/ykfde)5
-rw-r--r--udev/ykfde.c107
9 files changed, 408 insertions, 137 deletions
diff --git a/.gitignore b/.gitignore
index 94ca1e7..4da39b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
README.html
+bin/ykfde
udev/ykfde
diff --git a/Makefile b/Makefile
index 1cc25a7..cd126e7 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,10 @@ RM := rm
# a release tarball...
VERSION := 0.3.4
-all: udev/ykfde README.html
+all: bin/ykfde udev/ykfde README.html
+
+bin/ykfde: bin/ykfde.c
+ $(MAKE) -C bin
udev/ykfde: udev/ykfde.c
$(MAKE) -C udev
@@ -16,11 +19,12 @@ README.html: README.md
install: install-bin install-doc
-install-bin: udev/ykfde
+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 install/ykfde $(DESTDIR)/usr/lib/initcpio/install/ykfde
+ $(INSTALL) -D -m0644 mkinitcpio/ykfde $(DESTDIR)/usr/lib/initcpio/install/ykfde
$(INSTALL) -d -m0700 $(DESTDIR)/etc/ykfde.d/
install-doc: README.md README.html
@@ -28,6 +32,7 @@ install-doc: README.md README.html
$(INSTALL) -D -m0644 README.html $(DESTDIR)/usr/share/doc/ykfde/README.html
clean:
+ $(MAKE) -C bin clean
$(MAKE) -C udev clean
$(RM) -f README.html
diff --git a/README.md b/README.md
index 083a19b..6f47e94 100644
--- a/README.md
+++ b/README.md
@@ -43,8 +43,23 @@ adding a line to `/etc/crypttab.initramfs`. It should read like:
> `mapping-name` /dev/`LUKS-device` -
-`ykfde` will read its information from there. Then prepare the key. Plug
-it in, make sure it is configured for `HMAC-SHA1`. After that run:
+Update `/etc/ykfde.conf` with correct settings. Add `mapping-name` from
+above to `device name` in the `general` section. Then add a new section
+with your key's decimal serial number containing the key slot setting.
+The file should look like this:
+
+ [general]
+ device name = crypt
+
+ [1234567]
+ luks slot = 1
+
+*Be warned*: Do not remove or overwrite your interactive key! Keep that
+for backup and rescue!
+
+`ykfde` will read its information from these files. Then prepare
+the key. Plug it in, make sure it is configured for `HMAC-SHA1`.
+After that run:
> ykfde
@@ -62,6 +77,13 @@ 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. The file is accessible read only in
+* 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...
+ 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
+
+URL: [GitHub.com](https://github.com/eworm-de/mkinitcpio-ykfde)
+Mirror: [eworm.de](http://git.eworm.de/cgit.cgi/mkinitcpio-ykfde/)
diff --git a/bin/Makefile b/bin/Makefile
new file mode 100644
index 0000000..daa77f2
--- /dev/null
+++ b/bin/Makefile
@@ -0,0 +1,17 @@
+# commands
+CC := gcc
+INSTALL := install
+RM := rm
+# flags
+CFLAGS += -std=c11 -O2 -fpic -pie -Wall -Werror
+
+all: ykfde
+
+ykfde: ykfde.c
+ $(CC) $(CFLAGS) -lykpers-1 -lyubikey -liniparser -lcryptsetup $(LDFLAGS) -o ykfde ykfde.c
+
+install: ykfde
+ $(INSTALL) -D -m0755 ykfde $(DESTDIR)/usr/bin/ykfde
+
+clean:
+ $(RM) -f ykfde
diff --git a/bin/ykfde b/bin/ykfde
deleted file mode 100755
index 41601b1..0000000
--- a/bin/ykfde
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/bin/sh
-
-function help() {
- echo "usage: ${0} [OPTIONS]"
- echo
- echo "where OPTIONS are:"
- echo " -1 use Yubico key slot 1"
- echo " -2 use Yubico key slot 2 (default)"
- echo " -h show this help"
-}
-
-DEVICE="$(egrep -v '^(#|$)' /etc/crypttab.initramfs 2>/dev/null | head -n1 | sed 's/\s\+/:/g' | cut -d: -f2)"
-SERIAL="$(ykinfo -sq)"
-SLOT="2"
-TMPDIR="$(mktemp --directory --tmpdir=/tmp/ .$(basename ${0})-${$}-XXXXXX)"
-
-while getopts "12h" opt; do
- case ${opt} in
- 1)
- SLOT="1"
- ;;
- 2)
- SLOT="2"
- ;;
- h)
- help
- exit 0
- ;;
- esac
-done
-
-# check we have all information
-if [ -z "${DEVICE}" ]; then
- echo "Failed to get device from /etc/crypttab.initramfs." >&2
- exit 1
-elif [ ! -b "${DEVICE}" ]; then
- echo "Device '${DEVICE}' does not exist or is not a block device." >&2
- exit 1
-elif ! cryptsetup isLuks "${DEVICE}" 2>/dev/null; then
- echo "Device '${DEVICE}' is not a LUKS device." >&2
- exit 1
-elif [ -z "${SERIAL}" ]; then
- echo "Did not get a serial number from key. Did you insert one?" >&2
- exit 1
-fi
-
-# This directroy should exist, but we create it in case it does not
-if [ ! -d "/etc/ykfde.d/" ]; then
- install -d -m 0700 "/etc/ykfde.d/"
-fi
-
-# generate the challenge
-if ! makepasswd --chars=64 | tr -d '\n' > "/etc/ykfde.d/challenge-${SERIAL}"; then
- exit 1
-fi
-
-# generate response
-if ! ykchalresp -${SLOT} "$(cat "/etc/ykfde.d/challenge-${SERIAL}")" | tr -d '\n' > "${TMPDIR}/ykfde-response"; then
- # ykchalresp should have shouted, so do not complain here
- exit 1
-fi
-
-# add key to LUKS device
-if ! cryptsetup luksAddKey "${DEVICE}" "${TMPDIR}/ykfde-response"; then
- # cryptsetup should have shouted, ...
- exit 1
-fi
-
-# shred response and remove temporary directory
-shred --remove "${TMPDIR}/ykfde-response"
-rm -rf "${TMPDIR}"
-
-echo "Please do not forget to remove old keys when changing challenge!"
-echo "Now run 'mkinitcpio' to build a new initramfs!"
diff --git a/bin/ykfde.c b/bin/ykfde.c
new file mode 100644
index 0000000..43735d5
--- /dev/null
+++ b/bin/ykfde.c
@@ -0,0 +1,280 @@
+/*
+ * (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 ykfde ykfde.c -lykpers-1 -lyubikey -lcryptsetup -liniparser
+ */
+
+#ifndef _DEFAULT_SOURCE
+#define _DEFAULT_SOURCE
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <iniparser.h>
+
+#include <yubikey.h>
+#include <ykpers-1/ykdef.h>
+#include <ykpers-1/ykcore.h>
+
+#include <libcryptsetup.h>
+
+/* challenge is 64 byte,
+ * HMAC-SHA1 response is 40 byte */
+#define CHALLENGELEN 64
+#define RESPONSELEN SHA1_MAX_BLOCK_SIZE
+#define PASSPHRASELEN SHA1_DIGEST_SIZE * 2
+
+#define CONFIGFILE "/etc/ykfde.conf"
+#define CHALLENGEDIR "/etc/ykfde.d/"
+#define CONFYKSLOT "yk slot"
+#define CONFLUKSSLOT "luks slot"
+#define CONFDEVNAME "device name"
+
+int main(int argc, char **argv) {
+ char challenge_old[CHALLENGELEN + 1],
+ challenge_new[CHALLENGELEN + 1],
+ repose_old[RESPONSELEN],
+ repose_new[RESPONSELEN],
+ passphrase_old[PASSPHRASELEN + 1],
+ passphrase_new[PASSPHRASELEN + 1];
+ char challengefilename[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 1],
+ challengefiletmpname[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 7 /* -XXXXXX */ + 1];
+ int challengefile = 0, challengefiletmp = 0;
+ struct timeval tv;
+ int i;
+ int8_t rc = EXIT_FAILURE;
+ /* cryptsetup */
+ char * device_name;
+ int8_t luks_slot = -1;
+ struct crypt_device *cd;
+ crypt_status_info cs;
+ crypt_keyslot_info ck;
+ /* yubikey */
+ YK_KEY * yk;
+ uint8_t yk_slot = SLOT_CHAL_HMAC2;
+ unsigned int serial = 0;
+ /* iniparser */
+ dictionary * ini;
+ char section_ykslot[10 /* unsigned int in char */ + 1 + sizeof(CONFYKSLOT) + 1];
+ char section_luksslot[10 /* unsigned int in char */ + 1 + sizeof(CONFLUKSSLOT) + 1];
+
+ /* initialize random seed */
+ gettimeofday(&tv, NULL);
+ srand(tv.tv_usec * tv.tv_sec);
+
+ memset(challenge_old, 0, CHALLENGELEN + 1);
+ memset(challenge_new, 0, CHALLENGELEN + 1);
+ memset(repose_old, 0, RESPONSELEN);
+ memset(repose_new, 0, RESPONSELEN);
+ memset(passphrase_old, 0, PASSPHRASELEN + 1);
+ memset(passphrase_new, 0, PASSPHRASELEN + 1);
+
+ if ((ini = iniparser_load(CONFIGFILE)) == NULL) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "Could not parse configuration file.\n");
+ goto out10;
+ }
+
+ if ((device_name = iniparser_getstring(ini, "general:" CONFDEVNAME, NULL)) == NULL) {
+ rc = EXIT_FAILURE;
+ /* read from crypttab? */
+ /* get device from currently open devices? */
+ fprintf(stderr, "Could not read LUKS device from configuration file.\n");
+ goto out20;
+ }
+
+ /* init and open first Yubikey */
+ if ((rc = yk_init()) < 0) {
+ perror("yk_init() failed");
+ goto out20;
+ }
+
+ if ((yk = yk_open_first_key()) == NULL) {
+ rc = EXIT_FAILURE;
+ perror("yk_open_first_key() failed");
+ goto out30;
+ }
+
+ /* read the serial number from key */
+ if ((rc = yk_get_serial(yk, 0, 0, &serial)) < 0) {
+ perror("yk_get_serial() failed");
+ goto out40;
+ }
+
+ /* get the yk slot */
+ sprintf(section_ykslot, "%d:" CONFYKSLOT, serial);
+ yk_slot = iniparser_getint(ini, "general:" CONFYKSLOT, yk_slot);
+ yk_slot = iniparser_getint(ini, section_ykslot, yk_slot);
+ switch (yk_slot) {
+ case 1:
+ case SLOT_CHAL_HMAC1:
+ yk_slot = SLOT_CHAL_HMAC1;
+ break;
+ case 2:
+ case SLOT_CHAL_HMAC2:
+ default:
+ yk_slot = SLOT_CHAL_HMAC2;
+ break;
+ }
+
+ /* get the luks slot */
+ sprintf(section_luksslot, "%d:" CONFLUKSSLOT, serial);
+ luks_slot = iniparser_getint(ini, section_luksslot, luks_slot);
+ if (luks_slot < 0) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "Please set LUKS key slot for Yubikey with serial %d!\n", serial);
+ printf("Add something like this to " CONFIGFILE ":\n\n[%d]\nluks slot = 1\n", serial);
+ goto out40;
+ }
+
+ /* get random number and limit to printable ASCII character (32 to 126) */
+ for(i = 0; i < CHALLENGELEN; i++)
+ challenge_new[i] = (rand() % (126 - 32)) + 32;
+
+ /* do challenge/response and encode to hex */
+ if ((rc = yk_challenge_response(yk, yk_slot, true,
+ CHALLENGELEN, (unsigned char *)challenge_new,
+ RESPONSELEN, (unsigned char *)repose_new)) < 0) {
+ perror("yk_challenge_response() failed");
+ goto out40;
+ }
+ yubikey_hex_encode((char *)passphrase_new, (char *)repose_new, 20);
+
+ /* initialize crypt device */
+ if ((rc = crypt_init_by_name(&cd, device_name)) < 0) {
+ fprintf(stderr, "Device %s failed to initialize.\n", device_name);
+ goto out40;
+ }
+
+ /* these are the filenames for challenge
+ * we need this for reading and writing */
+ sprintf(challengefilename, CHALLENGEDIR "/challenge-%d", serial);
+ sprintf(challengefiletmpname, CHALLENGEDIR "/challenge-%d-XXXXXX", serial);
+
+ /* write new challenge to file */
+ if ((rc = challengefiletmp = mkstemp(challengefiletmpname)) < 0) {
+ fprintf(stderr, "Could not open file %s for writing.\n", challengefiletmpname);
+ goto out50;
+ }
+ if ((rc = write(challengefiletmp, challenge_new, CHALLENGELEN)) < 0) {
+ fprintf(stderr, "Failed to write challenge to file.\n");
+ goto out60;
+ }
+ challengefiletmp = close(challengefiletmp);
+
+ /* get status of crypt device
+ * We expect this to be active (or busy). It is the actual root device, no? */
+ cs = crypt_status(cd, device_name);
+ if (cs != CRYPT_ACTIVE && cs != CRYPT_BUSY) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "Device %s is invalid or inactive.\n", device_name);
+ goto out60;
+ }
+
+ ck = crypt_keyslot_status(cd, luks_slot);
+ if (ck == CRYPT_SLOT_INVALID) {
+ rc = EXIT_FAILURE;
+ fprintf(stderr, "Key slot %d is invalid.\n", luks_slot);
+ goto out60;
+ } else if (ck == CRYPT_SLOT_ACTIVE || ck == CRYPT_SLOT_ACTIVE_LAST) {
+ /* read challenge from file */
+ if ((rc = challengefile = open(challengefilename, O_RDONLY)) < 0) {
+ perror("Failed opening challenge file for reading");
+ goto out60;
+ }
+
+ if ((rc = read(challengefile, challenge_old, CHALLENGELEN)) < 0) {
+ perror("Failed reading challenge from file");
+ goto out60;
+ }
+
+ challengefile = close(challengefile);
+ /* finished reading challenge */
+
+ /* do challenge/response and encode to hex */
+ if ((rc = yk_challenge_response(yk, yk_slot, true,
+ CHALLENGELEN, (unsigned char *)challenge_old,
+ RESPONSELEN, (unsigned char *)repose_old)) < 0) {
+ perror("yk_challenge_response() failed");
+ goto out60;
+ }
+ yubikey_hex_encode((char *)passphrase_old, (char *)repose_old, 20);
+
+ if ((rc = crypt_keyslot_change_by_passphrase(cd, luks_slot, luks_slot,
+ passphrase_old, PASSPHRASELEN,
+ passphrase_new, PASSPHRASELEN)) < 0) {
+ fprintf(stderr, "Could not update passphrase for key slot %d.\n", luks_slot);
+ goto out60;
+ }
+
+ if ((rc = unlink(challengefilename)) < 0) {
+ fprintf(stderr, "Failed to delete old challenge file.\n");
+ goto out60;
+ }
+ } else { /* ck == CRYPT_SLOT_INACTIVE */
+ if ((rc = crypt_keyslot_add_by_passphrase(cd, luks_slot, NULL, 0,
+ passphrase_new, PASSPHRASELEN)) < 0) {
+ fprintf(stderr, "Could add passphrase for key slot %d.\n", luks_slot);
+ goto out60;
+ }
+ }
+
+ if ((rc = rename(challengefiletmpname, challengefilename)) < 0) {
+ fprintf(stderr, "Failed to rename new challenge file.\n");
+ goto out60;
+ }
+
+ rc = EXIT_SUCCESS;
+
+out60:
+ /* close the challenge file */
+ if (challengefile)
+ close(challengefile);
+ if (challengefiletmp)
+ close(challengefiletmp);
+ if (access(challengefiletmpname, F_OK ) == 0 ) {
+ unlink(challengefiletmpname);
+ }
+
+out50:
+ /* free crypt context */
+ crypt_free(cd);
+
+out40:
+ /* close Yubikey */
+ if (!yk_close_key(yk))
+ perror("yk_close_key() failed");
+
+out30:
+ /* release Yubikey */
+ if (!yk_release())
+ perror("yk_release() failed");
+
+out20:
+ /* free iniparser dictionary */
+ iniparser_freedict(ini);
+
+
+out10:
+ /* wipe response (cleartext password!) from memory */
+ /* This is statically allocated and always save to wipe! */
+ memset(challenge_old, 0, CHALLENGELEN + 1);
+ memset(challenge_new, 0, CHALLENGELEN + 1);
+ memset(repose_old, 0, RESPONSELEN);
+ memset(repose_new, 0, RESPONSELEN);
+ memset(passphrase_old, 0, PASSPHRASELEN + 1);
+ memset(passphrase_new, 0, PASSPHRASELEN + 1);
+
+ return rc;
+}
+
+// vim: set syntax=c:
diff --git a/conf/ykfde.conf b/conf/ykfde.conf
index af25ad7..0525053 100644
--- a/conf/ykfde.conf
+++ b/conf/ykfde.conf
@@ -1,8 +1,20 @@
[general]
-# Specify what Yubikey slot to use for full disk encryption
+# Specify what Yubikey slot to use for full disk encryption.
+# This is just the system default, you can configure one or more
+# Yubikeys below.
# The specified slot has to be configured for HMAC-SHA1.
-slot = 2
+yk slot = 2
-# you can specify slot for one or more specific Yubikeys as well
+# This is the LUKS device. Make sure you use the name, not
+# block device, e.g. it has to match first column of
+# /etc/crypttab.initramfs.
+device name = crypt
+
+# For every Yubikey in use add a section here.
+# * 'yk slot' is optional and only required for keys differing
+# from system default.
+# * 'luks slot' is required to make sure one Yukikey is associated
+# with exactly one LUKS slot!
#[1234567]
-#slot = 1
+#yk slot = 1
+#luks slot = 1
diff --git a/install/ykfde b/mkinitcpio/ykfde
index 71e5eb5..f4115d6 100644
--- a/install/ykfde
+++ b/mkinitcpio/ykfde
@@ -1,6 +1,11 @@
#!/bin/sh
build() {
+ # This will update to LUKS key slot if Yubikey is available.
+ # Do not fail if key is not present!
+ /usr/bin/ykfde >/dev/null 2>/dev/null || true
+
+ # 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
diff --git a/udev/ykfde.c b/udev/ykfde.c
index 0f5bd17..2adedbb 100644
--- a/udev/ykfde.c
+++ b/udev/ykfde.c
@@ -13,6 +13,7 @@
#include <dirent.h>
#include <errno.h>
+#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -36,12 +37,18 @@
#define EVENT_SIZE (sizeof (struct inotify_event))
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
+#define CHALLENGELEN 64
+#define RESPONSELEN SHA1_MAX_BLOCK_SIZE
+#define PASSPHRASELEN SHA1_DIGEST_SIZE * 2
+
#define ASK_PATH "/run/systemd/ask-password/"
#define ASK_MESSAGE "Please enter passphrase for disk"
#define CONFIGFILE "/etc/ykfde.conf"
#define CHALLENGEDIR "/etc/ykfde.d/"
+#define CONFYKSLOT "yk slot"
+
static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
union {
struct sockaddr sa;
@@ -61,7 +68,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
}
static int try_answer(char * ask_file, char * response) {
- int8_t ret = EXIT_FAILURE;
+ int8_t rc = EXIT_FAILURE;
dictionary * ini;
char * ask_message, * ask_socket;
int fd_askpass;
@@ -81,12 +88,12 @@ static int try_answer(char * ask_file, char * response) {
goto out1;
}
- if (send_on_socket(fd_askpass, ask_socket, response, strlen(response)) < 0) {
+ if (send_on_socket(fd_askpass, ask_socket, response, PASSPHRASELEN + 1) < 0) {
perror("send_on_socket() failed");
goto out2;
}
- ret = EXIT_SUCCESS;
+ rc = EXIT_SUCCESS;
out2:
close(fd_askpass);
@@ -94,26 +101,23 @@ out2:
out1:
iniparser_freedict(ini);
- return ret;
+ return rc;
}
int main(int argc, char **argv) {
- int8_t ret = EXIT_FAILURE;
+ int8_t rc = EXIT_FAILURE;
/* Yubikey */
YK_KEY * yk;
uint8_t slot = SLOT_CHAL_HMAC2;
unsigned int serial = 0;
- unsigned char response[SHA1_MAX_BLOCK_SIZE];
- unsigned char response_hex[(SHA1_MAX_BLOCK_SIZE * 2) + 1];
- char response_askpass[(SHA1_MAX_BLOCK_SIZE * 2) + 2];
+ char response[RESPONSELEN], passphrase[PASSPHRASELEN + 1], passphrase_askpass[PASSPHRASELEN + 2];
/* iniparser */
dictionary * ini;
- char section_serial[10 /* unsigned int in char */ + 5 /* ":slot" */ + 1];
+ char section_ykslot[10 /* unsigned int in char */ + 1 + sizeof(CONFYKSLOT) + 1];
/* read challenge */
- size_t fsize;
- char * challenge;
+ char challenge[CHALLENGELEN + 1];
char challengefilename[sizeof(CHALLENGEDIR) + 11 /* "/challenge-" */ + 10 /* unsigned int in char */ + 1];
- FILE * challengefile;
+ int challengefile;
/* read dir */
DIR * dir;
struct dirent * ent;
@@ -127,19 +131,22 @@ int main(int argc, char **argv) {
freopen("/dev/console", "w", stderr);
#endif
+ memset(challenge, 0, CHALLENGELEN);
+
/* init and open first Yubikey */
- if (!yk_init()) {
+ if ((rc = yk_init()) < 0) {
perror("yk_init() failed");
goto out10;
}
if ((yk = yk_open_first_key()) == NULL) {
+ rc = EXIT_FAILURE;
perror("yk_open_first_key() failed");
goto out20;
}
/* read the serial number from key */
- if(!yk_get_serial(yk, 0, 0, &serial)) {
+ if((rc = !yk_get_serial(yk, 0, 0, &serial)) < 0) {
perror("yk_get_serial() failed");
goto out30;
}
@@ -151,42 +158,37 @@ int main(int argc, char **argv) {
goto out30;
/* read challenge from file */
- if ((challengefile = fopen(challengefilename, "r")) == NULL) {
+ if ((rc = challengefile = open(challengefilename, O_RDONLY)) < 0) {
perror("Failed opening challenge file for reading");
goto out30;
}
- fseek(challengefile, 0, SEEK_END);
- fsize = ftell(challengefile);
- fseek(challengefile, 0, SEEK_SET);
- if ((challenge = malloc(fsize + 1)) == NULL) {
- perror("malloc() failed");
- goto out40;
- }
-
- if ((fread(challenge, fsize, 1, challengefile)) != 1) {
+ if ((rc = read(challengefile, challenge, CHALLENGELEN)) < 0) {
perror("Failed reading challenge from file");
goto out50;
}
- challenge[fsize] = 0;
+ challengefile = close(challengefile);
/* finished reading challenge */
/* try to read config file
* if anything here fails we do not care... slot 2 is the default */
if ((ini = iniparser_load(CONFIGFILE)) != NULL) {
/* first try the general setting */
- slot = iniparser_getint(ini, "general:slot", slot);
+ slot = iniparser_getint(ini, "general:" CONFYKSLOT, slot);
- sprintf(section_serial, "%d:slot", serial);
+ sprintf(section_ykslot, "%d:" CONFYKSLOT, serial);
/* then probe for setting with serial number */
- slot = iniparser_getint(ini, section_serial, slot);
+ slot = iniparser_getint(ini, section_ykslot, slot);
switch (slot) {
- case '1':
+ case 1:
+ case SLOT_CHAL_HMAC1:
slot = SLOT_CHAL_HMAC1;
break;
- default: /* slot 2 is default */
+ case 2:
+ case SLOT_CHAL_HMAC2:
+ default:
slot = SLOT_CHAL_HMAC2;
break;
}
@@ -194,26 +196,28 @@ int main(int argc, char **argv) {
iniparser_freedict(ini);
}
- memset(response, 0, sizeof(response));
- memset(response_hex, 0, sizeof(response_hex));
+ memset(response, 0, RESPONSELEN);
+ memset(passphrase, 0, PASSPHRASELEN + 1);
/* do challenge/response and encode to hex */
- if (!yk_challenge_response(yk, slot, true, strlen(challenge), (unsigned char *)challenge, sizeof(response), response)) {
+ if ((rc = yk_challenge_response(yk, slot, true,
+ CHALLENGELEN, (unsigned char *)challenge,
+ RESPONSELEN, (unsigned char *)response)) < 0) {
perror("yk_challenge_response() failed");
goto out50;
}
- yubikey_hex_encode((char *)response_hex, (char *)response, 20);
+ yubikey_hex_encode((char *)passphrase, (char *)response, 20);
- sprintf(response_askpass, "+%s", response_hex);
+ sprintf(passphrase_askpass, "+%s", passphrase);
/* change to directory so we do not have to assemble complete/absolute path */
- if (chdir(ASK_PATH) != 0) {
+ if ((rc = chdir(ASK_PATH)) != 0) {
perror("chdir() failed");
goto out50;
}
/* creating the INOTIFY instance and add ASK_PATH directory into watch list */
- if ((fd_inotify = inotify_init()) < 0) {
+ if ((rc = fd_inotify = inotify_init()) < 0) {
perror("inotify_init() failed");
goto out50;
}
@@ -225,17 +229,18 @@ int main(int argc, char **argv) {
if ((dir = opendir(ASK_PATH)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
if (strncmp(ent->d_name, "ask.", 4) == 0) {
- if ((ret = try_answer(ent->d_name, response_askpass)) == EXIT_SUCCESS)
+ if ((rc = try_answer(ent->d_name, passphrase_askpass)) == EXIT_SUCCESS)
goto out70;
}
}
} else {
+ rc = EXIT_FAILURE;
perror ("opendir() failed");
goto out60;
}
/* read to determine the event change happens. Actually this read blocks until the change event occurs */
- if ((length = read(fd_inotify, buffer, EVENT_BUF_LEN)) < 0) {
+ if ((rc = length = read(fd_inotify, buffer, EVENT_BUF_LEN)) < 0) {
perror("read() failed");
goto out70;
}
@@ -245,7 +250,7 @@ int main(int argc, char **argv) {
while (i < length) {
event = (struct inotify_event *)&buffer[i];
if (event->len > 0)
- if ((ret = try_answer(event->name, response_askpass)) == EXIT_SUCCESS)
+ if ((rc = try_answer(event->name, passphrase_askpass)) == EXIT_SUCCESS)
goto out70;
i += EVENT_SIZE + event->len;
}
@@ -260,33 +265,31 @@ out60:
close(fd_inotify);
out50:
- /* free challenge */
- free(challenge);
-
-out40:
/* close the challenge file */
- fclose(challengefile);
+ if (challengefile)
+ close(challengefile);
/* Unlink it if we were successful, we can not try again later! */
- if (ret == EXIT_SUCCESS)
+ if (rc == EXIT_SUCCESS)
unlink(challengefilename);
out30:
/* wipe response (cleartext password!) from memory */
- memset(response, 0, sizeof(response));
- memset(response_hex, 0, sizeof(response_hex));
- memset(response_askpass, 0, sizeof(response_askpass));
+ memset(challenge, 0, CHALLENGELEN);
+ memset(response, 0, RESPONSELEN);
+ memset(passphrase, 0, PASSPHRASELEN + 1);
+ memset(passphrase_askpass, 0, PASSPHRASELEN + 2);
/* close Yubikey */
- if (!yk_close_key(yk))
+ if (yk_close_key(yk) < 0)
perror("yk_close_key() failed");
out20:
/* release Yubikey */
- if (!yk_release())
+ if (yk_release() < 0)
perror("yk_release() failed");
out10:
- return ret;
+ return rc;
}
// vim: set syntax=c: