OpenSSL  1.0.1c
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
s_socket.c
Go to the documentation of this file.
1 /* apps/s_socket.c - socket-related functions used by s_client and s_server */
2 /* Copyright (C) 1995-1998 Eric Young ([email protected])
3  * All rights reserved.
4  *
5  * This package is an SSL implementation written
6  * by Eric Young ([email protected]).
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 ([email protected]).
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 ([email protected])"
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 ([email protected])"
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 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <errno.h>
63 #include <signal.h>
64 
65 #ifdef FLAT_INC
66 #include "e_os2.h"
67 #else
68 #include "../e_os2.h"
69 #endif
70 
71 /* With IPv6, it looks like Digital has mixed up the proper order of
72  recursive header file inclusion, resulting in the compiler complaining
73  that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which
74  is needed to have fileno() declared correctly... So let's define u_int */
75 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
76 #define __U_INT
77 typedef unsigned int u_int;
78 #endif
79 
80 #define USE_SOCKETS
81 #define NON_MAIN
82 #include "apps.h"
83 #undef USE_SOCKETS
84 #undef NON_MAIN
85 #include "s_apps.h"
86 #include <openssl/ssl.h>
87 
88 #ifdef FLAT_INC
89 #include "e_os.h"
90 #else
91 #include "../e_os.h"
92 #endif
93 
94 #ifndef OPENSSL_NO_SOCK
95 
96 #if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
97 #include "netdb.h"
98 #endif
99 
100 static struct hostent *GetHostByName(char *name);
101 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
102 static void ssl_sock_cleanup(void);
103 #endif
104 static int ssl_sock_init(void);
105 static int init_client_ip(int *sock,unsigned char ip[4], int port, int type);
106 static int init_server(int *sock, int port, int type);
107 static int init_server_long(int *sock, int port,char *ip, int type);
108 static int do_accept(int acc_sock, int *sock, char **host);
109 static int host_ip(char *str, unsigned char ip[4]);
110 
111 #ifdef OPENSSL_SYS_WIN16
112 #define SOCKET_PROTOCOL 0 /* more microsoft stupidity */
113 #else
114 #define SOCKET_PROTOCOL IPPROTO_TCP
115 #endif
116 
117 #if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
118 static int wsa_init_done=0;
119 #endif
120 
121 #ifdef OPENSSL_SYS_WINDOWS
122 static struct WSAData wsa_state;
123 static int wsa_init_done=0;
124 
125 #ifdef OPENSSL_SYS_WIN16
126 static HWND topWnd=0;
127 static FARPROC lpTopWndProc=NULL;
128 static FARPROC lpTopHookProc=NULL;
129 extern HINSTANCE _hInstance; /* nice global CRT provides */
130 
131 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
132  LPARAM lParam)
133  {
134  if (hwnd == topWnd)
135  {
136  switch(message)
137  {
138  case WM_DESTROY:
139  case WM_CLOSE:
140  SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopWndProc);
141  ssl_sock_cleanup();
142  break;
143  }
144  }
145  return CallWindowProc(lpTopWndProc,hwnd,message,wParam,lParam);
146  }
147 
148 static BOOL CALLBACK enumproc(HWND hwnd,LPARAM lParam)
149  {
150  topWnd=hwnd;
151  return(FALSE);
152  }
153 
154 #endif /* OPENSSL_SYS_WIN32 */
155 #endif /* OPENSSL_SYS_WINDOWS */
156 
157 #ifdef OPENSSL_SYS_WINDOWS
158 static void ssl_sock_cleanup(void)
159  {
160  if (wsa_init_done)
161  {
162  wsa_init_done=0;
163 #ifndef OPENSSL_SYS_WINCE
164  WSACancelBlockingCall();
165 #endif
166  WSACleanup();
167  }
168  }
169 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
170 static void sock_cleanup(void)
171  {
172  if (wsa_init_done)
173  {
174  wsa_init_done=0;
175  WSACleanup();
176  }
177  }
178 #endif
179 
180 static int ssl_sock_init(void)
181  {
182 #ifdef WATT32
183  extern int _watt_do_exit;
184  _watt_do_exit = 0;
185  if (sock_init())
186  return (0);
187 #elif defined(OPENSSL_SYS_WINDOWS)
188  if (!wsa_init_done)
189  {
190  int err;
191 
192 #ifdef SIGINT
193  signal(SIGINT,(void (*)(int))ssl_sock_cleanup);
194 #endif
195  wsa_init_done=1;
196  memset(&wsa_state,0,sizeof(wsa_state));
197  if (WSAStartup(0x0101,&wsa_state)!=0)
198  {
199  err=WSAGetLastError();
200  BIO_printf(bio_err,"unable to start WINSOCK, error code=%d\n",err);
201  return(0);
202  }
203 
204 #ifdef OPENSSL_SYS_WIN16
205  EnumTaskWindows(GetCurrentTask(),enumproc,0L);
206  lpTopWndProc=(FARPROC)GetWindowLong(topWnd,GWL_WNDPROC);
207  lpTopHookProc=MakeProcInstance((FARPROC)topHookProc,_hInstance);
208 
209  SetWindowLong(topWnd,GWL_WNDPROC,(LONG)lpTopHookProc);
210 #endif /* OPENSSL_SYS_WIN16 */
211  }
212 #elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
213  WORD wVerReq;
214  WSADATA wsaData;
215  int err;
216 
217  if (!wsa_init_done)
218  {
219 
220 # ifdef SIGINT
221  signal(SIGINT,(void (*)(int))sock_cleanup);
222 # endif
223 
224  wsa_init_done=1;
225  wVerReq = MAKEWORD( 2, 0 );
226  err = WSAStartup(wVerReq,&wsaData);
227  if (err != 0)
228  {
229  BIO_printf(bio_err,"unable to start WINSOCK2, error code=%d\n",err);
230  return(0);
231  }
232  }
233 #endif /* OPENSSL_SYS_WINDOWS */
234  return(1);
235  }
236 
237 int init_client(int *sock, char *host, int port, int type)
238  {
239  unsigned char ip[4];
240 
241  memset(ip, '\0', sizeof ip);
242  if (!host_ip(host,&(ip[0])))
243  return 0;
244  return init_client_ip(sock,ip,port,type);
245  }
246 
247 static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
248  {
249  unsigned long addr;
250  struct sockaddr_in them;
251  int s,i;
252 
253  if (!ssl_sock_init()) return(0);
254 
255  memset((char *)&them,0,sizeof(them));
256  them.sin_family=AF_INET;
257  them.sin_port=htons((unsigned short)port);
258  addr=(unsigned long)
259  ((unsigned long)ip[0]<<24L)|
260  ((unsigned long)ip[1]<<16L)|
261  ((unsigned long)ip[2]<< 8L)|
262  ((unsigned long)ip[3]);
263  them.sin_addr.s_addr=htonl(addr);
264 
265  if (type == SOCK_STREAM)
266  s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
267  else /* ( type == SOCK_DGRAM) */
268  s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
269 
270  if (s == INVALID_SOCKET) { perror("socket"); return(0); }
271 
272 #if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
273  if (type == SOCK_STREAM)
274  {
275  i=0;
276  i=setsockopt(s,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
277  if (i < 0) { perror("keepalive"); return(0); }
278  }
279 #endif
280 
281  if (connect(s,(struct sockaddr *)&them,sizeof(them)) == -1)
282  { closesocket(s); perror("connect"); return(0); }
283  *sock=s;
284  return(1);
285  }
286 
287 int do_server(int port, int type, int *ret, int (*cb)(char *hostname, int s, unsigned char *context), unsigned char *context)
288  {
289  int sock;
290  char *name = NULL;
291  int accept_socket = 0;
292  int i;
293 
294  if (!init_server(&accept_socket,port,type)) return(0);
295 
296  if (ret != NULL)
297  {
298  *ret=accept_socket;
299  /* return(1);*/
300  }
301  for (;;)
302  {
303  if (type==SOCK_STREAM)
304  {
305  if (do_accept(accept_socket,&sock,&name) == 0)
306  {
307  SHUTDOWN(accept_socket);
308  return(0);
309  }
310  }
311  else
312  sock = accept_socket;
313  i=(*cb)(name,sock, context);
314  if (name != NULL) OPENSSL_free(name);
315  if (type==SOCK_STREAM)
316  SHUTDOWN2(sock);
317  if (i < 0)
318  {
319  SHUTDOWN2(accept_socket);
320  return(i);
321  }
322  }
323  }
324 
325 static int init_server_long(int *sock, int port, char *ip, int type)
326  {
327  int ret=0;
328  struct sockaddr_in server;
329  int s= -1;
330 
331  if (!ssl_sock_init()) return(0);
332 
333  memset((char *)&server,0,sizeof(server));
334  server.sin_family=AF_INET;
335  server.sin_port=htons((unsigned short)port);
336  if (ip == NULL)
337  server.sin_addr.s_addr=INADDR_ANY;
338  else
339 /* Added for T3E, address-of fails on bit field ([email protected]) */
340 #ifndef BIT_FIELD_LIMITS
341  memcpy(&server.sin_addr.s_addr,ip,4);
342 #else
343  memcpy(&server.sin_addr,ip,4);
344 #endif
345 
346  if (type == SOCK_STREAM)
347  s=socket(AF_INET,SOCK_STREAM,SOCKET_PROTOCOL);
348  else /* type == SOCK_DGRAM */
349  s=socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP);
350 
351  if (s == INVALID_SOCKET) goto err;
352 #if defined SOL_SOCKET && defined SO_REUSEADDR
353  {
354  int j = 1;
355  setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
356  (void *) &j, sizeof j);
357  }
358 #endif
359  if (bind(s,(struct sockaddr *)&server,sizeof(server)) == -1)
360  {
361 #ifndef OPENSSL_SYS_WINDOWS
362  perror("bind");
363 #endif
364  goto err;
365  }
366  /* Make it 128 for linux */
367  if (type==SOCK_STREAM && listen(s,128) == -1) goto err;
368  *sock=s;
369  ret=1;
370 err:
371  if ((ret == 0) && (s != -1))
372  {
373  SHUTDOWN(s);
374  }
375  return(ret);
376  }
377 
378 static int init_server(int *sock, int port, int type)
379  {
380  return(init_server_long(sock, port, NULL, type));
381  }
382 
383 static int do_accept(int acc_sock, int *sock, char **host)
384  {
385  int ret;
386  struct hostent *h1,*h2;
387  static struct sockaddr_in from;
388  int len;
389 /* struct linger ling; */
390 
391  if (!ssl_sock_init()) return(0);
392 
393 #ifndef OPENSSL_SYS_WINDOWS
394 redoit:
395 #endif
396 
397  memset((char *)&from,0,sizeof(from));
398  len=sizeof(from);
399  /* Note: under VMS with SOCKETSHR the fourth parameter is currently
400  * of type (int *) whereas under other systems it is (void *) if
401  * you don't have a cast it will choke the compiler: if you do
402  * have a cast then you can either go for (int *) or (void *).
403  */
404  ret=accept(acc_sock,(struct sockaddr *)&from,(void *)&len);
405  if (ret == INVALID_SOCKET)
406  {
407 #if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
408  int i;
409  i=WSAGetLastError();
410  BIO_printf(bio_err,"accept error %d\n",i);
411 #else
412  if (errno == EINTR)
413  {
414  /*check_timeout(); */
415  goto redoit;
416  }
417  fprintf(stderr,"errno=%d ",errno);
418  perror("accept");
419 #endif
420  return(0);
421  }
422 
423 /*
424  ling.l_onoff=1;
425  ling.l_linger=0;
426  i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
427  if (i < 0) { perror("linger"); return(0); }
428  i=0;
429  i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
430  if (i < 0) { perror("keepalive"); return(0); }
431 */
432 
433  if (host == NULL) goto end;
434 #ifndef BIT_FIELD_LIMITS
435  /* I should use WSAAsyncGetHostByName() under windows */
436  h1=gethostbyaddr((char *)&from.sin_addr.s_addr,
437  sizeof(from.sin_addr.s_addr),AF_INET);
438 #else
439  h1=gethostbyaddr((char *)&from.sin_addr,
440  sizeof(struct in_addr),AF_INET);
441 #endif
442  if (h1 == NULL)
443  {
444  BIO_printf(bio_err,"bad gethostbyaddr\n");
445  *host=NULL;
446  /* return(0); */
447  }
448  else
449  {
450  if ((*host=(char *)OPENSSL_malloc(strlen(h1->h_name)+1)) == NULL)
451  {
452  perror("OPENSSL_malloc");
453  return(0);
454  }
455  BUF_strlcpy(*host,h1->h_name,strlen(h1->h_name)+1);
456 
457  h2=GetHostByName(*host);
458  if (h2 == NULL)
459  {
460  BIO_printf(bio_err,"gethostbyname failure\n");
461  return(0);
462  }
463  if (h2->h_addrtype != AF_INET)
464  {
465  BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
466  return(0);
467  }
468  }
469 end:
470  *sock=ret;
471  return(1);
472  }
473 
474 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
475  short *port_ptr)
476  {
477  char *h,*p;
478 
479  h=str;
480  p=strchr(str,':');
481  if (p == NULL)
482  {
483  BIO_printf(bio_err,"no port defined\n");
484  return(0);
485  }
486  *(p++)='\0';
487 
488  if ((ip != NULL) && !host_ip(str,ip))
489  goto err;
490  if (host_ptr != NULL) *host_ptr=h;
491 
492  if (!extract_port(p,port_ptr))
493  goto err;
494  return(1);
495 err:
496  return(0);
497  }
498 
499 static int host_ip(char *str, unsigned char ip[4])
500  {
501  unsigned int in[4];
502  int i;
503 
504  if (sscanf(str,"%u.%u.%u.%u",&(in[0]),&(in[1]),&(in[2]),&(in[3])) == 4)
505  {
506  for (i=0; i<4; i++)
507  if (in[i] > 255)
508  {
509  BIO_printf(bio_err,"invalid IP address\n");
510  goto err;
511  }
512  ip[0]=in[0];
513  ip[1]=in[1];
514  ip[2]=in[2];
515  ip[3]=in[3];
516  }
517  else
518  { /* do a gethostbyname */
519  struct hostent *he;
520 
521  if (!ssl_sock_init()) return(0);
522 
523  he=GetHostByName(str);
524  if (he == NULL)
525  {
526  BIO_printf(bio_err,"gethostbyname failure\n");
527  goto err;
528  }
529  /* cast to short because of win16 winsock definition */
530  if ((short)he->h_addrtype != AF_INET)
531  {
532  BIO_printf(bio_err,"gethostbyname addr is not AF_INET\n");
533  return(0);
534  }
535  ip[0]=he->h_addr_list[0][0];
536  ip[1]=he->h_addr_list[0][1];
537  ip[2]=he->h_addr_list[0][2];
538  ip[3]=he->h_addr_list[0][3];
539  }
540  return(1);
541 err:
542  return(0);
543  }
544 
545 int extract_port(char *str, short *port_ptr)
546  {
547  int i;
548  struct servent *s;
549 
550  i=atoi(str);
551  if (i != 0)
552  *port_ptr=(unsigned short)i;
553  else
554  {
555  s=getservbyname(str,"tcp");
556  if (s == NULL)
557  {
558  BIO_printf(bio_err,"getservbyname failure for %s\n",str);
559  return(0);
560  }
561  *port_ptr=ntohs((unsigned short)s->s_port);
562  }
563  return(1);
564  }
565 
566 #define GHBN_NUM 4
567 static struct ghbn_cache_st
568  {
569  char name[128];
570  struct hostent ent;
571  unsigned long order;
572  } ghbn_cache[GHBN_NUM];
573 
574 static unsigned long ghbn_hits=0L;
575 static unsigned long ghbn_miss=0L;
576 
577 static struct hostent *GetHostByName(char *name)
578  {
579  struct hostent *ret;
580  int i,lowi=0;
581  unsigned long low= (unsigned long)-1;
582 
583  for (i=0; i<GHBN_NUM; i++)
584  {
585  if (low > ghbn_cache[i].order)
586  {
587  low=ghbn_cache[i].order;
588  lowi=i;
589  }
590  if (ghbn_cache[i].order > 0)
591  {
592  if (strncmp(name,ghbn_cache[i].name,128) == 0)
593  break;
594  }
595  }
596  if (i == GHBN_NUM) /* no hit*/
597  {
598  ghbn_miss++;
599  ret=gethostbyname(name);
600  if (ret == NULL) return(NULL);
601  /* else add to cache */
602  if(strlen(name) < sizeof ghbn_cache[0].name)
603  {
604  strcpy(ghbn_cache[lowi].name,name);
605  memcpy((char *)&(ghbn_cache[lowi].ent),ret,sizeof(struct hostent));
606  ghbn_cache[lowi].order=ghbn_miss+ghbn_hits;
607  }
608  return(ret);
609  }
610  else
611  {
612  ghbn_hits++;
613  ret= &(ghbn_cache[i].ent);
614  ghbn_cache[i].order=ghbn_miss+ghbn_hits;
615  return(ret);
616  }
617  }
618 
619 #endif