]> git.proxmox.com Git - swtpm.git/blob - src/swtpm/swtpm_nvstore_dir.c
swtpm: Add missing braces around TPM_DEBUG after if statement
[swtpm.git] / src / swtpm / swtpm_nvstore_dir.c
1 /********************************************************************************/
2 /* */
3 /* NVRAM File Abstraction Layer */
4 /* Written by Ken Goldman */
5 /* Adapted to SWTPM by Stefan Berger */
6 /* IBM Thomas J. Watson Research Center */
7 /* */
8 /* (c) Copyright IBM Corporation 2006, 2010, 2014, 2015. */
9 /* */
10 /* All rights reserved. */
11 /* */
12 /* Redistribution and use in source and binary forms, with or without */
13 /* modification, are permitted provided that the following conditions are */
14 /* met: */
15 /* */
16 /* Redistributions of source code must retain the above copyright notice, */
17 /* this list of conditions and the following disclaimer. */
18 /* */
19 /* Redistributions in binary form must reproduce the above copyright */
20 /* notice, this list of conditions and the following disclaimer in the */
21 /* documentation and/or other materials provided with the distribution. */
22 /* */
23 /* Neither the names of the IBM Corporation nor the names of its */
24 /* contributors may be used to endorse or promote products derived from */
25 /* this software without specific prior written permission. */
26 /* */
27 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
28 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
29 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
30 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
31 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
32 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
33 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
34 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
35 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
36 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
37 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
38 /********************************************************************************/
39
40 #include "config.h"
41
42 #define _GNU_SOURCE
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <errno.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49
50 #include <libtpms/tpm_error.h>
51
52 #include "swtpm.h"
53 #include "swtpm_debug.h"
54 #include "swtpm_nvstore.h"
55 #include "swtpm_nvstore_dir.h"
56 #include "key.h"
57 #include "logging.h"
58 #include "tpmstate.h"
59 #include "utils.h"
60
61 struct nvram_backend_ops nvram_dir_ops = {
62 .prepare = SWTPM_NVRAM_Prepare_Dir,
63 .load = SWTPM_NVRAM_LoadData_Dir,
64 .store = SWTPM_NVRAM_StoreData_Dir,
65 .delete = SWTPM_NVRAM_DeleteName_Dir,
66 };
67
68 /* SWTPM_NVRAM_GetFilenameForName() constructs a rooted file name from the name.
69
70 The filename is of the form:
71
72 tpm_state_path/tpm_number.name
73
74 A temporary filename used to write to may be created. It should be rename()'d to
75 the non-temporary filename.
76 */
77
78 static TPM_RESULT
79 SWTPM_NVRAM_GetFilenameForName(char *filename, /* output: rooted filename */
80 size_t bufsize,
81 uint32_t tpm_number,
82 const char *name, /* input: abstract name */
83 bool is_tempfile, /* input: is temporary file? */
84 const char *tpm_state_path)
85 {
86 TPM_RESULT res = TPM_SUCCESS;
87 int n;
88 const char *suffix = "";
89
90 TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: For name %s\n", name);
91
92 switch (tpmstate_get_version()) {
93 case TPMLIB_TPM_VERSION_1_2:
94 break;
95 case TPMLIB_TPM_VERSION_2:
96 suffix = "2";
97 break;
98 }
99
100 if (is_tempfile) {
101 n = snprintf(filename, bufsize, "%s/TMP%s-%02lx.%s",
102 tpm_state_path, suffix, (unsigned long)tpm_number, name);
103 } else {
104 n = snprintf(filename, bufsize, "%s/tpm%s-%02lx.%s",
105 tpm_state_path, suffix, (unsigned long)tpm_number, name);
106 }
107 if ((size_t)n > bufsize) {
108 res = TPM_FAIL;
109 }
110
111 TPM_DEBUG(" SWTPM_NVRAM_GetFilenameForName: File name %s\n", filename);
112
113 return res;
114 }
115
116 static const char *
117 SWTPM_NVRAM_Uri_to_Dir(const char *uri)
118 {
119 return uri + strlen("dir://");
120 }
121
122 static TPM_RESULT
123 SWTPM_NVRAM_Validate_Dir(const char *tpm_state_path)
124 {
125 TPM_RESULT rc = 0;
126 size_t length;
127
128 /* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */
129 if (rc == 0) {
130 if (tpm_state_path == NULL) {
131 logprintf(STDERR_FILENO,
132 "SWTPM_NVRAM_Validate_Dir: Error (fatal), TPM_PATH environment "
133 "variable not set\n");
134 rc = TPM_FAIL;
135 }
136 }
137
138 /* check that the directory name plus a file name will not overflow FILENAME_MAX */
139 if (rc == 0) {
140 length = strlen(tpm_state_path);
141 if ((length + TPM_FILENAME_MAX) > FILENAME_MAX) {
142 logprintf(STDERR_FILENO,
143 "SWTPM_NVRAM_Validate_Dir: Error (fatal), TPM state path name "
144 "%s too large\n", tpm_state_path);
145 rc = TPM_FAIL;
146 }
147 }
148 if (rc == 0) {
149 TPM_DEBUG("SWTPM_NVRAM_Validate_Dir: Rooted state path %s\n", tpm_state_path);
150 }
151
152 return rc;
153 }
154
155 static TPM_RESULT
156 SWTPM_NVRAM_Lock_Dir(const char *tpm_state_path)
157 {
158 TPM_RESULT rc = 0;
159 int fd;
160 char *lockfile = NULL;
161 struct flock flock = {
162 .l_type = F_WRLCK,
163 .l_whence = SEEK_SET,
164 .l_start = 0,
165 .l_len = 0,
166 };
167
168 if (asprintf(&lockfile, "%s/.lock", tpm_state_path) < 0) {
169 logprintf(STDERR_FILENO,
170 "SWTPM_NVRAM_Lock_Dir: Could not asprintf lock filename\n");
171 return TPM_FAIL;
172 }
173
174 fd = open(lockfile, O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW, 0660);
175 if (fd < 0) {
176 logprintf(STDERR_FILENO,
177 "SWTPM_NVRAM_Lock_Dir: Could not open lockfile: %s\n",
178 strerror(errno));
179 rc = TPM_FAIL;
180 goto exit;
181 }
182
183 if (fcntl(fd, F_SETLK, &flock) < 0) {
184 logprintf(STDERR_FILENO,
185 "SWTPM_NVRAM_Lock_Dir: Could not lock access to lockfile: %s\n",
186 strerror(errno));
187 rc = TPM_FAIL;
188 close(fd);
189 }
190 exit:
191 free(lockfile);
192
193 return rc;
194 }
195
196 TPM_RESULT
197 SWTPM_NVRAM_Prepare_Dir(const char *uri)
198 {
199 TPM_RESULT rc = 0;
200 const char *tpm_state_path = NULL;
201
202 tpm_state_path = SWTPM_NVRAM_Uri_to_Dir(uri);
203 if (rc == 0)
204 rc = SWTPM_NVRAM_Validate_Dir(tpm_state_path);
205 if (rc == 0)
206 rc = SWTPM_NVRAM_Lock_Dir(tpm_state_path);
207
208 return rc;
209 }
210
211 TPM_RESULT
212 SWTPM_NVRAM_LoadData_Dir(unsigned char **data,
213 uint32_t *length,
214 uint32_t tpm_number,
215 const char *name,
216 const char *uri)
217 {
218 TPM_RESULT rc = 0;
219 int irc;
220 size_t src;
221 int fd = -1;
222 char filename[FILENAME_MAX]; /* rooted file name from name */
223 struct stat statbuf;
224 const char *tpm_state_path = NULL;
225
226 tpm_state_path = SWTPM_NVRAM_Uri_to_Dir(uri);
227
228 /* open the file */
229 if (rc == 0) {
230 /* map name to the rooted filename */
231 rc = SWTPM_NVRAM_GetFilenameForName(filename, sizeof(filename),
232 tpm_number, name, false,
233 tpm_state_path);
234 }
235
236 if (rc == 0) {
237 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Opening file %s\n", filename);
238 fd = open(filename, O_RDONLY); /* closed @1 */
239 if (fd < 0) { /* if failure, determine cause */
240 if (errno == ENOENT) {
241 TPM_DEBUG("SWTPM_NVRAM_LoadData: No such file %s\n",
242 filename);
243 rc = TPM_RETRY; /* first time start up */
244 }
245 else {
246 logprintf(STDERR_FILENO,
247 "SWTPM_NVRAM_LoadData: Error (fatal) opening "
248 "%s for read, %s\n", filename, strerror(errno));
249 rc = TPM_FAIL;
250 }
251 }
252 }
253
254 if (rc == 0) {
255 if (fchmod(fd, tpmstate_get_mode()) < 0) {
256 logprintf(STDERR_FILENO,
257 "SWTPM_NVRAM_LoadData: Could not fchmod %s : %s\n",
258 filename, strerror(errno));
259 rc = TPM_FAIL;
260 }
261 }
262
263 /* determine the file length */
264 if (rc == 0) {
265 irc = fstat(fd, &statbuf);
266 if (irc == -1L) {
267 logprintf(STDERR_FILENO,
268 "SWTPM_NVRAM_LoadData: Error (fatal) fstat'ing %s, %s\n",
269 filename, strerror(errno));
270 rc = TPM_FAIL;
271 }
272 }
273 if (rc == 0) {
274 *length = statbuf.st_size; /* save the length */
275 }
276 /* allocate a buffer for the actual data */
277 if ((rc == 0) && *length != 0) {
278 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Reading %u bytes of data\n", *length);
279 *data = malloc(*length);
280 if (!*data) {
281 logprintf(STDERR_FILENO,
282 "SWTPM_NVRAM_LoadData: Error (fatal) allocating %u "
283 "bytes\n", *length);
284 rc = TPM_FAIL;
285 }
286 }
287 /* read the contents of the file into the data buffer */
288 if ((rc == 0) && *length != 0) {
289 src = read(fd, *data, *length);
290 if (src != *length) {
291 logprintf(STDERR_FILENO,
292 "SWTPM_NVRAM_LoadData: Error (fatal), data read of %u "
293 "only read %lu\n", *length, (unsigned long)src);
294 rc = TPM_FAIL;
295 }
296 }
297 /* close the file */
298 if (fd >= 0) {
299 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Closing file %s\n", filename);
300 irc = close(fd); /* @1 */
301 if (irc != 0) {
302 logprintf(STDERR_FILENO,
303 "SWTPM_NVRAM_LoadData: Error (fatal) closing file %s\n",
304 filename);
305 rc = TPM_FAIL;
306 }
307 else {
308 TPM_DEBUG(" SWTPM_NVRAM_LoadData: Closed file %s\n", filename);
309 }
310 }
311
312 return rc;
313 }
314
315 TPM_RESULT
316 SWTPM_NVRAM_StoreData_Dir(unsigned char *filedata,
317 uint32_t filedata_length,
318 uint32_t tpm_number,
319 const char *name,
320 const char *uri)
321 {
322 TPM_RESULT rc = 0;
323 int fd = -1;
324 int dir_fd = -1;
325 uint32_t lrc;
326 int irc;
327 char tmpfile[FILENAME_MAX]; /* rooted temporary file */
328 char filename[FILENAME_MAX]; /* rooted file name from name */
329 const char *tpm_state_path = NULL;
330
331 tpm_state_path = SWTPM_NVRAM_Uri_to_Dir(uri);
332
333 if (rc == 0) {
334 /* map name to the rooted filename */
335 rc = SWTPM_NVRAM_GetFilenameForName(filename, sizeof(filename),
336 tpm_number, name, false,
337 tpm_state_path);
338 }
339
340 if (rc == 0) {
341 /* map name to the rooted temporary file */
342 rc = SWTPM_NVRAM_GetFilenameForName(tmpfile, sizeof(tmpfile),
343 tpm_number, name, true,
344 tpm_state_path);
345 }
346
347 if (rc == 0) {
348 /* open the file */
349 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Opening file %s\n", tmpfile);
350 fd = open(tmpfile, O_WRONLY|O_CREAT|O_TRUNC|O_NOFOLLOW,
351 tpmstate_get_mode()); /* closed @1 */
352 if (fd < 0) {
353 logprintf(STDERR_FILENO,
354 "SWTPM_NVRAM_StoreData: Error (fatal) opening %s for "
355 "write failed, %s\n", tmpfile, strerror(errno));
356 rc = TPM_FAIL;
357 }
358 }
359
360 /* write the data to the file */
361 if (rc == 0) {
362 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Writing %u bytes of data\n",
363 filedata_length);
364 lrc = write_full(fd, filedata, filedata_length);
365 if (lrc != filedata_length) {
366 logprintf(STDERR_FILENO,
367 "SWTPM_NVRAM_StoreData: Error (fatal), data write "
368 "of %u only wrote %u\n", filedata_length, lrc);
369 rc = TPM_FAIL;
370 }
371 }
372 if (rc == 0 && fd >= 0) {
373 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Syncing file %s\n", tmpfile);
374 irc = fsync(fd);
375 if (irc != 0) {
376 logprintf(STDERR_FILENO,
377 "SWTPM_NVRAM_StoreData: Error (fatal) syncing file, %s\n",
378 strerror(errno));
379 rc = TPM_FAIL;
380 } else {
381 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Synced file %s\n", tmpfile);
382 }
383 }
384 if (fd >= 0) {
385 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closing file %s\n", tmpfile);
386 irc = close(fd); /* @1 */
387 if (irc != 0) {
388 logprintf(STDERR_FILENO,
389 "SWTPM_NVRAM_StoreData: Error (fatal) closing file\n");
390 rc = TPM_FAIL;
391 }
392 else {
393 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closed file %s\n", tmpfile);
394 }
395 }
396
397 if (rc == 0 && fd >= 0) {
398 irc = rename(tmpfile, filename);
399 if (irc != 0) {
400 logprintf(STDERR_FILENO,
401 "SWTPM_NVRAM_StoreData: Error (fatal) renaming file: %s\n",
402 strerror(errno));
403 rc = TPM_FAIL;
404 } else {
405 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Renamed file to %s\n", filename);
406 }
407 }
408
409 /*
410 * Quote from linux man 2 fsync:
411 * Calling fsync() does not necessarily ensure that the entry in the
412 * directory containing the file has also reached disk. For that an
413 * explicit fsync() on a file descriptor for the directory is also needed.
414 */
415 if (rc == 0 && fd >= 0) {
416 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Opening dir %s\n", tpm_state_path);
417 dir_fd = open(tpm_state_path, O_RDONLY);
418 if (dir_fd < 0) {
419 logprintf(STDERR_FILENO,
420 "SWTPM_NVRAM_StoreData: Error (fatal) opening %s for "
421 "fsync failed, %s\n", tpm_state_path, strerror(errno));
422 rc = TPM_FAIL;
423 }
424 }
425 if (rc == 0 && dir_fd >= 0) {
426 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Syncing dir %s\n", tpm_state_path);
427 irc = fsync(dir_fd);
428 if (irc != 0) {
429 logprintf(STDERR_FILENO,
430 "SWTPM_NVRAM_StoreData: Error (fatal) syncing dir, %s\n",
431 strerror(errno));
432 rc = TPM_FAIL;
433 } else {
434 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Synced dir %s\n", tpm_state_path);
435 }
436 }
437 if (dir_fd >= 0) {
438 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closing dir %s\n", tpm_state_path);
439 irc = close(dir_fd);
440 if (irc != 0) {
441 logprintf(STDERR_FILENO,
442 "SWTPM_NVRAM_StoreData: Error (fatal) closing dir\n");
443 rc = TPM_FAIL;
444 } else {
445 TPM_DEBUG(" SWTPM_NVRAM_StoreData: Closed dir %s\n", tpm_state_path);
446 }
447 }
448
449 if (rc != 0 && fd >= 0) {
450 unlink(tmpfile);
451 }
452
453 return rc;
454 }
455
456 TPM_RESULT SWTPM_NVRAM_DeleteName_Dir(uint32_t tpm_number,
457 const char *name,
458 TPM_BOOL mustExist,
459 const char *uri)
460 {
461 TPM_RESULT rc = 0;
462 int irc;
463 char filename[FILENAME_MAX]; /* rooted file name from name */
464 const char *tpm_state_path = NULL;
465
466 tpm_state_path = SWTPM_NVRAM_Uri_to_Dir(uri);
467
468 TPM_DEBUG(" SWTPM_NVRAM_DeleteName: Name %s\n", name);
469 /* map name to the rooted filename */
470 rc = SWTPM_NVRAM_GetFilenameForName(filename, sizeof(filename),
471 tpm_number, name, false,
472 tpm_state_path);
473 if (rc == 0) {
474 irc = remove(filename);
475 if ((irc != 0) && /* if the remove failed */
476 (mustExist || /* if any error is a failure, or */
477 (errno != ENOENT))) { /* if error other than no such file */
478 logprintf(STDERR_FILENO,
479 "SWTPM_NVRAM_DeleteName: Error, (fatal) file "
480 "remove failed, errno %d\n", errno);
481 rc = TPM_FAIL;
482 }
483 }
484 return rc;
485 }