Home | History | Annotate | Line # | Download | only in tddl
      1 
      2 /*
      3  * Licensed Materials - Property of IBM
      4  *
      5  * trousers - An open source TCG Software Stack
      6  *
      7  * (C) Copyright International Business Machines Corp. 2004, 2005
      8  *
      9  */
     10 
     11 
     12 #include <unistd.h>
     13 #include <fcntl.h>
     14 #include <stdio.h>
     15 #include <errno.h>
     16 #include <string.h>
     17 #include <sys/ioctl.h>
     18 
     19 #include "trousers/tss.h"
     20 #include "trousers_types.h"
     21 #include "linux/tpm.h"
     22 #include "tcslog.h"
     23 #include "tddl.h"
     24 
     25 struct tpm_device_node tpm_device_nodes[] = {
     26 	{"/dev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
     27 	{"/udev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
     28 	{"/dev/tpm", TDDL_UNDEF, TDDL_UNDEF},
     29 	{NULL, 0, 0}
     30 };
     31 
     32 struct tpm_device_node *opened_device = NULL;
     33 
     34 BYTE txBuffer[TDDL_TXBUF_SIZE];
     35 TSS_BOOL use_in_socket = FALSE;
     36 struct tcsd_config *_tcsd_options = NULL;
     37 
     38 #include <sys/socket.h>
     39 #include <sys/un.h>
     40 #include <netinet/in.h>
     41 #include <sys/types.h>
     42 #include <netdb.h>
     43 #include <fcntl.h>
     44 
     45 
     46 int
     47 open_device()
     48 {
     49 	int i = 0, fd = -1, tcp_device_port;
     50 	char *tcp_device_hostname = NULL;
     51 	char *un_socket_device_path = NULL;
     52 	char *tcp_device_port_string = NULL;
     53 
     54 	if (getenv("TCSD_USE_TCP_DEVICE")) {
     55 		if ((tcp_device_hostname = getenv("TCSD_TCP_DEVICE_HOSTNAME")) == NULL)
     56 			tcp_device_hostname = "localhost";
     57 		if ((un_socket_device_path = getenv("TCSD_UN_SOCKET_DEVICE_PATH")) == NULL)
     58 			un_socket_device_path = "/var/run/tpm/tpmd_socket:0";
     59 		if ((tcp_device_port_string = getenv("TCSD_TCP_DEVICE_PORT")) != NULL)
     60 			tcp_device_port = atoi(tcp_device_port_string);
     61 		else
     62 			tcp_device_port = 6545;
     63 
     64 
     65 		fd = socket(AF_INET, SOCK_STREAM, 0);
     66 		if (fd > 0) {
     67 			struct hostent *host = gethostbyname(tcp_device_hostname);
     68 			if (host != NULL) {
     69 				struct sockaddr_in addr;
     70 				memset(&addr, 0x0, sizeof(addr));
     71 				addr.sin_family = host->h_addrtype;
     72 				addr.sin_port   = htons(tcp_device_port);
     73 				memcpy(&addr.sin_addr,
     74 						host->h_addr,
     75 						host->h_length);
     76 				if (connect(fd,	(struct sockaddr *)&addr,
     77 					    sizeof(addr)) < 0) {
     78 					close(fd);
     79 					fd = -1;
     80 				} else
     81 					use_in_socket = TRUE;
     82 			} else {
     83 				close (fd);
     84 				fd = -1;
     85 			}
     86 		}
     87 
     88 		if (fd < 0) {
     89 			struct sockaddr_un addr;
     90 
     91 			fd = socket(AF_UNIX, SOCK_STREAM, 0);
     92 			if (fd >= 0) {
     93 				addr.sun_family = AF_UNIX;
     94 				strncpy(addr.sun_path, un_socket_device_path,
     95 						sizeof(addr.sun_path));
     96 				if (connect(fd, (void *)&addr, sizeof(addr)) < 0) {
     97 					close(fd);
     98 					fd = -1;
     99 				}
    100 			}
    101 		}
    102 	}
    103 
    104 	if (fd < 0) {
    105 		/* tpm_device_paths is filled out in tddl.h */
    106 		for (i = 0; tpm_device_nodes[i].path != NULL; i++) {
    107 			errno = 0;
    108 			if ((fd = open(tpm_device_nodes[i].path, O_RDWR)) >= 0)
    109 				break;
    110 		}
    111 	}
    112 
    113 	if (fd > 0) {
    114 		opened_device = &(tpm_device_nodes[i]);
    115 		tpm_device_nodes[i].fd = fd;
    116 	}
    117 	return fd;
    118 }
    119 
    120 TSS_RESULT
    121 Tddli_Open()
    122 {
    123 	int rc;
    124 
    125 	if (opened_device != NULL) {
    126 		LogDebug("attempted to re-open the TPM driver!");
    127 		return TDDLERR(TDDL_E_ALREADY_OPENED);
    128 	}
    129 
    130 	rc = open_device();
    131 	if (rc < 0) {
    132 		LogError("Could not find a device to open!");
    133 		if (errno == ENOENT) {
    134 			/* File DNE */
    135 			return TDDLERR(TDDL_E_COMPONENT_NOT_FOUND);
    136 		}
    137 
    138 		return TDDLERR(TDDL_E_FAIL);
    139 	}
    140 
    141 	return TSS_SUCCESS;
    142 }
    143 
    144 TSS_RESULT
    145 Tddli_Close()
    146 {
    147 	if (opened_device == NULL) {
    148 		LogDebug("attempted to re-close the TPM driver!");
    149 		return TDDLERR(TDDL_E_ALREADY_CLOSED);
    150 	}
    151 
    152 	close(opened_device->fd);
    153 	opened_device->fd = TDDL_UNDEF;
    154 	opened_device = NULL;
    155 
    156 	return TSS_SUCCESS;
    157 }
    158 
    159 TSS_RESULT
    160 Tddli_TransmitData(BYTE * pTransmitBuf, UINT32 TransmitBufLen, BYTE * pReceiveBuf,
    161 		   UINT32 * pReceiveBufLen)
    162 {
    163 	int sizeResult;
    164 
    165 	if (TransmitBufLen > TDDL_TXBUF_SIZE) {
    166 		LogError("buffer size handed to TDDL is too large! (%u bytes)", TransmitBufLen);
    167 		return TDDLERR(TDDL_E_FAIL);
    168 	}
    169 
    170 	memcpy(txBuffer, pTransmitBuf, TransmitBufLen);
    171 	LogDebug("Calling write to driver");
    172 
    173 	if (use_in_socket) {
    174 		Tddli_Close();
    175 		if (Tddli_Open())
    176 			return TDDLERR(TDDL_E_IOERROR);
    177 	}
    178 
    179 	switch (opened_device->transmit) {
    180 		case TDDL_UNDEF:
    181 			/* fall through */
    182 		case TDDL_TRANSMIT_IOCTL:
    183 			errno = 0;
    184 			if ((sizeResult = ioctl(opened_device->fd, TPMIOC_TRANSMIT, txBuffer)) != -1) {
    185 				opened_device->transmit = TDDL_TRANSMIT_IOCTL;
    186 				break;
    187 			}
    188 			LogWarn("ioctl: (%d) %s", errno, strerror(errno));
    189 			LogInfo("Falling back to Read/Write device support.");
    190 			/* fall through */
    191 		case TDDL_TRANSMIT_RW:
    192 			if ((sizeResult = write(opened_device->fd,
    193 						txBuffer,
    194 						TransmitBufLen)) == (int)TransmitBufLen) {
    195 				opened_device->transmit = TDDL_TRANSMIT_RW;
    196 				sizeResult = read(opened_device->fd, txBuffer,
    197 						  TDDL_TXBUF_SIZE);
    198 				break;
    199 			} else {
    200 				if (sizeResult == -1) {
    201 					LogError("write to device %s failed: %s",
    202 						 opened_device->path,
    203 						 strerror(errno));
    204 				} else {
    205 					LogError("wrote %d bytes to %s (tried "
    206 						 "to write %d)", sizeResult,
    207 						 opened_device->path,
    208 						 TransmitBufLen);
    209 				}
    210 			}
    211 			/* fall through */
    212 		default:
    213 			return TDDLERR(TDDL_E_IOERROR);
    214 	}
    215 
    216 	if (sizeResult < 0) {
    217 		LogError("read from device %s failed: %s", opened_device->path, strerror(errno));
    218 		return TDDLERR(TDDL_E_IOERROR);
    219 	} else if (sizeResult == 0) {
    220 		LogError("Zero bytes read from device %s", opened_device->path);
    221 		return TDDLERR(TDDL_E_IOERROR);
    222 	}
    223 
    224 	if ((unsigned)sizeResult > *pReceiveBufLen) {
    225 		LogError("read %d bytes from device %s, (only room for %d)", sizeResult,
    226 				opened_device->path, *pReceiveBufLen);
    227 		return TDDLERR(TDDL_E_INSUFFICIENT_BUFFER);
    228 	}
    229 
    230 	*pReceiveBufLen = sizeResult;
    231 
    232 	memcpy(pReceiveBuf, txBuffer, *pReceiveBufLen);
    233 	return TSS_SUCCESS;
    234 }
    235 
    236 TSS_RESULT
    237 Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus)
    238 {
    239 	return TDDLERR(TSS_E_NOTIMPL);
    240 }
    241 
    242 TSS_RESULT
    243 Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap,
    244 		    BYTE *pSetCapBuf, UINT32 SetCapBufLen)
    245 {
    246 	return TDDLERR(TSS_E_NOTIMPL);
    247 }
    248 
    249 TSS_RESULT
    250 Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap,
    251 		    BYTE *pCapBuf, UINT32 *pCapBufLen)
    252 {
    253 	return TDDLERR(TSS_E_NOTIMPL);
    254 }
    255 
    256 TSS_RESULT Tddli_Cancel(void)
    257 {
    258 	int rc;
    259 
    260 	if (opened_device->transmit == TDDL_TRANSMIT_IOCTL) {
    261 		if ((rc = ioctl(opened_device->fd, TPMIOC_CANCEL, NULL)) == -1) {
    262 			LogError("ioctl: (%d) %s", errno, strerror(errno));
    263 			return TDDLERR(TDDL_E_FAIL);
    264 		} else if (rc == -EIO) {
    265 			/* The driver timed out while trying to tell the chip to cancel */
    266 			return TDDLERR(TDDL_E_COMMAND_COMPLETED);
    267 		}
    268 
    269 		return TSS_SUCCESS;
    270 	} else {
    271 		return TDDLERR(TSS_E_NOTIMPL);
    272 	}
    273 }
    274