1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
*/
#include "types.h"
#include "socket.h"
#include "in.h"
#include "netdb.h"
/* TCP_REXEC -- Execute a command on a remote node via the network. This is
* an implementation of the Berkeley UNIX procedure of the same name for a
* machine independent TCP network interface. Unlike the UNIX rexec,
* however, we require that the user login name and password be given as
* input arguments, in addition to the host name and port number and the
* command to be executed.
*
* REXEC assumes that it is talking to an REXECD server on the remote node.
* The TCP EXEC port on the remote node spawns the REXECD server which reads and
* authenticates the user login and password, sets up the error socket if so
* indicated, changes the current directory to the user's home directory, and
* then executes the command. The command syntax is determined by the shell
* REXECD spawns to execute the command, and is implementation dependent.
* Currently the REXECD daemons are either UNIX hosted or UNIX emulated, hence
* the command syntax is the UNIX shell (Bourne shell usually). The command
* executes with its standard input and output (and error output if fd2p=0)
* connected to the socket returned by REXEC.
*
* Note that the shell spawned by the REXEC daemon may be used to spawn a user
* specified server process using a shell command, e.g. "run server.e arg arg".
* In this case the daemon is used to login and set the current directory and
* pass args to the user server, at the expense of one additional process spawn
* for the shell.
*/
tcp_rexec (ahost, rport, name, pass, cmd, fd2p)
char **ahost; /* alias of server node */
int rport; /* IP port number (for EXEC) */
char *name, *pass; /* user login and password */
char *cmd; /* command to be executed */
int *fd2p; /* error channel */
{
struct hostent *tcp_gethostbyname();
struct sockaddr_in sin, sin2, from;
struct hostent *hp;
int timo = 1;
u_sock s, s3;
char c;
short port;
eprintf("rexec %s %s %s %s\n", *ahost, name, pass, cmd);
/* Read host name table for the local network to get the internet
* address of the named host.
*/
hp = tcp_gethostbyname (*ahost);
if (hp == 0) {
ku_error ("unknown network host");
return (-1);
}
/* Set up a full duplex TCP socket to the TCP/EXEC server process
* on the remote node.
*/
retry:
s = tcp_socket (AF_INET, SOCK_STREAM, 0);
if (s < 0) {
ku_error ("rexec: cannot make socket");
return (-1);
}
sin.sin_family = hp->h_addrtype;
sin.sin_port = rport;
ku_bcopy (hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
if (tcp_connect (s, &sin, sizeof(sin)) < 0) {
if (timo <= 16) {
tcp_close (s);
ku_sleep (timo);
timo *= 2;
goto retry;
}
ku_error ("rexec: connect failure");
return (-1);
}
/* If no output error channel variable was given instruct the REXECD
* server to return error output on the data socket, else open a second
* socket to be used for error communications and signals.
*/
if (fd2p == 0) {
tcp_write (s, "", 1);
port = 0;
} else {
char *num, *ku_itoc();
int sin2len, len;
u_sock s2;
s2 = tcp_socket (AF_INET, SOCK_STREAM, 0);
if (s2 < 0) {
tcp_close (s);
return (-1);
}
tcp_listen (s2, 1);
sin2len = sizeof (sin2);
if (tcp_gsockname (s2, (char *)&sin2, &sin2len) < 0 ||
sin2len != sizeof (sin2)) {
ku_error ("rexec: getsockname failed");
tcp_close (s2);
goto bad;
}
port = htons ((u_short)sin2.sin_port);
num = ku_itoc (port);
tcp_write (s, num, strlen(num)+1);
len = sizeof (from);
s3 = tcp_accept (s2, &from, &len, 0);
tcp_close (s2);
if (s3 < 0) {
ku_error ("rexec: accept failure");
port = 0;
goto bad;
}
*fd2p = s3;
}
tcp_write (s, name, strlen (name) + 1);
tcp_write (s, pass, strlen (pass) + 1);
tcp_write (s, cmd, strlen (cmd) + 1);
if (tcp_read (s, &c, 1) != 1) {
ku_error ("rexec: cannot read server");
goto bad;
}
/* Read error message from server process.
*/
if (c != 0) {
char lbuf[80];
char *op;
for (op=lbuf; (tcp_read (s, op, 1) == 1); op++)
if (*op == '\n')
break;
*op = '\0';
ku_error (lbuf);
goto bad;
}
return (s);
bad:
if (port)
tcp_close (*fd2p);
tcp_close (s);
return (-1);
}
|