1 /* 2 * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. 3 * Copyright 2016 VMS Software, Inc. All Rights Reserved. 4 * 5 * Licensed under the Apache License 2.0 (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 /*----------------------------------------------------------------------------*/ 125 /* */ 126 /*----------------------------------------------------------------------------*/ 127 int main (int argc, char *argv[], char *envp[]) 128 { 129 char TermBuff[80]; 130 int TermSock, 131 status, 132 len; 133 134 LogMessage ("Enter 'q' or 'Q' to quit ..."); 135 while (OPENSSL_strcasecmp (TermBuff, "Q")) { 136 /* 137 ** Create the terminal socket 138 */ 139 status = TerminalSocket (TERM_SOCK_CREATE, &TermSock); 140 if (status != TERM_SOCK_SUCCESS) 141 exit (1); 142 143 /* 144 ** Process the terminal input 145 */ 146 LogMessage ("Waiting on terminal I/O ...\n"); 147 len = recv (TermSock, TermBuff, sizeof(TermBuff), 0) ; 148 TermBuff[len] = '\0'; 149 LogMessage ("Received terminal I/O [%s]", TermBuff); 150 151 /* 152 ** Delete the terminal socket 153 */ 154 status = TerminalSocket (TERM_SOCK_DELETE, &TermSock); 155 if (status != TERM_SOCK_SUCCESS) 156 exit (1); 157 } 158 159 return 1; 160 161 } 162 # endif 163 164 /*----------------------------------------------------------------------------*/ 165 /* */ 166 /*----------------------------------------------------------------------------*/ 167 int TerminalSocket (int FunctionCode, int *ReturnSocket) 168 { 169 int status; 170 $DESCRIPTOR (TerminalDeviceDesc, "SYS$COMMAND"); 171 172 /* 173 ** Process the requested function code 174 */ 175 switch (FunctionCode) { 176 case TERM_SOCK_CREATE: 177 /* 178 ** Create a socket pair 179 */ 180 status = CreateSocketPair (AF_INET, SOCK_STREAM, 0, TerminalSocketPair); 181 if (status == -1) { 182 LogMessage ("TerminalSocket: CreateSocketPair () - %08X", status); 183 if (TerminalSocketPair[0]) 184 close (TerminalSocketPair[0]); 185 if (TerminalSocketPair[1]) 186 close (TerminalSocketPair[1]); 187 return TERM_SOCK_FAILURE; 188 } 189 190 /* 191 ** Assign a channel to the terminal device 192 */ 193 status = sys$assign (&TerminalDeviceDesc, 194 &TerminalDeviceChan, 195 0, 0, 0); 196 if (! (status & 1)) { 197 LogMessage ("TerminalSocket: SYS$ASSIGN () - %08X", status); 198 close (TerminalSocketPair[0]); 199 close (TerminalSocketPair[1]); 200 return TERM_SOCK_FAILURE; 201 } 202 203 /* 204 ** Queue an async IO to the terminal device 205 */ 206 status = sys$qio (EFN$C_ENF, 207 TerminalDeviceChan, 208 IO$_READVBLK, 209 &TerminalDeviceIosb, 210 TerminalDeviceAst, 211 0, 212 TerminalDeviceBuff, 213 sizeof(TerminalDeviceBuff) - 2, 214 0, 0, 0, 0); 215 if (! (status & 1)) { 216 LogMessage ("TerminalSocket: SYS$QIO () - %08X", status); 217 close (TerminalSocketPair[0]); 218 close (TerminalSocketPair[1]); 219 return TERM_SOCK_FAILURE; 220 } 221 222 /* 223 ** Return the input side of the socket pair 224 */ 225 *ReturnSocket = TerminalSocketPair[1]; 226 break; 227 228 case TERM_SOCK_DELETE: 229 /* 230 ** Cancel any pending IO on the terminal channel 231 */ 232 status = sys$cancel (TerminalDeviceChan); 233 if (! (status & 1)) { 234 LogMessage ("TerminalSocket: SYS$CANCEL () - %08X", status); 235 close (TerminalSocketPair[0]); 236 close (TerminalSocketPair[1]); 237 return TERM_SOCK_FAILURE; 238 } 239 240 /* 241 ** Deassign the terminal channel 242 */ 243 status = sys$dassgn (TerminalDeviceChan); 244 if (! (status & 1)) { 245 LogMessage ("TerminalSocket: SYS$DASSGN () - %08X", status); 246 close (TerminalSocketPair[0]); 247 close (TerminalSocketPair[1]); 248 return TERM_SOCK_FAILURE; 249 } 250 251 /* 252 ** Close the terminal socket pair 253 */ 254 close (TerminalSocketPair[0]); 255 close (TerminalSocketPair[1]); 256 257 /* 258 ** Return the initialized socket 259 */ 260 *ReturnSocket = 0; 261 break; 262 263 default: 264 /* 265 ** Invalid function code 266 */ 267 LogMessage ("TerminalSocket: Invalid Function Code - %d", FunctionCode); 268 return TERM_SOCK_FAILURE; 269 break; 270 } 271 272 /* 273 ** Return success 274 */ 275 return TERM_SOCK_SUCCESS; 276 277 } 278 279 /*----------------------------------------------------------------------------*/ 280 /* */ 281 /*----------------------------------------------------------------------------*/ 282 static int CreateSocketPair (int SocketFamily, 283 int SocketType, 284 int SocketProtocol, 285 int *SocketPair) 286 { 287 struct dsc$descriptor AscTimeDesc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL}; 288 static const char* LocalHostAddr = {"127.0.0.1"}; 289 unsigned short TcpAcceptChan = 0, 290 TcpDeviceChan = 0; 291 unsigned long BinTimeBuff[2]; 292 struct sockaddr_in sin; 293 char AscTimeBuff[32]; 294 short LocalHostPort; 295 int status; 296 unsigned int slen; 297 298 # ifdef __alpha 299 struct _iosb iosb; 300 # else 301 IOSB iosb; 302 # endif 303 304 int SockDesc1 = 0, 305 SockDesc2 = 0; 306 SPTB sptb; 307 $DESCRIPTOR (TcpDeviceDesc, "TCPIP$DEVICE"); 308 309 /* 310 ** Create a socket 311 */ 312 SockDesc1 = socket (SocketFamily, SocketType, 0); 313 if (SockDesc1 < 0) { 314 LogMessage ("CreateSocketPair: socket () - %d", errno); 315 return -1; 316 } 317 318 /* 319 ** Initialize the socket information 320 */ 321 slen = sizeof(sin); 322 memset ((char *) &sin, 0, slen); 323 sin.sin_family = SocketFamily; 324 sin.sin_addr.s_addr = inet_addr (LocalHostAddr); 325 sin.sin_port = 0; 326 327 /* 328 ** Bind the socket to the local IP 329 */ 330 status = bind (SockDesc1, (struct sockaddr *) &sin, slen); 331 if (status < 0) { 332 LogMessage ("CreateSocketPair: bind () - %d", errno); 333 close (SockDesc1); 334 return -1; 335 } 336 337 /* 338 ** Get the socket name so we can save the port number 339 */ 340 status = getsockname (SockDesc1, (struct sockaddr *) &sin, &slen); 341 if (status < 0) { 342 LogMessage ("CreateSocketPair: getsockname () - %d", errno); 343 close (SockDesc1); 344 return -1; 345 } else 346 LocalHostPort = sin.sin_port; 347 348 /* 349 ** Setup a listen for the socket 350 */ 351 listen (SockDesc1, 5); 352 353 /* 354 ** Get the binary (64-bit) time of the specified timeout value 355 */ 356 sprintf (AscTimeBuff, "0 0:0:%02d.00", SOCKET_PAIR_TIMEOUT_VALUE); 357 AscTimeDesc.dsc$w_length = strlen (AscTimeBuff); 358 AscTimeDesc.dsc$a_pointer = AscTimeBuff; 359 status = sys$bintim (&AscTimeDesc, BinTimeBuff); 360 if (! (status & 1)) { 361 LogMessage ("CreateSocketPair: SYS$BINTIM () - %08X", status); 362 close (SockDesc1); 363 return -1; 364 } 365 366 /* 367 ** Assign another channel to the TCP/IP device for the accept. 368 ** This is the channel that ends up being connected to. 369 */ 370 status = sys$assign (&TcpDeviceDesc, &TcpDeviceChan, 0, 0, 0); 371 if (! (status & 1)) { 372 LogMessage ("CreateSocketPair: SYS$ASSIGN () - %08X", status); 373 close (SockDesc1); 374 return -1; 375 } 376 377 /* 378 ** Get the channel of the first socket for the accept 379 */ 380 TcpAcceptChan = decc$get_sdc (SockDesc1); 381 382 /* 383 ** Perform the accept using $QIO so we can do this asynchronously 384 */ 385 status = sys$qio (EFN$C_ENF, 386 TcpAcceptChan, 387 IO$_ACCESS | IO$M_ACCEPT, 388 &iosb, 389 0, 0, 0, 0, 0, 390 &TcpDeviceChan, 391 0, 0); 392 if (! (status & 1)) { 393 LogMessage ("CreateSocketPair: SYS$QIO () - %08X", status); 394 close (SockDesc1); 395 sys$dassgn (TcpDeviceChan); 396 return -1; 397 } 398 399 /* 400 ** Create the second socket to do the connect 401 */ 402 SockDesc2 = socket (SocketFamily, SocketType, 0); 403 if (SockDesc2 < 0) { 404 LogMessage ("CreateSocketPair: socket () - %d", errno); 405 sys$cancel (TcpAcceptChan); 406 close (SockDesc1); 407 sys$dassgn (TcpDeviceChan); 408 return (-1) ; 409 } 410 411 /* 412 ** Setup the Socket Pair Timeout Block 413 */ 414 sptb.SockChan1 = TcpAcceptChan; 415 sptb.SockChan2 = decc$get_sdc (SockDesc2); 416 417 /* 418 ** Before we block on the connect, set a timer that can cancel I/O on our 419 ** two sockets if it never connects. 420 */ 421 status = sys$setimr (EFN$C_ENF, 422 BinTimeBuff, 423 SocketPairTimeoutAst, 424 &sptb, 425 0); 426 if (! (status & 1)) { 427 LogMessage ("CreateSocketPair: SYS$SETIMR () - %08X", status); 428 sys$cancel (TcpAcceptChan); 429 close (SockDesc1); 430 close (SockDesc2); 431 sys$dassgn (TcpDeviceChan); 432 return -1; 433 } 434 435 /* 436 ** Now issue the connect 437 */ 438 memset ((char *) &sin, 0, sizeof(sin)) ; 439 sin.sin_family = SocketFamily; 440 sin.sin_addr.s_addr = inet_addr (LocalHostAddr) ; 441 sin.sin_port = LocalHostPort ; 442 443 status = connect (SockDesc2, (struct sockaddr *) &sin, sizeof(sin)); 444 if (status < 0 ) { 445 LogMessage ("CreateSocketPair: connect () - %d", errno); 446 sys$cantim (&sptb, 0); 447 sys$cancel (TcpAcceptChan); 448 close (SockDesc1); 449 close (SockDesc2); 450 sys$dassgn (TcpDeviceChan); 451 return -1; 452 } 453 454 /* 455 ** Wait for the asynch $QIO to finish. Note that if the I/O was aborted 456 ** (SS$_ABORT), then we probably canceled it from the AST routine - so log 457 ** a timeout. 458 */ 459 status = sys$synch (EFN$C_ENF, &iosb); 460 if (! (iosb.iosb$w_status & 1)) { 461 if (iosb.iosb$w_status == SS$_ABORT) 462 LogMessage ("CreateSocketPair: SYS$QIO(iosb) timeout"); 463 else { 464 LogMessage ("CreateSocketPair: SYS$QIO(iosb) - %d", 465 iosb.iosb$w_status); 466 sys$cantim (&sptb, 0); 467 } 468 close (SockDesc1); 469 close (SockDesc2); 470 sys$dassgn (TcpDeviceChan); 471 return -1; 472 } 473 474 /* 475 ** Here we're successfully connected, so cancel the timer, convert the 476 ** I/O channel to a socket fd, close the listener socket and return the 477 ** connected pair. 478 */ 479 sys$cantim (&sptb, 0); 480 481 close (SockDesc1) ; 482 SocketPair[0] = SockDesc2 ; 483 SocketPair[1] = socket_fd (TcpDeviceChan); 484 485 return (0) ; 486 487 } 488 489 /*----------------------------------------------------------------------------*/ 490 /* */ 491 /*----------------------------------------------------------------------------*/ 492 static void SocketPairTimeoutAst (int astparm) 493 { 494 SPTB *sptb = (SPTB *) astparm; 495 496 sys$cancel (sptb->SockChan2); /* Cancel the connect() */ 497 sys$cancel (sptb->SockChan1); /* Cancel the accept() */ 498 499 return; 500 501 } 502 503 /*----------------------------------------------------------------------------*/ 504 /* */ 505 /*----------------------------------------------------------------------------*/ 506 static int TerminalDeviceAst (int astparm) 507 { 508 int status; 509 510 /* 511 ** Terminate the terminal buffer 512 */ 513 TerminalDeviceBuff[TerminalDeviceIosb.iosb$w_bcnt] = '\0'; 514 strcat (TerminalDeviceBuff, "\n"); 515 516 /* 517 ** Send the data read from the terminal device through the socket pair 518 */ 519 send (TerminalSocketPair[0], TerminalDeviceBuff, 520 TerminalDeviceIosb.iosb$w_bcnt + 1, 0); 521 522 /* 523 ** Queue another async IO to the terminal device 524 */ 525 status = sys$qio (EFN$C_ENF, 526 TerminalDeviceChan, 527 IO$_READVBLK, 528 &TerminalDeviceIosb, 529 TerminalDeviceAst, 530 0, 531 TerminalDeviceBuff, 532 sizeof(TerminalDeviceBuff) - 1, 533 0, 0, 0, 0); 534 535 /* 536 ** Return status 537 */ 538 return status; 539 540 } 541 542 /*----------------------------------------------------------------------------*/ 543 /* */ 544 /*----------------------------------------------------------------------------*/ 545 static void LogMessage (char *msg, ...) 546 { 547 char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 548 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 549 static unsigned int pid = 0; 550 va_list args; 551 time_t CurTime; 552 struct tm *LocTime; 553 char MsgBuff[256]; 554 555 /* 556 ** Get the process pid 557 */ 558 if (pid == 0) 559 pid = getpid (); 560 561 /* 562 ** Convert the current time into local time 563 */ 564 CurTime = time (NULL); 565 LocTime = localtime (&CurTime); 566 567 /* 568 ** Format the message buffer 569 */ 570 sprintf (MsgBuff, "%02d-%s-%04d %02d:%02d:%02d [%08X] %s\n", 571 LocTime->tm_mday, Month[LocTime->tm_mon], 572 (LocTime->tm_year + 1900), LocTime->tm_hour, LocTime->tm_min, 573 LocTime->tm_sec, pid, msg); 574 575 /* 576 ** Get any variable arguments and add them to the print of the message 577 ** buffer 578 */ 579 va_start (args, msg); 580 vfprintf (stderr, MsgBuff, args); 581 va_end (args); 582 583 /* 584 ** Flush standard error output 585 */ 586 fsync (fileno (stderr)); 587 588 return; 589 590 } 591 #endif 592