1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "libwebsockets.h" 26d4afb5ceSopenharmony_ci#include "lws-ssh.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci#include <string.h> 29d4afb5ceSopenharmony_ci#include <stdlib.h> 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_civoid *sshd_zalloc(size_t s) 32d4afb5ceSopenharmony_ci{ 33d4afb5ceSopenharmony_ci void *p = malloc(s); 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ci if (p) 36d4afb5ceSopenharmony_ci memset(p, 0, s); 37d4afb5ceSopenharmony_ci 38d4afb5ceSopenharmony_ci return p; 39d4afb5ceSopenharmony_ci} 40d4afb5ceSopenharmony_ci 41d4afb5ceSopenharmony_ciuint32_t 42d4afb5ceSopenharmony_cilws_g32(uint8_t **p) 43d4afb5ceSopenharmony_ci{ 44d4afb5ceSopenharmony_ci uint32_t v = 0; 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci v = (v << 8) | *((*p)++); 47d4afb5ceSopenharmony_ci v = (v << 8) | *((*p)++); 48d4afb5ceSopenharmony_ci v = (v << 8) | *((*p)++); 49d4afb5ceSopenharmony_ci v = (v << 8) | *((*p)++); 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci return v; 52d4afb5ceSopenharmony_ci} 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ciuint32_t 55d4afb5ceSopenharmony_cilws_p32(uint8_t *p, uint32_t v) 56d4afb5ceSopenharmony_ci{ 57d4afb5ceSopenharmony_ci *p++ = (uint8_t)(v >> 24); 58d4afb5ceSopenharmony_ci *p++ = (uint8_t)(v >> 16); 59d4afb5ceSopenharmony_ci *p++ = (uint8_t)(v >> 8); 60d4afb5ceSopenharmony_ci *p++ = (uint8_t)v; 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci return v; 63d4afb5ceSopenharmony_ci} 64d4afb5ceSopenharmony_ci 65d4afb5ceSopenharmony_ciint 66d4afb5ceSopenharmony_cilws_cstr(uint8_t **p, const char *s, uint32_t max) 67d4afb5ceSopenharmony_ci{ 68d4afb5ceSopenharmony_ci uint32_t n = (uint32_t)strlen(s); 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ci if (n > max) 71d4afb5ceSopenharmony_ci return 1; 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_ci lws_p32(*p, n); 74d4afb5ceSopenharmony_ci *p += 4; 75d4afb5ceSopenharmony_ci strcpy((char *)(*p), s); 76d4afb5ceSopenharmony_ci *p += n; 77d4afb5ceSopenharmony_ci 78d4afb5ceSopenharmony_ci return 0; 79d4afb5ceSopenharmony_ci} 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ciint 82d4afb5ceSopenharmony_cilws_buf(uint8_t **p, void *s, uint32_t len) 83d4afb5ceSopenharmony_ci{ 84d4afb5ceSopenharmony_ci lws_p32(*p, len); 85d4afb5ceSopenharmony_ci *p += 4; 86d4afb5ceSopenharmony_ci memcpy((char *)(*p), s, len); 87d4afb5ceSopenharmony_ci *p += len; 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci return 0; 90d4afb5ceSopenharmony_ci} 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_civoid 93d4afb5ceSopenharmony_ciwrite_task(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch, 94d4afb5ceSopenharmony_ci int task) 95d4afb5ceSopenharmony_ci{ 96d4afb5ceSopenharmony_ci pss->write_task[pss->wt_head] = (uint8_t)task; 97d4afb5ceSopenharmony_ci pss->write_channel[pss->wt_head] = ch; 98d4afb5ceSopenharmony_ci pss->wt_head = (pss->wt_head + 1) & 7; 99d4afb5ceSopenharmony_ci lws_callback_on_writable(pss->wsi); 100d4afb5ceSopenharmony_ci} 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_civoid 103d4afb5ceSopenharmony_ciwrite_task_insert(struct per_session_data__sshd *pss, struct lws_ssh_channel *ch, 104d4afb5ceSopenharmony_ci int task) 105d4afb5ceSopenharmony_ci{ 106d4afb5ceSopenharmony_ci pss->wt_tail = (pss->wt_tail - 1) & 7; 107d4afb5ceSopenharmony_ci pss->write_task[pss->wt_tail] = (uint8_t)task; 108d4afb5ceSopenharmony_ci pss->write_channel[pss->wt_tail] = ch; 109d4afb5ceSopenharmony_ci lws_callback_on_writable(pss->wsi); 110d4afb5ceSopenharmony_ci} 111d4afb5ceSopenharmony_ci 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_civoid 114d4afb5ceSopenharmony_cilws_pad_set_length(struct per_session_data__sshd *pss, void *start, uint8_t **p, 115d4afb5ceSopenharmony_ci struct lws_ssh_keys *keys) 116d4afb5ceSopenharmony_ci{ 117d4afb5ceSopenharmony_ci uint32_t len = (uint32_t)lws_ptr_diff(*p, start); 118d4afb5ceSopenharmony_ci uint8_t padc = 4, *bs = start; 119d4afb5ceSopenharmony_ci 120d4afb5ceSopenharmony_ci if (keys->full_length) 121d4afb5ceSopenharmony_ci len -= 4; 122d4afb5ceSopenharmony_ci 123d4afb5ceSopenharmony_ci if ((len + padc) & (uint32_t)(keys->padding_alignment - 1)) 124d4afb5ceSopenharmony_ci padc = (uint8_t)((uint8_t)padc + (uint8_t)(keys->padding_alignment - 125d4afb5ceSopenharmony_ci ((len + padc) & (uint32_t)(keys->padding_alignment - 1)))); 126d4afb5ceSopenharmony_ci 127d4afb5ceSopenharmony_ci bs[4] = padc; 128d4afb5ceSopenharmony_ci len += padc; 129d4afb5ceSopenharmony_ci 130d4afb5ceSopenharmony_ci if (!keys->valid) /* no crypto = pad with 00 */ 131d4afb5ceSopenharmony_ci while (padc--) 132d4afb5ceSopenharmony_ci *((*p)++) = 0; 133d4afb5ceSopenharmony_ci else { /* crypto active = pad with random */ 134d4afb5ceSopenharmony_ci lws_get_random(pss->vhd->context, *p, padc); 135d4afb5ceSopenharmony_ci (*p) += padc; 136d4afb5ceSopenharmony_ci } 137d4afb5ceSopenharmony_ci if (keys->full_length) 138d4afb5ceSopenharmony_ci len += 4; 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci lws_p32(start, len - 4); 141d4afb5ceSopenharmony_ci} 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_cistatic uint32_t 144d4afb5ceSopenharmony_cioffer(struct per_session_data__sshd *pss, uint8_t *p, uint32_t len, int first, 145d4afb5ceSopenharmony_ci int *payload_len) 146d4afb5ceSopenharmony_ci{ 147d4afb5ceSopenharmony_ci uint8_t *op = p, *lp, *end = p + len - 1; 148d4afb5ceSopenharmony_ci int n, padc = 4, keylen; 149d4afb5ceSopenharmony_ci char keyt[32]; 150d4afb5ceSopenharmony_ci uint8_t keybuf[256]; 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_ci keylen = (int)get_gen_server_key_25519(pss, keybuf, (int)sizeof(keybuf)); 153d4afb5ceSopenharmony_ci if (!keylen) { 154d4afb5ceSopenharmony_ci lwsl_notice("get_gen_server_key failed\n"); 155d4afb5ceSopenharmony_ci return 1; 156d4afb5ceSopenharmony_ci } 157d4afb5ceSopenharmony_ci lwsl_info("keylen %d\n", keylen); 158d4afb5ceSopenharmony_ci n = ed25519_key_parse(keybuf, (unsigned int)keylen, 159d4afb5ceSopenharmony_ci keyt, sizeof(keyt), NULL, NULL); 160d4afb5ceSopenharmony_ci if (n) { 161d4afb5ceSopenharmony_ci lwsl_notice("unable to parse server key: %d\n", n); 162d4afb5ceSopenharmony_ci return 1; 163d4afb5ceSopenharmony_ci } 164d4afb5ceSopenharmony_ci 165d4afb5ceSopenharmony_ci /* 166d4afb5ceSopenharmony_ci * byte SSH_MSG_KEXINIT 167d4afb5ceSopenharmony_ci * byte[16] cookie (random bytes) 168d4afb5ceSopenharmony_ci * name-list kex_algorithms 169d4afb5ceSopenharmony_ci * name-list server_host_key_algorithms 170d4afb5ceSopenharmony_ci * name-list encryption_algorithms_client_to_server 171d4afb5ceSopenharmony_ci * name-list encryption_algorithms_server_to_client 172d4afb5ceSopenharmony_ci * name-list mac_algorithms_client_to_server 173d4afb5ceSopenharmony_ci * name-list mac_algorithms_server_to_client 174d4afb5ceSopenharmony_ci * name-list compression_algorithms_client_to_server 175d4afb5ceSopenharmony_ci * name-list compression_algorithms_server_to_client 176d4afb5ceSopenharmony_ci * name-list langua->es_client_to_server 177d4afb5ceSopenharmony_ci * name-list langua->es_server_to_client 178d4afb5ceSopenharmony_ci * boolean first_kex_packet_follows 179d4afb5ceSopenharmony_ci * uint32 0 (reserved for future extension) 180d4afb5ceSopenharmony_ci */ 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci p += 5; /* msg len + padding */ 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci *p++ = SSH_MSG_KEXINIT; 185d4afb5ceSopenharmony_ci lws_get_random(pss->vhd->context, p, 16); 186d4afb5ceSopenharmony_ci p += 16; 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci /* KEX algorithms */ 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci lp = p; 191d4afb5ceSopenharmony_ci p += 4; 192d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "curve25519-sha256@libssh.org"); 193d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci /* Server Host Key Algorithms */ 196d4afb5ceSopenharmony_ci 197d4afb5ceSopenharmony_ci lp = p; 198d4afb5ceSopenharmony_ci p += 4; 199d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "%s", keyt); 200d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci /* Encryption Algorithms: C -> S */ 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci lp = p; 205d4afb5ceSopenharmony_ci p += 4; 206d4afb5ceSopenharmony_ci// n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com"); 207d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com"); 208d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci /* Encryption Algorithms: S -> C */ 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci lp = p; 213d4afb5ceSopenharmony_ci p += 4; 214d4afb5ceSopenharmony_ci// n = lws_snprintf((char *)p, end - p, "aes256-gcm@openssh.com"); 215d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "chacha20-poly1305@openssh.com"); 216d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci /* MAC Algorithms: C -> S */ 219d4afb5ceSopenharmony_ci 220d4afb5ceSopenharmony_ci lp = p; 221d4afb5ceSopenharmony_ci p += 4; 222d4afb5ceSopenharmony_ci /* bogus: chacha20 does not use MACs, but 'none' is not offered */ 223d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256"); 224d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 225d4afb5ceSopenharmony_ci 226d4afb5ceSopenharmony_ci /* MAC Algorithms: S -> C */ 227d4afb5ceSopenharmony_ci 228d4afb5ceSopenharmony_ci lp = p; 229d4afb5ceSopenharmony_ci p += 4; 230d4afb5ceSopenharmony_ci /* bogus: chacha20 does not use MACs, but 'none' is not offered */ 231d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "hmac-sha2-256"); 232d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 233d4afb5ceSopenharmony_ci 234d4afb5ceSopenharmony_ci /* Compression Algorithms: C -> S */ 235d4afb5ceSopenharmony_ci 236d4afb5ceSopenharmony_ci lp = p; 237d4afb5ceSopenharmony_ci p += 4; 238d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none"); 239d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci /* Compression Algorithms: S -> C */ 242d4afb5ceSopenharmony_ci 243d4afb5ceSopenharmony_ci lp = p; 244d4afb5ceSopenharmony_ci p += 4; 245d4afb5ceSopenharmony_ci n = lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "none"); 246d4afb5ceSopenharmony_ci p += lws_p32(lp, (uint32_t)n); 247d4afb5ceSopenharmony_ci 248d4afb5ceSopenharmony_ci if (p - op < 13 + padc + 8) 249d4afb5ceSopenharmony_ci return 0; 250d4afb5ceSopenharmony_ci 251d4afb5ceSopenharmony_ci /* Languages: C -> S */ 252d4afb5ceSopenharmony_ci 253d4afb5ceSopenharmony_ci *p++ = 0; 254d4afb5ceSopenharmony_ci *p++ = 0; 255d4afb5ceSopenharmony_ci *p++ = 0; 256d4afb5ceSopenharmony_ci *p++ = 0; 257d4afb5ceSopenharmony_ci 258d4afb5ceSopenharmony_ci /* Languages: S -> C */ 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci *p++ = 0; 261d4afb5ceSopenharmony_ci *p++ = 0; 262d4afb5ceSopenharmony_ci *p++ = 0; 263d4afb5ceSopenharmony_ci *p++ = 0; 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci /* First KEX packet coming */ 266d4afb5ceSopenharmony_ci 267d4afb5ceSopenharmony_ci *p++ = !!first; 268d4afb5ceSopenharmony_ci 269d4afb5ceSopenharmony_ci /* Reserved */ 270d4afb5ceSopenharmony_ci 271d4afb5ceSopenharmony_ci *p++ = 0; 272d4afb5ceSopenharmony_ci *p++ = 0; 273d4afb5ceSopenharmony_ci *p++ = 0; 274d4afb5ceSopenharmony_ci *p++ = 0; 275d4afb5ceSopenharmony_ci 276d4afb5ceSopenharmony_ci len = (uint32_t)lws_ptr_diff(p, op); 277d4afb5ceSopenharmony_ci if (payload_len) 278d4afb5ceSopenharmony_ci /* starts at buf + 5 and excludes padding */ 279d4afb5ceSopenharmony_ci *payload_len = (int)(len - 5); 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci /* we must give at least 4 bytes of 00 padding */ 282d4afb5ceSopenharmony_ci 283d4afb5ceSopenharmony_ci if (((int)len + padc) & 7) 284d4afb5ceSopenharmony_ci padc += 8 - (((int)len + padc) & 7); 285d4afb5ceSopenharmony_ci 286d4afb5ceSopenharmony_ci op[4] = (uint8_t)padc; 287d4afb5ceSopenharmony_ci len += (uint32_t)padc; 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci while (padc--) 290d4afb5ceSopenharmony_ci *p++ = 0; 291d4afb5ceSopenharmony_ci 292d4afb5ceSopenharmony_ci /* recorded length does not include the uint32_t len itself */ 293d4afb5ceSopenharmony_ci lws_p32(op, len - 4); 294d4afb5ceSopenharmony_ci 295d4afb5ceSopenharmony_ci return len; 296d4afb5ceSopenharmony_ci} 297d4afb5ceSopenharmony_ci 298d4afb5ceSopenharmony_cistatic int 299d4afb5ceSopenharmony_cihandle_name(struct per_session_data__sshd *pss) 300d4afb5ceSopenharmony_ci{ 301d4afb5ceSopenharmony_ci struct lws_kex *kex = pss->kex; 302d4afb5ceSopenharmony_ci char keyt[32]; 303d4afb5ceSopenharmony_ci uint8_t keybuf[256]; 304d4afb5ceSopenharmony_ci int n = 0, len; 305d4afb5ceSopenharmony_ci 306d4afb5ceSopenharmony_ci switch (pss->parser_state) { 307d4afb5ceSopenharmony_ci case SSH_KEX_NL_KEX_ALGS: 308d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "curve25519-sha256@libssh.org")) 309d4afb5ceSopenharmony_ci kex->match_bitfield |= 1; 310d4afb5ceSopenharmony_ci break; 311d4afb5ceSopenharmony_ci case SSH_KEX_NL_SHK_ALGS: 312d4afb5ceSopenharmony_ci len = (int)get_gen_server_key_25519(pss, keybuf, (int)sizeof(keybuf)); 313d4afb5ceSopenharmony_ci if (!len) 314d4afb5ceSopenharmony_ci break; 315d4afb5ceSopenharmony_ci if (ed25519_key_parse(keybuf, (unsigned int)len, 316d4afb5ceSopenharmony_ci keyt, sizeof(keyt), 317d4afb5ceSopenharmony_ci NULL, NULL)) { 318d4afb5ceSopenharmony_ci lwsl_err("Unable to parse host key %d\n", n); 319d4afb5ceSopenharmony_ci } else { 320d4afb5ceSopenharmony_ci if (!strcmp(pss->name, keyt)) { 321d4afb5ceSopenharmony_ci kex->match_bitfield |= 2; 322d4afb5ceSopenharmony_ci break; 323d4afb5ceSopenharmony_ci } 324d4afb5ceSopenharmony_ci } 325d4afb5ceSopenharmony_ci break; 326d4afb5ceSopenharmony_ci case SSH_KEX_NL_EACTS_ALGS: 327d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "chacha20-poly1305@openssh.com")) 328d4afb5ceSopenharmony_ci kex->match_bitfield |= 4; 329d4afb5ceSopenharmony_ci break; 330d4afb5ceSopenharmony_ci case SSH_KEX_NL_EASTC_ALGS: 331d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "chacha20-poly1305@openssh.com")) 332d4afb5ceSopenharmony_ci kex->match_bitfield |= 8; 333d4afb5ceSopenharmony_ci break; 334d4afb5ceSopenharmony_ci case SSH_KEX_NL_MACTS_ALGS: 335d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "hmac-sha2-256")) 336d4afb5ceSopenharmony_ci kex->match_bitfield |= 16; 337d4afb5ceSopenharmony_ci break; 338d4afb5ceSopenharmony_ci case SSH_KEX_NL_MASTC_ALGS: 339d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "hmac-sha2-256")) 340d4afb5ceSopenharmony_ci kex->match_bitfield |= 32; 341d4afb5ceSopenharmony_ci break; 342d4afb5ceSopenharmony_ci case SSH_KEX_NL_CACTS_ALGS: 343d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "none")) 344d4afb5ceSopenharmony_ci kex->match_bitfield |= 64; 345d4afb5ceSopenharmony_ci break; 346d4afb5ceSopenharmony_ci case SSH_KEX_NL_CASTC_ALGS: 347d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "none")) 348d4afb5ceSopenharmony_ci kex->match_bitfield |= 128; 349d4afb5ceSopenharmony_ci break; 350d4afb5ceSopenharmony_ci case SSH_KEX_NL_LCTS_ALGS: 351d4afb5ceSopenharmony_ci case SSH_KEX_NL_LSTC_ALGS: 352d4afb5ceSopenharmony_ci break; 353d4afb5ceSopenharmony_ci default: 354d4afb5ceSopenharmony_ci break; 355d4afb5ceSopenharmony_ci } 356d4afb5ceSopenharmony_ci 357d4afb5ceSopenharmony_ci return 0; 358d4afb5ceSopenharmony_ci} 359d4afb5ceSopenharmony_ci 360d4afb5ceSopenharmony_ci 361d4afb5ceSopenharmony_cistatic int 362d4afb5ceSopenharmony_cilws_kex_create(struct per_session_data__sshd *pss) 363d4afb5ceSopenharmony_ci{ 364d4afb5ceSopenharmony_ci pss->kex = sshd_zalloc(sizeof(struct lws_kex)); 365d4afb5ceSopenharmony_ci lwsl_info("%s\n", __func__); 366d4afb5ceSopenharmony_ci return !pss->kex; 367d4afb5ceSopenharmony_ci} 368d4afb5ceSopenharmony_ci 369d4afb5ceSopenharmony_cistatic void 370d4afb5ceSopenharmony_cilws_kex_destroy(struct per_session_data__sshd *pss) 371d4afb5ceSopenharmony_ci{ 372d4afb5ceSopenharmony_ci if (!pss->kex) 373d4afb5ceSopenharmony_ci return; 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci lwsl_info("Destroying KEX\n"); 376d4afb5ceSopenharmony_ci 377d4afb5ceSopenharmony_ci if (pss->kex->I_C) { 378d4afb5ceSopenharmony_ci free(pss->kex->I_C); 379d4afb5ceSopenharmony_ci pss->kex->I_C = NULL; 380d4afb5ceSopenharmony_ci } 381d4afb5ceSopenharmony_ci if (pss->kex->I_S) { 382d4afb5ceSopenharmony_ci free(pss->kex->I_S); 383d4afb5ceSopenharmony_ci pss->kex->I_S = NULL; 384d4afb5ceSopenharmony_ci } 385d4afb5ceSopenharmony_ci 386d4afb5ceSopenharmony_ci lws_explicit_bzero(pss->kex, sizeof(*pss->kex)); 387d4afb5ceSopenharmony_ci free(pss->kex); 388d4afb5ceSopenharmony_ci pss->kex = NULL; 389d4afb5ceSopenharmony_ci} 390d4afb5ceSopenharmony_ci 391d4afb5ceSopenharmony_cistatic void 392d4afb5ceSopenharmony_cissh_free(void *p) 393d4afb5ceSopenharmony_ci{ 394d4afb5ceSopenharmony_ci if (!p) 395d4afb5ceSopenharmony_ci return; 396d4afb5ceSopenharmony_ci 397d4afb5ceSopenharmony_ci lwsl_debug("%s: FREE %p\n", __func__, p); 398d4afb5ceSopenharmony_ci free(p); 399d4afb5ceSopenharmony_ci} 400d4afb5ceSopenharmony_ci 401d4afb5ceSopenharmony_ci#define ssh_free_set_NULL(x) if (x) { ssh_free(x); (x) = NULL; } 402d4afb5ceSopenharmony_ci 403d4afb5ceSopenharmony_cistatic void 404d4afb5ceSopenharmony_cilws_ua_destroy(struct per_session_data__sshd *pss) 405d4afb5ceSopenharmony_ci{ 406d4afb5ceSopenharmony_ci if (!pss->ua) 407d4afb5ceSopenharmony_ci return; 408d4afb5ceSopenharmony_ci 409d4afb5ceSopenharmony_ci lwsl_info("%s\n", __func__); 410d4afb5ceSopenharmony_ci 411d4afb5ceSopenharmony_ci if (pss->ua->username) 412d4afb5ceSopenharmony_ci ssh_free(pss->ua->username); 413d4afb5ceSopenharmony_ci if (pss->ua->service) 414d4afb5ceSopenharmony_ci ssh_free(pss->ua->service); 415d4afb5ceSopenharmony_ci if (pss->ua->alg) 416d4afb5ceSopenharmony_ci ssh_free(pss->ua->alg); 417d4afb5ceSopenharmony_ci if (pss->ua->pubkey) 418d4afb5ceSopenharmony_ci ssh_free(pss->ua->pubkey); 419d4afb5ceSopenharmony_ci if (pss->ua->sig) { 420d4afb5ceSopenharmony_ci lws_explicit_bzero(pss->ua->sig, pss->ua->sig_len); 421d4afb5ceSopenharmony_ci ssh_free(pss->ua->sig); 422d4afb5ceSopenharmony_ci } 423d4afb5ceSopenharmony_ci 424d4afb5ceSopenharmony_ci lws_explicit_bzero(pss->ua, sizeof(*pss->ua)); 425d4afb5ceSopenharmony_ci free(pss->ua); 426d4afb5ceSopenharmony_ci pss->ua = NULL; 427d4afb5ceSopenharmony_ci} 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci 430d4afb5ceSopenharmony_cistatic int 431d4afb5ceSopenharmony_cirsa_hash_alg_from_ident(const char *ident) 432d4afb5ceSopenharmony_ci{ 433d4afb5ceSopenharmony_ci if (strcmp(ident, "ssh-rsa") == 0 || 434d4afb5ceSopenharmony_ci strcmp(ident, "ssh-rsa-cert-v01@openssh.com") == 0) 435d4afb5ceSopenharmony_ci return LWS_GENHASH_TYPE_SHA1; 436d4afb5ceSopenharmony_ci if (strcmp(ident, "rsa-sha2-256") == 0) 437d4afb5ceSopenharmony_ci return LWS_GENHASH_TYPE_SHA256; 438d4afb5ceSopenharmony_ci if (strcmp(ident, "rsa-sha2-512") == 0) 439d4afb5ceSopenharmony_ci return LWS_GENHASH_TYPE_SHA512; 440d4afb5ceSopenharmony_ci 441d4afb5ceSopenharmony_ci return -1; 442d4afb5ceSopenharmony_ci} 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_cistatic void 445d4afb5ceSopenharmony_cistate_get_string_alloc(struct per_session_data__sshd *pss, int next) 446d4afb5ceSopenharmony_ci{ 447d4afb5ceSopenharmony_ci pss->parser_state = SSHS_GET_STRING_LEN_ALLOC; 448d4afb5ceSopenharmony_ci pss->state_after_string = (char)next; 449d4afb5ceSopenharmony_ci} 450d4afb5ceSopenharmony_ci 451d4afb5ceSopenharmony_cistatic void 452d4afb5ceSopenharmony_cistate_get_string(struct per_session_data__sshd *pss, int next) 453d4afb5ceSopenharmony_ci{ 454d4afb5ceSopenharmony_ci pss->parser_state = SSHS_GET_STRING_LEN; 455d4afb5ceSopenharmony_ci pss->state_after_string = (char)next; 456d4afb5ceSopenharmony_ci} 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_cistatic void 459d4afb5ceSopenharmony_cistate_get_u32(struct per_session_data__sshd *pss, int next) 460d4afb5ceSopenharmony_ci{ 461d4afb5ceSopenharmony_ci pss->parser_state = SSHS_GET_U32; 462d4afb5ceSopenharmony_ci pss->state_after_string = (char)next; 463d4afb5ceSopenharmony_ci} 464d4afb5ceSopenharmony_ci 465d4afb5ceSopenharmony_cistatic struct lws_ssh_channel * 466d4afb5ceSopenharmony_cissh_get_server_ch(struct per_session_data__sshd *pss, uint32_t chi) 467d4afb5ceSopenharmony_ci{ 468d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch = pss->ch_list; 469d4afb5ceSopenharmony_ci 470d4afb5ceSopenharmony_ci while (ch) { 471d4afb5ceSopenharmony_ci if (ch->server_ch == chi) 472d4afb5ceSopenharmony_ci return ch; 473d4afb5ceSopenharmony_ci ch = ch->next; 474d4afb5ceSopenharmony_ci } 475d4afb5ceSopenharmony_ci 476d4afb5ceSopenharmony_ci return NULL; 477d4afb5ceSopenharmony_ci} 478d4afb5ceSopenharmony_ci 479d4afb5ceSopenharmony_ci#if 0 480d4afb5ceSopenharmony_cistatic struct lws_ssh_channel * 481d4afb5ceSopenharmony_cissh_get_peer_ch(struct per_session_data__sshd *pss, uint32_t chi) 482d4afb5ceSopenharmony_ci{ 483d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch = pss->ch_list; 484d4afb5ceSopenharmony_ci 485d4afb5ceSopenharmony_ci while (ch) { 486d4afb5ceSopenharmony_ci if (ch->sender_ch == chi) 487d4afb5ceSopenharmony_ci return ch; 488d4afb5ceSopenharmony_ci ch = ch->next; 489d4afb5ceSopenharmony_ci } 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci return NULL; 492d4afb5ceSopenharmony_ci} 493d4afb5ceSopenharmony_ci#endif 494d4afb5ceSopenharmony_ci 495d4afb5ceSopenharmony_cistatic void 496d4afb5ceSopenharmony_cissh_destroy_channel(struct per_session_data__sshd *pss, 497d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch) 498d4afb5ceSopenharmony_ci{ 499d4afb5ceSopenharmony_ci lws_start_foreach_llp(struct lws_ssh_channel **, ppch, pss->ch_list) { 500d4afb5ceSopenharmony_ci if (*ppch == ch) { 501d4afb5ceSopenharmony_ci lwsl_info("Deleting ch %p\n", ch); 502d4afb5ceSopenharmony_ci if (pss->vhd && pss->vhd->ops && 503d4afb5ceSopenharmony_ci pss->vhd->ops->channel_destroy) 504d4afb5ceSopenharmony_ci pss->vhd->ops->channel_destroy(ch->priv); 505d4afb5ceSopenharmony_ci *ppch = ch->next; 506d4afb5ceSopenharmony_ci if (ch->sub) 507d4afb5ceSopenharmony_ci free(ch->sub); 508d4afb5ceSopenharmony_ci free(ch); 509d4afb5ceSopenharmony_ci 510d4afb5ceSopenharmony_ci return; 511d4afb5ceSopenharmony_ci } 512d4afb5ceSopenharmony_ci } lws_end_foreach_llp(ppch, next); 513d4afb5ceSopenharmony_ci 514d4afb5ceSopenharmony_ci lwsl_notice("Failed to delete ch\n"); 515d4afb5ceSopenharmony_ci} 516d4afb5ceSopenharmony_ci 517d4afb5ceSopenharmony_cistatic void 518d4afb5ceSopenharmony_cilws_ssh_exec_finish(void *finish_handle, int retcode) 519d4afb5ceSopenharmony_ci{ 520d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch = (struct lws_ssh_channel *)finish_handle; 521d4afb5ceSopenharmony_ci struct per_session_data__sshd *pss = ch->pss; 522d4afb5ceSopenharmony_ci 523d4afb5ceSopenharmony_ci ch->retcode = retcode; 524d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_EXIT_STATUS); 525d4afb5ceSopenharmony_ci ch->scheduled_close = 1; 526d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_CH_CLOSE); 527d4afb5ceSopenharmony_ci} 528d4afb5ceSopenharmony_ci 529d4afb5ceSopenharmony_cistatic int 530d4afb5ceSopenharmony_cilws_ssh_parse_plaintext(struct per_session_data__sshd *pss, uint8_t *p, size_t len) 531d4afb5ceSopenharmony_ci{ 532d4afb5ceSopenharmony_ci struct lws_gencrypto_keyelem e[LWS_GENCRYPTO_RSA_KEYEL_COUNT]; 533d4afb5ceSopenharmony_ci struct lws_genrsa_ctx ctx; 534d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch; 535d4afb5ceSopenharmony_ci struct lws_subprotocol_scp *scp; 536d4afb5ceSopenharmony_ci uint8_t *pp, *ps, hash[64]; 537d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000 538d4afb5ceSopenharmony_ci uint8_t *otmp = NULL; 539d4afb5ceSopenharmony_ci#endif 540d4afb5ceSopenharmony_ci uint32_t m; 541d4afb5ceSopenharmony_ci int n; 542d4afb5ceSopenharmony_ci 543d4afb5ceSopenharmony_ci while (len --) { 544d4afb5ceSopenharmony_ciagain: 545d4afb5ceSopenharmony_ci switch(pss->parser_state) { 546d4afb5ceSopenharmony_ci case SSH_INITIALIZE_TRANSIENT: 547d4afb5ceSopenharmony_ci pss->parser_state = SSHS_IDSTRING; 548d4afb5ceSopenharmony_ci pss->ctr = 0; 549d4afb5ceSopenharmony_ci pss->copy_to_I_C = 0; 550d4afb5ceSopenharmony_ci 551d4afb5ceSopenharmony_ci /* fallthru */ 552d4afb5ceSopenharmony_ci case SSHS_IDSTRING: 553d4afb5ceSopenharmony_ci if (*p == 0x0d) { 554d4afb5ceSopenharmony_ci pss->V_C[pss->npos] = '\0'; 555d4afb5ceSopenharmony_ci pss->npos = 0; 556d4afb5ceSopenharmony_ci lwsl_info("peer id: %s\n", pss->V_C); 557d4afb5ceSopenharmony_ci p++; 558d4afb5ceSopenharmony_ci pss->parser_state = SSHS_IDSTRING_CR; 559d4afb5ceSopenharmony_ci break; 560d4afb5ceSopenharmony_ci } 561d4afb5ceSopenharmony_ci if (pss->npos < sizeof(pss->V_C) - 1) 562d4afb5ceSopenharmony_ci pss->V_C[pss->npos++] = (char)*p; 563d4afb5ceSopenharmony_ci p++; 564d4afb5ceSopenharmony_ci break; 565d4afb5ceSopenharmony_ci 566d4afb5ceSopenharmony_ci case SSHS_IDSTRING_CR: 567d4afb5ceSopenharmony_ci if (*p++ != 0x0a) { 568d4afb5ceSopenharmony_ci lwsl_notice("mangled id string\n"); 569d4afb5ceSopenharmony_ci return 1; 570d4afb5ceSopenharmony_ci } 571d4afb5ceSopenharmony_ci pss->ssh_sequence_ctr_cts = 0; 572d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_LEN; 573d4afb5ceSopenharmony_ci break; 574d4afb5ceSopenharmony_ci 575d4afb5ceSopenharmony_ci case SSHS_MSG_LEN: 576d4afb5ceSopenharmony_ci pss->msg_len = (pss->msg_len << 8) | *p++; 577d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 578d4afb5ceSopenharmony_ci break; 579d4afb5ceSopenharmony_ci 580d4afb5ceSopenharmony_ci if (pss->active_keys_cts.valid) { 581d4afb5ceSopenharmony_ci uint8_t b[4]; 582d4afb5ceSopenharmony_ci 583d4afb5ceSopenharmony_ci POKE_U32(b, (uint32_t)pss->msg_len); 584d4afb5ceSopenharmony_ci pss->msg_len = lws_chachapoly_get_length( 585d4afb5ceSopenharmony_ci &pss->active_keys_cts, 586d4afb5ceSopenharmony_ci pss->ssh_sequence_ctr_cts, b); 587d4afb5ceSopenharmony_ci } else 588d4afb5ceSopenharmony_ci pss->ssh_sequence_ctr_cts++; 589d4afb5ceSopenharmony_ci 590d4afb5ceSopenharmony_ci lwsl_info("msg len %d\n", pss->msg_len); 591d4afb5ceSopenharmony_ci 592d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_PADDING; 593d4afb5ceSopenharmony_ci pss->ctr = 0; 594d4afb5ceSopenharmony_ci pss->pos = 4; 595d4afb5ceSopenharmony_ci if (pss->msg_len < 2 + 4) { 596d4afb5ceSopenharmony_ci lwsl_notice("illegal msg size\n"); 597d4afb5ceSopenharmony_ci goto bail; 598d4afb5ceSopenharmony_ci } 599d4afb5ceSopenharmony_ci break; 600d4afb5ceSopenharmony_ci 601d4afb5ceSopenharmony_ci case SSHS_MSG_PADDING: 602d4afb5ceSopenharmony_ci pss->msg_padding = *p++; 603d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_ID; 604d4afb5ceSopenharmony_ci break; 605d4afb5ceSopenharmony_ci 606d4afb5ceSopenharmony_ci case SSHS_MSG_ID: 607d4afb5ceSopenharmony_ci pss->msg_id = *p++; 608d4afb5ceSopenharmony_ci pss->ctr = 0; 609d4afb5ceSopenharmony_ci switch (pss->msg_id) { 610d4afb5ceSopenharmony_ci case SSH_MSG_DISCONNECT: 611d4afb5ceSopenharmony_ci /* 612d4afb5ceSopenharmony_ci * byte SSH_MSG_DISCONNECT 613d4afb5ceSopenharmony_ci * uint32 reason code 614d4afb5ceSopenharmony_ci * string description in ISO-10646 615d4afb5ceSopenharmony_ci * UTF-8 encoding [RFC3629] 616d4afb5ceSopenharmony_ci * string language tag [RFC3066] 617d4afb5ceSopenharmony_ci */ 618d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_DISCONNECT\n"); 619d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_DISCONNECT_REASON); 620d4afb5ceSopenharmony_ci break; 621d4afb5ceSopenharmony_ci case SSH_MSG_IGNORE: 622d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_IGNORE\n"); 623d4afb5ceSopenharmony_ci break; 624d4afb5ceSopenharmony_ci case SSH_MSG_UNIMPLEMENTED: 625d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_UNIMPLEMENTED\n"); 626d4afb5ceSopenharmony_ci break; 627d4afb5ceSopenharmony_ci case SSH_MSG_DEBUG: 628d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_DEBUG\n"); 629d4afb5ceSopenharmony_ci break; 630d4afb5ceSopenharmony_ci case SSH_MSG_SERVICE_REQUEST: 631d4afb5ceSopenharmony_ci lwsl_info("SSH_MSG_SERVICE_REQUEST\n"); 632d4afb5ceSopenharmony_ci /* payload is a string */ 633d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_DO_SERVICE_REQUEST); 634d4afb5ceSopenharmony_ci break; 635d4afb5ceSopenharmony_ci case SSH_MSG_SERVICE_ACCEPT: 636d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_ACCEPT\n"); 637d4afb5ceSopenharmony_ci break; 638d4afb5ceSopenharmony_ci 639d4afb5ceSopenharmony_ci case SSH_MSG_KEXINIT: 640d4afb5ceSopenharmony_ci if (pss->kex_state != 641d4afb5ceSopenharmony_ci KEX_STATE_EXPECTING_CLIENT_OFFER) { 642d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_SKIP; 643d4afb5ceSopenharmony_ci break; 644d4afb5ceSopenharmony_ci } 645d4afb5ceSopenharmony_ci if (!pss->kex) { 646d4afb5ceSopenharmony_ci lwsl_notice("%s: SSH_MSG_KEXINIT: NULL pss->kex\n", __func__); 647d4afb5ceSopenharmony_ci goto bail; 648d4afb5ceSopenharmony_ci } 649d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_COOKIE; 650d4afb5ceSopenharmony_ci pss->kex->I_C_payload_len = 0; 651d4afb5ceSopenharmony_ci pss->kex->I_C_alloc_len = pss->msg_len; 652d4afb5ceSopenharmony_ci pss->kex->I_C = sshd_zalloc(pss->kex->I_C_alloc_len); 653d4afb5ceSopenharmony_ci if (!pss->kex->I_C) { 654d4afb5ceSopenharmony_ci lwsl_notice("OOM 3\n"); 655d4afb5ceSopenharmony_ci goto bail; 656d4afb5ceSopenharmony_ci } 657d4afb5ceSopenharmony_ci pss->kex->I_C[pss->kex->I_C_payload_len++] = 658d4afb5ceSopenharmony_ci pss->msg_id; 659d4afb5ceSopenharmony_ci pss->copy_to_I_C = 1; 660d4afb5ceSopenharmony_ci break; 661d4afb5ceSopenharmony_ci case SSH_MSG_KEX_ECDH_INIT: 662d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_ECDH_KEYLEN; 663d4afb5ceSopenharmony_ci break; 664d4afb5ceSopenharmony_ci 665d4afb5ceSopenharmony_ci case SSH_MSG_NEWKEYS: 666d4afb5ceSopenharmony_ci if (pss->kex_state != 667d4afb5ceSopenharmony_ci KEX_STATE_REPLIED_TO_OFFER && 668d4afb5ceSopenharmony_ci pss->kex_state != 669d4afb5ceSopenharmony_ci KEX_STATE_CRYPTO_INITIALIZED) { 670d4afb5ceSopenharmony_ci lwsl_notice("unexpected newkeys\n"); 671d4afb5ceSopenharmony_ci 672d4afb5ceSopenharmony_ci goto bail; 673d4afb5ceSopenharmony_ci } 674d4afb5ceSopenharmony_ci /* 675d4afb5ceSopenharmony_ci * it means we should now use the keys we 676d4afb5ceSopenharmony_ci * agreed on 677d4afb5ceSopenharmony_ci */ 678d4afb5ceSopenharmony_ci lwsl_info("Activating CTS keys\n"); 679d4afb5ceSopenharmony_ci pss->active_keys_cts = pss->kex->keys_next_cts; 680d4afb5ceSopenharmony_ci if (lws_chacha_activate(&pss->active_keys_cts)) 681d4afb5ceSopenharmony_ci goto bail; 682d4afb5ceSopenharmony_ci 683d4afb5ceSopenharmony_ci pss->kex->newkeys |= 2; 684d4afb5ceSopenharmony_ci if (pss->kex->newkeys == 3) 685d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 686d4afb5ceSopenharmony_ci 687d4afb5ceSopenharmony_ci if (pss->msg_padding) { 688d4afb5ceSopenharmony_ci pss->copy_to_I_C = 0; 689d4afb5ceSopenharmony_ci pss->parser_state = 690d4afb5ceSopenharmony_ci SSHS_MSG_EAT_PADDING; 691d4afb5ceSopenharmony_ci break; 692d4afb5ceSopenharmony_ci } else { 693d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_LEN; 694d4afb5ceSopenharmony_ci } 695d4afb5ceSopenharmony_ci break; 696d4afb5ceSopenharmony_ci 697d4afb5ceSopenharmony_ci case SSH_MSG_USERAUTH_REQUEST: 698d4afb5ceSopenharmony_ci /* 699d4afb5ceSopenharmony_ci * byte SSH_MSG_USERAUTH_REQUEST 700d4afb5ceSopenharmony_ci * string user name in UTF-8 701d4afb5ceSopenharmony_ci * encoding [RFC3629] 702d4afb5ceSopenharmony_ci * string service name in US-ASCII 703d4afb5ceSopenharmony_ci * string "publickey" 704d4afb5ceSopenharmony_ci * boolean FALSE 705d4afb5ceSopenharmony_ci * string public key alg 706d4afb5ceSopenharmony_ci * string public key blob 707d4afb5ceSopenharmony_ci */ 708d4afb5ceSopenharmony_ci lwsl_info("SSH_MSG_USERAUTH_REQUEST\n"); 709d4afb5ceSopenharmony_ci if (pss->ua) { 710d4afb5ceSopenharmony_ci lwsl_notice("pss->ua overwrite\n"); 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ci goto bail; 713d4afb5ceSopenharmony_ci } 714d4afb5ceSopenharmony_ci 715d4afb5ceSopenharmony_ci pss->ua = sshd_zalloc(sizeof(*pss->ua)); 716d4afb5ceSopenharmony_ci if (!pss->ua) 717d4afb5ceSopenharmony_ci goto bail; 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_DO_UAR_SVC); 720d4afb5ceSopenharmony_ci /* username is destroyed with userauth struct */ 721d4afb5ceSopenharmony_ci if (!pss->sent_banner) { 722d4afb5ceSopenharmony_ci if (pss->vhd->ops->banner) 723d4afb5ceSopenharmony_ci write_task(pss, NULL, 724d4afb5ceSopenharmony_ci SSH_WT_UA_BANNER); 725d4afb5ceSopenharmony_ci pss->sent_banner = 1; 726d4afb5ceSopenharmony_ci } 727d4afb5ceSopenharmony_ci break; 728d4afb5ceSopenharmony_ci case SSH_MSG_USERAUTH_FAILURE: 729d4afb5ceSopenharmony_ci goto bail; 730d4afb5ceSopenharmony_ci case SSH_MSG_USERAUTH_SUCCESS: 731d4afb5ceSopenharmony_ci goto bail; 732d4afb5ceSopenharmony_ci case SSH_MSG_USERAUTH_BANNER: 733d4afb5ceSopenharmony_ci goto bail; 734d4afb5ceSopenharmony_ci 735d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_OPEN: 736d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CHOPEN_TYPE); 737d4afb5ceSopenharmony_ci break; 738d4afb5ceSopenharmony_ci 739d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_REQUEST: 740d4afb5ceSopenharmony_ci /* RFC4254 741d4afb5ceSopenharmony_ci * 742d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_REQUEST 743d4afb5ceSopenharmony_ci * uint32 recipient channel 744d4afb5ceSopenharmony_ci * string "pty-req" 745d4afb5ceSopenharmony_ci * boolean want_reply 746d4afb5ceSopenharmony_ci * string TERM environment variable value 747d4afb5ceSopenharmony_ci * (e.g., vt100) 748d4afb5ceSopenharmony_ci * uint32 terminal width, characters 749d4afb5ceSopenharmony_ci * (e.g., 80) 750d4afb5ceSopenharmony_ci * uint32 terminal height, rows (e.g., 24) 751d4afb5ceSopenharmony_ci * uint32 terminal width, px (e.g., 640) 752d4afb5ceSopenharmony_ci * uint32 terminal height, px (e.g., 480) 753d4afb5ceSopenharmony_ci * string encoded terminal modes 754d4afb5ceSopenharmony_ci */ 755d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_RECIP); 756d4afb5ceSopenharmony_ci break; 757d4afb5ceSopenharmony_ci 758d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_EOF: 759d4afb5ceSopenharmony_ci /* RFC4254 760d4afb5ceSopenharmony_ci * When a party will no longer send more data 761d4afb5ceSopenharmony_ci * to a channel, it SHOULD send 762d4afb5ceSopenharmony_ci * SSH_MSG_CHANNEL_EOF. 763d4afb5ceSopenharmony_ci * 764d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_EOF 765d4afb5ceSopenharmony_ci * uint32 recipient channel 766d4afb5ceSopenharmony_ci */ 767d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CH_EOF); 768d4afb5ceSopenharmony_ci break; 769d4afb5ceSopenharmony_ci 770d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_CLOSE: 771d4afb5ceSopenharmony_ci /* RFC4254 772d4afb5ceSopenharmony_ci * 773d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_CLOSE 774d4afb5ceSopenharmony_ci * uint32 recipient channel 775d4afb5ceSopenharmony_ci * 776d4afb5ceSopenharmony_ci * This message does not consume window space 777d4afb5ceSopenharmony_ci * and can be sent even if no window space is 778d4afb5ceSopenharmony_ci * available. 779d4afb5ceSopenharmony_ci * 780d4afb5ceSopenharmony_ci * It is RECOMMENDED that all data sent before 781d4afb5ceSopenharmony_ci * this message be delivered to the actual 782d4afb5ceSopenharmony_ci * destination, if possible. 783d4afb5ceSopenharmony_ci */ 784d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CH_CLOSE); 785d4afb5ceSopenharmony_ci break; 786d4afb5ceSopenharmony_ci 787d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_DATA: 788d4afb5ceSopenharmony_ci /* RFC4254 789d4afb5ceSopenharmony_ci * 790d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_DATA 791d4afb5ceSopenharmony_ci * uint32 recipient channel 792d4afb5ceSopenharmony_ci * string data 793d4afb5ceSopenharmony_ci */ 794d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CD_RECIP); 795d4afb5ceSopenharmony_ci break; 796d4afb5ceSopenharmony_ci 797d4afb5ceSopenharmony_ci case SSH_MSG_CHANNEL_WINDOW_ADJUST: 798d4afb5ceSopenharmony_ci /* RFC452 799d4afb5ceSopenharmony_ci * 800d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_WINDOW_ADJUST 801d4afb5ceSopenharmony_ci * uint32 recipient channel 802d4afb5ceSopenharmony_ci * uint32 bytes to add 803d4afb5ceSopenharmony_ci */ 804d4afb5ceSopenharmony_ci if (!pss->ch_list) 805d4afb5ceSopenharmony_ci goto bail; 806d4afb5ceSopenharmony_ci 807d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_WA_RECIP); 808d4afb5ceSopenharmony_ci break; 809d4afb5ceSopenharmony_ci default: 810d4afb5ceSopenharmony_ci lwsl_notice("unk msg_id %d\n", pss->msg_id); 811d4afb5ceSopenharmony_ci 812d4afb5ceSopenharmony_ci goto bail; 813d4afb5ceSopenharmony_ci } 814d4afb5ceSopenharmony_ci break; 815d4afb5ceSopenharmony_ci 816d4afb5ceSopenharmony_ci case SSH_KEX_STATE_COOKIE: 817d4afb5ceSopenharmony_ci if (pss->msg_len < 16 + 1 + 1 + (10 * 4) + 5) { 818d4afb5ceSopenharmony_ci lwsl_notice("sanity: kex length failed\n"); 819d4afb5ceSopenharmony_ci goto bail; 820d4afb5ceSopenharmony_ci } 821d4afb5ceSopenharmony_ci pss->kex->kex_cookie[pss->ctr++] = *p++; 822d4afb5ceSopenharmony_ci if (pss->ctr != sizeof(pss->kex->kex_cookie)) 823d4afb5ceSopenharmony_ci break; 824d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_NL_KEX_ALGS_LEN; 825d4afb5ceSopenharmony_ci pss->ctr = 0; 826d4afb5ceSopenharmony_ci break; 827d4afb5ceSopenharmony_ci case SSH_KEX_NL_KEX_ALGS_LEN: 828d4afb5ceSopenharmony_ci case SSH_KEX_NL_SHK_ALGS_LEN: 829d4afb5ceSopenharmony_ci case SSH_KEX_NL_EACTS_ALGS_LEN: 830d4afb5ceSopenharmony_ci case SSH_KEX_NL_EASTC_ALGS_LEN: 831d4afb5ceSopenharmony_ci case SSH_KEX_NL_MACTS_ALGS_LEN: 832d4afb5ceSopenharmony_ci case SSH_KEX_NL_MASTC_ALGS_LEN: 833d4afb5ceSopenharmony_ci case SSH_KEX_NL_CACTS_ALGS_LEN: 834d4afb5ceSopenharmony_ci case SSH_KEX_NL_CASTC_ALGS_LEN: 835d4afb5ceSopenharmony_ci case SSH_KEX_NL_LCTS_ALGS_LEN: 836d4afb5ceSopenharmony_ci case SSH_KEX_NL_LSTC_ALGS_LEN: 837d4afb5ceSopenharmony_ci case SSH_KEX_STATE_ECDH_KEYLEN: 838d4afb5ceSopenharmony_ci 839d4afb5ceSopenharmony_ci pss->len = (pss->len << 8) | *p++; 840d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 841d4afb5ceSopenharmony_ci break; 842d4afb5ceSopenharmony_ci 843d4afb5ceSopenharmony_ci switch (pss->parser_state) { 844d4afb5ceSopenharmony_ci case SSH_KEX_STATE_ECDH_KEYLEN: 845d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_ECDH_Q_C; 846d4afb5ceSopenharmony_ci break; 847d4afb5ceSopenharmony_ci default: 848d4afb5ceSopenharmony_ci pss->parser_state++; 849d4afb5ceSopenharmony_ci if (pss->len == 0) 850d4afb5ceSopenharmony_ci pss->parser_state++; 851d4afb5ceSopenharmony_ci break; 852d4afb5ceSopenharmony_ci } 853d4afb5ceSopenharmony_ci pss->ctr = 0; 854d4afb5ceSopenharmony_ci pss->npos = 0; 855d4afb5ceSopenharmony_ci if (pss->msg_len - pss->pos < pss->len) { 856d4afb5ceSopenharmony_ci lwsl_notice("sanity: length %d - %d < %d\n", 857d4afb5ceSopenharmony_ci pss->msg_len, pss->pos, pss->len); 858d4afb5ceSopenharmony_ci goto bail; 859d4afb5ceSopenharmony_ci } 860d4afb5ceSopenharmony_ci break; 861d4afb5ceSopenharmony_ci 862d4afb5ceSopenharmony_ci case SSH_KEX_NL_KEX_ALGS: 863d4afb5ceSopenharmony_ci case SSH_KEX_NL_SHK_ALGS: 864d4afb5ceSopenharmony_ci case SSH_KEX_NL_EACTS_ALGS: 865d4afb5ceSopenharmony_ci case SSH_KEX_NL_EASTC_ALGS: 866d4afb5ceSopenharmony_ci case SSH_KEX_NL_MACTS_ALGS: 867d4afb5ceSopenharmony_ci case SSH_KEX_NL_MASTC_ALGS: 868d4afb5ceSopenharmony_ci case SSH_KEX_NL_CACTS_ALGS: 869d4afb5ceSopenharmony_ci case SSH_KEX_NL_CASTC_ALGS: 870d4afb5ceSopenharmony_ci case SSH_KEX_NL_LCTS_ALGS: 871d4afb5ceSopenharmony_ci case SSH_KEX_NL_LSTC_ALGS: 872d4afb5ceSopenharmony_ci if (*p != ',') { 873d4afb5ceSopenharmony_ci if (pss->npos < sizeof(pss->name) - 1) 874d4afb5ceSopenharmony_ci pss->name[pss->npos++] = (char)*p; 875d4afb5ceSopenharmony_ci } else { 876d4afb5ceSopenharmony_ci pss->name[pss->npos] = '\0'; 877d4afb5ceSopenharmony_ci pss->npos = 0; 878d4afb5ceSopenharmony_ci handle_name(pss); 879d4afb5ceSopenharmony_ci } 880d4afb5ceSopenharmony_ci p++; 881d4afb5ceSopenharmony_ci if (!--pss->len) { 882d4afb5ceSopenharmony_ci pss->name[pss->npos] = '\0'; 883d4afb5ceSopenharmony_ci if (pss->npos) 884d4afb5ceSopenharmony_ci handle_name(pss); 885d4afb5ceSopenharmony_ci pss->parser_state++; 886d4afb5ceSopenharmony_ci break; 887d4afb5ceSopenharmony_ci } 888d4afb5ceSopenharmony_ci break; 889d4afb5ceSopenharmony_ci 890d4afb5ceSopenharmony_ci case SSH_KEX_FIRST_PKT: 891d4afb5ceSopenharmony_ci pss->first_coming = !!*p++; 892d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_RESERVED; 893d4afb5ceSopenharmony_ci break; 894d4afb5ceSopenharmony_ci 895d4afb5ceSopenharmony_ci case SSH_KEX_RESERVED: 896d4afb5ceSopenharmony_ci pss->len = (pss->len << 8) | *p++; 897d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 898d4afb5ceSopenharmony_ci break; 899d4afb5ceSopenharmony_ci pss->ctr = 0; 900d4afb5ceSopenharmony_ci if (pss->msg_padding) { 901d4afb5ceSopenharmony_ci pss->copy_to_I_C = 0; 902d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 903d4afb5ceSopenharmony_ci break; 904d4afb5ceSopenharmony_ci } 905d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_LEN; 906d4afb5ceSopenharmony_ci break; 907d4afb5ceSopenharmony_ci 908d4afb5ceSopenharmony_ci case SSH_KEX_STATE_ECDH_Q_C: 909d4afb5ceSopenharmony_ci if (pss->len != 32) { 910d4afb5ceSopenharmony_ci lwsl_notice("wrong key len\n"); 911d4afb5ceSopenharmony_ci goto bail; 912d4afb5ceSopenharmony_ci } 913d4afb5ceSopenharmony_ci pss->kex->Q_C[pss->ctr++] = *p++; 914d4afb5ceSopenharmony_ci if (pss->ctr != 32) 915d4afb5ceSopenharmony_ci break; 916d4afb5ceSopenharmony_ci lwsl_info("Q_C parsed\n"); 917d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 918d4afb5ceSopenharmony_ci break; 919d4afb5ceSopenharmony_ci 920d4afb5ceSopenharmony_ci case SSH_KEX_STATE_SKIP: 921d4afb5ceSopenharmony_ci if (pss->pos - 4 < pss->msg_len) { 922d4afb5ceSopenharmony_ci p++; 923d4afb5ceSopenharmony_ci break; 924d4afb5ceSopenharmony_ci } 925d4afb5ceSopenharmony_ci lwsl_debug("skip done pos %d, msg_len %d len=%ld, \n", 926d4afb5ceSopenharmony_ci pss->pos, pss->msg_len, (long)len); 927d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_LEN; 928d4afb5ceSopenharmony_ci pss->ctr = 0; 929d4afb5ceSopenharmony_ci break; 930d4afb5ceSopenharmony_ci 931d4afb5ceSopenharmony_ci case SSHS_MSG_EAT_PADDING: 932d4afb5ceSopenharmony_ci p++; 933d4afb5ceSopenharmony_ci if (--pss->msg_padding) 934d4afb5ceSopenharmony_ci break; 935d4afb5ceSopenharmony_ci if (pss->msg_len + 4 != pss->pos) { 936d4afb5ceSopenharmony_ci lwsl_notice("sanity: kex end mismatch %d %d\n", 937d4afb5ceSopenharmony_ci pss->pos, pss->msg_len); 938d4afb5ceSopenharmony_ci goto bail; 939d4afb5ceSopenharmony_ci } 940d4afb5ceSopenharmony_ci 941d4afb5ceSopenharmony_ci switch (pss->msg_id) { 942d4afb5ceSopenharmony_ci case SSH_MSG_KEX_ECDH_INIT: 943d4afb5ceSopenharmony_ci if (pss->kex->match_bitfield != 0xff) { 944d4afb5ceSopenharmony_ci lwsl_notice("unable to negotiate\n"); 945d4afb5ceSopenharmony_ci goto bail; 946d4afb5ceSopenharmony_ci } 947d4afb5ceSopenharmony_ci if (kex_ecdh(pss, pss->kex->kex_r, 948d4afb5ceSopenharmony_ci &pss->kex->kex_r_len)) { 949d4afb5ceSopenharmony_ci lwsl_notice("hex_ecdh failed\n"); 950d4afb5ceSopenharmony_ci goto bail; 951d4afb5ceSopenharmony_ci } 952d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_OFFER_REPLY); 953d4afb5ceSopenharmony_ci break; 954d4afb5ceSopenharmony_ci } 955d4afb5ceSopenharmony_ci 956d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_LEN; 957d4afb5ceSopenharmony_ci pss->ctr = 0; 958d4afb5ceSopenharmony_ci break; 959d4afb5ceSopenharmony_ci 960d4afb5ceSopenharmony_ci case SSHS_GET_STRING_LEN: 961d4afb5ceSopenharmony_ci pss->npos = 0; 962d4afb5ceSopenharmony_ci pss->len = (pss->len << 8) | *p++; 963d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 964d4afb5ceSopenharmony_ci break; 965d4afb5ceSopenharmony_ci pss->ctr = 0; 966d4afb5ceSopenharmony_ci pss->parser_state = SSHS_GET_STRING; 967d4afb5ceSopenharmony_ci break; 968d4afb5ceSopenharmony_ci 969d4afb5ceSopenharmony_ci case SSHS_GET_STRING: 970d4afb5ceSopenharmony_ci if (pss->npos >= sizeof(pss->name) - 1) { 971d4afb5ceSopenharmony_ci lwsl_notice("non-alloc string too big\n"); 972d4afb5ceSopenharmony_ci goto bail; 973d4afb5ceSopenharmony_ci } 974d4afb5ceSopenharmony_ci pss->name[pss->npos++] = (char)*p++; 975d4afb5ceSopenharmony_ci if (pss->npos != pss->len) 976d4afb5ceSopenharmony_ci break; 977d4afb5ceSopenharmony_ci 978d4afb5ceSopenharmony_ci pss->name[pss->npos] = '\0'; 979d4afb5ceSopenharmony_ci pss->parser_state = pss->state_after_string; 980d4afb5ceSopenharmony_ci goto again; 981d4afb5ceSopenharmony_ci 982d4afb5ceSopenharmony_ci case SSHS_GET_STRING_LEN_ALLOC: 983d4afb5ceSopenharmony_ci pss->npos = 0; 984d4afb5ceSopenharmony_ci pss->len = (pss->len << 8) | *p++; 985d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 986d4afb5ceSopenharmony_ci break; 987d4afb5ceSopenharmony_ci pss->ctr = 0; 988d4afb5ceSopenharmony_ci pss->last_alloc = sshd_zalloc(pss->len + 1); 989d4afb5ceSopenharmony_ci lwsl_debug("SSHS_GET_STRING_LEN_ALLOC: %p, state %d\n", 990d4afb5ceSopenharmony_ci pss->last_alloc, pss->state_after_string); 991d4afb5ceSopenharmony_ci if (!pss->last_alloc) { 992d4afb5ceSopenharmony_ci lwsl_notice("alloc string too big\n"); 993d4afb5ceSopenharmony_ci goto bail; 994d4afb5ceSopenharmony_ci } 995d4afb5ceSopenharmony_ci pss->parser_state = SSHS_GET_STRING_ALLOC; 996d4afb5ceSopenharmony_ci break; 997d4afb5ceSopenharmony_ci 998d4afb5ceSopenharmony_ci case SSHS_GET_STRING_ALLOC: 999d4afb5ceSopenharmony_ci if (pss->npos >= pss->len) 1000d4afb5ceSopenharmony_ci goto bail; 1001d4afb5ceSopenharmony_ci pss->last_alloc[pss->npos++] = *p++; 1002d4afb5ceSopenharmony_ci if (pss->npos != pss->len) 1003d4afb5ceSopenharmony_ci break; 1004d4afb5ceSopenharmony_ci pss->last_alloc[pss->npos] = '\0'; 1005d4afb5ceSopenharmony_ci pss->parser_state = pss->state_after_string; 1006d4afb5ceSopenharmony_ci goto again; 1007d4afb5ceSopenharmony_ci 1008d4afb5ceSopenharmony_ci /* 1009d4afb5ceSopenharmony_ci * User Authentication 1010d4afb5ceSopenharmony_ci */ 1011d4afb5ceSopenharmony_ci 1012d4afb5ceSopenharmony_ci case SSHS_DO_SERVICE_REQUEST: 1013d4afb5ceSopenharmony_ci pss->okayed_userauth = 1; 1014d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1015d4afb5ceSopenharmony_ci /* 1016d4afb5ceSopenharmony_ci * this only 'accepts' that we can negotiate auth for 1017d4afb5ceSopenharmony_ci * this service, not accepts the auth 1018d4afb5ceSopenharmony_ci */ 1019d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_UA_ACCEPT); 1020d4afb5ceSopenharmony_ci break; 1021d4afb5ceSopenharmony_ci 1022d4afb5ceSopenharmony_ci case SSHS_DO_UAR_SVC: 1023d4afb5ceSopenharmony_ci pss->ua->username = (char *)pss->last_alloc; 1024d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1025d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_DO_UAR_PUBLICKEY); 1026d4afb5ceSopenharmony_ci /* destroyed with UA struct */ 1027d4afb5ceSopenharmony_ci break; 1028d4afb5ceSopenharmony_ci 1029d4afb5ceSopenharmony_ci case SSHS_DO_UAR_PUBLICKEY: 1030d4afb5ceSopenharmony_ci pss->ua->service = (char *)pss->last_alloc; 1031d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1032d4afb5ceSopenharmony_ci 1033d4afb5ceSopenharmony_ci /* Sect 5, RFC4252 1034d4afb5ceSopenharmony_ci * 1035d4afb5ceSopenharmony_ci * The 'user name' and 'service name' are repeated in 1036d4afb5ceSopenharmony_ci * every new authentication attempt, and MAY change. 1037d4afb5ceSopenharmony_ci * 1038d4afb5ceSopenharmony_ci * The server implementation MUST carefully check them 1039d4afb5ceSopenharmony_ci * in every message, and MUST flush any accumulated 1040d4afb5ceSopenharmony_ci * authentication states if they change. If it is 1041d4afb5ceSopenharmony_ci * unable to flush an authentication state, it MUST 1042d4afb5ceSopenharmony_ci * disconnect if the 'user name' or 'service name' 1043d4afb5ceSopenharmony_ci * changes. 1044d4afb5ceSopenharmony_ci */ 1045d4afb5ceSopenharmony_ci 1046d4afb5ceSopenharmony_ci if (pss->seen_auth_req_before && ( 1047d4afb5ceSopenharmony_ci strcmp(pss->ua->username, 1048d4afb5ceSopenharmony_ci pss->last_auth_req_username) || 1049d4afb5ceSopenharmony_ci strcmp(pss->ua->service, 1050d4afb5ceSopenharmony_ci pss->last_auth_req_service))) { 1051d4afb5ceSopenharmony_ci lwsl_notice("username / svc changed\n"); 1052d4afb5ceSopenharmony_ci 1053d4afb5ceSopenharmony_ci goto bail; 1054d4afb5ceSopenharmony_ci } 1055d4afb5ceSopenharmony_ci 1056d4afb5ceSopenharmony_ci pss->seen_auth_req_before = 1; 1057d4afb5ceSopenharmony_ci lws_strncpy(pss->last_auth_req_username, 1058d4afb5ceSopenharmony_ci pss->ua->username, 1059d4afb5ceSopenharmony_ci sizeof(pss->last_auth_req_username)); 1060d4afb5ceSopenharmony_ci lws_strncpy(pss->last_auth_req_service, 1061d4afb5ceSopenharmony_ci pss->ua->service, 1062d4afb5ceSopenharmony_ci sizeof(pss->last_auth_req_service)); 1063d4afb5ceSopenharmony_ci 1064d4afb5ceSopenharmony_ci if (strcmp(pss->ua->service, "ssh-connection")) 1065d4afb5ceSopenharmony_ci goto ua_fail; 1066d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_DO_UAR_CHECK_PUBLICKEY); 1067d4afb5ceSopenharmony_ci break; 1068d4afb5ceSopenharmony_ci 1069d4afb5ceSopenharmony_ci case SSHS_NVC_DO_UAR_CHECK_PUBLICKEY: 1070d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "none")) { 1071d4afb5ceSopenharmony_ci /* we must fail it */ 1072d4afb5ceSopenharmony_ci lwsl_info("got 'none' req, refusing\n"); 1073d4afb5ceSopenharmony_ci goto ua_fail; 1074d4afb5ceSopenharmony_ci } 1075d4afb5ceSopenharmony_ci 1076d4afb5ceSopenharmony_ci if (strcmp(pss->name, "publickey")) { 1077d4afb5ceSopenharmony_ci lwsl_notice("expected 'publickey' got '%s'\n", 1078d4afb5ceSopenharmony_ci pss->name); 1079d4afb5ceSopenharmony_ci goto ua_fail; 1080d4afb5ceSopenharmony_ci } 1081d4afb5ceSopenharmony_ci pss->parser_state = SSHS_DO_UAR_SIG_PRESENT; 1082d4afb5ceSopenharmony_ci break; 1083d4afb5ceSopenharmony_ci 1084d4afb5ceSopenharmony_ci case SSHS_DO_UAR_SIG_PRESENT: 1085d4afb5ceSopenharmony_ci lwsl_info("SSHS_DO_UAR_SIG_PRESENT\n"); 1086d4afb5ceSopenharmony_ci pss->ua->sig_present = (char)*p++; 1087d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_DO_UAR_ALG); 1088d4afb5ceSopenharmony_ci /* destroyed with UA struct */ 1089d4afb5ceSopenharmony_ci break; 1090d4afb5ceSopenharmony_ci 1091d4afb5ceSopenharmony_ci case SSHS_NVC_DO_UAR_ALG: 1092d4afb5ceSopenharmony_ci pss->ua->alg = (char *)pss->last_alloc; 1093d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1094d4afb5ceSopenharmony_ci if (rsa_hash_alg_from_ident(pss->ua->alg) < 0) { 1095d4afb5ceSopenharmony_ci lwsl_notice("unknown alg\n"); 1096d4afb5ceSopenharmony_ci goto ua_fail; 1097d4afb5ceSopenharmony_ci } 1098d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_DO_UAR_PUBKEY_BLOB); 1099d4afb5ceSopenharmony_ci /* destroyed with UA struct */ 1100d4afb5ceSopenharmony_ci break; 1101d4afb5ceSopenharmony_ci 1102d4afb5ceSopenharmony_ci case SSHS_NVC_DO_UAR_PUBKEY_BLOB: 1103d4afb5ceSopenharmony_ci pss->ua->pubkey = pss->last_alloc; 1104d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1105d4afb5ceSopenharmony_ci pss->ua->pubkey_len = pss->npos; 1106d4afb5ceSopenharmony_ci /* 1107d4afb5ceSopenharmony_ci * RFC4253 1108d4afb5ceSopenharmony_ci * 1109d4afb5ceSopenharmony_ci * ssh-rsa 1110d4afb5ceSopenharmony_ci * 1111d4afb5ceSopenharmony_ci * The structure inside the blob is 1112d4afb5ceSopenharmony_ci * 1113d4afb5ceSopenharmony_ci * mpint e 1114d4afb5ceSopenharmony_ci * mpint n 1115d4afb5ceSopenharmony_ci * 1116d4afb5ceSopenharmony_ci * Let's see if this key is authorized 1117d4afb5ceSopenharmony_ci */ 1118d4afb5ceSopenharmony_ci 1119d4afb5ceSopenharmony_ci n = 1; 1120d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->is_pubkey_authorized) 1121d4afb5ceSopenharmony_ci n = pss->vhd->ops->is_pubkey_authorized( 1122d4afb5ceSopenharmony_ci pss->ua->username, pss->ua->alg, 1123d4afb5ceSopenharmony_ci pss->ua->pubkey, (int)pss->ua->pubkey_len); 1124d4afb5ceSopenharmony_ci if (n) { 1125d4afb5ceSopenharmony_ci lwsl_info("rejecting peer pubkey\n"); 1126d4afb5ceSopenharmony_ci goto ua_fail; 1127d4afb5ceSopenharmony_ci } 1128d4afb5ceSopenharmony_ci 1129d4afb5ceSopenharmony_ci if (pss->ua->sig_present) { 1130d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_DO_UAR_SIG); 1131d4afb5ceSopenharmony_ci /* destroyed with UA struct */ 1132d4afb5ceSopenharmony_ci break; 1133d4afb5ceSopenharmony_ci } 1134d4afb5ceSopenharmony_ci 1135d4afb5ceSopenharmony_ci /* 1136d4afb5ceSopenharmony_ci * This key is at least one we would be prepared 1137d4afb5ceSopenharmony_ci * to accept if he really has it... since no sig 1138d4afb5ceSopenharmony_ci * client should resend everything with a sig 1139d4afb5ceSopenharmony_ci * appended. OK it and delete this initial UA 1140d4afb5ceSopenharmony_ci */ 1141d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_UA_PK_OK); 1142d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1143d4afb5ceSopenharmony_ci break; 1144d4afb5ceSopenharmony_ci 1145d4afb5ceSopenharmony_ci case SSHS_NVC_DO_UAR_SIG: 1146d4afb5ceSopenharmony_ci /* 1147d4afb5ceSopenharmony_ci * Now the pubkey is coming with a sig 1148d4afb5ceSopenharmony_ci */ 1149d4afb5ceSopenharmony_ci /* Sect 5.1 RFC4252 1150d4afb5ceSopenharmony_ci * 1151d4afb5ceSopenharmony_ci * SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. 1152d4afb5ceSopenharmony_ci * When SSH_MSG_USERAUTH_SUCCESS has been sent, any 1153d4afb5ceSopenharmony_ci * further authentication requests received after that 1154d4afb5ceSopenharmony_ci * SHOULD be silently ignored. 1155d4afb5ceSopenharmony_ci */ 1156d4afb5ceSopenharmony_ci if (pss->ssh_auth_state == SSH_AUTH_STATE_GAVE_AUTH_IGNORE_REQS) { 1157d4afb5ceSopenharmony_ci lwsl_info("Silently ignoring auth req after accepted\n"); 1158d4afb5ceSopenharmony_ci goto ua_fail_silently; 1159d4afb5ceSopenharmony_ci } 1160d4afb5ceSopenharmony_ci lwsl_info("SSHS_DO_UAR_SIG\n"); 1161d4afb5ceSopenharmony_ci pss->ua->sig = pss->last_alloc; 1162d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1163d4afb5ceSopenharmony_ci pss->ua->sig_len = pss->npos; 1164d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1165d4afb5ceSopenharmony_ci 1166d4afb5ceSopenharmony_ci /* 1167d4afb5ceSopenharmony_ci * RFC 4252 p9 1168d4afb5ceSopenharmony_ci * 1169d4afb5ceSopenharmony_ci * The value of 'signature' is a signature with 1170d4afb5ceSopenharmony_ci * the private host key of the following data, in 1171d4afb5ceSopenharmony_ci * this order: 1172d4afb5ceSopenharmony_ci * 1173d4afb5ceSopenharmony_ci * string session identifier 1174d4afb5ceSopenharmony_ci * byte SSH_MSG_USERAUTH_REQUEST 1175d4afb5ceSopenharmony_ci * string user name 1176d4afb5ceSopenharmony_ci * string service name 1177d4afb5ceSopenharmony_ci * string "publickey" 1178d4afb5ceSopenharmony_ci * boolean TRUE 1179d4afb5ceSopenharmony_ci * string public key algorithm name 1180d4afb5ceSopenharmony_ci * string public key to be used for auth 1181d4afb5ceSopenharmony_ci * 1182d4afb5ceSopenharmony_ci * We reproduce the signature plaintext and the 1183d4afb5ceSopenharmony_ci * hash, and then decrypt the incoming signed block. 1184d4afb5ceSopenharmony_ci * What comes out is some ASN1, in there is the 1185d4afb5ceSopenharmony_ci * hash decrypted. We find it and confirm it 1186d4afb5ceSopenharmony_ci * matches the hash we computed ourselves. 1187d4afb5ceSopenharmony_ci * 1188d4afb5ceSopenharmony_ci * First step is generate the sig plaintext 1189d4afb5ceSopenharmony_ci */ 1190d4afb5ceSopenharmony_ci n = 4 + 32 + 1191d4afb5ceSopenharmony_ci 1 + 1192d4afb5ceSopenharmony_ci 4 + (int)strlen(pss->ua->username) + 1193d4afb5ceSopenharmony_ci 4 + (int)strlen(pss->ua->service) + 1194d4afb5ceSopenharmony_ci 4 + 9 + 1195d4afb5ceSopenharmony_ci 1 + 1196d4afb5ceSopenharmony_ci 4 + (int)strlen(pss->ua->alg) + 1197d4afb5ceSopenharmony_ci 4 + (int)pss->ua->pubkey_len; 1198d4afb5ceSopenharmony_ci 1199d4afb5ceSopenharmony_ci ps = sshd_zalloc((unsigned int)n); 1200d4afb5ceSopenharmony_ci if (!ps) { 1201d4afb5ceSopenharmony_ci lwsl_notice("OOM 4\n"); 1202d4afb5ceSopenharmony_ci goto ua_fail; 1203d4afb5ceSopenharmony_ci } 1204d4afb5ceSopenharmony_ci 1205d4afb5ceSopenharmony_ci pp = ps; 1206d4afb5ceSopenharmony_ci lws_buf(&pp, pss->session_id, 32); 1207d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_USERAUTH_REQUEST; 1208d4afb5ceSopenharmony_ci lws_cstr(&pp, pss->ua->username, 64); 1209d4afb5ceSopenharmony_ci lws_cstr(&pp, pss->ua->service, 64); 1210d4afb5ceSopenharmony_ci lws_cstr(&pp, "publickey", 64); 1211d4afb5ceSopenharmony_ci *pp++ = 1; 1212d4afb5ceSopenharmony_ci lws_cstr(&pp, pss->ua->alg, 64); 1213d4afb5ceSopenharmony_ci lws_buf(&pp, pss->ua->pubkey, pss->ua->pubkey_len); 1214d4afb5ceSopenharmony_ci 1215d4afb5ceSopenharmony_ci /* Next hash the plaintext */ 1216d4afb5ceSopenharmony_ci 1217d4afb5ceSopenharmony_ci if (lws_genhash_init(&pss->ua->hash_ctx, 1218d4afb5ceSopenharmony_ci (enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg))) { 1219d4afb5ceSopenharmony_ci lwsl_notice("genhash init failed\n"); 1220d4afb5ceSopenharmony_ci free(ps); 1221d4afb5ceSopenharmony_ci goto ua_fail; 1222d4afb5ceSopenharmony_ci } 1223d4afb5ceSopenharmony_ci 1224d4afb5ceSopenharmony_ci if (lws_genhash_update(&pss->ua->hash_ctx, ps, lws_ptr_diff_size_t(pp, ps))) { 1225d4afb5ceSopenharmony_ci lwsl_notice("genhash update failed\n"); 1226d4afb5ceSopenharmony_ci free(ps); 1227d4afb5ceSopenharmony_ci goto ua_fail; 1228d4afb5ceSopenharmony_ci } 1229d4afb5ceSopenharmony_ci lws_genhash_destroy(&pss->ua->hash_ctx, hash); 1230d4afb5ceSopenharmony_ci free(ps); 1231d4afb5ceSopenharmony_ci 1232d4afb5ceSopenharmony_ci /* 1233d4afb5ceSopenharmony_ci * Prepare the RSA decryption context: load in 1234d4afb5ceSopenharmony_ci * the E and N factors 1235d4afb5ceSopenharmony_ci */ 1236d4afb5ceSopenharmony_ci 1237d4afb5ceSopenharmony_ci memset(e, 0, sizeof(e)); 1238d4afb5ceSopenharmony_ci pp = pss->ua->pubkey; 1239d4afb5ceSopenharmony_ci m = lws_g32(&pp); 1240d4afb5ceSopenharmony_ci pp += m; 1241d4afb5ceSopenharmony_ci m = lws_g32(&pp); 1242d4afb5ceSopenharmony_ci e[LWS_GENCRYPTO_RSA_KEYEL_E].buf = pp; 1243d4afb5ceSopenharmony_ci e[LWS_GENCRYPTO_RSA_KEYEL_E].len = m; 1244d4afb5ceSopenharmony_ci pp += m; 1245d4afb5ceSopenharmony_ci m = lws_g32(&pp); 1246d4afb5ceSopenharmony_ci e[LWS_GENCRYPTO_RSA_KEYEL_N].buf = pp; 1247d4afb5ceSopenharmony_ci e[LWS_GENCRYPTO_RSA_KEYEL_N].len = m; 1248d4afb5ceSopenharmony_ci 1249d4afb5ceSopenharmony_ci if (lws_genrsa_create(&ctx, e, pss->vhd->context, 1250d4afb5ceSopenharmony_ci LGRSAM_PKCS1_1_5, 1251d4afb5ceSopenharmony_ci LWS_GENHASH_TYPE_UNKNOWN)) 1252d4afb5ceSopenharmony_ci goto ua_fail; 1253d4afb5ceSopenharmony_ci /* 1254d4afb5ceSopenharmony_ci * point to the encrypted signature payload we 1255d4afb5ceSopenharmony_ci * were sent 1256d4afb5ceSopenharmony_ci */ 1257d4afb5ceSopenharmony_ci pp = pss->ua->sig; 1258d4afb5ceSopenharmony_ci m = lws_g32(&pp); 1259d4afb5ceSopenharmony_ci pp += m; 1260d4afb5ceSopenharmony_ci m = lws_g32(&pp); 1261d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000 1262d4afb5ceSopenharmony_ci 1263d4afb5ceSopenharmony_ci /* 1264d4afb5ceSopenharmony_ci * decrypt it, resulting in an error, or some ASN1 1265d4afb5ceSopenharmony_ci * including the decrypted signature 1266d4afb5ceSopenharmony_ci */ 1267d4afb5ceSopenharmony_ci otmp = sshd_zalloc(m); 1268d4afb5ceSopenharmony_ci if (!otmp) 1269d4afb5ceSopenharmony_ci /* ua_fail1 frees bn_e, bn_n and rsa */ 1270d4afb5ceSopenharmony_ci goto ua_fail1; 1271d4afb5ceSopenharmony_ci 1272d4afb5ceSopenharmony_ci n = lws_genrsa_public_decrypt(&ctx, pp, m, otmp, m); 1273d4afb5ceSopenharmony_ci if (n > 0) { 1274d4afb5ceSopenharmony_ci /* the decrypted sig is in ASN1 format */ 1275d4afb5ceSopenharmony_ci m = 0; 1276d4afb5ceSopenharmony_ci while ((int)m < n) { 1277d4afb5ceSopenharmony_ci /* sig payload */ 1278d4afb5ceSopenharmony_ci if (otmp[m] == 0x04 && 1279d4afb5ceSopenharmony_ci otmp[m + 1] == lws_genhash_size( 1280d4afb5ceSopenharmony_ci pss->ua->hash_ctx.type)) { 1281d4afb5ceSopenharmony_ci m = (uint32_t)memcmp(&otmp[m + 2], hash, 1282d4afb5ceSopenharmony_ci (unsigned int)lws_genhash_size(pss->ua->hash_ctx.type)); 1283d4afb5ceSopenharmony_ci break; 1284d4afb5ceSopenharmony_ci } 1285d4afb5ceSopenharmony_ci /* go into these */ 1286d4afb5ceSopenharmony_ci if (otmp[m] == 0x30) { 1287d4afb5ceSopenharmony_ci m += 2; 1288d4afb5ceSopenharmony_ci continue; 1289d4afb5ceSopenharmony_ci } 1290d4afb5ceSopenharmony_ci /* otherwise skip payloads */ 1291d4afb5ceSopenharmony_ci m += (uint32_t)(otmp[m + 1] + 2); 1292d4afb5ceSopenharmony_ci } 1293d4afb5ceSopenharmony_ci } 1294d4afb5ceSopenharmony_ci 1295d4afb5ceSopenharmony_ci free(otmp); 1296d4afb5ceSopenharmony_ci #else 1297d4afb5ceSopenharmony_ci ctx.ctx->MBEDTLS_PRIVATE(len) = m; 1298d4afb5ceSopenharmony_ci n = lws_genrsa_hash_sig_verify(&ctx, hash, 1299d4afb5ceSopenharmony_ci (enum lws_genhash_types)rsa_hash_alg_from_ident(pss->ua->alg), 1300d4afb5ceSopenharmony_ci pp, m) == 0 ? 1 : 0; 1301d4afb5ceSopenharmony_ci #endif 1302d4afb5ceSopenharmony_ci lws_genrsa_destroy(&ctx); 1303d4afb5ceSopenharmony_ci 1304d4afb5ceSopenharmony_ci /* 1305d4afb5ceSopenharmony_ci * if no good, m is nonzero and inform peer 1306d4afb5ceSopenharmony_ci */ 1307d4afb5ceSopenharmony_ci if (n <= 0) { 1308d4afb5ceSopenharmony_ci lwsl_notice("hash sig verify fail: %d\n", m); 1309d4afb5ceSopenharmony_ci goto ua_fail; 1310d4afb5ceSopenharmony_ci } 1311d4afb5ceSopenharmony_ci 1312d4afb5ceSopenharmony_ci /* if it checks out, inform peer */ 1313d4afb5ceSopenharmony_ci 1314d4afb5ceSopenharmony_ci lwsl_info("sig check OK\n"); 1315d4afb5ceSopenharmony_ci 1316d4afb5ceSopenharmony_ci /* Sect 5.1 RFC4252 1317d4afb5ceSopenharmony_ci * 1318d4afb5ceSopenharmony_ci * SSH_MSG_USERAUTH_SUCCESS MUST be sent only once. 1319d4afb5ceSopenharmony_ci * When SSH_MSG_USERAUTH_SUCCESS has been sent, any 1320d4afb5ceSopenharmony_ci * further authentication requests received after that 1321d4afb5ceSopenharmony_ci * SHOULD be silently ignored. 1322d4afb5ceSopenharmony_ci */ 1323d4afb5ceSopenharmony_ci pss->ssh_auth_state = SSH_AUTH_STATE_GAVE_AUTH_IGNORE_REQS; 1324d4afb5ceSopenharmony_ci 1325d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_UA_SUCCESS); 1326d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 1327d4afb5ceSopenharmony_ci break; 1328d4afb5ceSopenharmony_ci 1329d4afb5ceSopenharmony_ci /* 1330d4afb5ceSopenharmony_ci * Channels 1331d4afb5ceSopenharmony_ci */ 1332d4afb5ceSopenharmony_ci 1333d4afb5ceSopenharmony_ci case SSHS_GET_U32: 1334d4afb5ceSopenharmony_ci pss->len = (pss->len << 8) | *p++; 1335d4afb5ceSopenharmony_ci if (++pss->ctr != 4) 1336d4afb5ceSopenharmony_ci break; 1337d4afb5ceSopenharmony_ci pss->ctr = 0; 1338d4afb5ceSopenharmony_ci pss->parser_state = pss->state_after_string; 1339d4afb5ceSopenharmony_ci goto again; 1340d4afb5ceSopenharmony_ci 1341d4afb5ceSopenharmony_ci /* 1342d4afb5ceSopenharmony_ci * Channel: Disconnect 1343d4afb5ceSopenharmony_ci */ 1344d4afb5ceSopenharmony_ci 1345d4afb5ceSopenharmony_ci case SSHS_NVC_DISCONNECT_REASON: 1346d4afb5ceSopenharmony_ci pss->disconnect_reason = pss->len; 1347d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_DISCONNECT_DESC); 1348d4afb5ceSopenharmony_ci break; 1349d4afb5ceSopenharmony_ci 1350d4afb5ceSopenharmony_ci case SSHS_NVC_DISCONNECT_DESC: 1351d4afb5ceSopenharmony_ci pss->disconnect_desc = (char *)pss->last_alloc; 1352d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1353d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_DISCONNECT_LANG); 1354d4afb5ceSopenharmony_ci break; 1355d4afb5ceSopenharmony_ci 1356d4afb5ceSopenharmony_ci case SSHS_NVC_DISCONNECT_LANG: 1357d4afb5ceSopenharmony_ci lwsl_notice("SSHS_NVC_DISCONNECT_LANG\n"); 1358d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->disconnect_reason) 1359d4afb5ceSopenharmony_ci pss->vhd->ops->disconnect_reason( 1360d4afb5ceSopenharmony_ci pss->disconnect_reason, 1361d4afb5ceSopenharmony_ci pss->disconnect_desc, pss->name); 1362d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 1363d4afb5ceSopenharmony_ci break; 1364d4afb5ceSopenharmony_ci 1365d4afb5ceSopenharmony_ci /* 1366d4afb5ceSopenharmony_ci * Channel: Open 1367d4afb5ceSopenharmony_ci */ 1368d4afb5ceSopenharmony_ci 1369d4afb5ceSopenharmony_ci case SSHS_NVC_CHOPEN_TYPE: 1370d4afb5ceSopenharmony_ci /* channel open */ 1371d4afb5ceSopenharmony_ci if (strcmp(pss->name, "session")) { 1372d4afb5ceSopenharmony_ci lwsl_notice("Failing on not session\n"); 1373d4afb5ceSopenharmony_ci pss->reason = 3; 1374d4afb5ceSopenharmony_ci goto ch_fail; 1375d4afb5ceSopenharmony_ci } 1376d4afb5ceSopenharmony_ci lwsl_info("SSHS_NVC_CHOPEN_TYPE: creating session\n"); 1377d4afb5ceSopenharmony_ci pss->ch_temp = sshd_zalloc(sizeof(*pss->ch_temp)); 1378d4afb5ceSopenharmony_ci if (!pss->ch_temp) 1379d4afb5ceSopenharmony_ci return -1; 1380d4afb5ceSopenharmony_ci 1381d4afb5ceSopenharmony_ci pss->ch_temp->type = SSH_CH_TYPE_SESSION; 1382d4afb5ceSopenharmony_ci pss->ch_temp->pss = pss; 1383d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHOPEN_SENDER_CH); 1384d4afb5ceSopenharmony_ci break; 1385d4afb5ceSopenharmony_ci 1386d4afb5ceSopenharmony_ci case SSHS_NVC_CHOPEN_SENDER_CH: 1387d4afb5ceSopenharmony_ci pss->ch_temp->sender_ch = pss->len; 1388d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHOPEN_WINSIZE); 1389d4afb5ceSopenharmony_ci break; 1390d4afb5ceSopenharmony_ci case SSHS_NVC_CHOPEN_WINSIZE: 1391d4afb5ceSopenharmony_ci lwsl_info("Initial window set to %d\n", pss->len); 1392d4afb5ceSopenharmony_ci pss->ch_temp->window = (int32_t)pss->len; 1393d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHOPEN_PKTSIZE); 1394d4afb5ceSopenharmony_ci break; 1395d4afb5ceSopenharmony_ci case SSHS_NVC_CHOPEN_PKTSIZE: 1396d4afb5ceSopenharmony_ci pss->ch_temp->max_pkt = pss->len; 1397d4afb5ceSopenharmony_ci pss->ch_temp->peer_window_est = LWS_SSH_INITIAL_WINDOW; 1398d4afb5ceSopenharmony_ci pss->ch_temp->server_ch = (uint32_t)pss->next_ch_num++; 1399d4afb5ceSopenharmony_ci /* 1400d4afb5ceSopenharmony_ci * add us to channel list... leave as ch_temp 1401d4afb5ceSopenharmony_ci * as write task needs it and will NULL down 1402d4afb5ceSopenharmony_ci */ 1403d4afb5ceSopenharmony_ci lwsl_info("creating new session ch\n"); 1404d4afb5ceSopenharmony_ci pss->ch_temp->next = pss->ch_list; 1405d4afb5ceSopenharmony_ci pss->ch_list = pss->ch_temp; 1406d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->channel_create) 1407d4afb5ceSopenharmony_ci pss->vhd->ops->channel_create(pss->wsi, 1408d4afb5ceSopenharmony_ci &pss->ch_temp->priv); 1409d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_CH_OPEN_CONF); 1410d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1411d4afb5ceSopenharmony_ci break; 1412d4afb5ceSopenharmony_ci 1413d4afb5ceSopenharmony_ci /* 1414d4afb5ceSopenharmony_ci * SSH_MSG_CHANNEL_REQUEST 1415d4afb5ceSopenharmony_ci */ 1416d4afb5ceSopenharmony_ci 1417d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_RECIP: 1418d4afb5ceSopenharmony_ci pss->ch_recip = pss->len; 1419d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CHRQ_TYPE); 1420d4afb5ceSopenharmony_ci break; 1421d4afb5ceSopenharmony_ci 1422d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_TYPE: 1423d4afb5ceSopenharmony_ci pss->parser_state = SSHS_CHRQ_WANT_REPLY; 1424d4afb5ceSopenharmony_ci break; 1425d4afb5ceSopenharmony_ci 1426d4afb5ceSopenharmony_ci case SSHS_CHRQ_WANT_REPLY: 1427d4afb5ceSopenharmony_ci pss->rq_want_reply = *p++; 1428d4afb5ceSopenharmony_ci lwsl_info("SSHS_CHRQ_WANT_REPLY: %s, wantrep: %d\n", 1429d4afb5ceSopenharmony_ci pss->name, pss->rq_want_reply); 1430d4afb5ceSopenharmony_ci 1431d4afb5ceSopenharmony_ci pss->ch_temp = ssh_get_server_ch(pss, pss->ch_recip); 1432d4afb5ceSopenharmony_ci 1433d4afb5ceSopenharmony_ci /* after this they differ by the request */ 1434d4afb5ceSopenharmony_ci 1435d4afb5ceSopenharmony_ci /* 1436d4afb5ceSopenharmony_ci * a PTY for a shell 1437d4afb5ceSopenharmony_ci */ 1438d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "pty-req")) { 1439d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CHRQ_TERM); 1440d4afb5ceSopenharmony_ci break; 1441d4afb5ceSopenharmony_ci } 1442d4afb5ceSopenharmony_ci /* 1443d4afb5ceSopenharmony_ci * a shell 1444d4afb5ceSopenharmony_ci */ 1445d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "shell")) { 1446d4afb5ceSopenharmony_ci pss->channel_doing_spawn = pss->ch_temp->server_ch; 1447d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->shell && 1448d4afb5ceSopenharmony_ci !pss->vhd->ops->shell(pss->ch_temp->priv, 1449d4afb5ceSopenharmony_ci pss->wsi, 1450d4afb5ceSopenharmony_ci lws_ssh_exec_finish, pss->ch_temp)) { 1451d4afb5ceSopenharmony_ci 1452d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1453d4afb5ceSopenharmony_ci write_task_insert(pss, pss->ch_temp, 1454d4afb5ceSopenharmony_ci SSH_WT_CHRQ_SUCC); 1455d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1456d4afb5ceSopenharmony_ci break; 1457d4afb5ceSopenharmony_ci } 1458d4afb5ceSopenharmony_ci 1459d4afb5ceSopenharmony_ci goto chrq_fail; 1460d4afb5ceSopenharmony_ci } 1461d4afb5ceSopenharmony_ci /* 1462d4afb5ceSopenharmony_ci * env vars to be set in the shell 1463d4afb5ceSopenharmony_ci */ 1464d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "env")) { 1465d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CHRQ_ENV_NAME); 1466d4afb5ceSopenharmony_ci break; 1467d4afb5ceSopenharmony_ci } 1468d4afb5ceSopenharmony_ci 1469d4afb5ceSopenharmony_ci /* 1470d4afb5ceSopenharmony_ci * exec something 1471d4afb5ceSopenharmony_ci */ 1472d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "exec")) { 1473d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_CHRQ_EXEC_CMD); 1474d4afb5ceSopenharmony_ci break; 1475d4afb5ceSopenharmony_ci } 1476d4afb5ceSopenharmony_ci 1477d4afb5ceSopenharmony_ci /* 1478d4afb5ceSopenharmony_ci * spawn a subsystem 1479d4afb5ceSopenharmony_ci */ 1480d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "subsystem")) { 1481d4afb5ceSopenharmony_ci lwsl_notice("subsystem\n"); 1482d4afb5ceSopenharmony_ci state_get_string_alloc(pss, 1483d4afb5ceSopenharmony_ci SSHS_NVC_CHRQ_SUBSYSTEM); 1484d4afb5ceSopenharmony_ci break; 1485d4afb5ceSopenharmony_ci } 1486d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "window-change")) { 1487d4afb5ceSopenharmony_ci lwsl_info("%s: window-change\n", __func__); 1488d4afb5ceSopenharmony_ci state_get_u32(pss, 1489d4afb5ceSopenharmony_ci SSHS_NVC_CHRQ_WNDCHANGE_TW); 1490d4afb5ceSopenharmony_ci break; 1491d4afb5ceSopenharmony_ci } 1492d4afb5ceSopenharmony_ci 1493d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1494d4afb5ceSopenharmony_ci goto chrq_fail; 1495d4afb5ceSopenharmony_ci 1496d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_SKIP; 1497d4afb5ceSopenharmony_ci break; 1498d4afb5ceSopenharmony_ci 1499d4afb5ceSopenharmony_ci /* CHRQ pty-req */ 1500d4afb5ceSopenharmony_ci 1501d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_TERM: 1502d4afb5ceSopenharmony_ci memcpy(pss->args.pty.term, pss->name, 1503d4afb5ceSopenharmony_ci sizeof(pss->args.pty.term) - 1); 1504d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_TW); 1505d4afb5ceSopenharmony_ci break; 1506d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_TW: 1507d4afb5ceSopenharmony_ci pss->args.pty.width_ch = pss->len; 1508d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_TH); 1509d4afb5ceSopenharmony_ci break; 1510d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_TH: 1511d4afb5ceSopenharmony_ci pss->args.pty.height_ch = pss->len; 1512d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_TWP); 1513d4afb5ceSopenharmony_ci break; 1514d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_TWP: 1515d4afb5ceSopenharmony_ci pss->args.pty.width_px = pss->len; 1516d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_THP); 1517d4afb5ceSopenharmony_ci break; 1518d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_THP: 1519d4afb5ceSopenharmony_ci pss->args.pty.height_px = pss->len; 1520d4afb5ceSopenharmony_ci state_get_string_alloc(pss, SSHS_NVC_CHRQ_MODES); 1521d4afb5ceSopenharmony_ci break; 1522d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_MODES: 1523d4afb5ceSopenharmony_ci /* modes is a stream of byte-pairs, not a string */ 1524d4afb5ceSopenharmony_ci pss->args.pty.modes = (char *)pss->last_alloc; 1525d4afb5ceSopenharmony_ci pss->last_alloc = NULL; /* it was adopted */ 1526d4afb5ceSopenharmony_ci pss->args.pty.modes_len = pss->npos; 1527d4afb5ceSopenharmony_ci n = 0; 1528d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->pty_req) 1529d4afb5ceSopenharmony_ci n = pss->vhd->ops->pty_req(pss->ch_temp->priv, 1530d4afb5ceSopenharmony_ci &pss->args.pty); 1531d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->args.pty.modes); 1532d4afb5ceSopenharmony_ci if (n) 1533d4afb5ceSopenharmony_ci goto chrq_fail; 1534d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1535d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_CHRQ_SUCC); 1536d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1537d4afb5ceSopenharmony_ci break; 1538d4afb5ceSopenharmony_ci 1539d4afb5ceSopenharmony_ci /* CHRQ env */ 1540d4afb5ceSopenharmony_ci 1541d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_ENV_NAME: 1542d4afb5ceSopenharmony_ci strcpy(pss->args.aux, pss->name); 1543d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CHRQ_ENV_VALUE); 1544d4afb5ceSopenharmony_ci break; 1545d4afb5ceSopenharmony_ci 1546d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_ENV_VALUE: 1547d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->set_env) 1548d4afb5ceSopenharmony_ci if (pss->vhd->ops->set_env(pss->ch_temp->priv, 1549d4afb5ceSopenharmony_ci pss->args.aux, pss->name)) 1550d4afb5ceSopenharmony_ci goto chrq_fail; 1551d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1552d4afb5ceSopenharmony_ci break; 1553d4afb5ceSopenharmony_ci 1554d4afb5ceSopenharmony_ci /* CHRQ exec */ 1555d4afb5ceSopenharmony_ci 1556d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_EXEC_CMD: 1557d4afb5ceSopenharmony_ci /* 1558d4afb5ceSopenharmony_ci * byte SSH_MSG_CHANNEL_REQUEST 1559d4afb5ceSopenharmony_ci * uint32 recipient channel 1560d4afb5ceSopenharmony_ci * string "exec" 1561d4afb5ceSopenharmony_ci * boolean want reply 1562d4afb5ceSopenharmony_ci * string command 1563d4afb5ceSopenharmony_ci * 1564d4afb5ceSopenharmony_ci * This message will request that the server start the 1565d4afb5ceSopenharmony_ci * execution of the given command. The 'command' string 1566d4afb5ceSopenharmony_ci * may contain a path. Normal precautions MUST be taken 1567d4afb5ceSopenharmony_ci * to prevent the execution of unauthorized commands. 1568d4afb5ceSopenharmony_ci * 1569d4afb5ceSopenharmony_ci * scp sends "scp -t /path/..." 1570d4afb5ceSopenharmony_ci */ 1571d4afb5ceSopenharmony_ci lwsl_info("exec cmd: %s %02X\n", pss->last_alloc, *p); 1572d4afb5ceSopenharmony_ci 1573d4afb5ceSopenharmony_ci pss->channel_doing_spawn = pss->ch_temp->server_ch; 1574d4afb5ceSopenharmony_ci 1575d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->exec && 1576d4afb5ceSopenharmony_ci !pss->vhd->ops->exec(pss->ch_temp->priv, pss->wsi, 1577d4afb5ceSopenharmony_ci (const char *)pss->last_alloc, 1578d4afb5ceSopenharmony_ci lws_ssh_exec_finish, pss->ch_temp)) { 1579d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 1580d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1581d4afb5ceSopenharmony_ci write_task_insert(pss, pss->ch_temp, 1582d4afb5ceSopenharmony_ci SSH_WT_CHRQ_SUCC); 1583d4afb5ceSopenharmony_ci 1584d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1585d4afb5ceSopenharmony_ci break; 1586d4afb5ceSopenharmony_ci } 1587d4afb5ceSopenharmony_ci 1588d4afb5ceSopenharmony_ci /* 1589d4afb5ceSopenharmony_ci * even if he doesn't want to exec it, we know how to 1590d4afb5ceSopenharmony_ci * fake scp 1591d4afb5ceSopenharmony_ci */ 1592d4afb5ceSopenharmony_ci 1593d4afb5ceSopenharmony_ci /* we only alloc "exec" of scp for scp destination */ 1594d4afb5ceSopenharmony_ci n = 1; 1595d4afb5ceSopenharmony_ci if (pss->last_alloc[0] != 's' || 1596d4afb5ceSopenharmony_ci pss->last_alloc[1] != 'c' || 1597d4afb5ceSopenharmony_ci pss->last_alloc[2] != 'p' || 1598d4afb5ceSopenharmony_ci pss->last_alloc[3] != ' ') 1599d4afb5ceSopenharmony_ci /* disallow it */ 1600d4afb5ceSopenharmony_ci n = 0; 1601d4afb5ceSopenharmony_ci 1602d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 1603d4afb5ceSopenharmony_ci if (!n) 1604d4afb5ceSopenharmony_ci goto chrq_fail; 1605d4afb5ceSopenharmony_ci 1606d4afb5ceSopenharmony_ci /* our channel speaks SCP protocol now */ 1607d4afb5ceSopenharmony_ci 1608d4afb5ceSopenharmony_ci scp = sshd_zalloc(sizeof(*scp)); 1609d4afb5ceSopenharmony_ci if (!scp) 1610d4afb5ceSopenharmony_ci return -1; 1611d4afb5ceSopenharmony_ci 1612d4afb5ceSopenharmony_ci pss->ch_temp->type = SSH_CH_TYPE_SCP; 1613d4afb5ceSopenharmony_ci pss->ch_temp->sub = (lws_subprotocol *)scp; 1614d4afb5ceSopenharmony_ci 1615d4afb5ceSopenharmony_ci scp->ips = SSHS_SCP_COLLECTSTR; 1616d4afb5ceSopenharmony_ci 1617d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1618d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_CHRQ_SUCC); 1619d4afb5ceSopenharmony_ci 1620d4afb5ceSopenharmony_ci /* we start the scp protocol first by sending an ACK */ 1621d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_SCP_ACK_OKAY); 1622d4afb5ceSopenharmony_ci 1623d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1624d4afb5ceSopenharmony_ci break; 1625d4afb5ceSopenharmony_ci 1626d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_SUBSYSTEM: 1627d4afb5ceSopenharmony_ci lwsl_notice("subsystem: %s", pss->last_alloc); 1628d4afb5ceSopenharmony_ci n = 0; 1629d4afb5ceSopenharmony_ci#if 0 1630d4afb5ceSopenharmony_ci if (!strcmp(pss->name, "sftp")) { 1631d4afb5ceSopenharmony_ci lwsl_notice("SFTP session\n"); 1632d4afb5ceSopenharmony_ci pss->ch_temp->type = SSH_CH_TYPE_SFTP; 1633d4afb5ceSopenharmony_ci n = 1; 1634d4afb5ceSopenharmony_ci } 1635d4afb5ceSopenharmony_ci#endif 1636d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 1637d4afb5ceSopenharmony_ci// if (!n) 1638d4afb5ceSopenharmony_ci goto ch_fail; 1639d4afb5ceSopenharmony_ci#if 0 1640d4afb5ceSopenharmony_ci if (pss->rq_want_reply) 1641d4afb5ceSopenharmony_ci write_task(pss, ssh_get_server_ch(pss, 1642d4afb5ceSopenharmony_ci pss->ch_recip), SSH_WT_CHRQ_SUCC); 1643d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1644d4afb5ceSopenharmony_ci break; 1645d4afb5ceSopenharmony_ci#endif 1646d4afb5ceSopenharmony_ci 1647d4afb5ceSopenharmony_ci /* CHRQ window-change */ 1648d4afb5ceSopenharmony_ci 1649d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_WNDCHANGE_TW: 1650d4afb5ceSopenharmony_ci pss->args.pty.width_ch = pss->len; 1651d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TH); 1652d4afb5ceSopenharmony_ci break; 1653d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_WNDCHANGE_TH: 1654d4afb5ceSopenharmony_ci pss->args.pty.height_ch = pss->len; 1655d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_TWP); 1656d4afb5ceSopenharmony_ci break; 1657d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_WNDCHANGE_TWP: 1658d4afb5ceSopenharmony_ci pss->args.pty.width_px = pss->len; 1659d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_CHRQ_WNDCHANGE_THP); 1660d4afb5ceSopenharmony_ci break; 1661d4afb5ceSopenharmony_ci case SSHS_NVC_CHRQ_WNDCHANGE_THP: 1662d4afb5ceSopenharmony_ci pss->args.pty.height_px = pss->len; 1663d4afb5ceSopenharmony_ci pss->args.pty.term[0] = 0; 1664d4afb5ceSopenharmony_ci pss->args.pty.modes = NULL; 1665d4afb5ceSopenharmony_ci pss->args.pty.modes_len = 0; 1666d4afb5ceSopenharmony_ci n = 0; 1667d4afb5ceSopenharmony_ci if (pss->vhd->ops && pss->vhd->ops->pty_req) 1668d4afb5ceSopenharmony_ci n = pss->vhd->ops->pty_req(pss->ch_temp->priv, 1669d4afb5ceSopenharmony_ci &pss->args.pty); 1670d4afb5ceSopenharmony_ci if (n) 1671d4afb5ceSopenharmony_ci goto chrq_fail; 1672d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1673d4afb5ceSopenharmony_ci break; 1674d4afb5ceSopenharmony_ci 1675d4afb5ceSopenharmony_ci /* SSH_MSG_CHANNEL_DATA */ 1676d4afb5ceSopenharmony_ci 1677d4afb5ceSopenharmony_ci case SSHS_NVC_CD_RECIP: 1678d4afb5ceSopenharmony_ci pss->ch_recip = pss->len; 1679d4afb5ceSopenharmony_ci 1680d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->ch_recip); 1681d4afb5ceSopenharmony_ci ch->peer_window_est -= (int32_t)pss->msg_len; 1682d4afb5ceSopenharmony_ci 1683d4afb5ceSopenharmony_ci if (pss->msg_len < sizeof(pss->name)) 1684d4afb5ceSopenharmony_ci state_get_string(pss, SSHS_NVC_CD_DATA); 1685d4afb5ceSopenharmony_ci else 1686d4afb5ceSopenharmony_ci state_get_string_alloc(pss, 1687d4afb5ceSopenharmony_ci SSHS_NVC_CD_DATA_ALLOC); 1688d4afb5ceSopenharmony_ci break; 1689d4afb5ceSopenharmony_ci 1690d4afb5ceSopenharmony_ci case SSHS_NVC_CD_DATA_ALLOC: 1691d4afb5ceSopenharmony_ci case SSHS_NVC_CD_DATA: 1692d4afb5ceSopenharmony_ci /* 1693d4afb5ceSopenharmony_ci * Actual protocol incoming payload 1694d4afb5ceSopenharmony_ci */ 1695d4afb5ceSopenharmony_ci if (pss->parser_state == SSHS_NVC_CD_DATA_ALLOC) 1696d4afb5ceSopenharmony_ci pp = pss->last_alloc; 1697d4afb5ceSopenharmony_ci else 1698d4afb5ceSopenharmony_ci pp = (uint8_t *)pss->name; 1699d4afb5ceSopenharmony_ci lwsl_info("SSHS_NVC_CD_DATA\n"); 1700d4afb5ceSopenharmony_ci 1701d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->ch_recip); 1702d4afb5ceSopenharmony_ci switch (ch->type) { 1703d4afb5ceSopenharmony_ci case SSH_CH_TYPE_SCP: 1704d4afb5ceSopenharmony_ci scp = &ch->sub->scp; 1705d4afb5ceSopenharmony_ci switch (scp->ips) { 1706d4afb5ceSopenharmony_ci case SSHS_SCP_COLLECTSTR: 1707d4afb5ceSopenharmony_ci /* gather the ascii-coded headers */ 1708d4afb5ceSopenharmony_ci for (n = 0; n < (int)pss->npos; n++) 1709d4afb5ceSopenharmony_ci lwsl_notice("0x%02X %c\n", 1710d4afb5ceSopenharmony_ci pp[n], pp[n]); 1711d4afb5ceSopenharmony_ci 1712d4afb5ceSopenharmony_ci /* Header triggers the transfer? */ 1713d4afb5ceSopenharmony_ci if (pp[0] == 'C' && pp[pss->npos - 1] == '\x0a') { 1714d4afb5ceSopenharmony_ci while (*pp != ' ' && *pp != '\x0a') 1715d4afb5ceSopenharmony_ci pp++; 1716d4afb5ceSopenharmony_ci if (*pp++ != ' ') { 1717d4afb5ceSopenharmony_ci write_task(pss, ch, 1718d4afb5ceSopenharmony_ci SSH_WT_SCP_ACK_ERROR); 1719d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1720d4afb5ceSopenharmony_ci break; 1721d4afb5ceSopenharmony_ci } 1722d4afb5ceSopenharmony_ci scp->len = (uint64_t)atoll((const char *)pp); 1723d4afb5ceSopenharmony_ci lwsl_notice("scp payload %llu expected\n", 1724d4afb5ceSopenharmony_ci (unsigned long long)scp->len); 1725d4afb5ceSopenharmony_ci scp->ips = SSHS_SCP_PAYLOADIN; 1726d4afb5ceSopenharmony_ci } 1727d4afb5ceSopenharmony_ci /* ack it */ 1728d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, 1729d4afb5ceSopenharmony_ci SSH_WT_SCP_ACK_OKAY); 1730d4afb5ceSopenharmony_ci break; 1731d4afb5ceSopenharmony_ci case SSHS_SCP_PAYLOADIN: 1732d4afb5ceSopenharmony_ci /* the scp file payload */ 1733d4afb5ceSopenharmony_ci if (pss->vhd->ops) 1734d4afb5ceSopenharmony_ci pss->vhd->ops->rx(ch->priv, 1735d4afb5ceSopenharmony_ci pss->wsi, pp, pss->npos); 1736d4afb5ceSopenharmony_ci if (scp->len >= pss->npos) 1737d4afb5ceSopenharmony_ci scp->len -= pss->npos; 1738d4afb5ceSopenharmony_ci else 1739d4afb5ceSopenharmony_ci scp->len = 0; 1740d4afb5ceSopenharmony_ci if (!scp->len) { 1741d4afb5ceSopenharmony_ci lwsl_notice("scp txfer completed\n"); 1742d4afb5ceSopenharmony_ci scp->ips = SSHS_SCP_COLLECTSTR; 1743d4afb5ceSopenharmony_ci break; 1744d4afb5ceSopenharmony_ci } 1745d4afb5ceSopenharmony_ci break; 1746d4afb5ceSopenharmony_ci } 1747d4afb5ceSopenharmony_ci break; 1748d4afb5ceSopenharmony_ci default: /* scp payload */ 1749d4afb5ceSopenharmony_ci if (pss->vhd->ops) 1750d4afb5ceSopenharmony_ci pss->vhd->ops->rx(ch->priv, pss->wsi, 1751d4afb5ceSopenharmony_ci pp, pss->npos); 1752d4afb5ceSopenharmony_ci break; 1753d4afb5ceSopenharmony_ci } 1754d4afb5ceSopenharmony_ci if (pss->parser_state == SSHS_NVC_CD_DATA_ALLOC) 1755d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 1756d4afb5ceSopenharmony_ci 1757d4afb5ceSopenharmony_ci if (ch->peer_window_est < 32768) { 1758d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_WINDOW_ADJUST); 1759d4afb5ceSopenharmony_ci ch->peer_window_est += 32768; 1760d4afb5ceSopenharmony_ci lwsl_info("extra peer WINDOW_ADJUST (~ %d)\n", 1761d4afb5ceSopenharmony_ci ch->peer_window_est); 1762d4afb5ceSopenharmony_ci } 1763d4afb5ceSopenharmony_ci 1764d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1765d4afb5ceSopenharmony_ci break; 1766d4afb5ceSopenharmony_ci 1767d4afb5ceSopenharmony_ci case SSHS_NVC_WA_RECIP: 1768d4afb5ceSopenharmony_ci pss->ch_recip = pss->len; 1769d4afb5ceSopenharmony_ci state_get_u32(pss, SSHS_NVC_WA_ADD); 1770d4afb5ceSopenharmony_ci break; 1771d4afb5ceSopenharmony_ci 1772d4afb5ceSopenharmony_ci case SSHS_NVC_WA_ADD: 1773d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->ch_recip); 1774d4afb5ceSopenharmony_ci if (ch) { 1775d4afb5ceSopenharmony_ci ch->window += (int32_t)pss->len; 1776d4afb5ceSopenharmony_ci lwsl_notice("got additional window %d (now %d)\n", 1777d4afb5ceSopenharmony_ci pss->len, ch->window); 1778d4afb5ceSopenharmony_ci } 1779d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1780d4afb5ceSopenharmony_ci break; 1781d4afb5ceSopenharmony_ci 1782d4afb5ceSopenharmony_ci /* 1783d4afb5ceSopenharmony_ci * channel close 1784d4afb5ceSopenharmony_ci */ 1785d4afb5ceSopenharmony_ci 1786d4afb5ceSopenharmony_ci case SSHS_NVC_CH_EOF: 1787d4afb5ceSopenharmony_ci /* 1788d4afb5ceSopenharmony_ci * No explicit response is sent to this 1789d4afb5ceSopenharmony_ci * message. However, the application may send 1790d4afb5ceSopenharmony_ci * EOF to whatever is at the other end of the 1791d4afb5ceSopenharmony_ci * channel. Note that the channel remains open 1792d4afb5ceSopenharmony_ci * after this message, and more data may still 1793d4afb5ceSopenharmony_ci * be sent in the other direction. This message 1794d4afb5ceSopenharmony_ci * does not consume window space and can be sent 1795d4afb5ceSopenharmony_ci * even if no window space is available. 1796d4afb5ceSopenharmony_ci */ 1797d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_CHANNEL_EOF: %d\n", pss->ch_recip); 1798d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->ch_recip); 1799d4afb5ceSopenharmony_ci if (!ch) { 1800d4afb5ceSopenharmony_ci lwsl_notice("unknown ch %d\n", pss->ch_recip); 1801d4afb5ceSopenharmony_ci return -1; 1802d4afb5ceSopenharmony_ci } 1803d4afb5ceSopenharmony_ci 1804d4afb5ceSopenharmony_ci if (!ch->scheduled_close) { 1805d4afb5ceSopenharmony_ci lwsl_notice("scheduling CLOSE\n"); 1806d4afb5ceSopenharmony_ci ch->scheduled_close = 1; 1807d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_CH_CLOSE); 1808d4afb5ceSopenharmony_ci } 1809d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1810d4afb5ceSopenharmony_ci break; 1811d4afb5ceSopenharmony_ci 1812d4afb5ceSopenharmony_ci case SSHS_NVC_CH_CLOSE: 1813d4afb5ceSopenharmony_ci /* 1814d4afb5ceSopenharmony_ci * When either party wishes to terminate the 1815d4afb5ceSopenharmony_ci * channel, it sends SSH_MSG_CHANNEL_CLOSE. 1816d4afb5ceSopenharmony_ci * Upon receiving this message, a party MUST 1817d4afb5ceSopenharmony_ci * send back an SSH_MSG_CHANNEL_CLOSE unless it 1818d4afb5ceSopenharmony_ci * has already sent this message for the 1819d4afb5ceSopenharmony_ci * channel. The channel is considered closed 1820d4afb5ceSopenharmony_ci * for a party when it has both sent and 1821d4afb5ceSopenharmony_ci * received SSH_MSG_CHANNEL_CLOSE, and the 1822d4afb5ceSopenharmony_ci * party may then reuse the channel number. 1823d4afb5ceSopenharmony_ci * A party MAY send SSH_MSG_CHANNEL_CLOSE 1824d4afb5ceSopenharmony_ci * without having sent or received 1825d4afb5ceSopenharmony_ci * SSH_MSG_CHANNEL_EOF. 1826d4afb5ceSopenharmony_ci */ 1827d4afb5ceSopenharmony_ci lwsl_notice("SSH_MSG_CHANNEL_CLOSE ch %d\n", 1828d4afb5ceSopenharmony_ci pss->ch_recip); 1829d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->ch_recip); 1830d4afb5ceSopenharmony_ci if (!ch) 1831d4afb5ceSopenharmony_ci goto bail; 1832d4afb5ceSopenharmony_ci 1833d4afb5ceSopenharmony_ci pss->parser_state = SSHS_MSG_EAT_PADDING; 1834d4afb5ceSopenharmony_ci 1835d4afb5ceSopenharmony_ci if (ch->sent_close) { 1836d4afb5ceSopenharmony_ci /* 1837d4afb5ceSopenharmony_ci * This is acking our sent close... 1838d4afb5ceSopenharmony_ci * we can destroy the channel with no 1839d4afb5ceSopenharmony_ci * further communication. 1840d4afb5ceSopenharmony_ci */ 1841d4afb5ceSopenharmony_ci ssh_destroy_channel(pss, ch); 1842d4afb5ceSopenharmony_ci break; 1843d4afb5ceSopenharmony_ci } 1844d4afb5ceSopenharmony_ci 1845d4afb5ceSopenharmony_ci ch->received_close = 1; 1846d4afb5ceSopenharmony_ci ch->scheduled_close = 1; 1847d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_CH_CLOSE); 1848d4afb5ceSopenharmony_ci break; 1849d4afb5ceSopenharmony_ci 1850d4afb5ceSopenharmony_ci default: 1851d4afb5ceSopenharmony_ci break; 1852d4afb5ceSopenharmony_ci 1853d4afb5ceSopenharmony_cichrq_fail: 1854d4afb5ceSopenharmony_ci lwsl_notice("chrq_fail\n"); 1855d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_CHRQ_FAILURE); 1856d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_SKIP; 1857d4afb5ceSopenharmony_ci break; 1858d4afb5ceSopenharmony_ci 1859d4afb5ceSopenharmony_cich_fail: 1860d4afb5ceSopenharmony_ci if (pss->ch_temp) { 1861d4afb5ceSopenharmony_ci free(pss->ch_temp); 1862d4afb5ceSopenharmony_ci pss->ch_temp = NULL; 1863d4afb5ceSopenharmony_ci } 1864d4afb5ceSopenharmony_ci write_task(pss, pss->ch_temp, SSH_WT_CH_FAILURE); 1865d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_SKIP; 1866d4afb5ceSopenharmony_ci break; 1867d4afb5ceSopenharmony_ci 1868d4afb5ceSopenharmony_ci#if !defined(MBEDTLS_VERSION_NUMBER) || MBEDTLS_VERSION_NUMBER < 0x03000000 1869d4afb5ceSopenharmony_ciua_fail1: 1870d4afb5ceSopenharmony_ci#endif 1871d4afb5ceSopenharmony_ci lws_genrsa_destroy(&ctx); 1872d4afb5ceSopenharmony_ciua_fail: 1873d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_UA_FAILURE); 1874d4afb5ceSopenharmony_ciua_fail_silently: 1875d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 1876d4afb5ceSopenharmony_ci /* Sect 4, RFC4252 1877d4afb5ceSopenharmony_ci * 1878d4afb5ceSopenharmony_ci * Additionally, the implementation SHOULD limit the 1879d4afb5ceSopenharmony_ci * number of failed authentication attempts a client 1880d4afb5ceSopenharmony_ci * may perform in a single session (the RECOMMENDED 1881d4afb5ceSopenharmony_ci * limit is 20 attempts). If the threshold is 1882d4afb5ceSopenharmony_ci * exceeded, the server SHOULD disconnect. 1883d4afb5ceSopenharmony_ci */ 1884d4afb5ceSopenharmony_ci if (pss->count_auth_attempts++ > 20) 1885d4afb5ceSopenharmony_ci goto bail; 1886d4afb5ceSopenharmony_ci 1887d4afb5ceSopenharmony_ci pss->parser_state = SSH_KEX_STATE_SKIP; 1888d4afb5ceSopenharmony_ci break; 1889d4afb5ceSopenharmony_ci } 1890d4afb5ceSopenharmony_ci 1891d4afb5ceSopenharmony_ci pss->pos++; 1892d4afb5ceSopenharmony_ci } 1893d4afb5ceSopenharmony_ci 1894d4afb5ceSopenharmony_ci return 0; 1895d4afb5ceSopenharmony_cibail: 1896d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 1897d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 1898d4afb5ceSopenharmony_ci 1899d4afb5ceSopenharmony_ci return SSH_DISCONNECT_KEY_EXCHANGE_FAILED; 1900d4afb5ceSopenharmony_ci} 1901d4afb5ceSopenharmony_ci 1902d4afb5ceSopenharmony_cistatic int 1903d4afb5ceSopenharmony_ciparse(struct per_session_data__sshd *pss, uint8_t *p, size_t len) 1904d4afb5ceSopenharmony_ci{ 1905d4afb5ceSopenharmony_ci while (len--) { 1906d4afb5ceSopenharmony_ci 1907d4afb5ceSopenharmony_ci if (pss->copy_to_I_C && pss->kex->I_C_payload_len < 1908d4afb5ceSopenharmony_ci pss->kex->I_C_alloc_len && 1909d4afb5ceSopenharmony_ci pss->parser_state != SSHS_MSG_EAT_PADDING) 1910d4afb5ceSopenharmony_ci pss->kex->I_C[pss->kex->I_C_payload_len++] = *p; 1911d4afb5ceSopenharmony_ci 1912d4afb5ceSopenharmony_ci if (pss->active_keys_cts.valid && 1913d4afb5ceSopenharmony_ci pss->parser_state == SSHS_MSG_LEN) 1914d4afb5ceSopenharmony_ci /* take a copy for full decrypt */ 1915d4afb5ceSopenharmony_ci pss->packet_assembly[pss->pa_pos++] = *p; 1916d4afb5ceSopenharmony_ci 1917d4afb5ceSopenharmony_ci if (pss->active_keys_cts.valid && 1918d4afb5ceSopenharmony_ci pss->parser_state == SSHS_MSG_PADDING && 1919d4afb5ceSopenharmony_ci pss->msg_len) { 1920d4afb5ceSopenharmony_ci /* we are going to have to decrypt it */ 1921d4afb5ceSopenharmony_ci uint32_t cp, l = pss->msg_len + 4 + 1922d4afb5ceSopenharmony_ci pss->active_keys_cts.MAC_length; 1923d4afb5ceSopenharmony_ci uint8_t pt[2048]; 1924d4afb5ceSopenharmony_ci 1925d4afb5ceSopenharmony_ci len++; 1926d4afb5ceSopenharmony_ci cp = (uint32_t)len; 1927d4afb5ceSopenharmony_ci 1928d4afb5ceSopenharmony_ci if (cp > l - pss->pa_pos) 1929d4afb5ceSopenharmony_ci cp = l - pss->pa_pos; 1930d4afb5ceSopenharmony_ci 1931d4afb5ceSopenharmony_ci if (cp > sizeof(pss->packet_assembly) - 1932d4afb5ceSopenharmony_ci pss->pa_pos) { 1933d4afb5ceSopenharmony_ci lwsl_err("Packet is too big to decrypt\n"); 1934d4afb5ceSopenharmony_ci 1935d4afb5ceSopenharmony_ci goto bail; 1936d4afb5ceSopenharmony_ci } 1937d4afb5ceSopenharmony_ci if (pss->msg_len < 2 + 4) { 1938d4afb5ceSopenharmony_ci lwsl_err("packet too small\n"); 1939d4afb5ceSopenharmony_ci 1940d4afb5ceSopenharmony_ci goto bail; 1941d4afb5ceSopenharmony_ci } 1942d4afb5ceSopenharmony_ci 1943d4afb5ceSopenharmony_ci memcpy(&pss->packet_assembly[pss->pa_pos], p, cp); 1944d4afb5ceSopenharmony_ci pss->pa_pos += cp; 1945d4afb5ceSopenharmony_ci len -= cp; 1946d4afb5ceSopenharmony_ci p += cp; 1947d4afb5ceSopenharmony_ci 1948d4afb5ceSopenharmony_ci if (pss->pa_pos != l) 1949d4afb5ceSopenharmony_ci return 0; 1950d4afb5ceSopenharmony_ci 1951d4afb5ceSopenharmony_ci /* decrypt it */ 1952d4afb5ceSopenharmony_ci cp = (uint32_t)lws_chacha_decrypt(&pss->active_keys_cts, 1953d4afb5ceSopenharmony_ci pss->ssh_sequence_ctr_cts++, 1954d4afb5ceSopenharmony_ci pss->packet_assembly, 1955d4afb5ceSopenharmony_ci pss->pa_pos, pt); 1956d4afb5ceSopenharmony_ci if (cp) { 1957d4afb5ceSopenharmony_ci lwsl_notice("Decryption failed: %d\n", cp); 1958d4afb5ceSopenharmony_ci goto bail; 1959d4afb5ceSopenharmony_ci } 1960d4afb5ceSopenharmony_ci 1961d4afb5ceSopenharmony_ci if (lws_ssh_parse_plaintext(pss, pt + 4, pss->msg_len)) 1962d4afb5ceSopenharmony_ci goto bail; 1963d4afb5ceSopenharmony_ci 1964d4afb5ceSopenharmony_ci pss->pa_pos = 0; 1965d4afb5ceSopenharmony_ci pss->ctr = 0; 1966d4afb5ceSopenharmony_ci continue; 1967d4afb5ceSopenharmony_ci } 1968d4afb5ceSopenharmony_ci 1969d4afb5ceSopenharmony_ci if (lws_ssh_parse_plaintext(pss, p, 1)) 1970d4afb5ceSopenharmony_ci goto bail; 1971d4afb5ceSopenharmony_ci 1972d4afb5ceSopenharmony_ci p++; 1973d4afb5ceSopenharmony_ci } 1974d4afb5ceSopenharmony_ci 1975d4afb5ceSopenharmony_ci return 0; 1976d4afb5ceSopenharmony_ci 1977d4afb5ceSopenharmony_cibail: 1978d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 1979d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 1980d4afb5ceSopenharmony_ci 1981d4afb5ceSopenharmony_ci return SSH_DISCONNECT_KEY_EXCHANGE_FAILED; 1982d4afb5ceSopenharmony_ci} 1983d4afb5ceSopenharmony_ci 1984d4afb5ceSopenharmony_cistatic uint32_t 1985d4afb5ceSopenharmony_cipad_and_encrypt(uint8_t *dest, void *ps, uint8_t *pp, 1986d4afb5ceSopenharmony_ci struct per_session_data__sshd *pss, int skip_pad) 1987d4afb5ceSopenharmony_ci{ 1988d4afb5ceSopenharmony_ci uint32_t n; 1989d4afb5ceSopenharmony_ci 1990d4afb5ceSopenharmony_ci if (!skip_pad) 1991d4afb5ceSopenharmony_ci lws_pad_set_length(pss, ps, &pp, &pss->active_keys_stc); 1992d4afb5ceSopenharmony_ci n = (uint32_t)lws_ptr_diff(pp, ps); 1993d4afb5ceSopenharmony_ci 1994d4afb5ceSopenharmony_ci if (!pss->active_keys_stc.valid) { 1995d4afb5ceSopenharmony_ci memcpy(dest, ps, n); 1996d4afb5ceSopenharmony_ci return n; 1997d4afb5ceSopenharmony_ci } 1998d4afb5ceSopenharmony_ci 1999d4afb5ceSopenharmony_ci lws_chacha_encrypt(&pss->active_keys_stc, pss->ssh_sequence_ctr_stc, 2000d4afb5ceSopenharmony_ci ps, n, dest); 2001d4afb5ceSopenharmony_ci n += pss->active_keys_stc.MAC_length; 2002d4afb5ceSopenharmony_ci 2003d4afb5ceSopenharmony_ci return n; 2004d4afb5ceSopenharmony_ci} 2005d4afb5ceSopenharmony_ci 2006d4afb5ceSopenharmony_cistatic int 2007d4afb5ceSopenharmony_cilws_callback_raw_sshd(struct lws *wsi, enum lws_callback_reasons reason, 2008d4afb5ceSopenharmony_ci void *user, void *in, size_t len) 2009d4afb5ceSopenharmony_ci{ 2010d4afb5ceSopenharmony_ci struct per_session_data__sshd *pss = 2011d4afb5ceSopenharmony_ci (struct per_session_data__sshd *)user, **p; 2012d4afb5ceSopenharmony_ci struct per_vhost_data__sshd *vhd = NULL; 2013d4afb5ceSopenharmony_ci uint8_t buf[LWS_PRE + 1024], *pp, *ps = &buf[LWS_PRE + 512], *ps1 = NULL; 2014d4afb5ceSopenharmony_ci const struct lws_protocol_vhost_options *pvo; 2015d4afb5ceSopenharmony_ci const struct lws_protocols *prot; 2016d4afb5ceSopenharmony_ci struct lws_ssh_channel *ch; 2017d4afb5ceSopenharmony_ci char lang[10] = ""; 2018d4afb5ceSopenharmony_ci int n, m, o; 2019d4afb5ceSopenharmony_ci 2020d4afb5ceSopenharmony_ci /* 2021d4afb5ceSopenharmony_ci * Because we are an abstract protocol plugin, we will get called by 2022d4afb5ceSopenharmony_ci * wsi that actually bind to a plugin "on top of us" that calls thru 2023d4afb5ceSopenharmony_ci * to our callback. 2024d4afb5ceSopenharmony_ci * 2025d4afb5ceSopenharmony_ci * Under those circumstances, we can't simply get a pointer to our own 2026d4afb5ceSopenharmony_ci * protocol from the wsi. If there's a pss already, we can get it from 2027d4afb5ceSopenharmony_ci * there, but the first time for each connection we have to look it up. 2028d4afb5ceSopenharmony_ci */ 2029d4afb5ceSopenharmony_ci if (pss && pss->vhd) 2030d4afb5ceSopenharmony_ci vhd = (struct per_vhost_data__sshd *) 2031d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 2032d4afb5ceSopenharmony_ci pss->vhd->protocol); 2033d4afb5ceSopenharmony_ci else 2034d4afb5ceSopenharmony_ci if (lws_get_vhost(wsi)) 2035d4afb5ceSopenharmony_ci vhd = (struct per_vhost_data__sshd *) 2036d4afb5ceSopenharmony_ci lws_protocol_vh_priv_get(lws_get_vhost(wsi), 2037d4afb5ceSopenharmony_ci lws_vhost_name_to_protocol( 2038d4afb5ceSopenharmony_ci lws_get_vhost(wsi), "lws-ssh-base")); 2039d4afb5ceSopenharmony_ci 2040d4afb5ceSopenharmony_ci switch ((int)reason) { 2041d4afb5ceSopenharmony_ci case LWS_CALLBACK_PROTOCOL_INIT: 2042d4afb5ceSopenharmony_ci vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi), 2043d4afb5ceSopenharmony_ci lws_get_protocol(wsi), 2044d4afb5ceSopenharmony_ci sizeof(struct per_vhost_data__sshd)); 2045d4afb5ceSopenharmony_ci if (!vhd) 2046d4afb5ceSopenharmony_ci return 0; 2047d4afb5ceSopenharmony_ci vhd->context = lws_get_context(wsi); 2048d4afb5ceSopenharmony_ci vhd->protocol = lws_get_protocol(wsi); 2049d4afb5ceSopenharmony_ci vhd->vhost = lws_get_vhost(wsi); 2050d4afb5ceSopenharmony_ci 2051d4afb5ceSopenharmony_ci pvo = (const struct lws_protocol_vhost_options *)in; 2052d4afb5ceSopenharmony_ci while (pvo) { 2053d4afb5ceSopenharmony_ci /* 2054d4afb5ceSopenharmony_ci * the user code passes the ops struct address to us 2055d4afb5ceSopenharmony_ci * using a pvo (per-vhost option) 2056d4afb5ceSopenharmony_ci */ 2057d4afb5ceSopenharmony_ci if (!strcmp(pvo->name, "ops")) 2058d4afb5ceSopenharmony_ci vhd->ops = (const struct lws_ssh_ops *)pvo->value; 2059d4afb5ceSopenharmony_ci 2060d4afb5ceSopenharmony_ci /* 2061d4afb5ceSopenharmony_ci * the user code is telling us to get the ops struct 2062d4afb5ceSopenharmony_ci * from another protocol's protocol.user pointer 2063d4afb5ceSopenharmony_ci */ 2064d4afb5ceSopenharmony_ci if (!strcmp(pvo->name, "ops-from")) { 2065d4afb5ceSopenharmony_ci prot = lws_vhost_name_to_protocol(vhd->vhost, 2066d4afb5ceSopenharmony_ci pvo->value); 2067d4afb5ceSopenharmony_ci if (prot) 2068d4afb5ceSopenharmony_ci vhd->ops = (const struct lws_ssh_ops *)prot->user; 2069d4afb5ceSopenharmony_ci else 2070d4afb5ceSopenharmony_ci lwsl_err("%s: can't find protocol %s\n", 2071d4afb5ceSopenharmony_ci __func__, pvo->value); 2072d4afb5ceSopenharmony_ci } 2073d4afb5ceSopenharmony_ci 2074d4afb5ceSopenharmony_ci pvo = pvo->next; 2075d4afb5ceSopenharmony_ci } 2076d4afb5ceSopenharmony_ci 2077d4afb5ceSopenharmony_ci if (!vhd->ops) { 2078d4afb5ceSopenharmony_ci lwsl_warn("ssh pvo \"ops\" is mandatory\n"); 2079d4afb5ceSopenharmony_ci return 0; 2080d4afb5ceSopenharmony_ci } 2081d4afb5ceSopenharmony_ci /* 2082d4afb5ceSopenharmony_ci * The user code ops api_version has to be current 2083d4afb5ceSopenharmony_ci */ 2084d4afb5ceSopenharmony_ci if (vhd->ops->api_version != LWS_SSH_OPS_VERSION) { 2085d4afb5ceSopenharmony_ci lwsl_err("FATAL ops is api_version v%d but code is v%d\n", 2086d4afb5ceSopenharmony_ci vhd->ops->api_version, LWS_SSH_OPS_VERSION); 2087d4afb5ceSopenharmony_ci return 1; 2088d4afb5ceSopenharmony_ci } 2089d4afb5ceSopenharmony_ci break; 2090d4afb5ceSopenharmony_ci 2091d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_ADOPT: 2092d4afb5ceSopenharmony_ci lwsl_info("LWS_CALLBACK_RAW_ADOPT\n"); 2093d4afb5ceSopenharmony_ci if (!vhd || !pss) 2094d4afb5ceSopenharmony_ci return -1; 2095d4afb5ceSopenharmony_ci pss->next = vhd->live_pss_list; 2096d4afb5ceSopenharmony_ci vhd->live_pss_list = pss; 2097d4afb5ceSopenharmony_ci pss->parser_state = SSH_INITIALIZE_TRANSIENT; 2098d4afb5ceSopenharmony_ci pss->wsi = wsi; 2099d4afb5ceSopenharmony_ci pss->vhd = vhd; 2100d4afb5ceSopenharmony_ci pss->kex_state = KEX_STATE_EXPECTING_CLIENT_OFFER; 2101d4afb5ceSopenharmony_ci pss->active_keys_cts.padding_alignment = 8; 2102d4afb5ceSopenharmony_ci pss->active_keys_stc.padding_alignment = 8; 2103d4afb5ceSopenharmony_ci if (lws_kex_create(pss)) 2104d4afb5ceSopenharmony_ci return -1; 2105d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_VERSION); 2106d4afb5ceSopenharmony_ci 2107d4afb5ceSopenharmony_ci /* sect 4 RFC4252 2108d4afb5ceSopenharmony_ci * 2109d4afb5ceSopenharmony_ci * The server SHOULD have a timeout for authentication and 2110d4afb5ceSopenharmony_ci * disconnect if the authentication has not been accepted 2111d4afb5ceSopenharmony_ci * within the timeout period. 2112d4afb5ceSopenharmony_ci * 2113d4afb5ceSopenharmony_ci * The RECOMMENDED timeout period is 10 minutes. 2114d4afb5ceSopenharmony_ci */ 2115d4afb5ceSopenharmony_ci lws_set_timeout(wsi, (enum pending_timeout) 2116d4afb5ceSopenharmony_ci SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH, 10 * 60); 2117d4afb5ceSopenharmony_ci break; 2118d4afb5ceSopenharmony_ci 2119d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_CLOSE: 2120d4afb5ceSopenharmony_ci if (!pss) 2121d4afb5ceSopenharmony_ci return -1; 2122d4afb5ceSopenharmony_ci lwsl_info("LWS_CALLBACK_RAW_CLOSE\n"); 2123d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 2124d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 2125d4afb5ceSopenharmony_ci 2126d4afb5ceSopenharmony_ci ssh_free_set_NULL(pss->last_alloc); 2127d4afb5ceSopenharmony_ci 2128d4afb5ceSopenharmony_ci while (pss->ch_list) 2129d4afb5ceSopenharmony_ci ssh_destroy_channel(pss, pss->ch_list); 2130d4afb5ceSopenharmony_ci 2131d4afb5ceSopenharmony_ci lws_chacha_destroy(&pss->active_keys_cts); 2132d4afb5ceSopenharmony_ci lws_chacha_destroy(&pss->active_keys_stc); 2133d4afb5ceSopenharmony_ci 2134d4afb5ceSopenharmony_ci p = &vhd->live_pss_list; 2135d4afb5ceSopenharmony_ci 2136d4afb5ceSopenharmony_ci while (*p) { 2137d4afb5ceSopenharmony_ci if ((*p) == pss) { 2138d4afb5ceSopenharmony_ci *p = pss->next; 2139d4afb5ceSopenharmony_ci continue; 2140d4afb5ceSopenharmony_ci } 2141d4afb5ceSopenharmony_ci p = &((*p)->next); 2142d4afb5ceSopenharmony_ci } 2143d4afb5ceSopenharmony_ci break; 2144d4afb5ceSopenharmony_ci 2145d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_RX: 2146d4afb5ceSopenharmony_ci if (!pss) 2147d4afb5ceSopenharmony_ci return -1; 2148d4afb5ceSopenharmony_ci if (parse(pss, in, len)) 2149d4afb5ceSopenharmony_ci return -1; 2150d4afb5ceSopenharmony_ci break; 2151d4afb5ceSopenharmony_ci 2152d4afb5ceSopenharmony_ci case LWS_CALLBACK_RAW_WRITEABLE: 2153d4afb5ceSopenharmony_ci if (!pss) 2154d4afb5ceSopenharmony_ci break; 2155d4afb5ceSopenharmony_ci n = 0; 2156d4afb5ceSopenharmony_ci o = pss->write_task[pss->wt_tail]; 2157d4afb5ceSopenharmony_ci ch = pss->write_channel[pss->wt_tail]; 2158d4afb5ceSopenharmony_ci 2159d4afb5ceSopenharmony_ci if (pss->wt_head == pss->wt_tail) 2160d4afb5ceSopenharmony_ci o = SSH_WT_NONE; 2161d4afb5ceSopenharmony_ci 2162d4afb5ceSopenharmony_ci switch (o) { 2163d4afb5ceSopenharmony_ci case SSH_WT_VERSION: 2164d4afb5ceSopenharmony_ci if (!pss->vhd) 2165d4afb5ceSopenharmony_ci break; 2166d4afb5ceSopenharmony_ci n = lws_snprintf((char *)buf + LWS_PRE, 2167d4afb5ceSopenharmony_ci sizeof(buf) - LWS_PRE - 1, "%s\r\n", 2168d4afb5ceSopenharmony_ci pss->vhd->ops->server_string); 2169d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_OFFER); 2170d4afb5ceSopenharmony_ci break; 2171d4afb5ceSopenharmony_ci 2172d4afb5ceSopenharmony_ci case SSH_WT_OFFER: 2173d4afb5ceSopenharmony_ci if (!pss->vhd) 2174d4afb5ceSopenharmony_ci break; 2175d4afb5ceSopenharmony_ci m = 0; 2176d4afb5ceSopenharmony_ci n = (int)offer(pss, buf + LWS_PRE, 2177d4afb5ceSopenharmony_ci sizeof(buf) - LWS_PRE, 0, &m); 2178d4afb5ceSopenharmony_ci if (n == 0) { 2179d4afb5ceSopenharmony_ci lwsl_notice("Too small\n"); 2180d4afb5ceSopenharmony_ci 2181d4afb5ceSopenharmony_ci return -1; 2182d4afb5ceSopenharmony_ci } 2183d4afb5ceSopenharmony_ci 2184d4afb5ceSopenharmony_ci if (!pss->kex) { 2185d4afb5ceSopenharmony_ci lwsl_notice("%s: SSH_WT_OFFER: pss->kex is NULL\n", 2186d4afb5ceSopenharmony_ci __func__); 2187d4afb5ceSopenharmony_ci return -1; 2188d4afb5ceSopenharmony_ci } 2189d4afb5ceSopenharmony_ci 2190d4afb5ceSopenharmony_ci /* we need a copy of it to generate the hash later */ 2191d4afb5ceSopenharmony_ci if (pss->kex->I_S) 2192d4afb5ceSopenharmony_ci free(pss->kex->I_S); 2193d4afb5ceSopenharmony_ci pss->kex->I_S = sshd_zalloc((unsigned int)m); 2194d4afb5ceSopenharmony_ci if (!pss->kex->I_S) { 2195d4afb5ceSopenharmony_ci lwsl_notice("OOM 5: %d\n", m); 2196d4afb5ceSopenharmony_ci 2197d4afb5ceSopenharmony_ci return -1; 2198d4afb5ceSopenharmony_ci } 2199d4afb5ceSopenharmony_ci /* without length + padcount part */ 2200d4afb5ceSopenharmony_ci memcpy(pss->kex->I_S, buf + LWS_PRE + 5, (unsigned int)m); 2201d4afb5ceSopenharmony_ci pss->kex->I_S_payload_len = (uint32_t)m; /* without padding */ 2202d4afb5ceSopenharmony_ci break; 2203d4afb5ceSopenharmony_ci 2204d4afb5ceSopenharmony_ci case SSH_WT_OFFER_REPLY: 2205d4afb5ceSopenharmony_ci memcpy(ps, pss->kex->kex_r, pss->kex->kex_r_len); 2206d4afb5ceSopenharmony_ci n = (int)pad_and_encrypt(&buf[LWS_PRE], ps, 2207d4afb5ceSopenharmony_ci ps + pss->kex->kex_r_len, pss, 1); 2208d4afb5ceSopenharmony_ci pss->kex_state = KEX_STATE_REPLIED_TO_OFFER; 2209d4afb5ceSopenharmony_ci /* afterwards, must do newkeys */ 2210d4afb5ceSopenharmony_ci write_task(pss, NULL, SSH_WT_SEND_NEWKEYS); 2211d4afb5ceSopenharmony_ci break; 2212d4afb5ceSopenharmony_ci 2213d4afb5ceSopenharmony_ci case SSH_WT_SEND_NEWKEYS: 2214d4afb5ceSopenharmony_ci pp = ps + 5; 2215d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_NEWKEYS; 2216d4afb5ceSopenharmony_ci goto pac; 2217d4afb5ceSopenharmony_ci 2218d4afb5ceSopenharmony_ci case SSH_WT_UA_ACCEPT: 2219d4afb5ceSopenharmony_ci /* 2220d4afb5ceSopenharmony_ci * If the server supports the service (and permits 2221d4afb5ceSopenharmony_ci * the client to use it), it MUST respond with the 2222d4afb5ceSopenharmony_ci * following: 2223d4afb5ceSopenharmony_ci * 2224d4afb5ceSopenharmony_ci * byte SSH_MSG_SERVICE_ACCEPT 2225d4afb5ceSopenharmony_ci * string service name 2226d4afb5ceSopenharmony_ci */ 2227d4afb5ceSopenharmony_ci pp = ps + 5; 2228d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_SERVICE_ACCEPT; 2229d4afb5ceSopenharmony_ci lws_p32(pp, pss->npos); 2230d4afb5ceSopenharmony_ci pp += 4; 2231d4afb5ceSopenharmony_ci strcpy((char *)pp, pss->name); 2232d4afb5ceSopenharmony_ci pp += pss->npos; 2233d4afb5ceSopenharmony_ci goto pac; 2234d4afb5ceSopenharmony_ci 2235d4afb5ceSopenharmony_ci case SSH_WT_UA_FAILURE: 2236d4afb5ceSopenharmony_ci pp = ps + 5; 2237d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_USERAUTH_FAILURE; 2238d4afb5ceSopenharmony_ci lws_p32(pp, 9); 2239d4afb5ceSopenharmony_ci pp += 4; 2240d4afb5ceSopenharmony_ci strcpy((char *)pp, "publickey"); 2241d4afb5ceSopenharmony_ci pp += 9; 2242d4afb5ceSopenharmony_ci *pp++ = 0; 2243d4afb5ceSopenharmony_ci goto pac; 2244d4afb5ceSopenharmony_ci 2245d4afb5ceSopenharmony_ci case SSH_WT_UA_BANNER: 2246d4afb5ceSopenharmony_ci pp = ps + 5; 2247d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_USERAUTH_BANNER; 2248d4afb5ceSopenharmony_ci if (pss->vhd && pss->vhd->ops->banner) 2249d4afb5ceSopenharmony_ci n = (int)pss->vhd->ops->banner((char *)&buf[650], 2250d4afb5ceSopenharmony_ci 150 - 1, 2251d4afb5ceSopenharmony_ci lang, (int)sizeof(lang)); 2252d4afb5ceSopenharmony_ci lws_p32(pp, (uint32_t)n); 2253d4afb5ceSopenharmony_ci pp += 4; 2254d4afb5ceSopenharmony_ci strcpy((char *)pp, (char *)&buf[650]); 2255d4afb5ceSopenharmony_ci pp += n; 2256d4afb5ceSopenharmony_ci if (lws_cstr(&pp, lang, sizeof(lang))) 2257d4afb5ceSopenharmony_ci goto bail; 2258d4afb5ceSopenharmony_ci goto pac; 2259d4afb5ceSopenharmony_ci 2260d4afb5ceSopenharmony_ci case SSH_WT_UA_PK_OK: 2261d4afb5ceSopenharmony_ci /* 2262d4afb5ceSopenharmony_ci * The server MUST respond to this message with 2263d4afb5ceSopenharmony_ci * either SSH_MSG_USERAUTH_FAILURE or with the 2264d4afb5ceSopenharmony_ci * following: 2265d4afb5ceSopenharmony_ci * 2266d4afb5ceSopenharmony_ci * byte SSH_MSG_USERAUTH_PK_OK 2267d4afb5ceSopenharmony_ci * string public key alg name from the request 2268d4afb5ceSopenharmony_ci * string public key blob from the request 2269d4afb5ceSopenharmony_ci */ 2270d4afb5ceSopenharmony_ci n = 74 + (int)pss->ua->pubkey_len; 2271d4afb5ceSopenharmony_ci if (n > (int)sizeof(buf) - LWS_PRE) { 2272d4afb5ceSopenharmony_ci lwsl_notice("pubkey too large\n"); 2273d4afb5ceSopenharmony_ci goto bail; 2274d4afb5ceSopenharmony_ci } 2275d4afb5ceSopenharmony_ci ps1 = sshd_zalloc((unsigned int)n); 2276d4afb5ceSopenharmony_ci if (!ps1) 2277d4afb5ceSopenharmony_ci goto bail; 2278d4afb5ceSopenharmony_ci ps = ps1; 2279d4afb5ceSopenharmony_ci pp = ps1 + 5; 2280d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_USERAUTH_PK_OK; 2281d4afb5ceSopenharmony_ci if (lws_cstr(&pp, pss->ua->alg, 64)) { 2282d4afb5ceSopenharmony_ci free(ps1); 2283d4afb5ceSopenharmony_ci goto bail; 2284d4afb5ceSopenharmony_ci } 2285d4afb5ceSopenharmony_ci lws_p32(pp, pss->ua->pubkey_len); 2286d4afb5ceSopenharmony_ci pp += 4; 2287d4afb5ceSopenharmony_ci memcpy(pp, pss->ua->pubkey, pss->ua->pubkey_len); 2288d4afb5ceSopenharmony_ci pp += pss->ua->pubkey_len; 2289d4afb5ceSopenharmony_ci 2290d4afb5ceSopenharmony_ci /* we no longer need the UA now we judged it */ 2291d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 2292d4afb5ceSopenharmony_ci 2293d4afb5ceSopenharmony_ci goto pac; 2294d4afb5ceSopenharmony_ci 2295d4afb5ceSopenharmony_ci case SSH_WT_UA_SUCCESS: 2296d4afb5ceSopenharmony_ci pp = ps + 5; 2297d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_USERAUTH_SUCCESS; 2298d4afb5ceSopenharmony_ci /* end SSH_PENDING_TIMEOUT_CONNECT_TO_SUCCESSFUL_AUTH */ 2299d4afb5ceSopenharmony_ci lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0); 2300d4afb5ceSopenharmony_ci goto pac; 2301d4afb5ceSopenharmony_ci 2302d4afb5ceSopenharmony_ci case SSH_WT_CH_OPEN_CONF: 2303d4afb5ceSopenharmony_ci pp = ps + 5; 2304d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; 2305d4afb5ceSopenharmony_ci lws_p32(pp, pss->ch_temp->sender_ch); 2306d4afb5ceSopenharmony_ci pp += 4; 2307d4afb5ceSopenharmony_ci lws_p32(pp, pss->ch_temp->server_ch); 2308d4afb5ceSopenharmony_ci pp += 4; 2309d4afb5ceSopenharmony_ci /* tx initial window size towards us */ 2310d4afb5ceSopenharmony_ci lws_p32(pp, LWS_SSH_INITIAL_WINDOW); 2311d4afb5ceSopenharmony_ci pp += 4; 2312d4afb5ceSopenharmony_ci /* maximum packet size towards us */ 2313d4afb5ceSopenharmony_ci lws_p32(pp, 800); 2314d4afb5ceSopenharmony_ci pp += 4; 2315d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CH_OPEN_CONF\n"); 2316d4afb5ceSopenharmony_ci /* it's on the linked-list */ 2317d4afb5ceSopenharmony_ci pss->ch_temp = NULL; 2318d4afb5ceSopenharmony_ci goto pac; 2319d4afb5ceSopenharmony_ci 2320d4afb5ceSopenharmony_ci case SSH_WT_CH_FAILURE: 2321d4afb5ceSopenharmony_ci pp = ps + 5; 2322d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_OPEN_FAILURE; 2323d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2324d4afb5ceSopenharmony_ci pp += 4; 2325d4afb5ceSopenharmony_ci lws_p32(pp, ch->server_ch); 2326d4afb5ceSopenharmony_ci pp += 4; 2327d4afb5ceSopenharmony_ci lws_cstr(&pp, "reason", 64); 2328d4afb5ceSopenharmony_ci lws_cstr(&pp, "en/US", 64); 2329d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CH_FAILURE\n"); 2330d4afb5ceSopenharmony_ci goto pac; 2331d4afb5ceSopenharmony_ci 2332d4afb5ceSopenharmony_ci case SSH_WT_CHRQ_SUCC: 2333d4afb5ceSopenharmony_ci pp = ps + 5; 2334d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_SUCCESS; 2335d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2336d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CHRQ_SUCC\n"); 2337d4afb5ceSopenharmony_ci pp += 4; 2338d4afb5ceSopenharmony_ci goto pac; 2339d4afb5ceSopenharmony_ci 2340d4afb5ceSopenharmony_ci case SSH_WT_CHRQ_FAILURE: 2341d4afb5ceSopenharmony_ci pp = ps + 5; 2342d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_FAILURE; 2343d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2344d4afb5ceSopenharmony_ci pp += 4; 2345d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CHRQ_FAILURE\n"); 2346d4afb5ceSopenharmony_ci goto pac; 2347d4afb5ceSopenharmony_ci 2348d4afb5ceSopenharmony_ci case SSH_WT_CH_CLOSE: 2349d4afb5ceSopenharmony_ci pp = ps + 5; 2350d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_CLOSE; 2351d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2352d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CH_CLOSE\n"); 2353d4afb5ceSopenharmony_ci pp += 4; 2354d4afb5ceSopenharmony_ci goto pac; 2355d4afb5ceSopenharmony_ci 2356d4afb5ceSopenharmony_ci case SSH_WT_CH_EOF: 2357d4afb5ceSopenharmony_ci pp = ps + 5; 2358d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_EOF; 2359d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2360d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_CH_EOF\n"); 2361d4afb5ceSopenharmony_ci pp += 4; 2362d4afb5ceSopenharmony_ci goto pac; 2363d4afb5ceSopenharmony_ci 2364d4afb5ceSopenharmony_ci case SSH_WT_SCP_ACK_ERROR: 2365d4afb5ceSopenharmony_ci case SSH_WT_SCP_ACK_OKAY: 2366d4afb5ceSopenharmony_ci pp = ps + 5; 2367d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_DATA; 2368d4afb5ceSopenharmony_ci /* ps + 6 */ 2369d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2370d4afb5ceSopenharmony_ci pp += 4; 2371d4afb5ceSopenharmony_ci lws_p32(pp, 1); 2372d4afb5ceSopenharmony_ci pp += 4; 2373d4afb5ceSopenharmony_ci if (o == SSH_WT_SCP_ACK_ERROR) 2374d4afb5ceSopenharmony_ci *pp++ = 2; 2375d4afb5ceSopenharmony_ci else 2376d4afb5ceSopenharmony_ci *pp++ = 0; 2377d4afb5ceSopenharmony_ci lwsl_info("SSH_WT_SCP_ACK_OKAY\n"); 2378d4afb5ceSopenharmony_ci goto pac; 2379d4afb5ceSopenharmony_ci 2380d4afb5ceSopenharmony_ci case SSH_WT_WINDOW_ADJUST: 2381d4afb5ceSopenharmony_ci pp = ps + 5; 2382d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_WINDOW_ADJUST; 2383d4afb5ceSopenharmony_ci /* ps + 6 */ 2384d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2385d4afb5ceSopenharmony_ci pp += 4; 2386d4afb5ceSopenharmony_ci lws_p32(pp, 32768); 2387d4afb5ceSopenharmony_ci pp += 4; 2388d4afb5ceSopenharmony_ci lwsl_info("send SSH_MSG_CHANNEL_WINDOW_ADJUST\n"); 2389d4afb5ceSopenharmony_ci goto pac; 2390d4afb5ceSopenharmony_ci 2391d4afb5ceSopenharmony_ci case SSH_WT_EXIT_STATUS: 2392d4afb5ceSopenharmony_ci pp = ps + 5; 2393d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_REQUEST; 2394d4afb5ceSopenharmony_ci lws_p32(pp, ch->sender_ch); 2395d4afb5ceSopenharmony_ci pp += 4; 2396d4afb5ceSopenharmony_ci lws_p32(pp, 11); 2397d4afb5ceSopenharmony_ci pp += 4; 2398d4afb5ceSopenharmony_ci strcpy((char *)pp, "exit-status"); 2399d4afb5ceSopenharmony_ci pp += 11; 2400d4afb5ceSopenharmony_ci *pp++ = 0; 2401d4afb5ceSopenharmony_ci lws_p32(pp, (uint32_t)ch->retcode); 2402d4afb5ceSopenharmony_ci pp += 4; 2403d4afb5ceSopenharmony_ci lwsl_info("send SSH_MSG_CHANNEL_EXIT_STATUS\n"); 2404d4afb5ceSopenharmony_ci goto pac; 2405d4afb5ceSopenharmony_ci 2406d4afb5ceSopenharmony_ci case SSH_WT_NONE: 2407d4afb5ceSopenharmony_ci default: 2408d4afb5ceSopenharmony_ci /* sending payload */ 2409d4afb5ceSopenharmony_ci 2410d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, 0); 2411d4afb5ceSopenharmony_ci /* have a channel up to send on? */ 2412d4afb5ceSopenharmony_ci if (!ch) 2413d4afb5ceSopenharmony_ci break; 2414d4afb5ceSopenharmony_ci 2415d4afb5ceSopenharmony_ci if (!pss->vhd || !pss->vhd->ops) 2416d4afb5ceSopenharmony_ci break; 2417d4afb5ceSopenharmony_ci n = pss->vhd->ops->tx_waiting(ch->priv); 2418d4afb5ceSopenharmony_ci if (n < 0) 2419d4afb5ceSopenharmony_ci return -1; 2420d4afb5ceSopenharmony_ci if (!n) 2421d4afb5ceSopenharmony_ci /* nothing to send */ 2422d4afb5ceSopenharmony_ci break; 2423d4afb5ceSopenharmony_ci 2424d4afb5ceSopenharmony_ci if (n == (LWS_STDOUT | LWS_STDERR)) { 2425d4afb5ceSopenharmony_ci /* pick one using round-robin */ 2426d4afb5ceSopenharmony_ci if (pss->serviced_stderr_last) 2427d4afb5ceSopenharmony_ci n = LWS_STDOUT; 2428d4afb5ceSopenharmony_ci else 2429d4afb5ceSopenharmony_ci n = LWS_STDERR; 2430d4afb5ceSopenharmony_ci } 2431d4afb5ceSopenharmony_ci 2432d4afb5ceSopenharmony_ci pss->serviced_stderr_last = !!(n & LWS_STDERR); 2433d4afb5ceSopenharmony_ci 2434d4afb5ceSopenharmony_ci /* stdout or stderr */ 2435d4afb5ceSopenharmony_ci pp = ps + 5; 2436d4afb5ceSopenharmony_ci if (n == LWS_STDOUT) 2437d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_DATA; 2438d4afb5ceSopenharmony_ci else 2439d4afb5ceSopenharmony_ci *pp++ = SSH_MSG_CHANNEL_EXTENDED_DATA; 2440d4afb5ceSopenharmony_ci /* ps + 6 */ 2441d4afb5ceSopenharmony_ci lws_p32(pp, pss->ch_list->sender_ch); 2442d4afb5ceSopenharmony_ci m = 14; 2443d4afb5ceSopenharmony_ci if (n == LWS_STDERR) { 2444d4afb5ceSopenharmony_ci pp += 4; 2445d4afb5ceSopenharmony_ci /* data type code... 1 for stderr payload */ 2446d4afb5ceSopenharmony_ci lws_p32(pp, SSH_EXTENDED_DATA_STDERR); 2447d4afb5ceSopenharmony_ci m = 18; 2448d4afb5ceSopenharmony_ci } 2449d4afb5ceSopenharmony_ci /* also skip another strlen u32 at + 10 / +14 */ 2450d4afb5ceSopenharmony_ci pp += 8; 2451d4afb5ceSopenharmony_ci /* ps + 14 / + 18 */ 2452d4afb5ceSopenharmony_ci 2453d4afb5ceSopenharmony_ci pp += pss->vhd->ops->tx(ch->priv, n, pp, 2454d4afb5ceSopenharmony_ci lws_ptr_diff_size_t( 2455d4afb5ceSopenharmony_ci &buf[sizeof(buf) - 1], pp)); 2456d4afb5ceSopenharmony_ci 2457d4afb5ceSopenharmony_ci lws_p32(ps + m - 4, (uint32_t)lws_ptr_diff(pp, (ps + m))); 2458d4afb5ceSopenharmony_ci 2459d4afb5ceSopenharmony_ci if (pss->vhd->ops->tx_waiting(ch->priv) > 0) 2460d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 2461d4afb5ceSopenharmony_ci 2462d4afb5ceSopenharmony_ci ch->window -= lws_ptr_diff(pp, ps) - m; 2463d4afb5ceSopenharmony_ci //lwsl_debug("our send window: %d\n", ch->window); 2464d4afb5ceSopenharmony_ci 2465d4afb5ceSopenharmony_ci /* fallthru */ 2466d4afb5ceSopenharmony_cipac: 2467d4afb5ceSopenharmony_ci if (!pss->vhd) 2468d4afb5ceSopenharmony_ci break; 2469d4afb5ceSopenharmony_ci n = (int)pad_and_encrypt(&buf[LWS_PRE], ps, pp, pss, 0); 2470d4afb5ceSopenharmony_ci break; 2471d4afb5ceSopenharmony_ci 2472d4afb5ceSopenharmony_cibail: 2473d4afb5ceSopenharmony_ci lws_ua_destroy(pss); 2474d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 2475d4afb5ceSopenharmony_ci 2476d4afb5ceSopenharmony_ci return 1; 2477d4afb5ceSopenharmony_ci 2478d4afb5ceSopenharmony_ci } 2479d4afb5ceSopenharmony_ci 2480d4afb5ceSopenharmony_ci if (n > 0) { 2481d4afb5ceSopenharmony_ci m = lws_write(wsi, (unsigned char *)buf + LWS_PRE, (unsigned int)n, 2482d4afb5ceSopenharmony_ci LWS_WRITE_HTTP); 2483d4afb5ceSopenharmony_ci 2484d4afb5ceSopenharmony_ci switch(o) { 2485d4afb5ceSopenharmony_ci case SSH_WT_SEND_NEWKEYS: 2486d4afb5ceSopenharmony_ci lwsl_info("Activating STC keys\n"); 2487d4afb5ceSopenharmony_ci pss->active_keys_stc = pss->kex->keys_next_stc; 2488d4afb5ceSopenharmony_ci lws_chacha_activate(&pss->active_keys_stc); 2489d4afb5ceSopenharmony_ci pss->kex_state = KEX_STATE_CRYPTO_INITIALIZED; 2490d4afb5ceSopenharmony_ci pss->kex->newkeys |= 1; 2491d4afb5ceSopenharmony_ci if (pss->kex->newkeys == 3) 2492d4afb5ceSopenharmony_ci lws_kex_destroy(pss); 2493d4afb5ceSopenharmony_ci break; 2494d4afb5ceSopenharmony_ci case SSH_WT_UA_PK_OK: 2495d4afb5ceSopenharmony_ci free(ps1); 2496d4afb5ceSopenharmony_ci break; 2497d4afb5ceSopenharmony_ci case SSH_WT_CH_CLOSE: 2498d4afb5ceSopenharmony_ci if (ch->received_close) { 2499d4afb5ceSopenharmony_ci /* 2500d4afb5ceSopenharmony_ci * We are sending this at the behest of 2501d4afb5ceSopenharmony_ci * the remote peer... 2502d4afb5ceSopenharmony_ci * we can destroy the channel with no 2503d4afb5ceSopenharmony_ci * further communication. 2504d4afb5ceSopenharmony_ci */ 2505d4afb5ceSopenharmony_ci ssh_destroy_channel(pss, ch); 2506d4afb5ceSopenharmony_ci break; 2507d4afb5ceSopenharmony_ci } 2508d4afb5ceSopenharmony_ci ch->sent_close = 1; 2509d4afb5ceSopenharmony_ci break; 2510d4afb5ceSopenharmony_ci } 2511d4afb5ceSopenharmony_ci if (m < 0) { 2512d4afb5ceSopenharmony_ci lwsl_err("ERR %d from write\n", m); 2513d4afb5ceSopenharmony_ci goto bail; 2514d4afb5ceSopenharmony_ci } 2515d4afb5ceSopenharmony_ci 2516d4afb5ceSopenharmony_ci if (o != SSH_WT_VERSION) 2517d4afb5ceSopenharmony_ci pss->ssh_sequence_ctr_stc++; 2518d4afb5ceSopenharmony_ci 2519d4afb5ceSopenharmony_ci if (o != SSH_WT_NONE) 2520d4afb5ceSopenharmony_ci pss->wt_tail = 2521d4afb5ceSopenharmony_ci (pss->wt_tail + 1) & 7; 2522d4afb5ceSopenharmony_ci } else 2523d4afb5ceSopenharmony_ci if (o == SSH_WT_UA_PK_OK) /* free it either way */ 2524d4afb5ceSopenharmony_ci free(ps1); 2525d4afb5ceSopenharmony_ci 2526d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, 0); 2527d4afb5ceSopenharmony_ci 2528d4afb5ceSopenharmony_ci if (pss->wt_head != pss->wt_tail || 2529d4afb5ceSopenharmony_ci (ch && ch->priv && pss->vhd && 2530d4afb5ceSopenharmony_ci pss->vhd->ops->tx_waiting(ch->priv))) 2531d4afb5ceSopenharmony_ci lws_callback_on_writable(wsi); 2532d4afb5ceSopenharmony_ci 2533d4afb5ceSopenharmony_ci break; 2534d4afb5ceSopenharmony_ci 2535d4afb5ceSopenharmony_ci case LWS_CALLBACK_SSH_UART_SET_RXFLOW: 2536d4afb5ceSopenharmony_ci /* 2537d4afb5ceSopenharmony_ci * this is sent to set rxflow state on any connections that 2538d4afb5ceSopenharmony_ci * sink on a particular sink. The sink index affected is in len 2539d4afb5ceSopenharmony_ci * 2540d4afb5ceSopenharmony_ci * More than one protocol may sink to the same uart, and the 2541d4afb5ceSopenharmony_ci * protocol may select the sink itself, eg, in the URL used 2542d4afb5ceSopenharmony_ci * to set up the connection. 2543d4afb5ceSopenharmony_ci */ 2544d4afb5ceSopenharmony_ci lwsl_notice("sshd LWS_CALLBACK_SSH_UART_SET_RXFLOW: wsi %p, %d\n", 2545d4afb5ceSopenharmony_ci wsi, (int)len & 1); 2546d4afb5ceSopenharmony_ci lws_rx_flow_control(wsi, len & 1); 2547d4afb5ceSopenharmony_ci break; 2548d4afb5ceSopenharmony_ci 2549d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI: 2550d4afb5ceSopenharmony_ci if (!pss) 2551d4afb5ceSopenharmony_ci break; 2552d4afb5ceSopenharmony_ci if (pss->vhd && pss->vhd->ops && 2553d4afb5ceSopenharmony_ci pss->vhd->ops->child_process_io && 2554d4afb5ceSopenharmony_ci pss->vhd->ops->child_process_io(pss->ch_temp->priv, 2555d4afb5ceSopenharmony_ci pss->wsi, (struct lws_cgi_args *)in)) 2556d4afb5ceSopenharmony_ci return -1; 2557d4afb5ceSopenharmony_ci break; 2558d4afb5ceSopenharmony_ci 2559d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI_PROCESS_ATTACH: 2560d4afb5ceSopenharmony_ci if (!pss) 2561d4afb5ceSopenharmony_ci break; 2562d4afb5ceSopenharmony_ci ch = ssh_get_server_ch(pss, pss->channel_doing_spawn); 2563d4afb5ceSopenharmony_ci if (ch) { 2564d4afb5ceSopenharmony_ci ch->spawn_pid = (uint32_t)len; /* child process PID */ 2565d4afb5ceSopenharmony_ci lwsl_notice("associated PID %d to ch %d\n", (int)len, 2566d4afb5ceSopenharmony_ci pss->channel_doing_spawn); 2567d4afb5ceSopenharmony_ci } 2568d4afb5ceSopenharmony_ci break; 2569d4afb5ceSopenharmony_ci 2570d4afb5ceSopenharmony_ci case LWS_CALLBACK_CGI_TERMINATED: 2571d4afb5ceSopenharmony_ci if (!pss) 2572d4afb5ceSopenharmony_ci break; 2573d4afb5ceSopenharmony_ci if (pss->vhd && pss->vhd->ops && 2574d4afb5ceSopenharmony_ci pss->vhd->ops->child_process_terminated) 2575d4afb5ceSopenharmony_ci pss->vhd->ops->child_process_terminated(pss->ch_temp->priv, 2576d4afb5ceSopenharmony_ci pss->wsi); 2577d4afb5ceSopenharmony_ci /* 2578d4afb5ceSopenharmony_ci * we have the child PID in len... we need to match it to a 2579d4afb5ceSopenharmony_ci * channel that is on the wsi 2580d4afb5ceSopenharmony_ci */ 2581d4afb5ceSopenharmony_ci ch = pss->ch_list; 2582d4afb5ceSopenharmony_ci 2583d4afb5ceSopenharmony_ci while (ch) { 2584d4afb5ceSopenharmony_ci if (ch->spawn_pid == len) { 2585d4afb5ceSopenharmony_ci lwsl_notice("starting close of ch with PID %d\n", 2586d4afb5ceSopenharmony_ci (int)len); 2587d4afb5ceSopenharmony_ci ch->scheduled_close = 1; 2588d4afb5ceSopenharmony_ci write_task(pss, ch, SSH_WT_CH_CLOSE); 2589d4afb5ceSopenharmony_ci break; 2590d4afb5ceSopenharmony_ci } 2591d4afb5ceSopenharmony_ci ch = ch->next; 2592d4afb5ceSopenharmony_ci } 2593d4afb5ceSopenharmony_ci break; 2594d4afb5ceSopenharmony_ci 2595d4afb5ceSopenharmony_ci default: 2596d4afb5ceSopenharmony_ci break; 2597d4afb5ceSopenharmony_ci } 2598d4afb5ceSopenharmony_ci 2599d4afb5ceSopenharmony_ci return 0; 2600d4afb5ceSopenharmony_ci} 2601d4afb5ceSopenharmony_ci 2602d4afb5ceSopenharmony_ci#define LWS_PLUGIN_PROTOCOL_LWS_RAW_SSHD { \ 2603d4afb5ceSopenharmony_ci "lws-ssh-base", \ 2604d4afb5ceSopenharmony_ci lws_callback_raw_sshd, \ 2605d4afb5ceSopenharmony_ci sizeof(struct per_session_data__sshd), \ 2606d4afb5ceSopenharmony_ci 1024, 0, NULL, 900 \ 2607d4afb5ceSopenharmony_ci } 2608d4afb5ceSopenharmony_ci 2609d4afb5ceSopenharmony_ciLWS_VISIBLE const struct lws_protocols lws_ssh_base_protocols[] = { 2610d4afb5ceSopenharmony_ci LWS_PLUGIN_PROTOCOL_LWS_RAW_SSHD, 2611d4afb5ceSopenharmony_ci { NULL, NULL, 0, 0, 0, NULL, 0 } /* terminator */ 2612d4afb5ceSopenharmony_ci}; 2613d4afb5ceSopenharmony_ci 2614d4afb5ceSopenharmony_ci#if !defined (LWS_PLUGIN_STATIC) 2615d4afb5ceSopenharmony_ci 2616d4afb5ceSopenharmony_ciLWS_VISIBLE const lws_plugin_protocol_t lws_ssh_base = { 2617d4afb5ceSopenharmony_ci .hdr = { 2618d4afb5ceSopenharmony_ci "ssh base", 2619d4afb5ceSopenharmony_ci "lws_protocol_plugin", 2620d4afb5ceSopenharmony_ci LWS_BUILD_HASH, 2621d4afb5ceSopenharmony_ci LWS_PLUGIN_API_MAGIC 2622d4afb5ceSopenharmony_ci }, 2623d4afb5ceSopenharmony_ci 2624d4afb5ceSopenharmony_ci .protocols = lws_ssh_base_protocols, 2625d4afb5ceSopenharmony_ci .count_protocols = LWS_ARRAY_SIZE(lws_ssh_base_protocols), 2626d4afb5ceSopenharmony_ci .extensions = NULL, 2627d4afb5ceSopenharmony_ci .count_extensions = 0, 2628d4afb5ceSopenharmony_ci}; 2629d4afb5ceSopenharmony_ci 2630d4afb5ceSopenharmony_ci#endif 2631