From 81371f665f8043fcf4c0c5144635dd93eb68f9bb Mon Sep 17 00:00:00 2001 From: Stefan Reiter Date: Thu, 30 Sep 2021 10:03:05 +0200 Subject: [PATCH] swtpm_setup: add abstract swtpm_backend_ops with dir:// implementation Abstract away implementation specific code for handling TPM state in swtpm_setup. The current code for handling directories is moved to 'swtpm_backend_dir.c'. Where possible, the input argument is simply passed verbatim as 'backend-uri' to swtpm. No functional change intended, aside from supporting 'dir://' as optional prefix. The checks for lock-file accessibility are moved to check_access(), but that shouldn't affect anything AFAICT. Signed-off-by: Stefan Reiter --- src/swtpm_setup/Makefile.am | 3 +- src/swtpm_setup/swtpm.c | 4 +- src/swtpm_setup/swtpm.h | 11 +++ src/swtpm_setup/swtpm_backend_dir.c | 118 ++++++++++++++++++++++++++++ src/swtpm_setup/swtpm_setup.c | 86 +++++--------------- 5 files changed, 153 insertions(+), 69 deletions(-) create mode 100644 src/swtpm_setup/swtpm_backend_dir.c diff --git a/src/swtpm_setup/Makefile.am b/src/swtpm_setup/Makefile.am index 26e3f68..eb2d5e8 100644 --- a/src/swtpm_setup/Makefile.am +++ b/src/swtpm_setup/Makefile.am @@ -18,7 +18,8 @@ bin_PROGRAMS = \ swtpm_setup_SOURCES = \ swtpm.c \ swtpm_setup.c \ - swtpm_setup_utils.c + swtpm_setup_utils.c \ + swtpm_backend_dir.c $(top_builddir)/src/utils/libswtpm_utils.la: $(MAKE) -C$(dir $@) diff --git a/src/swtpm_setup/swtpm.c b/src/swtpm_setup/swtpm.c index 03e1db3..b5de43b 100644 --- a/src/swtpm_setup/swtpm.c +++ b/src/swtpm_setup/swtpm.c @@ -56,7 +56,7 @@ struct tpm_resp_header { static int swtpm_start(struct swtpm *self) { - g_autofree gchar *tpmstate_dir = g_strdup_printf("dir=%s", self->state_path); + g_autofree gchar *tpmstate = g_strdup_printf("backend-uri=%s", self->state_path); g_autofree gchar *pidfile_arg = NULL; g_autofree gchar *server_fd = NULL; g_autofree gchar *ctrl_fd = NULL; @@ -81,7 +81,7 @@ static int swtpm_start(struct swtpm *self) argv = concat_arrays(self->swtpm_exec_l, (gchar*[]){ "--flags", "not-need-init,startup-clear", - "--tpmstate", tpmstate_dir, + "--tpmstate", tpmstate, "--pid", pidfile_arg, #if 0 "--log", "file=/tmp/log,level=20", diff --git a/src/swtpm_setup/swtpm.h b/src/swtpm_setup/swtpm.h index 103ce6f..28cfa6e 100644 --- a/src/swtpm_setup/swtpm.h +++ b/src/swtpm_setup/swtpm.h @@ -11,6 +11,7 @@ #define SWTPM_SETUP_SWTPM_H #include +#include #include @@ -93,4 +94,14 @@ struct swtpm2 *swtpm2_new(gchar **swtpm_prg_l, const gchar *tpm_state_path, void swtpm_free(struct swtpm *); +/* backend-specific implementations */ +struct swtpm_backend_ops { + void* (*parse_backend)(const gchar* uri); + int (*check_access)(void *backend, int mode, const struct passwd *curr_user); + int (*delete_state)(void *backend); + void (*free_backend)(void *backend); +}; + +extern struct swtpm_backend_ops swtpm_backend_dir; + #endif /* SWTPM_SETUP_SWTPM_H */ diff --git a/src/swtpm_setup/swtpm_backend_dir.c b/src/swtpm_setup/swtpm_backend_dir.c new file mode 100644 index 0000000..ac2c18b --- /dev/null +++ b/src/swtpm_setup/swtpm_backend_dir.c @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* + * swtpm_backend_dir.c: storage backend specific functions for dir:// + * + * Originally by: Stefan Berger, stefanb@linux.ibm.com + * Refactored as module: Stefan Reiter, stefan@pimaker.at + */ + +#include +#include +#include +#include + +#include "swtpm.h" +#include "swtpm_utils.h" + +struct dir_state { + gchar* dir; +}; + +/* Parse a dir:// URI by removing the prefix if given. */ +static void *parse_dir_state(const gchar* uri) { + struct dir_state *ret; + + if (strncmp(uri, "dir://", 6) == 0) { + uri += 6; + } + + ret = g_malloc(sizeof(struct dir_state)); + ret->dir = g_strdup(uri); + + return (void*)ret; +} + +/* Check user access in 'mode' to directory specified in backend state. */ +static int check_access(void *state, int mode, const struct passwd *curr_user) { + gchar *tpm_state_path = ((struct dir_state*)state)->dir; + gchar *p; + struct stat statbuf; + char path[PATH_MAX]; + + /* check lockfile */ + p = pathjoin(path, sizeof(path), tpm_state_path, ".lock", NULL); + if (!p) + return 1; + if (stat(p, &statbuf) == 0 && access(p, R_OK|W_OK) != 0) { + logerr(gl_LOGFILE, "User %s cannot read/write lockfile %s.\n", + curr_user ? curr_user->pw_name : "", p); + return 1; + } + + /* check access to state directory itself */ + return check_directory_access(tpm_state_path, mode, curr_user); +} + +/* Delete swtpm's state file. Those are the files with suffixes + * 'permall', 'volatilestate', and 'savestate'. + */ +static int delete_statefiles(void *state) +{ + gchar *tpm_state_path = ((struct dir_state*)state)->dir; + GError *error = NULL; + GDir *dir = g_dir_open(tpm_state_path, 0, &error); + int ret = 1; + + if (dir == NULL) { + logerr(gl_LOGFILE, "%s\n", error->message); + g_error_free(error); + return 1; + } + while (1) { + const gchar *fn = g_dir_read_name(dir); + + if (fn == NULL) { + if (errno != 0 && errno != ENOENT +#ifdef __FreeBSD__ + && errno != EINVAL +#endif + ) { + logerr(gl_LOGFILE, "Error getting next filename: %s\n", strerror(errno)); + break; + } else { + ret = 0; + break; + } + } + if (g_str_has_suffix(fn, "permall") || + g_str_has_suffix(fn, "volatilestate") || + g_str_has_suffix(fn, "savestate")) { + g_autofree gchar *fullname = g_strjoin(G_DIR_SEPARATOR_S, + tpm_state_path, fn, NULL); + if (unlink(fullname) != 0) { + logerr(gl_LOGFILE, "Could not remove %s: %s\n", fn, strerror(errno)); + break; + } + } + } + + g_dir_close(dir); + + return ret; +} + +/* Free an instance of dir_state. */ +static void free_dir_state(void *state) { + if (state) { + struct dir_state *dstate = (struct dir_state*)state; + g_free(dstate->dir); + g_free(dstate); + } +} + +struct swtpm_backend_ops swtpm_backend_dir = { + .parse_backend = parse_dir_state, + .check_access = check_access, + .delete_state = delete_statefiles, + .free_backend = free_dir_state, +}; diff --git a/src/swtpm_setup/swtpm_setup.c b/src/swtpm_setup/swtpm_setup.c index 2092113..20f0674 100644 --- a/src/swtpm_setup/swtpm_setup.c +++ b/src/swtpm_setup/swtpm_setup.c @@ -703,14 +703,14 @@ static int check_state_overwrite(gchar **swtpm_prg_l, unsigned int flags, int exit_status = 0; g_autoptr(GError) error = NULL; g_autofree gchar **argv = NULL; - g_autofree gchar *dirop = g_strdup_printf("dir=%s", tpm_state_path); + g_autofree gchar *statearg = g_strdup_printf("backend-uri=%s", tpm_state_path); g_autofree gchar *logop = NULL; g_autofree gchar **my_argv = NULL; my_argv = concat_arrays((gchar*[]) { "--print-states", "--tpmstate", - dirop, + statearg, NULL }, NULL, FALSE); @@ -1081,53 +1081,6 @@ error: return ret; } -/* Delete swtpm's state file. Those are the files with suffixes - * 'permall', 'volatilestate', and 'savestate'. - */ -static int delete_swtpm_statefiles(const gchar *tpm_state_path) -{ - GError *error = NULL; - GDir *dir = g_dir_open(tpm_state_path, 0, &error); - int ret = 1; - - if (dir == NULL) { - logerr(gl_LOGFILE, "%s\n", error->message); - g_error_free(error); - return 1; - } - while (1) { - const gchar *fn = g_dir_read_name(dir); - - if (fn == NULL) { - if (errno != 0 && errno != ENOENT -#ifdef __FreeBSD__ - && errno != EINVAL -#endif - ) { - logerr(gl_LOGFILE, "Error getting next filename: %s\n", strerror(errno)); - break; - } else { - ret = 0; - break; - } - } - if (g_str_has_suffix(fn, "permall") || - g_str_has_suffix(fn, "volatilestate") || - g_str_has_suffix(fn, "savestate")) { - g_autofree gchar *fullname = g_strjoin(G_DIR_SEPARATOR_S, - tpm_state_path, fn, NULL); - if (unlink(fullname) != 0) { - logerr(gl_LOGFILE, "Coud not remove %s: %s\n", fn, strerror(errno)); - break; - } - } - } - - g_dir_close(dir); - - return ret; -} - int main(int argc, char *argv[]) { int opt, option_index = 0; @@ -1174,6 +1127,8 @@ int main(int argc, char *argv[]) unsigned long flags = 0; g_autofree gchar *swtpm_prg = NULL; g_autofree gchar *tpm_state_path = NULL; + struct swtpm_backend_ops *backend_ops = &swtpm_backend_dir; + void *backend_state = NULL; g_autofree gchar *config_file = NULL; g_autofree gchar *ownerpass = NULL; gboolean got_ownerpass = FALSE; @@ -1201,10 +1156,7 @@ int main(int argc, char *argv[]) const struct passwd *curr_user; struct group *curr_grp; char *endptr; - char path[PATH_MAX]; - char *p; gboolean swtpm_has_tpm12, swtpm_has_tpm2; - g_autofree gchar *lockfile = NULL; int fds_to_pass[1] = { -1 }; unsigned n_fds_to_pass = 0; char tmpbuffer[200]; @@ -1228,7 +1180,12 @@ int main(int argc, char *argv[]) switch (opt) { case 't': /* --tpmstate, --tpm-state */ g_free(tpm_state_path); - tpm_state_path = g_strdup(optarg); + if (strncmp(optarg, "dir://", 6) == 0) { + tpm_state_path = g_strdup(optarg); + } else { + /* always prefix with dir:// so we can pass verbatim to swtpm */ + tpm_state_path = g_strconcat("dir://", optarg, NULL); + } break; case 'T': /* --tpm */ g_free(swtpm_prg); @@ -1446,7 +1403,12 @@ int main(int argc, char *argv[]) logerr(gl_LOGFILE, "--tpm-state must be provided\n"); goto error; } - if (check_directory_access(tpm_state_path, R_OK|W_OK, curr_user) != 0) + + backend_state = backend_ops->parse_backend(tpm_state_path); + if (!backend_state) + goto error; + + if (backend_ops->check_access(backend_state, R_OK|W_OK, curr_user) != 0) goto error; if ((flags & SETUP_WRITE_EK_CERT_FILES_F)) { @@ -1478,20 +1440,10 @@ int main(int argc, char *argv[]) goto out; } - ret = delete_swtpm_statefiles(tpm_state_path); + ret = backend_ops->delete_state(backend_state); if (ret != 0) goto error; - p = pathjoin(path, sizeof(path), tpm_state_path, ".lock", NULL); - if (!p) - goto error; - lockfile = g_strdup(p); - if (stat(lockfile, &statbuf) == 0 && access(lockfile, R_OK|W_OK) != 0) { - logerr(gl_LOGFILE, "User %s cannot read/write lockfile %s.\n", - curr_user ? curr_user->pw_name : "", lockfile); - goto error; - } - if (access(config_file, R_OK) != 0) { logerr(gl_LOGFILE, "User %s cannot read config file %s.\n", curr_user ? curr_user->pw_name : "", config_file); @@ -1608,7 +1560,7 @@ int main(int argc, char *argv[]) logit(gl_LOGFILE, "Successfully authored TPM state.\n"); } else { logerr(gl_LOGFILE, "An error occurred. Authoring the TPM state failed.\n"); - delete_swtpm_statefiles(tpm_state_path); + backend_ops->delete_state(backend_state); } now = time(NULL); @@ -1625,6 +1577,8 @@ out: logerr(gl_LOGFILE, "Could not remove temporary directory for certs: %s\n", strerror(errno)); + if (backend_ops && backend_state) + backend_ops->free_backend(backend_state); g_strfreev(swtpm_prg_l); g_free(gl_LOGFILE);