From: <ped...@us...> - 2007-06-25 01:15:45
|
Revision: 1008 http://svn.sourceforge.net/cegcc/?rev=1008&view=rev Author: pedroalves Date: 2007-06-24 18:15:40 -0700 (Sun, 24 Jun 2007) Log Message: ----------- Initial import. * LICENSE, README, TODO, ChangeLog, Makefile, rcp.c, FindFileA.c, Readme_org.txt: New files. Added Paths: ----------- trunk/cegcc/tools/rcp/ trunk/cegcc/tools/rcp/ChangeLog trunk/cegcc/tools/rcp/FindFileA.c trunk/cegcc/tools/rcp/LICENSE trunk/cegcc/tools/rcp/Makefile trunk/cegcc/tools/rcp/README trunk/cegcc/tools/rcp/Readme_org.txt trunk/cegcc/tools/rcp/TODO trunk/cegcc/tools/rcp/rcp.c Added: trunk/cegcc/tools/rcp/ChangeLog =================================================================== --- trunk/cegcc/tools/rcp/ChangeLog (rev 0) +++ trunk/cegcc/tools/rcp/ChangeLog 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,14 @@ +2007-06-25 Pedro Alves <ped...@po...> + + Initial import. + + * LICENSE, README, TODO, ChangeLog, Makefile, rcp.c, FindFileA.c, + Readme_org.txt: New files. + + +Local Variables: +mode: change-log +left-margin: 8 +fill-column: 74 +version-control: never +End: Property changes on: trunk/cegcc/tools/rcp/ChangeLog ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/FindFileA.c =================================================================== --- trunk/cegcc/tools/rcp/FindFileA.c (rev 0) +++ trunk/cegcc/tools/rcp/FindFileA.c 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,91 @@ +// findfile.c +// +// Time-stamp: <12/02/01 14:42:40 keuchel@keuchelnt> + +#include <wchar.h> + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#define COUNTOF(X) (sizeof (X)/sizeof ((X)[0])) + +HANDLE WINAPI +FindFirstFileA (const char *lpName, LPWIN32_FIND_DATAA lpfd) +{ + HANDLE hFind; + WIN32_FIND_DATAW fdw; + wchar_t lpNameNew[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, lpName, -1, lpNameNew, COUNTOF (lpNameNew)); + + hFind = FindFirstFileW (lpNameNew, &fdw); + + if(hFind != INVALID_HANDLE_VALUE) + { + lpfd->dwFileAttributes = fdw.dwFileAttributes; + lpfd->ftCreationTime = fdw.ftCreationTime; + lpfd->ftLastAccessTime = fdw.ftLastAccessTime; + lpfd->ftLastWriteTime = fdw.ftLastWriteTime; + lpfd->nFileSizeHigh = fdw.nFileSizeHigh; + lpfd->nFileSizeLow = fdw.nFileSizeLow; + +#ifdef __COREDLL__ + lpfd->dwReserved0 = fdw.dwOID; +#endif + + WideCharToMultiByte (CP_ACP, 0, + fdw.cFileName, -1, + lpfd->cFileName, + COUNTOF (lpfd->cFileName), + NULL, NULL); + + // not in wince... + lpfd->cAlternateFileName[0] = 0; + } + + return hFind; +} + +BOOL WINAPI +FindNextFileA (HANDLE hFind, LPWIN32_FIND_DATAA lpfd) +{ + WIN32_FIND_DATAW fdw; + BOOL res; + + // is this needed? + fdw.dwFileAttributes = lpfd->dwFileAttributes; + fdw.ftCreationTime = lpfd->ftCreationTime; + fdw.ftLastAccessTime = lpfd->ftLastAccessTime; + fdw.ftLastWriteTime = lpfd->ftLastWriteTime; + fdw.nFileSizeHigh = lpfd->nFileSizeHigh; + fdw.nFileSizeLow = lpfd->nFileSizeLow; +#ifdef __COREDLL__ + fdw.dwOID = lpfd->dwReserved0; +#endif + + res = FindNextFileW(hFind, &fdw); + + if(res == TRUE) + { + lpfd->dwFileAttributes = fdw.dwFileAttributes; + lpfd->ftCreationTime = fdw.ftCreationTime; + lpfd->ftLastAccessTime = fdw.ftLastAccessTime; + lpfd->ftLastWriteTime = fdw.ftLastWriteTime; + lpfd->nFileSizeHigh = fdw.nFileSizeHigh; + lpfd->nFileSizeLow = fdw.nFileSizeLow; + +#ifdef __COREDLL__ + lpfd->dwReserved0 = fdw.dwOID; +#endif + + WideCharToMultiByte(CP_ACP, 0, + fdw.cFileName, -1, + lpfd->cFileName, + COUNTOF(lpfd->cFileName), + NULL, NULL); + + lpfd->cAlternateFileName[0] = 0; + } + + return res; +} Property changes on: trunk/cegcc/tools/rcp/FindFileA.c ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/LICENSE =================================================================== --- trunk/cegcc/tools/rcp/LICENSE (rev 0) +++ trunk/cegcc/tools/rcp/LICENSE 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,27 @@ +This tool was written based on the rcp extension to +"rshd - Remote Shell Daemon for Windows NT version 1.6" written by +Silviu C. Marghescu (http://www.cs.umd.edu/~silviu). The rcp +extension was written by Gary Doss (gd...@rp...). + +See the Readme_org.txt file for the original copyright notice, and the +original disclaimer. + +The changes made to the original files are also covered by the +following conditions: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ Added: trunk/cegcc/tools/rcp/Makefile =================================================================== --- trunk/cegcc/tools/rcp/Makefile (rev 0) +++ trunk/cegcc/tools/rcp/Makefile 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,74 @@ +TARGET=arm-wince-mingw32ce +CFLAGS=-O0 -g3 +WARNFLAGS=-Wall -Wextra + +INCLUDES=-I../errno -I../libcwd +LDFLAGS=-L../errno -L../libcwd +LIBS=-lcwd -lerrno + +ALLFLAGS=$(CFLAGS) $(INCLUDES) $(WARNFLAGS) + +CC=$(TARGET)-gcc +STRIP=$(TARGET)-strip + +BINS = rcp_unstripped.exe +STRIPPED_BINS = rcp.exe + +TARGETS = $(STRIPPED_BINS) + +srcdir=. +distdir=rcp-0.1.0 +TAR = tar +TARFLAGS = z +TARFILEEXT = .tar.gz + +SRCDIST_FILES=\ + rcp.c Makefile README TODO COPYING ChangeLog + +BINDIST_FILES=\ + rcp.exe + +OBJECTS=rcp.o FindFileA.o + +all: $(TARGETS) +bins: $(BINS) + +.c.o: + $(CC) -o $@ $< -c $(ALLFLAGS) + +rcp_unstripped.exe: $(OBJECTS) Makefile + $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(ALLFLAGS) $(LIBS) + +rcp.exe: rcp_unstripped.exe + $(STRIP) $< -o $@ + +download: rcp.exe + pcp rcp.exe ":/rcp.exe" + +clean: + rm -f $(BINS) $(STRIPPED_BINS) $(OBJECTS) + +dist: srcdist bindist + +srcdist: all + rm -rf $(distdir) + mkdir $(distdir) + chmod 755 $(distdir) + for i in $(SRCDIST_FILES); do \ + cp -p $(srcdir)/$$i $(distdir)/$$i ; \ + done + rm -f $(distdir).tar.gz + $(TAR) $(TARFLAGS)cf $(distdir)-src$(TARFILEEXT) $(distdir) + +bindist: all + rm -rf $(distdir) + mkdir $(distdir) + chmod 755 $(distdir) + for i in $(BINDIST_FILES); do \ + cp -p $(srcdir)/$$i $(distdir)/$$i ; \ + done + rm -f $(distdir).tar.gz + $(TAR) $(TARFLAGS)cf $(distdir)-bin$(TARFILEEXT) $(distdir) + + +.PHONY: all install download clean dist bindist srcdist Property changes on: trunk/cegcc/tools/rcp/Makefile ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/README =================================================================== --- trunk/cegcc/tools/rcp/README (rev 0) +++ trunk/cegcc/tools/rcp/README 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,26 @@ + README for rcp for Windows CE + +This directory contains rcp for Windows CE. + +This tool was written based on the rcp extension to +"rshd - Remote Shell Daemon for Windows NT version 1.6" written by +Silviu C. Marghescu (http://www.cs.umd.edu/~silviu). The rcp +extension was written by Gary Doss (gd...@rp...). + +The rcp part was totally separated from Silviu's rshd, and converted +to read/write from/to stdin/stdout. It is supposed to be invoked from +rshd for WinCE with stdin/stdout/stderr redirected, much like a unix +version of rcp would do. + +To build make sure you have the mingw32ce toolchain on your path, and +type make. + +Have fun! + +Pedro Alves + +-- + +REPORTING BUGS: +ce...@so... +pe...@po... Property changes on: trunk/cegcc/tools/rcp/README ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/Readme_org.txt =================================================================== --- trunk/cegcc/tools/rcp/Readme_org.txt (rev 0) +++ trunk/cegcc/tools/rcp/Readme_org.txt 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,241 @@ +rshd - Remote Shell Daemon for Windows NT version 1.6 + +Written by Silviu C. Marghescu (http://www.cs.umd.edu/~silviu) +Copyright (C) 1996 Silviu C. Marghescu, Emaginet, Inc. +All Rights Reserved. + +Password functionality added by Ashley M. Hopkins (http://www.csee.usf.edu/~amhopki2) + +rshd is free software; you can redistribute it in its entirety +in any form you like. If you find any bugs, feel free to send me an +email at si...@em.... If you have added new features to rshd, +please send me all the source code modifications, including the version +of rshd that you are based on. Your additions may benefit other users. + + +Disclaimer +========== + +rshd is distributed hoping that it will be useful, but WITHOUT ANY WARRANTY; +without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. + +Good data processing procedure dictates that any program be +thoroughly tested with non-critical data before relying on it. +The user must assume the entire risk of using the program. +THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY KIND OF DAMAGES OR CLAIMS THAT +DIRECTLY OR INDIRECTLY RESULT FROM USING THIS SOFTWARE. + + +Description +=========== + +rshd is a multithreaded daemon service that listens for connections on port +514 (tcp port for the shell/cmd protocol), runs commands passed by clients and sends +back the results. It was my experience that the rshd service included in the +Windows NT Resource Kit does not fully follow the BSD specification for the rsh protocol; +it works fine with the rsh client in NT, but other clients fail to connect. +This implementation of rshd tries to get as close as possible to the BSD specs +(http://www.bsdi.com). + +As of version 1.5, rshd comes with RCP server support, thanks to Gary Doss +(gd...@rp...); any problem/question concerning the rcp +part of rshd would be better answered by him. + +Important note: rshd was designed and implemented to be convenient and reliable, +rather than tightly secure. A client trying to connect to rshd will have to pass +a security clearance process, but rshd is probably far from a secure service. +If security is of major concern across your network, you should be very careful +when using this service. My target for rshd was a closed network, or a network +guarded by a firewall. + + +Requirements +============ + +o An Intel processor based machine running Microsoft Windows NT and TCP/IP. +o Window Socket DLL installed properly (version 1.1 or higher). + + +Installation +============ + +This package contains the following files: + readme.txt - this file + rshd.exe - the rshd daemon executable +The source distribution also contains: + rshd.cpp - the C++ source file (actually mostly C, but I prefer to define + variables when I really need them; plus, I like the // comments) + rshd_rcp.cpp - the C++ source file for the RCP service + service.cpp, service.h - the service routines (many thanks to Craig Link, + Microsoft for including the Service project in the samples) + rshd.ide - the project file for Borland C++ 5.0 users + rshd.mak - the project file for Microsoft Visual C++ 2.0 + + +Running rshd +============ + +In this new version, rshd runs as a service. You also have the option of running rshd +as a command line application (see "-d" later on). In order to get the service up and +running, you will have to complete the following steps: +1. install the service: + rhsd -install +2. start the service: + net start rshd +That's it! Stopping the service is as easy as starting it: + net stop rshd +Should you decide rshd is not the way to go: + rshd -remove +Starting/stopping the service can also be done through the "Services" Control Panel +applet; just look for the RSHD Daemon service. + +Note that if the applications you are running require user credentials, you should +run the service under the corresponding user account. + +Command line options: +-install installs the rshd service +-remove removes the rshd service + +The following command line options have been inherited from the previous, interactive +versions. I don't know if they'll be useful if you decide to run rshd as a service. +I haven't figured out yet how to run the service with command line options, therefore +the '-r' is set by default. + +-d enables debugging messages and allows you to run rshd as a command line process. Good + for those days when nothing works... +-1 no stdout redirection. By default, rshd will redirect the output of your + command into a temporary file and send the result back thru the client + socket. If however you are not interested in the output, or the command + is already redirected, this option will prevent stdout redirection. + Note that the option is global, meaning it will disable redirection + regardless of the commands you're passing... +-2 no stderr redirection. Same as '-1', but for stderr. At this point it + should be noted that under the BSD rshd specification, the client can pass + an auxillary tcp port number that the daemon can use to send the stderr + output back. The rshd will connect to that port if provided and send + back the stderr, unless this option is given. If no alternative stderr port + is provided, rshd will use the main socket for both stdout and stderr. +-4 4DOS command shell. Different shells and different operating systems have + different ways of redirecting output, especially for the standard error stream. + rshd was tested in the following configurations: CMD.EXE and 4NT.EXE on + Windows NT; COMMAND.COM and 4DOS.COM on Windows 95. If you're running 4DOS + on Windows 95, make sure you set the '-4' command parameter, otherwise the + stderr redirection will fail. +-s stronger security enabled. By default, when the client credentials can't + be checked, rshd assumes it to be friendly and runs the command. If that + creates security concernes, this option will accept the connection to a client + only if everything checks out. +-r no .rhosts checking. Per BSD rshd specification, rshd loads the + <windir>\.rhosts file and builds a list of trusted hosts. + Any further connections will be accepted only from a host in the + list. '-r' disables this checking. Note that this is a major security + issue: if your network is not closed or guarded by a firewall, anybody + can connect thru the rsh protocol and run commands on your machines. + Use this option only if you know exactly who is running what across your + network! +-p password option enabled. User will be prompted to enter a password after start of + the daemon. To enable rsh commands to execute on the daemon with this enabled user + must enter password from the command line in the rsh command between the hostname and the command. (rsh hostname password command) + The password option does not affect the rcp command. +-v displays the rshd version. +-h help screen. + +RCP usage: + Valid rcp requests are in the form: + rcp -t [-d] [-r] [-p] target + rcp -f [r] [-p] target + NOTE: The -p option is being ignored since there is not a good + correlation between UNIX and NT when it comes to file + permissions and ownership. + +I have tested rshd with the following rsh clients: WinRSH (both 16 and 32 bit +versions; this was the client I needed to use and didn't work with the Resource +Kit implementation of rshd); NT client of rsh; SunOS client of rsh. The main +difference between WinRSH and the other rsh clients is that WinRSH does not open +a stderr additional port; rshd will send both the stdout and stderr output thru +the main socket. + + +Security considerations +======================= + +As stated above, security was not the main issue while implementing rshd. The +daemon still tries to authenticate the remote user/host, but the authentication +process is not fully implemented and should not be considered secure. +In this version, only host authentication is implemented. If not disabled (see +the '-r' switch), an .rhosts mechanism is used: the remote host name is searched +in the .rhosts file; if it is not found, the connection is refused. +Sometimes, rshd does not have enough information to decide whether the connection +is secure or not (e.g. cannot determine the remote host name); in this cases, by +default, the connection is accepted, unless the '-s' switch is on. The '-s' switch +will enable a tighter security: only fully recognized clients will be able to connect. + +The password functionality added by Ashley M. Hopkins enables another layer of security by requiring that the user enter a password. This option can be used in conjunction with the .rhosts file or with the .rhosts checking disabled (-r). + +To allow compatibility across NT/95 platforms, the required path for the .rhosts file +(if you decide to use the feature) is: <windir>\.rhosts, where <windir> is your +Windows root directory as reported by the WINDIR environment variable. + + +Rebuilding rshd +=============== + +You probably have the sources already... I've built rshd with both Visual C++ +and Borland C++; the .ide file is the Borland project and the .mak is the one +you need for Visual C++. Make sure you define the appropriate macro (first lines +in rshd.cpp define either VISUALCPP or BORLANDCPP). + + +Known problems +============== + +Some rsh clients open an additional connection for the stderr output. There is a +known problem/feature in Microsoft's implementation of TCP/IP that causes closed +connections to linger on for 2 maximum segment lives (4 minutes). Within the timeout +period, the local port is unusable. For this reason, rshd has a mechanism for port +resolution that tries to assign local ports in a round-robin fashion. +It is not a clean solution, but it works for the time being (there is still a problem +if rshd is restarted, since it begins assigning ports from 1023; if those ports are +taken by TIME_WAIT connections, they'll be unusable). A way of reducing the timeout +period to less than 4 minutes is described in Microsoft's Knowledge Base article Q149532: + +***************************************************************************************** +A new registry has been added to TCP/IP to allow the TIME-WAIT state to be configurable. +This will allow TCP/IP users to free closed connection resources more quickly. + +The new registry entry is: + + TcpTimedWaitDelay + Key: Tcpip\Parameters + Value Type: REG_DWORD - Time in seconds + Valid Range: 30-300 (decimal) + Default: 0xF0 (240 decimal) +***************************************************************************************** + + +Also, very long command lines (e.g. more than 1024 characters) can cause rshd to +crash. Still working on it. + +For complex commands (e.g. "comm1 | comm2"), to achieve correct redirection, the whole +command needs to be enclosed in parenthesis (e.g. (comm1 | comm2) ). However, that creates +problems on some machines (errors have been reported on Windows 95, running under command.com). +Things go smoothly though if you have 4NT or 4DOS (use the '-4' flag then). + + + +Whether you have good or bad comments, improvements and suggestions, I would like +to hear from you at si...@em.... + + +Bug fixes, improvements +======================= + +Gary Doss (gd...@rp...) has had a major contribution to rshd, +with the RCP support and some pretty good bug fixes. + +Barbara Dawkins (bda...@rp...) has improved Gary's RCP support +and fixed a couple of bugs. + + +Ashley Hopkins (amh...@cs...) has added the password option to the rshd to improve security of this daemon. Additionally a bug has been fixed to allow the transfer of executable files. \ No newline at end of file Property changes on: trunk/cegcc/tools/rcp/Readme_org.txt ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/TODO =================================================================== --- trunk/cegcc/tools/rcp/TODO (rev 0) +++ trunk/cegcc/tools/rcp/TODO 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,5 @@ + +* Rewrite the ParseTarget, NextTarget and CloseTarget function to use + _findfirst, or dirent or something else. + +* Convert rcp_main to use getopt. Property changes on: trunk/cegcc/tools/rcp/TODO ___________________________________________________________________ Name: svn:eol-style + native Added: trunk/cegcc/tools/rcp/rcp.c =================================================================== --- trunk/cegcc/tools/rcp/rcp.c (rev 0) +++ trunk/cegcc/tools/rcp/rcp.c 2007-06-25 01:15:40 UTC (rev 1008) @@ -0,0 +1,1002 @@ +/* +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +/* Follows the original Copyright and disclaimer statements of the + original package. */ + +////////////////////////////////////////////////////////////////////////// +// +// rshd_rcp.cpp +// +// This file contains code which will extend rshd to handle rcp +// requests. +// +// Author: Gary L. Doss NCR Corporation +// Date: December 16, 1996 +// +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// +// +// rsh daemon for Windows NT/95 +// (c) 1996 Silviu Marghescu - Emaginet, Inc. +// +// +// This program is free software; you can redistribute and/or modify +// it. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// +// rshd - Remote Shell Daemon for Windows NT/95 +// Author: Silviu C. Marghescu (http://www.cs.umd.edu/~silviu) +// Date: May 16, 1996 +// +////////////////////////////////////////////////////////////////////////// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <io.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <dirent.h> +#include <stdarg.h> + +#include <windows.h> + +#include <cwd.h> + +static FILE * +get_logfile (void) +{ +#if 0 + static FILE* logger = NULL; + + if (logger == NULL) + { + char buf[200]; + sprintf (buf, "rcp-%08x", (unsigned) GetCurrentProcessId ()); + logger = fopen (buf, "a+"); + } + return logger; +#else + return stderr; +#endif +} + +static int debugFlag = 0; + +static void +error (const char *message) +{ + FILE* f = get_logfile (); + fprintf (f, "%s\n", message); + fflush (f); +} + +static void +debug (const char *format, ...) +{ + if (debugFlag) + { + FILE* f = get_logfile (); + va_list ap; + va_start (ap, format); + vfprintf (f, format, ap); + fflush (f); + va_end (ap); + } +} + +/* This is the size of the buffer used with rcp */ +#define RCP_BUFFER_SIZE 8192 +/* This is a delay time in milliseconds to wait after sending an error + condition to the remote hosts during an rcp. */ +#define RCP_ERR_DELAY 1000 + +/* Several of the messages sent in the rcp protocol are single + byte ( 0x00 ) or are text messages terminated by a ('\n'). + This routine reads the message a single byte at a time and + checks for the appropriate termination condition. + BUFF is the buffer to hold the data. + BLEN is the length of the buffer. + returns -1 if recv fails or number of characters received on SUCCESS. */ +static int +RcpReceive (char *buff, int blen) +{ + int i; + int rlen; + char tchar; + + i = 0; + buff[0] = 0; + do + { + rlen = read (fileno (stdin), &buff[i], 1); + if (rlen == -1) + { + error ("Cannot receive client data."); + return rlen; + } + if (debugFlag) + { + if (!rlen) + fprintf (stderr, "...got %d chars. \n", rlen); + else + fprintf (stderr, "...got %d chars. [%c]\n", rlen, buff[i]); + } + tchar = buff[i]; + i++; + if (i > blen) + { + /* The buffer has overflowed. */ + SetLastError (WSAEMSGSIZE); + return -1; + } + } + while (tchar != '\n' && tchar != '\0'); + + return i; +} + +/* ParseTarget is the first step in processing environment + variables and wild card characters that may exists in + the target specification of the rcp command. All + environment variables are expanded and a find is initiated + to handle the wild card characters ( ? and * ). + HFILE is a pointer to a file handle. The file handle is used + by the calling process to obtain more files associated with the target. + TARGET is the target file/directory that needs to be expanded. + BDIR is a flag will be set to TRUE if the TARGET is a directory and + FALSE if it is a file. + Return TRUE if there are possibly more files that match the target + and FALSE if this is the only file that matches. + + The wildcard characters are only valid if used in the last item + in the path specified by Target. + + See Also NextTarget and CloseTarget. */ +static BOOL +ParseTarget (HANDLE * hFile, char *Target, BOOL *bDir) +{ + char strPath[MAX_PATH]; +#if 0 + long lLen; +#endif + WIN32_FIND_DATAA wfdFileData; + BOOL bMoreFiles = FALSE; + char *strLastSlash; + char strDirectory[MAX_PATH]; + struct stat statbuf; + + /* TARGET may contain: + Environment Variables: %name% + Wild Card Characters: ? and * */ +#if 0 + lLen = ExpandEnvironmentStrings (Target, strPath, MAX_PATH); + + if (debugFlag) + fprintf (stderr, "The expanded path is %d chars %d: %s\n", lLen, + GetLastError (), strPath); +#else + strcpy (strPath, Target); +#endif + /* Determine the directory name for the expanded target. */ + strLastSlash = strchr (strPath, '/'); + while (strLastSlash != NULL) + { + *strLastSlash = '\\'; + strLastSlash++; + strLastSlash = strrchr (strLastSlash, '/'); + } + + strLastSlash = strrchr (strPath, '\\'); + if ((strLastSlash == NULL) || (strLastSlash == strPath)) + strDirectory[0] = 0; + else + { + strncpy (strDirectory, strPath, (long) (strLastSlash - strPath)); + strDirectory[(long) (strLastSlash - strPath)] = 0; + strcat (strDirectory, "\\"); + } + + /* If the target has wildcards, process them. */ + if ((strchr (strPath, '?') != NULL) || (strchr (strPath, '*') != NULL)) + { + *hFile = FindFirstFileA (strPath, &wfdFileData); + if (*hFile != INVALID_HANDLE_VALUE) + { + bMoreFiles = TRUE; + if (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + *bDir = TRUE; + /* Ignore directories "." and ".." */ + while (!(strcmp (wfdFileData.cFileName, ".")) || + !(strcmp (wfdFileData.cFileName, ".."))) + { + if (!FindNextFileA (*hFile, &wfdFileData)) + { + /* Handle error. */ + Target[0] = 0; + *bDir = FALSE; + return FALSE; + } + *bDir = + (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? TRUE : FALSE; + } + } + else + *bDir = FALSE; + + sprintf (Target, "%s%s", strDirectory, wfdFileData.cFileName); + } + else + { + Target[0] = 0; + *bDir = FALSE; + return FALSE; + } + } + else + { + /* Check to see if Target is a file or a directory. */ + strcpy (Target, strPath); + if (stat (Target, &statbuf) != 0) + return FALSE; + else + *bDir = (statbuf.st_mode & S_IFDIR) ? TRUE : FALSE; + } + return bMoreFiles; +} + +/* This function gets the next available target that matches + the specification passed to ParseTarget for the specified + HANDLE. HFILE is a HANDLE returned from call to ParseTarget. + BDIR is a flag that will be set to TRUE if the TARGET is a + directory and to FALSE if it is a regular file. + Returns NULL if no more matches exist, of a pointer to target + name if a match is found. + + Assumptions: + The pointer returned by NextTarget should never be deleted. + NextTarget is always called after ParseTarget. + No target names will be larger than MAX_PATH. + + See Also: ParseTarget, CloseTarget. */ +static char * +NextTarget (HANDLE hFile, BOOL * bDir) +{ + static char Target[MAX_PATH]; + WIN32_FIND_DATAA wfdFileData; + + /* Make sure the handle is not bad. */ + if (hFile == INVALID_HANDLE_VALUE) + { + *bDir = FALSE; + return NULL; + } + + if (FindNextFileA (hFile, &wfdFileData)) + { + /* A match was found. */ + if (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + *bDir = TRUE; + /* Ignore directories "." and "..". */ + while (!(strcmp (wfdFileData.cFileName, ".")) || + !(strcmp (wfdFileData.cFileName, ".."))) + { + if (!FindNextFileA (hFile, &wfdFileData)) + { + /* Handle error. */ + Target[0] = 0; + *bDir = FALSE; + return NULL; + } + if (wfdFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + *bDir = TRUE; + else + *bDir = FALSE; + } + } + else + *bDir = FALSE; + + sprintf (Target, "%s", wfdFileData.cFileName); + } + else + { + Target[0] = 0; + *bDir = FALSE; + return NULL; + } + return (Target); +} + +/* Terminate the search for target matches that was initiated + in the call to ParseTarget. HFILE is a HANDLE returned from + the call to ParseTarget. + + Assumptions: + CloseTarget must always be used to close the find initiated by + ParseTarget. + There are no more matches to a target when NextTarget returns + NULL. + + See Also: ParseTarget, NextTarget. */ +void +CloseTarget (HANDLE hFile) +{ + if (hFile != INVALID_HANDLE_VALUE) + FindClose (hFile); + return; +} + +/* This functions processes an rcp request to send files to + a remote system. TARGET is the target specified in the rcp + request. BRECURSIVE specified that this request must recurse + the sub-directories of the specfied target. + + Assumptions: + All files sent are read as BINARY files. This prevents + the translation of CR-LF to LF and preserves the size of the file + and the data contained in it. */ +void +RcpSvrSend (const char *Target, BOOL bRecursive) +{ + char buff[RCP_BUFFER_SIZE + 1]; + int blen = RCP_BUFFER_SIZE; + int FileId; + int nFileSize; + int nBytesRead; + int nBytesSent; + int dwBytes; + int nValue; + BOOL bMoreFiles; + HANDLE hFile = INVALID_HANDLE_VALUE; + char expTarget[MAX_PATH]; + char *Target2; + char *FileName; + BOOL bDir; + BOOL bTarget; + BOOL bProcessing; + struct _stat statbuf; + + debug ("sending %s\n", Target); + + /* Copy the target to a buffer we know will hold MAX_PATH. */ + strcpy (expTarget, Target); + /* Check the target for environment variables and wild cards. */ + bMoreFiles = ParseTarget (&hFile, expTarget, &bDir); + bTarget = bDir; + + if (!bRecursive & bDir) + { + /* Error condition. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Not a plain file\n", expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + debug ("sending %s\n", expTarget); + + if (access (expTarget, 02) != 0) + { + debug ("error\n"); + /* Error condition */ + buff[0] = 1; + if (errno == ENOENT) + sprintf (&buff[1], "rcp: %s: No such file or directory\n", expTarget); + else + sprintf (&buff[1], "rcp: %s: Permission Denied\n", expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + debug ("waiting for '\\0'\n"); + + /* Receive data from the client expecting 0x00. */ + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + debug ("waiting for '\\0' : done\n"); + + if (buff[0] != 0) + { + error ("Remote system failed."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + bProcessing = TRUE; + Target2 = expTarget; + while (Target2 != NULL) + { + if (bDir) + { + /* Notify remote system to create a directory. */ + FileName = strrchr (Target2, '\\'); + if (FileName == NULL) + FileName = Target2; + else + FileName++; + + sprintf (buff, "D0755 0 %s\n", FileName); + + if (write (fileno (stdout), buff, strlen (buff)) < 1) + { + error ("Error sending directory status."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + chdir (Target2); + RcpSvrSend ("*", bRecursive); + chdir (".."); + } + else + { + FileName = strrchr (Target2, '\\'); + if (FileName == NULL) + FileName = Target2; + else + { + *FileName = 0; + chdir (Target2); + FileName++; + } + /* Open the file for reading. */ + FileId = _open (FileName, O_RDONLY | O_BINARY, S_IWRITE); + if (FileId == -1) + { + /* Error condition. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Cannot open file\n", FileName); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + else + { + /* Notify remote system to create a file. */ + nValue = _fstat (FileId, &statbuf); + nFileSize = statbuf.st_size; + sprintf (buff, "C0644 %d %s\n", nFileSize, FileName); + if (write (fileno (stdout), buff, strlen (buff)) < 1) + { + error ("Error sending result status."); + close (FileId); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + /* Receive data from the client expecting 0x00. */ + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data."); + close (FileId); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + if (buff[0] != 0) + { + error ("Remote system Failed."); + close (FileId); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + /* Process the contents of the file. */ + nBytesSent = 0; + while (nBytesSent < nFileSize) + { + /* Read the file. */ + nBytesRead = read (FileId, buff, blen); + if (nBytesRead <= 0) + { + /* Error condition. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Cannot read source\n", + FileName); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) + < 1) + error ("Error sending result status."); + close (FileId); + Sleep (RCP_ERR_DELAY); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + nBytesSent += nBytesRead; + if (write (fileno (stdout), buff, nBytesRead) < 1) + { + error ("Error sending file."); + close (FileId); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + } + + close (FileId); + + buff[0] = 0; + if (write (fileno (stdout), buff, 1) < 1) + { + error ("Error sending file termination."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + } + + /* Receive data from the client expecting 0x00. */ + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + if (buff[0] != 0) + { + error ("Remote system failed."); + if (bMoreFiles) + CloseTarget (hFile); + return; + } + + } + + Target2 = NextTarget (hFile, &bDir); + if (Target2 == NULL) + CloseTarget (hFile); + } + + if (bRecursive) + { + /* Recursive sends are closed by sending "E\n". */ + sprintf (buff, "E\n"); + if (write (fileno (stdout), buff, strlen (buff)) < 1) + { + error ("Error sending directory status."); + return; + } + + /* Receive data from the client. */ + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data."); + return; + } + if (buff[0] != 0) + { + error ("Remote system Failed."); + return; + } + + } + +} + +/* Process files being sent by a remote system. + TARGET is the target specified in the rcp request. + BRECURSIVE specifies if this request recurses sub-directories + on the remote system. Directories may need to be created. + BTARGDIR specifies if the target specified MUST be a directory. + + Assumptions: + All files are written as BINARY to preserve the file size and + data contained in the files. */ +void +RcpSvrRecv (char *Target, BOOL bRecursive, BOOL bTargDir) +{ + char buff[RCP_BUFFER_SIZE + 1]; + int blen = RCP_BUFFER_SIZE; + int FileId; + DWORD dwFileSize; + DWORD dwBytesRecv; + int dwBytes; + int nValue; + BOOL bMoreFiles; + HANDLE hFile = INVALID_HANDLE_VALUE; + char expTarget[MAX_PATH]; + char *Target2; + char *NewLine; + BOOL bDir; + BOOL bTarget; + BOOL bProcessing; + + debug ("RcpSvrRecv\n"); + + strcpy (expTarget, Target); + bDir = bTargDir; + bMoreFiles = ParseTarget (&hFile, expTarget, &bDir); + if (bMoreFiles) + { + Target2 = NextTarget (hFile, &bTarget); + if (Target2 != NULL) + { + /* Error condition: more than one target. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: ambiguous target\n"); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + { + error ("Error sending result status."); + } + Sleep (RCP_ERR_DELAY); + CloseTarget (hFile); + return; + } + } + CloseTarget (hFile); + bTarget = bDir; + + if (bTargDir & !bDir) + { + /* Error condition: Directory required but file specified. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Not a directory\n", expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + { + error ("Error sending result status."); + } + Sleep (RCP_ERR_DELAY); + return; + } + + if (access (expTarget, 02) != 0) + { + if (bDir || (!bDir && (errno != ENOENT))) + { + /* Error condition: Can't access the target. */ + buff[0] = 1; + if (bDir && (errno == ENOENT)) + sprintf (&buff[1], "rcp: %s: No such file or directory\n", + expTarget); + else + sprintf (&buff[1], "rcp: %s: Permission Denied\n", expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + return; + } + } + + bProcessing = TRUE; + Target2 = expTarget; + + /* Process files/directories from the remote system. */ + while (bProcessing) + { + debug ("Sending null byte ...\n"); + buff[0] = 0; + if (write (fileno (stdout), buff, 1) < 1) + { + error ("Error sending result status."); + return; + } + debug ("Sent.\n"); + + if (bDir) + { + nValue = chdir (Target2); + if (nValue == -1) + { + /* Error condition. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: No such file or directory\n", + expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + return; + } + } + + debug ("waiting for data.\n"); + + /* Receive data from the client + File/dir specification ends in a '\n', so read byte by byte + until one is reached or a '\0' is received. */ + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data.");; + return; + } + + debug ("got %d bytes.\n", dwBytes); + debug ("got: %d (%c)\n", buff[0], buff[0]); + + /* Process the file or directory specification. */ + switch (buff[0]) + { + case 0: + case 1: + /* Finished processing. */ + return; + + case 'E': + /* Finished with current directory. Backup to the + parent directory. */ + + Target2 = ".."; + bDir = TRUE; + continue; + + case 'T': + /* This is permissions data related to the -p option. + Just ignore it. */ + continue; + + case 'D': + /* A directory is being identified. */ + + bDir = TRUE; + Target2 = strtok (buff, " "); + Target2 = strtok (NULL, " "); + Target2 = strtok (NULL, " "); + NewLine = strchr (Target2, 0x0a); + *NewLine = 0; + strcpy (expTarget, Target2); + Target2 = expTarget; + + if (access (Target2, 02) != 0) + { + if (errno != ENOENT) + { + /* Error condition: Can't access directory. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Directory access failure %d\n", + expTarget, errno); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < + 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + return; + } + /* Create directory. */ + nValue = mkdir (Target2); + if (nValue == -1) + { + /* Error condition: Can't create directory. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s: Directory creation failed\n", + expTarget); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + return; + } + } + continue; + + case 'C': + /* A file is being identified. */ + if (bTarget) + { + Target2 = strtok (buff, " "); + Target2 = strtok (NULL, " "); + Target2 = strtok (NULL, " "); + NewLine = strchr (Target2, 0x0a); + *NewLine = 0; + strcpy (expTarget, Target2); + Target2 = expTarget; + } + + bDir = FALSE; + /* Open the file for writing. */ + FileId = + _open (Target2, _O_WRONLY | _O_TRUNC | _O_CREAT | _O_BINARY, + _S_IWRITE); + if (FileId == -1) + { + /* Error condition. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s :Cannot open file\n", Target2); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error sending result status."); + Sleep (RCP_ERR_DELAY); + return; + } + break; + + default: + return; + } + + dwFileSize = atol (&buff[6]); + if (debugFlag) + fprintf (stderr, "Receiving file %s of size %lu.\n", Target2, dwFileSize); + + buff[0] = 0; + if (write (fileno (stdout), buff, 1) < 1) + { + error ("Error sending result status."); + close (FileId); + return; + } + + /* Process the file being transferred. */ + dwBytesRecv = 0; + /* If file size=0, expect 1 byte 0x00. */ + if (dwFileSize == 0) + { + if ((dwBytes = RcpReceive (buff, blen)) == -1) + { + error ("Cannot receive client data."); + close (FileId); + return; + } + else if (buff[0] != 0) + error ("Received data for zero length file"); + } + else + { + while (dwBytesRecv < dwFileSize) + { + /* Receive data from the client. */ + if ((dwBytes = read (fileno (stdin), buff, blen)) == -1) + { + error ("Cannot receive client data."); + close (FileId); + return; + } + + dwBytesRecv += dwBytes; + + /* Write the data to the file. */ + nValue = write (FileId, buff, dwBytes); + + if (nValue != dwBytes) + { + /* Error condition: write failure. */ + buff[0] = 1; + sprintf (&buff[1], "rcp: %s :Cannot write to file\n", + Target2); + if (write (fileno (stdout), buff, strlen (&buff[1]) + 1) < 1) + error ("Error writing error status."); + Sleep (RCP_ERR_DELAY); + close (FileId); + return; + } + } + } + + close (FileId); + } + + return; +} + +/* Determines what type of rcp is being + requested and processes it accordingly. + + Valid rcp requests are in the form: + rcp -t [-d] [-r] [-p] target + rcp -f [r] [-p] target + + NOTE: The -p option is being ignored since there is not a good + correlation between UNIX and NT when it comes to file + permissions and ownership. */ +int +rcp_main (int argc, char **argv) +{ + int i; + char *HomeDir; + + BOOL bTargDir = FALSE; + BOOL bSvrRecv = FALSE; + BOOL bSvrSend = FALSE; + BOOL bRecursive = FALSE; + + /* Get the current working directory. */ + HomeDir = getcwd (NULL, MAX_PATH); + + i = 1; + for (; argv[i] && argv[i][0] == '-'; i++) + { + switch (argv[i][1]) + { + case 'd': + /* Target must be directory. */ + bTargDir = TRUE; + break; + + case 't': + /* rcp is receiving files. */ + bSvrRecv = TRUE; + break; + + case 'f': + /* rcp is sending files. */ + bSvrSend = TRUE; + break; + + case 'p': + /* Preserve Permissions. This option is ignored for now. */ + break; + + case 'r': + /* Recursive send/recv. */ + bRecursive = TRUE; + break; + + default: + fprintf (stderr, "wrong args\n"); + exit (1); + } + } + + if (!bSvrRecv && !bSvrSend) + { + error ("Invalid args"); + exit (1); + } + + if (bSvrRecv) + { + if (bRecursive) + bTargDir = TRUE; + + RcpSvrRecv (argv[i], bRecursive, bTargDir); + } + else + RcpSvrSend (argv[i], bRecursive); + + /* Make sure we end up where we started. */ + chdir (HomeDir); + free (HomeDir); + return 0; +} + +int +main (int argc, char **argv) +{ + return rcp_main (argc, argv); +} Property changes on: trunk/cegcc/tools/rcp/rcp.c ___________________________________________________________________ Name: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |