blob: ac2c18ba901b1b56a34374eeac8a317983f788f4 [file] [log] [blame]
/* 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 <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#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 : "<unknown>", 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,
};