Compare commits

..

10 Commits

Author SHA1 Message Date
Yu Watanabe 51692fab56
Merge pull request #14370 from poettering/homed-preparation-misc
four smaller preparation patches from the homed PR
2019-12-18 11:17:59 +09:00
Yu Watanabe 12742abe07
Merge pull request #14369 from poettering/pkcs11-cryptsetup-followup
PKCS#11 cryptsetup support followup
2019-12-18 11:16:17 +09:00
Lennart Poettering 9652d74092 varlink: add varlink_close_unref() helper 2019-12-17 20:05:46 +01:00
Lennart Poettering e10720818e chown-recursive: add fd based API 2019-12-17 20:03:40 +01:00
Lennart Poettering 417a6eece8 chown-recursive: move src/core/chown-recursive.[ch] → src/shared/
We want to use it outside of the core, hence let's moved it to the
shared code directory.
2019-12-17 20:03:40 +01:00
Lennart Poettering 845a7c1fc1 basic: add quota-util.[ch] with some helpers for the Linux quotactl() API 2019-12-17 20:03:40 +01:00
Lennart Poettering 6789dd57f0 cryptsetup-pkcs11: just return zero on success, no need to return anything else 2019-12-17 18:54:07 +01:00
Lennart Poettering 3ded1d616a cryptsetup-pkcs11: line break some overly long lines 2019-12-17 18:54:04 +01:00
Lennart Poettering 12f69587e9 cryptsetup-pkcs11: refuse keys above 16MiB size 2019-12-17 18:54:00 +01:00
Lennart Poettering 2ccf0ff6e8 man: tweaks to the crypttab(5) man page 2019-12-17 18:53:45 +01:00
12 changed files with 158 additions and 20 deletions

View File

@ -425,10 +425,10 @@
line. This is useful for unlocking encrypted volumes through security tokens or smartcards. See below
for an example how to set up this mechanism for unlocking a LUKS volume with a YubiKey security
token. The specified URI can refer directly to a private RSA key stored on a token or alternatively
just to a slot or token in which case a suitable private RSA key object is automatically searched on
it. In this case if multiple suitable objects are found the token is refused. The key configured in
the third column is passed as is to RSA decryption. The resulting decrypted key is then base64
encoded before it is used to unlock the LUKS volume.</para></listitem>
just to a slot or token, in which case a search for a suitable private RSA key will be performed. In
this case if multiple suitable objects are found the token is refused. The key configured in the
third column is passed as is to RSA decryption. The resulting decrypted key is then base64 encoded
before it is used to unlock the LUKS volume.</para></listitem>
</varlistentry>
<varlistentry>
@ -489,7 +489,8 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s</programlist
<title>Yubikey-based Volume Unlocking Example</title>
<para>The PKCS#11 logic allows hooking up any compatible security token that is capable of storing RSA
decryption keys. Here's an example how to set up a Yubikey security token for this purpose:</para>
decryption keys. Here's an example how to set up a Yubikey security token for this purpose, using
<command>ykman</command> from the yubikey-manager project:</para>
<programlisting><xi:include href="yubikey-crypttab.sh" parse="text" /></programlisting>

View File

