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