os

An operating system
git clone https://erai.gay/code/os/
Log | Files | Refs | README | LICENSE

sshd.om (44187B)


      1 func read_line(fd: int, buf: *byte, max: int): int {
      2 	var len: int;
      3 	var ret: int;
      4 	var c: byte;
      5 	len = 0;
      6 	loop {
      7 		if len == max {
      8 			return 0;
      9 		}
     10 
     11 		ret = read(fd, &c, 1);
     12 
     13 		if ret == -EINTR {
     14 			continue;
     15 		}
     16 
     17 		if ret == 0 {
     18 			return 0;
     19 		}
     20 
     21 		if c == '\n' as byte {
     22 			buf[len] = 0 as byte;
     23 			return len;
     24 		}
     25 
     26 		if c == '\r' as byte {
     27 			continue;
     28 		}
     29 
     30 		buf[len] = c;
     31 		len = len + 1;
     32 	}
     33 }
     34 
     35 func writeall(fd: int, buf: *byte, n: int): int {
     36 	var ret: int;
     37 	loop {
     38 		if n == 0 {
     39 			return 0;
     40 		}
     41 
     42 		ret = write(fd, buf, n);
     43 		if ret == -EINTR {
     44 			continue;
     45 		}
     46 		if ret < 0 {
     47 			return ret;
     48 		}
     49 
     50 		buf = &buf[ret];
     51 		n = n - ret;
     52 	}
     53 }
     54 
     55 func read_fill(fd: int, buf: *byte, n: int): int {
     56 	var ret: int;
     57 	loop {
     58 		if n == 0 {
     59 			return 0;
     60 		}
     61 
     62 		ret = read(fd, buf, n);
     63 		if ret == -EINTR {
     64 			continue;
     65 		}
     66 
     67 		if ret <= 0 {
     68 			return -1;
     69 		}
     70 
     71 		buf = &buf[ret];
     72 		n = n - ret;
     73 	}
     74 }
     75 
     76 func read_rand(buf: *byte, n: int) {
     77 	if getrandom(buf, n, 0) != n {
     78 		die("getrandom");
     79 	}
     80 }
     81 
     82 struct _ssh_nonce {
     83 	x0: int;
     84 	x1: int;
     85 }
     86 
     87 func read_frame(ctx: *sshd_ctx) {
     88 	var len: int;
     89 	var padlen: int;
     90 	var minlen: int;
     91 	var align: int;
     92 	var maclen: int;
     93 	var tmp: int;
     94 	var _nonce: _ssh_nonce;
     95 	var nonce: *byte;
     96 	var seq: int;
     97 	var _mackey: _sha512_digest;
     98 	var mackey: *byte;
     99 	var _mac: _sha256_digest;
    100 	var mac: *byte;
    101 
    102 	nonce = (&_nonce) as *byte;
    103 	mackey = (&_mackey) as *byte;
    104 	mac = (&_mac) as *byte;
    105 
    106 	if read_fill(ctx.fd, ctx.buf, 4) != 0 {
    107 		die("truncated");
    108 	}
    109 
    110 	if ctx.en_client_to_server {
    111 		nonce[0] = 0 as byte;
    112 		nonce[1] = 0 as byte;
    113 		nonce[2] = 0 as byte;
    114 		nonce[3] = 0 as byte;
    115 		nonce[4] = (ctx.seq_client_to_server >> 56) as byte;
    116 		nonce[5] = (ctx.seq_client_to_server >> 48) as byte;
    117 		nonce[6] = (ctx.seq_client_to_server >> 40) as byte;
    118 		nonce[7] = (ctx.seq_client_to_server >> 32) as byte;
    119 		nonce[8] = (ctx.seq_client_to_server >> 24) as byte;
    120 		nonce[9] = (ctx.seq_client_to_server >> 16) as byte;
    121 		nonce[10] = (ctx.seq_client_to_server >> 8) as byte;
    122 		nonce[11] = ctx.seq_client_to_server as byte;
    123 
    124 		seq = 0;
    125 		chacha20_stream((&tmp) as *byte, ctx.buf, 4, &seq, &((&ctx.ek_client_to_server) as *byte)[32], nonce);
    126 
    127 		minlen = 16;
    128 		align = 8;
    129 		maclen = 16;
    130 
    131 		len = ((&tmp) as *byte)[3] as int
    132 			| (((&tmp) as *byte)[2] as int << 8)
    133 			| (((&tmp) as *byte)[1] as int << 16)
    134 			| (((&tmp) as *byte)[0] as int << 24);
    135 
    136 		if len % align != 0 {
    137 			die("not aligned");
    138 		}
    139 	} else {
    140 		minlen = 16;
    141 		align = 8;
    142 		maclen = 0;
    143 
    144 		len = ctx.buf[3] as int
    145 			| (ctx.buf[2] as int << 8)
    146 			| (ctx.buf[1] as int << 16)
    147 			| (ctx.buf[0] as int << 24);
    148 
    149 		if (len + 4) % align != 0 {
    150 			die("not aligned");
    151 		}
    152 	}
    153 
    154 	if len > ctx.bufsz - 4 - maclen {
    155 		die("too long");
    156 	}
    157 
    158 	if len < minlen - 4 {
    159 		die("too short");
    160 	}
    161 
    162 	if read_fill(ctx.fd, &ctx.buf[4], len + maclen) != 0 {
    163 		die("truncated");
    164 	}
    165 
    166 	if ctx.en_client_to_server {
    167 		bzero(mackey, 64);
    168 		seq = 0;
    169 		chacha20_stream(mackey, mackey, 64, &seq, (&ctx.ek_client_to_server) as *byte, nonce);
    170 		poly1305(mac, mackey, ctx.buf, len + 4);
    171 		if memcmp(mac, &ctx.buf[len + 4], 16) {
    172 			die("mac");
    173 		}
    174 		memcpy(ctx.buf, (&tmp) as *byte, 4);
    175 		seq = 64;
    176 		chacha20_stream(&ctx.buf[4], &ctx.buf[4], len, &seq, (&ctx.ek_client_to_server) as *byte, nonce);
    177 	}
    178 
    179 	padlen = ctx.buf[4] as int;
    180 
    181 	if padlen < 4 || padlen > len - 1 {
    182 		die("bad padding");
    183 	}
    184 
    185 	ctx.seq_client_to_server = (ctx.seq_client_to_server + 1) & (-1 >> 32);
    186 	ctx.frame = &ctx.buf[5];
    187 	ctx.framelen = len - padlen - 1;
    188 	ctx.index = 0;
    189 }
    190 
    191 func write_frame(ctx: *sshd_ctx) {
    192 	var len: int;
    193 	var padlen: int;
    194 	var minlen: int;
    195 	var align: int;
    196 	var maclen: int;
    197 	var _nonce: _ssh_nonce;
    198 	var nonce: *byte;
    199 	var seq: int;
    200 	var _mackey: _sha512_digest;
    201 	var mackey: *byte;
    202 
    203 	nonce = (&_nonce) as *byte;
    204 	mackey = (&_mackey) as *byte;
    205 
    206 	if ctx.en_server_to_client {
    207 		minlen = 16;
    208 		align = 8;
    209 		maclen = 16;
    210 		padlen = align - ((ctx.framelen + 1) % align);
    211 
    212 		nonce[0] = 0 as byte;
    213 		nonce[1] = 0 as byte;
    214 		nonce[2] = 0 as byte;
    215 		nonce[3] = 0 as byte;
    216 		nonce[4] = (ctx.seq_server_to_client >> 56) as byte;
    217 		nonce[5] = (ctx.seq_server_to_client >> 48) as byte;
    218 		nonce[6] = (ctx.seq_server_to_client >> 40) as byte;
    219 		nonce[7] = (ctx.seq_server_to_client >> 32) as byte;
    220 		nonce[8] = (ctx.seq_server_to_client >> 24) as byte;
    221 		nonce[9] = (ctx.seq_server_to_client >> 16) as byte;
    222 		nonce[10] = (ctx.seq_server_to_client >> 8) as byte;
    223 		nonce[11] = ctx.seq_server_to_client as byte;
    224 	} else {
    225 		minlen = 16;
    226 		align = 8;
    227 		maclen = 0;
    228 		padlen = align - ((ctx.framelen + 5) % align);
    229 	}
    230 
    231 	if padlen < 4 {
    232 		padlen = padlen + align;
    233 	}
    234 
    235 	if ctx.framelen + padlen + 5 < minlen {
    236 		padlen = padlen + align;
    237 	}
    238 
    239 	if padlen + ctx.framelen + 5 + maclen > ctx.bufsz {
    240 		die("write too large");
    241 	}
    242 
    243 	if padlen > 255 {
    244 		die("padding too large");
    245 	}
    246 
    247 	len = padlen + ctx.framelen + 1;
    248 
    249 	ctx.frame = &ctx.frame[-5];
    250 	ctx.frame[0] = (len >> 24) as byte;
    251 	ctx.frame[1] = (len >> 16) as byte;
    252 	ctx.frame[2] = (len >> 8) as byte;
    253 	ctx.frame[3] = len as byte;
    254 	ctx.frame[4] = padlen as byte;
    255 	read_rand(&ctx.frame[ctx.framelen + 5], padlen);
    256 	ctx.framelen = ctx.framelen + 5 + padlen;
    257 
    258 	if ctx.en_server_to_client {
    259 		seq = 0;
    260 		chacha20_stream(ctx.buf, ctx.buf, 4, &seq, &((&ctx.ek_server_to_client) as *byte)[32], nonce);
    261 		seq = 0;
    262 		chacha20_stream(mackey, mackey, 64, &seq, (&ctx.ek_server_to_client) as *byte, nonce);
    263 		seq = 64;
    264 		chacha20_stream(&ctx.buf[4], &ctx.buf[4], len, &seq, (&ctx.ek_server_to_client) as *byte, nonce);
    265 		poly1305(&ctx.buf[len + 4], mackey, ctx.buf, len + 4);
    266 	}
    267 
    268 	ctx.seq_server_to_client = (ctx.seq_server_to_client + 1) & (-1 >> 32);
    269 
    270 	if writeall(ctx.fd, ctx.frame, len + 4 + maclen) != 0 {
    271 		die("write truncated");
    272 	}
    273 }
    274 
    275 enum {
    276 	SSH_MSG_DISCONNECT = 0x01,
    277 	SSH_MSG_SERVICE_REQUEST = 0x05,
    278 	SSH_MSG_SERVICE_ACCEPT = 0x06,
    279 	SSH_MSG_KEXINIT = 0x14,
    280 	SSH_MSG_NEWKEYS = 0x15,
    281 	SSH_MSG_ECDH_INIT = 0x1e,
    282 	SSH_MSG_ECDH_REPLY = 0x1f,
    283 	SSH_MSG_USERAUTH_REQUEST = 0x32,
    284 	SSH_MSG_USERAUTH_FAILURE = 0x33,
    285 	SSH_MSG_USERAUTH_SUCCESS = 0x34,
    286 	SSH_MSG_USERAUTH_PK_OK = 0x3c,
    287 	SSH_MSG_CHANNEL_OPEN = 0x5a,
    288 	SSH_MSG_CHANNEL_OPEN_CONFIRMATION = 0x5b,
    289 	SSH_MSG_CHANNEL_OPEN_FAILURE = 0x5c,
    290 	SSH_MSG_CHANNEL_WINDOW_ADJUST = 0x5d,
    291 	SSH_MSG_CHANNEL_DATA = 0x5e,
    292 	SSH_MSG_CHANNEL_EXTENDED_DATA = 0x5f,
    293 	SSH_MSG_CHANNEL_EOF = 0x60,
    294 	SSH_MSG_CHANNEL_CLOSE = 0x61,
    295 	SSH_MSG_CHANNEL_REQUEST = 0x62,
    296 	SSH_MSG_CHANNEL_SUCCESS = 0x63,
    297 	SSH_MSG_CHANNEL_FAILURE = 0x64,
    298 }
    299 
    300 enum {
    301 	SSH_CR_UNKNOWN,
    302 	SSH_CR_PTY,
    303 	SSH_CR_SHELL,
    304 	SSH_CR_EXEC,
    305 	SSH_CR_WINCH,
    306 	SSH_CR_SIGNAL,
    307 	SSH_CR_EXIT_STATUS,
    308 	SSH_CR_EXIT_SIGNAL,
    309 }
    310 
    311 struct ssh_cr_pty {
    312 	term: ssh_str;
    313 	cx: int;
    314 	cy: int;
    315 	px: int;
    316 	py: int;
    317 	modes: ssh_str;
    318 }
    319 
    320 struct ssh_cr_shell {
    321 }
    322 
    323 struct ssh_cr_exec {
    324 	command: ssh_str;
    325 }
    326 
    327 struct ssh_cr_winch {
    328 	cx: int;
    329 	cy: int;
    330 	px: int;
    331 	py: int;
    332 }
    333 
    334 struct ssh_cr_signal {
    335 	name: ssh_str;
    336 }
    337 
    338 struct ssh_cr_exit {
    339 	status: int;
    340 }
    341 
    342 struct ssh_cr_exit_signal {
    343 	name: ssh_str;
    344 	core_dumpped: int;
    345 	message: ssh_str;
    346 	lang: ssh_str;
    347 }
    348 
    349 func doversion(ctx: *sshd_ctx) {
    350 	var ident: *byte;
    351 	var n: int;
    352 
    353 	//SSH-2.0-VERSION<CR><LF>
    354 	n = read_line(ctx.fd, ctx.buf, ctx.bufsz);
    355 	if n < 8 || memcmp(ctx.buf, "SSH-2.0-", 8) != 0 {
    356 		die("bad version");
    357 	}
    358 
    359 	ctx.cver = alloc(ctx.a, n + 1);
    360 	memcpy(ctx.cver, ctx.buf, n);
    361 	ctx.cver[n] = 0 as byte;
    362 
    363 	if writeall(ctx.fd, ctx.sver, strlen(ctx.sver)) != 0 {
    364 		die("write truncated");
    365 	}
    366 
    367 	if writeall(ctx.fd, "\r\n", 2) != 0 {
    368 		die("write truncated");
    369 	}
    370 }
    371 
    372 struct ssh_str {
    373 	len: int;
    374 	s: *byte;
    375 }
    376 
    377 struct ssh_disconnect {
    378 	reason: int;
    379 	description: ssh_str;
    380 	lang: ssh_str;
    381 }
    382 
    383 func decode_disconnect(p: *ssh_disconnect, ctx: *sshd_ctx) {
    384 	var tag: int;
    385 	decode_u8(&tag, ctx);
    386 	if tag != SSH_MSG_DISCONNECT {
    387 		die("not a ssh_disconnect");
    388 	}
    389 	decode_u32(&p.reason, ctx);
    390 	decode_str(&p.description, ctx);
    391 	decode_str(&p.lang, ctx);
    392 	if ctx.index != ctx.framelen {
    393 		die("trailing data");
    394 	}
    395 }
    396 
    397 func encode_disconnect(p: *ssh_disconnect, ctx: *sshd_ctx) {
    398 	var tag: int;
    399 	clear_frame(ctx);
    400 	tag = SSH_MSG_DISCONNECT;
    401 	encode_u32(&p.reason, ctx);
    402 	encode_str(&p.description, ctx);
    403 	encode_str(&p.lang, ctx);
    404 	finish_frame(ctx);
    405 }
    406 
    407 struct ssh_kexinit {
    408 	cookie: ssh_str;
    409 	kex_algorithms: ssh_str;
    410 	server_host_key_algorithms: ssh_str;
    411 	encryption_algorithms_client_to_server: ssh_str;
    412 	encryption_algorithms_server_to_client: ssh_str;
    413 	mac_algorithms_client_to_server: ssh_str;
    414 	mac_algorithms_server_to_client: ssh_str;
    415 	compression_algorithms_client_to_server: ssh_str;
    416 	compression_algorithms_server_to_client: ssh_str;
    417 	languages_client_to_server: ssh_str;
    418 	languages_server_to_client: ssh_str;
    419 	first_kex_packet_follows: int;
    420 	reserved: int;
    421 }
    422 
    423 func decode_u8(s: *int, ctx: *sshd_ctx) {
    424 	if ctx.framelen < 1 || ctx.index > ctx.framelen - 1 {
    425 		die("u8 truncated");
    426 	}
    427 	*s = ctx.frame[ctx.index] as int;
    428 	ctx.index = ctx.index + 1;
    429 }
    430 
    431 func decode_u32(s: *int, ctx: *sshd_ctx) {
    432 	if ctx.framelen < 4 || ctx.index > ctx.framelen - 4 {
    433 		die("u32 truncated");
    434 	}
    435 	*s = (ctx.frame[ctx.index] as int << 24)
    436 		| (ctx.frame[ctx.index + 1] as int << 16)
    437 		| (ctx.frame[ctx.index + 2] as int << 8)
    438 		| ctx.frame[ctx.index + 3] as int;
    439 	ctx.index = ctx.index + 4;
    440 }
    441 
    442 func decode_str(s: *ssh_str, ctx: *sshd_ctx) {
    443 	decode_u32(&s.len, ctx);
    444 	if s.len < 0 || ctx.framelen < s.len || ctx.index > ctx.framelen - s.len {
    445 		die("str truncated");
    446 	}
    447 	s.s = &ctx.frame[ctx.index];
    448 	ctx.index = ctx.index + s.len;
    449 }
    450 
    451 func decode_cookie(s: *ssh_str, ctx: *sshd_ctx) {
    452 	if ctx.framelen < 16 || ctx.index > ctx.framelen - 16 {
    453 		die("cookie truncated");
    454 	}
    455 	s.s = &ctx.frame[ctx.index];
    456 	s.len = 16;
    457 	ctx.index = ctx.index + 16;
    458 }
    459 
    460 func decode_bool(s: *int, ctx: *sshd_ctx) {
    461 	decode_u8(s, ctx);
    462 	*s = (*s != 0);
    463 }
    464 
    465 func decode_kexinit(kex: *ssh_kexinit, ctx: *sshd_ctx) {
    466 	var tag: int;
    467 	decode_u8(&tag, ctx);
    468 	if tag != SSH_MSG_KEXINIT {
    469 		die("not a kexinit");
    470 	}
    471 	decode_cookie(&kex.cookie, ctx);
    472 	decode_str(&kex.kex_algorithms, ctx);
    473 	decode_str(&kex.server_host_key_algorithms, ctx);
    474 	decode_str(&kex.encryption_algorithms_client_to_server, ctx);
    475 	decode_str(&kex.encryption_algorithms_server_to_client, ctx);
    476 	decode_str(&kex.mac_algorithms_client_to_server, ctx);
    477 	decode_str(&kex.mac_algorithms_server_to_client, ctx);
    478 	decode_str(&kex.compression_algorithms_client_to_server, ctx);
    479 	decode_str(&kex.compression_algorithms_server_to_client, ctx);
    480 	decode_str(&kex.languages_client_to_server, ctx);
    481 	decode_str(&kex.languages_server_to_client, ctx);
    482 	decode_bool(&kex.first_kex_packet_follows, ctx);
    483 	decode_u32(&kex.reserved, ctx);
    484 	if ctx.index != ctx.framelen {
    485 		die("trailing data");
    486 	}
    487 }
    488 
    489 func decode_newkeys(kex: *ssh_newkeys, ctx: *sshd_ctx) {
    490 	var tag: int;
    491 	decode_u8(&tag, ctx);
    492 	if tag != SSH_MSG_NEWKEYS {
    493 		die("not a newkeys");
    494 	}
    495 	if ctx.index != ctx.framelen {
    496 		die("trailing data");
    497 	}
    498 }
    499 
    500 struct ssh_ecdh_init {
    501 	qc: ssh_str;
    502 }
    503 
    504 func decode_ecdh_init(dh: *ssh_ecdh_init, ctx: *sshd_ctx) {
    505 	var tag: int;
    506 	decode_u8(&tag, ctx);
    507 	if tag != SSH_MSG_ECDH_INIT {
    508 		die("not a ecdh_init");
    509 	}
    510 	decode_str(&dh.qc, ctx);
    511 	if ctx.index != ctx.framelen {
    512 		die("trailing data");
    513 	}
    514 }
    515 
    516 struct ssh_service_request {
    517 	name: ssh_str;
    518 }
    519 
    520 func decode_service_request(sr: *ssh_service_request, ctx: *sshd_ctx) {
    521 	var tag: int;
    522 	decode_u8(&tag, ctx);
    523 	if tag != SSH_MSG_SERVICE_REQUEST {
    524 		die("not a ecdh_init");
    525 	}
    526 	decode_str(&sr.name, ctx);
    527 	if ctx.index != ctx.framelen {
    528 		die("trailing data");
    529 	}
    530 }
    531 
    532 struct ssh_userauth_request {
    533 	user: ssh_str;
    534 	service: ssh_str;
    535 	method: ssh_str;
    536 	has_sig: int;
    537 	alg: ssh_str;
    538 	pub: ssh_str;
    539 	sig: ssh_str;
    540 }
    541 
    542 func decode_userauth_request(ar: *ssh_userauth_request, ctx: *sshd_ctx) {
    543 	var tag: int;
    544 	decode_u8(&tag, ctx);
    545 	if tag != SSH_MSG_USERAUTH_REQUEST {
    546 		die("not a userauth_request");
    547 	}
    548 
    549 	decode_str(&ar.user, ctx);
    550 	decode_str(&ar.service, ctx);
    551 	decode_str(&ar.method, ctx);
    552 
    553 	if ssh_streq(&ar.method, "none") {
    554 		ar.has_sig = 0;
    555 		set_str(&ar.alg, "");
    556 		set_str(&ar.pub, "");
    557 		set_str(&ar.sig, "");
    558 	} else if ssh_streq(&ar.method, "publickey") {
    559 		decode_bool(&ar.has_sig, ctx);
    560 		decode_str(&ar.alg, ctx);
    561 		decode_str(&ar.pub, ctx);
    562 		if ar.has_sig {
    563 			decode_str(&ar.sig, ctx);
    564 		} else {
    565 			set_str(&ar.sig, "");
    566 		}
    567 	} else {
    568 		die("unknown method");
    569 	}
    570 
    571 	if ctx.index != ctx.framelen {
    572 		die("trailing data");
    573 	}
    574 }
    575 
    576 func set_str(s: *ssh_str, v: *byte) {
    577 	s.s = v;
    578 	s.len = strlen(v);
    579 }
    580 
    581 struct _ssh_cookie {
    582 	x0: int;
    583 	x1: int;
    584 }
    585 
    586 func clear_frame(ctx: *sshd_ctx) {
    587 	ctx.frame = &ctx.buf[5];
    588 	ctx.framelen = ctx.bufsz - 5;
    589 	ctx.index = 0;
    590 }
    591 
    592 func finish_frame(ctx: *sshd_ctx) {
    593 	ctx.framelen = ctx.index;
    594 }
    595 
    596 func encode_u8(x: *int, ctx: *sshd_ctx) {
    597 	if ctx.framelen < 1 || ctx.index > ctx.framelen - 1 {
    598 		die("u8 truncated");
    599 	}
    600 	ctx.frame[ctx.index] = (*x) as byte;
    601 	ctx.index = ctx.index + 1;
    602 }
    603 
    604 func encode_cookie(x: *ssh_str, ctx: *sshd_ctx) {
    605 	if x.len != 16 || ctx.framelen < 16 || ctx.index > ctx.framelen - 16 {
    606 		die("cookie truncated");
    607 	}
    608 	memcpy(&ctx.frame[ctx.index], x.s, 16);
    609 	ctx.index = ctx.index + 16;
    610 }
    611 
    612 func encode_bool(x: *int, ctx: *sshd_ctx) {
    613 	var y: int;
    614 	y = *x != 0;
    615 	encode_u8(&y, ctx);
    616 }
    617 
    618 func encode_u32(x: *int, ctx: *sshd_ctx) {
    619 	if ctx.framelen < 4 || ctx.index > ctx.framelen - 4 {
    620 		die("u32 truncated");
    621 	}
    622 	ctx.frame[ctx.index] = (*x >> 24) as byte;
    623 	ctx.frame[ctx.index + 1] = (*x >> 16) as byte;
    624 	ctx.frame[ctx.index + 2] = (*x >> 8) as byte;
    625 	ctx.frame[ctx.index + 3] = (*x) as byte;
    626 	ctx.index = ctx.index + 4;
    627 }
    628 
    629 func encode_blob(x: *ssh_blob, ctx: *sshd_ctx) {
    630 	var len: int;
    631 	len = x.alg.len + x.blob.len + 8;
    632 	encode_u32(&len, ctx);
    633 	encode_str(&x.alg, ctx);
    634 	encode_str(&x.blob, ctx);
    635 }
    636 
    637 func encode_str(x: *ssh_str, ctx: *sshd_ctx) {
    638 	encode_u32(&x.len, ctx);
    639 	if ctx.framelen < x.len || ctx.index > ctx.framelen - x.len {
    640 		die("str truncated");
    641 	}
    642 	memcpy(&ctx.frame[ctx.index], x.s, x.len);
    643 	ctx.index = ctx.index + x.len;
    644 }
    645 
    646 func encode_kexinit(kex: *ssh_kexinit, ctx: *sshd_ctx) {
    647 	var tag: int;
    648 	clear_frame(ctx);
    649 	tag = SSH_MSG_KEXINIT;
    650 	encode_u8(&tag, ctx);
    651 	encode_cookie(&kex.cookie, ctx);
    652 	encode_str(&kex.kex_algorithms, ctx);
    653 	encode_str(&kex.server_host_key_algorithms, ctx);
    654 	encode_str(&kex.encryption_algorithms_client_to_server, ctx);
    655 	encode_str(&kex.encryption_algorithms_server_to_client, ctx);
    656 	encode_str(&kex.mac_algorithms_client_to_server, ctx);
    657 	encode_str(&kex.mac_algorithms_server_to_client, ctx);
    658 	encode_str(&kex.compression_algorithms_client_to_server, ctx);
    659 	encode_str(&kex.compression_algorithms_server_to_client, ctx);
    660 	encode_str(&kex.languages_client_to_server, ctx);
    661 	encode_str(&kex.languages_server_to_client, ctx);
    662 	encode_bool(&kex.first_kex_packet_follows, ctx);
    663 	encode_u32(&kex.reserved, ctx);
    664 	finish_frame(ctx);
    665 }
    666 
    667 struct ssh_newkeys {
    668 }
    669 
    670 func encode_newkeys(kex: *ssh_newkeys, ctx: *sshd_ctx) {
    671 	var tag: int;
    672 	clear_frame(ctx);
    673 	tag = SSH_MSG_NEWKEYS;
    674 	encode_u8(&tag, ctx);
    675 	finish_frame(ctx);
    676 }
    677 
    678 struct ssh_service_accept {
    679 	name: ssh_str;
    680 }
    681 
    682 func encode_service_accept(sa: *ssh_service_accept, ctx: *sshd_ctx) {
    683 	var tag: int;
    684 	clear_frame(ctx);
    685 	tag = SSH_MSG_SERVICE_ACCEPT;
    686 	encode_u8(&tag, ctx);
    687 	encode_str(&sa.name, ctx);
    688 	finish_frame(ctx);
    689 }
    690 
    691 struct ssh_userauth_failure {
    692 	methods: ssh_str;
    693 	partial_success: int;
    694 }
    695 
    696 func encode_userauth_failure(uf: *ssh_userauth_failure, ctx: *sshd_ctx) {
    697 	var tag: int;
    698 	clear_frame(ctx);
    699 	tag = SSH_MSG_USERAUTH_FAILURE;
    700 	encode_u8(&tag, ctx);
    701 	encode_str(&uf.methods, ctx);
    702 	encode_bool(&uf.partial_success, ctx);
    703 	finish_frame(ctx);
    704 }
    705 
    706 struct ssh_userauth_success {
    707 }
    708 
    709 func encode_userauth_success(us: *ssh_userauth_success, ctx: *sshd_ctx) {
    710 	var tag: int;
    711 	clear_frame(ctx);
    712 	tag = SSH_MSG_USERAUTH_SUCCESS;
    713 	encode_u8(&tag, ctx);
    714 	finish_frame(ctx);
    715 }
    716 
    717 struct ssh_userauth_pk_ok {
    718 	alg: ssh_str;
    719 	pub: ssh_str;
    720 }
    721 
    722 func encode_userauth_pk_ok(ok: *ssh_userauth_pk_ok, ctx: *sshd_ctx) {
    723 	var tag: int;
    724 	clear_frame(ctx);
    725 	tag = SSH_MSG_USERAUTH_PK_OK;
    726 	encode_u8(&tag, ctx);
    727 	encode_str(&ok.alg, ctx);
    728 	encode_str(&ok.pub, ctx);
    729 	finish_frame(ctx);
    730 }
    731 
    732 struct ssh_blob {
    733 	alg: ssh_str;
    734 	blob: ssh_str;
    735 }
    736 
    737 struct ssh_ecdh_reply {
    738 	ks: ssh_blob;
    739 	qs: ssh_str;
    740 	sig: ssh_blob;
    741 }
    742 
    743 func set_blob(d: *ssh_blob, alg: *byte, b: *byte, n: int) {
    744 	set_str(&d.alg, alg);
    745 	d.blob.s = b;
    746 	d.blob.len = n;
    747 }
    748 
    749 func encode_ecdh_reply(dh: *ssh_ecdh_reply, ctx: *sshd_ctx) {
    750 	var tag: int;
    751 	clear_frame(ctx);
    752 	tag = SSH_MSG_ECDH_REPLY;
    753 	encode_u8(&tag, ctx);
    754 	encode_blob(&dh.ks, ctx);
    755 	encode_str(&dh.qs, ctx);
    756 	encode_blob(&dh.sig, ctx);
    757 	finish_frame(ctx);
    758 }
    759 
    760 func ssh_u32_sha256_update(ctx: *sha256_ctx, n: int) {
    761 	var a: byte;
    762 	a = (n >> 24) as byte;
    763 	sha256_update(ctx, &a, 1);
    764 	a = (n >> 16) as byte;
    765 	sha256_update(ctx, &a, 1);
    766 	a = (n >> 8) as byte;
    767 	sha256_update(ctx, &a, 1);
    768 	a = n as byte;
    769 	sha256_update(ctx, &a, 1);
    770 }
    771 
    772 func ssh_blob_sha256_update(ctx: *sha256_ctx, b: *ssh_blob) {
    773 	ssh_u32_sha256_update(ctx, b.alg.len + b.blob.len + 8);
    774 	ssh_str_sha256_update(ctx, b.alg.s, b.alg.len);
    775 	ssh_str_sha256_update(ctx, b.blob.s, b.blob.len);
    776 }
    777 
    778 func ssh_str_sha256_update(ctx: *sha256_ctx, b: *byte, n: int) {
    779 	ssh_u32_sha256_update(ctx, n);
    780 	sha256_update(ctx, b, n);
    781 }
    782 
    783 func ssh_mpint_sha256_update(ctx: *sha256_ctx, b: *byte, n: int) {
    784 	var a: byte;
    785 
    786 	loop {
    787 		if n == 1 {
    788 			break;
    789 		}
    790 
    791 		if b[0] as int != 0 {
    792 			break;
    793 		}
    794 
    795 		b = &b[1];
    796 		n = n - 1;
    797 	}
    798 
    799 	if b[0] as int & 128 {
    800 		ssh_u32_sha256_update(ctx, n + 1);
    801 		a = 0 as byte;
    802 		sha256_update(ctx, &a, 1);
    803 		sha256_update(ctx, b, n);
    804 	} else {
    805 		ssh_u32_sha256_update(ctx, n);
    806 		sha256_update(ctx, b, n);
    807 	}
    808 }
    809 
    810 struct ssh_channel_open {
    811 	channel_type: ssh_str;
    812 	channel: int;
    813 	initial_window_size: int;
    814 	maximum_packet_size: int;
    815 }
    816 
    817 func decode_channel_open(p: *ssh_channel_open, ctx: *sshd_ctx) {
    818 	var tag: int;
    819 	decode_u8(&tag, ctx);
    820 	if tag != SSH_MSG_CHANNEL_OPEN {
    821 		die("not a channel_open");
    822 	}
    823 
    824 	decode_str(&p.channel_type, ctx);
    825 	decode_u32(&p.channel, ctx);
    826 	decode_u32(&p.initial_window_size, ctx);
    827 	decode_u32(&p.maximum_packet_size, ctx);
    828 
    829 	if ctx.index != ctx.framelen {
    830 		die("trailing data");
    831 	}
    832 }
    833 
    834 struct ssh_channel_open_confirmation {
    835 	channel: int;
    836 	sender_channel: int;
    837 	initial_window_size: int;
    838 	maximum_packet_size: int;
    839 }
    840 
    841 func encode_channel_open_confirmation(p: *ssh_channel_open_confirmation, ctx: *sshd_ctx) {
    842 	var tag: int;
    843 	clear_frame(ctx);
    844 	tag = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
    845 	encode_u8(&tag, ctx);
    846 	encode_u32(&p.channel, ctx);
    847 	encode_u32(&p.sender_channel, ctx);
    848 	encode_u32(&p.initial_window_size, ctx);
    849 	encode_u32(&p.maximum_packet_size, ctx);
    850 	finish_frame(ctx);
    851 	if ctx.index != ctx.framelen {
    852 		die("trailing data");
    853 	}
    854 }
    855 
    856 struct ssh_channel_open_failure {
    857 	channel: int;
    858 	reason: int;
    859 	description: ssh_str;
    860 	lang: ssh_str;
    861 }
    862 
    863 func encode_channel_open_failure(p: *ssh_channel_open_failure, ctx: *sshd_ctx) {
    864 	var tag: int;
    865 	clear_frame(ctx);
    866 	tag = SSH_MSG_CHANNEL_OPEN_FAILURE;
    867 	encode_u8(&tag, ctx);
    868 	encode_u32(&p.channel, ctx);
    869 	encode_u32(&p.reason, ctx);
    870 	encode_str(&p.description, ctx);
    871 	encode_str(&p.lang, ctx);
    872 	finish_frame(ctx);
    873 }
    874 
    875 struct ssh_channel_window_adjust {
    876 	channel: int;
    877 	window: int;
    878 }
    879 
    880 func decode_channel_window_adjust(p: *ssh_channel_window_adjust, ctx: *sshd_ctx) {
    881 	var tag: int;
    882 	decode_u8(&tag, ctx);
    883 	if tag != SSH_MSG_CHANNEL_WINDOW_ADJUST {
    884 		die("not a channel_window_adjust");
    885 	}
    886 	decode_u32(&p.channel, ctx);
    887 	decode_u32(&p.window, ctx);
    888 	if ctx.index != ctx.framelen {
    889 		die("trailing data");
    890 	}
    891 }
    892 
    893 func encode_channel_window_adjust(p: *ssh_channel_window_adjust, ctx: *sshd_ctx) {
    894 	var tag: int;
    895 	clear_frame(ctx);
    896 	tag = SSH_MSG_CHANNEL_WINDOW_ADJUST;
    897 	encode_u8(&tag, ctx);
    898 	encode_u32(&p.channel, ctx);
    899 	encode_u32(&p.window, ctx);
    900 	finish_frame(ctx);
    901 }
    902 
    903 struct ssh_channel_data {
    904 	channel: int;
    905 	data: ssh_str;
    906 }
    907 
    908 func decode_channel_data(p: *ssh_channel_data, ctx: *sshd_ctx) {
    909 	var tag: int;
    910 	decode_u8(&tag, ctx);
    911 	if tag != SSH_MSG_CHANNEL_DATA {
    912 		die("not a channel_data");
    913 	}
    914 	decode_u32(&p.channel, ctx);
    915 	decode_str(&p.data, ctx);
    916 	if ctx.index != ctx.framelen {
    917 		die("trailing data");
    918 	}
    919 }
    920 
    921 func encode_channel_data(p: *ssh_channel_data, ctx: *sshd_ctx) {
    922 	var tag: int;
    923 	clear_frame(ctx);
    924 	tag = SSH_MSG_CHANNEL_DATA;
    925 	encode_u8(&tag, ctx);
    926 	encode_u32(&p.channel, ctx);
    927 	encode_str(&p.data, ctx);
    928 	finish_frame(ctx);
    929 }
    930 
    931 struct ssh_channel_extended_data {
    932 	channel: int;
    933 	code: int;
    934 	data: ssh_str;
    935 }
    936 
    937 func encode_channel_extended_data(p: *ssh_channel_extended_data, ctx: *sshd_ctx) {
    938 	var tag: int;
    939 	clear_frame(ctx);
    940 	tag = SSH_MSG_CHANNEL_EXTENDED_DATA;
    941 	encode_u8(&tag, ctx);
    942 	encode_u32(&p.channel, ctx);
    943 	encode_u32(&p.code, ctx);
    944 	encode_str(&p.data, ctx);
    945 	finish_frame(ctx);
    946 }
    947 
    948 struct ssh_channel_eof {
    949 	channel: int;
    950 }
    951 
    952 func decode_channel_eof(p: *ssh_channel_eof, ctx: *sshd_ctx) {
    953 	var tag: int;
    954 	decode_u8(&tag, ctx);
    955 	if tag != SSH_MSG_CHANNEL_EOF {
    956 		die("not a channel_eof");
    957 	}
    958 	decode_u32(&p.channel, ctx);
    959 	if ctx.index != ctx.framelen {
    960 		die("trailing data");
    961 	}
    962 }
    963 
    964 func encode_channel_eof(p: *ssh_channel_eof, ctx: *sshd_ctx) {
    965 	var tag: int;
    966 	clear_frame(ctx);
    967 	tag = SSH_MSG_CHANNEL_EOF;
    968 	encode_u8(&tag, ctx);
    969 	encode_u32(&p.channel, ctx);
    970 	finish_frame(ctx);
    971 }
    972 
    973 struct ssh_channel_close {
    974 	channel: int;
    975 }
    976 
    977 func decode_channel_close(p: *ssh_channel_close, ctx: *sshd_ctx) {
    978 	var tag: int;
    979 	decode_u8(&tag, ctx);
    980 	if tag != SSH_MSG_CHANNEL_CLOSE {
    981 		die("not a channel_close");
    982 	}
    983 	decode_u32(&p.channel, ctx);
    984 	if ctx.index != ctx.framelen {
    985 		die("trailing data");
    986 	}
    987 }
    988 
    989 func encode_channel_close(p: *ssh_channel_close, ctx: *sshd_ctx) {
    990 	var tag: int;
    991 	clear_frame(ctx);
    992 	tag = SSH_MSG_CHANNEL_CLOSE;
    993 	encode_u8(&tag, ctx);
    994 	encode_u32(&p.channel, ctx);
    995 	finish_frame(ctx);
    996 }
    997 
    998 struct ssh_channel_request {
    999 	channel: int;
   1000 	request: ssh_str;
   1001 	want_reply: int;
   1002 	kind: int;
   1003 	unknown: ssh_str;
   1004 	pty: ssh_cr_pty;
   1005 	shell: ssh_cr_shell;
   1006 	exec: ssh_cr_exec;
   1007 	winch: ssh_cr_winch;
   1008 	signal: ssh_cr_signal;
   1009 	exit: ssh_cr_exit;
   1010 	exit_signal: ssh_cr_exit_signal;
   1011 }
   1012 
   1013 func decode_channel_request(p: *ssh_channel_request, ctx: *sshd_ctx) {
   1014 	var tag: int;
   1015 	bzero(p as *byte, sizeof(*p));
   1016 	decode_u8(&tag, ctx);
   1017 	if tag != SSH_MSG_CHANNEL_REQUEST {
   1018 		die("not a channel_request");
   1019 	}
   1020 	decode_u32(&p.channel, ctx);
   1021 	decode_str(&p.request, ctx);
   1022 	decode_bool(&p.want_reply, ctx);
   1023 	if ssh_streq(&p.request, "pty-req") {
   1024 		p.kind = SSH_CR_PTY;
   1025 		decode_str(&p.pty.term, ctx);
   1026 		decode_u32(&p.pty.cx, ctx);
   1027 		decode_u32(&p.pty.cy, ctx);
   1028 		decode_u32(&p.pty.px, ctx);
   1029 		decode_u32(&p.pty.py, ctx);
   1030 		decode_str(&p.pty.modes, ctx);
   1031 	} else if ssh_streq(&p.request, "shell") {
   1032 		p.kind = SSH_CR_SHELL;
   1033 	} else if ssh_streq(&p.request, "exec") {
   1034 		p.kind = SSH_CR_EXEC;
   1035 		decode_str(&p.exec.command, ctx);
   1036 	} else if ssh_streq(&p.request, "window-change") {
   1037 		p.kind = SSH_CR_WINCH;
   1038 		decode_u32(&p.winch.cx, ctx);
   1039 		decode_u32(&p.winch.cy, ctx);
   1040 		decode_u32(&p.winch.px, ctx);
   1041 		decode_u32(&p.winch.py, ctx);
   1042 	} else if ssh_streq(&p.request, "signal") {
   1043 		p.kind = SSH_CR_SIGNAL;
   1044 		decode_str(&p.signal.name, ctx);
   1045 	} else {
   1046 		p.kind = SSH_CR_UNKNOWN;
   1047 		p.unknown.s = &ctx.frame[ctx.index];
   1048 		p.unknown.len = ctx.framelen - ctx.index;
   1049 		ctx.index = ctx.framelen;
   1050 	}
   1051 	if ctx.index != ctx.framelen {
   1052 		die("trailing data");
   1053 	}
   1054 }
   1055 
   1056 func encode_channel_request(p: *ssh_channel_request, ctx: *sshd_ctx) {
   1057 	var tag: int;
   1058 	clear_frame(ctx);
   1059 	tag = SSH_MSG_CHANNEL_REQUEST;
   1060 	encode_u8(&tag, ctx);
   1061 	encode_u32(&p.channel, ctx);
   1062 	if p.kind == SSH_CR_EXIT_STATUS {
   1063 		set_str(&p.request, "exit-status");
   1064 		encode_str(&p.request, ctx);
   1065 		p.want_reply = 0;
   1066 		encode_bool(&p.want_reply, ctx);
   1067 		encode_u32(&p.exit.status, ctx);
   1068 	} else if p.kind == SSH_CR_EXIT_SIGNAL {
   1069 		set_str(&p.request, "exit-signal");
   1070 		encode_str(&p.request, ctx);
   1071 		p.want_reply = 0;
   1072 		encode_bool(&p.want_reply, ctx);
   1073 		encode_str(&p.exit_signal.name, ctx);
   1074 		encode_bool(&p.exit_signal.core_dumpped, ctx);
   1075 		encode_str(&p.exit_signal.message, ctx);
   1076 		encode_str(&p.exit_signal.lang, ctx);
   1077 	} else {
   1078 		encode_str(&p.request, ctx);
   1079 		encode_bool(&p.want_reply, ctx);
   1080 	}
   1081 	finish_frame(ctx);
   1082 }
   1083 
   1084 struct ssh_channel_success {
   1085 	channel: int;
   1086 }
   1087 
   1088 func encode_channel_success(p: *ssh_channel_success, ctx: *sshd_ctx) {
   1089 	var tag: int;
   1090 	clear_frame(ctx);
   1091 	tag = SSH_MSG_CHANNEL_SUCCESS;
   1092 	encode_u8(&tag, ctx);
   1093 	encode_u32(&p.channel, ctx);
   1094 	finish_frame(ctx);
   1095 }
   1096 
   1097 struct ssh_channel_failure {
   1098 	channel: int;
   1099 }
   1100 
   1101 func encode_channel_failure(p: *ssh_channel_failure, ctx: *sshd_ctx) {
   1102 	var tag: int;
   1103 	clear_frame(ctx);
   1104 	tag = SSH_MSG_CHANNEL_FAILURE;
   1105 	encode_u8(&tag, ctx);
   1106 	encode_u32(&p.channel, ctx);
   1107 	finish_frame(ctx);
   1108 }
   1109 
   1110 func dokex(ctx: *sshd_ctx) {
   1111 	var cookie: _ssh_cookie;
   1112 	var ckex: ssh_kexinit;
   1113 	var skex: ssh_kexinit;
   1114 	var newkeys: ssh_newkeys;
   1115 	var cdh: ssh_ecdh_init;
   1116 	var sdh: ssh_ecdh_reply;
   1117 	var rs: _ed25519_point;
   1118 	var qs: _ed25519_point;
   1119 	var k: _ed25519_point;
   1120 	var ehctx: sha256_ctx;
   1121 	var eh: _sha256_digest;
   1122 	var sig: _ed25519_sig;
   1123 
   1124 	// <- SSH_MSG_KEXINIT
   1125 	decode_kexinit(&ckex, ctx);
   1126 	memcpy(ctx.ckex, ctx.frame, ctx.framelen);
   1127 	ctx.ckexlen = ctx.framelen;
   1128 
   1129 	if ckex.first_kex_packet_follows {
   1130 		die("first_kex_packet_follows not implemented");
   1131 	}
   1132 
   1133 	// -> SSH_MSG_KEXINIT
   1134 	read_rand((&cookie) as *byte, 16);
   1135 	skex.cookie.len = 16;
   1136 	skex.cookie.s = (&cookie) as *byte;
   1137 	set_str(&skex.kex_algorithms, "curve25519-sha256");
   1138 	set_str(&skex.server_host_key_algorithms, "ssh-ed25519");
   1139 	set_str(&skex.encryption_algorithms_client_to_server, "chacha20-poly1305@openssh.com");
   1140 	set_str(&skex.encryption_algorithms_server_to_client, "chacha20-poly1305@openssh.com");
   1141 	set_str(&skex.mac_algorithms_client_to_server, "none");
   1142 	set_str(&skex.mac_algorithms_server_to_client, "none");
   1143 	set_str(&skex.compression_algorithms_client_to_server, "none");
   1144 	set_str(&skex.compression_algorithms_server_to_client, "none");
   1145 	set_str(&skex.languages_client_to_server, "");
   1146 	set_str(&skex.languages_server_to_client, "");
   1147 	skex.first_kex_packet_follows = 0;
   1148 	skex.reserved = 0;
   1149 
   1150 	encode_kexinit(&skex, ctx);
   1151 	memcpy(ctx.skex, ctx.frame, ctx.framelen);
   1152 	ctx.skexlen = ctx.index;
   1153 
   1154 	write_frame(ctx);
   1155 
   1156 	// <- SSH_MSG_ECDH_INIT
   1157 	read_frame(ctx);
   1158 	decode_ecdh_init(&cdh, ctx);
   1159 
   1160 	if cdh.qc.len != 32 {
   1161 		die("bad ecdh_init");
   1162 	}
   1163 
   1164 	read_rand((&rs) as *byte, 32);
   1165 
   1166 	x25519_base((&qs) as *byte);
   1167 
   1168 	if !x25519((&qs) as *byte, (&qs) as *byte, (&rs) as *byte) {
   1169 		die("bad x25519 server");
   1170 	}
   1171 
   1172 	if !x25519((&k) as *byte, cdh.qc.s, (&rs) as *byte) {
   1173 		die("bad x25519 client");
   1174 	}
   1175 
   1176 	set_blob(&sdh.ks, "ssh-ed25519", (&ctx.pub) as *byte, 32);
   1177 	sdh.qs.s = (&qs) as *byte;
   1178 	sdh.qs.len = 32;
   1179 	set_blob(&sdh.sig, "ssh-ed25519", (&sig) as *byte, 64);
   1180 
   1181 	sha256_init(&ehctx);
   1182 	ssh_str_sha256_update(&ehctx, ctx.cver, strlen(ctx.cver));
   1183 	ssh_str_sha256_update(&ehctx, ctx.sver, strlen(ctx.sver));
   1184 	ssh_str_sha256_update(&ehctx, ctx.ckex, ctx.ckexlen);
   1185 	ssh_str_sha256_update(&ehctx, ctx.skex, ctx.skexlen);
   1186 	ssh_blob_sha256_update(&ehctx, &sdh.ks);
   1187 	ssh_str_sha256_update(&ehctx, cdh.qc.s, 32);
   1188 	ssh_str_sha256_update(&ehctx, (&qs) as *byte, 32);
   1189 	ssh_mpint_sha256_update(&ehctx, (&k) as *byte, 32);
   1190 	sha256_final((&eh) as *byte, &ehctx);
   1191 
   1192 	ed25519_sign((&sig) as *byte, (&ctx.priv) as *byte, (&eh) as *byte, 32);
   1193 
   1194 	// -> SSH_MSG_ECDH_REPLY
   1195 	encode_ecdh_reply(&sdh, ctx);
   1196 	write_frame(ctx);
   1197 
   1198 	if !ctx.has_session_id {
   1199 		memcpy((&ctx.session_id) as *byte, (&eh) as *byte, 32);
   1200 		ctx.has_session_id = 1;
   1201 	}
   1202 
   1203 	memcpy((&ctx.eh) as *byte, (&eh) as *byte, 32);
   1204 	memcpy((&ctx.k) as *byte, (&k) as *byte, 32);
   1205 
   1206 	kex_key((&ctx.iv_client_to_server) as *byte, "A", ctx);
   1207 	kex_key((&ctx.iv_server_to_client) as *byte, "B", ctx);
   1208 	kex_key((&ctx.ek_client_to_server) as *byte, "C", ctx);
   1209 	kex_key((&ctx.ek_server_to_client) as *byte, "D", ctx);
   1210 	kex_key((&ctx.ik_client_to_server) as *byte, "E", ctx);
   1211 	kex_key((&ctx.ik_server_to_client) as *byte, "F", ctx);
   1212 
   1213 	// -> SSH_MSG_NEWKEYS
   1214 	encode_newkeys(&newkeys, ctx);
   1215 	write_frame(ctx);
   1216 	ctx.en_server_to_client = 1;
   1217 
   1218 	// <- SSH_MSG_NEWKEYS
   1219 	read_frame(ctx);
   1220 	decode_newkeys(&newkeys, ctx);
   1221 	ctx.en_client_to_server = 1;
   1222 }
   1223 
   1224 func kex_key(key: *byte, a: *byte, ctx: *sshd_ctx) {
   1225 	var h: sha256_ctx;
   1226 
   1227 	sha256_init(&h);
   1228 	ssh_mpint_sha256_update(&h, (&ctx.k) as *byte, 32);
   1229 	sha256_update(&h, (&ctx.eh) as *byte, 32);
   1230 	sha256_update(&h, a, 1);
   1231 	sha256_update(&h, (&ctx.session_id) as *byte, 32);
   1232 	sha256_final(key, &h);
   1233 
   1234 	sha256_init(&h);
   1235 	ssh_mpint_sha256_update(&h, (&ctx.k) as *byte, 32);
   1236 	sha256_update(&h, (&ctx.eh) as *byte, 32);
   1237 	sha256_update(&h, key, 32);
   1238 	sha256_final(&key[32], &h);
   1239 }
   1240 
   1241 func ssh_streq(a: *ssh_str, b: *byte): int {
   1242 	var len: int;
   1243 	len = strlen(b);
   1244 	return a.len == len && memcmp(a.s, b, len) == 0;
   1245 }
   1246 
   1247 func doauth(ctx: *sshd_ctx) {
   1248 	var csr: ssh_service_request;
   1249 	var cua: ssh_userauth_request;
   1250 	var ssa: ssh_service_accept;
   1251 	var suf: ssh_userauth_failure;
   1252 	var sus: ssh_userauth_success;
   1253 	var sok: ssh_userauth_pk_ok;
   1254 	var sig: _ed25519_sig;
   1255 	var b: int;
   1256 	var s: ssh_str;
   1257 
   1258 	// <- SSH_MSG_SERVICE_REQUEST
   1259 	decode_service_request(&csr, ctx);
   1260 	if !ssh_streq(&csr.name, "ssh-userauth") {
   1261 		die("not ssh-userauth");
   1262 	}
   1263 
   1264 	// -> SSH_MSG_SERVICE_ACCEPT
   1265 	set_str(&ssa.name, "ssh-userauth");
   1266 	encode_service_accept(&ssa, ctx);
   1267 	write_frame(ctx);
   1268 
   1269 	loop {
   1270 
   1271 		// <- SSH_MSG_USERAUTH_REQUEST
   1272 		read_frame(ctx);
   1273 		decode_userauth_request(&cua, ctx);
   1274 		if !ssh_streq(&cua.service, "ssh-connection") || !ssh_streq(&cua.user, ctx.username) {
   1275 			die("bad auth");
   1276 		}
   1277 
   1278 		if !ssh_streq(&cua.method, "publickey") || !ssh_streq(&cua.alg, "ssh-ed25519") {
   1279 			// -> SSH_MSG_USERAUTH_FAILURE("publickey")
   1280 			set_str(&suf.methods, "publickey");
   1281 			suf.partial_success = 0;
   1282 			encode_userauth_failure(&suf, ctx);
   1283 			write_frame(ctx);
   1284 			continue;
   1285 		}
   1286 
   1287 		if cua.pub.len != ctx.userkeylen || memcmp(cua.pub.s, ctx.userkey, ctx.userkeylen) {
   1288 			// -> SSH_MSG_USERAUTH_FAILURE("publickey")
   1289 			set_str(&suf.methods, "publickey");
   1290 			suf.partial_success = 0;
   1291 			encode_userauth_failure(&suf, ctx);
   1292 			write_frame(ctx);
   1293 			continue;
   1294 		}
   1295 
   1296 		if !cua.has_sig {
   1297 			// -> SSH_MSG_USERAUTH_PK_OK
   1298 			set_str(&sok.alg, "ssh-ed25519");
   1299 			sok.pub.s = ctx.userkey;
   1300 			sok.pub.len = ctx.userkeylen;
   1301 			encode_userauth_pk_ok(&sok, ctx);
   1302 			write_frame(ctx);
   1303 			continue;
   1304 		}
   1305 
   1306 		break;
   1307 	}
   1308 
   1309 	if cua.sig.len != 83 {
   1310 		die("sig wrong length");
   1311 	}
   1312 
   1313 	memcpy((&sig) as *byte, &cua.sig.s[19], 64);
   1314 
   1315 	clear_frame(ctx);
   1316 	s.s = (&ctx.session_id) as *byte;
   1317 	s.len = 32;
   1318 	encode_str(&s, ctx);
   1319 	b = SSH_MSG_USERAUTH_REQUEST;
   1320 	encode_u8(&b, ctx);
   1321 	set_str(&s, ctx.username);
   1322 	encode_str(&s, ctx);
   1323 	set_str(&s, "ssh-connection");
   1324 	encode_str(&s, ctx);
   1325 	set_str(&s, "publickey");
   1326 	encode_str(&s, ctx);
   1327 	b = 1;
   1328 	encode_bool(&b, ctx);
   1329 	set_str(&s, "ssh-ed25519");
   1330 	encode_str(&s, ctx);
   1331 	s.s = ctx.userkey;
   1332 	s.len = ctx.userkeylen;
   1333 	encode_str(&s, ctx);
   1334 	finish_frame(ctx);
   1335 
   1336 	if !ed25519_verify((&sig) as *byte, (&ctx.userpub) as *byte, ctx.frame, ctx.framelen) {
   1337 		die("bad signature");
   1338 	}
   1339 
   1340 	encode_userauth_success(&sus, ctx);
   1341 	write_frame(ctx);
   1342 }
   1343 
   1344 func dosession(ctx: *sshd_ctx) {
   1345 	var cco: ssh_channel_open;
   1346 	var scc: ssh_channel_open_confirmation;
   1347 	var ccr: ssh_channel_request;
   1348 	var scs: ssh_channel_success;
   1349 	var scf: ssh_channel_failure;
   1350 
   1351 	decode_channel_open(&cco, ctx);
   1352 	if !ssh_streq(&cco.channel_type, "session") || cco.channel != 0 {
   1353 		die("not session");
   1354 	}
   1355 
   1356 	ctx.stdout_window = cco.initial_window_size;
   1357 	if cco.maximum_packet_size < 1024 {
   1358 		die("max packet size too small");
   1359 	}
   1360 
   1361 	scc.channel = 0;
   1362 	scc.sender_channel = 0;
   1363 	scc.initial_window_size = ctx.stdin_size;
   1364 	scc.maximum_packet_size = ctx.bufsz - 64;
   1365 
   1366 	encode_channel_open_confirmation(&scc, ctx);
   1367 	write_frame(ctx);
   1368 }
   1369 
   1370 func dodisconnect(ctx: *sshd_ctx) {
   1371 	var d: ssh_disconnect;
   1372 	decode_disconnect(&d, ctx);
   1373 	exit(0);
   1374 }
   1375 
   1376 func dowindow(ctx: *sshd_ctx) {
   1377 	var cwa: ssh_channel_window_adjust;
   1378 	decode_channel_window_adjust(&cwa, ctx);
   1379 	ctx.stdout_window = ctx.stdout_window + cwa.window;
   1380 }
   1381 
   1382 func dodata(ctx: *sshd_ctx) {
   1383 	var cd: ssh_channel_data;
   1384 	decode_channel_data(&cd, ctx);
   1385 	if ctx.stdin_eof {
   1386 		return;
   1387 	}
   1388 	if cd.data.len > ctx.stdin_size - ctx.stdin_fill {
   1389 		die("stdin overflow");
   1390 	}
   1391 	memcpy(&ctx.stdin_buf[ctx.stdin_fill], cd.data.s, cd.data.len);
   1392 	ctx.stdin_fill = ctx.stdin_fill + cd.data.len;
   1393 }
   1394 
   1395 func doeof(ctx: *sshd_ctx) {
   1396 	var ce: ssh_channel_eof;
   1397 	decode_channel_eof(&ce, ctx);
   1398 	ctx.stdin_eof = 1;
   1399 }
   1400 
   1401 func doclose(ctx: *sshd_ctx) {
   1402 	var cc: ssh_channel_close;
   1403 	decode_channel_close(&cc, ctx);
   1404 	exit(0);
   1405 }
   1406 
   1407 struct _argv4 {
   1408 	arg0: *byte;
   1409 	arg1: *byte;
   1410 	arg2: *byte;
   1411 	arg3: *byte;
   1412 }
   1413 
   1414 func ssh_spawn(ctx: *sshd_ctx, argv: **byte) {
   1415 	var pid: int;
   1416 	var stdin_read: int;
   1417 	var stdin_write: int;
   1418 	var stdout_read: int;
   1419 	var stdout_write: int;
   1420 	var stderr_read: int;
   1421 	var stderr_write: int;
   1422 
   1423 	if ctx.has_child {
   1424 		die("already spawned");
   1425 	}
   1426 
   1427 	if pipe(&stdin_read, &stdin_write) != 0 {
   1428 		die("stdin pipe failed");
   1429 	}
   1430 
   1431 	if pipe(&stdout_read, &stdout_write) != 0 {
   1432 		die("stdout pipe failed");
   1433 	}
   1434 
   1435 	if pipe(&stderr_read, &stderr_write) != 0 {
   1436 		die("stderr pipe failed");
   1437 	}
   1438 
   1439 	pid = fork();
   1440 	if pid < 0 {
   1441 		die("fork failed");
   1442 	}
   1443 
   1444 	if pid == 0 {
   1445 		close(ctx.fd);
   1446 
   1447 		close(stdin_write);
   1448 		close(stdout_read);
   1449 		close(stderr_read);
   1450 
   1451 		dup2(stdin_read, 0);
   1452 		dup2(stdout_write, 1);
   1453 		dup2(stderr_write, 2);
   1454 
   1455 		close(stdin_read);
   1456 		close(stdout_write);
   1457 		close(stderr_write);
   1458 
   1459 		exec(argv[0], argv, nil);
   1460 
   1461 		exit(255);
   1462 	}
   1463 
   1464 	close(stdin_read);
   1465 	close(stdout_write);
   1466 	close(stderr_write);
   1467 
   1468 	ctx.has_child = 1;
   1469 	ctx.child_pid = pid;
   1470 	ctx.child_stdin = stdin_write;
   1471 	ctx.child_stdout = stdout_read;
   1472 	ctx.child_stderr = stderr_read;
   1473 }
   1474 
   1475 func dopty(cr: *ssh_cr_pty, ctx: *sshd_ctx): int {
   1476 	// allocate pty
   1477 	return 0;
   1478 }
   1479 
   1480 func doshell(cr: *ssh_cr_shell, ctx: *sshd_ctx): int {
   1481 	var argv: _argv4;
   1482 	argv.arg0 = "/bin/sh";
   1483 	argv.arg1 = nil;
   1484 	ssh_spawn(ctx, &argv.arg0);
   1485 	return 1;
   1486 }
   1487 
   1488 func doexec(cr: *ssh_cr_exec, ctx: *sshd_ctx): int {
   1489 	var argv: _argv4;
   1490 	var cmd: *byte;
   1491 	cmd = alloc(ctx.a, cr.command.len + 1);
   1492 	memcpy(cmd, cr.command.s, cr.command.len);
   1493 	cmd[cr.command.len] = 0 as byte;
   1494 	argv.arg0 = "/bin/sh";
   1495 	argv.arg1 = "-c";
   1496 	argv.arg2 = cmd;
   1497 	argv.arg3 = nil;
   1498 	ssh_spawn(ctx, &argv.arg0);
   1499 	free(ctx.a, cmd);
   1500 	return 1;
   1501 }
   1502 
   1503 func dowinch(cr: *ssh_cr_winch, ctx: *sshd_ctx): int {
   1504 	// window change
   1505 	return 0;
   1506 }
   1507 
   1508 func dosignal(cr: *ssh_cr_signal, ctx: *sshd_ctx): int {
   1509 	// signal
   1510 	return 0;
   1511 }
   1512 
   1513 func dorequest(ctx: *sshd_ctx) {
   1514 	var cr: ssh_channel_request;
   1515 	var ss: ssh_channel_success;
   1516 	var sf: ssh_channel_failure;
   1517 	var ok: int;
   1518 	decode_channel_request(&cr, ctx);
   1519 
   1520 	if cr.kind == SSH_CR_PTY {
   1521 		ok = dopty(&cr.pty, ctx);
   1522 	} else if cr.kind == SSH_CR_SHELL {
   1523 		ok = doshell(&cr.shell, ctx);
   1524 	} else if cr.kind == SSH_CR_EXEC {
   1525 		ok = doexec(&cr.exec, ctx);
   1526 	} else if cr.kind == SSH_CR_WINCH {
   1527 		ok = dowinch(&cr.winch, ctx);
   1528 	} else if cr.kind == SSH_CR_SIGNAL {
   1529 		ok = dosignal(&cr.signal, ctx);
   1530 	} else {
   1531 		//die("unknown request");
   1532 		if cr.want_reply {
   1533 			sf.channel = 0;
   1534 			encode_channel_failure(&sf, ctx);
   1535 			write_frame(ctx);
   1536 			return;
   1537 		}
   1538 	}
   1539 
   1540 	if cr.want_reply {
   1541 		if ok {
   1542 			ss.channel = 0;
   1543 			encode_channel_success(&ss, ctx);
   1544 			write_frame(ctx);
   1545 		} else {
   1546 			sf.channel = 0;
   1547 			encode_channel_failure(&sf, ctx);
   1548 			write_frame(ctx);
   1549 		}
   1550 	}
   1551 }
   1552 
   1553 struct pfd4 {
   1554 	p0: int;
   1555 	p1: int;
   1556 	p2: int;
   1557 	p3: int;
   1558 }
   1559 
   1560 func reset_pfd(pfd: *int, ctx: *sshd_ctx): int {
   1561 	var n: int;
   1562 	var events: int;
   1563 
   1564 	n = 0;
   1565 
   1566 	if (
   1567 		// There is a window update to send
   1568 		(ctx.stdin_window > 1024)
   1569 		// There is stdout to send
   1570 		|| (ctx.stdout_fill > 0 && ctx.stdout_window > 0)
   1571 		// There is stderr to send
   1572 		|| (ctx.stderr_fill > 0 && ctx.stdout_window > 0)
   1573 		// Child exited and there's no more stdout/stderr
   1574 		|| (ctx.has_child
   1575 			&& ctx.stdout_fill == 0
   1576 			&& ctx.stderr_fill == 0
   1577 			&& ctx.child_stdout == -1
   1578 			&& ctx.child_stderr == -1
   1579 			&& ctx.child_pid == -1)
   1580 	) {
   1581 		events = POLLIN | POLLOUT;
   1582 	} else {
   1583 		events = POLLIN;
   1584 	}
   1585 	pfd[n] = ctx.fd | (events << 32);
   1586 	n = n + 1;
   1587 
   1588 	if ctx.child_stdin >= 0 && (ctx.stdin_fill > 0 || ctx.stdin_eof) {
   1589 		events = POLLOUT;
   1590 		pfd[n] = ctx.child_stdin | (events << 32);
   1591 		n = n + 1;
   1592 	}
   1593 
   1594 	if ctx.child_stdout >= 0 && ctx.stdout_fill < ctx.stderr_size {
   1595 		events = POLLIN;
   1596 		pfd[n] = ctx.child_stdout | (events << 32);
   1597 		n = n + 1;
   1598 	}
   1599 
   1600 	if ctx.child_stderr >= 0 && ctx.stderr_fill < ctx.stderr_size {
   1601 		events = POLLIN;
   1602 		pfd[n] = ctx.child_stderr | (events << 32);
   1603 		n = n + 1;
   1604 	}
   1605 
   1606 	return n;
   1607 }
   1608 
   1609 func poll_client(revents: int, ctx: *sshd_ctx) {
   1610 	var tag: int;
   1611 	var len: int;
   1612 	var swa: ssh_channel_window_adjust;
   1613 	var sd: ssh_channel_data;
   1614 	var sed: ssh_channel_extended_data;
   1615 	var sr: ssh_channel_request;
   1616 	var sc: ssh_channel_close;
   1617 	var se: ssh_channel_eof;
   1618 	if revents & POLLOUT {
   1619 		if ctx.stdin_window > 1024 {
   1620 			swa.channel = 0;
   1621 			swa.window = ctx.stdin_window;
   1622 			encode_channel_window_adjust(&swa, ctx);
   1623 			write_frame(ctx);
   1624 			ctx.stdin_window = 0;
   1625 		} else if ctx.stdout_fill > 0 && ctx.stdout_window > 0 {
   1626 			len = ctx.stdout_fill;
   1627 			if len > 1024 {
   1628 				len = 1024;
   1629 			}
   1630 
   1631 			if len > ctx.stdout_window {
   1632 				len = ctx.stdout_window;
   1633 			}
   1634 
   1635 			sd.channel = 0;
   1636 			sd.data.s = ctx.stdout_buf;
   1637 			sd.data.len = len;
   1638 
   1639 			memcpy(ctx.stdout_buf, &ctx.stdout_buf[len], ctx.stdout_fill - len);
   1640 			ctx.stdout_window = ctx.stdout_window - len;
   1641 			ctx.stdout_fill = ctx.stdout_fill - len;
   1642 
   1643 			encode_channel_data(&sd, ctx);
   1644 			write_frame(ctx);
   1645 		} else if ctx.stderr_fill > 0 && ctx.stdout_window > 0 {
   1646 			len = ctx.stderr_fill;
   1647 			if len > 1024 {
   1648 				len = 1024;
   1649 			}
   1650 
   1651 			if len > ctx.stdout_window {
   1652 				len = ctx.stdout_window;
   1653 			}
   1654 
   1655 			sed.channel = 0;
   1656 			sed.code = 1;
   1657 			sed.data.s = ctx.stderr_buf;
   1658 			sed.data.len = len;
   1659 
   1660 			memcpy(ctx.stderr_buf, &ctx.stderr_buf[len], ctx.stderr_fill - len);
   1661 			ctx.stdout_window = ctx.stdout_window - len;
   1662 			ctx.stderr_fill = ctx.stderr_fill - len;
   1663 
   1664 			encode_channel_extended_data(&sed, ctx);
   1665 			write_frame(ctx);
   1666 		} else {
   1667 			se.channel = 0;
   1668 			encode_channel_eof(&se, ctx);
   1669 			write_frame(ctx);
   1670 
   1671 			sr.channel = 0;
   1672 			sr.want_reply = 0;
   1673 			sr.kind = SSH_CR_EXIT_STATUS;
   1674 			sr.exit.status = ctx.exit_status;
   1675 			encode_channel_request(&sr, ctx);
   1676 			write_frame(ctx);
   1677 
   1678 			sc.channel = 0;
   1679 			encode_channel_close(&sc, ctx);
   1680 			write_frame(ctx);
   1681 
   1682 			loop {
   1683 				read_frame(ctx);
   1684 				if ctx.frame[0] as int == SSH_MSG_DISCONNECT {
   1685 					break;
   1686 				}
   1687 			}
   1688 
   1689 			exit(0);
   1690 		}
   1691 	} else {
   1692 		read_frame(ctx);
   1693 
   1694 		tag = ctx.frame[0] as int;
   1695 		if tag == SSH_MSG_DISCONNECT {
   1696 			dodisconnect(ctx);
   1697 		} else if tag == SSH_MSG_KEXINIT {
   1698 			dokex(ctx);
   1699 		} else if tag == SSH_MSG_CHANNEL_WINDOW_ADJUST {
   1700 			dowindow(ctx);
   1701 		} else if tag == SSH_MSG_CHANNEL_DATA {
   1702 			dodata(ctx);
   1703 		} else if tag == SSH_MSG_CHANNEL_EOF {
   1704 			doeof(ctx);
   1705 		} else if tag == SSH_MSG_CHANNEL_CLOSE {
   1706 			doclose(ctx);
   1707 		} else if tag == SSH_MSG_CHANNEL_REQUEST {
   1708 			dorequest(ctx);
   1709 		} else {
   1710 			die("invalid packet");
   1711 		}
   1712 	}
   1713 }
   1714 
   1715 func poll_stdin(revents: int, ctx: *sshd_ctx) {
   1716 	var ret: int;
   1717 	if ctx.stdin_fill == 0 && ctx.stdin_eof {
   1718 		close(ctx.child_stdin);
   1719 		ctx.child_stdin = -1;
   1720 		return;
   1721 	}
   1722 	ret = write(ctx.child_stdin, ctx.stdin_buf, ctx.stdin_fill);
   1723 	if ret == -EINTR {
   1724 		return;
   1725 	}
   1726 	if ret == -EPIPE {
   1727 		close(ctx.child_stdin);
   1728 		ctx.child_stdin = -1;
   1729 		return;
   1730 	}
   1731 	memcpy(ctx.stdin_buf, &ctx.stdin_buf[ret], ctx.stdin_fill - ret);
   1732 	ctx.stdin_fill = ctx.stdin_fill - ret;
   1733 	ctx.stdin_window = ctx.stdin_window + ret;
   1734 }
   1735 
   1736 func poll_stdout(revents: int, ctx: *sshd_ctx) {
   1737 	var ret: int;
   1738 	ret = read(ctx.child_stdout, &ctx.stdout_buf[ctx.stdout_fill], ctx.stdout_size - ctx.stdout_fill);
   1739 	if ret == -EINTR {
   1740 		return;
   1741 	}
   1742 	if ret == 0 {
   1743 		close(ctx.child_stdout);
   1744 		ctx.child_stdout = -1;
   1745 		return;
   1746 	}
   1747 	ctx.stdout_fill = ctx.stdout_fill + ret;
   1748 }
   1749 
   1750 func poll_stderr(revents: int, ctx: *sshd_ctx) {
   1751 	var ret: int;
   1752 	ret = read(ctx.child_stderr, &ctx.stderr_buf[ctx.stderr_fill], ctx.stderr_size - ctx.stderr_fill);
   1753 	if ret == -EINTR {
   1754 		return;
   1755 	}
   1756 	if ret == 0 {
   1757 		close(ctx.child_stderr);
   1758 		ctx.child_stderr = -1;
   1759 		return;
   1760 	}
   1761 	ctx.stderr_fill = ctx.stderr_fill + ret;
   1762 }
   1763 
   1764 func poll_exit(ctx: *sshd_ctx) {
   1765 	var ret: int;
   1766 	var status: int;
   1767 	loop {
   1768 		ret = wait(-1, &status, WNOHANG);
   1769 		if ret <= 0 {
   1770 			break;
   1771 		}
   1772 		if ret == ctx.child_pid {
   1773 			ctx.child_pid = -1;
   1774 			ctx.exit_status = status;
   1775 		}
   1776 	}
   1777 }
   1778 
   1779 func client_loop(ctx: *sshd_ctx) {
   1780 	var _p: pfd4;
   1781 	var p: *int;
   1782 	var n: int;
   1783 	var i: int;
   1784 	var fd: int;
   1785 	var revents: int;
   1786 
   1787 	p = &_p.p0;
   1788 
   1789 	loop {
   1790 		poll_exit(ctx);
   1791 
   1792 		n = reset_pfd(p, ctx);
   1793 		if poll(p, n, -1) == -EINTR {
   1794 			continue;
   1795 		}
   1796 
   1797 		i = 0;
   1798 		loop {
   1799 			if i == n {
   1800 				break;
   1801 			}
   1802 
   1803 			fd = p[i] & (-1 >> 32);
   1804 			revents = p[i] >> 48;
   1805 			i = i + 1;
   1806 
   1807 			if !revents {
   1808 				continue;
   1809 			}
   1810 
   1811 			if fd == ctx.fd {
   1812 				poll_client(revents, ctx);
   1813 			}
   1814 
   1815 			if fd == ctx.child_stdin {
   1816 				poll_stdin(revents, ctx);
   1817 			}
   1818 
   1819 			if fd == ctx.child_stdout {
   1820 				poll_stdout(revents, ctx);
   1821 			}
   1822 
   1823 			if fd == ctx.child_stderr {
   1824 				poll_stderr(revents, ctx);
   1825 			}
   1826 		}
   1827 	}
   1828 }
   1829 
   1830 func cmain(ctx: *sshd_ctx) {
   1831 	doversion(ctx);
   1832 
   1833 	read_frame(ctx);
   1834 	dokex(ctx);
   1835 
   1836 	read_frame(ctx);
   1837 	doauth(ctx);
   1838 
   1839 	read_frame(ctx);
   1840 	dosession(ctx);
   1841 
   1842 	client_loop(ctx);
   1843 }
   1844 
   1845 struct sockaddr {
   1846 	fpa: int;
   1847 	pad: int;
   1848 }
   1849 
   1850 struct sshd_ctx {
   1851 	fd: int;
   1852 	a: *alloc;
   1853 	priv: _ed25519_priv;
   1854 	pub: _ed25519_pub;
   1855 	userpub: _ed25519_pub;
   1856 	hostkey: *byte;
   1857 	hostkeylen: int;
   1858 	username: *byte;
   1859 	userkey: *byte;
   1860 	userkeylen: int;
   1861 	buf: *byte;
   1862 	bufsz: int;
   1863 	frame: *byte;
   1864 	framelen: int;
   1865 	index: int;
   1866 	sver: *byte;
   1867 	cver: *byte;
   1868 	skex: *byte;
   1869 	skexlen: int;
   1870 	ckex: *byte;
   1871 	ckexlen: int;
   1872 	macsize: int;
   1873 	has_session_id: int;
   1874 	session_id: _sha256_digest;
   1875 	eh: _sha256_digest;
   1876 	k: _ed25519_point;
   1877 	iv_client_to_server: _sha512_digest;
   1878 	iv_server_to_client: _sha512_digest;
   1879 	ek_client_to_server: _sha512_digest;
   1880 	ek_server_to_client: _sha512_digest;
   1881 	ik_client_to_server: _sha512_digest;
   1882 	ik_server_to_client: _sha512_digest;
   1883 	en_client_to_server: int;
   1884 	en_server_to_client: int;
   1885 	seq_client_to_server: int;
   1886 	seq_server_to_client: int;
   1887 	has_child: int;
   1888 	child_pid: int;
   1889 	child_stdin: int;
   1890 	child_stdout: int;
   1891 	child_stderr: int;
   1892 	stdin_window: int;
   1893 	stdout_window: int;
   1894 	stdin_buf: *byte;
   1895 	stdin_size: int;
   1896 	stdin_fill: int;
   1897 	stdin_eof: int;
   1898 	stdout_buf: *byte;
   1899 	stdout_fill: int;
   1900 	stdout_size: int;
   1901 	stderr_buf: *byte;
   1902 	stderr_fill: int;
   1903 	stderr_size: int;
   1904 	exit_status: int;
   1905 }
   1906 
   1907 func format_key(d: **byte, dlen: *int, k: *byte, ctx: *sshd_ctx) {
   1908 	var s: ssh_str;
   1909 	clear_frame(ctx);
   1910 	set_str(&s, "ssh-ed25519");
   1911 	encode_str(&s, ctx);
   1912 	s.s = k;
   1913 	s.len = 32;
   1914 	encode_str(&s, ctx);
   1915 	finish_frame(ctx);
   1916 	*d = alloc(ctx.a, ctx.framelen);
   1917 	memcpy(*d, ctx.frame, ctx.framelen);
   1918 	*dlen = ctx.framelen;
   1919 	clear_frame(ctx);
   1920 }
   1921 
   1922 func dosigchld() {
   1923 }
   1924 
   1925 func _restorer();
   1926 
   1927 func signal(sig: int, handler: func()) {
   1928 	var act: sigaction;
   1929 	act.handler = dosigchld as int;
   1930 	act.flags = 1 << 26;
   1931 	act.restorer = _restorer as int;
   1932 	act.mask = 0;
   1933 	sigaction(sig, &act, nil);
   1934 }
   1935 
   1936 func main(argc: int, argv: **byte, envp: **byte) {
   1937 	var fd: int;
   1938 	var cfd: int;
   1939 	var port: int;
   1940 	var sa: sockaddr;
   1941 	var ctx: sshd_ctx;
   1942 	var a: alloc;
   1943 	setup_alloc(&a);
   1944 
   1945 	signal(SIGCHLD, dosigchld);
   1946 	signal(SIGPIPE, SIG_IGN as func());
   1947 
   1948 	bzero((&ctx) as *byte, sizeof(ctx));
   1949 
   1950 	if unhex((&ctx.userpub) as *byte, "5afb3032d86d60d700e1782bfe8083ff95504cecbda531bef5ba8cdd20f34c82") != 32 {
   1951 		die("invalid userpub");
   1952 	}
   1953 
   1954 	ed25519_pub((&ctx.pub) as *byte, (&ctx.priv) as *byte);
   1955 
   1956 	ctx.child_pid = -1;
   1957 	ctx.child_stdin = -1;
   1958 	ctx.child_stdout = -1;
   1959 	ctx.child_stderr = -1;
   1960 
   1961 	ctx.a = &a;
   1962 	ctx.bufsz = 64 * 1024;
   1963 	ctx.buf = alloc(ctx.a, ctx.bufsz);
   1964 	ctx.skex = alloc(ctx.a, 4096);
   1965 	ctx.ckex = alloc(ctx.a, 4096);
   1966 	ctx.sver = "SSH-2.0-omiltem";
   1967 
   1968 	ctx.stdin_size = 64 * 1024;
   1969 	ctx.stdin_buf = alloc(ctx.a, ctx.stdin_size);
   1970 	ctx.stdout_size = 64 * 1024;
   1971 	ctx.stdout_buf = alloc(ctx.a, ctx.stdout_size);
   1972 	ctx.stderr_size = 64 * 1024;
   1973 	ctx.stderr_buf = alloc(ctx.a, ctx.stderr_size);
   1974 
   1975 	ctx.username = "erai";
   1976 	format_key(&ctx.hostkey, &ctx.hostkeylen, (&ctx.pub) as *byte, &ctx);
   1977 	format_key(&ctx.userkey, &ctx.userkeylen, (&ctx.userpub) as *byte, &ctx);
   1978 
   1979 	fd = socket(AF_INET, SOCK_STREAM, 0);
   1980 	if fd < 0 {
   1981 		die("failed to open socket");
   1982 	}
   1983 
   1984 	port = 2222;
   1985 	sa.fpa = AF_INET | ((port & 0xff) << 24) | (((port >> 8) & 0xff) << 16);
   1986 	sa.pad = 0;
   1987 	if bind(fd, (&sa) as *byte, sizeof(sa)) != 0 {
   1988 		die("failed to bind");
   1989 	}
   1990 
   1991 	if listen(fd, 128) != 0 {
   1992 		die("failed to listen");
   1993 	}
   1994 
   1995 	loop {
   1996 		loop {
   1997 			if wait(-1, nil, WNOHANG) <= 0 {
   1998 				break;
   1999 			}
   2000 		}
   2001 
   2002 		ctx.fd = accept(fd, nil, nil);
   2003 		if ctx.fd == -EINTR {
   2004 			continue;
   2005 		}
   2006 
   2007 		if ctx.fd < 0 {
   2008 			exit(1);
   2009 		}
   2010 
   2011 		if fork() == 0 {
   2012 			close(fd);
   2013 			cmain(&ctx);
   2014 			die("cmain returned");
   2015 		}
   2016 
   2017 		close(ctx.fd);
   2018 	}
   2019 }