s_socket.c revision 127128
11590Srgrimes/* apps/s_socket.c -  socket-related functions used by s_client and s_server */
21590Srgrimes/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
31590Srgrimes * All rights reserved.
41590Srgrimes *
51590Srgrimes * This package is an SSL implementation written
61590Srgrimes * by Eric Young (eay@cryptsoft.com).
71590Srgrimes * The implementation was written so as to conform with Netscapes SSL.
81590Srgrimes *
91590Srgrimes * This library is free for commercial and non-commercial use as long as
101590Srgrimes * the following conditions are aheared to.  The following conditions
111590Srgrimes * apply to all code found in this distribution, be it the RC4, RSA,
121590Srgrimes * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
131590Srgrimes * included with this distribution is covered by the same copyright terms
141590Srgrimes * except that the holder is Tim Hudson (tjh@cryptsoft.com).
151590Srgrimes *
161590Srgrimes * Copyright remains Eric Young's, and as such any Copyright notices in
171590Srgrimes * the code are not to be removed.
181590Srgrimes * If this package is used in a product, Eric Young should be given attribution
191590Srgrimes * as the author of the parts of the library used.
201590Srgrimes * This can be in the form of a textual message at program startup or
211590Srgrimes * in documentation (online or textual) provided with the package.
221590Srgrimes *
231590Srgrimes * Redistribution and use in source and binary forms, with or without
241590Srgrimes * modification, are permitted provided that the following conditions
251590Srgrimes * are met:
261590Srgrimes * 1. Redistributions of source code must retain the copyright
271590Srgrimes *    notice, this list of conditions and the following disclaimer.
281590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
291590Srgrimes *    notice, this list of conditions and the following disclaimer in the
3087710Smarkm *    documentation and/or other materials provided with the distribution.
311590Srgrimes * 3. All advertising materials mentioning features or use of this software
321590Srgrimes *    must display the following acknowledgement:
3314443Sjoerg *    "This product includes cryptographic software written by
3414443Sjoerg *     Eric Young (eay@cryptsoft.com)"
3514443Sjoerg *    The word 'cryptographic' can be left out if the rouines from the library
3614443Sjoerg *    being used are not cryptographic related :-).
3714443Sjoerg * 4. If you include any Windows specific code (or a derivative thereof) from
3814443Sjoerg *    the apps directory (application code) you must include an acknowledgement:
3914443Sjoerg *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
401590Srgrimes *
41227185Sed * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
421590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
431590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
441590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
451590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
461590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4787710Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
481590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
491590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50227185Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51227185Sed * SUCH DAMAGE.
521590Srgrimes *
531590Srgrimes * The licence and distribution terms for any publically available version or
541590Srgrimes * derivative of this code cannot be changed.  i.e. this code cannot simply be
551590Srgrimes * copied and put under another distribution licence
561590Srgrimes * [including the GNU Public Licence.]
571590Srgrimes */
581590Srgrimes
591590Srgrimes#include <stdio.h>
601590Srgrimes#include <stdlib.h>
611590Srgrimes#include <string.h>
621590Srgrimes#include <errno.h>
631590Srgrimes#include <signal.h>
641590Srgrimes
651590Srgrimes#include <openssl/e_os2.h>
6614443Sjoerg
6792922Simp/* With IPv6, it looks like Digital has mixed up the proper order of
6892922Simp   recursive header file inclusion, resulting in the compiler complaining
6992922Simp   that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
7092922Simp   is needed to have fileno() declared correctly...  So let's define u_int */
7192922Simp#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
7292922Simp#define __U_INT
7392922Simptypedef unsigned int u_int;
74178642Sdelphij#endif
7592922Simp
7692922Simp#define USE_SOCKETS
7792922Simp#define NON_MAIN
7892922Simp#include "apps.h"
7992922Simp#undef USE_SOCKETS
8092922Simp#undef NON_MAIN
8192922Simp#include "s_apps.h"
8292922Simp#include <openssl/ssl.h>
8392922Simp
8492922Simpstatic struct hostent *GetHostByName(char *name);
8592922Simp#ifdef OPENSSL_SYS_WINDOWS
8692922Simpstatic void ssl_sock_cleanup(void);
8792922Simp#endif
8892922Simpstatic int ssl_sock_init(void);
8992922Simpstatic int init_client_ip(int *sock,unsigned char ip[4], int port);
9092922Simpstatic int init_server(int *sock, int port);
9192922Simpstatic int init_server_long(int *sock, int port,char *ip);
92128445Scognetstatic int do_accept(int acc_sock, int *sock, char **host);
9392922Simpstatic int host_ip(char *str, unsigned char ip[4]);
9492922Simp
95128445Scognet#ifdef OPENSSL_SYS_WIN16
96#define SOCKET_PROTOCOL	0 /* more microsoft stupidity */
97#else
98#define SOCKET_PROTOCOL	IPPROTO_TCP
99#endif
100
101#ifdef OPENSSL_SYS_WINDOWS
102static struct WSAData wsa_state;
103static int wsa_init_done=0;
104
105#ifdef OPENSSL_SYS_WIN16
106static HWND topWnd=0;
107static FARPROC lpTopWndProc=NULL;
108static FARPROC lpTopHookProc=NULL;
109extern HINSTANCE _hInstance;  /* nice global CRT provides */
110
111static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
112	     LPARAM lParam)
113	{
114	if (hwnd == topWnd)
115		{
116		switch(message)
117			{
118		case WM_DESTROY:
119		case WM_CLOSE:
120			SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
121			ssl_sock_cleanup();
122			break;
123			}
124		}
125	return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
126	}
127
128static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
129	{
130	topWnd=hwnd;
131	return(FALSE);
132	}
133
134#endif /* OPENSSL_SYS_WIN32 */
135#endif /* OPENSSL_SYS_WINDOWS */
136
137#ifdef OPENSSL_SYS_WINDOWS
138static void ssl_sock_cleanup(void)
139	{
140	if (wsa_init_done)
141		{
142		wsa_init_done=0;
143#ifndef OPENSSL_SYS_WINCE
144		WSACancelBlockingCall();
145#endif
146		WSACleanup();
147		}
148	}
149#endif
150
151static int ssl_sock_init(void)
152	{
153#ifdef WATT32
154	extern int _watt_do_exit;
155	_watt_do_exit = 0;
156	dbug_init();
157	if (sock_init())
158		return (0);
159#elif defined(OPENSSL_SYS_WINDOWS)
160	if (!wsa_init_done)
161		{
162		int err;
163
164#ifdef SIGINT
165		signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
166#endif
167		wsa_init_done=1;
168		memset(&wsa_state,0,sizeof(wsa_state));
169		if (WSAStartup(0x0101,&wsa_state)!=0)
170			{
171			err=WSAGetLastError();
172			BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
173			return(0);
174			}
175
176#ifdef OPENSSL_SYS_WIN16
177		EnumTaskWindows(GetCurrentTask(),enumproc,0L);
178		lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
179		lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
180
181		SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
182#endif /* OPENSSL_SYS_WIN16 */
183		}
184#endif /* OPENSSL_SYS_WINDOWS */
185	return(1);
186	}
187
188int init_client(int *sock, char *host, int port)
189	{
190	unsigned char ip[4];
191	short p=0;
192
193	if (!host_ip(host,&(ip[0])))
194		{
195		return(0);
196		}
197	if (p != 0) port=p;
198	return(init_client_ip(sock,ip,port));
199	}
200
201static int init_client_ip(int *sock, unsigned char ip[4], int port)
202	{
203	unsigned long addr;
204	struct sockaddr_in them;
205	int s,i;
206
207	if (!ssl_sock_init()) return(0);
208
209	memset((char *)&them,0,sizeof(them));
210	them.sin_family=AF_INET;
211	them.sin_port=htons((unsigned short)port);
212	addr=(unsigned long)
213		((unsigned long)ip[0]<<24L)|
214		((unsigned long)ip[1]<<16L)|
215		((unsigned long)ip[2]<< 8L)|
216		((unsigned long)ip[3]);
217	them.sin_addr.s_addr=htonl(addr);
218
219	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
220	if (s == INVALID_SOCKET) { perror("socket"); return(0); }
221
222#ifndef OPENSSL_SYS_MPE
223	i=0;
224	i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
225	if (i < 0) { perror("keepalive"); return(0); }
226#endif
227
228	if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
229		{ close(s); perror("connect"); return(0); }
230	*sock=s;
231	return(1);
232	}
233
234int do_server(int port, int *ret, int (*cb)(), char *context)
235	{
236	int sock;
237	char *name;
238	int accept_socket;
239	int i;
240
241	if (!init_server(&accept_socket,port)) return(0);
242
243	if (ret != NULL)
244		{
245		*ret=accept_socket;
246		/* return(1);*/
247		}
248	for (;;)
249		{
250		if (do_accept(accept_socket,&sock,&name) == 0)
251			{
252			SHUTDOWN(accept_socket);
253			return(0);
254			}
255		i=(*cb)(name,sock, context);
256		if (name != NULL) OPENSSL_free(name);
257		SHUTDOWN2(sock);
258		if (i < 0)
259			{
260			SHUTDOWN2(accept_socket);
261			return(i);
262			}
263		}
264	}
265
266static int init_server_long(int *sock, int port, char *ip)
267	{
268	int ret=0;
269	struct sockaddr_in server;
270	int s= -1,i;
271
272	if (!ssl_sock_init()) return(0);
273
274	memset((char *)&server,0,sizeof(server));
275	server.sin_family=AF_INET;
276	server.sin_port=htons((unsigned short)port);
277	if (ip == NULL)
278		server.sin_addr.s_addr=INADDR_ANY;
279	else
280/* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
281#ifndef BIT_FIELD_LIMITS
282		memcpy(&server.sin_addr.s_addr,ip,4);
283#else
284		memcpy(&server.sin_addr,ip,4);
285#endif
286	s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
287
288	if (s == INVALID_SOCKET) goto err;
289#if defined SOL_SOCKET && defined SO_REUSEADDR
290		{
291		int j = 1;
292		setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
293			   (void *) &j, sizeof j);
294		}
295#endif
296	if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
297		{
298#ifndef OPENSSL_SYS_WINDOWS
299		perror("bind");
300#endif
301		goto err;
302		}
303	/* Make it 128 for linux */
304	if (listen(s,128) == -1) goto err;
305	i=0;
306	*sock=s;
307	ret=1;
308err:
309	if ((ret == 0) && (s != -1))
310		{
311		SHUTDOWN(s);
312		}
313	return(ret);
314	}
315
316static int init_server(int *sock, int port)
317	{
318	return(init_server_long(sock, port, NULL));
319	}
320
321static int do_accept(int acc_sock, int *sock, char **host)
322	{
323	int ret,i;
324	struct hostent *h1,*h2;
325	static struct sockaddr_in from;
326	int len;
327/*	struct linger ling; */
328
329	if (!ssl_sock_init()) return(0);
330
331#ifndef OPENSSL_SYS_WINDOWS
332redoit:
333#endif
334
335	memset((char *)&from,0,sizeof(from));
336	len=sizeof(from);
337	/* Note: under VMS with SOCKETSHR the fourth parameter is currently
338	 * of type (int *) whereas under other systems it is (void *) if
339	 * you don't have a cast it will choke the compiler: if you do
340	 * have a cast then you can either go for (int *) or (void *).
341	 */
342	ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
343	if (ret == INVALID_SOCKET)
344		{
345#ifdef OPENSSL_SYS_WINDOWS
346		i=WSAGetLastError();
347		BIO_printf(bio_err,"accept error %d\n",i);
348#else
349		if (errno == EINTR)
350			{
351			/*check_timeout(); */
352			goto redoit;
353			}
354		fprintf(stderr,"errno=%d ",errno);
355		perror("accept");
356#endif
357		return(0);
358		}
359
360/*
361	ling.l_onoff=1;
362	ling.l_linger=0;
363	i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
364	if (i < 0) { perror("linger"); return(0); }
365	i=0;
366	i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
367	if (i < 0) { perror("keepalive"); return(0); }
368*/
369
370	if (host == NULL) goto end;
371#ifndef BIT_FIELD_LIMITS
372	/* I should use WSAAsyncGetHostByName() under windows */
373	h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
374		sizeof(from.sin_addr.s_addr),AF_INET);
375#else
376	h1=gethostbyaddr((char *)&from.sin_addr,
377		sizeof(struct in_addr),AF_INET);
378#endif
379	if (h1 == NULL)
380		{
381		BIO_printf(bio_err,"bad gethostbyaddr\n");
382		*host=NULL;
383		/* return(0); */
384		}
385	else
386		{
387		if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
388			{
389			perror("OPENSSL_malloc");
390			return(0);
391			}
392		BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
393
394		h2=GetHostByName(*host);
395		if (h2 == NULL)
396			{
397			BIO_printf(bio_err,"gethostbyname failure\n");
398			return(0);
399			}
400		i=0;
401		if (h2->h_addrtype != AF_INET)
402			{
403			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
404			return(0);
405			}
406		}
407end:
408	*sock=ret;
409	return(1);
410	}
411
412int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
413	     short *port_ptr)
414	{
415	char *h,*p;
416
417	h=str;
418	p=strchr(str,':');
419	if (p == NULL)
420		{
421		BIO_printf(bio_err,"no port defined\n");
422		return(0);
423		}
424	*(p++)='\0';
425
426	if ((ip != NULL) && !host_ip(str,ip))
427		goto err;
428	if (host_ptr != NULL) *host_ptr=h;
429
430	if (!extract_port(p,port_ptr))
431		goto err;
432	return(1);
433err:
434	return(0);
435	}
436
437static int host_ip(char *str, unsigned char ip[4])
438	{
439	unsigned int in[4];
440	int i;
441
442	if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
443		{
444		for (i=0; i<4; i++)
445			if (in[i] > 255)
446				{
447				BIO_printf(bio_err,"invalid IP address\n");
448				goto err;
449				}
450		ip[0]=in[0];
451		ip[1]=in[1];
452		ip[2]=in[2];
453		ip[3]=in[3];
454		}
455	else
456		{ /* do a gethostbyname */
457		struct hostent *he;
458
459		if (!ssl_sock_init()) return(0);
460
461		he=GetHostByName(str);
462		if (he == NULL)
463			{
464			BIO_printf(bio_err,"gethostbyname failure\n");
465			goto err;
466			}
467		/* cast to short because of win16 winsock definition */
468		if ((short)he->h_addrtype != AF_INET)
469			{
470			BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
471			return(0);
472			}
473		ip[0]=he->h_addr_list[0][0];
474		ip[1]=he->h_addr_list[0][1];
475		ip[2]=he->h_addr_list[0][2];
476		ip[3]=he->h_addr_list[0][3];
477		}
478	return(1);
479err:
480	return(0);
481	}
482
483int extract_port(char *str, short *port_ptr)
484	{
485	int i;
486	struct servent *s;
487
488	i=atoi(str);
489	if (i != 0)
490		*port_ptr=(unsigned short)i;
491	else
492		{
493		s=getservbyname(str,"tcp");
494		if (s == NULL)
495			{
496			BIO_printf(bio_err,"getservbyname failure for %s\n",str);
497			return(0);
498			}
499		*port_ptr=ntohs((unsigned short)s->s_port);
500		}
501	return(1);
502	}
503
504#define GHBN_NUM	4
505static struct ghbn_cache_st
506	{
507	char name[128];
508	struct hostent ent;
509	unsigned long order;
510	} ghbn_cache[GHBN_NUM];
511
512static unsigned long ghbn_hits=0L;
513static unsigned long ghbn_miss=0L;
514
515static struct hostent *GetHostByName(char *name)
516	{
517	struct hostent *ret;
518	int i,lowi=0;
519	unsigned long low= (unsigned long)-1;
520
521	for (i=0; i<GHBN_NUM; i++)
522		{
523		if (low > ghbn_cache[i].order)
524			{
525			low=ghbn_cache[i].order;
526			lowi=i;
527			}
528		if (ghbn_cache[i].order > 0)
529			{
530			if (strncmp(name,ghbn_cache[i].name,128) == 0)
531				break;
532			}
533		}
534	if (i == GHBN_NUM) /* no hit*/
535		{
536		ghbn_miss++;
537		ret=gethostbyname(name);
538		if (ret == NULL) return(NULL);
539		/* else add to cache */
540		if(strlen(name) < sizeof ghbn_cache[0].name)
541			{
542			strcpy(ghbn_cache[lowi].name,name);
543			memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
544			ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
545			}
546		return(ret);
547		}
548	else
549		{
550		ghbn_hits++;
551		ret= &(ghbn_cache[i].ent);
552		ghbn_cache[i].order=ghbn_miss+ghbn_hits;
553		return(ret);
554		}
555	}
556