code wiki / _hdl_build / nx_aw_fetch.nx

nx_aw_fetch.nx source

↩ module page · 179 lines · 9065 B

1// nx_aw_fetch.nx -- CAP-AW-FETCH: sovereign SFTP GET (pull) -- the READ rung, mirror of nx_aw_sftp's WRITE rung. 2// Pulls a remote NAS file (owned by elderwesto, reachable over SSH even when the home SMB share mounts empty locally) 3// down to a LOCAL path via the SSH sftp subsystem (FXP_OPEN read / FXP_READ / FXP_CLOSE) -- NOTHING on the remote is a 4// shell (sftp-server is a protocol endpoint). Closes the DR gap: archive the auth crown jewels (opaque_store etc.) 5// the local mount can't reach. Read-only on the NAS (never writes it). argv: [1]=remote-src [2]=local-dest. 6// license_tier: ORIGINAL (vault+SSH+sftp spine from nx_aw_sftp; the READ path is new) 7import "nx_syscalls.nx" 8import "nx_ssh_lib.nx" 9const FT_MAGIC_1000000: i64 = 1000000 10const FT_MAGIC_65536: i64 = 65536 11const FT_MAGIC_1048576: i64 = 1048576 12const FT_MAGIC_16384: i64 = 16384 13 14const FT_SECRET_OUT: *u8 = "/tmp/nxsecret.out" as *u8 15const FT_VAULT_NV: *u8 = "/home/elderwesto/.nishi/secrets/nas.nv" as *u8 16 17func ft_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 18func 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 } 19func ft_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 20 let pid: i64 = sys_fork() 21 if pid == 0 { 22 let argv: *i64 = sys_mmap(64) as *i64 23 argv[0] = path as i64 24 var ai: i64 = 1 25 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 26 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 27 argv[ai] = 0 28 let envp: *i64 = sys_mmap(16) as *i64 29 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 30 sys_execve(path, argv, envp) 31 sys_exit(127) 32 } 33 let st: *i64 = sys_mmap(16) as *i64 34 sys_wait4(pid, st, 0) 35 return (st[0] >> 8) & 0xff 36} 37func ft_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 38func 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 } 39 40func sftp_send(st: *SshState, rcid: i64, pkt: *u8, plen: i64) -> i64 { 41 let cd: *u8 = sys_mmap(plen + 32); var c: i64 = 0 42 c = ssh_put_byte(cd, c, 94); c = ssh_put_u32(cd, c, rcid); c = ssh_put_u32(cd, c, plen) 43 ssh_put_bytes(cd, c, pkt, plen); c = c + plen 44 ssh_enc_send(st, cd, c) 45 return 0 46} 47func sftp_reply(st: *SshState, rep: *u8) -> i64 { 48 var guard: i64 = 0 49 while guard < 128 { 50 let rl: i64 = ssh_enc_recv(st, rep) 51 if rl < 0 { return 0 - 1 } 52 if rep[0] == 94 as u8 { return rep[13] as i64 } 53 guard = guard + 1 54 } 55 return 0 - 2 56} 57func sftp_chan_ok(st: *SshState, rep: *u8) -> i64 { 58 var guard: i64 = 0 59 while guard < 32 { 60 let rl: i64 = ssh_enc_recv(st, rep) 61 if rl < 0 { return 0 - 1 } 62 if rep[0] == 99 as u8 { return 1 } 63 if rep[0] == 100 as u8 { return 0 } 64 guard = guard + 1 65 } 66 return 0 - 2 67} 68 69func main(argc: i64, argv: *i64) -> i64 { 70 if argc < 3 { ssh_puts("usage: nx_aw_fetch <remote-src-path> <local-dest-path>\n" as *u8); return 2 } 71 let srcp: *u8 = argv[1] as *u8 72 let dest: *u8 = argv[2] as *u8 73 let slen: i64 = ft_slen(srcp) 74 75 let pwbox: *i64 = sys_mmap(16) as *i64 76 var pw: *u8 = 0 as *u8 77 var att: i64 = 0 78 while att < 12 { 79 if ft_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) == 0 { 80 if ft_run("_offc/nx_vault.elf" as *u8, "open" as *u8, FT_VAULT_NV) == 0 { 81 pw = sys_read_file(FT_SECRET_OUT, pwbox) 82 if (pw as i64) != 0 { att = 1000 } 83 } 84 } 85 if att < 1000 { att = att + 1; ft_napms(150) } 86 } 87 if (pw as i64) == 0 { ssh_puts("nx_aw_fetch: secret derivation FAIL after 12 retries\n" as *u8); return 3 } 88 var pwlen: i64 = pwbox[0] 89 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 } } } 90 91 let st: *SshState = sys_mmap(SSH_STATE_BYTES) as *SshState 92 if ssh_open_session(st, (192 << 24) | (168 << 16) | (8 << 8) | 227) != 0 { ssh_puts("nx_aw_fetch: SSH session FAIL\n" as *u8); ft_unlink(FT_SECRET_OUT); return 7 } 93 if ssh_userauth_password(st, "elderwesto" as *u8, 10, pw, pwlen) != 1 { ssh_puts("nx_aw_fetch: SSH auth FAIL\n" as *u8); sys_close(st.fd); ft_unlink(FT_SECRET_OUT); return 8 } 94 ft_unlink(FT_SECRET_OUT) 95 96 let rep: *u8 = sys_mmap(FT_MAGIC_65536) 97 let co: *u8 = sys_mmap(64); var c: i64 = 0 98 c = ssh_put_byte(co, c, 90); c = ssh_put_str(co, c, "session" as *u8, 7) 99 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) 100 ssh_enc_send(st, co, c) 101 var rcid: i64 = 0 - 1; var guard: i64 = 0 102 while rcid < 0 { 103 if guard > 16 { ssh_puts("nx_aw_fetch: channel open FAIL\n" as *u8); sys_close(st.fd); return 9 } 104 let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { sys_close(st.fd); return 9 } 105 if rep[0] == 91 as u8 { rcid = ssh_u32be(rep, 5) } 106 if rep[0] == 92 as u8 { ssh_puts("nx_aw_fetch: channel open REJECTED\n" as *u8); sys_close(st.fd); return 9 } 107 guard = guard + 1 108 } 109 110 let sr: *u8 = sys_mmap(64); var q: i64 = 0 111 q = ssh_put_byte(sr, q, 98); q = ssh_put_u32(sr, q, rcid); q = ssh_put_str(sr, q, "subsystem" as *u8, 9) 112 q = ssh_put_byte(sr, q, 1); q = ssh_put_str(sr, q, "sftp" as *u8, 4) 113 ssh_enc_send(st, sr, q) 114 if sftp_chan_ok(st, rep) != 1 { ssh_puts("nx_aw_fetch: sftp subsystem REFUSED\n" as *u8); sys_close(st.fd); return 10 } 115 116 let initp: *u8 = sys_mmap(32); var ip: i64 = 0 117 ip = ssh_put_u32(initp, ip, 5); ip = ssh_put_byte(initp, ip, 1); ip = ssh_put_u32(initp, ip, 3) 118 sftp_send(st, rcid, initp, ip) 119 if sftp_reply(st, rep) != 2 { ssh_puts("nx_aw_fetch: no FXP_VERSION\n" as *u8); sys_close(st.fd); return 11 } 120 121 // ---- FXP_OPEN srcp, flags=READ (0x01), no attrs ---- 122 let ob: *u8 = sys_mmap(slen + 64); var b: i64 = 0 123 b = ssh_put_byte(ob, b, 3) // FXP_OPEN 124 b = ssh_put_u32(ob, b, 1) // request id 1 125 b = ssh_put_str(ob, b, srcp, slen) 126 b = ssh_put_u32(ob, b, 0x01) // SSH_FXF_READ 127 b = ssh_put_u32(ob, b, 0x00) // ATTR flags = none 128 let op: *u8 = sys_mmap(slen + 80); var on: i64 = 0 129 on = ssh_put_u32(op, on, b); ssh_put_bytes(op, on, ob, b); on = on + b 130 sftp_send(st, rcid, op, on) 131 let ot: i64 = sftp_reply(st, rep) 132 if ot != 102 { 133 ssh_puts("nx_aw_fetch: FXP_OPEN failed -- reply_type=" as *u8); ft_num(ot) 134 if ot == 101 { ssh_puts(" fx_status=" as *u8); ft_num(ssh_u32be(rep, 18)) } 135 ssh_puts(" (fx: 2=NOFILE 3=PERMDENIED 4=FAILURE)\n" as *u8) 136 sys_close(st.fd); return 12 137 } 138 let hlen: i64 = ssh_u32be(rep, 18) 139 let handle: *u8 = sys_mmap(hlen + 8) 140 ssh_put_bytes(handle, 0, (rep + 22) as *u8, hlen) 141 142 // ---- open the local dest (only after the remote OPEN succeeded) ---- 143 let lfd: i64 = sys_openat_wr(dest, 0x1a4) 144 if lfd < 0 { ssh_puts("nx_aw_fetch: cannot open local dest\n" as *u8); sys_close(st.fd); return 5 } 145 146 // ---- stream FXP_READ (16KB) until FXP_STATUS(101, EOF) ---- 147 var off: i64 = 0; var rid: i64 = 2; var go: i64 = 1; var total: i64 = 0 148 while go == 1 { 149 let rb: *u8 = sys_mmap(hlen + 64); var r: i64 = 0 150 r = ssh_put_byte(rb, r, 5) // FXP_READ 151 r = ssh_put_u32(rb, r, rid) 152 r = ssh_put_str(rb, r, handle, hlen) 153 r = ssh_put_u32(rb, r, 0) // offset high 32 154 r = ssh_put_u32(rb, r, off) // offset low 32 155 r = ssh_put_u32(rb, r, FT_MAGIC_16384) // length requested 156 let rp: *u8 = sys_mmap(r + 8); var rn: i64 = 0 157 rn = ssh_put_u32(rp, rn, r); ssh_put_bytes(rp, rn, rb, r); rn = rn + r 158 sftp_send(st, rcid, rp, rn) 159 let rt: i64 = sftp_reply(st, rep) 160 if rt == 103 { // FXP_DATA 161 let dl: i64 = ssh_u32be(rep, 18) 162 if dl <= 0 { go = 0 } else { sys_write(lfd, (rep + 22) as *u8, dl); off = off + dl; total = total + dl; rid = rid + 1 } 163 } else { go = 0 } // FXP_STATUS (EOF/err) or unexpected -> stop 164 } 165 sys_close(lfd) 166 167 // ---- FXP_CLOSE ---- 168 let cb: *u8 = sys_mmap(hlen + 32); var cbn: i64 = 0 169 cbn = ssh_put_byte(cb, cbn, 4); cbn = ssh_put_u32(cb, cbn, rid); cbn = ssh_put_str(cb, cbn, handle, hlen) 170 let cp: *u8 = sys_mmap(hlen + 48); var cpn: i64 = 0 171 cpn = ssh_put_u32(cp, cpn, cbn); ssh_put_bytes(cp, cpn, cb, cbn); cpn = cpn + cbn 172 sftp_send(st, rcid, cp, cpn) 173 sftp_reply(st, rep) 174 175 ssh_puts("nx_aw_fetch: PULLED bytes=" as *u8); ft_num(total) 176 ssh_puts(" -> " as *u8); ssh_puts(dest); ssh_puts(" (sovereign sftp GET, no shell, NAS read-only)\n" as *u8) 177 sys_close(st.fd) 178 return 0 179}