]> git.proxmox.com Git - swtpm.git/blob - src/swtpm/cuse_tpm.c
swtpm: Implement low level CUSE startup code to get to fuse_session
[swtpm.git] / src / swtpm / cuse_tpm.c
1 /********************************************************************************/
2 /* */
3 /* CUSE TPM */
4 /* IBM Thomas J. Watson Research Center */
5 /* */
6 /* (c) Copyright IBM Corporation 2014-2015. */
7 /* */
8 /* All rights reserved. */
9 /* */
10 /* Redistribution and use in source and binary forms, with or without */
11 /* modification, are permitted provided that the following conditions are */
12 /* met: */
13 /* */
14 /* Redistributions of source code must retain the above copyright notice, */
15 /* this list of conditions and the following disclaimer. */
16 /* */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in the */
19 /* documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the names of the IBM Corporation nor the names of its */
22 /* contributors may be used to endorse or promote products derived from */
23 /* this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
28 /* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
31 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
32 /* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
33 /* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
34 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
35 /* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /********************************************************************************/
37
38 /*
39 * Authors:
40 * Eric Richter, erichte@us.ibm.com
41 * Stefan Berger, stefanb@us.ibm.com
42 * David Safford, safford@us.ibm.com
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <stdbool.h>
48 #include <string.h>
49 #include <getopt.h>
50 #include <pwd.h>
51 #include <grp.h>
52 #include <limits.h>
53 #include <errno.h>
54 #include <arpa/inet.h>
55 #include <dirent.h>
56
57 #include <fuse/cuse_lowlevel.h>
58
59 #include <glib.h>
60
61 #include <libtpms/tpm_library.h>
62 #include <libtpms/tpm_tis.h>
63 #include <libtpms/tpm_error.h>
64 #include <libtpms/tpm_memory.h>
65
66 #include "swtpm.h"
67 #include "common.h"
68 #include "tpmstate.h"
69 #include "pidfile.h"
70 #include "locality.h"
71 #include "logging.h"
72 #include "tpm_ioctl.h"
73 #include "swtpm_nvfile.h"
74 #include "tpmlib.h"
75 #include "main.h"
76 #include "utils.h"
77 #include "threadpool.h"
78
79 /* maximum size of request buffer */
80 #define TPM_REQ_MAX 4096
81
82 /* version of the TPM (1.2 or 2) */
83 static TPMLIB_TPMVersion tpmversion;
84
85 /* buffer containing the TPM request */
86 static unsigned char *ptm_request;
87
88 /* buffer containing the TPM response */
89 static unsigned char *ptm_response;
90
91 /* the sizes of the data in the buffers */
92 static uint32_t ptm_req_len, ptm_res_len, ptm_res_tot;
93
94 /* locality applied to TPM commands */
95 static TPM_MODIFIER_INDICATOR locality;
96
97 /* whether the TPM is running (TPM_Init was received) */
98 static bool tpm_running;
99
100 /* flags on how to handle locality */
101 static uint32_t locality_flags;
102
103 /* the fuse_session that we will signal an exit to to exit the prg. */
104 static struct fuse_session *ptm_fuse_session;
105
106 #if GLIB_MAJOR_VERSION >= 2
107 # if GLIB_MINOR_VERSION >= 32
108
109 GMutex file_ops_lock;
110 # define FILE_OPS_LOCK &file_ops_lock
111
112 # else
113
114 GMutex *file_ops_lock;
115 # define FILE_OPS_LOCK file_ops_lock
116
117 # endif
118 #else
119
120 #error Unsupport glib version
121
122 #endif
123
124 struct cuse_param {
125 char *runas;
126 char *logging;
127 char *keydata;
128 char *migkeydata;
129 char *piddata;
130 char *tpmstatedata;
131 char *localitydata;
132 };
133
134 /* single message to send to the worker thread */
135 static struct thread_message msg;
136
137 struct stateblob {
138 uint8_t type;
139 uint8_t *data;
140 uint32_t length;
141 TPM_BOOL is_encrypted;
142 };
143
144 typedef struct stateblob_desc {
145 uint32_t blobtype;
146 TPM_BOOL decrypt;
147 TPM_BOOL is_encrypted;
148 unsigned char *data;
149 uint32_t data_length;
150 } stateblob_desc;
151
152 typedef enum tx_state_type {
153 TX_STATE_RW_COMMAND = 1,
154 TX_STATE_SET_STATE_BLOB = 2,
155 TX_STATE_GET_STATE_BLOB = 3,
156 } tx_state_type;
157
158 typedef struct transfer_state {
159 tx_state_type state;
160 /* while in TX_STATE_GET/SET_STATEBLOB */
161 uint32_t blobtype;
162 TPM_BOOL blob_is_encrypted;
163 /* while in TX_STATE_GET */
164 uint32_t offset;
165 } transfer_state;
166
167 typedef struct TPM_Response_Header {
168 uint16_t tag;
169 uint32_t paramSize;
170 uint32_t returnCode;
171 } __attribute__ ((packed)) TPM_Response_Header;
172
173 /*********************************** data *************************************/
174
175 static const char *usage =
176 "usage: %s %s [options]\n"
177 "\n"
178 "The following options are supported:\n"
179 "\n"
180 "-n NAME|--name=NAME : device name (mandatory)\n"
181 "-M MAJ|--maj=MAJ : device major number\n"
182 "-m MIN|--min=MIN : device minor number\n"
183 "--key file=<path>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
184 " : use an AES key for the encryption of the TPM's state\n"
185 " files; use the given mode for the block encryption;\n"
186 " the key is to be provided as a hex string or in binary\n"
187 " format; the keyfile can be automatically removed using\n"
188 " the remove parameter\n"
189 "--key pwdfile=<path>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]]\n"
190 " : provide a passphrase in a file; the AES key will be\n"
191 " derived from this passphrase\n"
192 "--locality [reject-locality-4][,allow-set-locality]\n"
193 " : reject-locality-4: reject any command in locality 4\n"
194 " allow-set-locality: accept SetLocality command\n"
195 "--migration-key file=<path>[,mode=aes-cbc|aes-256-cbc][,format=hex|binary][,remove=[true|false]]\n"
196 " : use an AES key for the encryption of the TPM's state\n"
197 " when it is retrieved from the TPM via ioctls;\n"
198 " Setting this key ensures that the TPM's state will always\n"
199 " be encrypted when migrated\n"
200 "--migration-key pwdfile=<path>[,mode=aes-cbc|aes-256-cbc][,remove=[true|false]]\n"
201 " : provide a passphrase in a file; the AES key will be\n"
202 " derived from this passphrase\n"
203 "--log file=<path>|fd=<filedescriptor>[,level=n][,prefix=<prefix>][,truncate]\n"
204 " : write the TPM's log into the given file rather than\n"
205 " to the console; provide '-' for path to avoid logging\n"
206 " log level 5 and higher will enable libtpms logging;\n"
207 " all logged output will be prefixed with prefix;\n"
208 " the log file can be reset (truncate)\n"
209 "--pid file=<path>|fd=<filedescriptor>\n"
210 " : write the process ID into the given file\n"
211 "--tpmstate dir=<dir>[,mode=0...]\n"
212 " : set the directory where the TPM's state will be written\n"
213 " into; the TPM_PATH environment variable can be used\n"
214 " instead;\n"
215 " mode allows to set the file mode bits of the state\n"
216 " files; the default mode is 0640;\n"
217 "-r|--runas <user> : after creating the CUSE device, change to the given\n"
218 " user\n"
219 "--tpm2 : choose TPM2 functionality\n"
220 "-h|--help : display this help screen and terminate\n"
221 "\n";
222
223 static TPM_RESULT
224 ptm_io_getlocality(TPM_MODIFIER_INDICATOR *loc, uint32_t tpmnum)
225 {
226 *loc = locality;
227 return TPM_SUCCESS;
228 }
229
230 static struct libtpms_callbacks cbs = {
231 .sizeOfStruct = sizeof(struct libtpms_callbacks),
232 .tpm_nvram_init = SWTPM_NVRAM_Init,
233 .tpm_nvram_loaddata = SWTPM_NVRAM_LoadData,
234 .tpm_nvram_storedata = SWTPM_NVRAM_StoreData,
235 .tpm_nvram_deletename = SWTPM_NVRAM_DeleteName,
236 .tpm_io_getlocality = ptm_io_getlocality,
237 };
238
239 /* the current state the transfer interface is in */
240 static transfer_state tx_state;
241
242 /* function prototypes */
243 static void ptm_cleanup(void);
244
245 /************************* cached stateblob *********************************/
246
247 static stateblob_desc cached_stateblob;
248
249 /*
250 * cached_stateblob_is_loaded: is the stateblob with the given properties
251 * the one in the cache?
252 */
253 static bool cached_stateblob_is_loaded(uint32_t blobtype,
254 TPM_BOOL decrypt)
255 {
256 return (cached_stateblob.data != NULL) &&
257 (cached_stateblob.blobtype == blobtype) &&
258 (cached_stateblob.decrypt == decrypt);
259 }
260
261 /*
262 * cached_stateblob_free: Free any previously loaded state blob
263 */
264 static void cached_stateblob_free(void)
265 {
266 free(cached_stateblob.data);
267 cached_stateblob.data = NULL;
268 cached_stateblob.data_length = 0;
269 }
270
271 /*
272 * cached_stateblob_get_bloblength: get the total length of the cached blob
273 */
274 static uint32_t cached_stateblob_get_bloblength(void)
275 {
276 return cached_stateblob.data_length;
277 }
278
279 /*
280 * cached_statblob_get: get stateblob data without copying them
281 *
282 * @offset: at which offset to get the data
283 * @bufptr: pointer to a buffer pointer used to return buffer start
284 * @length: pointer used to return number of available bytes in returned buffer
285 */
286 static int cached_stateblob_get(uint32_t offset,
287 unsigned char **bufptr, size_t *length)
288 {
289 if (cached_stateblob.data == NULL ||
290 offset > cached_stateblob.data_length)
291 return -1;
292
293 *bufptr = &cached_stateblob.data[offset];
294 *length = cached_stateblob.data_length - offset;
295
296 return 0;
297 }
298
299 /*
300 * cached_stateblob_load: load a state blob into the cache
301 *
302 * blobtype: the type of blob
303 * decrypt: whether the blob is to be decrypted
304 */
305 static TPM_RESULT cached_stateblob_load(uint32_t blobtype, TPM_BOOL decrypt)
306 {
307 TPM_RESULT res = 0;
308 const char *blobname = tpmlib_get_blobname(blobtype);
309 uint32_t tpm_number = 0;
310
311 if (!blobname)
312 return TPM_BAD_PARAMETER;
313
314 cached_stateblob_free();
315
316 if (blobtype == PTM_BLOB_TYPE_VOLATILE)
317 res = SWTPM_NVRAM_Store_Volatile();
318
319 if (res == 0)
320 res = SWTPM_NVRAM_GetStateBlob(&cached_stateblob.data,
321 &cached_stateblob.data_length,
322 tpm_number, blobname, decrypt,
323 &cached_stateblob.is_encrypted);
324
325 /* make sure the volatile state file is gone */
326 if (blobtype == PTM_BLOB_TYPE_VOLATILE)
327 SWTPM_NVRAM_DeleteName(tpm_number, blobname, FALSE);
328
329 if (res == 0) {
330 cached_stateblob.blobtype = blobtype;
331 cached_stateblob.decrypt = decrypt;
332 }
333
334 return res;
335 }
336
337 /*
338 * cached_state_blob_copy: copy the cached state blob to a destination buffer
339 *
340 * dest: destination buffer
341 * destlen: size of the buffer
342 * srcoffset: offset to copy from
343 * copied: variable to return the number of copied bytes
344 * is_encrypted: variable to return whether the blob is encrypted
345 */
346 static int cached_stateblob_copy(void *dest, size_t destlen,
347 uint32_t srcoffset, uint32_t *copied,
348 TPM_BOOL *is_encrypted)
349 {
350 int ret = -1;
351
352 *copied = 0;
353
354 if (cached_stateblob.data != NULL && cached_stateblob.data_length > 0) {
355
356 if (srcoffset < cached_stateblob.data_length) {
357 *copied = min(cached_stateblob.data_length - srcoffset, destlen);
358
359 memcpy(dest, &cached_stateblob.data[srcoffset], *copied);
360
361 *is_encrypted = cached_stateblob.is_encrypted;
362 }
363
364 ret = 0;
365 }
366
367 return ret;
368 }
369
370 /************************* worker thread ************************************/
371
372 /*
373 * worker_thread: the worker thread
374 */
375 static void worker_thread(gpointer data, gpointer user_data)
376 {
377 struct thread_message *msg = (struct thread_message *)data;
378
379 switch (msg->type) {
380 case MESSAGE_TPM_CMD:
381 TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
382 ptm_request, ptm_req_len);
383 break;
384 case MESSAGE_IOCTL:
385 break;
386 }
387
388 /* results are ready */
389 worker_thread_mark_done();
390 }
391
392 /***************************** utility functions ****************************/
393
394 /*
395 * tpm_start: Start the TPM
396 *
397 * Check whether the TPM's state directory exists and if it does
398 * not exists, try to creat it. Start the thread pool, initilize
399 * libtpms and allocate a global TPM request buffer.
400 *
401 * @flags: libtpms init flags
402 */
403 static int tpm_start(uint32_t flags, TPMLIB_TPMVersion l_tpmversion)
404 {
405 DIR *dir;
406 const char *tpmdir = tpmstate_get_dir();
407
408 dir = opendir(tpmdir);
409 if (dir) {
410 closedir(dir);
411 } else {
412 if (mkdir(tpmdir, 0775)) {
413 logprintf(STDERR_FILENO,
414 "Error: Could not open tpmstate dir %s\n",
415 tpmdir);
416 return -1;
417 }
418 }
419
420 pool = g_thread_pool_new(worker_thread,
421 NULL,
422 1,
423 TRUE,
424 NULL);
425 if (!pool) {
426 logprintf(STDERR_FILENO,
427 "Error: Could not create the thread pool.\n");
428 return -1;
429 }
430
431 if(!ptm_request)
432 ptm_request = malloc(4096);
433 if(!ptm_request) {
434 logprintf(STDERR_FILENO,
435 "Error: Could not allocate memory for request buffer.\n");
436 goto error_del_pool;
437 }
438
439 if (tpmlib_start(flags, l_tpmversion) != TPM_SUCCESS)
440 goto error_del_pool;
441
442 logprintf(STDOUT_FILENO,
443 "CUSE TPM successfully initialized.\n");
444
445 return 0;
446
447 error_del_pool:
448 g_thread_pool_free(pool, TRUE, TRUE);
449 pool = NULL;
450
451 return -1;
452 }
453
454 /*
455 * ptm_write_fatal_error_response: Write fatal error response
456 *
457 * Write a fatal error response into the global ptm_response buffer.
458 */
459 static void ptm_write_fatal_error_response(TPMLIB_TPMVersion l_tpmversion)
460 {
461 tpmlib_write_fatal_error_response(&ptm_response,
462 &ptm_res_len,
463 &ptm_res_tot,
464 l_tpmversion);
465 }
466
467 /************************************ read() support ***************************/
468
469 /*
470 * ptm_read_result: Return the TPM response packet
471 *
472 * @req: the fuse_req_t
473 * @size: the max. number of bytes to return to the requester
474 */
475 static void ptm_read_result(fuse_req_t req, size_t size)
476 {
477 int len;
478
479 if (tpm_running) {
480 /* wait until results are ready */
481 worker_thread_wait_done();
482 }
483
484 len = ptm_res_len;
485
486 if (ptm_res_len > size) {
487 len = size;
488 ptm_res_len -= size;
489 } else {
490 ptm_res_len = 0;
491 }
492
493 fuse_reply_buf(req, (const char *)ptm_response, len);
494 }
495
496 /*
497 * ptm_read_stateblob: get a TPM stateblob via the read() interface
498 *
499 * @req: the fuse_req_t
500 * @size: the number of bytes to read
501 *
502 * The internal offset into the buffer is advanced by the number
503 * of bytes that were copied. We switch back to command read/write
504 * mode if an error occurred or once all bytes were read.
505 */
506 static void ptm_read_stateblob(fuse_req_t req, size_t size)
507 {
508 unsigned char *bufptr = NULL;
509 size_t numbytes;
510 size_t tocopy;
511
512 if (cached_stateblob_get(tx_state.offset, &bufptr, &numbytes) < 0) {
513 fuse_reply_err(req, EIO);
514 tx_state.state = TX_STATE_RW_COMMAND;
515 } else {
516 tocopy = MIN(size, numbytes);
517 tx_state.offset += tocopy;
518
519 fuse_reply_buf(req, (char *)bufptr, tocopy);
520 /* last transfer indicated by less bytes available than requested */
521 if (numbytes < size) {
522 tx_state.state = TX_STATE_RW_COMMAND;
523 }
524 }
525 }
526
527 /*
528 * ptm_read: interface to POSIX read()
529 *
530 * @req: fuse_req_t
531 * @size: number of bytes to read
532 * @off: offset (not used)
533 * @fi: fuse_file_info (not used)
534 *
535 * Depending on the current state of the transfer interface (read/write)
536 * return either the results of TPM commands or a data of a TPM state blob.
537 */
538 static void ptm_read(fuse_req_t req, size_t size, off_t off,
539 struct fuse_file_info *fi)
540 {
541 switch (tx_state.state) {
542 case TX_STATE_RW_COMMAND:
543 ptm_read_result(req, size);
544 break;
545 case TX_STATE_SET_STATE_BLOB:
546 fuse_reply_err(req, EIO);
547 tx_state.state = TX_STATE_RW_COMMAND;
548 break;
549 case TX_STATE_GET_STATE_BLOB:
550 ptm_read_stateblob(req, size);
551 break;
552 }
553 }
554
555 /*************************read/write stateblob support ***********************/
556
557 /*
558 * ptm_set_stateblob_append: Append a piece of TPM state blob and transfer to TPM
559 *
560 * blobtype: the type of blob
561 * data: the data to append
562 * length: length of the data
563 * is_encrypted: whether the blob is encrypted
564 * is_last: whether this is the last part of the TPM state blob; if it is, the TPM
565 * state blob will then be transferred to the TPM
566 */
567 static TPM_RESULT
568 ptm_set_stateblob_append(uint32_t blobtype,
569 const unsigned char *data, uint32_t length,
570 bool is_encrypted, bool is_last)
571 {
572 TPM_RESULT res = 0;
573 static struct stateblob stateblob;
574 unsigned char *tmp;
575
576 if (stateblob.type != blobtype) {
577 /* new blob; clear old data */
578 free(stateblob.data);
579 stateblob.data = NULL;
580 stateblob.length = 0;
581 stateblob.type = blobtype;
582 stateblob.is_encrypted = is_encrypted;
583
584 /*
585 * on the first call for a new state blob we allow 0 bytes to be written
586 * this allows the user to transfer via write()
587 */
588 if (length == 0)
589 return 0;
590 }
591
592 /* append */
593 tmp = realloc(stateblob.data, stateblob.length + length);
594 if (!tmp) {
595 logprintf(STDERR_FILENO,
596 "Could not allocate %u bytes.\n", stateblob.length + length);
597 /* error */
598 free(stateblob.data);
599 stateblob.data = NULL;
600 stateblob.length = 0;
601 stateblob.type = 0;
602
603 return TPM_FAIL;
604 } else
605 stateblob.data = tmp;
606
607 memcpy(&stateblob.data[stateblob.length], data, length);
608 stateblob.length += length;
609
610 if (!is_last) {
611 /* full packet -- expecting more data */
612 return res;
613 }
614
615 res = SWTPM_NVRAM_SetStateBlob(stateblob.data,
616 stateblob.length,
617 stateblob.is_encrypted,
618 0 /* tpm_number */,
619 blobtype);
620
621 logprintf(STDERR_FILENO,
622 "Deserialized state type %d (%s), length=%d, res=%d\n",
623 blobtype, tpmlib_get_blobname(blobtype),
624 stateblob.length, res);
625
626 free(stateblob.data);
627 stateblob.data = NULL;
628 stateblob.length = 0;
629 stateblob.type = 0;
630
631 /* transfer of blob is complete */
632 tx_state.state = TX_STATE_RW_COMMAND;
633
634 return res;
635 }
636
637 /*
638 * ptm_set_stateblob: set part of a TPM state blob
639 *
640 * @req: fuse_req_t
641 * pss: ptm_setstate provided via ioctl()
642 */
643 static void
644 ptm_set_stateblob(fuse_req_t req, ptm_setstate *pss)
645 {
646 TPM_RESULT res = 0;
647 TPM_BOOL is_encrypted =
648 ((pss->u.req.state_flags & PTM_STATE_FLAG_ENCRYPTED) != 0);
649 bool is_last = (sizeof(pss->u.req.data) != pss->u.req.length);
650
651 if (pss->u.req.length > sizeof(pss->u.req.data)) {
652 res = TPM_BAD_PARAMETER;
653 goto send_response;
654 }
655
656 /* transfer of blob initiated */
657 tx_state.state = TX_STATE_SET_STATE_BLOB;
658 tx_state.blobtype = pss->u.req.type;
659 tx_state.blob_is_encrypted = is_encrypted;
660 tx_state.offset = 0;
661
662 res = ptm_set_stateblob_append(pss->u.req.type,
663 pss->u.req.data,
664 pss->u.req.length,
665 is_encrypted,
666 is_last);
667
668 if (res)
669 tx_state.state = TX_STATE_RW_COMMAND;
670
671 send_response:
672 pss->u.resp.tpm_result = res;
673
674 fuse_reply_ioctl(req, 0, pss, sizeof(*pss));
675 }
676
677 /*
678 * ptm_get_stateblob_part: get part of a state blob
679 *
680 * @blobtype: the type of blob to get
681 * @buffer: the buffer this function will write the blob into
682 * @buffer_size: the size of the buffer
683 * @offset: the offset into the state blob
684 * @copied: pointer to int to indicate the number of bytes that were copied
685 * @is_encryped: returns whether the state blob is encrypted
686 */
687 static TPM_RESULT
688 ptm_get_stateblob_part(uint32_t blobtype,
689 unsigned char *buffer, size_t buffer_size,
690 uint32_t offset, uint32_t *copied,
691 TPM_BOOL decrypt, TPM_BOOL *is_encrypted)
692 {
693 TPM_RESULT res = 0;
694
695 if (!cached_stateblob_is_loaded(blobtype, decrypt)) {
696 res = cached_stateblob_load(blobtype, decrypt);
697 }
698
699 if (res == 0) {
700 cached_stateblob_copy(buffer, buffer_size,
701 offset, copied, is_encrypted);
702 }
703
704 return res;
705 }
706
707 /*
708 * ptm_get_stateblob: Get the state blob from the TPM using ioctl()
709 */
710 static void
711 ptm_get_stateblob(fuse_req_t req, ptm_getstate *pgs)
712 {
713 TPM_RESULT res = 0;
714 uint32_t blobtype = pgs->u.req.type;
715 TPM_BOOL decrypt =
716 ((pgs->u.req.state_flags & PTM_STATE_FLAG_DECRYPTED) != 0);
717 TPM_BOOL is_encrypted = FALSE;
718 uint32_t copied = 0;
719 uint32_t offset = pgs->u.req.offset;
720 uint32_t totlength;
721
722 res = ptm_get_stateblob_part(blobtype,
723 pgs->u.resp.data, sizeof(pgs->u.resp.data),
724 pgs->u.req.offset, &copied,
725 decrypt, &is_encrypted);
726
727 totlength = cached_stateblob_get_bloblength();
728
729 pgs->u.resp.state_flags = 0;
730 if (is_encrypted)
731 pgs->u.resp.state_flags |= PTM_STATE_FLAG_ENCRYPTED;
732
733 pgs->u.resp.length = copied;
734 pgs->u.resp.totlength = totlength;
735 pgs->u.resp.tpm_result = res;
736 logprintf(STDERR_FILENO,
737 "Serialized state type %d, length=%d, totlength=%d, res=%d\n",
738 blobtype, copied, totlength, res);
739
740 if (res == 0) {
741 if (offset + copied < totlength) {
742 /* last byte was not copied */
743 tx_state.state = TX_STATE_GET_STATE_BLOB;
744 tx_state.blobtype = pgs->u.req.type;
745 tx_state.blob_is_encrypted = is_encrypted;
746 tx_state.offset = copied;
747 } else {
748 /* last byte was copied */
749 tx_state.state = TX_STATE_RW_COMMAND;
750 }
751 } else {
752 /* error occurred */
753 tx_state.state = TX_STATE_RW_COMMAND;
754 }
755
756 fuse_reply_ioctl(req, 0, pgs, sizeof(pgs->u.resp));
757 }
758
759 /*********************************** write() support *************************/
760
761 /*
762 * ptm_write_stateblob: Write the state blob using the write() interface
763 *
764 * @req: the fuse_req_t
765 * @buf: the buffer with the data
766 * @size: the number of bytes in the buffer
767 *
768 * The data are appended to an existing buffer that was created with the
769 * initial ioctl().
770 */
771 static void ptm_write_stateblob(fuse_req_t req, const char *buf, size_t size)
772 {
773 TPM_RESULT res;
774
775 res = ptm_set_stateblob_append(tx_state.blobtype,
776 (unsigned char *)buf, size,
777 tx_state.blob_is_encrypted,
778 (size == 0));
779 if (res) {
780 tx_state.state = TX_STATE_RW_COMMAND;
781 fuse_reply_err(req, EIO);
782 } else {
783 fuse_reply_write(req, size);
784 }
785 }
786
787 /*
788 * ptm_write_cmd: User writing a TPM command
789 *
790 * req: fuse_req_t
791 * buf: the buffer containing the TPM command
792 * size: the size of the buffer
793 * tpmversion: the version of the TPM
794 */
795 static void ptm_write_cmd(fuse_req_t req, const char *buf, size_t size,
796 TPMLIB_TPMVersion l_tpmversion)
797 {
798 ptm_req_len = size;
799 ptm_res_len = 0;
800
801 /* prevent other threads from writing or doing ioctls */
802 g_mutex_lock(FILE_OPS_LOCK);
803
804 if (tpm_running) {
805 /* ensure that we only ever work on one TPM command */
806 if (worker_thread_is_busy()) {
807 fuse_reply_err(req, EBUSY);
808 goto cleanup;
809 }
810
811 if (ptm_req_len > TPM_REQ_MAX)
812 ptm_req_len = TPM_REQ_MAX;
813
814 /* process SetLocality command, if */
815 tpmlib_process(&ptm_response, &ptm_res_len, &ptm_res_tot,
816 (unsigned char *)buf, ptm_req_len,
817 locality_flags, &locality, tpmversion);
818 if (ptm_res_len)
819 goto skip_process;
820
821 if (tpmlib_is_request_cancelable(l_tpmversion,
822 (const unsigned char*)buf,
823 ptm_req_len)) {
824 /* have command processed by thread pool */
825 memcpy(ptm_request, buf, ptm_req_len);
826
827 msg.type = MESSAGE_TPM_CMD;
828
829 worker_thread_mark_busy();
830
831 g_thread_pool_push(pool, &msg, NULL);
832 } else {
833 /* direct processing */
834 TPMLIB_Process(&ptm_response, &ptm_res_len, &ptm_res_tot,
835 (unsigned char *)buf, ptm_req_len);
836 }
837 } else {
838 /* TPM not initialized; return error */
839 ptm_write_fatal_error_response(l_tpmversion);
840 }
841
842 skip_process:
843 fuse_reply_write(req, ptm_req_len);
844
845 cleanup:
846 g_mutex_unlock(FILE_OPS_LOCK);
847
848 return;
849 }
850
851 /*
852 * ptm_write: low-level write() interface; calls approriate function depending
853 * on what is being transferred using the write()
854 */
855 static void ptm_write(fuse_req_t req, const char *buf, size_t size,
856 off_t off, struct fuse_file_info *fi)
857 {
858 switch (tx_state.state) {
859 case TX_STATE_RW_COMMAND:
860 ptm_write_cmd(req, buf, size, tpmversion);
861 break;
862 case TX_STATE_GET_STATE_BLOB:
863 fuse_reply_err(req, EIO);
864 tx_state.state = TX_STATE_RW_COMMAND;
865 break;
866 case TX_STATE_SET_STATE_BLOB:
867 ptm_write_stateblob(req, buf, size);
868 break;
869 }
870 }
871
872 /*
873 * ptm_open: interface to POSIX open()
874 */
875 static void ptm_open(fuse_req_t req, struct fuse_file_info *fi)
876 {
877 tx_state.state = TX_STATE_RW_COMMAND;
878
879 fuse_reply_open(req, fi);
880 }
881
882 /*
883 * ptm_ioctl : ioctl execution
884 *
885 * req: the fuse_req_t used to send response with
886 * cmd: the ioctl request code
887 * arg: the pointer the application used for calling the ioctl (3rd param)
888 * fi:
889 * flags: some flags provided by fuse
890 * in_buf: the copy of the input buffer
891 * in_bufsz: size of the input buffer; provided by fuse and has size of
892 * needed buffer
893 * out_bufsz: size of the output buffer; provided by fuse and has size of
894 * needed buffer
895 */
896 static void ptm_ioctl(fuse_req_t req, int cmd, void *arg,
897 struct fuse_file_info *fi, unsigned flags,
898 const void *in_buf, size_t in_bufsz, size_t out_bufsz)
899 {
900 TPM_RESULT res = TPM_FAIL;
901 bool exit_prg = FALSE;
902 ptm_init *init_p;
903 TPM_MODIFIER_INDICATOR orig_locality;
904
905 /* some commands have to wait until the worker thread is done */
906 switch(cmd) {
907 case PTM_GET_CAPABILITY:
908 case PTM_SET_LOCALITY:
909 case PTM_CANCEL_TPM_CMD:
910 case PTM_GET_CONFIG:
911 case PTM_SET_BUFFERSIZE:
912 /* no need to wait */
913 break;
914 case PTM_INIT:
915 case PTM_SHUTDOWN:
916 case PTM_GET_TPMESTABLISHED:
917 case PTM_RESET_TPMESTABLISHED:
918 case PTM_HASH_START:
919 case PTM_HASH_DATA:
920 case PTM_HASH_END:
921 case PTM_STORE_VOLATILE:
922 case PTM_GET_STATEBLOB:
923 case PTM_SET_STATEBLOB:
924 if (tpm_running)
925 worker_thread_wait_done();
926 break;
927 }
928
929 /* prevent other threads from writing or doing ioctls */
930 g_mutex_lock(FILE_OPS_LOCK);
931
932 switch (cmd) {
933 case PTM_GET_CAPABILITY:
934 if (out_bufsz != sizeof(ptm_cap)) {
935 struct iovec iov = { arg, sizeof(uint8_t) };
936 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
937 } else {
938 ptm_cap ptm_caps;
939 switch (tpmversion) {
940 case TPMLIB_TPM_VERSION_2:
941 ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN
942 | PTM_CAP_GET_TPMESTABLISHED
943 | PTM_CAP_SET_LOCALITY
944 | PTM_CAP_HASHING
945 | PTM_CAP_CANCEL_TPM_CMD
946 | PTM_CAP_STORE_VOLATILE
947 | PTM_CAP_RESET_TPMESTABLISHED
948 | PTM_CAP_GET_STATEBLOB
949 | PTM_CAP_SET_STATEBLOB
950 | PTM_CAP_STOP
951 | PTM_CAP_GET_CONFIG
952 | PTM_CAP_SET_BUFFERSIZE;
953 break;
954 case TPMLIB_TPM_VERSION_1_2:
955 ptm_caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN
956 | PTM_CAP_GET_TPMESTABLISHED
957 | PTM_CAP_SET_LOCALITY
958 | PTM_CAP_HASHING
959 | PTM_CAP_CANCEL_TPM_CMD
960 | PTM_CAP_STORE_VOLATILE
961 | PTM_CAP_RESET_TPMESTABLISHED
962 | PTM_CAP_GET_STATEBLOB
963 | PTM_CAP_SET_STATEBLOB
964 | PTM_CAP_STOP
965 | PTM_CAP_GET_CONFIG
966 | PTM_CAP_SET_BUFFERSIZE;
967 break;
968 }
969 fuse_reply_ioctl(req, 0, &ptm_caps, sizeof(ptm_caps));
970 }
971 break;
972
973 case PTM_INIT:
974 if (in_bufsz != sizeof(ptm_init)) {
975 struct iovec iov = { arg, sizeof(uint8_t) };
976 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
977 } else {
978 init_p = (ptm_init *)in_buf;
979
980 worker_thread_end();
981
982 TPMLIB_Terminate();
983
984 tpm_running = false;
985 if (tpm_start(init_p->u.req.init_flags, tpmversion) < 0) {
986 res = TPM_FAIL;
987 logprintf(STDERR_FILENO,
988 "Error: Could not initialize the TPM.\n");
989 } else {
990 res = TPM_SUCCESS;
991 tpm_running = true;
992 }
993 init_p->u.resp.tpm_result = res;
994 fuse_reply_ioctl(req, 0, init_p, sizeof(*init_p));
995 }
996 break;
997
998 case PTM_STOP:
999 worker_thread_end();
1000
1001 res = TPM_SUCCESS;
1002 TPMLIB_Terminate();
1003
1004 tpm_running = false;
1005
1006 free(ptm_response);
1007 ptm_response = NULL;
1008
1009 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1010
1011 break;
1012
1013 case PTM_SHUTDOWN:
1014 worker_thread_end();
1015
1016 res = TPM_SUCCESS;
1017 TPMLIB_Terminate();
1018
1019 free(ptm_response);
1020 ptm_response = NULL;
1021
1022 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1023 exit_prg = TRUE;
1024
1025 break;
1026
1027 case PTM_GET_TPMESTABLISHED:
1028 if (!tpm_running)
1029 goto error_not_running;
1030
1031 if (out_bufsz != sizeof(ptm_est)) {
1032 struct iovec iov = { arg, sizeof(uint8_t) };
1033 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1034 } else {
1035 ptm_est te;
1036 te.u.resp.tpm_result = TPM_IO_TpmEstablished_Get(&te.u.resp.bit);
1037 fuse_reply_ioctl(req, 0, &te, sizeof(te));
1038 }
1039 break;
1040
1041 case PTM_RESET_TPMESTABLISHED:
1042 if (!tpm_running)
1043 goto error_not_running;
1044
1045 if (in_bufsz != sizeof(ptm_reset_est)) {
1046 struct iovec iov = { arg, sizeof(uint32_t) };
1047 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1048 } else {
1049 ptm_reset_est *re = (ptm_reset_est *)in_buf;
1050 if (re->u.req.loc > 4) {
1051 res = TPM_BAD_LOCALITY;
1052 } else {
1053 /* set locality and reset flag in one command */
1054 orig_locality = locality;
1055 locality = re->u.req.loc;
1056
1057 res = TPM_IO_TpmEstablished_Reset();
1058
1059 locality = orig_locality;
1060 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1061 }
1062 }
1063 break;
1064
1065 case PTM_SET_LOCALITY:
1066 if (in_bufsz != sizeof(ptm_loc)) {
1067 struct iovec iov = { arg, sizeof(uint32_t) };
1068 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1069 } else {
1070 ptm_loc *l = (ptm_loc *)in_buf;
1071 if (l->u.req.loc > 4 ||
1072 (l->u.req.loc == 4 &&
1073 locality_flags & LOCALITY_FLAG_REJECT_LOCALITY_4)) {
1074 res = TPM_BAD_LOCALITY;
1075 } else {
1076 res = TPM_SUCCESS;
1077 locality = l->u.req.loc;
1078 }
1079 l->u.resp.tpm_result = res;
1080 fuse_reply_ioctl(req, 0, l, sizeof(*l));
1081 }
1082 break;
1083
1084 case PTM_HASH_START:
1085 if (!tpm_running)
1086 goto error_not_running;
1087
1088 res = TPM_IO_Hash_Start();
1089 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1090 break;
1091
1092 case PTM_HASH_DATA:
1093 if (!tpm_running)
1094 goto error_not_running;
1095
1096 if (in_bufsz != sizeof(ptm_hdata)) {
1097 struct iovec iov = { arg, sizeof(uint32_t) };
1098 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1099 } else {
1100 ptm_hdata *data = (ptm_hdata *)in_buf;
1101 if (data->u.req.length <= sizeof(data->u.req.data)) {
1102 res = TPM_IO_Hash_Data(data->u.req.data,
1103 data->u.req.length);
1104 } else {
1105 res = TPM_FAIL;
1106 }
1107 data->u.resp.tpm_result = res;
1108 fuse_reply_ioctl(req, 0, data, sizeof(*data));
1109 }
1110 break;
1111
1112 case PTM_HASH_END:
1113 if (!tpm_running)
1114 goto error_not_running;
1115
1116 res = TPM_IO_Hash_End();
1117 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1118 break;
1119
1120 case PTM_CANCEL_TPM_CMD:
1121 if (!tpm_running)
1122 goto error_not_running;
1123
1124 /* for cancellation to work, the TPM would have to
1125 * execute in another thread that polls on a cancel
1126 * flag
1127 */
1128 res = TPMLIB_CancelCommand();
1129 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1130 break;
1131
1132 case PTM_STORE_VOLATILE:
1133 if (!tpm_running)
1134 goto error_not_running;
1135
1136 res = SWTPM_NVRAM_Store_Volatile();
1137 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1138
1139 cached_stateblob_free();
1140 break;
1141
1142 case PTM_GET_STATEBLOB:
1143 if (!tpm_running)
1144 goto error_not_running;
1145
1146 if (in_bufsz != sizeof(ptm_getstate)) {
1147 struct iovec iov = { arg, sizeof(uint32_t) };
1148 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1149 } else {
1150 ptm_get_stateblob(req, (ptm_getstate *)in_buf);
1151 }
1152 break;
1153
1154 case PTM_SET_STATEBLOB:
1155 if (tpm_running)
1156 goto error_running;
1157
1158 /* tpm state dir must be set */
1159 SWTPM_NVRAM_Init();
1160
1161 if (in_bufsz != sizeof(ptm_setstate)) {
1162 struct iovec iov = { arg, sizeof(uint32_t) };
1163 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1164 } else {
1165 ptm_set_stateblob(req, (ptm_setstate *)in_buf);
1166 }
1167 break;
1168
1169 case PTM_GET_CONFIG:
1170 if (out_bufsz != sizeof(ptm_getconfig)) {
1171 struct iovec iov = { arg, sizeof(uint32_t) };
1172 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1173 } else {
1174 ptm_getconfig pgs;
1175 pgs.u.resp.tpm_result = 0;
1176 pgs.u.resp.flags = 0;
1177 if (SWTPM_NVRAM_Has_FileKey())
1178 pgs.u.resp.flags |= PTM_CONFIG_FLAG_FILE_KEY;
1179 if (SWTPM_NVRAM_Has_MigrationKey())
1180 pgs.u.resp.flags |= PTM_CONFIG_FLAG_MIGRATION_KEY;
1181 fuse_reply_ioctl(req, 0, &pgs, sizeof(pgs));
1182 }
1183 break;
1184
1185 case PTM_SET_BUFFERSIZE:
1186 if (out_bufsz != sizeof(ptm_setbuffersize)) {
1187 struct iovec iov = { arg, sizeof(uint32_t) };
1188 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1189 } else {
1190 ptm_setbuffersize *in_psbs = (ptm_setbuffersize *)in_buf;
1191 ptm_setbuffersize out_psbs;
1192 uint32_t buffersize, minsize, maxsize;
1193
1194 buffersize = in_psbs->u.req.buffersize;
1195
1196 if (buffersize > 0 && tpm_running)
1197 goto error_running;
1198
1199 buffersize = TPMLIB_SetBufferSize(buffersize,
1200 &minsize,
1201 &maxsize);
1202
1203 out_psbs.u.resp.tpm_result = TPM_SUCCESS;
1204 out_psbs.u.resp.buffersize = buffersize;
1205 out_psbs.u.resp.minsize = minsize;
1206 out_psbs.u.resp.maxsize = maxsize;
1207 fuse_reply_ioctl(req, 0, &out_psbs, sizeof(out_psbs));
1208 }
1209 break;
1210
1211 case PTM_GET_INFO:
1212 if (out_bufsz != sizeof(ptm_getinfo)) {
1213 struct iovec iov = { arg, sizeof(uint32_t) };
1214 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
1215 } else {
1216 ptm_getinfo *in_pgi = (ptm_getinfo *)in_buf;
1217 ptm_getinfo out_pgi;
1218 char *info_data;
1219 uint32_t length, offset;
1220
1221 info_data = TPMLIB_GetInfo(in_pgi->u.req.flags);
1222 if (!info_data)
1223 goto error_memory;
1224
1225 offset = in_pgi->u.req.offset;
1226 if (offset >= strlen(info_data)) {
1227 free(info_data);
1228 goto error_bad_input;
1229 }
1230
1231 length = min(strlen(info_data) + 1 - offset,
1232 sizeof(out_pgi.u.resp.buffer));
1233
1234 out_pgi.u.resp.tpm_result = 0;
1235 out_pgi.u.resp.totlength = strlen(info_data) + 1;
1236 out_pgi.u.resp.length = length;
1237 /* client has to collect whole string in case buffer is too small */
1238 memcpy(out_pgi.u.resp.buffer, &info_data[offset], length);
1239 free(info_data);
1240
1241 fuse_reply_ioctl(req, 0, &out_pgi, sizeof(out_pgi));
1242 }
1243 break;
1244
1245 default:
1246 fuse_reply_err(req, EINVAL);
1247 }
1248
1249 cleanup:
1250 g_mutex_unlock(FILE_OPS_LOCK);
1251
1252 if (exit_prg) {
1253 logprintf(STDOUT_FILENO, "CUSE TPM is shutting down.\n");
1254 ptm_cleanup();
1255 exit(0);
1256 }
1257
1258 return;
1259
1260 error_bad_input:
1261 res = TPM_BAD_PARAMETER;
1262 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1263
1264 goto cleanup;
1265
1266 error_running:
1267 error_not_running:
1268 res = TPM_BAD_ORDINAL;
1269 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1270
1271 goto cleanup;
1272
1273 error_memory:
1274 res = TPM_SIZE;
1275 fuse_reply_ioctl(req, 0, &res, sizeof(res));
1276
1277 goto cleanup;
1278 }
1279
1280 static void ptm_init_done(void *userdata)
1281 {
1282 struct cuse_param *param = userdata;
1283 int ret;
1284
1285 /* at this point the entry in /dev/ is available */
1286 if (pidfile_write(getpid()) < 0) {
1287 ptm_cleanup();
1288 exit(-13);
1289 }
1290
1291 if (param->runas) {
1292 ret = change_process_owner(param->runas);
1293 if (ret) {
1294 ptm_cleanup();
1295 exit(ret);
1296 }
1297 }
1298 }
1299
1300 static void ptm_cleanup(void)
1301 {
1302 pidfile_remove();
1303 log_global_free();
1304 tpmstate_global_free();
1305 }
1306
1307 static const struct cuse_lowlevel_ops clops = {
1308 .open = ptm_open,
1309 .read = ptm_read,
1310 .write = ptm_write,
1311 .ioctl = ptm_ioctl,
1312 .init_done = ptm_init_done,
1313 };
1314
1315 /* ptm_cuse_lowlevel_main is like cuse_lowlevel_main with the difference that
1316 * it uses a global ptm_fuse_session so we can call fuse_session_exit() on it
1317 * for a graceful exit with cleanups.
1318 */
1319 static int
1320 ptm_cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
1321 const struct cuse_lowlevel_ops *clop, void *userdata)
1322 {
1323 int mt;
1324 int ret;
1325
1326 ptm_fuse_session = cuse_lowlevel_setup(argc, argv, ci, clop, &mt,
1327 userdata);
1328 if (ptm_fuse_session == NULL)
1329 return 1;
1330
1331 if (mt)
1332 ret = fuse_session_loop_mt(ptm_fuse_session);
1333 else
1334 ret = fuse_session_loop(ptm_fuse_session);
1335
1336 cuse_lowlevel_teardown(ptm_fuse_session);
1337 if (ret < 0)
1338 ret = 1;
1339
1340 return ret;
1341 }
1342
1343 #ifndef HAVE_SWTPM_CUSE_MAIN
1344 int main(int argc, char **argv)
1345 {
1346 const char *prgname = argv[0];
1347 const char *iface = "";
1348 #else
1349 int swtpm_cuse_main(int argc, char **argv, const char *prgname, const char *iface)
1350 {
1351 #endif
1352 int opt, longindex = 0;
1353 static struct option longopts[] = {
1354 {"maj" , required_argument, 0, 'M'},
1355 {"min" , required_argument, 0, 'm'},
1356 {"name" , required_argument, 0, 'n'},
1357 {"runas" , required_argument, 0, 'r'},
1358 {"log" , required_argument, 0, 'l'},
1359 {"locality" , required_argument, 0, 'L'},
1360 {"key" , required_argument, 0, 'k'},
1361 {"migration-key" , required_argument, 0, 'K'},
1362 {"pid" , required_argument, 0, 'p'},
1363 {"tpmstate" , required_argument, 0, 's'},
1364 {"tpm2" , no_argument, 0, '2'},
1365 {"help" , no_argument, 0, 'h'},
1366 {"version" , no_argument, 0, 'v'},
1367 {NULL , 0 , 0, 0 },
1368 };
1369 struct cuse_info cinfo;
1370 struct cuse_param param;
1371 const char *devname = NULL;
1372 char *cinfo_argv[1] = { 0 };
1373 unsigned int num;
1374 struct passwd *passwd;
1375 const char *tpmdir;
1376 int n, tpmfd;
1377 char path[PATH_MAX];
1378 int ret = 0;
1379
1380 memset(&cinfo, 0, sizeof(cinfo));
1381 memset(&param, 0, sizeof(param));
1382
1383 log_set_prefix("swtpm: ");
1384
1385 tpmversion = TPMLIB_TPM_VERSION_1_2;
1386
1387 while (true) {
1388 opt = getopt_long(argc, argv, "M:m:n:r:hv", longopts, &longindex);
1389
1390 if (opt == -1)
1391 break;
1392
1393 switch (opt) {
1394 case 'M': /* major */
1395 if (sscanf(optarg, "%u", &num) != 1) {
1396 logprintf(STDERR_FILENO, "Could not parse major number\n");
1397 ret = -1;
1398 goto exit;
1399 }
1400 if (num > 65535) {
1401 logprintf(STDERR_FILENO,
1402 "Major number outside valid range [0 - 65535]\n");
1403 ret = -1;
1404 goto exit;
1405 }
1406 cinfo.dev_major = num;
1407 break;
1408 case 'm': /* minor */
1409 if (sscanf(optarg, "%u", &num) != 1) {
1410 logprintf(STDERR_FILENO, "Could not parse major number\n");
1411 ret = -1;
1412 goto exit;
1413 }
1414 if (num > 65535) {
1415 logprintf(STDERR_FILENO,
1416 "Major number outside valid range [0 - 65535]\n");
1417 ret = -1;
1418 goto exit;
1419 }
1420 cinfo.dev_minor = num;
1421 break;
1422 case 'n': /* name */
1423 if (!cinfo.dev_info_argc) {
1424 cinfo_argv[0] = calloc(1, strlen("DEVNAME=") + strlen(optarg) + 1);
1425 if (!cinfo_argv[0]) {
1426 logprintf(STDERR_FILENO, "Out of memory\n");
1427 ret = -1;
1428 goto exit;
1429 }
1430 devname = optarg;
1431
1432 strcpy(cinfo_argv[0], "DEVNAME=");
1433 strcat(cinfo_argv[0], optarg);
1434
1435 cinfo.dev_info_argc = 1;
1436 cinfo.dev_info_argv = (const char **)cinfo_argv;
1437 }
1438 break;
1439 case 'r': /* runas */
1440 param.runas = optarg;
1441 break;
1442 case 'l': /* log */
1443 param.logging = optarg;
1444 break;
1445 case 'k': /* key */
1446 param.keydata = optarg;
1447 break;
1448 case 'K': /* migration-key */
1449 param.migkeydata = optarg;
1450 break;
1451 case 'p': /* pid */
1452 param.piddata = optarg;
1453 break;
1454 case 's': /* tpmstate */
1455 param.tpmstatedata = optarg;
1456 break;
1457 case 'L':
1458 param.localitydata = optarg;
1459 break;
1460 case '2':
1461 tpmversion = TPMLIB_TPM_VERSION_2;
1462 break;
1463 case 'h': /* help */
1464 fprintf(stdout, usage, prgname, iface);
1465 goto exit;
1466 case 'v': /* version */
1467 fprintf(stdout, "TPM emulator CUSE interface version %d.%d.%d, "
1468 "Copyright (c) 2014-2015 IBM Corp.\n",
1469 SWTPM_VER_MAJOR,
1470 SWTPM_VER_MINOR,
1471 SWTPM_VER_MICRO);
1472 goto exit;
1473 }
1474 }
1475
1476 if (optind < argc) {
1477 logprintf(STDERR_FILENO,
1478 "Unknown parameter '%s'\n", argv[optind]);
1479 ret = EXIT_FAILURE;
1480 goto exit;
1481 }
1482
1483 /*
1484 * choose the TPM version early so that getting/setting
1485 * buffer size works.
1486 */
1487 if (TPMLIB_ChooseTPMVersion(tpmversion) != TPM_SUCCESS) {
1488 logprintf(STDERR_FILENO,
1489 "Error: Could not choose TPM version.\n");
1490 ret = EXIT_FAILURE;
1491 goto exit;
1492 }
1493
1494 SWTPM_NVRAM_Set_TPMVersion(tpmversion);
1495
1496 if (!cinfo.dev_info_argv) {
1497 logprintf(STDERR_FILENO, "Error: device name missing\n");
1498 ret = -2;
1499 goto exit;
1500 }
1501
1502 if (handle_log_options(param.logging) < 0 ||
1503 handle_key_options(param.keydata) < 0 ||
1504 handle_migration_key_options(param.migkeydata) < 0 ||
1505 handle_pid_options(param.piddata) < 0 ||
1506 handle_tpmstate_options(param.tpmstatedata) < 0 ||
1507 handle_locality_options(param.localitydata, &locality_flags) < 0) {
1508 ret = -3;
1509 goto exit;
1510 }
1511
1512 if (setuid(0)) {
1513 logprintf(STDERR_FILENO, "Error: Unable to setuid root. uid = %d, "
1514 "euid = %d, gid = %d\n", getuid(), geteuid(), getgid());
1515 ret = -4;
1516 goto exit;
1517 }
1518
1519 if (param.runas) {
1520 if (!(passwd = getpwnam(param.runas))) {
1521 logprintf(STDERR_FILENO, "User '%s' does not exist\n",
1522 param.runas);
1523 ret = -5;
1524 goto exit;
1525 }
1526 }
1527
1528 tpmdir = tpmstate_get_dir();
1529 if (tpmdir == NULL) {
1530 logprintf(STDERR_FILENO,
1531 "Error: No TPM state directory is defined; "
1532 "TPM_PATH is not set\n");
1533 ret = -1;
1534 goto exit;
1535 }
1536
1537 n = snprintf(path, sizeof(path), "/dev/%s", devname);
1538 if (n < 0) {
1539 logprintf(STDERR_FILENO,
1540 "Error: Could not create device file name\n");
1541 ret = -1;
1542 goto exit;
1543 }
1544 if (n >= (int)sizeof(path)) {
1545 logprintf(STDERR_FILENO,
1546 "Error: Buffer too small to create device file name\n");
1547 ret = -1;
1548 goto exit;
1549 }
1550
1551 tpmfd = open(path, O_RDWR);
1552 if (tpmfd >= 0) {
1553 close(tpmfd);
1554 logprintf(STDERR_FILENO,
1555 "Error: A device '%s' already exists.\n",
1556 path);
1557 ret = -1;
1558 goto exit;
1559 }
1560
1561 if (tpmlib_register_callbacks(&cbs) != TPM_SUCCESS) {
1562 ret = -1;
1563 goto exit;
1564 }
1565
1566 worker_thread_init();
1567
1568 #if GLIB_MINOR_VERSION >= 32
1569 g_mutex_init(FILE_OPS_LOCK);
1570 #else
1571 FILE_OPS_LOCK = g_mutex_new();
1572 #endif
1573
1574 ret = ptm_cuse_lowlevel_main(1, argv, &cinfo, &clops, &param);
1575
1576 exit:
1577 ptm_cleanup();
1578 free(cinfo_argv[0]);
1579
1580 return ret;
1581 }