2 * Copyright (c) 1994-1995 Ataman Software, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Ataman Software, Inc.
15 * 4. The name of Ataman Software, Inc. may not may be used to endorse or
16 * promote products derived from this software without specific prior
19 * THIS SOFTWARE IS PROVIDED BY ATAMAN SOFTWARE, INC. ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL ATAMAN SOFTWARE, INC. BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 static char copyright
[] =
34 "Copyright (c) 1994-1995 Ataman Software, Inc. All rights reserved.";
37 #pragma warning(disable: 4699)
38 /* Includes for Win32 systems go here. */
40 #pragma warning(disable: 4201)
42 #pragma warning(default: 4201)
54 #define STDINPUT hStdIn
55 #define STDOUTPUT hStdOut
56 #define STDERROR hStdErr
57 #define FILECOOKIE HANDLE
59 static void PassOutputThread(SOCKET
);
60 static void PassErrorThread(SOCKET
);
62 HANDLE hStdIn
, hStdOut
, hStdErr
;
67 Think carefully before enabling the -p option. While it may be
68 convenient to have this option, it is for many (if not most) sites a
69 security hole. Remember that the '-p password' used on the command
70 line is visible on most Unix systems to any user that is allow to run
71 the 'ps' command (normally ALL users can run this command). While no
72 utility that comes by default with Windows NT at this time shows the
73 same information, it is unclear whether or not the information is
74 avaiable to all users. Certainly privileged users would be be able to
75 see this information on any system.
77 If the security risk is acceptable at your site, you can enable the -p
78 option by uncommenting the #define below.
80 /* #define ALLOWDASH_P */
82 static void MyOpenService(const char *remote_host
);
83 static BOOL
Send(SOCKET
, const char *, size_t);
84 static BOOL
SendZString(const char *);
85 static BOOL
GetErrString(char *, size_t);
87 static IDENT
PassInput(void);
88 static IDENT
PassOutput(void);
89 static IDENT
PassError(void);
90 static BOOL
Close(FILECOOKIE
);
91 static int Read(FILECOOKIE
, char *, size_t);
92 static BOOL
Write(FILECOOKIE
, const char *, size_t);
93 static void Wait(IDENT
, RETVAL
*);
95 static SOCKET sIO
= INVALID_SOCKET
;
96 static SOCKET sErr
= INVALID_SOCKET
;
101 SOCKET
rexec(const char **hostname
, NETPORT port
, char *username
, char *password
,
102 char *command
, SOCKET
*sockerr
)
105 MyOpenService(*hostname
);
107 SendZString(username
);
108 SendZString(password
);
109 SendZString(command
);
111 if (!GetErrString(command
, sizeof command
)) {
112 errexit("Rexec: Remote aborted connection without initiating protocol: %s.\n",
116 if (*command
!= '\0') {
121 errexit("Rexec: Remote aborted connection: %s\n", p
);
124 hStdIn
= GetStdHandle(STD_INPUT_HANDLE
);
125 hStdOut
= GetStdHandle(STD_OUTPUT_HANDLE
);
126 hStdErr
= GetStdHandle(STD_ERROR_HANDLE
);
133 static void MyOpenService(const char *remote_host
)
135 struct sockaddr_in server_addr
, my_err_addr
, junk_addr
;
137 static char portbuf
[30];
141 if (remote_host
[0] >= '0' && remote_host
[0] <= '9') {
144 addr
= inet_addr(remote_host
);
145 if (addr
== INADDR_NONE
) {
146 returnerr("Invalid IP address %s\n", remote_host
);
150 server_addr
.sin_addr
.S_un
.S_addr
= addr
;
153 struct hostent
*hent
;
155 hent
= gethostbyname(remote_host
);
158 D_PRINTF( "Can't get %s host entry\n", remote_host
);
159 D_PRINTF( "Gethostbyname failed: %d", WSAGetLastError() );
160 errexit("Rexec: gethostbyname(%s) failed: %s\n",
161 remote_host
, neterrstr());
163 memcpy((char *)&server_addr
.sin_addr
, hent
->h_addr
, hent
->h_length
);
167 hent
= gethostbyname(remote_host
);
169 errexit("Rexec: Lookup of server hostname failed: %s.\n",
174 sv
=getservbyname("exec", "tcp");
176 errexit("Rexec: Lookup of port number for rexec service failed: %s.\n",
180 server_addr
.sin_family
= PF_INET
;
181 server_addr
.sin_port
= htons(sv
->s_port
);
183 if((sIO
=socket(PF_INET
, SOCK_STREAM
, 0)) == INVALID_SOCKET
) {
184 errexit("Rexec: I/O socket creation failed: %s.\n",
189 (struct sockaddr
*)&server_addr
, sizeof server_addr
) == SOCKET_ERROR
) {
190 errexit("Rexec: I/O socket connection failed: %s.\n",
194 memset(&my_err_addr
, '\0', sizeof my_err_addr
);
195 my_err_addr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
196 my_err_addr
.sin_family
= AF_INET
;
197 my_err_addr
.sin_port
= 0;
199 if ((sTmp
=socket(PF_INET
, SOCK_STREAM
, 0)) == INVALID_SOCKET
) {
200 errexit("Rexec: Error socket creation failed: error=%s.\n",
205 (struct sockaddr
*)&my_err_addr
, sizeof my_err_addr
) == SOCKET_ERROR
) {
206 errexit("Rexec: Error socket bind failed: %s.\n",
208 (void) closesocket(sTmp
);
211 if (listen(sTmp
, 1) == SOCKET_ERROR
) {
212 errexit("Rexec: Error socket listen failed: %s.\n",
214 (void) closesocket(sTmp
);
217 addr_len
= sizeof my_err_addr
;
218 if (getsockname(sTmp
,
219 (struct sockaddr
*)&my_err_addr
, &addr_len
) == SOCKET_ERROR
) {
220 errexit("Rexec: Error socket bind failed: %s.\n",
222 (void) closesocket(sTmp
);
225 sprintf(portbuf
, "%hu", ntohs(my_err_addr
.sin_port
));
226 SendZString(portbuf
);
228 addr_len
= sizeof junk_addr
;
229 if ((sErr
= accept(sTmp
, (struct sockaddr
*)&junk_addr
, &addr_len
)) == INVALID_SOCKET
) {
230 errexit("Rexec: Error socket accept failed: %s.\n",
232 (void) closesocket(sTmp
);
235 (void) closesocket(sTmp
);
238 static BOOL
Send(SOCKET s
, const char *buf
, size_t nbuf
)
243 while (sent
< nbuf
) {
244 cnt
= send(s
, &buf
[sent
], nbuf
-sent
, 0);
254 static BOOL
SendZString(const char *str
)
256 return Send(sIO
, str
, strlen(str
)+1);
260 static BOOL
GetErrString(char *str
, size_t len
)
266 if (recv(sIO
, &ch
, 1, 0) != 1) {
281 static IDENT
PassOutput()
284 id
= (IDENT
)_beginthread(PassOutputThread
, 4096, (void *)sIO
);
285 if ((long)id
== -1) {
286 errexit("Rexec: Could not start output passing thread: error = %lu\n",
292 static void PassOutputThread(SOCKET sIO
)
298 while ((count
=recv(sIO
, buf
, sizeof buf
, 0)) > 0) {
299 if (!Write(STDOUTPUT
, buf
, count
)) {
301 "Error writing to standard output: error = %lu.\n",
312 static IDENT
PassError()
315 id
= (IDENT
)_beginthread(PassErrorThread
, 4096, (void *)sErr
);
316 if ((long)id
== -1) {
317 errexit("Rexec: Could not start error passing thread: error = %lu\n",
323 static void PassErrorThread(SOCKET sErr
)
329 while ((count
=recv(sErr
, buf
, sizeof buf
, 0)) > 0) {
330 if (!Write(STDERROR
, buf
, count
)) {
332 "Error writing to standard error: error = %lu.\n",
341 static BOOL
Close(FILECOOKIE fc
)
343 return CloseHandle(fc
);
346 static int Read(FILECOOKIE fc
, char *buf
, size_t nbuf
)
349 if (!ReadFile(fc
, buf
, nbuf
, &cbRead
, 0)) {
356 static BOOL
Write(FILECOOKIE fc
, const char *buf
, size_t nbuf
)
360 if (!WriteFile(fc
, buf
, nbuf
, &cbWritten
, 0)) {
363 if (cbWritten
!= nbuf
) {
371 Wait(IDENT id
, RETVAL
*prv
)
373 if (!WaitForSingleObject(id
, INFINITE
)) {
376 if (!GetExitCodeThread(id
, prv
)) {