Home | History | Annotate | Line # | Download | only in lib
      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