X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=sidebyside;f=Usermode%2FApplications%2Ftelnetd_src%2Fmain.c;h=fa852506a155637f88c54dbb3d41449922005523;hb=13078002b01ee4f63eb2001d2ef479a2a006ea32;hp=8a66ad7a9512d399f30bc5d3fd68c63cd0d49c49;hpb=bfacdd3b71576cf6ceaa83352d3a7d162adb75e1;p=tpg%2Facess2.git diff --git a/Usermode/Applications/telnetd_src/main.c b/Usermode/Applications/telnetd_src/main.c index 8a66ad7a..fa852506 100644 --- a/Usermode/Applications/telnetd_src/main.c +++ b/Usermode/Applications/telnetd_src/main.c @@ -1,16 +1,39 @@ /* + * Acess2 Telnet Server (TCP server test case) + * - By John Hodge (thePowersGang) + * + * main.c + * - All */ #include #include -#include #include +#include +#include +#include +#include +#include +#include // === TYPES === +enum eTelnetMode +{ + MODE_DATA, + MODE_IAC, + MODE_WILL, + MODE_WONT, + MODE_DO, + MODE_DONT, + MODE_SUBNEG_OPTION, + MODE_SUBNEG_DATA, + MODE_SUBNEG_IAC, +}; + typedef struct sClient { + enum eTelnetMode Mode; int Socket; - int stdout; - int stdin; + int pty; } tClient; // === PROTOTYPES === @@ -18,6 +41,7 @@ void EventLoop(void); void Server_NewClient(int FD); void HandleServerBoundData(tClient *Client); void HandleClientBoundData(tClient *Client); +void HandleOptionRequest(tClient *Client, int Option, bool Value, bool IsRequest); // === GLOBALS === // --- Configuration --- @@ -41,7 +65,7 @@ int main(int argc, char *argv[]) int addrtype = Net_ParseAddress("10.0.2.10", data); int port = 23; giServerFD = Net_OpenSocket(addrtype, data, "tcps"); - ioctl(giServerFD, 4, &port); // Set port and start listening + _SysIOCtl(giServerFD, 4, &port); // Set port and start listening } // Event loop @@ -50,17 +74,17 @@ int main(int argc, char *argv[]) return 0; } +static void FD_SET_MAX(fd_set *set, int fd, int *maxfd) +{ + FD_SET(fd, set); + if(*maxfd < fd) *maxfd = fd; +} + void EventLoop(void) { fd_set fds; int maxfd; - void FD_SET_MAX(fd_set *set, int fd, int *maxfd) - { - FD_SET(fd, set); - if(*maxfd < fd) *maxfd = fd; - } - for( ;; ) { FD_ZERO(&fds); @@ -70,14 +94,13 @@ void EventLoop(void) for( int i = 0; i < giConfig_MaxClients; i ++ ) { if( gaClients[i].Socket == 0 ) continue ; - _SysDebug("Socket = %i, stdout = %i", - gaClients[i].Socket, gaClients[i].stdout); FD_SET_MAX(&fds, gaClients[i].Socket, &maxfd); - FD_SET_MAX(&fds, gaClients[i].stdout, &maxfd); + FD_SET_MAX(&fds, gaClients[i].pty, &maxfd); } // Select! - select( maxfd+1, &fds, NULL, NULL, NULL ); + int rv = _SysSelect( maxfd+1, &fds, NULL, NULL, NULL, 0 ); + _SysDebug("Select return %i", rv); // Check events if( FD_ISSET(giServerFD, &fds) ) @@ -91,7 +114,7 @@ void EventLoop(void) // Handle client data HandleServerBoundData(&gaClients[i]); } - if( FD_ISSET(gaClients[i].stdout, &fds) ) + if( FD_ISSET(gaClients[i].pty, &fds) ) { // Handle output from terminal HandleClientBoundData(&gaClients[i]); @@ -102,13 +125,13 @@ void EventLoop(void) void Server_NewClient(int FD) { - tClient *clt; + tClient *clt = NULL; // TODO: Is this done in the IPStack? if( giNumClients == giConfig_MaxClients ) { // Open, reject - close( _SysOpenChild(FD, "", O_RDWR) ); + _SysClose( _SysOpenChild(FD, "", OPENFLAG_READ) ); return ; } @@ -120,30 +143,165 @@ void Server_NewClient(int FD) break; } } + assert(clt); // Accept the connection - clt->Socket = _SysOpenChild(FD, "", O_RDWR); + clt->Socket = _SysOpenChild(FD, "", OPENFLAG_READ|OPENFLAG_WRITE); giNumClients ++; - // Create stdin/stdout - clt->stdin = open("/Devices/fifo/anon", O_RDWR); - clt->stdout = open("/Devices/fifo/anon", O_RDWR); + // Create PTY + // TODO: Use PTYs + clt->pty = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); + if( clt->pty < 0 ) { + perror("Unable to create/open PTY"); + _SysDebug("Unable to create/open PTY: %s", strerror(errno)); + _SysClose(clt->Socket); + clt->Socket = 0; + return ; + } + // - Initialise + { + _SysIOCtl(clt->pty, PTY_IOCTL_SETID, "telnetd#"); + struct ptymode mode = {.InputMode = 0, .OutputMode=0}; + struct ptydims dims = {.W = 80, .H = 25}; + _SysIOCtl(clt->pty, PTY_IOCTL_SETMODE, &mode); + _SysIOCtl(clt->pty, PTY_IOCTL_SETDIMS, &dims); + } // TODO: Arguments and envp { - int fds[3] = {clt->stdin, clt->stdout, clt->stdout}; - const char *argv[] = {NULL}; - _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds); + char pty_path[] = "/Devices/pts/telnetd000"; + _SysIOCtl(clt->pty, PTY_IOCTL_GETID, pty_path+13); + int clientfd = _SysOpen(pty_path, OPENFLAG_READ|OPENFLAG_WRITE); + if(clientfd < 0) { + perror("Unable to open login PTY"); + _SysClose(clt->Socket); + _SysClose(clt->pty); + clt->Socket = 0; + return ; + } + _SysDebug("Using client PTY %s", pty_path); + int fds[3] = {clientfd, clientfd, clientfd}; + const char *argv[] = {"login", NULL}; + _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds, NULL); + _SysClose(clientfd); } } void HandleServerBoundData(tClient *Client) { - char buf[BUFSIZ]; - int len; - - len = read(Client->Socket, buf, BUFSIZ); - if( len <= 0 ) return ; - write(Client->stdin, buf, len); + uint8_t buf[BUFSIZ]; + size_t len; + + _SysDebug("Client %p", Client); + len = _SysRead(Client->Socket, buf, BUFSIZ); + _SysDebug("%i bytes for %p", len, Client); + if( len == 0 ) return ; + if( len == -1 ) { + return ; + } + // handle options + // int last_flush = 0; + for( int i = 0; i < len; i ++ ) + { + switch(Client->Mode) + { + case MODE_IAC: + Client->Mode = MODE_DATA; + switch(buf[i]) + { + case 240: // End of subnegotiation parameters + _SysDebug("End Subnegotiation"); + break; + case 241: // Nop + break; + case 242: // SYNCH + case 243: // NVT Break + case 244: // Function 'IP' (Ctrl-C) + + break; + case 245: // Function 'AO' + case 246: // Function 'AYT' + case 247: // Function 'EC' + case 248: // Function 'EL' + case 249: // GA Signal + break; + case 250: // Subnegotation + _SysDebug("Subnegotiation"); + // TODO: Get option ID, and then cache until 'END SB' (240) + Client->Mode = MODE_SUBNEG_OPTION; + break; + case 251: // WILL + Client->Mode = MODE_WILL; + break; + case 252: // WONT + Client->Mode = MODE_WONT; + break; + case 253: // DO + Client->Mode = MODE_DO; + break; + case 254: // DONT + Client->Mode = MODE_DONT; + break; + case 255: // Literal 255 + _SysWrite(Client->pty, buf+i, 1); + break; + } + break; + case MODE_WILL: + _SysDebug("Option %i WILL", buf[i]); + HandleOptionRequest(Client, buf[i], true, false); + Client->Mode = MODE_DATA; + break; + case MODE_WONT: + _SysDebug("Option %i WONT", buf[i]); + HandleOptionRequest(Client, buf[i], false, false); + Client->Mode = MODE_DATA; + break; + case MODE_DO: + _SysDebug("Option %i DO", buf[i]); + HandleOptionRequest(Client, buf[i], true, true); + Client->Mode = MODE_DATA; + break; + case MODE_DONT: + _SysDebug("Option %i DONT", buf[i]); + HandleOptionRequest(Client, buf[i], false, true); + Client->Mode = MODE_DATA; + break; + case MODE_SUBNEG_OPTION: + _SysDebug("Option %i subnegotation", buf[i]); + Client->Mode = MODE_SUBNEG_DATA; + break; + case MODE_SUBNEG_IAC: + switch(buf[i]) + { + case 240: // End subnegotation + // TODO: Handle subnegotation data + Client->Mode = MODE_DATA; + break; + case 255: + // TODO: Literal 255 + Client->Mode = MODE_SUBNEG_DATA; + break; + default: + _SysDebug("Unexpected %i in SUBNEG IAC", buf[i]); + Client->Mode = MODE_SUBNEG_DATA; + break; + } + case MODE_SUBNEG_DATA: + if( buf[i] == 255 ) + Client->Mode = MODE_SUBNEG_IAC; + else + ;//_SysWrite(Client->pty, buf+i, 1); + break; + + case MODE_DATA: + if( buf[i] == 255 ) + Client->Mode = MODE_IAC; + else + _SysWrite(Client->pty, buf+i, 1); + break; + } + } } void HandleClientBoundData(tClient *Client) @@ -151,8 +309,18 @@ void HandleClientBoundData(tClient *Client) char buf[BUFSIZ]; int len; - len = read(Client->stdout, buf, BUFSIZ); + len = _SysRead(Client->pty, buf, BUFSIZ); if( len <= 0 ) return ; - write(Client->Socket, buf, len); + _SysWrite(Client->Socket, buf, len); +} + +void HandleOptionRequest(tClient *Client, int Option, bool Value, bool IsRequest) +{ + switch(Option) + { + default: + _SysDebug("Unknown option %i", Option); + break; + } }