4/22/98 revised 7/20/98 revised 3/18/99 E. Brady Trexler trexler@aecom.yu.edu http:\\magicbus.aecom.yu.edu ftp:\\magicbus.aecom.yu.edu I have been wanting to write a telnet daemon for Windows NT for quite some time. By a stroke of good fortune, I came across code from a number of people and sources that have allowed the development of a minimal telnet server. Thanks to Daniel Carey (whawke@multipro.com http://users.multipro.com/whawke) for TDCService, a class that installs, uninstalls, and starts itself as a service. Also, thanks to François Piette (francois.piette@ping.be and http://www.rtfm.be/fpiette/indexuk.htm) for his suite of internet components and demo telnet server and client programs. A lot of the code in the VTSession (VTTelnetSession.cpp) and VTDaemon (VTTelnetDaemon.cpp) classes is directly from his code. I have also written a command line telnet client, using François Piette's components. These programs and all of the source code is freeware. What I had hoped is that those of you who are interested would help me to improve this telnet daemon. There are some features that I could not get working, so the advice of more experienced programmers would be most appreciated. Feel free to modify anything. But please let me know. Hopefully a community of us could create a server that rivals the commercial ones available. USAGE AND INSTALLATION NOTES: Copy telnetd.exe (the telnet daemon), telnetd.ini (to specify the listening port) and vttelnet.exe (the command line client) to %SystemRoot%\system32. From the command line, type "telnetd -i" to install the service. "telnetd -u" uninstalls it, and "telnetd -v" gives extended information. In the "Services" applet in Control Panel, set the startup for VTrex Telnet Server to Automatic, Logon as SYSTEM Account. Allow Service to Interact with Desktop should be off. To allow users to log in, create a new group whose members have the "Logon as Service" right. In telnetd.ini, set port=XX, with no spaces. To change the listening port, change telnetd.ini appropriately and restart the service. Users can logon from any client, but some work better with VTrex Telnet Daemon than others. I have tested this server with a few clients (unix, qvt3, telnet (that comes with NT)), and with some quirks, they all work fine. If a user starts a non-console application, that program is non-accessible to any user. The locally logged in user will not be able to terminate this app from TaskManager. This is bad. Someone could use all machine memory by starting a whole bunch of non-console apps. Also, any drives the remote user mounts will not be unmounted, unless they do so explicitly before logging off. These drives will be accessible to all other users, but no one else will be able to unmount them. They will not appear as network drives but as local drives, i.e., you don't know to which shared drive they are connected. Note that these problems are due to WindowsNT architecture, not really from any fault of my own. Command line programs that do not use STDIN or STDOUT will have problems with this server. Some apps write directly to the console screen buffer, so that when STDIN and STDOUT are redirected, they can still prompt the user for info. Since the console that that apps started in a telnet session see is invisible, it appears as though the app is hung. FTP, for instance, behaves erratically. Once you get to the password prompt, it hangs, because it is looking for input at the invisible console. PROGRAMMING NOTES: The implementation of the daemon is as follows: A VTDaemon class is created in main(). This class owns a TWSocket that listens to the telnet port. main() contains a loop that does nothing but send a WM_TERMINATE message to TApplication. This message just sets TApplication->Terminated to true, so TApplication->Run() will exit, and the app will close. TApplication->Run() is not called in this program, so the message is essentially ignored. This is a silly hack that is necessary to start the message loop of TApplication. Otherwise, this program does nothing, and calling TApplication->Run() would create forms and do a bunch of other stuff we don't want. A request for a session creates a new instance of VTSession, which duplicates the socket, freeing VTDaemon to listen again. If "SERVICE" is defined when compiling, VTSession prompts for a username and password. After user validation, the WindowsNT command interpreter (cmd.exe) is started as a sub-process in the security context of the logged on user. The STDERR, STDIN, and STDOUT for cmd have all been redirected to the parent process (thanks to win32.hlp from MicroSoft for the code that does this). Two threads are started that listen for output from cmd (from STDERR and STDOUT) and one thread waits for input from the socket and feeds that to cmd through STDIN. If the cmd interpreter is closed (by responding to exit command), the STDOUT listening thread exits, and closes the session by sending a message to VTDaemon. Each logged on user requires over a megabyte of memory, so I limited MAXSESSIONS to 5 in VTTelnetDaemon.h. I used Borland C++ Builder 3.0 for this project because it allowed me to create console applications that use VCL components (hence, a TApplication object exists), but no visible HWND is created. This is ideal for a service. I had built the code previously in version 1.0 of Builder, but it creates this HWND, creating a button on the taskbar, and that is a nuisance. Moreover, the service must be able to interact with the desktop if compiled with ver 1.0. You must have installed the freeware components from F. Piette in order to compile these programs. His web site is http://www.rtfm.be/fpiette/indexuk.htm. NICE FEATURES THAT I HAVEN'T DONE YET: A command line interpreter that was written specifically for the purpose of telnet would be a great benefit. This interpreter would not allow any non-console apps to be invoked. A unix-style shell with process control would allow the user to "start" background apps, and kill them. Maybe someday...