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 /*----------------------------------------------------------------------------*/
main(int argc,char * argv[],char * envp[])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 /*----------------------------------------------------------------------------*/
TerminalSocket(int FunctionCode,int * ReturnSocket)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 /*----------------------------------------------------------------------------*/
CreateSocketPair(int SocketFamily,int SocketType,int SocketProtocol,int * SocketPair)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 /*----------------------------------------------------------------------------*/
SocketPairTimeoutAst(int astparm)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 /*----------------------------------------------------------------------------*/
TerminalDeviceAst(int astparm)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 /*----------------------------------------------------------------------------*/
LogMessage(char * msg,...)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