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
open_device()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
Tddli_Open()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
Tddli_Close()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
Tddli_TransmitData(BYTE * pTransmitBuf,UINT32 TransmitBufLen,BYTE * pReceiveBuf,UINT32 * pReceiveBufLen)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
Tddli_GetStatus(UINT32 ReqStatusType,UINT32 * pStatus)237 Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus)
238 {
239 return TDDLERR(TSS_E_NOTIMPL);
240 }
241
242 TSS_RESULT
Tddli_SetCapability(UINT32 CapArea,UINT32 SubCap,BYTE * pSetCapBuf,UINT32 SetCapBufLen)243 Tddli_SetCapability(UINT32 CapArea, UINT32 SubCap,
244 BYTE *pSetCapBuf, UINT32 SetCapBufLen)
245 {
246 return TDDLERR(TSS_E_NOTIMPL);
247 }
248
249 TSS_RESULT
Tddli_GetCapability(UINT32 CapArea,UINT32 SubCap,BYTE * pCapBuf,UINT32 * pCapBufLen)250 Tddli_GetCapability(UINT32 CapArea, UINT32 SubCap,
251 BYTE *pCapBuf, UINT32 *pCapBufLen)
252 {
253 return TDDLERR(TSS_E_NOTIMPL);
254 }
255
Tddli_Cancel(void)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