]>
Commit | Line | Data |
---|---|---|
d02b48c6 | 1 | /* crypto/bio/b_sock.c */ |
58964a49 | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
d02b48c6 RE |
3 | * All rights reserved. |
4 | * | |
5 | * This package is an SSL implementation written | |
6 | * by Eric Young (eay@cryptsoft.com). | |
7 | * The implementation was written so as to conform with Netscapes SSL. | |
0f113f3e | 8 | * |
d02b48c6 RE |
9 | * This library is free for commercial and non-commercial use as long as |
10 | * the following conditions are aheared to. The following conditions | |
11 | * apply to all code found in this distribution, be it the RC4, RSA, | |
12 | * lhash, DES, etc., code; not just the SSL code. The SSL documentation | |
13 | * included with this distribution is covered by the same copyright terms | |
14 | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | |
0f113f3e | 15 | * |
d02b48c6 RE |
16 | * Copyright remains Eric Young's, and as such any Copyright notices in |
17 | * the code are not to be removed. | |
18 | * If this package is used in a product, Eric Young should be given attribution | |
19 | * as the author of the parts of the library used. | |
20 | * This can be in the form of a textual message at program startup or | |
21 | * in documentation (online or textual) provided with the package. | |
0f113f3e | 22 | * |
d02b48c6 RE |
23 | * Redistribution and use in source and binary forms, with or without |
24 | * modification, are permitted provided that the following conditions | |
25 | * are met: | |
26 | * 1. Redistributions of source code must retain the copyright | |
27 | * notice, this list of conditions and the following disclaimer. | |
28 | * 2. Redistributions in binary form must reproduce the above copyright | |
29 | * notice, this list of conditions and the following disclaimer in the | |
30 | * documentation and/or other materials provided with the distribution. | |
31 | * 3. All advertising materials mentioning features or use of this software | |
32 | * must display the following acknowledgement: | |
33 | * "This product includes cryptographic software written by | |
34 | * Eric Young (eay@cryptsoft.com)" | |
35 | * The word 'cryptographic' can be left out if the rouines from the library | |
36 | * being used are not cryptographic related :-). | |
0f113f3e | 37 | * 4. If you include any Windows specific code (or a derivative thereof) from |
d02b48c6 RE |
38 | * the apps directory (application code) you must include an acknowledgement: |
39 | * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | |
0f113f3e | 40 | * |
d02b48c6 RE |
41 | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND |
42 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
43 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
44 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
45 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
46 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
47 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | |
0f113f3e | 52 | * |
d02b48c6 RE |
53 | * The licence and distribution terms for any publically available version or |
54 | * derivative of this code cannot be changed. i.e. this code cannot simply be | |
55 | * copied and put under another distribution licence | |
56 | * [including the GNU Public Licence.] | |
57 | */ | |
58 | ||
d02b48c6 | 59 | #include <stdio.h> |
58964a49 | 60 | #include <stdlib.h> |
d02b48c6 RE |
61 | #include <errno.h> |
62 | #define USE_SOCKETS | |
63 | #include "cryptlib.h" | |
ec577822 | 64 | #include <openssl/bio.h> |
b764ab95 | 65 | #if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK) |
0f113f3e MC |
66 | # include <netdb.h> |
67 | # if defined(NETWARE_CLIB) | |
68 | # include <sys/ioctl.h> | |
eef0c1f3 | 69 | NETDB_DEFINE_CONTEXT |
0f113f3e | 70 | # endif |
eef0c1f3 | 71 | #endif |
9ba4cc00 | 72 | #ifndef OPENSSL_NO_SOCK |
0f113f3e MC |
73 | # include <openssl/dso.h> |
74 | # define SOCKET_PROTOCOL IPPROTO_TCP | |
75 | # ifdef SO_MAXCONN | |
76 | # define MAX_LISTEN SO_MAXCONN | |
77 | # elif defined(SOMAXCONN) | |
78 | # define MAX_LISTEN SOMAXCONN | |
79 | # else | |
80 | # define MAX_LISTEN 32 | |
81 | # endif | |
82 | # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)) | |
83 | static int wsa_init_done = 0; | |
84 | # endif | |
d02b48c6 | 85 | |
2f4c1dc8 AP |
86 | /* |
87 | * WSAAPI specifier is required to make indirect calls to run-time | |
88 | * linked WinSock 2 functions used in this module, to be specific | |
89 | * [get|free]addrinfo and getnameinfo. This is because WinSock uses | |
90 | * uses non-C calling convention, __stdcall vs. __cdecl, on x86 | |
91 | * Windows. On non-WinSock platforms WSAAPI needs to be void. | |
92 | */ | |
0f113f3e MC |
93 | # ifndef WSAAPI |
94 | # define WSAAPI | |
95 | # endif | |
96 | ||
97 | # if 0 | |
98 | static unsigned long BIO_ghbn_hits = 0L; | |
99 | static unsigned long BIO_ghbn_miss = 0L; | |
100 | ||
101 | # define GHBN_NUM 4 | |
102 | static struct ghbn_cache_st { | |
103 | char name[129]; | |
104 | struct hostent *ent; | |
105 | unsigned long order; | |
106 | } ghbn_cache[GHBN_NUM]; | |
107 | # endif | |
108 | ||
109 | static int get_ip(const char *str, unsigned char *ip); | |
110 | # if 0 | |
58964a49 RE |
111 | static void ghbn_free(struct hostent *a); |
112 | static struct hostent *ghbn_dup(struct hostent *a); | |
0f113f3e | 113 | # endif |
6b691a5c | 114 | int BIO_get_host_ip(const char *str, unsigned char *ip) |
0f113f3e MC |
115 | { |
116 | int i; | |
117 | int err = 1; | |
118 | int locked = 0; | |
119 | struct hostent *he; | |
120 | ||
121 | i = get_ip(str, ip); | |
122 | if (i < 0) { | |
123 | BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_INVALID_IP_ADDRESS); | |
124 | goto err; | |
125 | } | |
126 | ||
127 | /* | |
128 | * At this point, we have something that is most probably correct in some | |
129 | * way, so let's init the socket. | |
130 | */ | |
131 | if (BIO_sock_init() != 1) | |
132 | return 0; /* don't generate another error code here */ | |
133 | ||
134 | /* | |
135 | * If the string actually contained an IP address, we need not do | |
136 | * anything more | |
137 | */ | |
138 | if (i > 0) | |
139 | return (1); | |
140 | ||
141 | /* do a gethostbyname */ | |
142 | CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME); | |
143 | locked = 1; | |
144 | he = BIO_gethostbyname(str); | |
145 | if (he == NULL) { | |
146 | BIOerr(BIO_F_BIO_GET_HOST_IP, BIO_R_BAD_HOSTNAME_LOOKUP); | |
147 | goto err; | |
148 | } | |
149 | ||
150 | if (he->h_addrtype != AF_INET) { | |
151 | BIOerr(BIO_F_BIO_GET_HOST_IP, | |
152 | BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); | |
153 | goto err; | |
154 | } | |
155 | for (i = 0; i < 4; i++) | |
156 | ip[i] = he->h_addr_list[0][i]; | |
157 | err = 0; | |
ba9f2808 BM |
158 | |
159 | err: | |
0f113f3e MC |
160 | if (locked) |
161 | CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME); | |
162 | if (err) { | |
163 | ERR_add_error_data(2, "host=", str); | |
164 | return 0; | |
165 | } else | |
166 | return 1; | |
167 | } | |
d02b48c6 | 168 | |
6b691a5c | 169 | int BIO_get_port(const char *str, unsigned short *port_ptr) |
0f113f3e MC |
170 | { |
171 | int i; | |
172 | struct servent *s; | |
173 | ||
174 | if (str == NULL) { | |
175 | BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED); | |
176 | return (0); | |
177 | } | |
178 | i = atoi(str); | |
179 | if (i != 0) | |
180 | *port_ptr = (unsigned short)i; | |
181 | else { | |
182 | CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME); | |
183 | /* | |
184 | * Note: under VMS with SOCKETSHR, it seems like the first parameter | |
185 | * is 'char *', instead of 'const char *' | |
186 | */ | |
187 | # ifndef CONST_STRICT | |
188 | s = getservbyname((char *)str, "tcp"); | |
189 | # else | |
190 | s = getservbyname(str, "tcp"); | |
191 | # endif | |
192 | if (s != NULL) | |
193 | *port_ptr = ntohs((unsigned short)s->s_port); | |
194 | CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME); | |
195 | if (s == NULL) { | |
196 | if (strcmp(str, "http") == 0) | |
197 | *port_ptr = 80; | |
198 | else if (strcmp(str, "telnet") == 0) | |
199 | *port_ptr = 23; | |
200 | else if (strcmp(str, "socks") == 0) | |
201 | *port_ptr = 1080; | |
202 | else if (strcmp(str, "https") == 0) | |
203 | *port_ptr = 443; | |
204 | else if (strcmp(str, "ssl") == 0) | |
205 | *port_ptr = 443; | |
206 | else if (strcmp(str, "ftp") == 0) | |
207 | *port_ptr = 21; | |
208 | else if (strcmp(str, "gopher") == 0) | |
209 | *port_ptr = 70; | |
210 | # if 0 | |
211 | else if (strcmp(str, "wais") == 0) | |
212 | *port_ptr = 21; | |
213 | # endif | |
214 | else { | |
215 | SYSerr(SYS_F_GETSERVBYNAME, get_last_socket_error()); | |
216 | ERR_add_error_data(3, "service='", str, "'"); | |
217 | return (0); | |
218 | } | |
219 | } | |
220 | } | |
221 | return (1); | |
222 | } | |
d02b48c6 | 223 | |
6b691a5c | 224 | int BIO_sock_error(int sock) |
0f113f3e MC |
225 | { |
226 | int j, i; | |
227 | union { | |
228 | size_t s; | |
229 | int i; | |
230 | } size; | |
231 | ||
232 | /* heuristic way to adapt for platforms that expect 64-bit optlen */ | |
233 | size.s = 0, size.i = sizeof(j); | |
234 | /* | |
235 | * Note: under Windows the third parameter is of type (char *) whereas | |
236 | * under other systems it is (void *) if you don't have a cast it will | |
237 | * choke the compiler: if you do have a cast then you can either go for | |
238 | * (char *) or (void *). | |
239 | */ | |
240 | i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, (void *)&size); | |
241 | if (i < 0) | |
242 | return (1); | |
243 | else | |
244 | return (j); | |
245 | } | |
246 | ||
247 | # if 0 | |
6b691a5c | 248 | long BIO_ghbn_ctrl(int cmd, int iarg, char *parg) |
0f113f3e MC |
249 | { |
250 | int i; | |
251 | char **p; | |
252 | ||
253 | switch (cmd) { | |
254 | case BIO_GHBN_CTRL_HITS: | |
255 | return (BIO_ghbn_hits); | |
256 | /* break; */ | |
257 | case BIO_GHBN_CTRL_MISSES: | |
258 | return (BIO_ghbn_miss); | |
259 | /* break; */ | |
260 | case BIO_GHBN_CTRL_CACHE_SIZE: | |
261 | return (GHBN_NUM); | |
262 | /* break; */ | |
263 | case BIO_GHBN_CTRL_GET_ENTRY: | |
264 | if ((iarg >= 0) && (iarg < GHBN_NUM) && (ghbn_cache[iarg].order > 0)) { | |
265 | p = (char **)parg; | |
266 | if (p == NULL) | |
267 | return (0); | |
268 | *p = ghbn_cache[iarg].name; | |
269 | ghbn_cache[iarg].name[128] = '\0'; | |
270 | return (1); | |
271 | } | |
272 | return (0); | |
273 | /* break; */ | |
274 | case BIO_GHBN_CTRL_FLUSH: | |
275 | for (i = 0; i < GHBN_NUM; i++) | |
276 | ghbn_cache[i].order = 0; | |
277 | break; | |
278 | default: | |
279 | return (0); | |
280 | } | |
281 | return (1); | |
282 | } | |
283 | # endif | |
284 | ||
285 | # if 0 | |
6b691a5c | 286 | static struct hostent *ghbn_dup(struct hostent *a) |
0f113f3e MC |
287 | { |
288 | struct hostent *ret; | |
289 | int i, j; | |
290 | ||
291 | MemCheck_off(); | |
292 | ret = (struct hostent *)OPENSSL_malloc(sizeof(struct hostent)); | |
293 | if (ret == NULL) | |
294 | return (NULL); | |
295 | memset(ret, 0, sizeof(struct hostent)); | |
296 | ||
297 | for (i = 0; a->h_aliases[i] != NULL; i++) ; | |
298 | i++; | |
299 | ret->h_aliases = (char **)OPENSSL_malloc(i * sizeof(char *)); | |
300 | if (ret->h_aliases == NULL) | |
301 | goto err; | |
302 | memset(ret->h_aliases, 0, i * sizeof(char *)); | |
303 | ||
304 | for (i = 0; a->h_addr_list[i] != NULL; i++) ; | |
305 | i++; | |
306 | ret->h_addr_list = (char **)OPENSSL_malloc(i * sizeof(char *)); | |
307 | if (ret->h_addr_list == NULL) | |
308 | goto err; | |
309 | memset(ret->h_addr_list, 0, i * sizeof(char *)); | |
310 | ||
311 | j = strlen(a->h_name) + 1; | |
312 | if ((ret->h_name = OPENSSL_malloc(j)) == NULL) | |
313 | goto err; | |
314 | memcpy((char *)ret->h_name, a->h_name, j); | |
315 | for (i = 0; a->h_aliases[i] != NULL; i++) { | |
316 | j = strlen(a->h_aliases[i]) + 1; | |
317 | if ((ret->h_aliases[i] = OPENSSL_malloc(j)) == NULL) | |
318 | goto err; | |
319 | memcpy(ret->h_aliases[i], a->h_aliases[i], j); | |
320 | } | |
321 | ret->h_length = a->h_length; | |
322 | ret->h_addrtype = a->h_addrtype; | |
323 | for (i = 0; a->h_addr_list[i] != NULL; i++) { | |
324 | if ((ret->h_addr_list[i] = OPENSSL_malloc(a->h_length)) == NULL) | |
325 | goto err; | |
326 | memcpy(ret->h_addr_list[i], a->h_addr_list[i], a->h_length); | |
327 | } | |
328 | if (0) { | |
329 | err: | |
330 | if (ret != NULL) | |
331 | ghbn_free(ret); | |
332 | ret = NULL; | |
333 | } | |
334 | MemCheck_on(); | |
335 | return (ret); | |
336 | } | |
58964a49 | 337 | |
6b691a5c | 338 | static void ghbn_free(struct hostent *a) |
0f113f3e MC |
339 | { |
340 | int i; | |
341 | ||
342 | if (a == NULL) | |
343 | return; | |
344 | ||
345 | if (a->h_aliases != NULL) { | |
346 | for (i = 0; a->h_aliases[i] != NULL; i++) | |
347 | OPENSSL_free(a->h_aliases[i]); | |
348 | OPENSSL_free(a->h_aliases); | |
349 | } | |
350 | if (a->h_addr_list != NULL) { | |
351 | for (i = 0; a->h_addr_list[i] != NULL; i++) | |
352 | OPENSSL_free(a->h_addr_list[i]); | |
353 | OPENSSL_free(a->h_addr_list); | |
354 | } | |
355 | if (a->h_name != NULL) | |
356 | OPENSSL_free(a->h_name); | |
357 | OPENSSL_free(a); | |
358 | } | |
359 | ||
360 | # endif | |
15863658 | 361 | |
6b691a5c | 362 | struct hostent *BIO_gethostbyname(const char *name) |
0f113f3e MC |
363 | { |
364 | # if 1 | |
365 | /* | |
366 | * Caching gethostbyname() results forever is wrong, so we have to let | |
367 | * the true gethostbyname() worry about this | |
368 | */ | |
369 | # if (defined(NETWARE_BSDSOCK) && !defined(__NOVELL_LIBC__)) | |
370 | return gethostbyname((char *)name); | |
371 | # else | |
372 | return gethostbyname(name); | |
373 | # endif | |
374 | # else | |
375 | struct hostent *ret; | |
376 | int i, lowi = 0, j; | |
377 | unsigned long low = (unsigned long)-1; | |
58964a49 | 378 | |
c602e7f4 | 379 | # if 0 |
0f113f3e MC |
380 | /* |
381 | * It doesn't make sense to use locking here: The function interface is | |
382 | * not thread-safe, because threads can never be sure when some other | |
383 | * thread destroys the data they were given a pointer to. | |
384 | */ | |
385 | CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME); | |
c602e7f4 | 386 | # endif |
0f113f3e MC |
387 | j = strlen(name); |
388 | if (j < 128) { | |
389 | for (i = 0; i < GHBN_NUM; i++) { | |
390 | if (low > ghbn_cache[i].order) { | |
391 | low = ghbn_cache[i].order; | |
392 | lowi = i; | |
393 | } | |
394 | if (ghbn_cache[i].order > 0) { | |
395 | if (strncmp(name, ghbn_cache[i].name, 128) == 0) | |
396 | break; | |
397 | } | |
398 | } | |
399 | } else | |
400 | i = GHBN_NUM; | |
401 | ||
402 | if (i == GHBN_NUM) { /* no hit */ | |
403 | BIO_ghbn_miss++; | |
404 | /* | |
405 | * Note: under VMS with SOCKETSHR, it seems like the first parameter | |
406 | * is 'char *', instead of 'const char *' | |
407 | */ | |
c602e7f4 | 408 | # ifndef CONST_STRICT |
0f113f3e | 409 | ret = gethostbyname((char *)name); |
eef0c1f3 | 410 | # else |
0f113f3e | 411 | ret = gethostbyname(name); |
c602e7f4 | 412 | # endif |
58964a49 | 413 | |
0f113f3e MC |
414 | if (ret == NULL) |
415 | goto end; | |
416 | if (j > 128) { /* too big to cache */ | |
c602e7f4 | 417 | # if 0 |
0f113f3e MC |
418 | /* |
419 | * If we were trying to make this function thread-safe (which is | |
420 | * bound to fail), we'd have to give up in this case (or allocate | |
421 | * more memory). | |
422 | */ | |
423 | ret = NULL; | |
c602e7f4 | 424 | # endif |
0f113f3e MC |
425 | goto end; |
426 | } | |
427 | ||
428 | /* else add to cache */ | |
429 | if (ghbn_cache[lowi].ent != NULL) | |
430 | ghbn_free(ghbn_cache[lowi].ent); /* XXX not thread-safe */ | |
431 | ghbn_cache[lowi].name[0] = '\0'; | |
432 | ||
433 | if ((ret = ghbn_cache[lowi].ent = ghbn_dup(ret)) == NULL) { | |
434 | BIOerr(BIO_F_BIO_GETHOSTBYNAME, ERR_R_MALLOC_FAILURE); | |
435 | goto end; | |
436 | } | |
437 | strncpy(ghbn_cache[lowi].name, name, 128); | |
438 | ghbn_cache[lowi].order = BIO_ghbn_miss + BIO_ghbn_hits; | |
439 | } else { | |
440 | BIO_ghbn_hits++; | |
441 | ret = ghbn_cache[i].ent; | |
442 | ghbn_cache[i].order = BIO_ghbn_miss + BIO_ghbn_hits; | |
443 | } | |
444 | end: | |
c602e7f4 | 445 | # if 0 |
0f113f3e | 446 | CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME); |
c602e7f4 | 447 | # endif |
0f113f3e MC |
448 | return (ret); |
449 | # endif | |
450 | } | |
c602e7f4 | 451 | |
6b691a5c | 452 | int BIO_sock_init(void) |
0f113f3e MC |
453 | { |
454 | # ifdef OPENSSL_SYS_WINDOWS | |
455 | static struct WSAData wsa_state; | |
456 | ||
457 | if (!wsa_init_done) { | |
458 | int err; | |
459 | ||
460 | wsa_init_done = 1; | |
461 | memset(&wsa_state, 0, sizeof(wsa_state)); | |
462 | /* | |
463 | * Not making wsa_state available to the rest of the code is formally | |
464 | * wrong. But the structures we use are [beleived to be] invariable | |
465 | * among Winsock DLLs, while API availability is [expected to be] | |
466 | * probed at run-time with DSO_global_lookup. | |
467 | */ | |
468 | if (WSAStartup(0x0202, &wsa_state) != 0) { | |
469 | err = WSAGetLastError(); | |
470 | SYSerr(SYS_F_WSASTARTUP, err); | |
471 | BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP); | |
472 | return (-1); | |
473 | } | |
474 | } | |
475 | # endif /* OPENSSL_SYS_WINDOWS */ | |
476 | # ifdef WATT32 | |
477 | extern int _watt_do_exit; | |
478 | _watt_do_exit = 0; /* don't make sock_init() call exit() */ | |
479 | if (sock_init()) | |
480 | return (-1); | |
481 | # endif | |
482 | ||
483 | # if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) | |
4d8743f4 RL |
484 | WORD wVerReq; |
485 | WSADATA wsaData; | |
486 | int err; | |
487 | ||
0f113f3e MC |
488 | if (!wsa_init_done) { |
489 | wsa_init_done = 1; | |
490 | wVerReq = MAKEWORD(2, 0); | |
491 | err = WSAStartup(wVerReq, &wsaData); | |
492 | if (err != 0) { | |
493 | SYSerr(SYS_F_WSASTARTUP, err); | |
494 | BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP); | |
495 | return (-1); | |
496 | } | |
497 | } | |
498 | # endif | |
499 | ||
500 | return (1); | |
501 | } | |
d02b48c6 | 502 | |
6b691a5c | 503 | void BIO_sock_cleanup(void) |
0f113f3e MC |
504 | { |
505 | # ifdef OPENSSL_SYS_WINDOWS | |
506 | if (wsa_init_done) { | |
507 | wsa_init_done = 0; | |
508 | # if 0 /* this call is claimed to be non-present in | |
509 | * Winsock2 */ | |
510 | WSACancelBlockingCall(); | |
511 | # endif | |
4d8743f4 | 512 | WSACleanup(); |
0f113f3e MC |
513 | } |
514 | # elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK) | |
515 | if (wsa_init_done) { | |
516 | wsa_init_done = 0; | |
517 | WSACleanup(); | |
518 | } | |
519 | # endif | |
520 | } | |
d02b48c6 | 521 | |
0f113f3e | 522 | # if !defined(OPENSSL_SYS_VMS) || __VMS_VER >= 70000000 |
7d7d2cbc | 523 | |
c029841e | 524 | int BIO_socket_ioctl(int fd, long type, void *arg) |
0f113f3e MC |
525 | { |
526 | int i; | |
527 | ||
528 | # ifdef __DJGPP__ | |
529 | i = ioctlsocket(fd, type, (char *)arg); | |
530 | # else | |
531 | # if defined(OPENSSL_SYS_VMS) | |
50e735f9 MC |
532 | /*- |
533 | * 2011-02-18 SMS. | |
534 | * VMS ioctl() can't tolerate a 64-bit "void *arg", but we | |
535 | * observe that all the consumers pass in an "unsigned long *", | |
536 | * so we arrange a local copy with a short pointer, and use | |
537 | * that, instead. | |
538 | */ | |
0f113f3e MC |
539 | # if __INITIAL_POINTER_SIZE == 64 |
540 | # define ARG arg_32p | |
541 | # pragma pointer_size save | |
542 | # pragma pointer_size 32 | |
543 | unsigned long arg_32; | |
544 | unsigned long *arg_32p; | |
545 | # pragma pointer_size restore | |
546 | arg_32p = &arg_32; | |
547 | arg_32 = *((unsigned long *)arg); | |
548 | # else /* __INITIAL_POINTER_SIZE == 64 */ | |
549 | # define ARG arg | |
550 | # endif /* __INITIAL_POINTER_SIZE == 64 [else] */ | |
551 | # else /* defined(OPENSSL_SYS_VMS) */ | |
552 | # define ARG arg | |
553 | # endif /* defined(OPENSSL_SYS_VMS) [else] */ | |
554 | ||
555 | i = ioctlsocket(fd, type, ARG); | |
556 | # endif /* __DJGPP__ */ | |
557 | if (i < 0) | |
558 | SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error()); | |
559 | return (i); | |
560 | } | |
561 | # endif /* __VMS_VER */ | |
562 | ||
563 | /* | |
564 | * The reason I have implemented this instead of using sscanf is because | |
565 | * Visual C 1.52c gives an unresolved external when linking a DLL :-( | |
566 | */ | |
6b691a5c | 567 | static int get_ip(const char *str, unsigned char ip[4]) |
0f113f3e MC |
568 | { |
569 | unsigned int tmp[4]; | |
570 | int num = 0, c, ok = 0; | |
571 | ||
572 | tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; | |
573 | ||
574 | for (;;) { | |
575 | c = *(str++); | |
576 | if ((c >= '0') && (c <= '9')) { | |
577 | ok = 1; | |
578 | tmp[num] = tmp[num] * 10 + c - '0'; | |
579 | if (tmp[num] > 255) | |
580 | return (0); | |
581 | } else if (c == '.') { | |
582 | if (!ok) | |
583 | return (-1); | |
584 | if (num == 3) | |
585 | return (0); | |
586 | num++; | |
587 | ok = 0; | |
588 | } else if (c == '\0' && (num == 3) && ok) | |
589 | break; | |
590 | else | |
591 | return (0); | |
592 | } | |
593 | ip[0] = tmp[0]; | |
594 | ip[1] = tmp[1]; | |
595 | ip[2] = tmp[2]; | |
596 | ip[3] = tmp[3]; | |
597 | return (1); | |
598 | } | |
d02b48c6 | 599 | |
6b691a5c | 600 | int BIO_get_accept_socket(char *host, int bind_mode) |
0f113f3e MC |
601 | { |
602 | int ret = 0; | |
603 | union { | |
604 | struct sockaddr sa; | |
605 | struct sockaddr_in sa_in; | |
606 | # if OPENSSL_USE_IPV6 | |
607 | struct sockaddr_in6 sa_in6; | |
608 | # endif | |
609 | } server, client; | |
610 | int s = INVALID_SOCKET, cs, addrlen; | |
611 | unsigned char ip[4]; | |
612 | unsigned short port; | |
613 | char *str = NULL, *e; | |
614 | char *h, *p; | |
615 | unsigned long l; | |
616 | int err_num; | |
617 | ||
618 | if (BIO_sock_init() != 1) | |
619 | return (INVALID_SOCKET); | |
620 | ||
621 | if ((str = BUF_strdup(host)) == NULL) | |
622 | return (INVALID_SOCKET); | |
623 | ||
624 | h = p = NULL; | |
625 | h = str; | |
626 | for (e = str; *e; e++) { | |
627 | if (*e == ':') { | |
628 | p = e; | |
629 | } else if (*e == '/') { | |
630 | *e = '\0'; | |
631 | break; | |
632 | } | |
633 | } | |
634 | if (p) | |
635 | *p++ = '\0'; /* points at last ':', '::port' is special | |
636 | * [see below] */ | |
637 | else | |
638 | p = h, h = NULL; | |
639 | ||
640 | # ifdef EAI_FAMILY | |
641 | do { | |
642 | static union { | |
643 | void *p; | |
644 | int (WSAAPI *f) (const char *, const char *, | |
645 | const struct addrinfo *, struct addrinfo **); | |
646 | } p_getaddrinfo = { | |
647 | NULL | |
648 | }; | |
649 | static union { | |
650 | void *p; | |
651 | void (WSAAPI *f) (struct addrinfo *); | |
652 | } p_freeaddrinfo = { | |
653 | NULL | |
654 | }; | |
655 | struct addrinfo *res, hint; | |
656 | ||
657 | if (p_getaddrinfo.p == NULL) { | |
658 | if ((p_getaddrinfo.p = DSO_global_lookup("getaddrinfo")) == NULL | |
659 | || (p_freeaddrinfo.p = | |
660 | DSO_global_lookup("freeaddrinfo")) == NULL) | |
661 | p_getaddrinfo.p = (void *)-1; | |
662 | } | |
663 | if (p_getaddrinfo.p == (void *)-1) | |
664 | break; | |
665 | ||
666 | /* | |
667 | * '::port' enforces IPv6 wildcard listener. Some OSes, e.g. Solaris, | |
668 | * default to IPv6 without any hint. Also note that commonly IPv6 | |
669 | * wildchard socket can service IPv4 connections just as well... | |
670 | */ | |
671 | memset(&hint, 0, sizeof(hint)); | |
672 | hint.ai_flags = AI_PASSIVE; | |
673 | if (h) { | |
674 | if (strchr(h, ':')) { | |
675 | if (h[1] == '\0') | |
676 | h = NULL; | |
677 | # if OPENSSL_USE_IPV6 | |
678 | hint.ai_family = AF_INET6; | |
679 | # else | |
680 | h = NULL; | |
681 | # endif | |
682 | } else if (h[0] == '*' && h[1] == '\0') { | |
683 | hint.ai_family = AF_INET; | |
684 | h = NULL; | |
685 | } | |
686 | } | |
687 | ||
688 | if ((*p_getaddrinfo.f) (h, p, &hint, &res)) | |
689 | break; | |
690 | ||
691 | addrlen = res->ai_addrlen <= sizeof(server) ? | |
692 | res->ai_addrlen : sizeof(server); | |
693 | memcpy(&server, res->ai_addr, addrlen); | |
694 | ||
695 | (*p_freeaddrinfo.f) (res); | |
696 | goto again; | |
697 | } while (0); | |
698 | # endif | |
699 | ||
700 | if (!BIO_get_port(p, &port)) | |
701 | goto err; | |
702 | ||
703 | memset((char *)&server, 0, sizeof(server)); | |
704 | server.sa_in.sin_family = AF_INET; | |
705 | server.sa_in.sin_port = htons(port); | |
706 | addrlen = sizeof(server.sa_in); | |
707 | ||
708 | if (h == NULL || strcmp(h, "*") == 0) | |
709 | server.sa_in.sin_addr.s_addr = INADDR_ANY; | |
710 | else { | |
711 | if (!BIO_get_host_ip(h, &(ip[0]))) | |
712 | goto err; | |
713 | l = (unsigned long) | |
714 | ((unsigned long)ip[0] << 24L) | | |
715 | ((unsigned long)ip[1] << 16L) | | |
716 | ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]); | |
717 | server.sa_in.sin_addr.s_addr = htonl(l); | |
718 | } | |
719 | ||
720 | again: | |
721 | s = socket(server.sa.sa_family, SOCK_STREAM, SOCKET_PROTOCOL); | |
722 | if (s == INVALID_SOCKET) { | |
723 | SYSerr(SYS_F_SOCKET, get_last_socket_error()); | |
724 | ERR_add_error_data(3, "port='", host, "'"); | |
725 | BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); | |
726 | goto err; | |
727 | } | |
728 | # ifdef SO_REUSEADDR | |
729 | if (bind_mode == BIO_BIND_REUSEADDR) { | |
730 | int i = 1; | |
731 | ||
732 | ret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&i, sizeof(i)); | |
733 | bind_mode = BIO_BIND_NORMAL; | |
734 | } | |
735 | # endif | |
736 | if (bind(s, &server.sa, addrlen) == -1) { | |
737 | # ifdef SO_REUSEADDR | |
738 | err_num = get_last_socket_error(); | |
739 | if ((bind_mode == BIO_BIND_REUSEADDR_IF_UNUSED) && | |
740 | # ifdef OPENSSL_SYS_WINDOWS | |
741 | /* | |
742 | * Some versions of Windows define EADDRINUSE to a dummy value. | |
743 | */ | |
744 | (err_num == WSAEADDRINUSE)) | |
745 | # else | |
746 | (err_num == EADDRINUSE)) | |
747 | # endif | |
748 | { | |
749 | client = server; | |
750 | if (h == NULL || strcmp(h, "*") == 0) { | |
751 | # if OPENSSL_USE_IPV6 | |
752 | if (client.sa.sa_family == AF_INET6) { | |
753 | memset(&client.sa_in6.sin6_addr, 0, | |
754 | sizeof(client.sa_in6.sin6_addr)); | |
755 | client.sa_in6.sin6_addr.s6_addr[15] = 1; | |
756 | } else | |
757 | # endif | |
758 | if (client.sa.sa_family == AF_INET) { | |
759 | client.sa_in.sin_addr.s_addr = htonl(0x7F000001); | |
760 | } else | |
761 | goto err; | |
762 | } | |
763 | cs = socket(client.sa.sa_family, SOCK_STREAM, SOCKET_PROTOCOL); | |
764 | if (cs != INVALID_SOCKET) { | |
765 | int ii; | |
766 | ii = connect(cs, &client.sa, addrlen); | |
767 | closesocket(cs); | |
768 | if (ii == INVALID_SOCKET) { | |
769 | bind_mode = BIO_BIND_REUSEADDR; | |
770 | closesocket(s); | |
771 | goto again; | |
772 | } | |
773 | /* else error */ | |
774 | } | |
775 | /* else error */ | |
776 | } | |
777 | # endif | |
778 | SYSerr(SYS_F_BIND, err_num); | |
779 | ERR_add_error_data(3, "port='", host, "'"); | |
780 | BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_BIND_SOCKET); | |
781 | goto err; | |
782 | } | |
783 | if (listen(s, MAX_LISTEN) == -1) { | |
784 | SYSerr(SYS_F_BIND, get_last_socket_error()); | |
785 | ERR_add_error_data(3, "port='", host, "'"); | |
786 | BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET, BIO_R_UNABLE_TO_LISTEN_SOCKET); | |
787 | goto err; | |
788 | } | |
789 | ret = 1; | |
790 | err: | |
791 | if (str != NULL) | |
792 | OPENSSL_free(str); | |
793 | if ((ret == 0) && (s != INVALID_SOCKET)) { | |
794 | closesocket(s); | |
795 | s = INVALID_SOCKET; | |
796 | } | |
797 | return (s); | |
798 | } | |
d02b48c6 | 799 | |
6b691a5c | 800 | int BIO_accept(int sock, char **addr) |
0f113f3e MC |
801 | { |
802 | int ret = INVALID_SOCKET; | |
803 | unsigned long l; | |
804 | unsigned short port; | |
805 | char *p; | |
806 | ||
807 | struct { | |
808 | /* | |
809 | * As for following union. Trouble is that there are platforms | |
810 | * that have socklen_t and there are platforms that don't, on | |
811 | * some platforms socklen_t is int and on some size_t. So what | |
812 | * one can do? One can cook #ifdef spaghetti, which is nothing | |
813 | * but masochistic. Or one can do union between int and size_t. | |
814 | * One naturally does it primarily for 64-bit platforms where | |
815 | * sizeof(int) != sizeof(size_t). But would it work? Note that | |
816 | * if size_t member is initialized to 0, then later int member | |
817 | * assignment naturally does the job on little-endian platforms | |
818 | * regardless accept's expectations! What about big-endians? | |
819 | * If accept expects int*, then it works, and if size_t*, then | |
820 | * length value would appear as unreasonably large. But this | |
821 | * won't prevent it from filling in the address structure. The | |
822 | * trouble of course would be if accept returns more data than | |
823 | * actual buffer can accomodate and overwrite stack... That's | |
824 | * where early OPENSSL_assert comes into picture. Besides, the | |
825 | * only 64-bit big-endian platform found so far that expects | |
826 | * size_t* is HP-UX, where stack grows towards higher address. | |
827 | * <appro> | |
828 | */ | |
829 | union { | |
830 | size_t s; | |
831 | int i; | |
832 | } len; | |
833 | union { | |
834 | struct sockaddr sa; | |
835 | struct sockaddr_in sa_in; | |
836 | # if OPENSSL_USE_IPV6 | |
837 | struct sockaddr_in6 sa_in6; | |
838 | # endif | |
839 | } from; | |
840 | } sa; | |
841 | ||
842 | sa.len.s = 0; | |
843 | sa.len.i = sizeof(sa.from); | |
844 | memset(&sa.from, 0, sizeof(sa.from)); | |
845 | ret = accept(sock, &sa.from.sa, (void *)&sa.len); | |
846 | if (sizeof(sa.len.i) != sizeof(sa.len.s) && sa.len.i == 0) { | |
847 | OPENSSL_assert(sa.len.s <= sizeof(sa.from)); | |
848 | sa.len.i = (int)sa.len.s; | |
849 | /* use sa.len.i from this point */ | |
850 | } | |
851 | if (ret == INVALID_SOCKET) { | |
852 | if (BIO_sock_should_retry(ret)) | |
853 | return -2; | |
854 | SYSerr(SYS_F_ACCEPT, get_last_socket_error()); | |
855 | BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); | |
856 | goto end; | |
857 | } | |
858 | ||
859 | if (addr == NULL) | |
860 | goto end; | |
861 | ||
862 | # ifdef EAI_FAMILY | |
863 | do { | |
864 | char h[NI_MAXHOST], s[NI_MAXSERV]; | |
865 | size_t nl; | |
866 | static union { | |
867 | void *p; | |
868 | int (WSAAPI *f) (const struct sockaddr *, size_t /* socklen_t */ , | |
869 | char *, size_t, char *, size_t, int); | |
870 | } p_getnameinfo = { | |
871 | NULL | |
872 | }; | |
873 | /* | |
874 | * 2nd argument to getnameinfo is specified to be socklen_t. | |
875 | * Unfortunately there is a number of environments where socklen_t is | |
876 | * not defined. As it's passed by value, it's safe to pass it as | |
877 | * size_t... <appro> | |
878 | */ | |
879 | ||
880 | if (p_getnameinfo.p == NULL) { | |
881 | if ((p_getnameinfo.p = DSO_global_lookup("getnameinfo")) == NULL) | |
882 | p_getnameinfo.p = (void *)-1; | |
883 | } | |
884 | if (p_getnameinfo.p == (void *)-1) | |
885 | break; | |
886 | ||
887 | if ((*p_getnameinfo.f) (&sa.from.sa, sa.len.i, h, sizeof(h), s, | |
888 | sizeof(s), NI_NUMERICHOST | NI_NUMERICSERV)) | |
889 | break; | |
890 | nl = strlen(h) + strlen(s) + 2; | |
891 | p = *addr; | |
892 | if (p) { | |
893 | *p = '\0'; | |
894 | p = OPENSSL_realloc(p, nl); | |
895 | } else { | |
896 | p = OPENSSL_malloc(nl); | |
897 | } | |
898 | if (p == NULL) { | |
899 | BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); | |
900 | goto end; | |
901 | } | |
902 | *addr = p; | |
903 | BIO_snprintf(*addr, nl, "%s:%s", h, s); | |
904 | goto end; | |
905 | } while (0); | |
906 | # endif | |
907 | if (sa.from.sa.sa_family != AF_INET) | |
908 | goto end; | |
909 | l = ntohl(sa.from.sa_in.sin_addr.s_addr); | |
910 | port = ntohs(sa.from.sa_in.sin_port); | |
911 | if (*addr == NULL) { | |
912 | if ((p = OPENSSL_malloc(24)) == NULL) { | |
913 | BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); | |
914 | goto end; | |
915 | } | |
916 | *addr = p; | |
917 | } | |
918 | BIO_snprintf(*addr, 24, "%d.%d.%d.%d:%d", | |
919 | (unsigned char)(l >> 24L) & 0xff, | |
920 | (unsigned char)(l >> 16L) & 0xff, | |
921 | (unsigned char)(l >> 8L) & 0xff, | |
922 | (unsigned char)(l) & 0xff, port); | |
923 | end: | |
924 | return (ret); | |
925 | } | |
d02b48c6 | 926 | |
6b691a5c | 927 | int BIO_set_tcp_ndelay(int s, int on) |
0f113f3e MC |
928 | { |
929 | int ret = 0; | |
930 | # if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP)) | |
931 | int opt; | |
d02b48c6 | 932 | |
0f113f3e MC |
933 | # ifdef SOL_TCP |
934 | opt = SOL_TCP; | |
935 | # else | |
936 | # ifdef IPPROTO_TCP | |
937 | opt = IPPROTO_TCP; | |
938 | # endif | |
939 | # endif | |
dfeab068 | 940 | |
0f113f3e MC |
941 | ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on)); |
942 | # endif | |
943 | return (ret == 0); | |
944 | } | |
945 | ||
946 | int BIO_socket_nbio(int s, int mode) | |
947 | { | |
948 | int ret = -1; | |
949 | int l; | |
950 | ||
951 | l = mode; | |
952 | # ifdef FIONBIO | |
953 | ret = BIO_socket_ioctl(s, FIONBIO, &l); | |
954 | # endif | |
955 | return (ret == 0); | |
956 | } | |
4a1fbd13 | 957 | #endif |