1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (c) 2015 - 2018 Intel Corporation
4  * All rights reserved.
5  */
6 #ifdef HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <inttypes.h>
13 #include <limits.h>
14 #include <string.h>
15 #include <stdio.h>
16 
17 #ifndef _WIN32
18 #include <netdb.h>
19 #include <netinet/in.h>
20 #include <unistd.h>
21 #endif
22 
23 #include "tss2_tpm2_types.h"
24 
25 #include "io.h"
26 #define LOGMODULE tcti
27 #include "util/log.h"
28 
29 #define MAX_PORT_STR_LEN    sizeof("65535")
30 /*
31  * The 'read_all' function attempts to read all of the 'size' bytes requested
32  * from the 'fd' provided into the buffer 'data'. This function will continue
33  * to retry after temporary failures and "short reads". It will only stop
34  * once all of the requested data has been read, an error occurs, or EOF.
35  * On error or EOF, the number of bytes read (if any) will be returned.
36  */
37 ssize_t
read_all(SOCKET fd,uint8_t * data,size_t size)38 read_all (
39     SOCKET fd,
40     uint8_t *data,
41     size_t size)
42 {
43     ssize_t recvd;
44     size_t recvd_total = 0;
45 
46     LOG_DEBUG ("reading %zu bytes from fd %d to buffer at 0x%" PRIxPTR,
47                size, fd, (uintptr_t)data);
48     do {
49 #ifdef _WIN32
50         TEMP_RETRY (recvd, recv (fd, (char *) &data [recvd_total], size, 0));
51         if (recvd < 0) {
52             LOG_WARNING ("read on fd %d failed with errno %d: %s",
53                          fd, WSAGetLastError(), strerror (WSAGetLastError()));
54             return recvd_total;
55         }
56 #else
57         TEMP_RETRY (recvd, read (fd, &data [recvd_total], size));
58         if (recvd < 0) {
59             LOG_WARNING ("read on fd %d failed with errno %d: %s",
60                          fd, errno, strerror (errno));
61             return recvd_total;
62         }
63 #endif
64         if (recvd == 0) {
65             LOG_WARNING ("Attempted read %zu bytes from fd %d, but EOF "
66                          "returned", size, fd);
67             return recvd_total;
68         }
69         LOGBLOB_DEBUG (&data [recvd_total], recvd, "read %zd bytes from fd %d:", recvd, fd);
70         recvd_total += recvd;
71         size -= recvd;
72     } while (size > 0);
73 
74     return recvd_total;
75 }
76 
77 ssize_t
write_all(SOCKET fd,const uint8_t * buf,size_t size)78 write_all (
79     SOCKET fd,
80     const uint8_t *buf,
81     size_t size)
82 {
83     ssize_t written = 0;
84     size_t written_total = 0;
85 
86     do {
87         LOG_DEBUG("writing %zu bytes starting at 0x%" PRIxPTR " to fd %d",
88                   size - written_total,
89                   (uintptr_t)(buf + written_total),
90                   fd);
91 #ifdef _WIN32
92         TEMP_RETRY (written, send (fd,
93                                    (const char*)&buf [written_total],
94                                    size - written_total, 0));
95 #else
96          TEMP_RETRY (written, write (fd,
97                                      (const char*)&buf [written_total],
98                                      size - written_total));
99 #endif
100         if (written >= 0) {
101             LOG_DEBUG ("wrote %zd bytes to fd %d", written, fd);
102             written_total += (size_t)written;
103         } else {
104 #ifdef _WIN32
105             LOG_ERROR ("failed to write to fd %d: %s", fd, strerror (WSAGetLastError()));
106 #else
107             LOG_ERROR ("failed to write to fd %d: %s", fd, strerror (errno));
108 #endif
109             return written_total;
110         }
111     } while (written_total < size);
112 
113     return (ssize_t)written_total;
114 }
115 
116 ssize_t
socket_recv_buf(SOCKET sock,uint8_t * data,size_t size)117 socket_recv_buf (
118     SOCKET sock,
119     uint8_t *data,
120     size_t size)
121 {
122     return read_all (sock, data, size);
123 }
124 
125 TSS2_RC
socket_xmit_buf(SOCKET sock,const void * buf,size_t size)126 socket_xmit_buf (
127     SOCKET sock,
128     const void *buf,
129     size_t size)
130 {
131     int ret;
132 
133     LOGBLOB_DEBUG (buf, size, "Writing %zu bytes to socket %d:", size, sock);
134     ret = write_all (sock, buf, size);
135     if (ret < (ssize_t) size) {
136 #ifdef _WIN32
137         LOG_ERROR ("write to fd %d failed, errno %d: %s", sock, WSAGetLastError(), strerror (WSAGetLastError()));
138 #else
139         LOG_ERROR ("write to fd %d failed, errno %d: %s", sock, errno, strerror (errno));
140 #endif
141         return TSS2_TCTI_RC_IO_ERROR;
142     }
143     return TSS2_RC_SUCCESS;
144 }
145 
146 TSS2_RC
socket_close(SOCKET * socket)147 socket_close (
148     SOCKET *socket)
149 {
150     int ret;
151 
152     if (socket == NULL) {
153         return TSS2_TCTI_RC_BAD_REFERENCE;
154     }
155     if (*socket == INVALID_SOCKET) {
156         return TSS2_RC_SUCCESS;
157     }
158 #ifdef _WIN32
159     ret = closesocket (*socket);
160     WSACleanup();
161     if (ret == SOCKET_ERROR) {
162         LOG_WARNING ("Failed to close SOCKET %d. errno %d: %s",
163                      *socket, WSAGetLastError(), strerror (WSAGetLastError()));
164         return TSS2_TCTI_RC_IO_ERROR;
165     }
166 #else
167     ret = close (*socket);
168     if (ret == SOCKET_ERROR) {
169         LOG_WARNING ("Failed to close SOCKET %d. errno %d: %s",
170                      *socket, errno, strerror (errno));
171         return TSS2_TCTI_RC_IO_ERROR;
172     }
173 #endif
174     *socket = INVALID_SOCKET;
175 
176     return TSS2_RC_SUCCESS;
177 }
178 
179 TSS2_RC
socket_connect(const char * hostname,uint16_t port,SOCKET * sock)180 socket_connect (
181     const char *hostname,
182     uint16_t port,
183     SOCKET *sock)
184 {
185     static const struct addrinfo hints = { .ai_socktype = SOCK_STREAM,
186         .ai_family = AF_UNSPEC, .ai_protocol = IPPROTO_TCP};
187     struct addrinfo *retp = NULL;
188     struct addrinfo *p;
189     char port_str[MAX_PORT_STR_LEN];
190     int ret = 0;
191 #ifdef _WIN32
192     char host_buff[_HOST_NAME_MAX];
193     const char *h = hostname;
194     WSADATA wsaData;
195     int iResult;
196     iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
197     if (iResult != 0) {
198         LOG_WARNING("WSAStartup failed: %d", iResult);
199         return TSS2_TCTI_RC_IO_ERROR;
200     }
201 #else
202     char host_buff[_HOST_NAME_MAX] __attribute__((unused));
203     const char *h __attribute__((unused)) = hostname;
204 #endif
205 
206     if (hostname == NULL || sock == NULL) {
207         return TSS2_TCTI_RC_BAD_REFERENCE;
208     }
209 
210     ret = snprintf(port_str, sizeof(port_str), "%u", port);
211     if (ret < 0)
212         return TSS2_TCTI_RC_BAD_VALUE;
213 
214 
215     LOG_DEBUG ("Resolving host %s", hostname);
216     ret = getaddrinfo (hostname, port_str, &hints, &retp);
217     if (ret != 0) {
218         LOG_WARNING ("Host %s does not resolve to a valid address: %d: %s",
219             hostname, ret, gai_strerror(ret));
220         return TSS2_TCTI_RC_IO_ERROR;
221     }
222 
223     for (p = retp; p != NULL; p = p->ai_next) {
224         *sock = socket (p->ai_family, SOCK_STREAM, 0);
225         void *sockaddr;
226 
227         if (*sock == INVALID_SOCKET)
228             continue;
229 
230         if (p->ai_family == AF_INET)
231             sockaddr = &((struct sockaddr_in*)p->ai_addr)->sin_addr;
232         else
233             sockaddr = &((struct sockaddr_in6*)p->ai_addr)->sin6_addr;
234 
235         h = inet_ntop(p->ai_family, sockaddr, host_buff, sizeof(host_buff));
236 
237         if (h == NULL)
238             h = hostname;
239 
240         LOG_DEBUG ("Attempting TCP connection to host %s, port %s",
241             h, port_str);
242         if (connect (*sock, p->ai_addr, p->ai_addrlen) != SOCKET_ERROR)
243             break; /* socket connected OK */
244         socket_close (sock);
245     }
246     freeaddrinfo (retp);
247     if (p == NULL) {
248 #ifdef _WIN32
249         LOG_WARNING ("Failed to connect to host %s, port %s: errno %d: %s",
250                       h, port_str, WSAGetLastError(), strerror (WSAGetLastError()));
251 #else
252         LOG_WARNING ("Failed to connect to host %s, port %s: errno %d: %s",
253                      h, port_str, errno, strerror (errno));
254 #endif
255 
256         return TSS2_TCTI_RC_IO_ERROR;
257     }
258 
259     return TSS2_RC_SUCCESS;
260 }
261