code wiki / _hdl_build / nx_aw_sftp.nx

nx_aw_sftp.nx source

↩ module page · 194 lines · 10509 B

1// nx_aw_sftp.nx -- the SOVEREIGN file WRITE rung (operator: "nishi ecosystem from the hardware rung up, each 2// rung; build if we are missing capabilities"). nx_aw_push/nx_put stream bytes over our own SSH but land them 3// with a remote `cat > file && mv` shell -- a coreutils dependency on the deploy path. This organ closes that 4// rung properly: it writes the file over the SSH **sftp subsystem** (SSH_FXP_OPEN/WRITE/CLOSE), so NOTHING on 5// the remote side is a shell -- the sftp-server is a protocol endpoint, not /bin/sh. No cat/mv/tee/dd, no 6// nascmd/.src/.dst spec files, argv-driven. Built on nx_ssh_lib's channel primitives (ssh_enc_send/recv, 7// ssh_put_*). Deploy-time only: a failed write leaves the running site untouched, so it cannot add flakiness. 8// nx_aw_sftp <local-src-path> <remote-dest-path> 9// license_tier: ORIGINAL (vault+SSH spine from nx_aw_send; the sftp layer is new) 10import "nx_syscalls.nx" 11import "nx_ssh_lib.nx" 12const FT_MAGIC_1000000: i64 = 1000000 13const FT_MAGIC_65536: i64 = 65536 14const FT_MAGIC_1048576: i64 = 1048576 15const FT_MAGIC_16384: i64 = 16384 16 17const FT_SECRET_OUT: *u8 = "/tmp/nxsecret.out" as *u8 18const FT_VAULT_NV: *u8 = "/home/elderwesto/.nishi/secrets/nas.nv" as *u8 19 20func ft_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 21func ft_num(v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(1,"-" as *u8,1)}; let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=(48 as u8);k=1}; while m>0{t[k]=((48+(m%10)) as u8);m=m/10;k=k+1}; var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1}; sys_write(1,bb,k); return 0 } 22func ft_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 23 let pid: i64 = sys_fork() 24 if pid == 0 { 25 let argv: *i64 = sys_mmap(64) as *i64 26 argv[0] = path as i64 27 var ai: i64 = 1 28 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 29 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 30 argv[ai] = 0 31 let envp: *i64 = sys_mmap(16) as *i64 32 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 33 sys_execve(path, argv, envp) 34 sys_exit(127) 35 } 36 let st: *i64 = sys_mmap(16) as *i64 37 sys_wait4(pid, st, 0) 38 return (st[0] >> 8) & 0xff 39} 40func ft_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 41func ft_napms(ms: i64) -> i64 { let ts: *i64 = sys_mmap(16) as *i64; ts[0] = 0; ts[1] = ms * FT_MAGIC_1000000; __syscall(35, ts as i64, 0, 0, 0, 0, 0); return 0 } 42 43// wrap an SFTP packet (pkt[0..plen], already [u32 len][type][body]) in an SSH CHANNEL_DATA (94) and send it. 44func sftp_send(st: *SshState, rcid: i64, pkt: *u8, plen: i64) -> i64 { 45 let cd: *u8 = sys_mmap(plen + 32); var c: i64 = 0 46 c = ssh_put_byte(cd, c, 94); c = ssh_put_u32(cd, c, rcid); c = ssh_put_u32(cd, c, plen) 47 ssh_put_bytes(cd, c, pkt, plen); c = c + plen 48 ssh_enc_send(st, cd, c) 49 return 0 50} 51// read packets until a CHANNEL_DATA (94) arrives; return the FXP type byte (rep[13]); skip WINDOW_ADJUST etc. 52func sftp_reply(st: *SshState, rep: *u8) -> i64 { 53 var guard: i64 = 0 54 while guard < 128 { 55 let rl: i64 = ssh_enc_recv(st, rep) 56 if rl < 0 { return 0 - 1 } 57 if rep[0] == 94 as u8 { return rep[13] as i64 } // FXP type sits at +13 (after 94|rcid:4|dlen:4|sftplen:4) 58 guard = guard + 1 59 } 60 return 0 - 2 61} 62// wait for CHANNEL_SUCCESS(99)/FAILURE(100) after the subsystem request. 63func sftp_chan_ok(st: *SshState, rep: *u8) -> i64 { 64 var guard: i64 = 0 65 while guard < 32 { 66 let rl: i64 = ssh_enc_recv(st, rep) 67 if rl < 0 { return 0 - 1 } 68 if rep[0] == 99 as u8 { return 1 } 69 if rep[0] == 100 as u8 { return 0 } 70 guard = guard + 1 71 } 72 return 0 - 2 73} 74 75func main(argc: i64, argv: *i64) -> i64 { 76 if argc < 3 { ssh_puts("usage: nx_aw_sftp <local-src-path> <remote-dest-path>\n" as *u8); return 2 } 77 let srcp: *u8 = argv[1] as *u8 78 let dest: *u8 = argv[2] as *u8 79 let dlen: i64 = ft_slen(dest) 80 81 // ---- sovereign credential retrieval, retry-tolerant (WSL /tmp churns mid-op) ---- 82 let pwbox: *i64 = sys_mmap(16) as *i64 83 var pw: *u8 = 0 as *u8 84 var att: i64 = 0 85 while att < 12 { 86 if ft_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) == 0 { 87 if ft_run("_offc/nx_vault.elf" as *u8, "open" as *u8, FT_VAULT_NV) == 0 { 88 pw = sys_read_file(FT_SECRET_OUT, pwbox) 89 if (pw as i64) != 0 { att = 1000 } 90 } 91 } 92 if att < 1000 { att = att + 1; ft_napms(150) } 93 } 94 ft_unlink("/tmp/nxpass" as *u8) 95 if (pw as i64) == 0 { ssh_puts("nx_aw_sftp: secret derivation FAIL after 12 retries\n" as *u8); return 3 } 96 var pwlen: i64 = pwbox[0] 97 while pwlen > 0 { if pw[pwlen-1] == 10 as u8 { pwlen = pwlen - 1 } else { if pw[pwlen-1] == 13 as u8 { pwlen = pwlen - 1 } else { break } } } 98 99 let fbox: *i64 = sys_mmap(16) as *i64 100 let payload: *u8 = sys_read_file(srcp, fbox) 101 if (payload as i64) == 0 { ssh_puts("nx_aw_sftp: cannot read local src file\n" as *u8); ft_unlink(FT_SECRET_OUT); return 5 } 102 let plen: i64 = fbox[0] 103 104 let st: *SshState = sys_mmap(SSH_STATE_BYTES) as *SshState 105 if ssh_open_session(st, (192 << 24) | (168 << 16) | (8 << 8) | 227) != 0 { ssh_puts("nx_aw_sftp: SSH session FAIL\n" as *u8); ft_unlink(FT_SECRET_OUT); return 7 } 106 if ssh_userauth_password(st, "elderwesto" as *u8, 10, pw, pwlen) != 1 { ssh_puts("nx_aw_sftp: SSH auth FAIL\n" as *u8); sys_close(st.fd); ft_unlink(FT_SECRET_OUT); return 8 } 107 ft_unlink(FT_SECRET_OUT) 108 109 // ---- open a session channel ---- 110 let rep: *u8 = sys_mmap(FT_MAGIC_65536) 111 let co: *u8 = sys_mmap(64); var c: i64 = 0 112 c = ssh_put_byte(co, c, 90); c = ssh_put_str(co, c, "session" as *u8, 7) 113 c = ssh_put_u32(co, c, 0); c = ssh_put_u32(co, c, FT_MAGIC_1048576); c = ssh_put_u32(co, c, FT_MAGIC_16384) 114 ssh_enc_send(st, co, c) 115 var rcid: i64 = 0 - 1; var guard: i64 = 0 116 while rcid < 0 { 117 if guard > 16 { ssh_puts("nx_aw_sftp: channel open FAIL\n" as *u8); sys_close(st.fd); return 9 } 118 let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { sys_close(st.fd); return 9 } 119 if rep[0] == 91 as u8 { rcid = ssh_u32be(rep, 5) } 120 if rep[0] == 92 as u8 { ssh_puts("nx_aw_sftp: channel open REJECTED\n" as *u8); sys_close(st.fd); return 9 } 121 guard = guard + 1 122 } 123 124 // ---- request the sftp subsystem ---- 125 let sr: *u8 = sys_mmap(64); var q: i64 = 0 126 q = ssh_put_byte(sr, q, 98); q = ssh_put_u32(sr, q, rcid); q = ssh_put_str(sr, q, "subsystem" as *u8, 9) 127 q = ssh_put_byte(sr, q, 1); q = ssh_put_str(sr, q, "sftp" as *u8, 4) 128 ssh_enc_send(st, sr, q) 129 if sftp_chan_ok(st, rep) != 1 { ssh_puts("nx_aw_sftp: sftp subsystem REFUSED\n" as *u8); sys_close(st.fd); return 10 } 130 131 // ---- FXP_INIT (version 3) ---- 132 let initp: *u8 = sys_mmap(32); var ip: i64 = 0 133 ip = ssh_put_u32(initp, ip, 5); ip = ssh_put_byte(initp, ip, 1); ip = ssh_put_u32(initp, ip, 3) 134 sftp_send(st, rcid, initp, ip) 135 if sftp_reply(st, rep) != 2 { ssh_puts("nx_aw_sftp: no FXP_VERSION\n" as *u8); sys_close(st.fd); return 11 } 136 137 // ---- FXP_OPEN dest, flags=WRITE|CREAT|TRUNC (0x1A), attrs=perms 0755 ---- 138 let ob: *u8 = sys_mmap(dlen + 64); var b: i64 = 0 139 b = ssh_put_byte(ob, b, 3) // FXP_OPEN 140 b = ssh_put_u32(ob, b, 1) // request id 1 141 b = ssh_put_str(ob, b, dest, dlen) 142 b = ssh_put_u32(ob, b, 0x1a) // SSH_FXF_WRITE|CREAT|TRUNC 143 b = ssh_put_u32(ob, b, 0x04) // ATTR flags = PERMISSIONS 144 b = ssh_put_u32(ob, b, 0x1ed) // 0755 145 let op: *u8 = sys_mmap(dlen + 80); var on: i64 = 0 146 on = ssh_put_u32(op, on, b); ssh_put_bytes(op, on, ob, b); on = on + b 147 sftp_send(st, rcid, op, on) 148 let ot: i64 = sftp_reply(st, rep) 149 if ot != 102 { 150 ssh_puts("nx_aw_sftp: FXP_OPEN failed -- reply_type=" as *u8); ft_num(ot) 151 if ot == 101 { ssh_puts(" fx_status=" as *u8); ft_num(ssh_u32be(rep, 18)) } 152 ssh_puts(" (fx: 1=EOF 2=NOFILE 3=PERMDENIED 4=FAILURE 5=BADMSG)\n" as *u8) 153 sys_close(st.fd); return 12 154 } 155 let hlen: i64 = ssh_u32be(rep, 18) // handle string length (rep: ..|sftplen:4|type:1|reqid:4|hlen:4|handle) 156 let handle: *u8 = sys_mmap(hlen + 8) 157 ssh_put_bytes(handle, 0, (rep + 22) as *u8, hlen) 158 159 // ---- stream FXP_WRITE chunks (<=16KB), each acked by FXP_STATUS(101) status==0 ---- 160 var off: i64 = 0; var rid: i64 = 2 161 while off < plen { 162 var nn: i64 = plen - off; if nn > FT_MAGIC_16384 { nn = FT_MAGIC_16384 } 163 let wb: *u8 = sys_mmap(nn + hlen + 64); var w: i64 = 0 164 w = ssh_put_byte(wb, w, 6) // FXP_WRITE 165 w = ssh_put_u32(wb, w, rid) 166 w = ssh_put_str(wb, w, handle, hlen) 167 w = ssh_put_u32(wb, w, 0) // offset high 32 bits (file < 4GB) 168 w = ssh_put_u32(wb, w, off) // offset low 32 bits 169 w = ssh_put_u32(wb, w, nn) // data string length 170 var i: i64 = 0; while i < nn { wb[w + i] = payload[off + i]; i = i + 1 } w = w + nn 171 let wp: *u8 = sys_mmap(w + 8); var wn: i64 = 0 172 wn = ssh_put_u32(wp, wn, w); ssh_put_bytes(wp, wn, wb, w); wn = wn + w 173 sftp_send(st, rcid, wp, wn) 174 let rt: i64 = sftp_reply(st, rep) 175 if rt != 101 { ssh_puts("nx_aw_sftp: write reply not STATUS\n" as *u8); sys_close(st.fd); return 13 } 176 let status: i64 = ssh_u32be(rep, 18) 177 if status != 0 { ssh_puts("nx_aw_sftp: FXP_WRITE STATUS error\n" as *u8); sys_close(st.fd); return 14 } 178 off = off + nn; rid = rid + 1 179 } 180 181 // ---- FXP_CLOSE ---- 182 let cb: *u8 = sys_mmap(hlen + 32); var cbn: i64 = 0 183 cbn = ssh_put_byte(cb, cbn, 4); cbn = ssh_put_u32(cb, cbn, rid); cbn = ssh_put_str(cb, cbn, handle, hlen) 184 let cp: *u8 = sys_mmap(hlen + 48); var cpn: i64 = 0 185 cpn = ssh_put_u32(cp, cpn, cbn); ssh_put_bytes(cp, cpn, cb, cbn); cpn = cpn + cbn 186 sftp_send(st, rcid, cp, cpn) 187 sftp_reply(st, rep) // final STATUS (best-effort) 188 189 ssh_puts("nx_aw_sftp: WROTE bytes=" as *u8) 190 let nbuf: *u8 = sys_mmap(28); var mm: i64=plen; let tb: *u8=sys_mmap(28); var kk: i64=0; if mm==0{tb[0]=48 as u8;kk=1}; while mm>0{tb[kk]=(48+(mm%10)) as u8;mm=mm/10;kk=kk+1}; var jj: i64=0; while jj<kk{nbuf[jj]=tb[kk-1-jj];jj=jj+1}; sys_write(1,nbuf,kk) 191 ssh_puts(" -> " as *u8); ssh_puts(dest); ssh_puts(" (sovereign sftp, no shell)\n" as *u8) 192 sys_close(st.fd) 193 return 0 194}