1 /* 2 * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. 3 * Copyright 2016 VMS Software, Inc. All Rights Reserved. 4 * 5 * Licensed under the OpenSSL license (the "License"). You may not use 6 * this file except in compliance with the License. You can obtain a copy 7 * in the file LICENSE in the source distribution or at 8 * https://www.openssl.org/source/license.html 9 */ 10 11 #ifdef __VMS 12 # define OPENSSL_SYS_VMS 13 # pragma message disable DOLLARID 14 15 16 # include <openssl/opensslconf.h> 17 18 # if !defined(_POSIX_C_SOURCE) && defined(OPENSSL_SYS_VMS) 19 /* 20 * On VMS, you need to define this to get the declaration of fileno(). The 21 * value 2 is to make sure no function defined in POSIX-2 is left undefined. 22 */ 23 # define _POSIX_C_SOURCE 2 24 # endif 25 26 # include <stdio.h> 27 28 # undef _POSIX_C_SOURCE 29 30 # include <sys/types.h> 31 # include <sys/socket.h> 32 # include <netinet/in.h> 33 # include <inet.h> 34 # include <unistd.h> 35 # include <string.h> 36 # include <errno.h> 37 # include <starlet.h> 38 # include <iodef.h> 39 # ifdef __alpha 40 # include <iosbdef.h> 41 # else 42 typedef struct _iosb { /* Copied from IOSBDEF.H for Alpha */ 43 # pragma __nomember_alignment 44 __union { 45 __struct { 46 unsigned short int iosb$w_status; /* Final I/O status */ 47 __union { 48 __struct { /* 16-bit byte count variant */ 49 unsigned short int iosb$w_bcnt; /* 16-bit byte count */ 50 __union { 51 unsigned int iosb$l_dev_depend; /* 32-bit device dependent info */ 52 unsigned int iosb$l_pid; /* 32-bit pid */ 53 } iosb$r_l; 54 } iosb$r_bcnt_16; 55 __struct { /* 32-bit byte count variant */ 56 unsigned int iosb$l_bcnt; /* 32-bit byte count (unaligned) */ 57 unsigned short int iosb$w_dev_depend_high; /* 16-bit device dependent info */ 58 } iosb$r_bcnt_32; 59 } iosb$r_devdepend; 60 } iosb$r_io_64; 61 __struct { 62 __union { 63 unsigned int iosb$l_getxxi_status; /* Final GETxxI status */ 64 unsigned int iosb$l_reg_status; /* Final $Registry status */ 65 } iosb$r_l_status; 66 unsigned int iosb$l_reserved; /* Reserved field */ 67 } iosb$r_get_64; 68 } iosb$r_io_get; 69 } IOSB; 70 71 # if !defined(__VAXC) 72 # define iosb$w_status iosb$r_io_get.iosb$r_io_64.iosb$w_status 73 # define iosb$w_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$w_bcnt 74 # define iosb$r_l iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_16.iosb$r_l 75 # define iosb$l_dev_depend iosb$r_l.iosb$l_dev_depend 76 # define iosb$l_pid iosb$r_l.iosb$l_pid 77 # define iosb$l_bcnt iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$l_bcnt 78 # define iosb$w_dev_depend_high iosb$r_io_get.iosb$r_io_64.iosb$r_devdepend.iosb$r_bcnt_32.iosb$w_dev_depend_high 79 # define iosb$l_getxxi_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_getxxi_status 80 # define iosb$l_reg_status iosb$r_io_get.iosb$r_get_64.iosb$r_l_status.iosb$l_reg_status 81 # endif /* #if !defined(__VAXC) */ 82 83 # endif /* End of IOSBDEF */ 84 85 # include <efndef.h> 86 # include <stdlib.h> 87 # include <ssdef.h> 88 # include <time.h> 89 # include <stdarg.h> 90 # include <descrip.h> 91 92 # include "vms_term_sock.h" 93 94 # ifdef __alpha 95 static struct _iosb TerminalDeviceIosb; 96 # else 97 IOSB TerminalDeviceIosb; 98 # endif 99 100 static char TerminalDeviceBuff[255 + 2]; 101 static int TerminalSocketPair[2] = {0, 0}; 102 static unsigned short TerminalDeviceChan = 0; 103 104 static int CreateSocketPair (int, int, int, int *); 105 static void SocketPairTimeoutAst (int); 106 static int TerminalDeviceAst (int); 107 static void LogMessage (char *, ...); 108 109 /* 110 ** Socket Pair Timeout Value (must be 0-59 seconds) 111 */ 112 # define SOCKET_PAIR_TIMEOUT_VALUE 20 113 114 /* 115 ** Socket Pair Timeout Block which is passed to timeout AST 116 */ 117 typedef struct _SocketPairTimeoutBlock { 118 unsigned short SockChan1; 119 unsigned short SockChan2; 120 } SPTB; 121 122 # ifdef TERM_SOCK_TEST 123 124 /*----------------------------------------------------------------------------*/ 126 /* */ 127 /*----------------------------------------------------------------------------*/ 128 int main (int argc, char *argv[], char *envp[]) 129 { 130 char TermBuff[80]; 131 int TermSock, 132 status, 133 len; 134 135 LogMessage ("Enter 'q' or 'Q' to quit ..."); 136 while (strcasecmp (TermBuff, "Q")) { 137 /* 138 ** Create the terminal socket 139 */ 140 status = TerminalSocket (TERM_SOCK_CREATE, &TermSock); 141 if (status != TERM_SOCK_SUCCESS) 142 exit (1); 143 144 /* 145 ** Process the terminal input 146 */ 147 LogMessage ("Waiting on terminal I/O ...\n"); 148 len = recv (TermSock, TermBuff, sizeof(TermBuff), 0) ; 149 TermBuff[len] = '\0'; 150 LogMessage ("Received terminal I/O [%s]", TermBuff); 151 152 /* 153 ** Delete the terminal socket 154 */ 155 status = TerminalSocket (TERM_SOCK_DELETE, &TermSock); 156 if (status != TERM_SOCK_SUCCESS) 157 exit (1); 158 } 159 160 return 1; 161 162 } 163 # endif 164 165 /*----------------------------------------------------------------------------*/ 167 /* */ 168 /*----------------------------------------------------------------------------*/ 169 int TerminalSocket (int FunctionCode, int *ReturnSocket) 170 { 171 int status; 172 $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND"); 173 174 /* 175 ** Process the requested function code 176 */ 177 switch (FunctionCode) { 178 case TERM_SOCK_CREATE: 179 /* 180 ** Create a socket pair 181 */ 182 status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair); 183 if (status == -1) { 184 LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status); 185 if (TerminalSocketPair[0]) 186 close (TerminalSocketPair[0]); 187 if (TerminalSocketPair[1]) 188 close (TerminalSocketPair[1]); 189 return TERM_SOCK_FAILURE; 190 } 191 192 /* 193 ** Assign a channel to the terminal device 194 */ 195 status = sys$assign (&TerminalDeviceDesc, 196 &TerminalDeviceChan, 197 0, 0, 0); 198 if (! (status & 1)) { 199 LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status); 200 close (TerminalSocketPair[0]); 201 close (TerminalSocketPair[1]); 202 return TERM_SOCK_FAILURE; 203 } 204 205 /* 206 ** Queue an async IO to the terminal device 207 */ 208 status = sys$qio (EFN$C_ENF, 209 TerminalDeviceChan, 210 IO$_READVBLK, 211 &TerminalDeviceIosb, 212 TerminalDeviceAst, 213 0, 214 TerminalDeviceBuff, 215 sizeof(TerminalDeviceBuff) - 2, 216 0, 0, 0, 0); 217 if (! (status & 1)) { 218 LogMessage ("TerminalSocket: SYS$QIO () - %08X", status); 219 close (TerminalSocketPair[0]); 220 close (TerminalSocketPair[1]); 221 return TERM_SOCK_FAILURE; 222 } 223 224 /* 225 ** Return the input side of the socket pair 226 */ 227 *ReturnSocket = TerminalSocketPair[1]; 228 break; 229 230 case TERM_SOCK_DELETE: 231 /* 232 ** Cancel any pending IO on the terminal channel 233 */ 234 status = sys$cancel (TerminalDeviceChan); 235 if (! (status & 1)) { 236 LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status); 237 close (TerminalSocketPair[0]); 238 close (TerminalSocketPair[1]); 239 return TERM_SOCK_FAILURE; 240 } 241 242 /* 243 ** Deassign the terminal channel 244 */ 245 status = sys$dassgn (TerminalDeviceChan); 246 if (! (status & 1)) { 247 LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status); 248 close (TerminalSocketPair[0]); 249 close (TerminalSocketPair[1]); 250 return TERM_SOCK_FAILURE; 251 } 252 253 /* 254 ** Close the terminal socket pair 255 */ 256 close (TerminalSocketPair[0]); 257 close (TerminalSocketPair[1]); 258 259 /* 260 ** Return the initialized socket 261 */ 262 *ReturnSocket = 0; 263 break; 264 265 default: 266 /* 267 ** Invalid function code 268 */ 269 LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode); 270 return TERM_SOCK_FAILURE; 271 break; 272 } 273 274 /* 275 ** Return success 276 */ 277 return TERM_SOCK_SUCCESS; 278 279 } 280 281 /*----------------------------------------------------------------------------*/ 283 /* */ 284 /*----------------------------------------------------------------------------*/ 285 static int CreateSocketPair (int SocketFamily, 286 int SocketType, 287 int SocketProtocol, 288 int *SocketPair) 289 { 290 struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; 291 static const char* LocalHostAddr = {"127.0.0.1"}; 292 unsigned short TcpAcceptChan = 0, 293 TcpDeviceChan = 0; 294 unsigned long BinTimeBuff[2]; 295 struct sockaddr_in sin; 296 char AscTimeBuff[32]; 297 short LocalHostPort; 298 int status; 299 unsigned int slen; 300 301 # ifdef __alpha 302 struct _iosb iosb; 303 # else 304 IOSB iosb; 305 # endif 306 307 int SockDesc1 = 0, 308 SockDesc2 = 0; 309 SPTB sptb; 310 $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE"); 311 312 /* 313 ** Create a socket 314 */ 315 SockDesc1 = socket (SocketFamily, SocketType, 0); 316 if (SockDesc1 < 0) { 317 LogMessage ("CreateSocketPair: socket () - %d", errno); 318 return -1; 319 } 320 321 /* 322 ** Initialize the socket information 323 */ 324 slen = sizeof(sin); 325 memset ((char *) &sin, 0, slen); 326 sin.sin_family = SocketFamily; 327 sin.sin_addr.s_addr = inet_addr (LocalHostAddr); 328 sin.sin_port = 0; 329 330 /* 331 ** Bind the socket to the local IP 332 */ 333 status = bind (SockDesc1, (struct sockaddr *) &sin, slen); 334 if (status < 0) { 335 LogMessage ("CreateSocketPair: bind () - %d", errno); 336 close (SockDesc1); 337 return -1; 338 } 339 340 /* 341 ** Get the socket name so we can save the port number 342 */ 343 status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen); 344 if (status < 0) { 345 LogMessage ("CreateSocketPair: getsockname () - %d", errno); 346 close (SockDesc1); 347 return -1; 348 } else 349 LocalHostPort = sin.sin_port; 350 351 /* 352 ** Setup a listen for the socket 353 */ 354 listen (SockDesc1, 5); 355 356 /* 357 ** Get the binary (64-bit) time of the specified timeout value 358 */ 359 sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE); 360 AscTimeDesc.dsc$w_length = strlen (AscTimeBuff); 361 AscTimeDesc.dsc$a_pointer = AscTimeBuff; 362 status = sys$bintim (&AscTimeDesc, BinTimeBuff); 363 if (! (status & 1)) { 364 LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status); 365 close (SockDesc1); 366 return -1; 367 } 368 369 /* 370 ** Assign another channel to the TCP/IP device for the accept. 371 ** This is the channel that ends up being connected to. 372 */ 373 status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0); 374 if (! (status & 1)) { 375 LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status); 376 close (SockDesc1); 377 return -1; 378 } 379 380 /* 381 ** Get the channel of the first socket for the accept 382 */ 383 TcpAcceptChan = decc$get_sdc (SockDesc1); 384 385 /* 386 ** Perform the accept using $QIO so we can do this asynchronously 387 */ 388 status = sys$qio (EFN$C_ENF, 389 TcpAcceptChan, 390 IO$_ACCESS | IO$M_ACCEPT, 391 &iosb, 392 0, 0, 0, 0, 0, 393 &TcpDeviceChan, 394 0, 0); 395 if (! (status & 1)) { 396 LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status); 397 close (SockDesc1); 398 sys$dassgn (TcpDeviceChan); 399 return -1; 400 } 401 402 /* 403 ** Create the second socket to do the connect 404 */ 405 SockDesc2 = socket (SocketFamily, SocketType, 0); 406 if (SockDesc2 < 0) { 407 LogMessage ("CreateSocketPair: socket () - %d", errno); 408 sys$cancel (TcpAcceptChan); 409 close (SockDesc1); 410 sys$dassgn (TcpDeviceChan); 411 return (-1) ; 412 } 413 414 /* 415 ** Setup the Socket Pair Timeout Block 416 */ 417 sptb.SockChan1 = TcpAcceptChan; 418 sptb.SockChan2 = decc$get_sdc (SockDesc2); 419 420 /* 421 ** Before we block on the connect, set a timer that can cancel I/O on our 422 ** two sockets if it never connects. 423 */ 424 status = sys$setimr (EFN$C_ENF, 425 BinTimeBuff, 426 SocketPairTimeoutAst, 427 &sptb, 428 0); 429 if (! (status & 1)) { 430 LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status); 431 sys$cancel (TcpAcceptChan); 432 close (SockDesc1); 433 close (SockDesc2); 434 sys$dassgn (TcpDeviceChan); 435 return -1; 436 } 437 438 /* 439 ** Now issue the connect 440 */ 441 memset ((char *) &sin, 0, sizeof(sin)) ; 442 sin.sin_family = SocketFamily; 443 sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ; 444 sin.sin_port = LocalHostPort ; 445 446 status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof(sin)); 447 if (status < 0 ) { 448 LogMessage ("CreateSocketPair: connect () - %d", errno); 449 sys$cantim (&sptb, 0); 450 sys$cancel (TcpAcceptChan); 451 close (SockDesc1); 452 close (SockDesc2); 453 sys$dassgn (TcpDeviceChan); 454 return -1; 455 } 456 457 /* 458 ** Wait for the asynch $QIO to finish. Note that if the I/O was aborted 459 ** (SS$_ABORT), then we probably canceled it from the AST routine - so log 460 ** a timeout. 461 */ 462 status = sys$synch (EFN$C_ENF, &iosb); 463 if (! (iosb.iosb$w_status & 1)) { 464 if (iosb.iosb$w_status == SS$_ABORT) 465 LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout"); 466 else { 467 LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d", 468 iosb.iosb$w_status); 469 sys$cantim (&sptb, 0); 470 } 471 close (SockDesc1); 472 close (SockDesc2); 473 sys$dassgn (TcpDeviceChan); 474 return -1; 475 } 476 477 /* 478 ** Here we're successfully connected, so cancel the timer, convert the 479 ** I/O channel to a socket fd, close the listener socket and return the 480 ** connected pair. 481 */ 482 sys$cantim (&sptb, 0); 483 484 close (SockDesc1) ; 485 SocketPair[0] = SockDesc2 ; 486 SocketPair[1] = socket_fd (TcpDeviceChan); 487 488 return (0) ; 489 490 } 491 492 /*----------------------------------------------------------------------------*/ 494 /* */ 495 /*----------------------------------------------------------------------------*/ 496 static void SocketPairTimeoutAst (int astparm) 497 { 498 SPTB *sptb = (SPTB *) astparm; 499 500 sys$cancel (sptb->SockChan2); /* Cancel the connect() */ 501 sys$cancel (sptb->SockChan1); /* Cancel the accept() */ 502 503 return; 504 505 } 506 507 /*----------------------------------------------------------------------------*/ 509 /* */ 510 /*----------------------------------------------------------------------------*/ 511 static int TerminalDeviceAst (int astparm) 512 { 513 int status; 514 515 /* 516 ** Terminate the terminal buffer 517 */ 518 TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0'; 519 strcat (TerminalDeviceBuff, "\n"); 520 521 /* 522 ** Send the data read from the terminal device through the socket pair 523 */ 524 send (TerminalSocketPair[0], TerminalDeviceBuff, 525 TerminalDeviceIosb.iosb$w_bcnt + 1, 0); 526 527 /* 528 ** Queue another async IO to the terminal device 529 */ 530 status = sys$qio (EFN$C_ENF, 531 TerminalDeviceChan, 532 IO$_READVBLK, 533 &TerminalDeviceIosb, 534 TerminalDeviceAst, 535 0, 536 TerminalDeviceBuff, 537 sizeof(TerminalDeviceBuff) - 1, 538 0, 0, 0, 0); 539 540 /* 541 ** Return status 542 */ 543 return status; 544 545 } 546 547 /*----------------------------------------------------------------------------*/ 549 /* */ 550 /*----------------------------------------------------------------------------*/ 551 static void LogMessage (char *msg, ...) 552 { 553 char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 554 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 555 static unsigned int pid = 0; 556 va_list args; 557 time_t CurTime; 558 struct tm *LocTime; 559 char MsgBuff[256]; 560 561 /* 562 ** Get the process pid 563 */ 564 if (pid == 0) 565 pid = getpid (); 566 567 /* 568 ** Convert the current time into local time 569 */ 570 CurTime = time (NULL); 571 LocTime = localtime (&CurTime); 572 573 /* 574 ** Format the message buffer 575 */ 576 sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n", 577 LocTime->tm_mday, Month[LocTime->tm_mon], 578 (LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min, 579 LocTime->tm_sec, pid, msg); 580 581 /* 582 ** Get any variable arguments and add them to the print of the message 583 ** buffer 584 */ 585 va_start (args, msg); 586 vfprintf (stderr, MsgBuff, args); 587 va_end (args); 588 589 /* 590 ** Flush standard error output 591 */ 592 fsync (fileno (stderr)); 593 594 return; 595 596 } 597 #endif 598