1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * ws protocol handler plugin for sshd demo 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Written in 2010-2019 by Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * This file is made available under the Creative Commons CC0 1.0 7d4afb5ceSopenharmony_ci * Universal Public Domain Dedication. 8d4afb5ceSopenharmony_ci * 9d4afb5ceSopenharmony_ci * The person who associated a work with this deed has dedicated 10d4afb5ceSopenharmony_ci * the work to the public domain by waiving all of his or her rights 11d4afb5ceSopenharmony_ci * to the work worldwide under copyright law, including all related 12d4afb5ceSopenharmony_ci * and neighboring rights, to the extent allowed by law. You can copy, 13d4afb5ceSopenharmony_ci * modify, distribute and perform the work, even for commercial purposes, 14d4afb5ceSopenharmony_ci * all without asking permission. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * These test plugins are intended to be adapted for use in your code, which 17d4afb5ceSopenharmony_ci * may be proprietary. So unlike the library itself, they are licensed 18d4afb5ceSopenharmony_ci * Public Domain. 19d4afb5ceSopenharmony_ci */ 20d4afb5ceSopenharmony_ci 21d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 22d4afb5ceSopenharmony_ci#if !defined(LWS_DLL) 23d4afb5ceSopenharmony_ci#define LWS_DLL 24d4afb5ceSopenharmony_ci#endif 25d4afb5ceSopenharmony_ci#if !defined(LWS_INTERNAL) 26d4afb5ceSopenharmony_ci#define LWS_INTERNAL 27d4afb5ceSopenharmony_ci#endif 28d4afb5ceSopenharmony_ci#include <libwebsockets.h> 29d4afb5ceSopenharmony_ci#endif 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_ci#include <lws-ssh.h> 32d4afb5ceSopenharmony_ci 33d4afb5ceSopenharmony_ci#include <string.h> 34d4afb5ceSopenharmony_ci#include <stdlib.h> 35d4afb5ceSopenharmony_ci#include <errno.h> 36d4afb5ceSopenharmony_ci#include <fcntl.h> 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci#define TEST_SERVER_KEY_PATH "/etc/lws-test-sshd-server-key" 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_cistruct per_vhost_data__lws_sshd_demo { 41d4afb5ceSopenharmony_ci const struct lws_protocols *ssh_base_protocol; 42d4afb5ceSopenharmony_ci int privileged_fd; 43d4afb5ceSopenharmony_ci}; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci/* 46d4afb5ceSopenharmony_ci * This is a copy of the lws ssh test public key, you can find it in 47d4afb5ceSopenharmony_ci * /usr[/local]/share/libwebsockets-test-server/lws-ssh-test-keys.pub 48d4afb5ceSopenharmony_ci * and the matching private key there too in .../lws-ssh-test-keys 49d4afb5ceSopenharmony_ci * 50d4afb5ceSopenharmony_ci * If the vhost with this protocol is using localhost:2222, you can test with 51d4afb5ceSopenharmony_ci * the matching private key like this: 52d4afb5ceSopenharmony_ci * 53d4afb5ceSopenharmony_ci * ssh -p 2222 -i /usr/local/share/libwebsockets-test-server/lws-ssh-test-keys anyuser@127.0.0.1 54d4afb5ceSopenharmony_ci * 55d4afb5ceSopenharmony_ci * These keys are distributed for testing! Don't use them on a real system 56d4afb5ceSopenharmony_ci * unless you want anyone with a copy of lws to access it. 57d4afb5ceSopenharmony_ci */ 58d4afb5ceSopenharmony_cistatic const char *authorized_key = 59d4afb5ceSopenharmony_ci "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCnWiP+c+kSD6Lk+C6NA9KruApa45sbt" 60d4afb5ceSopenharmony_ci "94/dxT0bCITlAA/+PBk6mR1lwWgXYozOMdrHrqx34piqDyXnc4HabqCaOm/FrYhkCPL8z" 61d4afb5ceSopenharmony_ci "a26PMYqteSosuwKv//5iT6ZWhNnsMwExBwtV6MIq0MxAeWqxRnYNWpNM8iN6sFzkdG/YF" 62d4afb5ceSopenharmony_ci "dyHrIBTgwzM77NLCMl6GEkJErRCFppC2SwYxGa3BRrgUwX3LkV8HpMIaYHFo1Qgj7Scqm" 63d4afb5ceSopenharmony_ci "HwS2R75SOqi2aOWDpKjznARg9JgzDWSQi4seBMV2oL0BTwJANSDf+p0sQLsaKGJhpVpBQ" 64d4afb5ceSopenharmony_ci "yS2wUeyuGyytupWzEluQrajMZq52iotcogv5BfeulfTTFbJP4kuHOsSP0lsQ2lpMDQANS" 65d4afb5ceSopenharmony_ci "HEvXxzHJLDLXM9gXJzwJ+ZiRt6R+bfmP1nfN3MiWtxcIbBanWwQK6xTCKBe4wPaKta5EU" 66d4afb5ceSopenharmony_ci "6wsLPeakOIVzoeaOu/HsbtPZlwX0Mu/oUFcfKyKAhlkU15MOAIEfUPo8Yh52bWMlIlpZa" 67d4afb5ceSopenharmony_ci "4xWbLMGw3GrsrPPdcsAauyqvY4/NjjWQbWhP1SuUfvv5709PIiOUjVKK2HUwmR1ouch6X" 68d4afb5ceSopenharmony_ci "MQGXfMR1h1Wjvc+bkNs17gCIrQnFilAZLC3Sm3Opiz/4LO99Hw448G0RM2vQn0mJE46w" 69d4afb5ceSopenharmony_ci "Eu/B10U6Jf4Efojhh1dk85BD1LTIb+N3Q== ssh-test-key@lws"; 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_cienum states { 72d4afb5ceSopenharmony_ci SSH_TEST_GREET, 73d4afb5ceSopenharmony_ci SSH_TEST_PRESSED, 74d4afb5ceSopenharmony_ci SSH_TEST_DONE, 75d4afb5ceSopenharmony_ci}; 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_cistatic const char * const strings[] = 78d4afb5ceSopenharmony_ci { 79d4afb5ceSopenharmony_ci /* SSH_TEST_GREET */ 80d4afb5ceSopenharmony_ci "Thanks for logging to lws sshd server demo.\n\r" 81d4afb5ceSopenharmony_ci "\n\r" 82d4afb5ceSopenharmony_ci "This demo is very simple, it waits for you to press\n\r" 83d4afb5ceSopenharmony_ci "a key, and acknowledges it. Then press another key\n\r" 84d4afb5ceSopenharmony_ci "and it will exit. But actually that demos the basic\n\r" 85d4afb5ceSopenharmony_ci "sshd functions underneath. You can use the ops struct\n\r" 86d4afb5ceSopenharmony_ci "members to add a pty / shell or whatever you want.\n\r" 87d4afb5ceSopenharmony_ci "\n\r" 88d4afb5ceSopenharmony_ci "Press a key...\n\r", 89d4afb5ceSopenharmony_ci 90d4afb5ceSopenharmony_ci /* SSH_TEST_PRESSED */ 91d4afb5ceSopenharmony_ci "Thanks for pressing a key. Press another to exit.\n\r", 92d4afb5ceSopenharmony_ci 93d4afb5ceSopenharmony_ci /* SSH_TEST_DONE */ 94d4afb5ceSopenharmony_ci "Bye!\n\r" 95d4afb5ceSopenharmony_ci }; 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_cistruct sshd_instance_priv { 98d4afb5ceSopenharmony_ci struct lws *wsi; 99d4afb5ceSopenharmony_ci enum states state; 100d4afb5ceSopenharmony_ci const char *ptr; 101d4afb5ceSopenharmony_ci int pos; 102d4afb5ceSopenharmony_ci int len; 103d4afb5ceSopenharmony_ci}; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_cistatic void 106d4afb5ceSopenharmony_cienter_state(struct sshd_instance_priv *priv, enum states state) 107d4afb5ceSopenharmony_ci{ 108d4afb5ceSopenharmony_ci priv->state = state; 109d4afb5ceSopenharmony_ci priv->ptr = strings[state]; 110d4afb5ceSopenharmony_ci priv->pos = 0; 111d4afb5ceSopenharmony_ci priv->len = (int)strlen(priv->ptr); 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci lws_callback_on_writable(priv->wsi); 114d4afb5ceSopenharmony_ci} 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci/* ops: channel lifecycle */ 117d4afb5ceSopenharmony_ci 118d4afb5ceSopenharmony_cistatic int 119d4afb5ceSopenharmony_cissh_ops_channel_create(struct lws *wsi, void **_priv) 120d4afb5ceSopenharmony_ci{ 121d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci priv = malloc(sizeof(struct sshd_instance_priv)); 124d4afb5ceSopenharmony_ci *_priv = priv; 125d4afb5ceSopenharmony_ci if (!priv) 126d4afb5ceSopenharmony_ci return 1; 127d4afb5ceSopenharmony_ci 128d4afb5ceSopenharmony_ci memset(priv, 0, sizeof(*priv)); 129d4afb5ceSopenharmony_ci priv->wsi = wsi; 130d4afb5ceSopenharmony_ci 131d4afb5ceSopenharmony_ci return 0; 132d4afb5ceSopenharmony_ci} 133d4afb5ceSopenharmony_ci 134d4afb5ceSopenharmony_cistatic int 135d4afb5ceSopenharmony_cissh_ops_channel_destroy(void *_priv) 136d4afb5ceSopenharmony_ci{ 137d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv = _priv; 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci free(priv); 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci return 0; 142d4afb5ceSopenharmony_ci} 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci/* ops: IO */ 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_cistatic int 147d4afb5ceSopenharmony_cissh_ops_tx_waiting(void *_priv) 148d4afb5ceSopenharmony_ci{ 149d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv = _priv; 150d4afb5ceSopenharmony_ci 151d4afb5ceSopenharmony_ci if (priv->state == SSH_TEST_DONE && 152d4afb5ceSopenharmony_ci priv->pos == priv->len) 153d4afb5ceSopenharmony_ci return -1; /* exit */ 154d4afb5ceSopenharmony_ci 155d4afb5ceSopenharmony_ci if (priv->pos != priv->len) 156d4afb5ceSopenharmony_ci return LWS_STDOUT; 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci return 0; 159d4afb5ceSopenharmony_ci} 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_cistatic size_t 162d4afb5ceSopenharmony_cissh_ops_tx(void *_priv, int stdch, uint8_t *buf, size_t len) 163d4afb5ceSopenharmony_ci{ 164d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv = _priv; 165d4afb5ceSopenharmony_ci size_t chunk = len; 166d4afb5ceSopenharmony_ci 167d4afb5ceSopenharmony_ci if (stdch != LWS_STDOUT) 168d4afb5ceSopenharmony_ci return 0; 169d4afb5ceSopenharmony_ci 170d4afb5ceSopenharmony_ci if ((size_t)(priv->len - priv->pos) < chunk) 171d4afb5ceSopenharmony_ci chunk = (size_t)(priv->len - priv->pos); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci if (!chunk) 174d4afb5ceSopenharmony_ci return 0; 175d4afb5ceSopenharmony_ci 176d4afb5ceSopenharmony_ci memcpy(buf, priv->ptr + priv->pos, chunk); 177d4afb5ceSopenharmony_ci priv->pos += (int)chunk; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci if (priv->state == SSH_TEST_DONE && priv->pos == priv->len) { 180d4afb5ceSopenharmony_ci /* 181d4afb5ceSopenharmony_ci * we are sending the last thing we want to send 182d4afb5ceSopenharmony_ci * before exiting. Make it ask again at ssh_ops_tx_waiting() 183d4afb5ceSopenharmony_ci * and we will exit then, after this has been sent 184d4afb5ceSopenharmony_ci */ 185d4afb5ceSopenharmony_ci lws_callback_on_writable(priv->wsi); 186d4afb5ceSopenharmony_ci } 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci return chunk; 189d4afb5ceSopenharmony_ci} 190d4afb5ceSopenharmony_ci 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_cistatic int 193d4afb5ceSopenharmony_cissh_ops_rx(void *_priv, struct lws *wsi, const uint8_t *buf, uint32_t len) 194d4afb5ceSopenharmony_ci{ 195d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv = _priv; 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci if (priv->state < SSH_TEST_DONE) 198d4afb5ceSopenharmony_ci enter_state(priv, priv->state + 1); 199d4afb5ceSopenharmony_ci else 200d4afb5ceSopenharmony_ci return -1; 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci return 0; 203d4afb5ceSopenharmony_ci} 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci/* ops: storage for the (autogenerated) persistent server key */ 206d4afb5ceSopenharmony_ci 207d4afb5ceSopenharmony_cistatic size_t 208d4afb5ceSopenharmony_cissh_ops_get_server_key(struct lws *wsi, uint8_t *buf, size_t len) 209d4afb5ceSopenharmony_ci{ 210d4afb5ceSopenharmony_ci struct per_vhost_data__lws_sshd_demo *vhd = 211d4afb5ceSopenharmony_ci (struct per_vhost_data__lws_sshd_demo *) 212d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 213d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 214d4afb5ceSopenharmony_ci int n; 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci if (lseek(vhd->privileged_fd, 0, SEEK_SET) < 0) 217d4afb5ceSopenharmony_ci return 0; 218d4afb5ceSopenharmony_ci n = (int)read(vhd->privileged_fd, buf, (unsigned int)len); 219d4afb5ceSopenharmony_ci if (n < 0) { 220d4afb5ceSopenharmony_ci lwsl_err("%s: read failed: %d\n", __func__, n); 221d4afb5ceSopenharmony_ci n = 0; 222d4afb5ceSopenharmony_ci } 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci return (size_t)n; 225d4afb5ceSopenharmony_ci} 226d4afb5ceSopenharmony_ci 227d4afb5ceSopenharmony_cistatic size_t 228d4afb5ceSopenharmony_cissh_ops_set_server_key(struct lws *wsi, uint8_t *buf, size_t len) 229d4afb5ceSopenharmony_ci{ 230d4afb5ceSopenharmony_ci struct per_vhost_data__lws_sshd_demo *vhd = 231d4afb5ceSopenharmony_ci (struct per_vhost_data__lws_sshd_demo *) 232d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 233d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 234d4afb5ceSopenharmony_ci int n; 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ci n = (int)write(vhd->privileged_fd, buf, (unsigned int)len); 237d4afb5ceSopenharmony_ci if (n < 0) { 238d4afb5ceSopenharmony_ci lwsl_err("%s: read failed: %d\n", __func__, errno); 239d4afb5ceSopenharmony_ci n = 0; 240d4afb5ceSopenharmony_ci } 241d4afb5ceSopenharmony_ci 242d4afb5ceSopenharmony_ci return (size_t)n; 243d4afb5ceSopenharmony_ci} 244d4afb5ceSopenharmony_ci 245d4afb5ceSopenharmony_ci/* ops: auth */ 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_cistatic int 248d4afb5ceSopenharmony_cissh_ops_is_pubkey_authorized(const char *username, const char *type, 249d4afb5ceSopenharmony_ci const uint8_t *peer, int peer_len) 250d4afb5ceSopenharmony_ci{ 251d4afb5ceSopenharmony_ci char *aps, *p, *ps; 252d4afb5ceSopenharmony_ci int n = (int)strlen(type), alen = 2048, ret = 2, len; 253d4afb5ceSopenharmony_ci size_t s = 0; 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci lwsl_info("%s: checking pubkey for %s\n", __func__, username); 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci s = strlen(authorized_key) + 1; 258d4afb5ceSopenharmony_ci 259d4afb5ceSopenharmony_ci aps = malloc(s); 260d4afb5ceSopenharmony_ci if (!aps) { 261d4afb5ceSopenharmony_ci lwsl_notice("OOM 1\n"); 262d4afb5ceSopenharmony_ci goto bail_p1; 263d4afb5ceSopenharmony_ci } 264d4afb5ceSopenharmony_ci memcpy(aps, authorized_key, s); 265d4afb5ceSopenharmony_ci 266d4afb5ceSopenharmony_ci /* we only understand RSA */ 267d4afb5ceSopenharmony_ci if (strcmp(type, "ssh-rsa")) { 268d4afb5ceSopenharmony_ci lwsl_notice("type is not ssh-rsa\n"); 269d4afb5ceSopenharmony_ci goto bail_p1; 270d4afb5ceSopenharmony_ci } 271d4afb5ceSopenharmony_ci p = aps; 272d4afb5ceSopenharmony_ci 273d4afb5ceSopenharmony_ci if (strncmp(p, type, (unsigned int)n)) { 274d4afb5ceSopenharmony_ci lwsl_notice("lead-in string does not match %s\n", type); 275d4afb5ceSopenharmony_ci goto bail_p1; 276d4afb5ceSopenharmony_ci } 277d4afb5ceSopenharmony_ci 278d4afb5ceSopenharmony_ci p += n; 279d4afb5ceSopenharmony_ci if (*p != ' ') { 280d4afb5ceSopenharmony_ci lwsl_notice("missing space at end of lead-in\n"); 281d4afb5ceSopenharmony_ci goto bail_p1; 282d4afb5ceSopenharmony_ci } 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci p++; 285d4afb5ceSopenharmony_ci ps = malloc((unsigned int)alen); 286d4afb5ceSopenharmony_ci if (!ps) { 287d4afb5ceSopenharmony_ci lwsl_notice("OOM 2\n"); 288d4afb5ceSopenharmony_ci free(aps); 289d4afb5ceSopenharmony_ci goto bail; 290d4afb5ceSopenharmony_ci } 291d4afb5ceSopenharmony_ci len = lws_b64_decode_string(p, ps, alen); 292d4afb5ceSopenharmony_ci free(aps); 293d4afb5ceSopenharmony_ci if (len < 0) { 294d4afb5ceSopenharmony_ci lwsl_notice("key too big\n"); 295d4afb5ceSopenharmony_ci goto bail; 296d4afb5ceSopenharmony_ci } 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_ci if (peer_len > len) { 299d4afb5ceSopenharmony_ci lwsl_notice("peer_len %d bigger than decoded len %d\n", 300d4afb5ceSopenharmony_ci peer_len, len); 301d4afb5ceSopenharmony_ci goto bail; 302d4afb5ceSopenharmony_ci } 303d4afb5ceSopenharmony_ci 304d4afb5ceSopenharmony_ci /* 305d4afb5ceSopenharmony_ci * once we are past that, it's the same <len32>name 306d4afb5ceSopenharmony_ci * <len32>E<len32>N that the peer sends us 307d4afb5ceSopenharmony_ci */ 308d4afb5ceSopenharmony_ci if (memcmp(peer, ps, (unsigned int)peer_len)) { 309d4afb5ceSopenharmony_ci lwsl_info("%s: factors mismatch, rejecting key\n", __func__); 310d4afb5ceSopenharmony_ci goto bail; 311d4afb5ceSopenharmony_ci } 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_ci lwsl_info("pubkey authorized\n"); 314d4afb5ceSopenharmony_ci 315d4afb5ceSopenharmony_ci ret = 0; 316d4afb5ceSopenharmony_cibail: 317d4afb5ceSopenharmony_ci free(ps); 318d4afb5ceSopenharmony_ci 319d4afb5ceSopenharmony_ci return ret; 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_cibail_p1: 322d4afb5ceSopenharmony_ci if (aps) 323d4afb5ceSopenharmony_ci free(aps); 324d4afb5ceSopenharmony_ci 325d4afb5ceSopenharmony_ci return 1; 326d4afb5ceSopenharmony_ci} 327d4afb5ceSopenharmony_ci 328d4afb5ceSopenharmony_cistatic int 329d4afb5ceSopenharmony_cissh_ops_shell(void *_priv, struct lws *wsi, lws_ssh_finish_exec finish, void *finish_handle) 330d4afb5ceSopenharmony_ci{ 331d4afb5ceSopenharmony_ci struct sshd_instance_priv *priv = _priv; 332d4afb5ceSopenharmony_ci 333d4afb5ceSopenharmony_ci /* for this demo, we don't open a real shell */ 334d4afb5ceSopenharmony_ci 335d4afb5ceSopenharmony_ci enter_state(priv, SSH_TEST_GREET); 336d4afb5ceSopenharmony_ci 337d4afb5ceSopenharmony_ci return 0; 338d4afb5ceSopenharmony_ci} 339d4afb5ceSopenharmony_ci 340d4afb5ceSopenharmony_ci/* ops: banner */ 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_cistatic size_t 343d4afb5ceSopenharmony_cissh_ops_banner(char *buf, size_t max_len, char *lang, size_t max_lang_len) 344d4afb5ceSopenharmony_ci{ 345d4afb5ceSopenharmony_ci int n = lws_snprintf(buf, max_len, "\n" 346d4afb5ceSopenharmony_ci " |\\---/| lws-ssh Test Server\n" 347d4afb5ceSopenharmony_ci " | o_o | SSH Terminal Server\n" 348d4afb5ceSopenharmony_ci " \\_^_/ Copyright (C) 2017 Crash Barrier Ltd\n\n"); 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci lws_snprintf(lang, max_lang_len, "en/US"); 351d4afb5ceSopenharmony_ci 352d4afb5ceSopenharmony_ci return (size_t)n; 353d4afb5ceSopenharmony_ci} 354d4afb5ceSopenharmony_ci 355d4afb5ceSopenharmony_cistatic void 356d4afb5ceSopenharmony_cissh_ops_disconnect_reason(uint32_t reason, const char *desc, 357d4afb5ceSopenharmony_ci const char *desc_lang) 358d4afb5ceSopenharmony_ci{ 359d4afb5ceSopenharmony_ci lwsl_notice("DISCONNECT reason 0x%X, %s (lang %s)\n", reason, desc, 360d4afb5ceSopenharmony_ci desc_lang); 361d4afb5ceSopenharmony_ci} 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci 364d4afb5ceSopenharmony_cistatic const struct lws_ssh_ops ssh_ops = { 365d4afb5ceSopenharmony_ci .channel_create = ssh_ops_channel_create, 366d4afb5ceSopenharmony_ci .channel_destroy = ssh_ops_channel_destroy, 367d4afb5ceSopenharmony_ci .tx_waiting = ssh_ops_tx_waiting, 368d4afb5ceSopenharmony_ci .tx = ssh_ops_tx, 369d4afb5ceSopenharmony_ci .rx = ssh_ops_rx, 370d4afb5ceSopenharmony_ci .get_server_key = ssh_ops_get_server_key, 371d4afb5ceSopenharmony_ci .set_server_key = ssh_ops_set_server_key, 372d4afb5ceSopenharmony_ci .set_env = NULL, 373d4afb5ceSopenharmony_ci .pty_req = NULL, 374d4afb5ceSopenharmony_ci .child_process_io = NULL, 375d4afb5ceSopenharmony_ci .child_process_terminated = NULL, 376d4afb5ceSopenharmony_ci .exec = NULL, 377d4afb5ceSopenharmony_ci .shell = ssh_ops_shell, 378d4afb5ceSopenharmony_ci .is_pubkey_authorized = ssh_ops_is_pubkey_authorized, 379d4afb5ceSopenharmony_ci .banner = ssh_ops_banner, 380d4afb5ceSopenharmony_ci .disconnect_reason = ssh_ops_disconnect_reason, 381d4afb5ceSopenharmony_ci .server_string = "SSH-2.0-Libwebsockets", 382d4afb5ceSopenharmony_ci .api_version = 2, 383d4afb5ceSopenharmony_ci}; 384d4afb5ceSopenharmony_ci 385d4afb5ceSopenharmony_cistatic int 386d4afb5ceSopenharmony_cicallback_lws_sshd_demo(struct lws *wsi, enum lws_callback_reasons reason, 387d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 388d4afb5ceSopenharmony_ci{ 389d4afb5ceSopenharmony_ci struct per_vhost_data__lws_sshd_demo *vhd = 390d4afb5ceSopenharmony_ci (struct per_vhost_data__lws_sshd_demo *) 391d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 392d4afb5ceSopenharmony_ci lws_get_protocol(wsi)); 393d4afb5ceSopenharmony_ci 394d4afb5ceSopenharmony_ci switch (reason) { 395d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 396d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 397d4afb5ceSopenharmony_ci lws_get_protocol(wsi), 398d4afb5ceSopenharmony_ci sizeof(struct per_vhost_data__lws_sshd_demo)); 399d4afb5ceSopenharmony_ci if (!vhd) 400d4afb5ceSopenharmony_ci return 0; 401d4afb5ceSopenharmony_ci /* 402d4afb5ceSopenharmony_ci * During this we still have the privs / caps we were started 403d4afb5ceSopenharmony_ci * with. So open an fd on the server key, either just for read 404d4afb5ceSopenharmony_ci * or for creat / trunc if doesn't exist. This allows us to 405d4afb5ceSopenharmony_ci * deal with it down /etc/.. when just after this we will lose 406d4afb5ceSopenharmony_ci * the privileges needed to read / write /etc/... 407d4afb5ceSopenharmony_ci */ 408d4afb5ceSopenharmony_ci vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, O_RDONLY); 409d4afb5ceSopenharmony_ci if (vhd->privileged_fd == -1) 410d4afb5ceSopenharmony_ci vhd->privileged_fd = lws_open(TEST_SERVER_KEY_PATH, 411d4afb5ceSopenharmony_ci O_CREAT | O_TRUNC | O_RDWR, 0600); 412d4afb5ceSopenharmony_ci if (vhd->privileged_fd == -1) { 413d4afb5ceSopenharmony_ci lwsl_warn("%s: Can't open %s\n", __func__, 414d4afb5ceSopenharmony_ci TEST_SERVER_KEY_PATH); 415d4afb5ceSopenharmony_ci return 0; 416d4afb5ceSopenharmony_ci } 417d4afb5ceSopenharmony_ci break; 418d4afb5ceSopenharmony_ci 419d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_DESTROY: 420d4afb5ceSopenharmony_ci if (vhd) 421d4afb5ceSopenharmony_ci close(vhd->privileged_fd); 422d4afb5ceSopenharmony_ci break; 423d4afb5ceSopenharmony_ci 424d4afb5ceSopenharmony_ci case LWS_CALLBACK_VHOST_CERT_AGING: 425d4afb5ceSopenharmony_ci break; 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci case LWS_CALLBACK_EVENT_WAIT_CANCELLED: 428d4afb5ceSopenharmony_ci break; 429d4afb5ceSopenharmony_ci 430d4afb5ceSopenharmony_ci default: 431d4afb5ceSopenharmony_ci if (!vhd->ssh_base_protocol) { 432d4afb5ceSopenharmony_ci vhd->ssh_base_protocol = lws_vhost_name_to_protocol( 433d4afb5ceSopenharmony_ci lws_get_vhost(wsi), 434d4afb5ceSopenharmony_ci "lws-ssh-base"); 435d4afb5ceSopenharmony_ci if (vhd->ssh_base_protocol) 436d4afb5ceSopenharmony_ci user = lws_adjust_protocol_psds(wsi, 437d4afb5ceSopenharmony_ci vhd->ssh_base_protocol->per_session_data_size); 438d4afb5ceSopenharmony_ci } 439d4afb5ceSopenharmony_ci 440d4afb5ceSopenharmony_ci if (vhd->ssh_base_protocol) 441d4afb5ceSopenharmony_ci return vhd->ssh_base_protocol->callback(wsi, reason, 442d4afb5ceSopenharmony_ci user, in, len); 443d4afb5ceSopenharmony_ci else 444d4afb5ceSopenharmony_ci lwsl_notice("can't find lws-ssh-base\n"); 445d4afb5ceSopenharmony_ci break; 446d4afb5ceSopenharmony_ci } 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci return 0; 449d4afb5ceSopenharmony_ci} 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_LWS_SSHD_DEMO \ 452d4afb5ceSopenharmony_ci { \ 453d4afb5ceSopenharmony_ci "lws-sshd-demo", \ 454d4afb5ceSopenharmony_ci callback_lws_sshd_demo, \ 455d4afb5ceSopenharmony_ci 0, \ 456d4afb5ceSopenharmony_ci 1024, /* rx buf size must be >= permessage-deflate rx size */ \ 457d4afb5ceSopenharmony_ci 0, (void *)&ssh_ops, 0 \ 458d4afb5ceSopenharmony_ci } 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 461d4afb5ceSopenharmony_ci 462d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_sshd_demo_protocols[] = { 463d4afb5ceSopenharmony_ci LWS_PLUGIN_PROTOCOL_LWS_SSHD_DEMO 464d4afb5ceSopenharmony_ci}; 465d4afb5ceSopenharmony_ci 466d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_sshd_demo = { 467d4afb5ceSopenharmony_ci .hdr = { 468d4afb5ceSopenharmony_ci "lws sshd demo", 469d4afb5ceSopenharmony_ci "lws_protocol_plugin", 470d4afb5ceSopenharmony_ci LWS_BUILD_HASH, 471d4afb5ceSopenharmony_ci LWS_PLUGIN_API_MAGIC 472d4afb5ceSopenharmony_ci }, 473d4afb5ceSopenharmony_ci 474d4afb5ceSopenharmony_ci .protocols = lws_sshd_demo_protocols, 475d4afb5ceSopenharmony_ci .count_protocols = LWS_ARRAY_SIZE(lws_sshd_demo_protocols), 476d4afb5ceSopenharmony_ci .extensions = NULL, 477d4afb5ceSopenharmony_ci .count_extensions = 0, 478d4afb5ceSopenharmony_ci}; 479d4afb5ceSopenharmony_ci 480d4afb5ceSopenharmony_ci#endif 481