@ -7,7 +7,9 @@ ykman piv reset
# Generate a new private/public key pair on the device, store the public key in 'pubkey.pem'.
ykman piv generate-key -a RSA2048 9d pubkey.pem
# Create a self-signed certificate from this public key, and store it on the device.
# Create a self-signed certificate from this public key, and store it on the
# device. The "subject" should be an arbitrary string to identify the token in
# the p11tool output below.
ykman piv generate-certificate --subject "Knobelei" 9d pubkey.pem
# Check if the newly create key on the Yubikey shows up as token in PKCS#11. Have a look at the output, and
@ -18,16 +20,16 @@ p11tool --list-tokens
dd if=/dev/urandom of=plaintext.bin bs=128 count=1
# Encode the secret key also as base64 text (with all whitespace removed)
base64 &lt; plaintext.bin | tr -d '\n\r\t ' &gt; plaintext.base64
base64 < plaintext.bin | tr -d '\n\r\t ' > plaintext.base64
# Encrypt this newly generated (binary) LUKS decryption key using the public key whose private key is on the
# Yubikey, store the result in /etc/encrypted-luks-key.bin, where we'll look for it during boot.
openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/encrypted-luks-key.bin
sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/encrypted-luks-key.bin
# Configure the LUKS decryption key on the LUKS device. We use very low pbkdf settings since the key already
# has quite a high quality (it comes directly from /dev/urandom after all), and thus we don't need to do much
# key derivation.
cryptsetup luksAddKey /dev/sda1 plaintext.base64 --pbkdf=pbkdf2 --pbkdf-force-iterations=1000
# key derivation. Replace /dev/sdXn by the partition to use (e.g. sda1)
sudo cryptsetup luksAddKey /dev/sdXn plaintext.base64 --pbkdf=pbkdf2 --pbkdf-force-iterations=1000
# Now securely delete the plain text LUKS key, we don't need it anymore, and since it contains secret key
# material it should be removed from disk thoroughly.
@ -39,7 +41,7 @@ rm pubkey.pem
# Test: Let's run systemd-cryptsetup to test if this all worked. The option string should contain the full
# PKCS#11 URI we have in the clipboard, it tells the tool how to decypher the encrypted LUKS key.
systemd-cryptsetup attach mytest /dev/sda1 /etc/encrypted-luks-key.bin 'pkcs11-uri=pkcs11:…'
sudo systemd-cryptsetup attach mytest /dev/sdXn /etc/encrypted-luks-key.bin 'pkcs11-uri=pkcs11:…'
# If that worked, let's now add the same line persistently to /etc/crypttab, for the future.
echo "mytest /dev/sda1 /etc/encrypted-luks-key 'pkcs11-uri=pkcs11:…' >> /etc/crypttab
sudo bash -c 'echo "mytest /dev/sdXn /etc/encrypted-luks-key \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab'

View File

