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