]> git.proxmox.com Git - swtpm.git/blob - src/swtpm_localca/swtpm_localca_utils.c
tests: Use SOCK_STREAM for CMD_SET_DATAFD socketpair
[swtpm.git] / src / swtpm_localca / swtpm_localca_utils.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * swtpm_localca_utils.c: Utility functions
4 *
5 * Author: Stefan Berger, stefanb@linux.ibm.com
6 *
7 * Copyright (c) IBM Corporation, 2021
8 */
9
10 #include "config.h"
11
12 #define _GNU_SOURCE
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <regex.h>
21 #include <errno.h>
22 #include <sys/file.h>
23
24 #include "swtpm_utils.h"
25 #include "swtpm_localca.h"
26 #include "swtpm_localca_utils.h"
27
28 /* Create a directory pat (and all its predecessors) if it doesn't exist */
29 int makedir(const char *dirname, const char *purpose)
30 {
31 struct stat statbuf;
32
33 if (stat(dirname, &statbuf) != 0) {
34 logit(gl_LOGFILE, "Creating swtpm-localca dir '%s'.\n", dirname);
35 if (g_mkdir_with_parents(dirname, S_IRWXU | S_IRWXG | S_IXGRP | S_IRGRP) == -1) {
36 logerr(gl_LOGFILE, "Could not create directory for '%s': %s\n",
37 purpose, strerror(errno));
38 return 1;
39 }
40 }
41 return 0;
42 }
43
44 /* Get a configuration value given its name */
45 gchar *get_config_value(gchar **config_file_lines, const gchar *configname, const gchar *fallback)
46 {
47 g_autofree gchar *regex = g_strdup_printf("^%s[[:space:]]*=[[:space:]]*([^#\n]*).*", configname);
48 gchar *result = NULL;
49 regex_t preg;
50 size_t idx;
51 regmatch_t pmatch[2];
52
53 if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
54 logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
55 goto error;
56 }
57
58 for (idx = 0; config_file_lines[idx] != NULL; idx++) {
59 const gchar *line = config_file_lines[idx];
60 if (regexec(&preg, line, 2, pmatch, 0) == 0) {
61 g_autofree gchar *tmp = NULL;
62
63 tmp = g_strndup(&line[pmatch[1].rm_so],
64 pmatch[1].rm_eo - pmatch[1].rm_so);
65 g_strchomp(tmp);
66 result = resolve_string(tmp);
67 break;
68 }
69 }
70 regfree(&preg);
71
72 error:
73 if (result == NULL)
74 result = g_strdup(fallback);
75 //printf("Found match for %s: |%s|\n", configname, result);
76
77 return result;
78 }
79
80 /* Extract all environment variables from the config file and add them to
81 * the given environent.
82 * Environment variable lines must start with 'env:' and must not contain
83 * trailing spaces or a comment starting with '#'
84 */
85 int get_config_envvars(gchar **config_file_lines, gchar ***env)
86 {
87 const char *regex = "^env:([a-zA-Z_][a-zA-Z_0-9]*)[[:space:]]*=[[:space:]]*([^\n]*)";
88 regex_t preg;
89 size_t idx;
90 regmatch_t pmatch[3];
91
92 if (regcomp(&preg, regex, REG_EXTENDED) != 0) {
93 logerr(gl_LOGFILE, "Internal error: Could not compile regex\n");
94 return 1;
95 }
96
97 for (idx = 0; config_file_lines[idx] != NULL; idx++) {
98 const gchar *line = config_file_lines[idx];
99 if (regexec(&preg, line, 3, pmatch, 0) == 0) {
100 g_autofree gchar *key = NULL, *value = NULL;
101
102 key = g_strndup(&line[pmatch[1].rm_so],
103 pmatch[1].rm_eo - pmatch[1].rm_so);
104 value = g_strndup(&line[pmatch[2].rm_so],
105 pmatch[2].rm_eo - pmatch[2].rm_so);
106 *env = g_environ_setenv(*env, key, value, TRUE);
107 }
108 }
109
110 regfree(&preg);
111
112 return 0;
113 }
114
115 /* flock a file; the file descriptor for the file to unlock later on is returned */
116 int lock_file(const gchar *lockfile)
117 {
118 int lockfd;
119 mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
120
121 lockfd = open(lockfile, O_RDWR | O_CREAT, mode);
122 if (lockfd < 0) {
123 logerr(gl_LOGFILE, "Could not open lockfile %s: %s\n", lockfile, strerror(errno));
124 return -1;
125 }
126
127 if (flock(lockfd, LOCK_EX) < 0) {
128 logerr(gl_LOGFILE, "Could not lock file %s: %s\n", lockfile, strerror(errno));
129 close(lockfd);
130 return -1;
131 }
132 return lockfd;
133 }
134
135 /* unlock a file previously locked using lock_file */
136 void unlock_file(int lockfd) {
137 if (lockfd >= 0) {
138 flock(lockfd, LOCK_UN);
139 close(lockfd);
140 }
141 }
142
143 /* Replace a few characters in vmid so it can be used by CommonName in cert */
144 void vmid_replacechars(char *vmid) {
145 size_t i = 0;
146 char c;
147
148 while ((c = vmid[i])) {
149 switch (c) {
150 case '+':
151 // https://github.com/gnutls/gnutls/blob/gnutls_3_6_x/lib/x509/x509_dn.c#L167
152 if (i == 0 || vmid[i - 1] != '\\')
153 vmid[i] = '_';
154 break;
155 case ',':
156 // no commas allowed
157 vmid[i] = '_';
158 break;
159 }
160 i++;
161 }
162 }