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