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