diff --git a/src/hasp_config.h b/src/hasp_config.h index c819141c..7555ec9c 100644 --- a/src/hasp_config.h +++ b/src/hasp_config.h @@ -18,6 +18,9 @@ const char F_CONFIG_USER[] PROGMEM = "user"; const char F_CONFIG_PASS[] PROGMEM = "pass"; const char F_CONFIG_SSID[] PROGMEM = "ssid"; const char F_CONFIG_GROUP[] PROGMEM = "group"; +const char F_CONFIG_BAUD[] PROGMEM = "baud"; +const char F_CONFIG_LOG[] PROGMEM = "log"; +const char F_CONFIG_PROTOCOL[] PROGMEM = "proto"; const char F_GUI_ROTATION[] PROGMEM = "rotation"; const char F_GUI_TICKPERIOD[] PROGMEM = "tickperiod"; const char F_GUI_IDLEPERIOD1[] PROGMEM = "idle1"; @@ -30,13 +33,11 @@ const char F_DEBUG_TELEPERIOD[] PROGMEM = "teleperiod"; const char HASP_CONFIG_FILE[] PROGMEM = "/config.json"; void configSetup(JsonDocument & settings); -void configLoop(void); void configStop(void); void configSetConfig(JsonObject & settings); void configGetConfig(JsonDocument & settings); void configWriteConfig(); -bool configChanged(void); void configOutput(const JsonObject & settings); bool configSet(int8_t & value, const JsonVariant & setting, const char * name); diff --git a/src/hasp_telnet.cpp b/src/hasp_telnet.cpp index f6132b90..828f1adc 100644 --- a/src/hasp_telnet.cpp +++ b/src/hasp_telnet.cpp @@ -1,27 +1,31 @@ +#include "hasp_conf.h" +#if HASP_USE_TELNET > 0 + #include "Arduino.h" #include "ArduinoJson.h" -#include "hasp_conf.h" #include "hasp_log.h" #include "hasp_debug.h" #include "hasp_config.h" #include "hasp_dispatch.h" #include "hasp_telnet.h" -#if HASP_USE_TELNET > 0 - #if defined(ARDUINO_ARCH_ESP32) #include #else #include #endif -//#define telnetInputMax 128; // Size of user input buffer for user telnet session +#define TELNET_UNAUTHENTICATED 0 +#define TELNET_USERNAME_OK 10 +#define TELNET_USERNAME_NOK 99 +#define TELNET_AUTHENTICATED 255 + +uint8_t telnetLoginState = TELNET_UNAUTHENTICATED; WiFiServer * telnetServer; //(23); WiFiClient * telnetClient; uint8_t telnetEnabled = true; // Enable telnet debug output uint8_t telnetLoginAttempt = 0; // Initial attempt -uint8_t telnetLoginState = 0; // Unauthenticated uint8_t telnetInputIndex = 0; // Empty buffer char telnetInputBuffer[128]; @@ -34,7 +38,7 @@ bool telnetExitCommand() telnetClient->remoteIP().toString().c_str()); debugPrintln(buffer); telnetClient->stop(); - telnetLoginState = 0; // Unauthenticated + telnetLoginState = TELNET_UNAUTHENTICATED; telnetInputIndex = 0; // Empty buffer telnetLoginAttempt = 0; // Initial attempt return true; @@ -43,6 +47,104 @@ bool telnetExitCommand() } } +void telnetAcceptClient() +{ + if(telnetClient) { + telnetClient->stop(); // client disconnected + } + *telnetClient = telnetServer->available(); // ready for new client + char buffer[128]; + snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: Client connected from %s"), + telnetClient->remoteIP().toString().c_str()); + debugPrintln(buffer); + snprintf_P(buffer, sizeof(buffer), PSTR("\r\nUsername: ")); + telnetClient->print(buffer); + telnetLoginState = TELNET_UNAUTHENTICATED; + telnetInputIndex = 0; // reset input buffer index + telnetLoginAttempt = 0; // Initial attempt +} + +void telnetProcessInput() +{ + char telnetInputByte = telnetClient->read(); // Read client byte + // debugPrintln(String("telnet in: 0x") + String(telnetInputByte, HEX)); + switch(telnetInputByte) { + case 0x01: + case 0x03: + case 0x05: + case 0xff: + case 0xfe: + case 0xfd: + case 0xfc: + case 0xfb: + case 0xf1: + case 0x1f: + case 10: + telnetInputIndex = 0; + break; + case 0x08: // Backspace + if(telnetInputIndex > 0) { + telnetInputIndex--; + } + break; + case 13: + telnetInputBuffer[telnetInputIndex] = 0; // null terminate our char array + switch(telnetLoginState) { + case TELNET_UNAUTHENTICATED: { + char buffer[128]; + snprintf_P(buffer, sizeof(buffer), PSTR("Password: %c%c%c"), 0xFF, 0xFB, 0x01); // Hide characters + telnetClient->print(buffer); + snprintf_P(buffer, sizeof(buffer), PSTR("admin")); + telnetLoginState = + strcmp(telnetInputBuffer, buffer) == 0 ? TELNET_USERNAME_OK : TELNET_USERNAME_NOK; + break; + } + case TELNET_USERNAME_OK: + case TELNET_USERNAME_NOK: { + char buffer[128]; + snprintf_P(buffer, sizeof(buffer), PSTR("%c%c%c"), 0xFF, 0xFC, 0x01); // Show characters + telnetClient->println(buffer); + snprintf_P(buffer, sizeof(buffer), PSTR("haspadmin")); + if(telnetLoginState == TELNET_AUTHENTICATED && strcmp(telnetInputBuffer, buffer) == 0) { + telnetLoginState = TELNET_AUTHENTICATED; + telnetLoginAttempt = 0; // Initial attempt + telnetClient->println(debugHaspHeader()); + snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: Client login from %s"), + telnetClient->remoteIP().toString().c_str()); + debugPrintln(buffer); + } else { + telnetLoginState = TELNET_UNAUTHENTICATED; + telnetLoginAttempt++; // Subsequent attempt + snprintf_P(buffer, sizeof(buffer), PSTR("Authorization failed!\r\n")); + telnetClient->println(buffer); + snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: %%Incorrect login attempt from %s"), + telnetClient->remoteIP().toString().c_str()); + errorPrintln(buffer); + if(telnetLoginAttempt >= 3) { + telnetExitCommand(); + } else { + snprintf_P(buffer, sizeof(buffer), PSTR("Username: ")); + telnetClient->print(buffer); + } + } + break; + } + default: + if(telnetInputIndex > 0 && !telnetExitCommand()) { + dispatchCommand(telnetInputBuffer); + } + } + telnetInputIndex = 0; + break; + default: + // If we have room left in our buffer add the current byte + if(telnetInputIndex < sizeof(telnetInputBuffer) - 1 && telnetInputByte >= 0x20) { + telnetInputBuffer[telnetInputIndex] = telnetInputByte; + telnetInputIndex++; + } + } +} + void telnetSetup(const JsonObject & settings) { telnetSetConfig(settings); @@ -65,119 +167,28 @@ void telnetLoop() if(telnetServer && telnetServer->hasClient()) { // client is connected if(!*telnetClient || !telnetClient->connected()) { - if(telnetClient) { - telnetClient->stop(); // client disconnected - } - *telnetClient = telnetServer->available(); // ready for new client - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: Client connected from %s"), - telnetClient->remoteIP().toString().c_str()); - debugPrintln(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("\r\nUsername: ")); - telnetClient->print(buffer); - telnetLoginState = 0; // Unauthenticated - telnetInputIndex = 0; // reset input buffer index - telnetLoginAttempt = 0; // Initial attempt + telnetAcceptClient(); } else { telnetServer->available().stop(); // have client, block new connections } } // Handle client input from telnet connection. - if(telnetClient && telnetClient->connected() && telnetClient->available()) { // client input processing - - if(telnetClient->available()) { - char telnetInputByte = telnetClient->read(); // Read client byte - // debugPrintln(String("telnet in: 0x") + String(telnetInputByte, HEX)); - switch(telnetInputByte) { - case 0x01: - case 0x03: - case 0x05: - case 0xff: - case 0xfe: - case 0xfd: - case 0xfc: - case 0xfb: - case 0xf1: - case 0x1f: - case 10: - telnetInputIndex = 0; - break; - case 0x08: // Backspace - if(telnetInputIndex > 0) { - telnetInputIndex--; - } - break; - case 13: - telnetInputBuffer[telnetInputIndex] = 0; // null terminate our char array - switch(telnetLoginState) { - case 0: { - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("Password: %c%c%c"), 0xFF, 0xFB, 0x01); - telnetClient->print(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("admin")); - telnetLoginState = - strcmp(telnetInputBuffer, buffer) == 0 ? 10 : 99; // Username OK=1 or NOK=99 - break; - } - case 10: - case 99: { - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("%c%c%c"), 0xFF, 0xFC, 0x01); - telnetClient->println(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("haspadmin")); - if(telnetLoginState == 10 && strcmp(telnetInputBuffer, buffer) == 0) { // Authenticated - telnetLoginState = 255; // Authenticated - telnetLoginAttempt = 0; // Initial attempt - telnetClient->println(debugHaspHeader()); - snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: Client login from %s"), - telnetClient->remoteIP().toString().c_str()); - debugPrintln(buffer); - } else { - telnetLoginState = 0; // Unauthorized - telnetLoginAttempt++; // Subsequent attempt - snprintf_P(buffer, sizeof(buffer), PSTR("Authorization failed!\r\n")); - telnetClient->println(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("TELNET: %%Incorrect login attempt from %s"), - telnetClient->remoteIP().toString().c_str()); - errorPrintln(buffer); - if(telnetLoginAttempt >= 3) { - telnetExitCommand(); - } else { - snprintf_P(buffer, sizeof(buffer), PSTR("Username: ")); - telnetClient->print(buffer); - } - } - break; - } - default: - if(telnetInputIndex > 0 && !telnetExitCommand()) { - dispatchCommand(telnetInputBuffer); - } - } - telnetInputIndex = 0; - break; - default: - // If we have room left in our buffer add the current byte - if(telnetInputIndex < sizeof(telnetInputBuffer) - 1 && telnetInputByte >= 0x20) { - telnetInputBuffer[telnetInputIndex] = telnetInputByte; - telnetInputIndex++; - } - } - } + if(telnetClient && telnetClient->connected() && telnetClient->available()) { + telnetProcessInput(); // client input processing } } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void telnetPrintln(const char * msg) { - if(telnetEnabled && telnetClient && telnetClient->connected() && telnetLoginState == 255) { + if(telnetEnabled && telnetClient && telnetClient->connected() && telnetLoginState == TELNET_AUTHENTICATED) { telnetClient->println(msg); } } void telnetPrint(const char * msg) { - if(telnetEnabled && telnetClient && telnetClient->connected() && telnetLoginState == 255) { + if(telnetEnabled && telnetClient && telnetClient->connected() && telnetLoginState == TELNET_AUTHENTICATED) { telnetClient->print(msg); } }