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}