blob: a0d0f4d2012e5319d59dc82eed58308b645d9b28 [file] [log] [blame]
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* swtpm_backend_file.c: storage backend specific functions for file://
*
* Author: Stefan Reiter, stefan@pimaker.at
*/
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "compiler_dependencies.h"
#include "swtpm.h"
#include "swtpm_utils.h"
struct file_state {
gchar* path;
bool is_blockdev;
};
/* Parse a file:// URI by removing the prefix and checking if block device. */
static void *parse_file_state(const gchar* uri) {
struct file_state *ret;
struct stat statbuf;
int stat_ret;
bool noent = false;
if (strncmp(uri, "file://", 7) == 0) {
uri += 7;
}
stat_ret = stat(uri, &statbuf);
if (stat_ret != 0) {
noent = errno == ENOENT;
if (!noent) {
logerr(gl_LOGFILE, "Couldn't stat file %s: %s\n", uri, strerror(errno));
return NULL;
}
}
ret = g_malloc(sizeof(struct file_state));
ret->path = g_strdup(uri);
ret->is_blockdev = noent ? false : S_ISBLK(statbuf.st_mode);
return (void*)ret;
}
/* Check user access in 'mode' to file/blockdev specified in backend state. */
static int check_access(void *state,
int mode SWTPM_ATTR_UNUSED,
const struct passwd *curr_user SWTPM_ATTR_UNUSED) {
const gchar *path = ((struct file_state*)state)->path;
int ret = access(path, R_OK|W_OK);
return ret == 0 || errno == ENOENT ? 0 : 1;
}
/* Delete state from file: if regular file, unlink, if blockdev, zero header so
* swtpm binary will treat it as a new instance. */
static int delete_state(void *state) {
const struct file_state *fstate = (struct file_state*)state;
int fd;
if (fstate->is_blockdev) {
char zerobuf[8] = {0}; /* swtpm header has 8 byte */
fd = open(fstate->path, O_WRONLY);
if (fd < 0) {
logerr(gl_LOGFILE, "Couldn't open file for clearing %s: %s\n",
fstate->path, strerror(errno));
return 1;
}
/* writing less bytes than requested is bad, but won't set errno */
errno = 0;
if (write(fd, zerobuf, sizeof(zerobuf)) < (long)sizeof(zerobuf)) {
logerr(gl_LOGFILE, "Couldn't write file for clearing %s: %s\n",
fstate->path, strerror(errno));
close(fd);
return 1;
}
close(fd);
} else {
if (unlink(fstate->path)) {
logerr(gl_LOGFILE, "Couldn't unlink file for clearing %s: %s\n",
fstate->path, strerror(errno));
return 1;
}
}
return 0;
}
/* Free an instance of file_state. */
static void free_file_state(void *state) {
if (state) {
struct file_state *fstate = (struct file_state*)state;
g_free(fstate->path);
g_free(fstate);
}
}
struct swtpm_backend_ops swtpm_backend_file = {
.parse_backend = parse_file_state,
.check_access = check_access,
.delete_state = delete_state,
.free_backend = free_file_state,
};