1 /*
2  * apps/s_socket.c - socket-related functions used by s_client and s_server
3  */
4 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
5  * All rights reserved.
6  *
7  * This package is an SSL implementation written
8  * by Eric Young (eay@cryptsoft.com).
9  * The implementation was written so as to conform with Netscapes SSL.
10  *
11  * This library is free for commercial and non-commercial use as long as
12  * the following conditions are aheared to.  The following conditions
13  * apply to all code found in this distribution, be it the RC4, RSA,
14  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
15  * included with this distribution is covered by the same copyright terms
16  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
17  *
18  * Copyright remains Eric Young's, and as such any Copyright notices in
19  * the code are not to be removed.
20  * If this package is used in a product, Eric Young should be given attribution
21  * as the author of the parts of the library used.
22  * This can be in the form of a textual message at program startup or
23  * in documentation (online or textual) provided with the package.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  * 3. All advertising materials mentioning features or use of this software
34  *    must display the following acknowledgement:
35  *    "This product includes cryptographic software written by
36  *     Eric Young (eay@cryptsoft.com)"
37  *    The word 'cryptographic' can be left out if the rouines from the library
38  *    being used are not cryptographic related :-).
39  * 4. If you include any Windows specific code (or a derivative thereof) from
40  *    the apps directory (application code) you must include an acknowledgement:
41  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
42  *
43  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
44  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53  * SUCH DAMAGE.
54  *
55  * The licence and distribution terms for any publically available version or
56  * derivative of this code cannot be changed.  i.e. this code cannot simply be
57  * copied and put under another distribution licence
58  * [including the GNU Public Licence.]
59  */
60 
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <errno.h>
65 #include <signal.h>
66 
67 #ifdef FLAT_INC
68 # include "e_os2.h"
69 #else
70 # include "../e_os2.h"
71 #endif
72 
73 /*
74  * With IPv6, it looks like Digital has mixed up the proper order of
75  * recursive header file inclusion, resulting in the compiler complaining
76  * that u_int isn't defined, but only if _POSIX_C_SOURCE is defined, which is
77  * needed to have fileno() declared correctly...  So let's define u_int
78  */
79 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__U_INT)
80 # define __U_INT
81 typedef unsigned int u_int;
82 #endif
83 
84 #define USE_SOCKETS
85 #define NON_MAIN
86 #include "apps.h"
87 #undef USE_SOCKETS
88 #undef NON_MAIN
89 #include "s_apps.h"
90 #include <openssl/ssl.h>
91 
92 #ifdef FLAT_INC
93 # include "e_os.h"
94 #else
95 # include "../e_os.h"
96 #endif
97 
98 #ifndef OPENSSL_NO_SOCK
99 
100 # if defined(OPENSSL_SYS_NETWARE) && defined(NETWARE_BSDSOCK)
101 #  include "netdb.h"
102 # endif
103 
104 static struct hostent *GetHostByName(char *name);
105 # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
106 static void ssl_sock_cleanup(void);
107 # endif
108 static int ssl_sock_init(void);
109 static int init_client_ip(int *sock, unsigned char ip[4], int port, int type);
110 static int init_server(int *sock, int port, int type);
111 static int init_server_long(int *sock, int port, char *ip, int type);
112 static int do_accept(int acc_sock, int *sock, char **host);
113 static int host_ip(char *str, unsigned char ip[4]);
114 
115 # ifdef OPENSSL_SYS_WIN16
116 #  define SOCKET_PROTOCOL 0     /* more microsoft stupidity */
117 # else
118 #  define SOCKET_PROTOCOL IPPROTO_TCP
119 # endif
120 
121 # if defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
122 static int wsa_init_done = 0;
123 # endif
124 
125 # ifdef OPENSSL_SYS_WINDOWS
126 static struct WSAData wsa_state;
127 static int wsa_init_done = 0;
128 
129 #  ifdef OPENSSL_SYS_WIN16
130 static HWND topWnd = 0;
131 static FARPROC lpTopWndProc = NULL;
132 static FARPROC lpTopHookProc = NULL;
133 extern HINSTANCE _hInstance;    /* nice global CRT provides */
134 
topHookProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)135 static LONG FAR PASCAL topHookProc(HWND hwnd, UINT message, WPARAM wParam,
136                                    LPARAM lParam)
137 {
138     if (hwnd == topWnd) {
139         switch (message) {
140         case WM_DESTROY:
141         case WM_CLOSE:
142             SetWindowLong(topWnd, GWL_WNDPROC, (LONG) lpTopWndProc);
143             ssl_sock_cleanup();
144             break;
145         }
146     }
147     return CallWindowProc(lpTopWndProc, hwnd, message, wParam, lParam);
148 }
149 
enumproc(HWND hwnd,LPARAM lParam)150 static BOOL CALLBACK enumproc(HWND hwnd, LPARAM lParam)
151 {
152     topWnd = hwnd;
153     return (FALSE);
154 }
155 
156 #  endif                        /* OPENSSL_SYS_WIN32 */
157 # endif                         /* OPENSSL_SYS_WINDOWS */
158 
159 # ifdef OPENSSL_SYS_WINDOWS
ssl_sock_cleanup(void)160 static void ssl_sock_cleanup(void)
161 {
162     if (wsa_init_done) {
163         wsa_init_done = 0;
164 #  ifndef OPENSSL_SYS_WINCE
165         WSACancelBlockingCall();
166 #  endif
167         WSACleanup();
168     }
169 }
170 # elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
sock_cleanup(void)171 static void sock_cleanup(void)
172 {
173     if (wsa_init_done) {
174         wsa_init_done = 0;
175         WSACleanup();
176     }
177 }
178 # endif
179 
ssl_sock_init(void)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         int err;
190 
191 #  ifdef SIGINT
192         signal(SIGINT, (void (*)(int))ssl_sock_cleanup);
193 #  endif
194         wsa_init_done = 1;
195         memset(&wsa_state, 0, sizeof(wsa_state));
196         if (WSAStartup(0x0101, &wsa_state) != 0) {
197             err = WSAGetLastError();
198             BIO_printf(bio_err, "unable to start WINSOCK, error code=%d\n",
199                        err);
200             return (0);
201         }
202 #  ifdef OPENSSL_SYS_WIN16
203         EnumTaskWindows(GetCurrentTask(), enumproc, 0L);
204         lpTopWndProc = (FARPROC) GetWindowLong(topWnd, GWL_WNDPROC);
205         lpTopHookProc = MakeProcInstance((FARPROC) topHookProc, _hInstance);
206 
207         SetWindowLong(topWnd, GWL_WNDPROC, (LONG) lpTopHookProc);
208 #  endif                        /* OPENSSL_SYS_WIN16 */
209     }
210 # elif defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK)
211     WORD wVerReq;
212     WSADATA wsaData;
213     int err;
214 
215     if (!wsa_init_done) {
216 
217 #  ifdef SIGINT
218         signal(SIGINT, (void (*)(int))sock_cleanup);
219 #  endif
220 
221         wsa_init_done = 1;
222         wVerReq = MAKEWORD(2, 0);
223         err = WSAStartup(wVerReq, &wsaData);
224         if (err != 0) {
225             BIO_printf(bio_err, "unable to start WINSOCK2, error code=%d\n",
226                        err);
227             return (0);
228         }
229     }
230 # endif                         /* OPENSSL_SYS_WINDOWS */
231     return (1);
232 }
233 
init_client(int * sock,char * host,int port,int type)234 int init_client(int *sock, char *host, int port, int type)
235 {
236     unsigned char ip[4];
237 
238     memset(ip, '\0', sizeof ip);
239     if (!host_ip(host, &(ip[0])))
240         return 0;
241     return init_client_ip(sock, ip, port, type);
242 }
243 
init_client_ip(int * sock,unsigned char ip[4],int port,int type)244 static int init_client_ip(int *sock, unsigned char ip[4], int port, int type)
245 {
246     unsigned long addr;
247     struct sockaddr_in them;
248     int s, i;
249 
250     if (!ssl_sock_init())
251         return (0);
252 
253     memset((char *)&them, 0, sizeof(them));
254     them.sin_family = AF_INET;
255     them.sin_port = htons((unsigned short)port);
256     addr = (unsigned long)
257         ((unsigned long)ip[0] << 24L) |
258         ((unsigned long)ip[1] << 16L) |
259         ((unsigned long)ip[2] << 8L) | ((unsigned long)ip[3]);
260     them.sin_addr.s_addr = htonl(addr);
261 
262     if (type == SOCK_STREAM)
263         s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
264     else                        /* ( type == SOCK_DGRAM) */
265         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
266 
267     if (s == INVALID_SOCKET) {
268         perror("socket");
269         return (0);
270     }
271 # if defined(SO_KEEPALIVE) && !defined(OPENSSL_SYS_MPE)
272     if (type == SOCK_STREAM) {
273         i = 0;
274         i = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, sizeof(i));
275         if (i < 0) {
276             closesocket(s);
277             perror("keepalive");
278             return (0);
279         }
280     }
281 # endif
282 
283     if (connect(s, (struct sockaddr *)&them, sizeof(them)) == -1) {
284         closesocket(s);
285         perror("connect");
286         return (0);
287     }
288     *sock = s;
289     return (1);
290 }
291 
do_server(int port,int type,int * ret,int (* cb)(char * hostname,int s,unsigned char * context),unsigned char * context)292 int do_server(int port, int type, int *ret,
293               int (*cb) (char *hostname, int s, unsigned char *context),
294               unsigned char *context)
295 {
296     int sock;
297     char *name = NULL;
298     int accept_socket = 0;
299     int i;
300 
301     if (!init_server(&accept_socket, port, type))
302         return (0);
303 
304     if (ret != NULL) {
305         *ret = accept_socket;
306         /* return(1); */
307     }
308     for (;;) {
309         if (type == SOCK_STREAM) {
310             if (do_accept(accept_socket, &sock, &name) == 0) {
311                 SHUTDOWN(accept_socket);
312                 return (0);
313             }
314         } else
315             sock = accept_socket;
316         i = (*cb) (name, sock, context);
317         if (name != NULL)
318             OPENSSL_free(name);
319         if (type == SOCK_STREAM)
320             SHUTDOWN2(sock);
321         if (i < 0) {
322             SHUTDOWN2(accept_socket);
323             return (i);
324         }
325     }
326 }
327 
init_server_long(int * sock,int port,char * ip,int type)328 static int init_server_long(int *sock, int port, char *ip, int type)
329 {
330     int ret = 0;
331     struct sockaddr_in server;
332     int s = -1;
333 
334     if (!ssl_sock_init())
335         return (0);
336 
337     memset((char *)&server, 0, sizeof(server));
338     server.sin_family = AF_INET;
339     server.sin_port = htons((unsigned short)port);
340     if (ip == NULL)
341         server.sin_addr.s_addr = INADDR_ANY;
342     else
343 /* Added for T3E, address-of fails on bit field (beckman@acl.lanl.gov) */
344 # ifndef BIT_FIELD_LIMITS
345         memcpy(&server.sin_addr.s_addr, ip, 4);
346 # else
347         memcpy(&server.sin_addr, ip, 4);
348 # endif
349 
350     if (type == SOCK_STREAM)
351         s = socket(AF_INET, SOCK_STREAM, SOCKET_PROTOCOL);
352     else                        /* type == SOCK_DGRAM */
353         s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
354 
355     if (s == INVALID_SOCKET)
356         goto err;
357 # if defined SOL_SOCKET && defined SO_REUSEADDR
358     {
359         int j = 1;
360         setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&j, sizeof j);
361     }
362 # endif
363     if (bind(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
364 # ifndef OPENSSL_SYS_WINDOWS
365         perror("bind");
366 # endif
367         goto err;
368     }
369     /* Make it 128 for linux */
370     if (type == SOCK_STREAM && listen(s, 128) == -1)
371         goto err;
372     *sock = s;
373     ret = 1;
374  err:
375     if ((ret == 0) && (s != -1)) {
376         SHUTDOWN(s);
377     }
378     return (ret);
379 }
380 
init_server(int * sock,int port,int type)381 static int init_server(int *sock, int port, int type)
382 {
383     return (init_server_long(sock, port, NULL, type));
384 }
385 
do_accept(int acc_sock,int * sock,char ** host)386 static int do_accept(int acc_sock, int *sock, char **host)
387 {
388     int ret;
389     struct hostent *h1, *h2;
390     static struct sockaddr_in from;
391     int len;
392 /*      struct linger ling; */
393 
394     if (!ssl_sock_init())
395         return (0);
396 
397 # ifndef OPENSSL_SYS_WINDOWS
398  redoit:
399 # endif
400 
401     memset((char *)&from, 0, sizeof(from));
402     len = sizeof(from);
403     /*
404      * Note: under VMS with SOCKETSHR the fourth parameter is currently of
405      * type (int *) whereas under other systems it is (void *) if you don't
406      * have a cast it will choke the compiler: if you do have a cast then you
407      * can either go for (int *) or (void *).
408      */
409     ret = accept(acc_sock, (struct sockaddr *)&from, (void *)&len);
410     if (ret == INVALID_SOCKET) {
411 # if defined(OPENSSL_SYS_WINDOWS) || (defined(OPENSSL_SYS_NETWARE) && !defined(NETWARE_BSDSOCK))
412         int i;
413         i = WSAGetLastError();
414         BIO_printf(bio_err, "accept error %d\n", i);
415 # else
416         if (errno == EINTR) {
417             /*
418              * check_timeout();
419              */
420             goto redoit;
421         }
422         fprintf(stderr, "errno=%d ", errno);
423         perror("accept");
424 # endif
425         return (0);
426     }
427 
428 /*-
429     ling.l_onoff=1;
430     ling.l_linger=0;
431     i=setsockopt(ret,SOL_SOCKET,SO_LINGER,(char *)&ling,sizeof(ling));
432     if (i < 0) { perror("linger"); return(0); }
433     i=0;
434     i=setsockopt(ret,SOL_SOCKET,SO_KEEPALIVE,(char *)&i,sizeof(i));
435     if (i < 0) { perror("keepalive"); return(0); }
436 */
437 
438     if (host == NULL)
439         goto end;
440 # ifndef BIT_FIELD_LIMITS
441     /* I should use WSAAsyncGetHostByName() under windows */
442     h1 = gethostbyaddr((char *)&from.sin_addr.s_addr,
443                        sizeof(from.sin_addr.s_addr), AF_INET);
444 # else
445     h1 = gethostbyaddr((char *)&from.sin_addr,
446                        sizeof(struct in_addr), AF_INET);
447 # endif
448     if (h1 == NULL) {
449         BIO_printf(bio_err, "bad gethostbyaddr\n");
450         *host = NULL;
451         /* return(0); */
452     } else {
453         if ((*host = (char *)OPENSSL_malloc(strlen(h1->h_name) + 1)) == NULL) {
454             perror("OPENSSL_malloc");
455             closesocket(ret);
456             return (0);
457         }
458         BUF_strlcpy(*host, h1->h_name, strlen(h1->h_name) + 1);
459 
460         h2 = GetHostByName(*host);
461         if (h2 == NULL) {
462             BIO_printf(bio_err, "gethostbyname failure\n");
463             closesocket(ret);
464             return (0);
465         }
466         if (h2->h_addrtype != AF_INET) {
467             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
468             closesocket(ret);
469             return (0);
470         }
471     }
472  end:
473     *sock = ret;
474     return (1);
475 }
476 
extract_host_port(char * str,char ** host_ptr,unsigned char * ip,short * port_ptr)477 int extract_host_port(char *str, char **host_ptr, unsigned char *ip,
478                       short *port_ptr)
479 {
480     char *h, *p;
481 
482     h = str;
483     p = strchr(str, ':');
484     if (p == NULL) {
485         BIO_printf(bio_err, "no port defined\n");
486         return (0);
487     }
488     *(p++) = '\0';
489 
490     if ((ip != NULL) && !host_ip(str, ip))
491         goto err;
492     if (host_ptr != NULL)
493         *host_ptr = h;
494 
495     if (!extract_port(p, port_ptr))
496         goto err;
497     return (1);
498  err:
499     return (0);
500 }
501 
host_ip(char * str,unsigned char ip[4])502 static int host_ip(char *str, unsigned char ip[4])
503 {
504     unsigned int in[4];
505     int i;
506 
507     if (sscanf(str, "%u.%u.%u.%u", &(in[0]), &(in[1]), &(in[2]), &(in[3])) ==
508         4) {
509         for (i = 0; i < 4; i++)
510             if (in[i] > 255) {
511                 BIO_printf(bio_err, "invalid IP address\n");
512                 goto err;
513             }
514         ip[0] = in[0];
515         ip[1] = in[1];
516         ip[2] = in[2];
517         ip[3] = in[3];
518     } else {                    /* do a gethostbyname */
519         struct hostent *he;
520 
521         if (!ssl_sock_init())
522             return (0);
523 
524         he = GetHostByName(str);
525         if (he == NULL) {
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             BIO_printf(bio_err, "gethostbyname addr is not AF_INET\n");
532             return (0);
533         }
534         ip[0] = he->h_addr_list[0][0];
535         ip[1] = he->h_addr_list[0][1];
536         ip[2] = he->h_addr_list[0][2];
537         ip[3] = he->h_addr_list[0][3];
538     }
539     return (1);
540  err:
541     return (0);
542 }
543 
extract_port(char * str,short * port_ptr)544 int extract_port(char *str, short *port_ptr)
545 {
546     int i;
547     struct servent *s;
548 
549     i = atoi(str);
550     if (i != 0)
551         *port_ptr = (unsigned short)i;
552     else {
553         s = getservbyname(str, "tcp");
554         if (s == NULL) {
555             BIO_printf(bio_err, "getservbyname failure for %s\n", str);
556             return (0);
557         }
558         *port_ptr = ntohs((unsigned short)s->s_port);
559     }
560     return (1);
561 }
562 
563 # define GHBN_NUM        4
564 static struct ghbn_cache_st {
565     char name[128];
566     struct hostent ent;
567     unsigned long order;
568 } ghbn_cache[GHBN_NUM];
569 
570 static unsigned long ghbn_hits = 0L;
571 static unsigned long ghbn_miss = 0L;
572 
GetHostByName(char * name)573 static struct hostent *GetHostByName(char *name)
574 {
575     struct hostent *ret;
576     int i, lowi = 0;
577     unsigned long low = (unsigned long)-1;
578 
579     for (i = 0; i < GHBN_NUM; i++) {
580         if (low > ghbn_cache[i].order) {
581             low = ghbn_cache[i].order;
582             lowi = i;
583         }
584         if (ghbn_cache[i].order > 0) {
585             if (strncmp(name, ghbn_cache[i].name, 128) == 0)
586                 break;
587         }
588     }
589     if (i == GHBN_NUM) {        /* no hit */
590         ghbn_miss++;
591         ret = gethostbyname(name);
592         if (ret == NULL)
593             return (NULL);
594         /* else add to cache */
595         if (strlen(name) < sizeof ghbn_cache[0].name) {
596             strcpy(ghbn_cache[lowi].name, name);
597             memcpy((char *)&(ghbn_cache[lowi].ent), ret,
598                    sizeof(struct hostent));
599             ghbn_cache[lowi].order = ghbn_miss + ghbn_hits;
600         }
601         return (ret);
602     } else {
603         ghbn_hits++;
604         ret = &(ghbn_cache[i].ent);
605         ghbn_cache[i].order = ghbn_miss + ghbn_hits;
606         return (ret);
607     }
608 }
609 
610 #endif
611