mirror of
https://github.com/systemd/systemd
synced 2026-03-25 16:25:04 +01:00
Compare commits
19 Commits
12f76c3b38
...
468d9bc901
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
468d9bc901 | ||
|
|
7b58fcdd70 | ||
|
|
61a6aa21a5 | ||
|
|
8186022c9d | ||
|
|
0ff605665a | ||
|
|
ed3d3af148 | ||
|
|
351716e111 | ||
|
|
ddb6eeafe2 | ||
|
|
48a01cd934 | ||
|
|
6e1e4b59f9 | ||
|
|
3832cb90ba | ||
|
|
12a7f04a2b | ||
|
|
d93857ae09 | ||
|
|
138f761904 | ||
|
|
d8167c5212 | ||
|
|
5231ec50e9 | ||
|
|
6c8ba239d5 | ||
|
|
dfd73ccb14 | ||
|
|
abf062674e |
28
meson.build
28
meson.build
@ -1787,6 +1787,34 @@ if conf.get('HAVE_LIBCRYPTSETUP_PLUGINS') == 1
|
|||||||
install : true,
|
install : true,
|
||||||
install_dir : libcryptsetup_plugins_dir)
|
install_dir : libcryptsetup_plugins_dir)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if conf.get('HAVE_LIBFIDO2') == 1
|
||||||
|
cryptsetup_token_systemd_fido2 = shared_library(
|
||||||
|
'cryptsetup-token-systemd-fido2',
|
||||||
|
link_args : ['-shared',
|
||||||
|
'-Wl,--version-script=' + cryptsetup_token_sym_path],
|
||||||
|
dependencies : libshared_deps + [libcryptsetup, versiondep],
|
||||||
|
link_with : [libshared],
|
||||||
|
link_whole : [cryptsetup_token_systemd_fido2_static],
|
||||||
|
link_depends : cryptsetup_token_sym,
|
||||||
|
install_rpath : rootlibexecdir,
|
||||||
|
install : true,
|
||||||
|
install_dir : libcryptsetup_plugins_dir)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if conf.get('HAVE_P11KIT') == 1
|
||||||
|
cryptsetup_token_systemd_pkcs11 = shared_library(
|
||||||
|
'cryptsetup-token-systemd-pkcs11',
|
||||||
|
link_args : ['-shared',
|
||||||
|
'-Wl,--version-script=' + cryptsetup_token_sym_path],
|
||||||
|
dependencies : libshared_deps + [libcryptsetup, versiondep],
|
||||||
|
link_with : [libshared],
|
||||||
|
link_whole : [cryptsetup_token_systemd_pkcs11_static],
|
||||||
|
link_depends : cryptsetup_token_sym,
|
||||||
|
install_rpath : rootlibexecdir,
|
||||||
|
install : true,
|
||||||
|
install_dir : libcryptsetup_plugins_dir)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
|
|||||||
@ -433,11 +433,9 @@ bool fdname_is_valid(const char *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd_get_path(int fd, char **ret) {
|
int fd_get_path(int fd, char **ret) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = readlink_malloc(FORMAT_PROC_FD_PATH(fd), ret);
|
||||||
r = readlink_malloc(procfs_path, ret);
|
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT) {
|
||||||
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
|
/* ENOENT can mean two things: that the fd does not exist or that /proc is not mounted. Let's make
|
||||||
* things debuggable and distinguish the two. */
|
* things debuggable and distinguish the two. */
|
||||||
@ -647,7 +645,6 @@ finish:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fd_reopen(int fd, int flags) {
|
int fd_reopen(int fd, int flags) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
int new_fd;
|
int new_fd;
|
||||||
|
|
||||||
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
||||||
@ -657,8 +654,7 @@ int fd_reopen(int fd, int flags) {
|
|||||||
*
|
*
|
||||||
* This implicitly resets the file read index to 0. */
|
* This implicitly resets the file read index to 0. */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
|
||||||
new_fd = open(procfs_path, flags);
|
|
||||||
if (new_fd < 0) {
|
if (new_fd < 0) {
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "stdio-util.h"
|
||||||
|
|
||||||
/* maximum length of fdname */
|
/* maximum length of fdname */
|
||||||
#define FDNAME_MAX 255
|
#define FDNAME_MAX 255
|
||||||
@ -104,7 +105,20 @@ static inline int make_null_stdio(void) {
|
|||||||
0; \
|
0; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
int fd_reopen(int fd, int flags);
|
int fd_reopen(int fd, int flags);
|
||||||
int read_nr_open(void);
|
int read_nr_open(void);
|
||||||
int btrfs_defrag_fd(int fd);
|
int btrfs_defrag_fd(int fd);
|
||||||
|
|
||||||
|
/* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
|
||||||
|
#define PROC_FD_PATH_MAX \
|
||||||
|
(STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int))
|
||||||
|
|
||||||
|
static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int fd) {
|
||||||
|
assert(buf);
|
||||||
|
assert(fd >= 0);
|
||||||
|
assert_se(snprintf_ok(buf, PROC_FD_PATH_MAX, "/proc/self/fd/%i", fd));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FORMAT_PROC_FD_PATH(fd) \
|
||||||
|
format_proc_fd_path((char[PROC_FD_PATH_MAX]) {}, (fd))
|
||||||
|
|||||||
@ -721,8 +721,6 @@ int read_full_file_full(
|
|||||||
if (dir_fd == AT_FDCWD)
|
if (dir_fd == AT_FDCWD)
|
||||||
r = sockaddr_un_set_path(&sa.un, filename);
|
r = sockaddr_un_set_path(&sa.un, filename);
|
||||||
else {
|
else {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
/* If we shall operate relative to some directory, then let's use O_PATH first to
|
||||||
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
* open the socket inode, and then connect to it via /proc/self/fd/. We have to do
|
||||||
* this since there's not connectat() that takes a directory fd as first arg. */
|
* this since there's not connectat() that takes a directory fd as first arg. */
|
||||||
@ -731,8 +729,7 @@ int read_full_file_full(
|
|||||||
if (dfd < 0)
|
if (dfd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", dfd);
|
r = sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(dfd));
|
||||||
r = sockaddr_un_set_path(&sa.un, procfs_path);
|
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -308,14 +308,11 @@ int fchmod_umask(int fd, mode_t m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int fchmod_opath(int fd, mode_t m) {
|
int fchmod_opath(int fd, mode_t m) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* This function operates also on fd that might have been opened with
|
/* This function operates also on fd that might have been opened with
|
||||||
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
|
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
|
||||||
* fchownat() does. */
|
* fchownat() does. */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (chmod(FORMAT_PROC_FD_PATH(fd), m) < 0) {
|
||||||
if (chmod(procfs_path, m) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -329,12 +326,9 @@ int fchmod_opath(int fd, mode_t m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int futimens_opath(int fd, const struct timespec ts[2]) {
|
int futimens_opath(int fd, const struct timespec ts[2]) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
|
|
||||||
/* Similar to fchmod_path() but for futimens() */
|
/* Similar to fchmod_path() but for futimens() */
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, 0) < 0) {
|
||||||
if (utimensat(AT_FDCWD, procfs_path, ts, 0) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -380,7 +374,6 @@ int fd_warn_permissions(const char *path, int fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
|
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
|
||||||
char fdpath[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
int r, ret = 0;
|
int r, ret = 0;
|
||||||
|
|
||||||
@ -412,8 +405,6 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||||||
/* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
|
/* Let's make a path from the fd, and operate on that. With this logic, we can adjust the access mode,
|
||||||
* ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
|
* ownership and time of the file node in all cases, even if the fd refers to an O_PATH object — which is
|
||||||
* something fchown(), fchmod(), futimensat() don't allow. */
|
* something fchown(), fchmod(), futimensat() don't allow. */
|
||||||
xsprintf(fdpath, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
ret = fchmod_and_chown(fd, mode, uid, gid);
|
ret = fchmod_and_chown(fd, mode, uid, gid);
|
||||||
|
|
||||||
if (stamp != USEC_INFINITY) {
|
if (stamp != USEC_INFINITY) {
|
||||||
@ -421,9 +412,9 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi
|
|||||||
|
|
||||||
timespec_store(&ts[0], stamp);
|
timespec_store(&ts[0], stamp);
|
||||||
ts[1] = ts[0];
|
ts[1] = ts[0];
|
||||||
r = utimensat(AT_FDCWD, fdpath, ts, 0);
|
r = utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, 0);
|
||||||
} else
|
} else
|
||||||
r = utimensat(AT_FDCWD, fdpath, NULL, 0);
|
r = utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), NULL, 0);
|
||||||
if (r < 0 && ret >= 0)
|
if (r < 0 && ret >= 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -703,13 +694,10 @@ int unlink_or_warn(const char *filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
int wd;
|
int wd;
|
||||||
|
|
||||||
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
|
/* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
|
||||||
xsprintf(path, "/proc/self/fd/%i", what);
|
wd = inotify_add_watch(fd, FORMAT_PROC_FD_PATH(what), mask);
|
||||||
|
|
||||||
wd = inotify_add_watch(fd, path, mask);
|
|
||||||
if (wd < 0)
|
if (wd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -1156,7 +1144,6 @@ int chase_symlinks_and_opendir(
|
|||||||
char **ret_path,
|
char **ret_path,
|
||||||
DIR **ret_dir) {
|
DIR **ret_dir) {
|
||||||
|
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_close_ int path_fd = -1;
|
_cleanup_close_ int path_fd = -1;
|
||||||
_cleanup_free_ char *p = NULL;
|
_cleanup_free_ char *p = NULL;
|
||||||
DIR *d;
|
DIR *d;
|
||||||
@ -1182,8 +1169,7 @@ int chase_symlinks_and_opendir(
|
|||||||
return r;
|
return r;
|
||||||
assert(path_fd >= 0);
|
assert(path_fd >= 0);
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", path_fd);
|
d = opendir(FORMAT_PROC_FD_PATH(path_fd));
|
||||||
d = opendir(procfs_path);
|
|
||||||
if (!d)
|
if (!d)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -1237,12 +1223,9 @@ int chase_symlinks_and_stat(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int access_fd(int fd, int mode) {
|
int access_fd(int fd, int mode) {
|
||||||
char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
|
||||||
|
|
||||||
/* Like access() but operates on an already open fd */
|
/* Like access() but operates on an already open fd */
|
||||||
|
|
||||||
xsprintf(p, "/proc/self/fd/%i", fd);
|
if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
|
||||||
if (access(p, mode) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
|||||||
@ -89,9 +89,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
|
|||||||
/* Can't setns to your own userns, since then you could escalate from non-root to root in
|
/* Can't setns to your own userns, since then you could escalate from non-root to root in
|
||||||
* your own namespace, so check if namespaces are equal before attempting to enter. */
|
* your own namespace, so check if namespaces are equal before attempting to enter. */
|
||||||
|
|
||||||
char userns_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
r = files_same(FORMAT_PROC_FD_PATH(userns_fd), "/proc/self/ns/user", 0);
|
||||||
xsprintf(userns_fd_path, "/proc/self/fd/%d", userns_fd);
|
|
||||||
r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r)
|
if (r)
|
||||||
|
|||||||
@ -10,7 +10,12 @@
|
|||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
|
|
||||||
#define snprintf_ok(buf, len, fmt, ...) \
|
#define snprintf_ok(buf, len, fmt, ...) \
|
||||||
((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
|
({ \
|
||||||
|
char *_buf = (buf); \
|
||||||
|
size_t _len = (len); \
|
||||||
|
int _snpf = snprintf(_buf, _len, (fmt), __VA_ARGS__); \
|
||||||
|
_snpf >= 0 && (size_t) _snpf < _len ? _buf : NULL; \
|
||||||
|
})
|
||||||
|
|
||||||
#define xsprintf(buf, fmt, ...) \
|
#define xsprintf(buf, fmt, ...) \
|
||||||
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
assert_message_se(snprintf_ok(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__), "xsprintf: " #buf "[] must be big enough")
|
||||||
|
|||||||
@ -300,11 +300,7 @@ int link_tmpfile(int fd, const char *path, const char *target) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else {
|
} else {
|
||||||
char proc_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
|
if (linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
|
||||||
|
|
||||||
xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -108,11 +108,10 @@ static int getxattrat_fake_prepare(
|
|||||||
int dirfd,
|
int dirfd,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
int flags,
|
int flags,
|
||||||
char ret_fn[static STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1],
|
char ret_fn[static PROC_FD_PATH_MAX],
|
||||||
int *ret_fd) {
|
int *ret_fd) {
|
||||||
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
|
||||||
assert(ret_fn);
|
assert(ret_fn);
|
||||||
assert(ret_fd);
|
assert(ret_fd);
|
||||||
|
|
||||||
@ -125,13 +124,15 @@ static int getxattrat_fake_prepare(
|
|||||||
if (!(flags & AT_EMPTY_PATH))
|
if (!(flags & AT_EMPTY_PATH))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", dirfd);
|
assert(dirfd >= 0);
|
||||||
|
|
||||||
|
format_proc_fd_path(ret_fn, dirfd);
|
||||||
} else {
|
} else {
|
||||||
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
snprintf(ret_fn, STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1, "/proc/self/fd/%i", fd);
|
format_proc_fd_path(ret_fn, fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pass the FD to the caller, since in case we do openat() the filename depends on it. */
|
/* Pass the FD to the caller, since in case we do openat() the filename depends on it. */
|
||||||
@ -148,8 +149,8 @@ int fgetxattrat_fake(
|
|||||||
int flags,
|
int flags,
|
||||||
size_t *ret_size) {
|
size_t *ret_size) {
|
||||||
|
|
||||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
char fn[PROC_FD_PATH_MAX];
|
||||||
ssize_t l;
|
ssize_t l;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -172,8 +173,8 @@ int fgetxattrat_fake_malloc(
|
|||||||
int flags,
|
int flags,
|
||||||
char **value) {
|
char **value) {
|
||||||
|
|
||||||
char fn[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
|
char fn[PROC_FD_PATH_MAX];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
|
r = getxattrat_fake_prepare(dirfd, filename, flags, fn, &fd);
|
||||||
|
|||||||
@ -916,7 +916,6 @@ static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int service_load_pid_file(Service *s, bool may_warn) {
|
static int service_load_pid_file(Service *s, bool may_warn) {
|
||||||
char procfs[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
bool questionable_pid_file = false;
|
bool questionable_pid_file = false;
|
||||||
_cleanup_free_ char *k = NULL;
|
_cleanup_free_ char *k = NULL;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
@ -945,8 +944,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
|
|||||||
|
|
||||||
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
|
/* Let's read the PID file now that we chased it down. But we need to convert the O_PATH fd
|
||||||
* chase_symlinks() returned us into a proper fd first. */
|
* chase_symlinks() returned us into a proper fd first. */
|
||||||
xsprintf(procfs, "/proc/self/fd/%i", fd);
|
r = read_one_line_file(FORMAT_PROC_FD_PATH(fd), &k);
|
||||||
r = read_one_line_file(procfs, &k);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(UNIT(s), r,
|
return log_unit_error_errno(UNIT(s), r,
|
||||||
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
|
"Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
|
||||||
|
|||||||
@ -24,83 +24,6 @@
|
|||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
struct pkcs11_callback_data {
|
|
||||||
const char *friendly_name;
|
|
||||||
usec_t until;
|
|
||||||
void *encrypted_key;
|
|
||||||
size_t encrypted_key_size;
|
|
||||||
void *decrypted_key;
|
|
||||||
size_t decrypted_key_size;
|
|
||||||
bool free_encrypted_key;
|
|
||||||
bool headless;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) {
|
|
||||||
erase_and_free(data->decrypted_key);
|
|
||||||
|
|
||||||
if (data->free_encrypted_key)
|
|
||||||
free(data->encrypted_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pkcs11_callback(
|
|
||||||
CK_FUNCTION_LIST *m,
|
|
||||||
CK_SESSION_HANDLE session,
|
|
||||||
CK_SLOT_ID slot_id,
|
|
||||||
const CK_SLOT_INFO *slot_info,
|
|
||||||
const CK_TOKEN_INFO *token_info,
|
|
||||||
P11KitUri *uri,
|
|
||||||
void *userdata) {
|
|
||||||
|
|
||||||
struct pkcs11_callback_data *data = userdata;
|
|
||||||
CK_OBJECT_HANDLE object;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(m);
|
|
||||||
assert(slot_info);
|
|
||||||
assert(token_info);
|
|
||||||
assert(uri);
|
|
||||||
assert(data);
|
|
||||||
|
|
||||||
/* Called for every token matching our URI */
|
|
||||||
|
|
||||||
r = pkcs11_token_login(
|
|
||||||
m,
|
|
||||||
session,
|
|
||||||
slot_id,
|
|
||||||
token_info,
|
|
||||||
data->friendly_name,
|
|
||||||
"drive-harddisk",
|
|
||||||
"pkcs11-pin",
|
|
||||||
"cryptsetup.pkcs11-pin",
|
|
||||||
data->until,
|
|
||||||
data->headless,
|
|
||||||
NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
|
|
||||||
* token, if it supports that. It should be cheap, given that we already are talking to it anyway and
|
|
||||||
* shouldn't hurt. */
|
|
||||||
(void) pkcs11_token_acquire_rng(m, session);
|
|
||||||
|
|
||||||
r = pkcs11_token_find_private_key(m, session, uri, &object);
|
|
||||||
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);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int decrypt_pkcs11_key(
|
int decrypt_pkcs11_key(
|
||||||
const char *volume_name,
|
const char *volume_name,
|
||||||
const char *friendly_name,
|
const char *friendly_name,
|
||||||
@ -115,7 +38,7 @@ int decrypt_pkcs11_key(
|
|||||||
void **ret_decrypted_key,
|
void **ret_decrypted_key,
|
||||||
size_t *ret_decrypted_key_size) {
|
size_t *ret_decrypted_key_size) {
|
||||||
|
|
||||||
_cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = {
|
_cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
|
||||||
.friendly_name = friendly_name,
|
.friendly_name = friendly_name,
|
||||||
.until = until,
|
.until = until,
|
||||||
.headless = headless,
|
.headless = headless,
|
||||||
@ -155,7 +78,7 @@ int decrypt_pkcs11_key(
|
|||||||
data.free_encrypted_key = true;
|
data.free_encrypted_key = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = pkcs11_find_token(pkcs11_uri, pkcs11_callback, &data);
|
r = pkcs11_find_token(pkcs11_uri, pkcs11_crypt_device_callback, &data);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,224 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libcryptsetup.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cryptsetup-token.h"
|
||||||
|
#include "cryptsetup-token-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "luks2-fido2.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#define TOKEN_NAME "systemd-fido2"
|
||||||
|
#define TOKEN_VERSION_MAJOR "1"
|
||||||
|
#define TOKEN_VERSION_MINOR "0"
|
||||||
|
|
||||||
|
/* for libcryptsetup debug purpose */
|
||||||
|
_public_ const char *cryptsetup_token_version(void) {
|
||||||
|
return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
_public_ int cryptsetup_token_open_pin(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
int token /* is always >= 0 */,
|
||||||
|
const char *pin,
|
||||||
|
size_t pin_size,
|
||||||
|
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||||
|
size_t *password_len,
|
||||||
|
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
const char *json;
|
||||||
|
_cleanup_(erase_and_freep) char *pin_string = NULL;
|
||||||
|
|
||||||
|
assert(!pin || pin_size);
|
||||||
|
assert(token >= 0);
|
||||||
|
|
||||||
|
/* This must not fail at this moment (internal error) */
|
||||||
|
r = crypt_token_json_get(cd, token, &json);
|
||||||
|
assert(token == r);
|
||||||
|
assert(json);
|
||||||
|
|
||||||
|
if (pin && memchr(pin, 0, pin_size - 1))
|
||||||
|
return crypt_log_error_errno(cd, ENOANO, "PIN must be characters string.");
|
||||||
|
|
||||||
|
/* pin was passed as pin = pin, pin_size = strlen(pin). We need to add terminating
|
||||||
|
* NULL byte to addressable memory*/
|
||||||
|
if (pin && pin[pin_size-1] != '\0') {
|
||||||
|
pin_string = strndup(pin, pin_size);
|
||||||
|
if (!pin_string)
|
||||||
|
return crypt_log_oom(cd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acquire_luks2_key(cd, json, (const char *)usrptr, pin_string ?: pin, password, password_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called from within following libcryptsetup calls
|
||||||
|
* provided conditions further below are met:
|
||||||
|
*
|
||||||
|
* crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-fido2'):
|
||||||
|
*
|
||||||
|
* - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
|
||||||
|
* (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
|
||||||
|
* and token is assigned to at least single keyslot).
|
||||||
|
*
|
||||||
|
* - if plugin defines validate funtion (see cryptsetup_token_validate below) it must have
|
||||||
|
* passed the check (aka return 0)
|
||||||
|
*/
|
||||||
|
_public_ int cryptsetup_token_open(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
int token /* is always >= 0 */,
|
||||||
|
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||||
|
size_t *password_len,
|
||||||
|
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||||
|
|
||||||
|
return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libcryptsetup callback for memory deallocation of 'password' parameter passed in
|
||||||
|
* any crypt_token_open_* plugin function
|
||||||
|
*/
|
||||||
|
_public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
|
||||||
|
erase_and_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prints systemd-fido2 token content in crypt_dump().
|
||||||
|
* 'type' and 'keyslots' fields are printed by libcryptsetup
|
||||||
|
*/
|
||||||
|
_public_ void cryptsetup_token_dump(
|
||||||
|
struct crypt_device *cd /* is always LUKS2 context */,
|
||||||
|
const char *json /* validated 'systemd-tpm2' token if cryptsetup_token_validate is defined */) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
Fido2EnrollFlags required;
|
||||||
|
size_t cid_size, salt_size;
|
||||||
|
const char *client_pin_req_str, *up_req_str, *uv_req_str;
|
||||||
|
_cleanup_free_ void *cid = NULL, *salt = NULL;
|
||||||
|
_cleanup_free_ char *rp_id = NULL, *cid_str = NULL, *salt_str = NULL;
|
||||||
|
|
||||||
|
assert(json);
|
||||||
|
|
||||||
|
r = parse_luks2_fido2_data(cd, json, &rp_id, &salt, &salt_size, &cid, &cid_size, &required);
|
||||||
|
if (r < 0)
|
||||||
|
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
|
||||||
|
|
||||||
|
r = crypt_dump_buffer_to_hex_string(cid, cid_size, &cid_str);
|
||||||
|
if (r < 0)
|
||||||
|
return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
|
||||||
|
|
||||||
|
r = crypt_dump_buffer_to_hex_string(salt, salt_size, &salt_str);
|
||||||
|
if (r < 0)
|
||||||
|
return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
|
||||||
|
|
||||||
|
if (required & FIDO2ENROLL_PIN)
|
||||||
|
client_pin_req_str = "true";
|
||||||
|
else if (required & FIDO2ENROLL_PIN_IF_NEEDED)
|
||||||
|
client_pin_req_str = NULL;
|
||||||
|
else
|
||||||
|
client_pin_req_str = "false";
|
||||||
|
|
||||||
|
if (required & FIDO2ENROLL_UP)
|
||||||
|
up_req_str = "true";
|
||||||
|
else if (required & FIDO2ENROLL_UP_IF_NEEDED)
|
||||||
|
up_req_str = NULL;
|
||||||
|
else
|
||||||
|
up_req_str = "false";
|
||||||
|
|
||||||
|
if (required & FIDO2ENROLL_UV)
|
||||||
|
uv_req_str = "true";
|
||||||
|
else if (required & FIDO2ENROLL_UV_OMIT)
|
||||||
|
uv_req_str = NULL;
|
||||||
|
else
|
||||||
|
uv_req_str = "false";
|
||||||
|
|
||||||
|
crypt_log(cd, "\tfido2-credential:" CRYPT_DUMP_LINE_SEP "%s\n", cid_str);
|
||||||
|
crypt_log(cd, "\tfido2-salt: %s\n", salt_str);
|
||||||
|
|
||||||
|
/* optional fields */
|
||||||
|
if (rp_id)
|
||||||
|
crypt_log(cd, "\tfido2-rp: %s\n", rp_id);
|
||||||
|
if (client_pin_req_str)
|
||||||
|
crypt_log(cd, "\tfido2-clientPin-required:" CRYPT_DUMP_LINE_SEP "%s\n",
|
||||||
|
client_pin_req_str);
|
||||||
|
if (up_req_str)
|
||||||
|
crypt_log(cd, "\tfido2-up-required:" CRYPT_DUMP_LINE_SEP "%s\n", up_req_str);
|
||||||
|
if (uv_req_str)
|
||||||
|
crypt_log(cd, "\tfido2-uv-required:" CRYPT_DUMP_LINE_SEP "%s\n", uv_req_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note:
|
||||||
|
* If plugin is available in library path, it's called in before following libcryptsetup calls:
|
||||||
|
*
|
||||||
|
* crypt_token_json_set, crypt_dump, any crypt_activate_by_token_* flavour
|
||||||
|
*/
|
||||||
|
_public_ int cryptsetup_token_validate(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-tpm2' */) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
JsonVariant *w;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
|
||||||
|
assert(json);
|
||||||
|
|
||||||
|
r = json_parse(json, 0, &v, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m.");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-credential");
|
||||||
|
if (!w || !json_variant_is_string(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data lacks 'fido2-credential' field.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Invalid base64 data in 'fido2-credential' field: %m");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-salt");
|
||||||
|
if (!w || !json_variant_is_string(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data lacks 'fido2-salt' field.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded salt: %m.");
|
||||||
|
|
||||||
|
/* The "rp" field is optional. */
|
||||||
|
w = json_variant_by_key(v, "fido2-rp");
|
||||||
|
if (w && !json_variant_is_string(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data's 'fido2-rp' field is not a string.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "fido2-clientPin-required" field is optional. */
|
||||||
|
w = json_variant_by_key(v, "fido2-clientPin-required");
|
||||||
|
if (w && !json_variant_is_boolean(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data's 'fido2-clientPin-required' field is not a boolean.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "fido2-up-required" field is optional. */
|
||||||
|
w = json_variant_by_key(v, "fido2-up-required");
|
||||||
|
if (w && !json_variant_is_boolean(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data's 'fido2-up-required' field is not a boolean.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "fido2-uv-required" field is optional. */
|
||||||
|
w = json_variant_by_key(v, "fido2-uv-required");
|
||||||
|
if (w && !json_variant_is_boolean(w)) {
|
||||||
|
crypt_log_debug(cd, "FIDO2 token data's 'fido2-uv-required' field is not a boolean.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -0,0 +1,143 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <libcryptsetup.h>
|
||||||
|
|
||||||
|
#include "cryptsetup-token.h"
|
||||||
|
#include "cryptsetup-token-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "luks2-pkcs11.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
#include "pkcs11-util.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
#define TOKEN_NAME "systemd-pkcs11"
|
||||||
|
#define TOKEN_VERSION_MAJOR "1"
|
||||||
|
#define TOKEN_VERSION_MINOR "0"
|
||||||
|
|
||||||
|
/* for libcryptsetup debug purpose */
|
||||||
|
_public_ const char *cryptsetup_token_version(void) {
|
||||||
|
return TOKEN_VERSION_MAJOR "." TOKEN_VERSION_MINOR " systemd-v" STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
_public_ int cryptsetup_token_open_pin(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
int token /* is always >= 0 */,
|
||||||
|
const char *pin,
|
||||||
|
size_t pin_size,
|
||||||
|
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||||
|
size_t *password_len,
|
||||||
|
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||||
|
|
||||||
|
const char *json;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(!pin || pin_size);
|
||||||
|
assert(token >= 0);
|
||||||
|
|
||||||
|
/* This must not fail at this moment (internal error) */
|
||||||
|
r = crypt_token_json_get(cd, token, &json);
|
||||||
|
assert(token == r);
|
||||||
|
assert(json);
|
||||||
|
|
||||||
|
return acquire_luks2_key(cd, json, usrptr, pin, pin_size, password, password_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is called from within following libcryptsetup calls
|
||||||
|
* provided conditions further below are met:
|
||||||
|
*
|
||||||
|
* crypt_activate_by_token(), crypt_activate_by_token_type(type == 'systemd-pkcs11'):
|
||||||
|
*
|
||||||
|
* - token is assigned to at least one luks2 keyslot eligible to activate LUKS2 device
|
||||||
|
* (alternatively: name is set to null, flags contains CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY
|
||||||
|
* and token is assigned to at least single keyslot).
|
||||||
|
*
|
||||||
|
* - if plugin defines validate funtion (see cryptsetup_token_validate below) it must have
|
||||||
|
* passed the check (aka return 0)
|
||||||
|
*/
|
||||||
|
_public_ int cryptsetup_token_open(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
int token /* is always >= 0 */,
|
||||||
|
char **password, /* freed by cryptsetup_token_buffer_free */
|
||||||
|
size_t *password_len,
|
||||||
|
void *usrptr /* plugin defined parameter passed to crypt_activate_by_token*() API */) {
|
||||||
|
|
||||||
|
return cryptsetup_token_open_pin(cd, token, NULL, 0, password, password_len, usrptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* libcryptsetup callback for memory deallocation of 'password' parameter passed in
|
||||||
|
* any crypt_token_open_* plugin function
|
||||||
|
*/
|
||||||
|
_public_ void cryptsetup_token_buffer_free(void *buffer, size_t buffer_len) {
|
||||||
|
erase_and_free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prints systemd-pkcs11 token content in crypt_dump().
|
||||||
|
* 'type' and 'keyslots' fields are printed by libcryptsetup
|
||||||
|
*/
|
||||||
|
_public_ void cryptsetup_token_dump(
|
||||||
|
struct crypt_device *cd /* is always LUKS2 context */,
|
||||||
|
const char *json /* validated 'systemd-pkcs11' token if cryptsetup_token_validate is defined */) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
size_t pkcs11_key_size;
|
||||||
|
_cleanup_free_ char *pkcs11_uri = NULL, *key_str = NULL;
|
||||||
|
_cleanup_free_ void *pkcs11_key = NULL;
|
||||||
|
|
||||||
|
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &pkcs11_key, &pkcs11_key_size);
|
||||||
|
if (r < 0)
|
||||||
|
return (void) crypt_log_debug_errno(cd, r, "Failed to parse " TOKEN_NAME " metadata: %m.");
|
||||||
|
|
||||||
|
r = crypt_dump_buffer_to_hex_string(pkcs11_key, pkcs11_key_size, &key_str);
|
||||||
|
if (r < 0)
|
||||||
|
return (void) crypt_log_debug_errno(cd, r, "Can not dump " TOKEN_NAME " content: %m");
|
||||||
|
|
||||||
|
crypt_log(cd, "\tpkcs11-uri: %s\n", pkcs11_uri);
|
||||||
|
crypt_log(cd, "\tpkcs11-key: %s\n", key_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note:
|
||||||
|
* If plugin is available in library path, it's called in before following libcryptsetup calls:
|
||||||
|
*
|
||||||
|
* crypt_token_json_set, crypt_dump, any crypt_activate_by_token_* flavour
|
||||||
|
*/
|
||||||
|
_public_ int cryptsetup_token_validate(
|
||||||
|
struct crypt_device *cd, /* is always LUKS2 context */
|
||||||
|
const char *json /* contains valid 'type' and 'keyslots' fields. 'type' is 'systemd-pkcs11' */) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
JsonVariant *w;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
|
||||||
|
r = json_parse(json, 0, &v, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Could not parse " TOKEN_NAME " json object: %m.");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "pkcs11-uri");
|
||||||
|
if (!w || !json_variant_is_string(w)) {
|
||||||
|
crypt_log_debug(cd, "PKCS#11 token data lacks 'pkcs11-uri' field.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pkcs11_uri_valid(json_variant_string(w))) {
|
||||||
|
crypt_log_debug(cd, "PKCS#11 token data contains invalid PKCS#11 URI.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "pkcs11-key");
|
||||||
|
if (!w || !json_variant_is_string(w)) {
|
||||||
|
crypt_log_debug(cd, "PKCS#11 token data lacks 'pkcs11-key' field.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -2,23 +2,34 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <libcryptsetup.h>
|
||||||
|
|
||||||
/* crypt_dump() internal indentation magic */
|
/* crypt_dump() internal indentation magic */
|
||||||
#define CRYPT_DUMP_LINE_SEP "\n\t "
|
#define CRYPT_DUMP_LINE_SEP "\n\t "
|
||||||
|
|
||||||
#define crypt_log_debug(cd, ...) crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__)
|
#define crypt_log_debug(cd, ...) crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__)
|
||||||
#define crypt_log_error(cd, ...) crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__)
|
#define crypt_log_error(cd, ...) crypt_logf(cd, CRYPT_LOG_ERROR, __VA_ARGS__)
|
||||||
|
#define crypt_log_verbose(cd, ...) crypt_logf(cd, CRYPT_LOG_VERBOSE, __VA_ARGS__)
|
||||||
#define crypt_log(cd, ...) crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__)
|
#define crypt_log(cd, ...) crypt_logf(cd, CRYPT_LOG_NORMAL, __VA_ARGS__)
|
||||||
|
|
||||||
#define crypt_log_debug_errno(cd, e, ...) ({ \
|
#define crypt_log_full_errno(cd, e, lvl, ...) ({ \
|
||||||
int _e = abs(e), _s = errno; \
|
int _e = abs(e), _s = errno; \
|
||||||
errno = _e; \
|
errno = _e; \
|
||||||
crypt_logf(cd, CRYPT_LOG_DEBUG, __VA_ARGS__); \
|
crypt_logf(cd, lvl, __VA_ARGS__); \
|
||||||
errno = _s; \
|
errno = _s; \
|
||||||
-_e; \
|
-_e; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#define crypt_log_debug_errno(cd, e, ...) \
|
||||||
|
crypt_log_full_errno(cd, e, CRYPT_LOG_DEBUG, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define crypt_log_error_errno(cd, e, ...) \
|
||||||
|
crypt_log_full_errno(cd, e, CRYPT_LOG_ERROR, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define crypt_log_oom(cd) crypt_log_error_errno(cd, ENOMEM, "Not enough memory.")
|
||||||
|
|
||||||
int crypt_dump_buffer_to_hex_string(
|
int crypt_dump_buffer_to_hex_string(
|
||||||
const char *buf,
|
const char *buf,
|
||||||
size_t buf_size,
|
size_t buf_size,
|
||||||
|
|||||||
@ -8,6 +8,10 @@ const char *cryptsetup_token_version(void);
|
|||||||
int cryptsetup_token_open(struct crypt_device *cd, int token,
|
int cryptsetup_token_open(struct crypt_device *cd, int token,
|
||||||
char **password, size_t *password_len, void *usrptr);
|
char **password, size_t *password_len, void *usrptr);
|
||||||
|
|
||||||
|
int cryptsetup_token_open_pin(struct crypt_device *cd, int token,
|
||||||
|
const char *pin, size_t pin_size,
|
||||||
|
char **password, size_t *password_len, void *usrptr);
|
||||||
|
|
||||||
void cryptsetup_token_dump(struct crypt_device *cd, const char *json);
|
void cryptsetup_token_dump(struct crypt_device *cd, const char *json);
|
||||||
|
|
||||||
int cryptsetup_token_validate(struct crypt_device *cd, const char *json);
|
int cryptsetup_token_validate(struct crypt_device *cd, const char *json);
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
CRYPTSETUP_TOKEN_1.0 {
|
CRYPTSETUP_TOKEN_1.0 {
|
||||||
global:
|
global:
|
||||||
cryptsetup_token_open;
|
cryptsetup_token_open;
|
||||||
|
cryptsetup_token_open_pin;
|
||||||
cryptsetup_token_buffer_free;
|
cryptsetup_token_buffer_free;
|
||||||
cryptsetup_token_validate;
|
cryptsetup_token_validate;
|
||||||
cryptsetup_token_dump;
|
cryptsetup_token_dump;
|
||||||
|
|||||||
158
src/cryptsetup/cryptsetup-tokens/luks2-fido2.c
Normal file
158
src/cryptsetup/cryptsetup-tokens/luks2-fido2.c
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <libcryptsetup.h>
|
||||||
|
|
||||||
|
#include "cryptsetup-token-util.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "luks2-fido2.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
#include "strv.h"
|
||||||
|
|
||||||
|
int acquire_luks2_key(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
const char *device,
|
||||||
|
const char *pin,
|
||||||
|
char **ret_keyslot_passphrase,
|
||||||
|
size_t *ret_keyslot_passphrase_size) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
Fido2EnrollFlags required;
|
||||||
|
size_t cid_size, salt_size, decrypted_key_size;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
_cleanup_free_ void *cid = NULL, *salt = NULL;
|
||||||
|
_cleanup_free_ char *rp_id = NULL;
|
||||||
|
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||||
|
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||||
|
_cleanup_strv_free_erase_ char **pins = NULL;
|
||||||
|
|
||||||
|
assert(ret_keyslot_passphrase);
|
||||||
|
assert(ret_keyslot_passphrase_size);
|
||||||
|
|
||||||
|
r = parse_luks2_fido2_data(cd, json, &rp_id, &salt, &salt_size, &cid, &cid_size, &required);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (pin) {
|
||||||
|
pins = strv_new(pin);
|
||||||
|
if (!pins)
|
||||||
|
return crypt_log_oom(cd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* configured to use pin but none was provided */
|
||||||
|
if ((required & FIDO2ENROLL_PIN) && strv_isempty(pins))
|
||||||
|
return -ENOANO;
|
||||||
|
|
||||||
|
r = fido2_use_hmac_hash(
|
||||||
|
device,
|
||||||
|
rp_id ?: "io.systemd.cryptsetup",
|
||||||
|
salt, salt_size,
|
||||||
|
cid, cid_size,
|
||||||
|
pins,
|
||||||
|
required,
|
||||||
|
&decrypted_key,
|
||||||
|
&decrypted_key_size);
|
||||||
|
if (r == -ENOLCK) /* libcryptsetup returns -ENOANO also on wrong pin */
|
||||||
|
r = -ENOANO;
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Before using this key as passphrase we base64 encode it, for compat with homed */
|
||||||
|
r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_error_errno(cd, r, "Can not base64 encode key: %m");
|
||||||
|
|
||||||
|
*ret_keyslot_passphrase = TAKE_PTR(base64_encoded);
|
||||||
|
*ret_keyslot_passphrase_size = strlen(*ret_keyslot_passphrase);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this function expects valid "systemd-fido2" in json */
|
||||||
|
int parse_luks2_fido2_data(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
char **ret_rp_id,
|
||||||
|
void **ret_salt,
|
||||||
|
size_t *ret_salt_size,
|
||||||
|
void **ret_cid,
|
||||||
|
size_t *ret_cid_size,
|
||||||
|
Fido2EnrollFlags *ret_required) {
|
||||||
|
|
||||||
|
_cleanup_free_ void *cid = NULL, *salt = NULL;
|
||||||
|
size_t cid_size = 0, salt_size = 0;
|
||||||
|
_cleanup_free_ char *rp = NULL;
|
||||||
|
int r;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
JsonVariant *w;
|
||||||
|
Fido2EnrollFlags required = 0;
|
||||||
|
|
||||||
|
assert(json);
|
||||||
|
assert(ret_rp_id);
|
||||||
|
assert(ret_salt);
|
||||||
|
assert(ret_salt_size);
|
||||||
|
assert(ret_cid);
|
||||||
|
assert(ret_cid_size);
|
||||||
|
assert(ret_required);
|
||||||
|
|
||||||
|
r = json_parse(json, 0, &v, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_error_errno(cd, r, "Failed to parse JSON token data: %m");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-credential");
|
||||||
|
if (!w)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, &cid, &cid_size);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-credentials' field: %m");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-salt");
|
||||||
|
if (!w)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, &salt, &salt_size);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_error_errno(cd, r, "Failed to parse 'fido2-salt' field: %m");
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-rp");
|
||||||
|
if (w) {
|
||||||
|
/* The "rp" field is optional. */
|
||||||
|
rp = strdup(json_variant_string(w));
|
||||||
|
if (!rp) {
|
||||||
|
crypt_log_error(cd, "Not enough memory.");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-clientPin-required");
|
||||||
|
if (w)
|
||||||
|
/* The "fido2-clientPin-required" field is optional. */
|
||||||
|
SET_FLAG(required, FIDO2ENROLL_PIN, json_variant_boolean(w));
|
||||||
|
else
|
||||||
|
required |= FIDO2ENROLL_PIN_IF_NEEDED; /* compat with 248, where the field was unset */
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-up-required");
|
||||||
|
if (w)
|
||||||
|
/* The "fido2-up-required" field is optional. */
|
||||||
|
SET_FLAG(required, FIDO2ENROLL_UP, json_variant_boolean(w));
|
||||||
|
else
|
||||||
|
required |= FIDO2ENROLL_UP_IF_NEEDED; /* compat with 248 */
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "fido2-uv-required");
|
||||||
|
if (w)
|
||||||
|
/* The "fido2-uv-required" field is optional. */
|
||||||
|
SET_FLAG(required, FIDO2ENROLL_UV, json_variant_boolean(w));
|
||||||
|
else
|
||||||
|
required |= FIDO2ENROLL_UV_OMIT; /* compat with 248 */
|
||||||
|
|
||||||
|
*ret_rp_id = TAKE_PTR(rp);
|
||||||
|
*ret_cid = TAKE_PTR(cid);
|
||||||
|
*ret_cid_size = cid_size;
|
||||||
|
*ret_salt = TAKE_PTR(salt);
|
||||||
|
*ret_salt_size = salt_size;
|
||||||
|
*ret_required = required;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
24
src/cryptsetup/cryptsetup-tokens/luks2-fido2.h
Normal file
24
src/cryptsetup/cryptsetup-tokens/luks2-fido2.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "libfido2-util.h"
|
||||||
|
|
||||||
|
struct crypt_device;
|
||||||
|
|
||||||
|
int acquire_luks2_key(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
const char *device,
|
||||||
|
const char *pin,
|
||||||
|
char **ret_keyslot_passphrase,
|
||||||
|
size_t *ret_keyslot_passphrase_size);
|
||||||
|
|
||||||
|
int parse_luks2_fido2_data(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
char **ret_rp_id,
|
||||||
|
void **ret_salt,
|
||||||
|
size_t *ret_salt_size,
|
||||||
|
void **ret_cid,
|
||||||
|
size_t *ret_cid_size,
|
||||||
|
Fido2EnrollFlags *ret_required);
|
||||||
271
src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
Normal file
271
src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <p11-kit/p11-kit.h>
|
||||||
|
#include <p11-kit/uri.h>
|
||||||
|
|
||||||
|
#include "cryptsetup-token-util.h"
|
||||||
|
#include "escape.h"
|
||||||
|
#include "hexdecoct.h"
|
||||||
|
#include "json.h"
|
||||||
|
#include "luks2-pkcs11.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
#include "pkcs11-util.h"
|
||||||
|
#include "time-util.h"
|
||||||
|
|
||||||
|
struct luks2_pkcs11_callback_data {
|
||||||
|
struct crypt_device *cd;
|
||||||
|
const char *pin;
|
||||||
|
size_t pin_size;
|
||||||
|
void *encrypted_key;
|
||||||
|
size_t encrypted_key_size;
|
||||||
|
void *decrypted_key;
|
||||||
|
size_t decrypted_key_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int luks2_pkcs11_callback(
|
||||||
|
CK_FUNCTION_LIST *m,
|
||||||
|
CK_SESSION_HANDLE session,
|
||||||
|
CK_SLOT_ID slot_id,
|
||||||
|
const CK_SLOT_INFO *slot_info,
|
||||||
|
const CK_TOKEN_INFO *token_info,
|
||||||
|
P11KitUri *uri,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
CK_OBJECT_HANDLE object;
|
||||||
|
CK_RV rv;
|
||||||
|
CK_TOKEN_INFO updated_token_info;
|
||||||
|
int r;
|
||||||
|
_cleanup_free_ char *token_label = NULL;
|
||||||
|
struct luks2_pkcs11_callback_data *data = userdata;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(slot_info);
|
||||||
|
assert(token_info);
|
||||||
|
assert(uri);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
token_label = pkcs11_token_label(token_info);
|
||||||
|
if (!token_label)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Called for every token matching our URI */
|
||||||
|
r = pkcs11_token_login_by_pin(m, session, token_info, token_label, data->pin, data->pin_size);
|
||||||
|
if (r == -ENOLCK) {
|
||||||
|
/* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
|
||||||
|
rv = m->C_GetTokenInfo(slot_id, &updated_token_info);
|
||||||
|
if (rv != CKR_OK) {
|
||||||
|
crypt_log_error(data->cd,
|
||||||
|
"Failed to acquire updated security token information for slot %lu: %s",
|
||||||
|
slot_id, p11_kit_strerror(rv));
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
token_info = &updated_token_info;
|
||||||
|
r = -ENOANO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == -ENOANO) {
|
||||||
|
if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY))
|
||||||
|
crypt_log_error(data->cd, "Please enter correct PIN for security token "
|
||||||
|
"'%s' in order to unlock it (final try).", token_label);
|
||||||
|
else if (FLAGS_SET(token_info->flags, CKF_USER_PIN_COUNT_LOW))
|
||||||
|
crypt_log_error(data->cd, "PIN has been entered incorrectly previously, "
|
||||||
|
"please enter correct PIN for security token '%s' in order to unlock it.",
|
||||||
|
token_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r == -EPERM) /* pin is locked, but map it to -ENOANO anyway */
|
||||||
|
r = -ENOANO;
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = pkcs11_token_find_private_key(m, session, uri, &object);
|
||||||
|
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);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void luks2_pkcs11_callback_data_release(struct luks2_pkcs11_callback_data *data) {
|
||||||
|
erase_and_free(data->decrypted_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int acquire_luks2_key_by_pin(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *pkcs11_uri,
|
||||||
|
const void *pin,
|
||||||
|
size_t pin_size,
|
||||||
|
void *encrypted_key,
|
||||||
|
size_t encrypted_key_size,
|
||||||
|
void **ret_decrypted_key,
|
||||||
|
size_t *ret_decrypted_key_size) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
_cleanup_(luks2_pkcs11_callback_data_release) struct luks2_pkcs11_callback_data data = {
|
||||||
|
.cd = cd,
|
||||||
|
.pin = pin,
|
||||||
|
.pin_size = pin_size,
|
||||||
|
.encrypted_key = encrypted_key,
|
||||||
|
.encrypted_key_size = encrypted_key_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(pkcs11_uri);
|
||||||
|
assert(encrypted_key);
|
||||||
|
assert(ret_decrypted_key);
|
||||||
|
assert(ret_decrypted_key_size);
|
||||||
|
|
||||||
|
r = pkcs11_find_token(pkcs11_uri, luks2_pkcs11_callback, &data);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret_decrypted_key = TAKE_PTR(data.decrypted_key);
|
||||||
|
*ret_decrypted_key_size = data.decrypted_key_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* called from within systemd utilities */
|
||||||
|
static int acquire_luks2_key_systemd(
|
||||||
|
const char *pkcs11_uri,
|
||||||
|
systemd_pkcs11_plugin_params *params,
|
||||||
|
void *encrypted_key,
|
||||||
|
size_t encrypted_key_size,
|
||||||
|
void **ret_decrypted_key,
|
||||||
|
size_t *ret_decrypted_key_size) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
_cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
|
||||||
|
.encrypted_key = encrypted_key,
|
||||||
|
.encrypted_key_size = encrypted_key_size,
|
||||||
|
.free_encrypted_key = false
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(pkcs11_uri);
|
||||||
|
assert(encrypted_key);
|
||||||
|
assert(ret_decrypted_key);
|
||||||
|
assert(ret_decrypted_key_size);
|
||||||
|
assert(params);
|
||||||
|
|
||||||
|
data.friendly_name = params->friendly_name;
|
||||||
|
data.headless = params->headless;
|
||||||
|
data.until = params->until;
|
||||||
|
|
||||||
|
/* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
|
||||||
|
r = pkcs11_find_token(pkcs11_uri, pkcs11_crypt_device_callback, &data);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret_decrypted_key = TAKE_PTR(data.decrypted_key);
|
||||||
|
*ret_decrypted_key_size = data.decrypted_key_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acquire_luks2_key(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
void *userdata,
|
||||||
|
const void *pin,
|
||||||
|
size_t pin_size,
|
||||||
|
char **ret_password,
|
||||||
|
size_t *ret_password_size) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
size_t decrypted_key_size, encrypted_key_size;
|
||||||
|
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||||
|
_cleanup_(erase_and_freep) char *base64_encoded = NULL;
|
||||||
|
_cleanup_free_ char *pkcs11_uri = NULL;
|
||||||
|
_cleanup_free_ void *encrypted_key = NULL;
|
||||||
|
systemd_pkcs11_plugin_params *pkcs11_params = userdata;
|
||||||
|
|
||||||
|
assert(json);
|
||||||
|
assert(ret_password);
|
||||||
|
assert(ret_password_size);
|
||||||
|
|
||||||
|
r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &encrypted_key, &encrypted_key_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (pkcs11_params && pin)
|
||||||
|
crypt_log_verbose(cd, "PIN parameter ignored in interactive mode.");
|
||||||
|
|
||||||
|
if (pkcs11_params) /* systemd based activation with interactive pin query callbacks */
|
||||||
|
r = acquire_luks2_key_systemd(
|
||||||
|
pkcs11_uri,
|
||||||
|
pkcs11_params,
|
||||||
|
encrypted_key, encrypted_key_size,
|
||||||
|
&decrypted_key, &decrypted_key_size);
|
||||||
|
else /* default activation that provides single PIN if needed */
|
||||||
|
r = acquire_luks2_key_by_pin(
|
||||||
|
cd, pkcs11_uri, pin, pin_size,
|
||||||
|
encrypted_key, encrypted_key_size,
|
||||||
|
&decrypted_key, &decrypted_key_size);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_error_errno(cd, r, "Can not base64 encode key: %m");
|
||||||
|
|
||||||
|
*ret_password = TAKE_PTR(base64_encoded);
|
||||||
|
*ret_password_size = strlen(*ret_password);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int parse_luks2_pkcs11_data(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
char **ret_uri,
|
||||||
|
void **ret_encrypted_key,
|
||||||
|
size_t *ret_encrypted_key_size) {
|
||||||
|
|
||||||
|
int r;
|
||||||
|
size_t key_size;
|
||||||
|
_cleanup_free_ char *uri = NULL;
|
||||||
|
_cleanup_free_ void *key = NULL;
|
||||||
|
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||||
|
JsonVariant *w;
|
||||||
|
|
||||||
|
assert(json);
|
||||||
|
assert(ret_uri);
|
||||||
|
assert(ret_encrypted_key);
|
||||||
|
assert(ret_encrypted_key_size);
|
||||||
|
|
||||||
|
r = json_parse(json, 0, &v, NULL, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "pkcs11-uri");
|
||||||
|
if (!w)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
uri = strdup(json_variant_string(w));
|
||||||
|
if (!uri)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
w = json_variant_by_key(v, "pkcs11-key");
|
||||||
|
if (!w)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size);
|
||||||
|
if (r < 0)
|
||||||
|
return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
|
||||||
|
|
||||||
|
*ret_uri = TAKE_PTR(uri);
|
||||||
|
*ret_encrypted_key = TAKE_PTR(key);
|
||||||
|
*ret_encrypted_key_size = key_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
21
src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.h
Normal file
21
src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct crypt_device;
|
||||||
|
|
||||||
|
int acquire_luks2_key(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
void *userdata,
|
||||||
|
const void *pin,
|
||||||
|
size_t pin_size,
|
||||||
|
char **password,
|
||||||
|
size_t *password_size);
|
||||||
|
|
||||||
|
int parse_luks2_pkcs11_data(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *json,
|
||||||
|
char **ret_uri,
|
||||||
|
void **ret_encrypted_key,
|
||||||
|
size_t *ret_encrypted_key_size);
|
||||||
@ -25,4 +25,40 @@ if conf.get('HAVE_TPM2') == 1
|
|||||||
c_args : cryptsetup_token_c_args)
|
c_args : cryptsetup_token_c_args)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if conf.get('HAVE_LIBFIDO2') == 1
|
||||||
|
cryptsetup_token_systemd_fido2_sources = files('''
|
||||||
|
cryptsetup-token-systemd-fido2.c
|
||||||
|
cryptsetup-token.h
|
||||||
|
cryptsetup-token-util.h
|
||||||
|
cryptsetup-token-util.c
|
||||||
|
luks2-fido2.c
|
||||||
|
luks2-fido2.h
|
||||||
|
'''.split())
|
||||||
|
|
||||||
|
cryptsetup_token_systemd_fido2_static = static_library(
|
||||||
|
'cryptsetup-token-systemd-fido2_static',
|
||||||
|
cryptsetup_token_systemd_fido2_sources,
|
||||||
|
include_directories : includes,
|
||||||
|
dependencies : libshared_deps + [libcryptsetup, versiondep],
|
||||||
|
c_args : cryptsetup_token_c_args)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if conf.get('HAVE_P11KIT') == 1
|
||||||
|
cryptsetup_token_systemd_pkcs11_sources = files('''
|
||||||
|
cryptsetup-token-systemd-pkcs11.c
|
||||||
|
cryptsetup-token.h
|
||||||
|
cryptsetup-token-util.h
|
||||||
|
cryptsetup-token-util.c
|
||||||
|
luks2-pkcs11.c
|
||||||
|
luks2-pkcs11.h
|
||||||
|
'''.split())
|
||||||
|
|
||||||
|
cryptsetup_token_systemd_pkcs11_static = static_library(
|
||||||
|
'cryptsetup-token-systemd-pkcs11_static',
|
||||||
|
cryptsetup_token_systemd_pkcs11_sources,
|
||||||
|
include_directories : includes,
|
||||||
|
dependencies : libshared_deps + [libcryptsetup, versiondep],
|
||||||
|
c_args : cryptsetup_token_c_args)
|
||||||
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|||||||
@ -736,6 +736,105 @@ static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool libcryptsetup_plugins_support(void) {
|
||||||
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
|
return crypt_token_external_path() != NULL;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
|
static int acquire_pins_from_env_variable(char ***ret_pins) {
|
||||||
|
char *e;
|
||||||
|
_cleanup_strv_free_erase_ char **pins = NULL;
|
||||||
|
|
||||||
|
assert(ret_pins);
|
||||||
|
|
||||||
|
e = getenv("PIN");
|
||||||
|
if (e) {
|
||||||
|
pins = strv_new(e);
|
||||||
|
if (!pins)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
string_erase(e);
|
||||||
|
if (unsetenv("PIN") < 0)
|
||||||
|
return log_error_errno(errno, "Failed to unset $PIN: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret_pins = TAKE_PTR(pins);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int attach_luks2_by_fido2(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *name,
|
||||||
|
usec_t until,
|
||||||
|
bool headless,
|
||||||
|
void *usrptr,
|
||||||
|
uint32_t activation_flags) {
|
||||||
|
|
||||||
|
int r = -EOPNOTSUPP;
|
||||||
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
|
char **p;
|
||||||
|
_cleanup_strv_free_erase_ char **pins = NULL;
|
||||||
|
AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED;
|
||||||
|
|
||||||
|
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, NULL, 0, usrptr, activation_flags);
|
||||||
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
|
r = 0;
|
||||||
|
if (r != -ENOANO) /* needs pin or pin is wrong */
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = acquire_pins_from_env_variable(&pins);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(p, pins) {
|
||||||
|
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
|
||||||
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
|
r = 0;
|
||||||
|
if (r != -ENOANO) /* needs pin or pin is wrong */
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (headless)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the '$PIN' environment variable.");
|
||||||
|
|
||||||
|
pins = strv_free_erase(pins);
|
||||||
|
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(p, pins) {
|
||||||
|
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
|
||||||
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
|
r = 0;
|
||||||
|
if (r != -ENOANO) /* needs pin or pin is wrong */
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
|
||||||
|
for (;;) {
|
||||||
|
pins = strv_free_erase(pins);
|
||||||
|
r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", "cryptsetup.fido2-pin", until, flags, &pins);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
STRV_FOREACH(p, pins) {
|
||||||
|
r = crypt_activate_by_token_pin(cd, name, "systemd-fido2", CRYPT_ANY_TOKEN, *p, strlen(*p), usrptr, activation_flags);
|
||||||
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
|
r = 0;
|
||||||
|
if (r != -ENOANO) /* needs pin or pin is wrong */
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int attach_luks_or_plain_or_bitlk_by_fido2(
|
static int attach_luks_or_plain_or_bitlk_by_fido2(
|
||||||
struct crypt_device *cd,
|
struct crypt_device *cd,
|
||||||
const char *name,
|
const char *name,
|
||||||
@ -750,12 +849,13 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
||||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
_cleanup_free_ void *discovered_salt = NULL, *discovered_cid = NULL;
|
_cleanup_free_ void *discovered_salt = NULL, *discovered_cid = NULL;
|
||||||
size_t discovered_salt_size, discovered_cid_size, cid_size, decrypted_key_size;
|
size_t discovered_salt_size, discovered_cid_size, decrypted_key_size, cid_size = 0;
|
||||||
_cleanup_free_ char *friendly = NULL, *discovered_rp_id = NULL;
|
_cleanup_free_ char *friendly = NULL, *discovered_rp_id = NULL;
|
||||||
int keyslot = arg_key_slot, r;
|
int keyslot = arg_key_slot, r;
|
||||||
const char *rp_id;
|
const char *rp_id = NULL;
|
||||||
const void *cid;
|
const void *cid = NULL;
|
||||||
Fido2EnrollFlags required;
|
Fido2EnrollFlags required;
|
||||||
|
bool use_libcryptsetup_plugin = libcryptsetup_plugins_support();
|
||||||
|
|
||||||
assert(cd);
|
assert(cd);
|
||||||
assert(name);
|
assert(name);
|
||||||
@ -775,7 +875,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
* use PIN + UP when needed, and do not configure UV at all. Eventually, we should make this
|
* use PIN + UP when needed, and do not configure UV at all. Eventually, we should make this
|
||||||
* explicitly configurable. */
|
* explicitly configurable. */
|
||||||
required = FIDO2ENROLL_PIN_IF_NEEDED | FIDO2ENROLL_UP_IF_NEEDED | FIDO2ENROLL_UV_OMIT;
|
required = FIDO2ENROLL_PIN_IF_NEEDED | FIDO2ENROLL_UP_IF_NEEDED | FIDO2ENROLL_UV_OMIT;
|
||||||
} else {
|
} else if (!use_libcryptsetup_plugin) {
|
||||||
r = find_fido2_auto_data(
|
r = find_fido2_auto_data(
|
||||||
cd,
|
cd,
|
||||||
&discovered_rp_id,
|
&discovered_rp_id,
|
||||||
@ -810,6 +910,13 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
|
|
||||||
|
if (use_libcryptsetup_plugin && !arg_fido2_cid) {
|
||||||
|
r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags);
|
||||||
|
if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT))
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
|
||||||
|
"Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking.");
|
||||||
|
|
||||||
|
} else {
|
||||||
r = acquire_fido2_key(
|
r = acquire_fido2_key(
|
||||||
name,
|
name,
|
||||||
friendly,
|
friendly,
|
||||||
@ -825,6 +932,8 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
arg_ask_password_flags);
|
arg_ask_password_flags);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (r != -EAGAIN) /* EAGAIN means: token not found */
|
if (r != -EAGAIN) /* EAGAIN means: token not found */
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -887,6 +996,32 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int attach_luks2_by_pkcs11(
|
||||||
|
struct crypt_device *cd,
|
||||||
|
const char *name,
|
||||||
|
const char *friendly_name,
|
||||||
|
usec_t until,
|
||||||
|
bool headless,
|
||||||
|
uint32_t flags) {
|
||||||
|
|
||||||
|
int r = -ENOTSUP;
|
||||||
|
#if HAVE_LIBCRYPTSETUP_PLUGINS
|
||||||
|
if (!crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Automatic PKCS#11 metadata requires LUKS2 device.");
|
||||||
|
|
||||||
|
systemd_pkcs11_plugin_params params = {
|
||||||
|
.friendly_name = friendly_name,
|
||||||
|
.until = until,
|
||||||
|
.headless = headless
|
||||||
|
};
|
||||||
|
|
||||||
|
r = crypt_activate_by_token_pin(cd, name, "systemd-pkcs11", CRYPT_ANY_TOKEN, NULL, 0, ¶ms, flags);
|
||||||
|
if (r > 0) /* returns unlocked keyslot id on success */
|
||||||
|
r = 0;
|
||||||
|
#endif
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
||||||
struct crypt_device *cd,
|
struct crypt_device *cd,
|
||||||
const char *name,
|
const char *name,
|
||||||
@ -904,13 +1039,15 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
||||||
_cleanup_free_ void *discovered_key = NULL;
|
_cleanup_free_ void *discovered_key = NULL;
|
||||||
int keyslot = arg_key_slot, r;
|
int keyslot = arg_key_slot, r;
|
||||||
const char *uri;
|
const char *uri = NULL;
|
||||||
|
bool use_libcryptsetup_plugin = libcryptsetup_plugins_support();
|
||||||
|
|
||||||
assert(cd);
|
assert(cd);
|
||||||
assert(name);
|
assert(name);
|
||||||
assert(arg_pkcs11_uri || arg_pkcs11_uri_auto);
|
assert(arg_pkcs11_uri || arg_pkcs11_uri_auto);
|
||||||
|
|
||||||
if (arg_pkcs11_uri_auto) {
|
if (arg_pkcs11_uri_auto) {
|
||||||
|
if (!use_libcryptsetup_plugin) {
|
||||||
r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &keyslot);
|
r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &keyslot);
|
||||||
if (IN_SET(r, -ENOTUNIQ, -ENXIO))
|
if (IN_SET(r, -ENOTUNIQ, -ENXIO))
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
|
return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN),
|
||||||
@ -921,6 +1058,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
uri = discovered_uri;
|
uri = discovered_uri;
|
||||||
key_data = discovered_key;
|
key_data = discovered_key;
|
||||||
key_data_size = discovered_key_size;
|
key_data_size = discovered_key_size;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
uri = arg_pkcs11_uri;
|
uri = arg_pkcs11_uri;
|
||||||
|
|
||||||
@ -935,6 +1073,9 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
bool processed = false;
|
bool processed = false;
|
||||||
|
|
||||||
|
if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto)
|
||||||
|
r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags);
|
||||||
|
else {
|
||||||
r = decrypt_pkcs11_key(
|
r = decrypt_pkcs11_key(
|
||||||
name,
|
name,
|
||||||
friendly,
|
friendly,
|
||||||
@ -946,6 +1087,8 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
&decrypted_key, &decrypted_key_size);
|
&decrypted_key, &decrypted_key_size);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (r != -EAGAIN) /* EAGAIN means: token not found */
|
if (r != -EAGAIN) /* EAGAIN means: token not found */
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -985,6 +1128,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11(
|
|||||||
|
|
||||||
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
|
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
|
||||||
}
|
}
|
||||||
|
assert(decrypted_key);
|
||||||
|
|
||||||
if (pass_volume_key)
|
if (pass_volume_key)
|
||||||
r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags);
|
r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags);
|
||||||
|
|||||||
@ -22,7 +22,6 @@
|
|||||||
#if HAVE_ACL
|
#if HAVE_ACL
|
||||||
|
|
||||||
static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
acl_t acl;
|
acl_t acl;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
@ -35,14 +34,11 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
|||||||
if (child_fd < 0)
|
if (child_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
|
acl = acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type);
|
||||||
acl = acl_get_file(procfs_path, type);
|
|
||||||
} else if (type == ACL_TYPE_ACCESS)
|
} else if (type == ACL_TYPE_ACCESS)
|
||||||
acl = acl_get_fd(fd);
|
acl = acl_get_fd(fd);
|
||||||
else {
|
else
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), type);
|
||||||
acl = acl_get_file(procfs_path, type);
|
|
||||||
}
|
|
||||||
if (!acl)
|
if (!acl)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -51,7 +47,6 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
@ -64,14 +59,11 @@ static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
|
|||||||
if (child_fd < 0)
|
if (child_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
|
r = acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl);
|
||||||
r = acl_set_file(procfs_path, type, acl);
|
|
||||||
} else if (type == ACL_TYPE_ACCESS)
|
} else if (type == ACL_TYPE_ACCESS)
|
||||||
r = acl_set_fd(fd, acl);
|
r = acl_set_fd(fd, acl);
|
||||||
else {
|
else
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl);
|
||||||
r = acl_set_file(procfs_path, type, acl);
|
|
||||||
}
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
|||||||
@ -1581,12 +1581,8 @@ static int context_load_partition_table(
|
|||||||
* /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
|
* /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
|
||||||
if (*backing_fd < 0)
|
if (*backing_fd < 0)
|
||||||
r = fdisk_assign_device(c, node, arg_dry_run);
|
r = fdisk_assign_device(c, node, arg_dry_run);
|
||||||
else {
|
else
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(*backing_fd), arg_dry_run);
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
|
|
||||||
|
|
||||||
r = fdisk_assign_device(c, procfs_path, arg_dry_run);
|
|
||||||
}
|
|
||||||
if (r == -EINVAL && arg_size_auto) {
|
if (r == -EINVAL && arg_size_auto) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
@ -4593,7 +4589,6 @@ static int find_root(char **ret, int *ret_fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int resize_pt(int fd) {
|
static int resize_pt(int fd) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
|
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -4605,14 +4600,13 @@ static int resize_pt(int fd) {
|
|||||||
if (!c)
|
if (!c)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
r = fdisk_assign_device(c, FORMAT_PROC_FD_PATH(fd), 0);
|
||||||
r = fdisk_assign_device(c, procfs_path, 0);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to open device '%s': %m", procfs_path);
|
return log_error_errno(r, "Failed to open device '%s': %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
|
|
||||||
r = fdisk_has_label(c);
|
r = fdisk_has_label(c);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", procfs_path);
|
return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
log_debug("Not resizing partition table, as there currently is none.");
|
log_debug("Not resizing partition table, as there currently is none.");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@ -21,7 +21,6 @@ static int chown_one(
|
|||||||
gid_t gid,
|
gid_t gid,
|
||||||
mode_t mask) {
|
mode_t mask) {
|
||||||
|
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
|
|
||||||
const char *n;
|
const char *n;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -30,11 +29,10 @@ static int chown_one(
|
|||||||
|
|
||||||
/* We change ACLs through the /proc/self/fd/%i path, so that we have a stable reference that works
|
/* We change ACLs through the /proc/self/fd/%i path, so that we have a stable reference that works
|
||||||
* with O_PATH. */
|
* with O_PATH. */
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
/* Drop any ACL if there is one */
|
/* Drop any ACL if there is one */
|
||||||
FOREACH_STRING(n, "system.posix_acl_access", "system.posix_acl_default")
|
FOREACH_STRING(n, "system.posix_acl_access", "system.posix_acl_default")
|
||||||
if (removexattr(procfs_path, n) < 0)
|
if (removexattr(FORMAT_PROC_FD_PATH(fd), n) < 0)
|
||||||
if (!IN_SET(errno, ENODATA, EOPNOTSUPP, ENOSYS, ENOTTY))
|
if (!IN_SET(errno, ENODATA, EOPNOTSUPP, ENOSYS, ENOTTY))
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
|
|||||||
@ -305,7 +305,7 @@ static int image_make(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get directory creation time (not available everywhere, but that's OK */
|
/* Get directory creation time (not available everywhere, but that's OK */
|
||||||
(void) fd_getcrtime(dfd, &crtime);
|
(void) fd_getcrtime(fd, &crtime);
|
||||||
|
|
||||||
/* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
|
/* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not
|
||||||
* supported everywhere we ignore failures. */
|
* supported everywhere we ignore failures. */
|
||||||
|
|||||||
@ -42,10 +42,7 @@ int mount_fd(const char *source,
|
|||||||
unsigned long mountflags,
|
unsigned long mountflags,
|
||||||
const void *data) {
|
const void *data) {
|
||||||
|
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
if (mount(source, FORMAT_PROC_FD_PATH(target_fd), filesystemtype, mountflags, data) < 0) {
|
||||||
|
|
||||||
xsprintf(path, "/proc/self/fd/%i", target_fd);
|
|
||||||
if (mount(source, path, filesystemtype, mountflags, data) < 0) {
|
|
||||||
if (errno != ENOENT)
|
if (errno != ENOENT)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
@ -733,8 +730,7 @@ static int mount_in_namespace(
|
|||||||
|
|
||||||
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
|
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
|
||||||
_cleanup_close_ int self_mntns_fd = -1, mntns_fd = -1, root_fd = -1, pidns_fd = -1, chased_src_fd = -1;
|
_cleanup_close_ int self_mntns_fd = -1, mntns_fd = -1, root_fd = -1, pidns_fd = -1, chased_src_fd = -1;
|
||||||
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p,
|
char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
|
||||||
chased_src[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
bool mount_slave_created = false, mount_slave_mounted = false,
|
bool mount_slave_created = false, mount_slave_mounted = false,
|
||||||
mount_tmp_created = false, mount_tmp_mounted = false,
|
mount_tmp_created = false, mount_tmp_mounted = false,
|
||||||
mount_outside_created = false, mount_outside_mounted = false;
|
mount_outside_created = false, mount_outside_mounted = false;
|
||||||
@ -767,9 +763,8 @@ static int mount_in_namespace(
|
|||||||
if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev)
|
if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev)
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
|
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace");
|
||||||
|
|
||||||
/* One day, when bind mounting /proc/self/fd/n works across
|
/* One day, when bind mounting /proc/self/fd/n works across namespace boundaries we should rework
|
||||||
* namespace boundaries we should rework this logic to make
|
* this logic to make use of it... */
|
||||||
* use of it... */
|
|
||||||
|
|
||||||
p = strjoina(propagate_path, "/");
|
p = strjoina(propagate_path, "/");
|
||||||
r = laccess(p, F_OK);
|
r = laccess(p, F_OK);
|
||||||
@ -779,7 +774,6 @@ static int mount_in_namespace(
|
|||||||
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, NULL, &chased_src_fd);
|
r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, NULL, &chased_src_fd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
|
return log_debug_errno(r, "Failed to resolve source path of %s: %m", src);
|
||||||
xsprintf(chased_src, "/proc/self/fd/%i", chased_src_fd);
|
|
||||||
|
|
||||||
if (fstat(chased_src_fd, &st) < 0)
|
if (fstat(chased_src_fd, &st) < 0)
|
||||||
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
|
return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src);
|
||||||
@ -824,9 +818,9 @@ static int mount_in_namespace(
|
|||||||
mount_tmp_created = true;
|
mount_tmp_created = true;
|
||||||
|
|
||||||
if (is_image)
|
if (is_image)
|
||||||
r = verity_dissect_and_mount(chased_src, mount_tmp, options, NULL, NULL, NULL);
|
r = verity_dissect_and_mount(FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, options, NULL, NULL, NULL);
|
||||||
else
|
else
|
||||||
r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL);
|
r = mount_follow_verbose(LOG_DEBUG, FORMAT_PROC_FD_PATH(chased_src_fd), mount_tmp, NULL, MS_BIND, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
|||||||
@ -175,6 +175,55 @@ char *pkcs11_token_model(const CK_TOKEN_INFO *token_info) {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pkcs11_token_login_by_pin(
|
||||||
|
CK_FUNCTION_LIST *m,
|
||||||
|
CK_SESSION_HANDLE session,
|
||||||
|
const CK_TOKEN_INFO *token_info,
|
||||||
|
const char *token_label,
|
||||||
|
const void *pin,
|
||||||
|
size_t pin_size) {
|
||||||
|
|
||||||
|
CK_RV rv;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(token_info);
|
||||||
|
|
||||||
|
if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
|
||||||
|
rv = m->C_Login(session, CKU_USER, NULL, 0);
|
||||||
|
if (rv != CKR_OK)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
||||||
|
|
||||||
|
log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
|
||||||
|
log_info("No login into security token '%s' required.", token_label);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pin)
|
||||||
|
return -ENOANO;
|
||||||
|
|
||||||
|
rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) pin, pin_size);
|
||||||
|
if (rv == CKR_OK) {
|
||||||
|
log_info("Successfully logged into security token '%s'.", token_label);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv == CKR_PIN_LOCKED)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
|
||||||
|
"PIN has been locked, please reset PIN of security token '%s'.", token_label);
|
||||||
|
if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
||||||
|
"Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
||||||
|
|
||||||
|
log_notice("PIN for token '%s' is incorrect, please try again.", token_label);
|
||||||
|
|
||||||
|
return -ENOLCK;
|
||||||
|
}
|
||||||
|
|
||||||
int pkcs11_token_login(
|
int pkcs11_token_login(
|
||||||
CK_FUNCTION_LIST *m,
|
CK_FUNCTION_LIST *m,
|
||||||
CK_SESSION_HANDLE session,
|
CK_SESSION_HANDLE session,
|
||||||
@ -209,24 +258,12 @@ int pkcs11_token_login(
|
|||||||
if (uri_result != P11_KIT_URI_OK)
|
if (uri_result != P11_KIT_URI_OK)
|
||||||
return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
|
return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
|
||||||
|
|
||||||
if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
|
r = pkcs11_token_login_by_pin(m, session, token_info, token_label, /* pin= */ NULL, 0);
|
||||||
rv = m->C_Login(session, CKU_USER, NULL, 0);
|
if (r == 0 && ret_used_pin)
|
||||||
if (rv != CKR_OK)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
|
||||||
"Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
|
||||||
|
|
||||||
log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
|
|
||||||
if (ret_used_pin)
|
|
||||||
*ret_used_pin = NULL;
|
*ret_used_pin = NULL;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
|
if (r != -ENOANO) /* pin required */
|
||||||
log_info("No login into security token '%s' required.", token_label);
|
return r;
|
||||||
if (ret_used_pin)
|
|
||||||
*ret_used_pin = NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
token_uri_escaped = cescape(token_uri_string);
|
token_uri_escaped = cescape(token_uri_string);
|
||||||
if (!token_uri_escaped)
|
if (!token_uri_escaped)
|
||||||
@ -278,10 +315,8 @@ int pkcs11_token_login(
|
|||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(i, passwords) {
|
STRV_FOREACH(i, passwords) {
|
||||||
rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) *i, strlen(*i));
|
r = pkcs11_token_login_by_pin(m, session, token_info, token_label, *i, strlen(*i));
|
||||||
if (rv == CKR_OK) {
|
if (r == 0 && ret_used_pin) {
|
||||||
|
|
||||||
if (ret_used_pin) {
|
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
c = strdup(*i);
|
c = strdup(*i);
|
||||||
@ -291,15 +326,8 @@ int pkcs11_token_login(
|
|||||||
*ret_used_pin = c;
|
*ret_used_pin = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("Successfully logged into security token '%s'.", token_label);
|
if (r != -ENOLCK)
|
||||||
return 0;
|
return r;
|
||||||
}
|
|
||||||
if (rv == CKR_PIN_LOCKED)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM),
|
|
||||||
"PIN has been locked, please reset PIN of security token '%s'.", token_label);
|
|
||||||
if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO),
|
|
||||||
"Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
|
||||||
|
|
||||||
/* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
|
/* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
|
||||||
rv = m->C_GetTokenInfo(slotid, &updated_token_info);
|
rv = m->C_GetTokenInfo(slotid, &updated_token_info);
|
||||||
@ -309,7 +337,6 @@ int pkcs11_token_login(
|
|||||||
slotid, p11_kit_strerror(rv));
|
slotid, p11_kit_strerror(rv));
|
||||||
|
|
||||||
token_info = &updated_token_info;
|
token_info = &updated_token_info;
|
||||||
log_notice("PIN for token '%s' is incorrect, please try again.", token_label);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1154,3 +1181,71 @@ int pkcs11_find_token_auto(char **ret) {
|
|||||||
"PKCS#11 tokens not supported on this build.");
|
"PKCS#11 tokens not supported on this build.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_P11KIT
|
||||||
|
void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data *data) {
|
||||||
|
erase_and_free(data->decrypted_key);
|
||||||
|
|
||||||
|
if (data->free_encrypted_key)
|
||||||
|
free(data->encrypted_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pkcs11_crypt_device_callback(
|
||||||
|
CK_FUNCTION_LIST *m,
|
||||||
|
CK_SESSION_HANDLE session,
|
||||||
|
CK_SLOT_ID slot_id,
|
||||||
|
const CK_SLOT_INFO *slot_info,
|
||||||
|
const CK_TOKEN_INFO *token_info,
|
||||||
|
P11KitUri *uri,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
pkcs11_crypt_device_callback_data *data = userdata;
|
||||||
|
CK_OBJECT_HANDLE object;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(slot_info);
|
||||||
|
assert(token_info);
|
||||||
|
assert(uri);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
/* Called for every token matching our URI */
|
||||||
|
|
||||||
|
r = pkcs11_token_login(
|
||||||
|
m,
|
||||||
|
session,
|
||||||
|
slot_id,
|
||||||
|
token_info,
|
||||||
|
data->friendly_name,
|
||||||
|
"drive-harddisk",
|
||||||
|
"pkcs11-pin",
|
||||||
|
"cryptsetup.pkcs11-pin",
|
||||||
|
data->until,
|
||||||
|
data->headless,
|
||||||
|
NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
|
||||||
|
* token, if it supports that. It should be cheap, given that we already are talking to it anyway and
|
||||||
|
* shouldn't hurt. */
|
||||||
|
(void) pkcs11_token_acquire_rng(m, session);
|
||||||
|
|
||||||
|
r = pkcs11_token_find_private_key(m, session, uri, &object);
|
||||||
|
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);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@ -30,6 +30,7 @@ char *pkcs11_token_label(const CK_TOKEN_INFO *token_info);
|
|||||||
char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info);
|
char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info);
|
||||||
char *pkcs11_token_model(const CK_TOKEN_INFO *token_info);
|
char *pkcs11_token_model(const CK_TOKEN_INFO *token_info);
|
||||||
|
|
||||||
|
int pkcs11_token_login_by_pin(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, const CK_TOKEN_INFO *token_info, const char *token_label, const void *pin, size_t pin_size);
|
||||||
int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, bool headless, char **ret_used_pin);
|
int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, bool headless, char **ret_used_pin);
|
||||||
|
|
||||||
int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object);
|
int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object);
|
||||||
@ -49,7 +50,35 @@ int pkcs11_find_token(const char *pkcs11_uri, pkcs11_find_token_callback_t callb
|
|||||||
int pkcs11_acquire_certificate(const char *uri, const char *askpw_friendly_name, const char *askpw_icon_name, X509 **ret_cert, char **ret_pin_used);
|
int pkcs11_acquire_certificate(const char *uri, const char *askpw_friendly_name, const char *askpw_icon_name, X509 **ret_cert, char **ret_pin_used);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *friendly_name;
|
||||||
|
usec_t until;
|
||||||
|
void *encrypted_key;
|
||||||
|
size_t encrypted_key_size;
|
||||||
|
void *decrypted_key;
|
||||||
|
size_t decrypted_key_size;
|
||||||
|
bool free_encrypted_key;
|
||||||
|
bool headless;
|
||||||
|
} pkcs11_crypt_device_callback_data;
|
||||||
|
|
||||||
|
void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data *data);
|
||||||
|
|
||||||
|
int pkcs11_crypt_device_callback(
|
||||||
|
CK_FUNCTION_LIST *m,
|
||||||
|
CK_SESSION_HANDLE session,
|
||||||
|
CK_SLOT_ID slot_id,
|
||||||
|
const CK_SLOT_INFO *slot_info,
|
||||||
|
const CK_TOKEN_INFO *token_info,
|
||||||
|
P11KitUri *uri,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *friendly_name;
|
||||||
|
usec_t until;
|
||||||
|
bool headless;
|
||||||
|
} systemd_pkcs11_plugin_params;
|
||||||
|
|
||||||
int pkcs11_list_tokens(void);
|
int pkcs11_list_tokens(void);
|
||||||
int pkcs11_find_token_auto(char **ret);
|
int pkcs11_find_token_auto(char **ret);
|
||||||
|
|||||||
@ -266,7 +266,6 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
assert(inside_path);
|
assert(inside_path);
|
||||||
|
|
||||||
#if HAVE_SELINUX
|
#if HAVE_SELINUX
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_freecon_ char* fcon = NULL;
|
_cleanup_freecon_ char* fcon = NULL;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r;
|
||||||
@ -292,8 +291,7 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (setfilecon_raw(FORMAT_PROC_FD_PATH(fd), fcon) < 0) {
|
||||||
if (setfilecon_raw(procfs_path, fcon) < 0) {
|
|
||||||
_cleanup_freecon_ char *oldcon = NULL;
|
_cleanup_freecon_ char *oldcon = NULL;
|
||||||
|
|
||||||
/* If the FS doesn't support labels, then exit without warning */
|
/* If the FS doesn't support labels, then exit without warning */
|
||||||
@ -307,7 +305,7 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa
|
|||||||
r = -errno;
|
r = -errno;
|
||||||
|
|
||||||
/* If the old label is identical to the new one, suppress any kind of error */
|
/* If the old label is identical to the new one, suppress any kind of error */
|
||||||
if (getfilecon_raw(procfs_path, &oldcon) >= 0 && streq(fcon, oldcon))
|
if (getfilecon_raw(FORMAT_PROC_FD_PATH(fd), &oldcon) >= 0 && streq(fcon, oldcon))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@ -122,7 +122,6 @@ int mac_smack_apply_pid(pid_t pid, const char *label) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
static int smack_fix_fd(int fd, const char *abspath, LabelFixFlags flags) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
const char *label;
|
const char *label;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int r;
|
int r;
|
||||||
@ -153,8 +152,7 @@ static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) {
|
|||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
if (setxattr(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", label, strlen(label), 0) < 0) {
|
||||||
if (setxattr(procfs_path, "security.SMACK64", label, strlen(label), 0) < 0) {
|
|
||||||
_cleanup_free_ char *old_label = NULL;
|
_cleanup_free_ char *old_label = NULL;
|
||||||
|
|
||||||
r = -errno;
|
r = -errno;
|
||||||
@ -168,7 +166,7 @@ static int smack_fix_fd(int fd , const char *abspath, LabelFixFlags flags) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* If the old label is identical to the new one, suppress any kind of error */
|
/* If the old label is identical to the new one, suppress any kind of error */
|
||||||
if (getxattr_malloc(procfs_path, "security.SMACK64", &old_label, false) >= 0 &&
|
if (getxattr_malloc(FORMAT_PROC_FD_PATH(fd), "security.SMACK64", &old_label, false) >= 0 &&
|
||||||
streq(old_label, label))
|
streq(old_label, label))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@ -50,12 +50,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
else
|
else
|
||||||
log_info(r == 0 ? "Done!" : "Action!");
|
log_info(r == 0 ? "Done!" : "Action!");
|
||||||
|
|
||||||
if (orig_stdout_fd >= 0) {
|
if (orig_stdout_fd >= 0)
|
||||||
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
assert_se(freopen(FORMAT_PROC_FD_PATH(orig_stdout_fd), "w", stdout));
|
||||||
|
|
||||||
xsprintf(path, "/proc/self/fd/%d", orig_stdout_fd);
|
|
||||||
assert_se(freopen(path, "w", stdout));
|
|
||||||
}
|
|
||||||
|
|
||||||
release_busses(); /* We open the bus for communication with logind.
|
release_busses(); /* We open the bus for communication with logind.
|
||||||
* It needs to be closed to avoid apparent leaks. */
|
* It needs to be closed to avoid apparent leaks. */
|
||||||
|
|||||||
@ -278,6 +278,14 @@ static void test_close_all_fds(void) {
|
|||||||
log_open();
|
log_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_format_proc_fd_path(void) {
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(0), "/proc/self/fd/0"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(1), "/proc/self/fd/1"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2), "/proc/self/fd/2"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(3), "/proc/self/fd/3"));
|
||||||
|
assert_se(streq_ptr(FORMAT_PROC_FD_PATH(2147483647), "/proc/self/fd/2147483647"));
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
test_setup_logging(LOG_DEBUG);
|
test_setup_logging(LOG_DEBUG);
|
||||||
@ -290,6 +298,7 @@ int main(int argc, char *argv[]) {
|
|||||||
test_rearrange_stdio();
|
test_rearrange_stdio();
|
||||||
test_read_nr_open();
|
test_read_nr_open();
|
||||||
test_close_all_fds();
|
test_close_all_fds();
|
||||||
|
test_format_proc_fd_path();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1058,18 +1058,15 @@ static int parse_xattrs_from_arg(Item *i) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) {
|
static int fd_set_xattrs(Item *i, int fd, const char *path, const struct stat *st) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
char **name, **value;
|
char **name, **value;
|
||||||
|
|
||||||
assert(i);
|
assert(i);
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(path);
|
assert(path);
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
STRV_FOREACH_PAIR(name, value, i->xattrs) {
|
STRV_FOREACH_PAIR(name, value, i->xattrs) {
|
||||||
log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
|
log_debug("Setting extended attribute '%s=%s' on %s.", *name, *value, path);
|
||||||
if (setxattr(procfs_path, *name, *value, strlen(*value), 0) < 0)
|
if (setxattr(FORMAT_PROC_FD_PATH(fd), *name, *value, strlen(*value), 0) < 0)
|
||||||
return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
|
return log_error_errno(errno, "Setting extended attribute %s=%s on %s failed: %m",
|
||||||
*name, *value, path);
|
*name, *value, path);
|
||||||
}
|
}
|
||||||
@ -1161,7 +1158,6 @@ static int path_set_acl(const char *path, const char *pretty, acl_type_t type, a
|
|||||||
static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *st) {
|
static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *st) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
#if HAVE_ACL
|
#if HAVE_ACL
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
|
|
||||||
assert(item);
|
assert(item);
|
||||||
@ -1184,14 +1180,12 @@ static int fd_set_acls(Item *item, int fd, const char *path, const struct stat *
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
|
||||||
|
|
||||||
if (item->acl_access)
|
if (item->acl_access)
|
||||||
r = path_set_acl(procfs_path, path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
|
r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_ACCESS, item->acl_access, item->append_or_force);
|
||||||
|
|
||||||
/* set only default acls to folders */
|
/* set only default acls to folders */
|
||||||
if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
|
if (r == 0 && item->acl_default && S_ISDIR(st->st_mode))
|
||||||
r = path_set_acl(procfs_path, path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
|
r = path_set_acl(FORMAT_PROC_FD_PATH(fd), path, ACL_TYPE_DEFAULT, item->acl_default, item->append_or_force);
|
||||||
|
|
||||||
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
if (ERRNO_IS_NOT_SUPPORTED(r)) {
|
||||||
log_debug_errno(r, "ACLs not supported by file system at %s", path);
|
log_debug_errno(r, "ACLs not supported by file system at %s", path);
|
||||||
@ -1938,17 +1932,14 @@ static int item_do(Item *i, int fd, const char *path, fdaction_t action) {
|
|||||||
r = action(i, fd, path, &st);
|
r = action(i, fd, path, &st);
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
|
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
|
|
||||||
/* The passed 'fd' was opened with O_PATH. We need to convert
|
/* The passed 'fd' was opened with O_PATH. We need to convert it into a 'regular' fd before
|
||||||
* it into a 'regular' fd before reading the directory content. */
|
* reading the directory content. */
|
||||||
xsprintf(procfs_path, "/proc/self/fd/%i", fd);
|
d = opendir(FORMAT_PROC_FD_PATH(fd));
|
||||||
|
|
||||||
d = opendir(procfs_path);
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
log_error_errno(errno, "Failed to opendir() '%s': %m", procfs_path);
|
log_error_errno(errno, "Failed to opendir() '%s': %m", FORMAT_PROC_FD_PATH(fd));
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|||||||
@ -11,7 +11,10 @@ TEST_NO_NSPAWN=1
|
|||||||
test_append_files() {
|
test_append_files() {
|
||||||
(
|
(
|
||||||
local workspace="${1:?}"
|
local workspace="${1:?}"
|
||||||
dracut_install busybox
|
|
||||||
|
# On openSUSE the static linked version of busybox is named "busybox-static".
|
||||||
|
busybox="$(type -P busybox-static || type -P busybox)"
|
||||||
|
inst_simple "$busybox" "$(dirname $busybox)/busybox"
|
||||||
|
|
||||||
if selinuxenabled >/dev/null; then
|
if selinuxenabled >/dev/null; then
|
||||||
dracut_install selinuxenabled
|
dracut_install selinuxenabled
|
||||||
|
|||||||
@ -7,18 +7,10 @@ set -o pipefail
|
|||||||
root="${1:?Usage $0 container-root}"
|
root="${1:?Usage $0 container-root}"
|
||||||
mkdir -p "$root"
|
mkdir -p "$root"
|
||||||
mkdir "$root/bin"
|
mkdir "$root/bin"
|
||||||
cp $(type -P busybox) "$root/bin"
|
|
||||||
|
|
||||||
os_release=$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release)
|
# On openSUSE the static linked version of busybox is named "busybox-static".
|
||||||
ID_LIKE=$(awk -F= '$1=="ID_LIKE" { print $2 ;}' $os_release)
|
busybox="$(type -P busybox-static || type -P busybox)"
|
||||||
if [[ "$ID_LIKE" = *"suse"* ]]; then
|
cp "$busybox" "$root/bin/busybox"
|
||||||
mkdir -p "$root/lib"
|
|
||||||
mkdir -p "$root/lib64"
|
|
||||||
for lib in $(find /lib*/ld*); do
|
|
||||||
[[ -d $root/$(dirname $lib) ]] || mkdir -p $root/$(dirname $lib)
|
|
||||||
cp $lib $root/$lib
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p "$root/usr/lib"
|
mkdir -p "$root/usr/lib"
|
||||||
touch "$root/usr/lib/os-release"
|
touch "$root/usr/lib/os-release"
|
||||||
@ -30,6 +22,7 @@ ln -s busybox "$root/bin/ps"
|
|||||||
ln -s busybox "$root/bin/ip"
|
ln -s busybox "$root/bin/ip"
|
||||||
ln -s busybox "$root/bin/seq"
|
ln -s busybox "$root/bin/seq"
|
||||||
ln -s busybox "$root/bin/sleep"
|
ln -s busybox "$root/bin/sleep"
|
||||||
|
ln -s busybox "$root/bin/usleep"
|
||||||
ln -s busybox "$root/bin/test"
|
ln -s busybox "$root/bin/test"
|
||||||
|
|
||||||
mkdir -p "$root/sbin"
|
mkdir -p "$root/sbin"
|
||||||
|
|||||||
@ -83,14 +83,12 @@ TOOLS_DIR="$SOURCE_DIR/tools"
|
|||||||
export TEST_BASE_DIR TEST_UNITS_DIR SOURCE_DIR TOOLS_DIR
|
export TEST_BASE_DIR TEST_UNITS_DIR SOURCE_DIR TOOLS_DIR
|
||||||
|
|
||||||
# note that find-build-dir.sh will return $BUILD_DIR if provided, else it will try to find it
|
# note that find-build-dir.sh will return $BUILD_DIR if provided, else it will try to find it
|
||||||
if ! BUILD_DIR="$("$TOOLS_DIR"/find-build-dir.sh)"; then
|
|
||||||
if get_bool "${NO_BUILD:=}"; then
|
if get_bool "${NO_BUILD:=}"; then
|
||||||
BUILD_DIR="$SOURCE_DIR"
|
BUILD_DIR="$SOURCE_DIR"
|
||||||
else
|
elif ! BUILD_DIR="$("$TOOLS_DIR"/find-build-dir.sh)"; then
|
||||||
echo "ERROR: no build found, please set BUILD_DIR or use NO_BUILD" >&2
|
echo "ERROR: no build found, please set BUILD_DIR or use NO_BUILD" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
PATH_TO_INIT="$ROOTLIBDIR/systemd"
|
PATH_TO_INIT="$ROOTLIBDIR/systemd"
|
||||||
SYSTEMD_JOURNALD="${SYSTEMD_JOURNALD:-$(command -v "$BUILD_DIR/systemd-journald" || command -v "$ROOTLIBDIR/systemd-journald")}"
|
SYSTEMD_JOURNALD="${SYSTEMD_JOURNALD:-$(command -v "$BUILD_DIR/systemd-journald" || command -v "$ROOTLIBDIR/systemd-journald")}"
|
||||||
@ -667,6 +665,7 @@ setup_basic_environment() {
|
|||||||
install_fs_tools
|
install_fs_tools
|
||||||
install_modules
|
install_modules
|
||||||
install_plymouth
|
install_plymouth
|
||||||
|
install_haveged
|
||||||
install_debug_tools
|
install_debug_tools
|
||||||
install_ld_so_conf
|
install_ld_so_conf
|
||||||
install_testuser
|
install_testuser
|
||||||
@ -936,11 +935,52 @@ install_debian_systemd() {
|
|||||||
done < <(grep -E '^Package:' "${SOURCE_DIR}/debian/control" | cut -d ':' -f 2)
|
done < <(grep -E '^Package:' "${SOURCE_DIR}/debian/control" | cut -d ':' -f 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_suse_systemd() {
|
||||||
|
local testsdir=/usr/lib/systemd/tests
|
||||||
|
local pkgs
|
||||||
|
|
||||||
|
dinfo "Install SUSE systemd"
|
||||||
|
|
||||||
|
pkgs=(
|
||||||
|
systemd
|
||||||
|
systemd-container
|
||||||
|
systemd-coredump
|
||||||
|
systemd-experimental
|
||||||
|
systemd-journal-remote
|
||||||
|
systemd-portable
|
||||||
|
udev
|
||||||
|
)
|
||||||
|
|
||||||
|
for p in "${pkgs[@]}"; do
|
||||||
|
rpm -q "$p" &>/dev/null || continue
|
||||||
|
|
||||||
|
ddebug "Install files from package $p"
|
||||||
|
while read -r f; do
|
||||||
|
[ -e "$f" ] || continue
|
||||||
|
[ -d "$f" ] && continue
|
||||||
|
inst "$f"
|
||||||
|
done < <(rpm -ql "$p")
|
||||||
|
done
|
||||||
|
|
||||||
|
# we only need testsdata dir as well as the unit tests (for
|
||||||
|
# TEST-02-UNITTESTS) in the image.
|
||||||
|
dinfo "Install unit tests and testdata directory"
|
||||||
|
|
||||||
|
mkdir -p "$initdir/$testsdir"
|
||||||
|
cp "$testsdir"/test-* "$initdir/$testsdir/"
|
||||||
|
cp -a "$testsdir/testdata" "$initdir/$testsdir/"
|
||||||
|
|
||||||
|
# On openSUSE, these dirs are not created at package install for now on.
|
||||||
|
mkdir -p "$initdir/var/log/journal/remote"
|
||||||
|
}
|
||||||
|
|
||||||
install_distro_systemd() {
|
install_distro_systemd() {
|
||||||
dinfo "Install distro systemd"
|
dinfo "Install distro systemd"
|
||||||
|
|
||||||
if get_bool "$LOOKS_LIKE_DEBIAN"; then
|
if get_bool "$LOOKS_LIKE_DEBIAN"; then
|
||||||
install_debian_systemd
|
install_debian_systemd
|
||||||
|
elif get_bool "$LOOKS_LIKE_SUSE"; then
|
||||||
|
install_suse_systemd
|
||||||
else
|
else
|
||||||
dfatal "NO_BUILD not supported for this distro"
|
dfatal "NO_BUILD not supported for this distro"
|
||||||
exit 1
|
exit 1
|
||||||
@ -958,8 +998,6 @@ install_systemd() {
|
|||||||
# remove unneeded documentation
|
# remove unneeded documentation
|
||||||
rm -fr "$initdir"/usr/share/{man,doc}
|
rm -fr "$initdir"/usr/share/{man,doc}
|
||||||
|
|
||||||
get_bool "$LOOKS_LIKE_SUSE" && setup_suse
|
|
||||||
|
|
||||||
# enable debug logging in PID1
|
# enable debug logging in PID1
|
||||||
echo LogLevel=debug >>"$initdir/etc/systemd/system.conf"
|
echo LogLevel=debug >>"$initdir/etc/systemd/system.conf"
|
||||||
# store coredumps in journal
|
# store coredumps in journal
|
||||||
@ -1390,6 +1428,16 @@ install_plymouth() {
|
|||||||
# fi
|
# fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_haveged() {
|
||||||
|
# If haveged is installed and probably included in initrd, it needs to be
|
||||||
|
# installed in the image too.
|
||||||
|
if [ -x /usr/sbin/haveged ]; then
|
||||||
|
dinfo "Install haveged files"
|
||||||
|
inst /usr/sbin/haveged
|
||||||
|
inst /usr/lib/systemd/system/haveged.service
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
install_ld_so_conf() {
|
install_ld_so_conf() {
|
||||||
dinfo "Install /etc/ld.so.conf*"
|
dinfo "Install /etc/ld.so.conf*"
|
||||||
cp -a /etc/ld.so.conf* "${initdir:?}/etc"
|
cp -a /etc/ld.so.conf* "${initdir:?}/etc"
|
||||||
@ -1551,7 +1599,7 @@ install_pam() {
|
|||||||
paths+=(/lib*/security)
|
paths+=(/lib*/security)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for d in /etc/pam.d /etc/security /usr/lib/pam.d; do
|
for d in /etc/pam.d /etc/security /usr/{etc,lib}/pam.d; do
|
||||||
[ -d "$d" ] && paths+=("$d")
|
[ -d "$d" ] && paths+=("$d")
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -1565,6 +1613,13 @@ install_pam() {
|
|||||||
|
|
||||||
# set empty root password for easy debugging
|
# set empty root password for easy debugging
|
||||||
sed -i 's/^root:x:/root::/' "${initdir:?}/etc/passwd"
|
sed -i 's/^root:x:/root::/' "${initdir:?}/etc/passwd"
|
||||||
|
|
||||||
|
# And make sure pam_unix will accept it by making sure that
|
||||||
|
# the PAM module has the nullok option.
|
||||||
|
for d in /etc/pam.d /usr/{etc,lib}/pam.d; do
|
||||||
|
[ -d "$initdir/$d" ] || continue
|
||||||
|
sed -i '/^auth.*pam_unix.so/s/$/ nullok/' "$initdir/$d"/*
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
install_keymaps() {
|
install_keymaps() {
|
||||||
@ -2406,12 +2461,6 @@ instmods() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_suse() {
|
|
||||||
ln -fs ../usr/bin/systemctl "${initdir:?}/bin/"
|
|
||||||
ln -fs ../usr/lib/systemd "$initdir/lib/"
|
|
||||||
inst_simple "/usr/lib/systemd/system/haveged.service"
|
|
||||||
}
|
|
||||||
|
|
||||||
_umount_dir() {
|
_umount_dir() {
|
||||||
local mountpoint="${1:?}"
|
local mountpoint="${1:?}"
|
||||||
if mountpoint -q "$mountpoint"; then
|
if mountpoint -q "$mountpoint"; then
|
||||||
|
|||||||
@ -30,19 +30,13 @@ if unshare -U sh -c :; then
|
|||||||
is_user_ns_supported=yes
|
is_user_ns_supported=yes
|
||||||
fi
|
fi
|
||||||
|
|
||||||
SUSE_OPTS=()
|
|
||||||
ID_LIKE=$(awk -F= '$1=="ID_LIKE" { print $2 ;}' /etc/os-release)
|
|
||||||
if [[ "$ID_LIKE" = *"suse"* ]]; then
|
|
||||||
SUSE_OPTS+=(--bind /lib64 --bind /usr/lib64)
|
|
||||||
fi
|
|
||||||
|
|
||||||
function check_bind_tmp_path {
|
function check_bind_tmp_path {
|
||||||
# https://github.com/systemd/systemd/issues/4789
|
# https://github.com/systemd/systemd/issues/4789
|
||||||
local _root="/var/lib/machines/testsuite-13.bind-tmp-path"
|
local _root="/var/lib/machines/testsuite-13.bind-tmp-path"
|
||||||
rm -rf "$_root"
|
rm -rf "$_root"
|
||||||
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
||||||
: >/tmp/bind
|
: >/tmp/bind
|
||||||
systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --bind=/tmp/bind /bin/sh -c 'test -e /tmp/bind'
|
systemd-nspawn --register=no -D "$_root" --bind=/tmp/bind /bin/sh -c 'test -e /tmp/bind'
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_norbind {
|
function check_norbind {
|
||||||
@ -54,15 +48,15 @@ function check_norbind {
|
|||||||
mount -t tmpfs tmpfs /tmp/binddir/subdir
|
mount -t tmpfs tmpfs /tmp/binddir/subdir
|
||||||
echo -n "inner" >/tmp/binddir/subdir/file
|
echo -n "inner" >/tmp/binddir/subdir/file
|
||||||
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
||||||
systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --bind=/tmp/binddir:/mnt:norbind /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi'
|
systemd-nspawn --register=no -D "$_root" --bind=/tmp/binddir:/mnt:norbind /bin/sh -c 'CONTENT=$(cat /mnt/subdir/file); if [[ $CONTENT != "outer" ]]; then echo "*** unexpected content: $CONTENT"; return 1; fi'
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_notification_socket {
|
function check_notification_socket {
|
||||||
# https://github.com/systemd/systemd/issues/4944
|
# https://github.com/systemd/systemd/issues/4944
|
||||||
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify'
|
local _cmd='echo a | $(busybox which nc) -U -u -w 1 /run/host/notify'
|
||||||
# /testsuite-13.nc-container is prepared by test.sh
|
# /testsuite-13.nc-container is prepared by test.sh
|
||||||
systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container /bin/sh -x -c "$_cmd"
|
systemd-nspawn --register=no -D /testsuite-13.nc-container /bin/sh -x -c "$_cmd"
|
||||||
systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd"
|
systemd-nspawn --register=no -D /testsuite-13.nc-container -U /bin/sh -x -c "$_cmd"
|
||||||
}
|
}
|
||||||
|
|
||||||
function check_os_release {
|
function check_os_release {
|
||||||
@ -84,7 +78,7 @@ if echo test >>/run/host/os-release; then exit 1; fi
|
|||||||
echo MARKER=1 >>/etc/os-release
|
echo MARKER=1 >>/etc/os-release
|
||||||
fi
|
fi
|
||||||
|
|
||||||
systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
|
systemd-nspawn --register=no -D /testsuite-13.nc-container --bind="${_os_release_source}":/tmp/os-release /bin/sh -x -e -c "$_cmd"
|
||||||
|
|
||||||
if grep -q MARKER /etc/os-release; then
|
if grep -q MARKER /etc/os-release; then
|
||||||
rm /etc/os-release
|
rm /etc/os-release
|
||||||
@ -93,7 +87,7 @@ if echo test >>/run/host/os-release; then exit 1; fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
function check_machinectl_bind {
|
function check_machinectl_bind {
|
||||||
local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep 0.5; done; exit 1;'
|
local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; usleep 500000; done; exit 1;'
|
||||||
|
|
||||||
cat >/run/systemd/system/nspawn_machinectl_bind.service <<EOF
|
cat >/run/systemd/system/nspawn_machinectl_bind.service <<EOF
|
||||||
[Service]
|
[Service]
|
||||||
@ -138,16 +132,16 @@ function run {
|
|||||||
local _root="/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3"
|
local _root="/var/lib/machines/testsuite-13.unified-$1-cgns-$2-api-vfs-writable-$3"
|
||||||
rm -rf "$_root"
|
rm -rf "$_root"
|
||||||
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
/usr/lib/systemd/tests/testdata/create-busybox-container "$_root"
|
||||||
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b
|
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -b
|
||||||
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --private-network -b
|
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -b
|
||||||
|
|
||||||
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -U -b; then
|
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -U -b; then
|
||||||
[[ "$is_user_ns_supported" = "yes" && "$3" = "network" ]] && return 1
|
[[ "$is_user_ns_supported" = "yes" && "$3" = "network" ]] && return 1
|
||||||
else
|
else
|
||||||
[[ "$is_user_ns_supported" = "no" && "$3" = "network" ]] && return 1
|
[[ "$is_user_ns_supported" = "no" && "$3" = "network" ]] && return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" --private-network -U -b; then
|
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" --private-network -U -b; then
|
||||||
[[ "$is_user_ns_supported" = "yes" && "$3" = "yes" ]] && return 1
|
[[ "$is_user_ns_supported" = "yes" && "$3" = "yes" ]] && return 1
|
||||||
else
|
else
|
||||||
[[ "$is_user_ns_supported" = "no" && "$3" = "yes" ]] && return 1
|
[[ "$is_user_ns_supported" = "no" && "$3" = "yes" ]] && return 1
|
||||||
@ -167,21 +161,21 @@ function run {
|
|||||||
# --network-namespace-path and network-related options cannot be used together
|
# --network-namespace-path and network-related options cannot be used together
|
||||||
for netopt in "${_net_opts[@]}"; do
|
for netopt in "${_net_opts[@]}"; do
|
||||||
echo "$_netns_opt in combination with $netopt should fail"
|
echo "$_netns_opt in combination with $netopt should fail"
|
||||||
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b "$_netns_opt" "$netopt"; then
|
if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -b "$_netns_opt" "$netopt"; then
|
||||||
echo >&2 "unexpected pass"
|
echo >&2 "unexpected pass"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# allow combination of --network-namespace-path and --private-network
|
# allow combination of --network-namespace-path and --private-network
|
||||||
if ! SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" -b "$_netns_opt" --private-network; then
|
if ! SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" -b "$_netns_opt" --private-network; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# test --network-namespace-path works with a network namespace created by "ip netns"
|
# test --network-namespace-path works with a network namespace created by "ip netns"
|
||||||
ip netns add nspawn_test
|
ip netns add nspawn_test
|
||||||
_netns_opt="--network-namespace-path=/run/netns/nspawn_test"
|
_netns_opt="--network-namespace-path=/run/netns/nspawn_test"
|
||||||
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn "${SUSE_OPTS[@]}" --register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP'
|
SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$1" SYSTEMD_NSPAWN_USE_CGNS="$2" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$3" systemd-nspawn --register=no -D "$_root" "$_netns_opt" /bin/ip a | grep -v -E '^1: lo.*UP'
|
||||||
local r=$?
|
local r=$?
|
||||||
ip netns del nspawn_test
|
ip netns del nspawn_test
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user