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 25struct 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 32struct tpm_device_node *opened_device = NULL; 33 34BYTE txBuffer[TDDL_TXBUF_SIZE]; 35TSS_BOOL use_in_socket = FALSE; 36struct 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 46int 47open_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 120TSS_RESULT 121Tddli_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 144TSS_RESULT 145Tddli_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 159TSS_RESULT 160Tddli_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 236TSS_RESULT 237Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus) 238{ 239 return TDDLERR(TSS_E_NOTIMPL); 240} 241 242TSS_RESULT 243Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, 244 BYTE *pSetCapBuf, UINT32 SetCapBufLen) 245{ 246 return TDDLERR(TSS_E_NOTIMPL); 247} 248 249TSS_RESULT 250Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, 251 BYTE *pCapBuf, UINT32 *pCapBufLen) 252{ 253 return TDDLERR(TSS_E_NOTIMPL); 254} 255 256TSS_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