diff options
Diffstat (limited to 'src/tddl/tddl.c')
-rw-r--r-- | src/tddl/tddl.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/tddl/tddl.c b/src/tddl/tddl.c new file mode 100644 index 0000000..b4f95b2 --- /dev/null +++ b/src/tddl/tddl.c @@ -0,0 +1,273 @@ + +/* + * Licensed Materials - Property of IBM + * + * trousers - An open source TCG Software Stack + * + * (C) Copyright International Business Machines Corp. 2004, 2005 + * + */ + + +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "trousers/tss.h" +#include "trousers_types.h" +#include "linux/tpm.h" +#include "tcslog.h" +#include "tddl.h" + +struct tpm_device_node tpm_device_nodes[] = { + {"/dev/tpm0", TDDL_UNDEF, TDDL_UNDEF}, + {"/udev/tpm0", TDDL_UNDEF, TDDL_UNDEF}, + {"/dev/tpm", TDDL_UNDEF, TDDL_UNDEF}, + {NULL, 0, 0} +}; + +struct tpm_device_node *opened_device = NULL; + +BYTE txBuffer[TDDL_TXBUF_SIZE]; +TSS_BOOL use_in_socket = FALSE; +struct tcsd_config *_tcsd_options = NULL; + +#include <sys/socket.h> +#include <sys/un.h> +#include <netinet/in.h> +#include <sys/types.h> +#include <netdb.h> +#include <fcntl.h> + + +int +open_device() +{ + int i = 0, fd = -1, tcp_device_port; + char *tcp_device_hostname = NULL; + char *un_socket_device_path = NULL; + char *tcp_device_port_string = NULL; + + if (getenv("TCSD_USE_TCP_DEVICE")) { + if ((tcp_device_hostname = getenv("TCSD_TCP_DEVICE_HOSTNAME")) == NULL) + tcp_device_hostname = "localhost"; + if ((un_socket_device_path = getenv("TCSD_UN_SOCKET_DEVICE_PATH")) == NULL) + un_socket_device_path = "/var/run/tpm/tpmd_socket:0"; + if ((tcp_device_port_string = getenv("TCSD_TCP_DEVICE_PORT")) != NULL) + tcp_device_port = atoi(tcp_device_port_string); + else + tcp_device_port = 6545; + + + fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd > 0) { + struct hostent *host = gethostbyname(tcp_device_hostname); + if (host != NULL) { + struct sockaddr_in addr; + memset(&addr, 0x0, sizeof(addr)); + addr.sin_family = host->h_addrtype; + addr.sin_port = htons(tcp_device_port); + memcpy(&addr.sin_addr, + host->h_addr, + host->h_length); + if (connect(fd, (struct sockaddr *)&addr, + sizeof(addr)) < 0) { + close(fd); + fd = -1; + } else + use_in_socket = TRUE; + } else { + close (fd); + fd = -1; + } + } + + if (fd < 0) { + struct sockaddr_un addr; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd >= 0) { + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, un_socket_device_path, + sizeof(addr.sun_path)); + if (connect(fd, (void *)&addr, sizeof(addr)) < 0) { + close(fd); + fd = -1; + } + } + } + } + + if (fd < 0) { + /* tpm_device_paths is filled out in tddl.h */ + for (i = 0; tpm_device_nodes[i].path != NULL; i++) { + errno = 0; + if ((fd = open(tpm_device_nodes[i].path, O_RDWR)) >= 0) + break; + } + } + + if (fd > 0) { + opened_device = &(tpm_device_nodes[i]); + tpm_device_nodes[i].fd = fd; + } + return fd; +} + +TSS_RESULT +Tddli_Open() +{ + int rc; + + if (opened_device != NULL) { + LogDebug("attempted to re-open the TPM driver!"); + return TDDLERR(TDDL_E_ALREADY_OPENED); + } + + rc = open_device(); + if (rc < 0) { + LogError("Could not find a device to open!"); + if (errno == ENOENT) { + /* File DNE */ + return TDDLERR(TDDL_E_COMPONENT_NOT_FOUND); + } + + return TDDLERR(TDDL_E_FAIL); + } + + return TSS_SUCCESS; +} + +TSS_RESULT +Tddli_Close() +{ + if (opened_device == NULL) { + LogDebug("attempted to re-close the TPM driver!"); + return TDDLERR(TDDL_E_ALREADY_CLOSED); + } + + close(opened_device->fd); + opened_device->fd = TDDL_UNDEF; + opened_device = NULL; + + return TSS_SUCCESS; +} + +TSS_RESULT +Tddli_TransmitData(BYTE * pTransmitBuf, UINT32 TransmitBufLen, BYTE * pReceiveBuf, + UINT32 * pReceiveBufLen) +{ + int sizeResult; + + if (TransmitBufLen > TDDL_TXBUF_SIZE) { + LogError("buffer size handed to TDDL is too large! (%u bytes)", TransmitBufLen); + return TDDLERR(TDDL_E_FAIL); + } + + memcpy(txBuffer, pTransmitBuf, TransmitBufLen); + LogDebug("Calling write to driver"); + + if (use_in_socket) { + Tddli_Close(); + if (Tddli_Open()) + return TDDLERR(TDDL_E_IOERROR); + } + + switch (opened_device->transmit) { + case TDDL_UNDEF: + /* fall through */ + case TDDL_TRANSMIT_IOCTL: + errno = 0; + if ((sizeResult = ioctl(opened_device->fd, TPMIOC_TRANSMIT, txBuffer)) != -1) { + opened_device->transmit = TDDL_TRANSMIT_IOCTL; + break; + } + LogWarn("ioctl: (%d) %s", errno, strerror(errno)); + LogInfo("Falling back to Read/Write device support."); + /* fall through */ + case TDDL_TRANSMIT_RW: + if ((sizeResult = write(opened_device->fd, + txBuffer, + TransmitBufLen)) == (int)TransmitBufLen) { + opened_device->transmit = TDDL_TRANSMIT_RW; + sizeResult = read(opened_device->fd, txBuffer, + TDDL_TXBUF_SIZE); + break; + } else { + if (sizeResult == -1) { + LogError("write to device %s failed: %s", + opened_device->path, + strerror(errno)); + } else { + LogError("wrote %d bytes to %s (tried " + "to write %d)", sizeResult, + opened_device->path, + TransmitBufLen); + } + } + /* fall through */ + default: + return TDDLERR(TDDL_E_IOERROR); + } + + if (sizeResult < 0) { + LogError("read from device %s failed: %s", opened_device->path, strerror(errno)); + return TDDLERR(TDDL_E_IOERROR); + } else if (sizeResult == 0) { + LogError("Zero bytes read from device %s", opened_device->path); + return TDDLERR(TDDL_E_IOERROR); + } + + if ((unsigned)sizeResult > *pReceiveBufLen) { + LogError("read %d bytes from device %s, (only room for %d)", sizeResult, + opened_device->path, *pReceiveBufLen); + return TDDLERR(TDDL_E_INSUFFICIENT_BUFFER); + } + + *pReceiveBufLen = sizeResult; + + memcpy(pReceiveBuf, txBuffer, *pReceiveBufLen); + return TSS_SUCCESS; +} + +TSS_RESULT +Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus) +{ + return TDDLERR(TSS_E_NOTIMPL); +} + +TSS_RESULT +Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap, + BYTE *pSetCapBuf, UINT32 SetCapBufLen) +{ + return TDDLERR(TSS_E_NOTIMPL); +} + +TSS_RESULT +Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap, + BYTE *pCapBuf, UINT32 *pCapBufLen) +{ + return TDDLERR(TSS_E_NOTIMPL); +} + +TSS_RESULT Tddli_Cancel(void) +{ + int rc; + + if (opened_device->transmit == TDDL_TRANSMIT_IOCTL) { + if ((rc = ioctl(opened_device->fd, TPMIOC_CANCEL, NULL)) == -1) { + LogError("ioctl: (%d) %s", errno, strerror(errno)); + return TDDLERR(TDDL_E_FAIL); + } else if (rc == -EIO) { + /* The driver timed out while trying to tell the chip to cancel */ + return TDDLERR(TDDL_E_COMMAND_COMPLETED); + } + + return TSS_SUCCESS; + } else { + return TDDLERR(TSS_E_NOTIMPL); + } +} |