1 /*
2 * OpenConnect (SSL + DTLS) VPN client
3 *
4 * Copyright © 2008-2015 Intel Corporation.
5 *
6 * Authors: David Woodhouse <dwmw2@infradead.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * version 2.1, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 */
17
18 #include <config.h>
19
20 #include <string.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <ctype.h>
25
26 #include "openconnect-internal.h"
27
28 #ifdef HAVE_SUNOS_BROKEN_TIME
29 /*
30 * On SunOS, time() goes backwards. Thankfully, gethrtime() doesn't.
31 * https://www.illumos.org/issues/1871 and, for Solaris 11, Oracle
32 * bug ID #15760793 (previously Sun CR ID 7121035).
33 */
34 #include <sys/time.h>
35
openconnect__time(time_t * t)36 time_t openconnect__time(time_t *t)
37 {
38 time_t s = gethrtime() / 1000000000LL;
39 if (t)
40 *t = s;
41
42 return s;
43 }
44 #endif
45
46 #ifndef HAVE_VASPRINTF
openconnect__vasprintf(char ** strp,const char * fmt,va_list ap)47 int openconnect__vasprintf(char **strp, const char *fmt, va_list ap)
48 {
49 va_list ap2;
50 char *res = NULL;
51 int len = 160, len2;
52 int ret = 0;
53 int errno_save = -ENOMEM;
54
55 res = malloc(160);
56 if (!res)
57 goto err;
58
59 /* Use a copy of 'ap', preserving it in case we need to retry into
60 a larger buffer. 160 characters should be sufficient for most
61 strings in openconnect. */
62 #ifdef HAVE_VA_COPY
63 va_copy(ap2, ap);
64 #elif defined(HAVE___VA_COPY)
65 __va_copy(ap2, ap);
66 #else
67 #error No va_copy()!
68 /* You could try this. */
69 ap2 = ap;
70 /* Or this */
71 *ap2 = *ap;
72 #endif
73 len = vsnprintf(res, 160, fmt, ap2);
74 va_end(ap2);
75
76 if (len < 0) {
77 printf_err:
78 errno_save = errno;
79 free(res);
80 res = NULL;
81 goto err;
82 }
83 if (len >= 0 && len < 160)
84 goto out;
85
86 free(res);
87 res = malloc(len+1);
88 if (!res)
89 goto err;
90
91 len2 = vsnprintf(res, len+1, fmt, ap);
92 if (len2 < 0 || len2 > len)
93 goto printf_err;
94
95 ret = 0;
96 goto out;
97
98 err:
99 errno = errno_save;
100 ret = -1;
101 out:
102 *strp = res;
103 return ret;
104 }
105 #endif
106
107 #ifndef HAVE_ASPRINTF
openconnect__asprintf(char ** strp,const char * fmt,...)108 int openconnect__asprintf(char **strp, const char *fmt, ...)
109 {
110 va_list ap;
111 int ret;
112
113 va_start(ap, fmt);
114 ret = vasprintf(strp, fmt, ap);
115 va_end(ap);
116 return ret;
117 }
118 #endif
119
120 #ifndef HAVE_GETLINE
openconnect__getline(char ** lineptr,size_t * n,FILE * stream)121 ssize_t openconnect__getline(char **lineptr, size_t *n, FILE *stream)
122 {
123 int len = 0;
124
125 if (!*lineptr) {
126 *n = 2;
127 *lineptr = malloc(*n);
128 if (!*lineptr)
129 return -1;
130 }
131
132 while (fgets((*lineptr) + len, (*n) - len, stream)) {
133
134 len += strlen((*lineptr) + len);
135 if ((*lineptr)[len-1] == '\n')
136 break;
137
138 *n *= 2;
139 realloc_inplace(*lineptr, *n);
140 if (!*lineptr)
141 return -1;
142 }
143 if (len)
144 return len;
145 return -1;
146 }
147 #endif
148
149 #ifndef HAVE_STRCASESTR
150
openconnect__strcasestr(const char * haystack,const char * needle)151 char *openconnect__strcasestr(const char *haystack, const char *needle)
152 {
153 int hlen = strlen(haystack);
154 int nlen = strlen(needle);
155 int i, j;
156
157 for (i = 0; i < hlen - nlen + 1; i++) {
158 for (j = 0; j < nlen; j++) {
159 if (tolower(haystack[i + j]) !=
160 tolower(needle[j]))
161 break;
162 }
163 if (j == nlen)
164 return (char *)haystack + i;
165 }
166 return NULL;
167 }
168 #endif
169
170 #ifndef HAVE_STRNDUP
openconnect__strndup(const char * s,size_t n)171 char *openconnect__strndup(const char *s, size_t n)
172 {
173 char *r;
174
175 if (n > strlen(s))
176 n = strlen(s);
177
178 r = malloc(n + 1);
179 if (r) {
180 memcpy(r, s, n);
181 r[n] = 0;
182 }
183 return r;
184 }
185 #endif
186
187 #ifndef HAVE_INET_ATON
openconnect__inet_aton(const char * cp,struct in_addr * addr)188 int openconnect__inet_aton(const char *cp, struct in_addr *addr)
189 {
190 return inet_pton(AF_INET, cp, addr);
191 }
192 #endif
193
194 #ifdef _WIN32
openconnect__win32_strerror(DWORD err)195 char *openconnect__win32_strerror(DWORD err)
196 {
197 wchar_t *msgw;
198 char *msgutf8;
199 int nr_chars;
200
201 if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
202 FORMAT_MESSAGE_IGNORE_INSERTS |
203 FORMAT_MESSAGE_ALLOCATE_BUFFER,
204 NULL, err,
205 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
206 (LPWSTR)&msgw, 0, NULL)) {
207 if (asprintf(&msgutf8, _("(error 0x%lx)"), err) != -1)
208 return msgutf8;
209 fail:
210 return strdup(_("(Error while describing error!)"));
211 }
212 nr_chars = wcslen(msgw);
213 if (nr_chars && msgw[nr_chars - 1] == 10)
214 msgw[--nr_chars] = 0;
215 if (nr_chars && msgw[nr_chars - 1] == 13)
216 msgw[--nr_chars] = 0;
217
218 nr_chars = WideCharToMultiByte(CP_UTF8, 0, msgw, -1, NULL, 0, NULL, NULL);
219
220 msgutf8 = malloc(nr_chars);
221 if (!msgutf8)
222 goto fail;
223
224 WideCharToMultiByte(CP_UTF8, 0, msgw, -1, msgutf8, nr_chars, NULL, NULL);
225 LocalFree(msgw);
226 return msgutf8;
227 }
228
openconnect__win32_sock_init()229 int openconnect__win32_sock_init()
230 {
231 WSADATA data;
232 if (WSAStartup (MAKEWORD(1, 1), &data) != 0) {
233 fprintf(stderr, _("ERROR: Cannot initialize sockets\n"));
234 return -EIO;
235 }
236 return 0;
237 }
238
openconnect__win32_inet_pton(int af,const char * src,void * dst)239 int openconnect__win32_inet_pton(int af, const char *src, void *dst)
240 {
241 union {
242 struct sockaddr_in s4;
243 struct sockaddr_in6 s6;
244 } sa;
245 int salen = sizeof(sa);
246
247 if (af != AF_INET && af != AF_INET6) {
248 errno = EAFNOSUPPORT;
249 return -1;
250 }
251
252 memset(&sa, 0, sizeof(sa));
253 sa.s4.sin_family = af;
254
255 if (WSAStringToAddressA((char *)src, af, NULL, (void *)&sa, &salen))
256 return 0;
257
258 /* For Legacy IP we need to filter out a lot of crap that
259 * inet_aton() (and WSAStringToAddress()) will support, but
260 * which inet_pton() should not. Not to mention the fact that
261 * Wine's implementation will even succeed for strings like
262 * "2001::1" (http://bugs.winehq.org/show_bug.cgi?id=36991) */
263 if (af == AF_INET) {
264 char canon[16];
265 unsigned char *a = (unsigned char *)&sa.s4.sin_addr;
266
267 snprintf(canon, sizeof(canon), "%d.%d.%d.%d",
268 a[0], a[1], a[2], a[3]);
269
270 if (strcmp(canon, src))
271 return 0;
272
273 memcpy(dst, &sa.s4.sin_addr, sizeof(sa.s4.sin_addr));
274 return 1;
275 } else {
276 memcpy(dst, &sa.s6.sin6_addr, sizeof(sa.s6.sin6_addr));
277 return 1;
278 }
279 }
280
281 /* https://github.com/ncm/selectable-socketpair
282
283 Copyright 2007, 2010 by Nathan C. Myers <ncm@cantrip.org>
284 Redistribution and use in source and binary forms, with or without modification,
285 are permitted provided that the following conditions are met:
286
287 Redistributions of source code must retain the above copyright notice, this
288 list of conditions and the following disclaimer.
289
290 Redistributions in binary form must reproduce the above copyright notice,
291 this list of conditions and the following disclaimer in the documentation
292 and/or other materials provided with the distribution.
293
294 The name of the author must not be used to endorse or promote products derived
295 from this software without specific prior written permission.
296
297 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
298 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
299 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
300 SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
301 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
302 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
303 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
304 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
305 WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
306 */
307
308 /* Changes:
309 * 2013-07-18: Change to BSD 3-clause license
310 * 2010-03-31:
311 * set addr to 127.0.0.1 because win32 getsockname does not always set it.
312 * 2010-02-25:
313 * set SO_REUSEADDR option to avoid leaking some windows resource.
314 * Windows System Error 10049, "Event ID 4226 TCP/IP has reached
315 * the security limit imposed on the number of concurrent TCP connect
316 * attempts." Bleah.
317 * 2007-04-25:
318 * preserve value of WSAGetLastError() on all error returns.
319 * 2007-04-22: (Thanks to Matthew Gregan <kinetik@flim.org>)
320 * s/EINVAL/WSAEINVAL/ fix trivial compile failure
321 * s/socket/WSASocket/ enable creation of sockets suitable as stdin/stdout
322 * of a child process.
323 * add argument make_overlapped
324 */
325
326 #include <string.h>
327
328 # include <winsock2.h>
329 # include <windows.h>
330 # include <io.h>
331
332 /* dumb_socketpair:
333 * If make_overlapped is nonzero, both sockets created will be usable for
334 * "overlapped" operations via WSASend etc. If make_overlapped is zero,
335 * socks[0] (only) will be usable with regular ReadFile etc., and thus
336 * suitable for use as stdin or stdout of a child process. Note that the
337 * sockets must be closed with closesocket() regardless.
338 */
339
dumb_socketpair(OPENCONNECT_CMD_SOCKET socks[2],int make_overlapped)340 OPENCONNECT_CMD_SOCKET dumb_socketpair(OPENCONNECT_CMD_SOCKET socks[2], int make_overlapped)
341 {
342 union {
343 struct sockaddr_in inaddr;
344 struct sockaddr addr;
345 } a;
346 OPENCONNECT_CMD_SOCKET listener;
347 int e;
348 socklen_t addrlen = sizeof(a.inaddr);
349 DWORD flags = (make_overlapped ? WSA_FLAG_OVERLAPPED : 0);
350 int reuse = 1;
351
352 if (socks == 0) {
353 WSASetLastError(WSAEINVAL);
354 return SOCKET_ERROR;
355 }
356
357 listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
358 if (listener == INVALID_SOCKET)
359 return SOCKET_ERROR;
360
361 memset(&a, 0, sizeof(a));
362 a.inaddr.sin_family = AF_INET;
363 a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
364 a.inaddr.sin_port = 0;
365
366 socks[0] = socks[1] = -1;
367 do {
368 if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR,
369 (char*) &reuse, (socklen_t) sizeof(reuse)) == -1)
370 break;
371 if (bind(listener, &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
372 break;
373
374 memset(&a, 0, sizeof(a));
375 if (getsockname(listener, &a.addr, &addrlen) == SOCKET_ERROR)
376 break;
377 // win32 getsockname may only set the port number, p=0.0005.
378 // ( http://msdn.microsoft.com/library/ms738543.aspx ):
379 a.inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
380 a.inaddr.sin_family = AF_INET;
381
382 if (listen(listener, 1) == SOCKET_ERROR)
383 break;
384
385 socks[0] = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, flags);
386 if (socks[0] == INVALID_SOCKET)
387 break;
388 if (connect(socks[0], &a.addr, sizeof(a.inaddr)) == SOCKET_ERROR)
389 break;
390
391 socks[1] = accept(listener, NULL, NULL);
392 if (socks[1] == INVALID_SOCKET)
393 break;
394
395 closesocket(listener);
396 return 0;
397
398 } while (0);
399
400 e = WSAGetLastError();
401 closesocket(listener);
402 closesocket(socks[0]);
403 closesocket(socks[1]);
404 WSASetLastError(e);
405 return SOCKET_ERROR;
406 }
407 #endif /* _WIN32 */
408