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