diff options
Diffstat (limited to 'vms/rcmd.c')
-rw-r--r-- | vms/rcmd.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/vms/rcmd.c b/vms/rcmd.c new file mode 100644 index 0000000..e403021 --- /dev/null +++ b/vms/rcmd.c @@ -0,0 +1,115 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unixio.h> + +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> + +int rcmd(char **remote_hostname, int remote_port, + char *local_user, char *remote_user, + char *command, int zero) +{ + struct hostent *remote_hp; + struct hostent *local_hp; + struct sockaddr_in remote_isa; + struct sockaddr_in local_isa; + char local_hostname[80]; + char ch; + int s; + int local_port; + int rs; + + remote_hp = gethostbyname(*remote_hostname); + if(!remote_hp) + { + perror("couldn't get remote host address"); + exit(-1); + } + + /* Copy remote IP address into socket address structure */ + remote_isa.sin_family = AF_INET; + remote_isa.sin_port = htons(remote_port); + memcpy(&remote_isa.sin_addr, remote_hp->h_addr, sizeof(remote_isa.sin_addr)); + + gethostname(local_hostname, 80); + local_hp = gethostbyname(local_hostname); + if(!local_hp) + { + perror("couldn't get local host address"); + exit(-1); + } + + /* Copy local IP address into socket address structure */ + local_isa.sin_family = AF_INET; + memcpy(&local_isa.sin_addr, local_hp->h_addr, sizeof(local_isa.sin_addr)); + + /* Create the local socket */ + s = socket(AF_INET, SOCK_STREAM, 0); + if(s < 0) + { + perror("socket failed\n"); + exit(-1); + } + + /* Bind local socket with a port from IPPORT_RESERVED/2 to IPPORT_RESERVED - 1 + this requires the OPER privilege under VMS -- to allow communication with + a stock rshd under UNIX */ + + for(local_port = IPPORT_RESERVED - 1; local_port >= IPPORT_RESERVED/2; local_port--) + { + local_isa.sin_port = htons(local_port); + rs = bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa)); + if(rs == 0) + break; + } + + /* Bind local socket to an unprivileged port. A normal rshd will drop the + connection; you must be running a patched rshd invoked through inetd for + this connection method to work */ + + if (rs != 0) + for(local_port = IPPORT_USERRESERVED - 1; + local_port > IPPORT_RESERVED; + local_port--) + { + local_isa.sin_port = htons(local_port); + rs = bind(s, (struct sockaddr *)&local_isa, sizeof(local_isa)); + if(rs == 0) + break; + } + + rs = connect(s, (struct sockaddr *) &remote_isa, sizeof(remote_isa)); + if(rs == -1) + { + fprintf(stderr, "connect: errno = %d\n", errno); + close(s); + exit(-2); + } + + /* Now supply authentication information */ + + /* Auxiliary port number for error messages, we don't use it */ + write(s, "0\0", 2); + + /* Who are we */ + write(s, local_user, strlen(local_user) + 1); + + /* Who do we want to be */ + write(s, remote_user, strlen(remote_user) + 1); + + /* What do we want to run */ + write(s, command, strlen(command) + 1); + + /* NUL is sent back to us if information is acceptable */ + read(s, &ch, 1); + if(ch != '\0') + { + errno = EPERM; + return -1; + } + + return s; +} |