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 /*----------------------------------------------------------------------------*/
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 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 /*----------------------------------------------------------------------------*/
CreateSocketPair(int SocketFamily,int SocketType,int SocketProtocol,int * SocketPair)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 /*----------------------------------------------------------------------------*/
SocketPairTimeoutAst(int astparm)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 /*----------------------------------------------------------------------------*/
TerminalDeviceAst(int astparm)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 /*----------------------------------------------------------------------------*/
LogMessage(char * msg,...)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