Expand admin SSH command capabilities

Add per-session history, tab completion, interactive prompts, and
bounded input handling. Support deferred lifecycle and host-key actions
after output drains, and document the expanded administration workflow.
This commit is contained in:
2026-08-30 18:34:01 +02:00
parent 0a1bbd6782
commit c2c11fee4e
14 changed files with 699 additions and 224 deletions
+47 -1
View File
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <string.h>
#include "admin_ssh_console.h"
#include "esp_console.h"
#include "mbedtls/base64.h"
#include "secure_random.h"
@@ -207,6 +208,18 @@ static bool parse_session_id(const char *text, uint32_t *session_id)
static int replace_host_key(bool reset)
{
if (admin_ssh_console_dispatch_is_remote()) {
esp_err_t deferred = admin_ssh_console_dispatch_defer(
reset ? ADMIN_SSH_DEFER_HOST_KEY_RESET : ADMIN_SSH_DEFER_HOST_KEY_ROTATE, 0U);
if (deferred != ESP_OK) {
printf("Could not schedule SSH host-key replacement: %s\n",
esp_err_to_name(deferred));
return 1;
}
printf("SSH host-key %s scheduled after output drains; all SSH sessions will close.\n",
reset ? "reset" : "rotation");
return 0;
}
ssh_security_metadata_t before = {0};
bool had_before = ssh_security_get_metadata(&before) == ESP_OK;
esp_err_t error = ssh_transport_replace_host_key(reset);
@@ -256,6 +269,16 @@ static int command_ssh(int argc, char **argv)
return 0;
}
if (argc == 2 && strcmp(argv[1], "stop") == 0) {
if (admin_ssh_console_dispatch_is_remote()) {
esp_err_t deferred = admin_ssh_console_dispatch_defer(
ADMIN_SSH_DEFER_STOP, 0U);
if (deferred != ESP_OK) {
printf("Could not schedule SSH stop: %s\n", esp_err_to_name(deferred));
return 1;
}
printf("SSH stop scheduled after output drains; all SSH sessions will close.\n");
return 0;
}
esp_err_t error = ssh_transport_stop();
if (error != ESP_OK) {
printf("Could not stop SSH: %s\n", esp_err_to_name(error));
@@ -282,7 +305,30 @@ static int command_ssh(int argc, char **argv)
printf("Session ID must be a nonzero decimal integer.\n");
return 1;
}
esp_err_t error = ssh_transport_disconnect(session_id);
esp_err_t error;
if (admin_ssh_console_dispatch_is_remote()) {
ssh_transport_snapshot_t snapshot;
error = ssh_transport_get_snapshot(&snapshot);
bool found = false;
if (error == ESP_OK) {
for (size_t index = 0U; index < SSH_TRANSPORT_MAX_SESSIONS; ++index) {
if (snapshot.sessions[index].active &&
snapshot.sessions[index].session_id == session_id) {
found = true;
break;
}
}
if (!found) {
error = ESP_ERR_NOT_FOUND;
}
}
if (error == ESP_OK) {
error = admin_ssh_console_dispatch_defer(
ADMIN_SSH_DEFER_DISCONNECT, session_id);
}
} else {
error = ssh_transport_disconnect(session_id);
}
if (error != ESP_OK) {
printf("Could not disconnect SSH session: %s\n", esp_err_to_name(error));
return 1;