@ -169,6 +169,8 @@ basic_sources = files('''
process-util.h
procfs-util.c
procfs-util.h
quota-util.c
quota-util.h
random-util.c
random-util.h
ratelimit.c

41
src/basic/quota-util.c Normal file
View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/quota.h>
#include "alloc-util.h"
#include "blockdev-util.h"
#include "quota-util.h"
#include "stat-util.h"
int quotactl_devno(int cmd, dev_t devno, int id, void *addr) {
_cleanup_free_ char *devnode = NULL;
int r;
/* Like quotactl() but takes a dev_t instead of a path to a device node, and fixes caddr_t → void*,
* like we should, today */
r = device_path_make_major_minor(S_IFBLK, devno, &devnode);
if (r < 0)
return r;
if (quotactl(cmd, devnode, id, addr) < 0)
return -errno;
return 0;
}
int quotactl_path(int cmd, const char *path, int id, void *addr) {
dev_t devno;
int r;
/* Like quotactl() but takes a path to some fs object, and changes the backing file system. I.e. the
* argument shouldn't be a block device but a regular file system object */
r = get_block_device(path, &devno);
if (r < 0)
return r;
if (devno == 0)
return -ENODEV;
return quotactl_devno(cmd, devno, id, addr);
}

19
src/basic/quota-util.h Normal file
View File

@ -0,0 +1,19 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <inttypes.h>
#include <sys/quota.h>
#include <sys/types.h>
/* Wrapper around the QCMD() macro of linux/quota.h that removes some undefined behaviour. A typical quota
* command such as QCMD(Q_GETQUOTA, USRQUOTA) cannot be resolved on platforms where "int" is 32bit, as it is
* larger than INT_MAX. Yikes, because that are basically all platforms Linux supports. Let's add a wrapper
* that explicitly takes its arguments as unsigned 32bit, and then converts the shift result explicitly to
* int, acknowledging the undefined behaviour of the kernel headers. This doesn't remove the undefined
* behaviour, but it stops ubsan from complaining about it. */
static inline int QCMD_FIXED(uint32_t cmd, uint32_t type) {
return (int) QCMD(cmd, type);
}
int quotactl_devno(int cmd, dev_t devno, int id, void *addr);
int quotactl_path(int cmd, const char *path, int id, void *addr);

View File

@ -22,8 +22,6 @@ libcore_sources = '''
bpf-firewall.h
cgroup.c
cgroup.h
chown-recursive.c
chown-recursive.h
dbus-automount.c
dbus-automount.h
dbus-cgroup.c

View File

@ -12,12 +12,15 @@
#include "cryptsetup-pkcs11.h"
#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "macro.h"
#include "memory-util.h"
#include "pkcs11-util.h"
#include "stat-util.h"
#include "strv.h"
#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
static int load_key_file(
const char *key_file,
size_t key_file_size,
@ -50,8 +53,13 @@ static int load_key_file(
if (st.st_size == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
if ((uint64_t) st.st_size > SIZE_MAX)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Key file too large, refusing.");
if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
"Key file larger (%s) than allowed maximum size (%s), refusing.",
format_bytes(buf1, sizeof(buf1), st.st_size),
format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
}
if (key_file_offset >= (uint64_t) st.st_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
@ -113,7 +121,16 @@ static int pkcs11_callback(
/* Called for every token matching our URI */
r = pkcs11_token_login(m, session, slot_id, token_info, data->friendly_name, "drive-harddisk", "pkcs11-pin", data->until, NULL);
r = pkcs11_token_login(
m,
session,
slot_id,
token_info,
data->friendly_name,
"drive-harddisk",
"pkcs11-pin",
data->until,
NULL);
if (r < 0)
return r;
@ -126,11 +143,18 @@ static int pkcs11_callback(
if (r < 0)
return r;
r = pkcs11_token_decrypt_data(m, session, object, data->encrypted_key, data->encrypted_key_size, &data->decrypted_key, &data->decrypted_key_size);
r = pkcs11_token_decrypt_data(
m,
session,
object,
data->encrypted_key,
data->encrypted_key_size,
&data->decrypted_key,
&data->decrypted_key_size);
if (r < 0)
return r;
return 1;
return 0;
}
int decrypt_pkcs11_key(

View File

@ -139,3 +139,40 @@ int path_chown_recursive(
return chown_recursive_internal(TAKE_FD(fd), &st, uid, gid, mask); /* we donate the fd to the call, regardless if it succeeded or failed */
}
int fd_chown_recursive(
int fd,
uid_t uid,
gid_t gid,
mode_t mask) {
int duplicated_fd = -1;
struct stat st;
/* Note that the slightly different order of fstat() and the checks here and in
* path_chown_recursive(). That's because when we open the dirctory ourselves we can specify
* O_DIRECTORY and we always want to ensure we are operating on a directory before deciding whether
* the operation is otherwise redundant. */
if (fstat(fd, &st) < 0)
return -errno;
if (!S_ISDIR(st.st_mode))
return -ENOTDIR;
if (!uid_is_valid(uid) && !gid_is_valid(gid) && (mask & 07777) == 07777)
return 0; /* nothing to do */
/* Shortcut, as above */
if ((!uid_is_valid(uid) || st.st_uid == uid) &&
(!gid_is_valid(gid) || st.st_gid == gid) &&
((st.st_mode & ~mask & 07777) == 0))
return 0;
/* Let's duplicate the fd here, as opendir() wants to take possession of it and close it afterwards */
duplicated_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
if (duplicated_fd < 0)
return -errno;
return chown_recursive_internal(duplicated_fd, &st, uid, gid, mask); /* fd donated even on failure */
}

View File

@ -4,3 +4,5 @@
#include <sys/types.h>
int path_chown_recursive(const char *path, uid_t uid, gid_t gid, mode_t mask);
int fd_chown_recursive(int fd, uid_t uid, gid_t gid, mode_t mask);

View File

@ -37,6 +37,8 @@ shared_sources = files('''
cgroup-setup.h
cgroup-show.c
cgroup-show.h
chown-recursive.c
chown-recursive.h
clean-ipc.c
clean-ipc.h
clock-util.c

View File

@ -1193,6 +1193,15 @@ int varlink_close(Varlink *v) {
return 1;
}
Varlink* varlink_close_unref(Varlink *v) {
if (!v)
return NULL;
(void) varlink_close(v);
return varlink_unref(v);
}
Varlink* varlink_flush_close_unref(Varlink *v) {
if (!v)
@ -1200,7 +1209,6 @@ Varlink* varlink_flush_close_unref(Varlink *v) {
(void) varlink_flush(v);
(void) varlink_close(v);
return varlink_unref(v);
}

View File

@ -73,6 +73,7 @@ int varlink_flush(Varlink *v);
int varlink_close(Varlink *v);
Varlink* varlink_flush_close_unref(Varlink *v);
Varlink* varlink_close_unref(Varlink *v);
/* Enqueue method call, not expecting a reply */
int varlink_send(Varlink *v, const char *method, JsonVariant *parameters);
@ -152,6 +153,7 @@ int varlink_server_set_connections_max(VarlinkServer *s, unsigned m);
int varlink_server_set_description(VarlinkServer *s, const char *description);
DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_close_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_flush_close_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(VarlinkServer *, varlink_server_unref);