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