/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2004, 2005 * */ #include #include #include #include #include #include #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 #include #include #include #include #include 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); } }