Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / JAWS / clients / WebSTONE / src / rexec.c
blob8bf640257c639df14fc0c23c119b8a7c9db4ecdb
1 /*
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
6 * are met:
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
17 * written permission.
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
29 * SUCH DAMAGE.
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. */
39 #define STRICT
40 #pragma warning(disable: 4201)
41 #include <windows.h>
42 #pragma warning(default: 4201)
43 #include <winsock.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <process.h>
48 #include <signal.h>
49 #include "sysdep.h"
50 #include "bench.h"
52 #define RETVAL DWORD
53 #define IDENT HANDLE
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;
98 IDENT idIn = 0;
99 IDENT idOut, idErr;
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",
113 neterrstr());
116 if (*command != '\0') {
117 char *p = command;
118 if (*p == '\001') {
119 p++;
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);
128 *sockerr = sErr;
129 return sIO;
133 static void MyOpenService(const char *remote_host)
135 struct sockaddr_in server_addr, my_err_addr, junk_addr;
136 struct servent *sv;
137 static char portbuf[30];
138 SOCKET sTmp;
139 int addr_len;
141 if (remote_host[0] >= '0' && remote_host[0] <= '9') {
142 unsigned long addr;
144 addr = inet_addr(remote_host);
145 if (addr == INADDR_NONE) {
146 returnerr("Invalid IP address %s\n", remote_host);
147 return;
150 server_addr.sin_addr.S_un.S_addr = addr;
152 else {
153 struct hostent *hent;
155 hent = gethostbyname(remote_host);
156 if (hent == 0)
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);
166 #ifdef OMIT
167 hent = gethostbyname(remote_host);
168 if(!hent) {
169 errexit("Rexec: Lookup of server hostname failed: %s.\n",
170 neterrstr());
172 #endif /* OMIT */
174 sv=getservbyname("exec", "tcp");
175 if (!sv) {
176 errexit("Rexec: Lookup of port number for rexec service failed: %s.\n",
177 neterrstr());
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",
185 neterrstr());
188 if(connect(sIO,
189 (struct sockaddr *)&server_addr, sizeof server_addr) == SOCKET_ERROR) {
190 errexit("Rexec: I/O socket connection failed: %s.\n",
191 neterrstr());
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",
201 neterrstr());
204 if (bind(sTmp,
205 (struct sockaddr *)&my_err_addr, sizeof my_err_addr) == SOCKET_ERROR) {
206 errexit("Rexec: Error socket bind failed: %s.\n",
207 neterrstr());
208 (void) closesocket(sTmp);
211 if (listen(sTmp, 1) == SOCKET_ERROR) {
212 errexit("Rexec: Error socket listen failed: %s.\n",
213 neterrstr());
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",
221 neterrstr());
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",
231 neterrstr());
232 (void) closesocket(sTmp);
235 (void) closesocket(sTmp);
238 static BOOL Send(SOCKET s, const char *buf, size_t nbuf)
240 int cnt;
241 size_t sent = 0;
243 while (sent < nbuf) {
244 cnt = send(s, &buf[sent], nbuf-sent, 0);
245 if (cnt == -1) {
246 return FALSE;
248 sent += cnt;
250 return TRUE;
254 static BOOL SendZString(const char *str)
256 return Send(sIO, str, strlen(str)+1);
260 static BOOL GetErrString(char *str, size_t len)
262 size_t pos = 0;
264 while (pos < len) {
265 char ch;
266 if (recv(sIO, &ch, 1, 0) != 1) {
267 return FALSE;
269 str[pos++] = ch;
270 if (ch == '\0') {
271 return TRUE;
273 if (ch == '\n') {
274 return TRUE;
277 return FALSE;
281 static IDENT PassOutput()
283 IDENT id;
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",
287 GetLastError());
289 return id;
292 static void PassOutputThread(SOCKET sIO)
294 RETVAL retval = 0;
295 int count;
296 char buf[4096];
298 while ((count=recv(sIO, buf, sizeof buf, 0)) > 0) {
299 if (!Write(STDOUTPUT, buf, count)) {
300 fprintf(stderr,
301 "Error writing to standard output: error = %lu.\n",
302 GetLastError());
303 retval = 1;
304 break;
308 _endthread();
312 static IDENT PassError()
314 IDENT id;
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",
318 GetLastError());
320 return id;
323 static void PassErrorThread(SOCKET sErr)
325 RETVAL retval = 0;
326 int count;
327 char buf[4096];
329 while ((count=recv(sErr, buf, sizeof buf, 0)) > 0) {
330 if (!Write(STDERROR, buf, count)) {
331 fprintf(stderr,
332 "Error writing to standard error: error = %lu.\n",
333 GetLastError());
334 retval = 1;
335 break;
338 _endthread();
341 static BOOL Close(FILECOOKIE fc)
343 return CloseHandle(fc);
346 static int Read(FILECOOKIE fc, char *buf, size_t nbuf)
348 DWORD cbRead;
349 if (!ReadFile(fc, buf, nbuf, &cbRead, 0)) {
350 return -1;
352 return (int)cbRead;
356 static BOOL Write(FILECOOKIE fc, const char *buf, size_t nbuf)
358 DWORD cbWritten;
360 if (!WriteFile(fc, buf, nbuf, &cbWritten, 0)) {
361 return FALSE;
363 if (cbWritten != nbuf) {
364 return FALSE;
366 return TRUE;
370 static void
371 Wait(IDENT id, RETVAL *prv)
373 if (!WaitForSingleObject(id, INFINITE)) {
374 *prv = 2;
375 } else {
376 if (!GetExitCodeThread(id, prv)) {
377 *prv = 4;