xref: /openbsd-src/lib/libcrypto/bio/b_sock.c (revision 5b37fcf34e412bf0b6ad32ddb294e900d64c5855)
1 /* crypto/bio/b_sock.c */
2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
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.
8  *
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).
15  *
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.
22  *
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 :-).
37  * 4. If you include any Windows specific code (or a derivative thereof) from
38  *    the apps directory (application code) you must include an acknowledgement:
39  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40  *
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.
52  *
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 
59 #ifndef NO_SOCK
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <errno.h>
64 #define USE_SOCKETS
65 #include "cryptlib.h"
66 #include "bio.h"
67 
68 /*	BIOerr(BIO_F_WSASTARTUP,BIO_R_WSASTARTUP ); */
69 
70 #ifdef WIN16
71 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
72 #else
73 #define SOCKET_PROTOCOL IPPROTO_TCP
74 #endif
75 
76 #ifdef SO_MAXCONN
77 #define MAX_LISTEN  SOMAXCONN
78 #elif defined(SO_MAXCONN)
79 #define MAX_LISTEN  SO_MAXCONN
80 #else
81 #define MAX_LISTEN  32
82 #endif
83 
84 #ifdef WINDOWS
85 static int wsa_init_done=0;
86 #endif
87 
88 static unsigned long BIO_ghbn_hits=0L;
89 static unsigned long BIO_ghbn_miss=0L;
90 
91 #define GHBN_NUM	4
92 static struct ghbn_cache_st
93 	{
94 	char name[129];
95 	struct hostent *ent;
96 	unsigned long order;
97 	} ghbn_cache[GHBN_NUM];
98 
99 #ifndef NOPROTO
100 static int get_ip(char *str,unsigned char *ip);
101 static void ghbn_free(struct hostent *a);
102 static struct hostent *ghbn_dup(struct hostent *a);
103 #else
104 static int get_ip();
105 static void ghbn_free();
106 static struct hostent *ghbn_dup();
107 #endif
108 
109 int BIO_get_host_ip(str,ip)
110 char *str;
111 unsigned char *ip;
112 	{
113 	int i;
114 	struct hostent *he;
115 
116 	i=get_ip(str,ip);
117 	if (i > 0) return(1);
118 	if (i < 0)
119 		{
120 		BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_INVALID_IP_ADDRESS);
121 		ERR_add_error_data(2,"host=",str);
122 		return(0);
123 		}
124 	else
125 		{ /* do a gethostbyname */
126 		if (!BIO_sock_init()) return(0);
127 
128 		he=BIO_gethostbyname(str);
129 		if (he == NULL)
130 			{
131 			BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_BAD_HOSTNAME_LOOKUP);
132 			ERR_add_error_data(2,"host=",str);
133 			return(0);
134 			}
135 
136 		/* cast to short because of win16 winsock definition */
137 		if ((short)he->h_addrtype != AF_INET)
138 			{
139 			BIOerr(BIO_F_BIO_GET_HOST_IP,BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET);
140 			ERR_add_error_data(2,"host=",str);
141 			return(0);
142 			}
143 		for (i=0; i<4; i++)
144 			ip[i]=he->h_addr_list[0][i];
145 		}
146 	return(1);
147 	}
148 
149 int BIO_get_port(str,port_ptr)
150 char *str;
151 short *port_ptr;
152 	{
153 	int i;
154 	struct servent *s;
155 
156 	if (str == NULL)
157 		{
158 		BIOerr(BIO_F_BIO_GET_PORT,BIO_R_NO_PORT_DEFINED);
159 		return(0);
160 		}
161 	i=atoi(str);
162 	if (i != 0)
163 		*port_ptr=(unsigned short)i;
164 	else
165 		{
166 		s=getservbyname(str,"tcp");
167 		if (s == NULL)
168 			{
169 			if (strcmp(str,"http") == 0)
170 				*port_ptr=80;
171 			else if (strcmp(str,"telnet") == 0)
172 				*port_ptr=23;
173 			else if (strcmp(str,"socks") == 0)
174 				*port_ptr=1080;
175 			else if (strcmp(str,"https") == 0)
176 				*port_ptr=443;
177 			else if (strcmp(str,"ssl") == 0)
178 				*port_ptr=443;
179 			else if (strcmp(str,"ftp") == 0)
180 				*port_ptr=21;
181 			else if (strcmp(str,"gopher") == 0)
182 				*port_ptr=70;
183 #if 0
184 			else if (strcmp(str,"wais") == 0)
185 				*port_ptr=21;
186 #endif
187 			else
188 				{
189 				SYSerr(SYS_F_GETSERVBYNAME,get_last_socket_error());
190 				ERR_add_error_data(3,"service='",str,"'");
191 				return(0);
192 				}
193 			return(1);
194 			}
195 		*port_ptr=htons((unsigned short)s->s_port);
196 		}
197 	return(1);
198 	}
199 
200 int BIO_sock_error(sock)
201 int sock;
202 	{
203 	int j,i,size;
204 
205 	size=sizeof(int);
206 
207 	i=getsockopt(sock,SOL_SOCKET,SO_ERROR,(char *)&j,&size);
208 	if (i < 0)
209 		return(1);
210 	else
211 		return(j);
212 	}
213 
214 long BIO_ghbn_ctrl(cmd,iarg,parg)
215 int cmd;
216 int iarg;
217 char *parg;
218 	{
219 	int i;
220 	char **p;
221 
222 	switch (cmd)
223 		{
224 	case BIO_GHBN_CTRL_HITS:
225 		return(BIO_ghbn_hits);
226 		break;
227 	case BIO_GHBN_CTRL_MISSES:
228 		return(BIO_ghbn_miss);
229 		break;
230 	case BIO_GHBN_CTRL_CACHE_SIZE:
231 		return(GHBN_NUM);
232 		break;
233 	case BIO_GHBN_CTRL_GET_ENTRY:
234 		if ((iarg >= 0) && (iarg <GHBN_NUM) &&
235 			(ghbn_cache[iarg].order > 0))
236 			{
237 			p=(char **)parg;
238 			if (p == NULL) return(0);
239 			*p=ghbn_cache[iarg].name;
240 			ghbn_cache[iarg].name[128]='\0';
241 			return(1);
242 			}
243 		return(0);
244 		break;
245 	case BIO_GHBN_CTRL_FLUSH:
246 		for (i=0; i<GHBN_NUM; i++)
247 			ghbn_cache[i].order=0;
248 		break;
249 	default:
250 		return(0);
251 		}
252 	return(1);
253 	}
254 
255 static struct hostent *ghbn_dup(a)
256 struct hostent *a;
257 	{
258 	struct hostent *ret;
259 	int i,j;
260 
261 	ret=(struct hostent *)malloc(sizeof(struct hostent));
262 	if (ret == NULL) return(NULL);
263 	memset(ret,0,sizeof(struct hostent));
264 
265 	for (i=0; a->h_aliases[i] != NULL; i++)
266 		;
267 	i++;
268 	ret->h_aliases=(char **)malloc(sizeof(char *)*i);
269 	memset(ret->h_aliases,0,sizeof(char *)*i);
270 	if (ret == NULL) goto err;
271 
272 	for (i=0; a->h_addr_list[i] != NULL; i++)
273 		;
274 	i++;
275 	ret->h_addr_list=(char **)malloc(sizeof(char *)*i);
276 	memset(ret->h_addr_list,0,sizeof(char *)*i);
277 	if (ret->h_addr_list == NULL) goto err;
278 
279 	j=strlen(a->h_name)+1;
280 	if ((ret->h_name=malloc(j)) == NULL) goto err;
281 	memcpy((char *)ret->h_name,a->h_name,j);
282 	for (i=0; a->h_aliases[i] != NULL; i++)
283 		{
284 		j=strlen(a->h_aliases[i])+1;
285 		if ((ret->h_aliases[i]=malloc(j)) == NULL) goto err;
286 		memcpy(ret->h_aliases[i],a->h_aliases[i],j);
287 		}
288 	ret->h_length=a->h_length;
289 	ret->h_addrtype=a->h_addrtype;
290 	for (i=0; a->h_addr_list[i] != NULL; i++)
291 		{
292 		if ((ret->h_addr_list[i]=malloc(a->h_length)) == NULL)
293 			goto err;
294 		memcpy(ret->h_addr_list[i],a->h_addr_list[i],a->h_length);
295 		}
296 	return(ret);
297 err:
298 	if (ret != NULL)
299 		ghbn_free(ret);
300 	return(NULL);
301 	}
302 
303 static void ghbn_free(a)
304 struct hostent *a;
305 	{
306 	int i;
307 
308 	if (a->h_aliases != NULL)
309 		{
310 		for (i=0; a->h_aliases[i] != NULL; i++)
311 			free(a->h_aliases[i]);
312 		free(a->h_aliases);
313 		}
314 	if (a->h_addr_list != NULL)
315 		{
316 		for (i=0; a->h_addr_list[i] != NULL; i++)
317 			free(a->h_addr_list[i]);
318 		free(a->h_addr_list);
319 		}
320 	if (a->h_name != NULL) free((char *)a->h_name);
321 	free(a);
322 	}
323 
324 struct hostent *BIO_gethostbyname(name)
325 char *name;
326 	{
327 	struct hostent *ret;
328 	int i,lowi=0,j;
329 	unsigned long low= (unsigned long)-1;
330 
331 /*	return(gethostbyname(name)); */
332 
333 	CRYPTO_w_lock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
334 	j=strlen(name);
335 	if (j < 128)
336 		{
337 		for (i=0; i<GHBN_NUM; i++)
338 			{
339 			if (low > ghbn_cache[i].order)
340 				{
341 				low=ghbn_cache[i].order;
342 				lowi=i;
343 				}
344 			if (ghbn_cache[i].order > 0)
345 				{
346 				if (strncmp(name,ghbn_cache[i].name,128) == 0)
347 					break;
348 				}
349 			}
350 		}
351 	else
352 		i=GHBN_NUM;
353 
354 	if (i == GHBN_NUM) /* no hit*/
355 		{
356 		BIO_ghbn_miss++;
357 		ret=gethostbyname(name);
358 
359 		if (ret == NULL) return(NULL);
360 		if (j > 128) return(ret); /* too big to cache */
361 
362 		/* else add to cache */
363 		if (ghbn_cache[lowi].ent != NULL)
364 			ghbn_free(ghbn_cache[lowi].ent);
365 
366 		strncpy(ghbn_cache[lowi].name,name,128);
367 		ghbn_cache[lowi].ent=ghbn_dup(ret);
368 		ghbn_cache[lowi].order=BIO_ghbn_miss+BIO_ghbn_hits;
369 		}
370 	else
371 		{
372 		BIO_ghbn_hits++;
373 		ret= ghbn_cache[i].ent;
374 		ghbn_cache[i].order=BIO_ghbn_miss+BIO_ghbn_hits;
375 		}
376 	CRYPTO_w_unlock(CRYPTO_LOCK_BIO_GETHOSTBYNAME);
377 	return(ret);
378 	}
379 
380 int BIO_sock_init()
381 	{
382 #ifdef WINDOWS
383 	static struct WSAData wsa_state;
384 
385 	if (!wsa_init_done)
386 		{
387 		int err;
388 
389 #ifdef SIGINT
390 		signal(SIGINT,(void (*)(int))BIO_sock_cleanup);
391 #endif
392 		wsa_init_done=1;
393 		memset(&wsa_state,0,sizeof(wsa_state));
394 		if (WSAStartup(0x0101,&wsa_state)!=0)
395 			{
396 			err=WSAGetLastError();
397 			SYSerr(SYS_F_WSASTARTUP,err);
398 			BIOerr(BIO_F_BIO_SOCK_INIT,BIO_R_WSASTARTUP);
399 			return(-1);
400 			}
401 		}
402 #endif /* WINDOWS */
403 	return(1);
404 	}
405 
406 void BIO_sock_cleanup()
407 	{
408 #ifdef WINDOWS
409 	if (wsa_init_done)
410 		{
411 		wsa_init_done=0;
412 		WSACancelBlockingCall();
413 		WSACleanup();
414 		}
415 #endif
416 	}
417 
418 int BIO_socket_ioctl(fd,type,arg)
419 int fd;
420 long type;
421 unsigned long *arg;
422 	{
423 	int i;
424 
425 	i=ioctlsocket(fd,type,arg);
426 	if (i < 0)
427 		SYSerr(SYS_F_IOCTLSOCKET,get_last_socket_error());
428 	return(i);
429 	}
430 
431 /* The reason I have implemented this instead of using sscanf is because
432  * Visual C 1.52c gives an unresolved external when linking a DLL :-( */
433 static int get_ip(str,ip)
434 char *str;
435 unsigned char ip[4];
436 	{
437 	unsigned int tmp[4];
438 	int num=0,c,ok=0;
439 
440 	tmp[0]=tmp[1]=tmp[2]=tmp[3]=0;
441 
442 	for (;;)
443 		{
444 		c= *(str++);
445 		if ((c >= '0') && (c <= '9'))
446 			{
447 			ok=1;
448 			tmp[num]=tmp[num]*10+c-'0';
449 			if (tmp[num] > 255) return(-1);
450 			}
451 		else if (c == '.')
452 			{
453 			if (!ok) return(-1);
454 			if (num == 3) break;
455 			num++;
456 			ok=0;
457 			}
458 		else if ((num == 3) && ok)
459 			break;
460 		else
461 			return(0);
462 		}
463 	ip[0]=tmp[0];
464 	ip[1]=tmp[1];
465 	ip[2]=tmp[2];
466 	ip[3]=tmp[3];
467 	return(1);
468 	}
469 
470 int BIO_get_accept_socket(host)
471 char *host;
472 	{
473 	int ret=0;
474 	struct sockaddr_in server;
475 	int s= -1;
476 	unsigned char ip[4];
477 	short port;
478 	char *str,*h,*p,*e;
479 	unsigned long l;
480 
481 	if (!BIO_sock_init()) return(INVALID_SOCKET);
482 
483 	if ((str=BUF_strdup(host)) == NULL) return(INVALID_SOCKET);
484 
485 	h=p=NULL;
486 	h=str;
487 	for (e=str; *e; e++)
488 		{
489 		if (*e == ':')
490 			{
491 			p= &(e[1]);
492 			*e='\0';
493 			}
494 		else if (*e == '/')
495 			{
496 			*e='\0';
497 			break;
498 			}
499 		}
500 
501 	if (p == NULL)
502 		{
503 		p=h;
504 		h="*";
505 		}
506 
507 	if (!BIO_get_port(p,&port)) return(INVALID_SOCKET);
508 
509 	memset((char *)&server,0,sizeof(server));
510 	server.sin_family=AF_INET;
511 	server.sin_port=htons((unsigned short)port);
512 
513 	if (strcmp(h,"*") == 0)
514 		server.sin_addr.s_addr=INADDR_ANY;
515 	else
516 		{
517 		if (!BIO_get_host_ip(h,&(ip[0]))) return(INVALID_SOCKET);
518 		l=(unsigned long)
519 			((unsigned long)ip[0]<<24L)|
520 			((unsigned long)ip[0]<<16L)|
521 			((unsigned long)ip[0]<< 8L)|
522 			((unsigned long)ip[0]);
523 		server.sin_addr.s_addr=htonl(l);
524 		}
525 
526 	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
527 	if (s == INVALID_SOCKET)
528 		{
529 		SYSerr(SYS_F_SOCKET,get_last_socket_error());
530 		ERR_add_error_data(3,"port='",host,"'");
531 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_CREATE_SOCKET);
532 		goto err;
533 		}
534 	if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
535 		{
536 		SYSerr(SYS_F_BIND,get_last_socket_error());
537 		ERR_add_error_data(3,"port='",host,"'");
538 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_BIND_SOCKET);
539 		goto err;
540 		}
541 	if (listen(s,MAX_LISTEN) == -1)
542 		{
543 		SYSerr(SYS_F_BIND,get_last_socket_error());
544 		ERR_add_error_data(3,"port='",host,"'");
545 		BIOerr(BIO_F_BIO_GET_ACCEPT_SOCKET,BIO_R_UNABLE_TO_LISTEN_SOCKET);
546 		goto err;
547 		}
548 	ret=1;
549 err:
550 	if (str != NULL) Free(str);
551 	if ((ret == 0) && (s != INVALID_SOCKET))
552 		{
553 #ifdef WINDOWS
554 		closesocket(s);
555 #else
556 		close(s);
557 #endif
558 		s= INVALID_SOCKET;
559 		}
560 	return(s);
561 	}
562 
563 int BIO_accept(sock,addr)
564 int sock;
565 char **addr;
566 	{
567 	int ret=INVALID_SOCKET;
568 	static struct sockaddr_in from;
569 	unsigned long l;
570 	short port;
571 	int len;
572 	char *p;
573 
574 	memset((char *)&from,0,sizeof(from));
575 	len=sizeof(from);
576 	ret=accept(sock,(struct sockaddr *)&from,&len);
577 	if (ret == INVALID_SOCKET)
578 		{
579 		SYSerr(SYS_F_ACCEPT,get_last_socket_error());
580 		BIOerr(BIO_F_BIO_ACCEPT,BIO_R_ACCEPT_ERROR);
581 		goto end;
582 		}
583 
584 	if (addr == NULL) goto end;
585 
586 	l=ntohl(from.sin_addr.s_addr);
587 	port=ntohs(from.sin_port);
588 	if (*addr == NULL)
589 		{
590 		if ((p=Malloc(24)) == NULL)
591 			{
592 			BIOerr(BIO_F_BIO_ACCEPT,ERR_R_MALLOC_FAILURE);
593 			goto end;
594 			}
595 		*addr=p;
596 		}
597 	sprintf(*addr,"%d.%d.%d.%d:%d",
598 		(unsigned char)(l>>24L)&0xff,
599 		(unsigned char)(l>>16L)&0xff,
600 		(unsigned char)(l>> 8L)&0xff,
601 		(unsigned char)(l     )&0xff,
602 		port);
603 end:
604 	return(ret);
605 	}
606 
607 int BIO_set_tcp_ndelay(s,on)
608 int s;
609 int on;
610 	{
611 	int ret=0;
612 #if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP))
613 	int opt;
614 
615 #ifdef SOL_TCP
616 	opt=SOL_TCP;
617 #else
618 #ifdef IPPROTO_TCP
619 	opt=IPPROTO_TCP;
620 #endif
621 #endif
622 
623 	ret=setsockopt(s,opt,TCP_NODELAY,(char *)&on,sizeof(on));
624 #endif
625 	return(ret == 0);
626 	}
627 #endif
628 
629