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 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 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 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) 171 static void sock_cleanup(void) 172 { 173 if (wsa_init_done) { 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 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 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 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 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 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 381 static int init_server(int *sock, int port, int type) 382 { 383 return (init_server_long(sock, port, NULL, type)); 384 } 385 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 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 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 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 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