| /* SPDX-License-Identifier: BSD-3-Clause */ |
| /* |
| * swtpm_setup_utils.c: Utility functions for swtpm_setup |
| * |
| * Author: Stefan Berger, stefanb@linux.ibm.com |
| * |
| * Copyright (c) IBM Corporation, 2021 |
| */ |
| |
| #include "config.h" |
| |
| #include <errno.h> |
| #include <regex.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/utsname.h> |
| #include <unistd.h> |
| |
| #include <glib.h> |
| |
| #include "swtpm_setup_conf.h" |
| #include "swtpm_setup_utils.h" |
| #include "swtpm_utils.h" |
| |
| /* Get a configuration value given its name */ |
| gchar *get_config_value(gchar **config_file_lines, const gchar *configname) |
| { |
| g_autofree gchar *regex = g_strdup_printf("^%s[[:space:]]*=[[:space:]]*([^#\n]*).*", |
| configname); |
| gchar *result = NULL; |
| regmatch_t pmatch[2]; |
| regex_t preg; |
| size_t idx; |
| |
| if (regcomp(&preg, regex, REG_EXTENDED) != 0) { |
| logerr(gl_LOGFILE, "Internal error: Could not compile regex\n"); |
| return NULL; |
| } |
| |
| for (idx = 0; config_file_lines[idx] != NULL; idx++) { |
| const gchar *line = config_file_lines[idx]; |
| if (regexec(&preg, line, 2, pmatch, 0) == 0) { |
| g_autofree gchar *tmp = NULL; |
| |
| tmp = g_strndup(&line[pmatch[1].rm_so], |
| pmatch[1].rm_eo - pmatch[1].rm_so); |
| g_strchomp(tmp); |
| result = resolve_string(tmp); |
| break; |
| } |
| } |
| |
| regfree(&preg); |
| |
| return result; |
| } |
| |
| /* Create swtpm_setup and swtpm-localca config files for a user |
| * |
| * @overwrite: TRUE: overwrite any existing config files |
| * FALSE: return error if any file exists |
| * @root_flag: TRUE: create the config files under root's home |
| * directory shadowing any existing config files in /etc/ |
| * FALSE: refuse to create config files as root |
| * @skip_if_exist: TRUE if any one config files exists return with no error |
| * |
| */ |
| int create_config_files(gboolean overwrite, gboolean root_flag, |
| gboolean skip_if_exist) |
| { |
| enum { |
| SWTPM_SETUP_CONF = 0, |
| SWTPM_LOCALCA_CONF = 1, |
| SWTPM_LOCALCA_OPTIONS = 2, |
| NUM_FILES = 3, |
| }; |
| const gchar *filenames[NUM_FILES] = { |
| "swtpm_setup.conf", |
| "swtpm-localca.conf", |
| "swtpm-localca.options" |
| }; |
| const gchar *configdir = g_get_user_config_dir(); |
| g_autofree gchar *create_certs_tool = NULL; |
| g_autofree gchar *swtpm_localca_dir = NULL; |
| g_autofree gchar *signkey = NULL; |
| g_autofree gchar *issuercert = NULL; |
| g_autofree gchar *certserial = NULL; |
| g_autofree gchar *platform_manufacturer = NULL; |
| g_autofree gchar *platform_version = NULL; |
| g_autofree gchar *platform_model = NULL; |
| g_autoptr(GError) error = NULL; |
| gboolean delete_files = FALSE; |
| g_auto(GStrv) configfiles = NULL; |
| g_auto(GStrv) filedata = NULL; |
| struct utsname utsname; |
| int ret = 1; |
| size_t i; |
| |
| if (getuid() == 0 && !root_flag) { |
| fprintf(stderr, "Requiring the 'root' flag since the configuration " |
| "files will shadow those in %s.\n", SYSCONFDIR); |
| goto error; |
| } |
| |
| configfiles = g_new0(gchar *, NUM_FILES + 1); |
| for (i = 0; i < NUM_FILES; i++) { |
| configfiles[i] = g_build_filename(configdir, filenames[i], NULL); |
| if (!overwrite && g_file_test(configfiles[i], G_FILE_TEST_EXISTS)) { |
| if (skip_if_exist) { |
| ret = 0; |
| } else { |
| fprintf(stderr, "File %s already exists. Refusing to overwrite.\n", |
| configfiles[i]); |
| } |
| goto out; |
| } |
| } |
| |
| swtpm_localca_dir = g_build_filename(configdir, |
| "var", "lib", "swtpm-localca", NULL); |
| if (g_mkdir_with_parents(swtpm_localca_dir, 0775) < 0) { |
| fprintf(stderr, "Could not create %s: %s\n", |
| swtpm_localca_dir, strerror(errno)); |
| goto error; |
| } |
| |
| filedata = g_new0(gchar *, NUM_FILES + 1); |
| |
| /* setpm_setup.conf */ |
| create_certs_tool = g_build_filename(BINDIR, |
| "swtpm_localca", NULL); |
| filedata[SWTPM_SETUP_CONF] = g_strdup_printf( |
| "create_certs_tool = %s\n" |
| "create_certs_tool_config = %s\n" |
| "create_certs_tool_options = %s\n" |
| "# Comma-separated list (no spaces) of PCR banks to activate by default\n" |
| "active_pcr_banks = %s\n", |
| create_certs_tool, |
| configfiles[SWTPM_LOCALCA_CONF], |
| configfiles[SWTPM_LOCALCA_OPTIONS], |
| DEFAULT_PCR_BANKS |
| ); |
| |
| /* swtpm-localca.conf */ |
| signkey = g_build_filename(swtpm_localca_dir, "signkey.pem", NULL); |
| issuercert = g_build_filename(swtpm_localca_dir, "issuercert.pem", NULL); |
| certserial = g_build_filename(swtpm_localca_dir, "certserial", NULL); |
| filedata[SWTPM_LOCALCA_CONF] = g_strdup_printf( |
| "statedir = %s\n" |
| "signingkey = %s\n" |
| "issuercert = %s\n" |
| "certserial = %s\n", |
| swtpm_localca_dir, |
| signkey, |
| issuercert, |
| certserial |
| ); |
| |
| /* swtpm-localca.options */ |
| if (uname(&utsname) < 0) { |
| fprintf(stderr, "uname failed: %s\n", strerror(errno)); |
| goto error; |
| } |
| |
| platform_manufacturer = str_replace(utsname.sysname, " ", "_"); |
| platform_version = str_replace(utsname.version, " ", "_"); |
| platform_model = str_replace(utsname.sysname, " ", "_"); |
| |
| filedata[SWTPM_LOCALCA_OPTIONS] = g_strdup_printf( |
| "--platform-manufacturer %s\n" |
| "--platform-version %s\n" |
| "--platform-model %s\n", |
| platform_manufacturer, |
| platform_version, |
| platform_model |
| ); |
| |
| for (i = 0; i < NUM_FILES; i++) { |
| fprintf(stdout, "Writing %s.\n", configfiles[i]); |
| if (!g_file_set_contents(configfiles[i], filedata[i], -1, &error)) { |
| fprintf(stderr, |
| "Could not write to %s: %s\n", |
| configfiles[i], strerror(errno)); |
| delete_files = TRUE; |
| goto error; |
| } |
| } |
| |
| ret = 0; |
| |
| error: |
| if (delete_files) { |
| for (i = 0; i < NUM_FILES; i++) |
| unlink(configfiles[i]); |
| } |
| |
| out: |
| return ret; |
| } |