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}