/*
- * File: TelnetD.c
- *
* Abstract: a simple telnet 'daemon' for Windows hosts.
*
* Compiled & run successfully using MSVC 5.0 under Windows95 (requires
* Use freely, no copyrights.
* Use Linux.
*
+ * Parts Copyright Steven Edwards
+ * Public Domain
+ *
* TODO:
* - access control
* - will/won't handshake
- * - (run as) Windows NT service
+ * - Unify Debugging output and return StatusCodes
*/
-#include <stdio.h>
-#include <windows.h>
-
-/*
-** macro definitions
-*/
-#define TELNET_PORT (23)
-
-#define BUFSIZE (4096)
-#define USERID_SIZE (64)
-#define CTRLC (3)
-#define BS (8)
-#define CR (13)
-#define LF (10)
-#define DEL (127)
-
-#define IAC (255)
-#define DONT (254)
-#define WONT (253)
-#define DO (252)
-#define WILL (251)
-#define ECHO (1)
-
-#define HANDSHAKE_TIMEOUT (3)
-
-/*
-** types
-*/
+#include "telnetd.h"
-typedef struct client_s
+#define telnetd_printf printf
+#if 0
+static inline int telnetd_printf(const char *format, ...);
{
- char userID[USERID_SIZE];
- int socket;
- BOOLEAN bTerminate;
- BOOLEAN bReadFromPipe;
- BOOLEAN bWriteToPipe;
- HANDLE hProcess;
- DWORD dwProcessId;
- HANDLE hChildStdinWr;
- HANDLE hChildStdoutRd;
-} client_t;
-
-typedef enum
-{
- NoEcho = 0,
- Echo = 1,
- Password = 2
-} EchoMode;
+ printf(format,...);
+ syslog (6, format);
+}
+#endif
-/*
-** Local data
-*/
+/* Local data */
static BOOLEAN bShutdown = 0;
static BOOLEAN bSocketInterfaceInitialised = 0;
-
static int sock;
-/*
-** Forward function declarations
-*/
-static BOOL WINAPI Cleanup(DWORD dwControlType);
-static void WaitForConnect(void);
-static BOOLEAN StartSocketInterface(void);
-static void CreateSocket(void);
-static void UserLogin(int client_socket);
-static DWORD WINAPI UserLoginThread(LPVOID);
-static int DoTelnetHandshake(int sock);
-static int ReceiveLine(int sock, char *buffer, int len, EchoMode echo);
-static void RunShell(client_t *client);
-static BOOL CreateChildProcess(const char *);
-static DWORD WINAPI MonitorChildThread(LPVOID);
-static DWORD WINAPI WriteToPipeThread(LPVOID);
-static DWORD WINAPI ReadFromPipeThread(LPVOID);
-static void TerminateShell(client_t *client);
-static VOID ErrorExit(LPTSTR);
-
-
-/*
-** main
-*/
-DWORD telnetd_main()
+/* In the future, some options might be passed here to handle
+ * authentication options in the registry or command line
+ * options passed to the service
+ *
+ * Once you are ready to turn on the service
+ * rename this function
+ * int kickoff_telnetd(void)
+ */
+int main(int argc, char **argv)
{
+ printf("Attempting to start Simple TelnetD\n");
+
+// DetectPlatform();
SetConsoleCtrlHandler(Cleanup, 1);
- if (!StartSocketInterface()) {
+ if (!StartSocketInterface())
ErrorExit("Unable to start socket interface\n");
- }
CreateSocket();
return 0;
}
-/*
-** Cleanup
-*/
+/* Cleanup */
static BOOL WINAPI Cleanup(DWORD dwControlType)
{
if (bSocketInterfaceInitialised) {
- printf("Cleanup...\n");
+ telnetd_printf("Cleanup...\n");
WSACleanup();
}
return 0;
}
-/*
-** StartSocketInterface
-*/
+/* StartSocketInterface */
static BOOLEAN StartSocketInterface(void)
{
WORD wVersionRequested;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
- printf("requested winsock version not supported\n");
+ telnetd_printf("requested winsock version not supported\n");
return 0;
}
bSocketInterfaceInitialised = 1; /* for ErrorExit function */
- if ( wsaData.wVersion != wVersionRequested) {
- printf("requested winsock version not supported\n");
- return 0;
- }
- printf("TelnetD, using %s\n", wsaData.szDescription);
+ if ( wsaData.wVersion != wVersionRequested)
+ ErrorExit("requested winsock version not supported\n");
+
+ telnetd_printf("TelnetD, using %s\n", wsaData.szDescription);
return 1;
}
-/*
-** CreateSocket
-*/
+/* CreateSocket */
static void CreateSocket(void)
{
struct sockaddr_in sa;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (sock < 0) {
+ if (sock < 0)
ErrorExit("Cannot create socket");
- }
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(TELNET_PORT);
- if (bind(sock, (struct sockaddr*) &sa, sizeof(sa)) != 0) {
+
+ if (bind(sock, (struct sockaddr*) &sa, sizeof(sa)) != 0)
ErrorExit("Cannot bind address to socket");
- }
}
-/*
-** WaitForConnect
-*/
+/* WaitForConnect */
static void WaitForConnect(void)
{
struct sockaddr_in sa;
int new_sock;
- if (listen(sock, 1) < 0) {
+ if (listen(sock, 1) < 0)
ErrorExit("Cannot listen on socket");
- }
if ((new_sock = accept(sock, (struct sockaddr*) &sa, NULL)) < 0) {
fprintf(stderr, "Failed to accept incoming call\n");
} else {
- printf("user connected on socket %d, port %d, address %lx\n", new_sock,
+ telnetd_printf("user connected on socket %d, port %d, address %lx\n", new_sock,
htons(sa.sin_port), sa.sin_addr.s_addr);
UserLogin(new_sock);
}
}
-
-/*
-** Function: UserLogin
-*/
+/* Function: UserLogin */
static void UserLogin(int client_socket)
{
DWORD threadID;
client_t *client = malloc(sizeof(client_t));
- if (client == NULL) {
+ if (client == NULL)
ErrorExit("failed to allocate memory for client");
- }
client->socket = client_socket;
CreateThread(NULL, 0, UserLoginThread, client, 0, &threadID);
}
-/*
-** Function: UserLoginThread
-*/
+/* Function: UserLoginThread */
static DWORD WINAPI UserLoginThread(LPVOID data)
{
client_t *client = (client_t *) data;
char welcome[256];
char hostname[64] = "Unknown";
char *pwdPrompt = "\r\npass:";
- char *logonPrompt = "\r\nLogin OK, please wait...";
- char *byebye = "\r\nWrong! bye bye...\r\n";
+ //char *logonPrompt = "\r\nLogin OK, please wait...";
+ //char *byebye = "\r\nWrong! bye bye...\r\n";
char userID[USERID_SIZE];
char password[USERID_SIZE];
int received;
return 0;
}
received = ReceiveLine(client->socket, password, sizeof(password), Password );
+
+#if 0
if (received < 0) {
closesocket(client->socket);
free(client);
*terminator = '\0';
}
}
-
+#endif
/* TODO: do authentication here */
- printf("User '%s' logged on\n", userID);
+ telnetd_printf("User '%p' logged on\n", userID);
+#if 0
strcpy(client->userID, userID);
if (send(client->socket, logonPrompt, strlen(logonPrompt), 0) < 0) {
closesocket(client->socket);
free(client);
return 0;
}
+#endif
RunShell(client);
return 0;
}
-/*
-** Function: DoTelnetHandshake
-*/
+/* Function: DoTelnetHandshake */
static int DoTelnetHandshake(int sock)
{
int retval;
int received;
fd_set set;
struct timeval timeout = { HANDSHAKE_TIMEOUT, 0 };
- unsigned char will_echo[3] = { IAC, WILL, ECHO };
+
+ char will_echo[]=
+ IAC DONT ECHO
+ IAC WILL ECHO
+ IAC WILL NAWS
+ IAC WILL SUPPRESS_GO_AHEAD
+ IAC DO SUPPRESS_GO_AHEAD
+ IAC DONT NEWENVIRON
+ IAC WONT NEWENVIRON
+ IAC WONT LINEMODE
+ IAC DO NAWS
+ IAC SB TERMINAL_TYPE "\x01" IAC SE
+ ;
+
unsigned char client_reply[256];
- if (send(sock, (const char *) will_echo, sizeof(will_echo), 0) < 0) {
+ if (send(sock, will_echo, sizeof(will_echo), 0) < 0) {
return -1;
}
return 0;
}
/* no error and no timeout, we have data in our sock */
- received = recv(sock, client_reply, sizeof(client_reply), 0);
+ received = recv(sock, (char *) client_reply, sizeof(client_reply), 0);
if (received <= 0) {
return -1;
}
PROCESS_INFORMATION piProcInfo;
SECURITY_ATTRIBUTES saAttr;
- const char *name = "c:\\windows\\system32\\cmd.exe";
+ const char *name = "c:\\reactos\\system32\\cmd.exe";
const char *cmd = NULL;
//const char *name = "d:\\cygwin\\bin\\bash.exe";
//const char *cmd = "d:\\cygwin\\bin\\bash.exe --login -i";
// Create the child process (the shell)
- printf("Creating child process...\n");
+ telnetd_printf("Creating child process...\n");
ZeroMemory( &si, sizeof(STARTUPINFO) );
si.cb = sizeof(STARTUPINFO);
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
- //DETACHED_PROCESS + // creation flags
+ DETACHED_PROCESS + // creation flags
CREATE_NEW_PROCESS_GROUP,
NULL, // use parent's environment
NULL, // use parent's current directory
client->hProcess = piProcInfo.hProcess;
client->dwProcessId = piProcInfo.dwProcessId;
- printf("New child created (groupid=%lu)\n", client->dwProcessId);
+ telnetd_printf("New child created (groupid=%lu)\n", client->dwProcessId);
// No longer need these in the parent...
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
+
if (!CloseHandle(hChildStdinRd))
ErrorExit("Closing handle failed");
CreateThread(NULL, 0, MonitorChildThread, client, 0, &threadID);
}
-
/*
-** Function: MonitorChildThread
-**
-** Abstract: Monitor the child (shell) process
-*/
+ * Function: MonitorChildThread
+ *
+ * Abstract: Monitor the child (shell) process
+ */
static DWORD WINAPI MonitorChildThread(LPVOID data)
{
DWORD exitCode;
client_t *client = (client_t *) data;
- printf("Monitor thread running...\n");
+ telnetd_printf("Monitor thread running...\n");
WaitForSingleObject(client->hProcess, INFINITE);
GetExitCodeProcess(client->hProcess, &exitCode);
- printf("Child process terminated with code %d\n", exitCode);
+ telnetd_printf("Child process terminated with code %lx\n", exitCode);
/* signal the other threads to give up */
client->bTerminate = TRUE;
closesocket(client->socket);
- printf("Waiting for all threads to give up..\n");
+ telnetd_printf("Waiting for all threads to give up..\n");
while (client->bWriteToPipe || client->bReadFromPipe) {
- printf(".");
+ telnetd_printf(".");
fflush(stdout);
Sleep(1000);
}
- printf("Cleanup for user '%s'\n", client->userID);
+ telnetd_printf("Cleanup for user '%s'\n", client->userID);
free(client);
return 0;
}
/*
-** Function: WriteToPipeThread
-**
-** Abstract: read data from the telnet client socket
-** and pass it on to the shell process.
-*/
+ * Function: WriteToPipeThread
+ *
+ * Abstract: read data from the telnet client socket
+ * and pass it on to the shell process.
+ */
static DWORD WINAPI WriteToPipeThread(LPVOID data)
{
int iRead;
while (!client->bTerminate) {
iRead = ReceiveLine(client->socket, chBuf, BUFSIZE, FALSE);
if (iRead < 0) {
- printf("Client disconnect\n");
+ telnetd_printf("Client disconnect\n");
break;
} else if (iRead > 0) {
if (strchr(chBuf, CTRLC)) {
GenerateConsoleCtrlEvent(CTRL_C_EVENT, client->dwProcessId);
}
if (send(client->socket, chBuf, iRead, 0) < 0) {
- printf("error writing to socket\n");
+ telnetd_printf("error writing to socket\n");
break;
}
if (! WriteFile(client->hChildStdinWr, chBuf, (DWORD) iRead, &dwWritten, NULL)) {
- printf("Error writing to pipe\n");
+ telnetd_printf("Error writing to pipe\n");
break;
}
}
}
- if (!client->bTerminate) {
+ if (!client->bTerminate)
TerminateShell(client);
- }
- printf("WriteToPipeThread terminated\n");
+ telnetd_printf("WriteToPipeThread terminated\n");
client->bWriteToPipe = FALSE;
return 0;
}
/*
-** Function: ReadFromPipeThread
-**
-** Abstract: Read data from the shell's stdout handle and
-** pass it on to the telnet client socket.
-*/
+ * Function: ReadFromPipeThread
+ *
+ * Abstract: Read data from the shell's stdout handle and
+ * pass it on to the telnet client socket.
+ */
static DWORD WINAPI ReadFromPipeThread(LPVOID data)
{
DWORD dwRead;
CHAR chBuf[BUFSIZE];
CHAR txBuf[BUFSIZE*2];
DWORD from,to;
- char warning[] = "warning: rl_prep_terminal: cannot get terminal settings";
+ //char warning[] = "warning: rl_prep_terminal: cannot get terminal settings";
client_t *client = (client_t *) data;
while (!client->bTerminate && client->bWriteToPipe) {
// Since we do not want to block, first peek...
if (PeekNamedPipe(client->hChildStdoutRd, NULL, 0, NULL, &dwAvail, NULL) == 0) {
- printf("Failed to peek in pipe\n");
+ telnetd_printf("Failed to peek in pipe\n");
break;
}
if (dwAvail) {
if( ! ReadFile( client->hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) ||
dwRead == 0) {
- printf("Failed to read from pipe\n");
+ telnetd_printf("Failed to read from pipe\n");
break;
}
for (from=0, to=0; from<dwRead; from++, to++) {
}
}
if (send(client->socket, txBuf, to, 0) < 0) {
- printf("error writing to socket\n");
+ telnetd_printf("error writing to socket\n");
break;
}
}
Sleep(100); /* Hmmm, oh well... what the heck! */
}
- if (!client->bTerminate) {
+ if (!client->bTerminate)
TerminateShell(client);
- }
- printf("ReadFromPipeThread terminated\n");
+ telnetd_printf("ReadFromPipeThread terminated\n");
client->bReadFromPipe = FALSE;
return 0;
}
-/*
-** TerminateShell
-*/
+/* TerminateShell */
static void TerminateShell(client_t *client)
{
- DWORD exitCode;
- DWORD dwWritten;
- char stop[] = "\003\r\nexit\r\n"; /* Ctrl-C + exit */
+ DWORD exitCode;
+ DWORD dwWritten;
+ char stop[] = "\003\r\nexit\r\n"; /* Ctrl-C + exit */
- GetExitCodeProcess(client->hProcess, &exitCode);
- if (exitCode == STILL_ACTIVE) {
- printf("user shell still active, send Ctrl-Break to group-id %lu\n", client->dwProcessId );
+ GetExitCodeProcess(client->hProcess, &exitCode);
- if (!GenerateConsoleCtrlEvent( CTRL_BREAK_EVENT, client->dwProcessId )) {
- printf("Failed to send Ctrl_break\n");
- }
+ if (exitCode == STILL_ACTIVE)
+ {
+ HANDLE hEvent = NULL;
+ DWORD dwWaitResult;
- Sleep(500);
+ telnetd_printf("user shell still active, send Ctrl-Break to group-id %lu\n", client->dwProcessId );
- if (!GenerateConsoleCtrlEvent( CTRL_C_EVENT, client->dwProcessId )) {
- printf("Failed to send Ctrl_C\n");
- }
+ hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
- Sleep(500);
+ if (hEvent == NULL)
+ printf("CreateEvent error\n");
- if (! WriteFile(client->hChildStdinWr, stop, sizeof(stop), &dwWritten, NULL)) {
- printf("Error writing to pipe\n");
- }
+ if (!GenerateConsoleCtrlEvent( CTRL_BREAK_EVENT, client->dwProcessId ))
+ telnetd_printf("Failed to send Ctrl_break\n");
- Sleep(500);
+ if (!GenerateConsoleCtrlEvent( CTRL_C_EVENT, client->dwProcessId ))
+ telnetd_printf("Failed to send Ctrl_C\n");
- GetExitCodeProcess(client->hProcess, &exitCode);
- if (exitCode == STILL_ACTIVE) {
- printf("user shell still active, attempt to terminate it now...\n");
- TerminateProcess(client->hProcess, 0);
+ if (!WriteFile(client->hChildStdinWr, stop, sizeof(stop), &dwWritten, NULL))
+ telnetd_printf("Error writing to pipe\n");
+
+ /* wait for our handler to be called */
+ dwWaitResult=WaitForSingleObject(hEvent, 500);
+
+ if (WAIT_FAILED==dwWaitResult)
+ telnetd_printf("WaitForSingleObject failed\n");
+
+ GetExitCodeProcess(client->hProcess, &exitCode);
+ if (exitCode == STILL_ACTIVE)
+ {
+ telnetd_printf("user shell still active, attempt to terminate it now...\n");
+
+ if (hEvent != NULL)
+ {
+ if (!CloseHandle(hEvent))
+ telnetd_printf("CloseHandle");
+ }
+ TerminateProcess(client->hProcess, 0);
+ }
+ TerminateProcess(client->hProcess, 0);
}
- }
+ TerminateProcess(client->hProcess, 0);
}
-/*
-** ErrorExit
-*/
+/* ErrorExit */
static VOID ErrorExit (LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
if (bSocketInterfaceInitialised) {
- printf("WSAGetLastError=%d\n", WSAGetLastError());
+ telnetd_printf("WSAGetLastError=%d\n", WSAGetLastError());
WSACleanup();
}
ExitProcess(0);
}
+