code wiki / _hdl_build / nx_aw_hostctl.nx

nx_aw_hostctl.nx source

↩ module page · 290 lines · 22860 B

1// nx_aw_hostctl.nx -- SOVEREIGN deploy/supervision TRIGGER for the NAS control plane. Retires the 2// nascmd.txt + nx_aw_nasfix "run arbitrary shell" escape hatch for the deploy path (operator: "no .txt and 3// other bullshit... nishi ecosystem all the way up from the hardware rung, each rung"). It gets the NAS 4// password from the sovereign vault (composes _offc/nx_machine_key.elf + _offc/nx_vault.elf, exactly as 5// nx_aw_nasfix/nx_secret_cli do), opens the team's OWN sovereign SSH (nx_ssh_lib), and runs EXACTLY ONE 6// thing remotely: the sovereign control-plane binary nx_hostctl with an ALLOWLISTED subcommand. The remote 7// payload is an absolute binary path + one validated arg -- NO command file, NO cd/&&, NO tar/kill/setsid/ 8// fuser/dev-tcp coreutils. All real lifecycle work (atomic binary swap, kill, respawn, health) is done by 9// nx_hostctl's own syscalls. This is the "named sovereign op-organ" the sovereignty memo specified. 10// nx_aw_hostctl selfswap -> run nx_hostctl.new selfswap : install+adopt the NEW supervisor (wiki-aware) 11// nx_aw_hostctl deploy -> run nx_hostctl deploy : atomic-swap sites.elf + respawn (/wiki route) 12// nx_aw_hostctl wikideploy -> run nx_hostctl wikideploy : atomic-swap the wiki gateway + respawn 13// nx_aw_hostctl galxdeploy -> run nx_hostctl galxdeploy : atomic-swap the gallery gateway + respawn 14// nx_aw_hostctl reconcile -> run nx_hostctl reconcile : one-supervisor reconcile (adopt sites.elf) 15// license_tier: ORIGINAL (vault+SSH spine reused from nx_aw_nasfix; the shell escape hatch removed) 16import "nx_syscalls.nx" 17import "nx_ssh_lib.nx" 18import "nx_arbiter.nx" // fl_acquire/fl_release -- serialize control-plane ops vs sibling publishes (the queue) 19import "nx_receipt.nx" // rcpt_emit -- the op acceptance/receipt ledger (every control-plane op reports back to the workstream) 20const AH_MAGIC_8095: i64 = 8095 21const AH_MAGIC_18190: i64 = 18190 22const AH_MAGIC_18794: i64 = 18794 23const AH_MAGIC_18795: i64 = 18795 24const AH_MAGIC_18099: i64 = 18099 25const AH_MAGIC_9099: i64 = 9099 26const AH_MAGIC_9091: i64 = 9091 27const AH_MAGIC_9444: i64 = 9444 28const AH_MAGIC_8453: i64 = 8453 29const AH_MAGIC_8444: i64 = 8444 30const AH_MAGIC_8791: i64 = 8791 31const AH_MAGIC_8097: i64 = 8097 32const AH_MAGIC_18797: i64 = 18797 33const AH_MAGIC_18793: i64 = 18793 34const AH_MAGIC_6881: i64 = 6881 35const AH_MAGIC_18090: i64 = 18090 36const AH_MAGIC_18796: i64 = 18796 37const AH_MAGIC_18456: i64 = 18456 38const AH_MAGIC_65536: i64 = 65536 39const AH_MAGIC_1048576: i64 = 1048576 40const AH_MAGIC_16384: i64 = 16384 41const AH_MAGIC_1024: i64 = 1024 42const AH_MAGIC_1800: i64 = 1800 43 44const AH_SECRET_OUT: *u8 = "/tmp/nxsecret.out" as *u8 45const AH_VAULT_NV: *u8 = "/home/elderwesto/.nishi/secrets/nas.nv" as *u8 46const AH_HOSTCTL: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl" as *u8 47const AH_HOSTCTL_NEW: *u8 = "/volume1/homes/elderwesto/nishihost/nx_hostctl.new" as *u8 48 49func ah_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 50func ah_streq(a: *u8, b: *u8) -> i64 { var i: i64=0; while a[i]!=(0 as u8) { if a[i]!=b[i] { return 0 } i=i+1 } if b[i]!=(0 as u8) { return 0 } return 1 } 51 52// fork+execve a sovereign helper binary; parent waits; returns child WEXITSTATUS (mirrors nx_aw_nasfix). 53func ah_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 54 let pid: i64 = sys_fork() 55 if pid == 0 { 56 let argv: *i64 = sys_mmap(64) as *i64 57 argv[0] = path as i64 58 var ai: i64 = 1 59 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 60 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 61 argv[ai] = 0 62 let envp: *i64 = sys_mmap(16) as *i64 63 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 64 sys_execve(path, argv, envp) 65 sys_exit(127) 66 } 67 let st: *i64 = sys_mmap(16) as *i64 68 sys_wait4(pid, st, 0) 69 return (st[0] >> 8) & 0xff 70} 71func ah_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 72 73// DEFENSIVE BOUNDARY (operator: "no one can ever get into areas they shouldnt"): only these exact subcommands 74// may be sent to the NAS control plane. Anything else is REFUSED before any SSH happens -- zero command 75// injection surface (this organ can NEVER run arbitrary shell, by construction, unlike nx_aw_nasfix). 76func ah_allowed(sub: *u8) -> i64 { 77 if ah_streq(sub, "selfswap" as *u8) == 1 { return 1 } 78 if ah_streq(sub, "galxpipeline" as *u8) == 1 { return 1 } // run analysis-on-ingest pipeline (thumbnails + NXVI) 79 if ah_streq(sub, "mgmtdeploy" as *u8) == 1 { return 1 } // deploy the mgmt-API allowlist update (pure-MCP run path) 80 if ah_streq(sub, "status" as *u8) == 1 { return 1 } 81 if ah_streq(sub, "sitetest" as *u8) == 1 { return 1 } 82 if ah_streq(sub, "startsite" as *u8) == 1 { return 1 } 83 if ah_streq(sub, "statushtml" as *u8) == 1 { return 1 } 84 if ah_streq(sub, "deploy" as *u8) == 1 { return 1 } 85 if ah_streq(sub, "wikideploy" as *u8) == 1 { return 1 } 86 if ah_streq(sub, "galxdeploy" as *u8) == 1 { return 1 } 87 if ah_streq(sub, "galxservedeploy" as *u8) == 1 { return 1 } // promote+restart the gallery SERVE (mirror galxdeploy) 88 if ah_streq(sub, "libdeploy" as *u8) == 1 { return 1 } // promote+launch the sovereign library backend :AH_MAGIC_8095 (/research) 89 if ah_streq(sub, "reconcile" as *u8) == 1 { return 1 } 90 if ah_streq(sub, "restart" as *u8) == 1 { return 1 } // restart <known-service>: heal action -- kill+respawn a wedged supervised daemon (2nd arg = service name) 91 if ah_streq(sub, "buildrun" as *u8) == 1 { return 1 } // buildrun <target>: COMPILE a target on the NAS (build-over-API) -> stage <target>.sov.elf.new 92 if ah_streq(sub, "buildsetup" as *u8) == 1 { return 1 } // buildsetup: mkdir buildroot/{_offc,runtime} (once, before toolchain deploy) 93 if ah_streq(sub, "galxauthprobe" as *u8) == 1 { return 1 } // loopback POST :AH_MAGIC_18190 auth -- isolates olg_login-hang vs proxy 94 if ah_streq(sub, "galxregprobe" as *u8) == 1 { return 1 } // loopback POST :AH_MAGIC_18190 register -- proves a user can create an account 95 if ah_streq(sub, "superrollback" as *u8) == 1 { return 1 } // never-brick rollback of a bad selfswap (restore nx_hostctl.prev) 96 if ah_streq(sub, "supervisetest" as *u8) == 1 { return 1 } // read-only lease check = mechanical single-supervisor proof 97 if ah_streq(sub, "hubdeploy" as *u8) == 1 { return 1 } // mkdir /volume1/ai/hub{,/pages} (sovereign sys_mkdir) 98 if ah_streq(sub, "gendeploy" as *u8) == 1 { return 1 } // mkdir /volume1/ai/gen + chmod gen daemons +x (HC_GEN guards launch :AH_MAGIC_18794/:AH_MAGIC_18795) 99 if ah_streq(sub, "mirror" as *u8) == 1 { return 1 } // NAS-resident Apertus/model mirror -> /volume1/ai/apertus (run-on-target, not the dev laptop) 100 if ah_streq(sub, "mirrorpar" as *u8) == 1 { return 1 } // NAS-resident PARALLEL concurrent download (proves what crashed WSL) 101 if ah_streq(sub, "mirrorstop" as *u8) == 1 { return 1 } // stop the NAS mirror/parallel pulls (full-cmdline kill) 102 if ah_streq(sub, "distpub" as *u8) == 1 { return 1 } // publish a real NAS file into the hub distribution index 103 if ah_streq(sub, "distserve" as *u8) == 1 { return 1 } // start the /dist content-addressed download server (:AH_MAGIC_18099) 104 if ah_streq(sub, "distprobe" as *u8) == 1 { return 1 } // loopback self-test: GET a published cid -> real bytes 105 if ah_streq(sub, "genprobe" as *u8) == 1 { return 1 } // one-shot LIVE proof: run nx_gen_live_probe.elf -> drive the deployed /gen gateway, relay PASS/FAIL 106 if ah_streq(sub, "rollback" as *u8) == 1 { return 1 } // restore sites.elf.prev (reverse a bad deploy) 107 if ah_streq(sub, "certswap" as *u8) == 1 { return 1 } // backup live TLS cert -> .bak, install .new -> live, restart sites.elf (no binary swap) 108 if ah_streq(sub, "certrollback" as *u8) == 1 { return 1 } // restore TLS cert .bak -> live + restart (reverse a bad certswap) 109 if ah_streq(sub, "logintest" as *u8) == 1 { return 1 } // spawn login .new on :AH_MAGIC_9099 (pre-flight, live :AH_MAGIC_9091 untouched) 110 if ah_streq(sub, "mtlsproxytest" as *u8) == 1 { return 1 } // sovereign-launch the mTLS reverse proxy on TEST :AH_MAGIC_9444 (no :443/DSM change) 111 if ah_streq(sub, "platformtest" as *u8) == 1 { return 1 } // sovereign-launch andelinwest :AH_MAGIC_8453 + SNI router :AH_MAGIC_8444 (INTERNAL, no :443/DSM change) 112 if ah_streq(sub, "nftread" as *u8) == 1 { return 1 } // sovereign netfilter R0: READ-ONLY nat-table probe (grounds legacy-vs-nft; cannot touch DSM's rules) 113 if ah_streq(sub, "nettap" as *u8) == 1 { return 1 } // NX-NETSCOPE wire tap: read-only bounded 60s capture of inbound SYNs to [arg=port|443] -- the wireshark-in-the-API 114 if ah_streq(sub, "logindeploy" as *u8) == 1 { return 1 } // swap+restart the 24h-TTL login daemon (.prev rollback) 115 if ah_streq(sub, "loginrollback" as *u8) == 1 { return 1 } // restore nx_opaque_login.elf.prev 116 if ah_streq(sub, "findlaunch" as *u8) == 1 { return 1 } // recover the original login launch args (read-only grep) 117 if ah_streq(sub, "receipts" as *u8) == 1 { return 1 } // dump op_receipts.tsv (acceptance + MEASURED ms per op, read-only) 118 if ah_streq(sub, "kickreader" as *u8) == 1 { return 1 } // surgical: kill the wedged :AH_MAGIC_8791 reader; keeper respawns 119 if ah_streq(sub, "kicktorrent" as *u8) == 1 { return 1 } // surgical: kill the :AH_MAGIC_8097 media daemon; guard respawns the NEW (loopback) binary 120 if ah_streq(sub, "kickdevapi" as *u8) == 1 { return 1 } // surgical: kill the :AH_MAGIC_18797 dev/CI API daemon; guard respawns the NEW binary 121 if ah_streq(sub, "devapitoolchain" as *u8) == 1 { return 1 } // extract the nx_cc toolchain tarball on the hub -> /api/dev/build compiles on the NAS 122 if ah_streq(sub, "kicktorrentgw" as *u8) == 1 { return 1 } // surgical: kill the :AH_MAGIC_18793 torrent gateway; guard respawns the NEW binary 123 if ah_streq(sub, "kickseed" as *u8) == 1 { return 1 } // surgical: kill the :AH_MAGIC_6881 BitTorrent seeder; hc_guard_seed respawns the NEW binary (+ re-reads seed_index.conf) 124 if ah_streq(sub, "torstat" as *u8) == 1 { return 1 } // diagnostic: seedeval per active download -> SCARCE/IGNORING/COMPLETE (read-only) 125 if ah_streq(sub, "kickworkers" as *u8) == 1 { return 1 } // kill stale download workers -> kicktorrent respawns the NEW worker binary 126 if ah_streq(sub, "reseed" as *u8) == 1 { return 1 } // register all completed downloads for seeding (share the library back) 127 if ah_streq(sub, "trackerrefresh" as *u8) == 1 { return 1 } // grow trackers.txt from live public lists (sovereign TLS fetch) 128 if ah_streq(sub, "portmap" as *u8) == 1 { return 1 } // NAT-PMP auto-open :AH_MAGIC_6881 on the router (WAN reach) 129 if ah_streq(sub, "routerctl" as *u8) == 1 { return 1 } // sovereign GL.iNet dashboard (model/wan/forwards/clients via SSH+uci) 130 if ah_streq(sub, "torrentdeploy" as *u8) == 1 { return 1 } // P1 off-LAN parity: promote staged torrent daemon/seedeval -> /volume1/ai/torrent/ + kick 131 if ah_streq(sub, "torrentrollback" as *u8) == 1 { return 1 } // never-brick reverse of a bad torrentdeploy (.prev -> live) 132 if ah_streq(sub, "kickseedann" as *u8) == 1 { return 1 } // surgical: kill the DHT announcer; hc_guard_seedann respawns it (immediate re-announce sweep) 133 if ah_streq(sub, "killdurindex" as *u8) == 1 { return 1 } // surgical: kill the stray durindex holding the gallery's :AH_MAGIC_18090 socket (fd-leak from a removed boot-spawn) 134 if ah_streq(sub, "durindexrun" as *u8) == 1 { return 1 } // proper detached one-shot: launch the duration-index batch (fds closed, flock) -> runtime-sort populates 135 if ah_streq(sub, "durindexstat" as *u8) == 1 { return 1 } // read-only: galx_dur.raw durations done vs vid_paths total (runtime-sort data readiness) 136 if ah_streq(sub, "tsdurtest" as *u8) == 1 { return 1 } // diagnostic: run nx_ts_dur on one tail video + show output 137 if ah_streq(sub, "durbinbuild" as *u8) == 1 { return 1 } // compact galx_dur.raw -> galx_dur.bin: O(1) /dur seekbar lookup (no 16MB PCR re-scan), no gallery restart 138 if ah_streq(sub, "galxdurprobe" as *u8) == 1 { return 1 } // LIVE proof: loopback GET :AH_MAGIC_18090/vid/0/dur asserts the /dur fast-path serves a duration (no crash) 139 if ah_streq(sub, "galxtagprobe" as *u8) == 1 { return 1 } // LIVE proof: POST /tag -> GET /api/tags round-trip (R4 tag store write+read+last-wins over loopback) 140 if ah_streq(sub, "galxstreamprobe" as *u8) == 1 { return 1 } // read-only MEASURE: time /segs + .idx build + /init + /seg (grounds the streaming-perf fix; no playback change) 141 if ah_streq(sub, "galxgwprobe" as *u8) == 1 { return 1 } // read-only: loopback GET :AH_MAGIC_18190/gallery -> isolates the /gallery 404 (gateway vs sites.elf route) 142 if ah_streq(sub, "kicksites" as *u8) == 1 { return 1 } // kill sites.elf -> supervisor respawns live binary (re-reads proxy_routes.conf; NO binary swap) 143 if ah_streq(sub, "kicksynth" as *u8) == 1 { return 1 } // kill nx_synth_serve_daemon.elf -> hc_guard_synth respawns the freshly-staged binary (:AH_MAGIC_18796 /synth/api redeploy) 144 if ah_streq(sub, "kickdocportal" as *u8) == 1 { return 1 } // kill the docportal admin daemon (:AH_MAGIC_18456); guard respawns the NEW shipped binary (was remote-only, never client-allowlisted) 145 if ah_streq(sub, "tsindextest" as *u8) == 1 { return 1 } // read-only MEASURE: run nx_ts_index on a .ts + show scan_ms (the .idx build time) + keyframes/dur 146 if ah_streq(sub, "galxlibstats" as *u8) == 1 { return 1 } // read-only: library scale (count + total runtime) from galx_dur.bin 147 return 0 148} 149 150// non-blocking drain of pending server packets (prevents the bidirectional deadlock while streaming stdin). 151func ah_drain(st: *SshState) -> i64 { 152 let pfd: *u8 = sys_mmap(8); let fdv: i64 = st.fd 153 pfd[0]=(fdv&0xff) as u8; pfd[1]=((fdv>>8)&0xff) as u8; pfd[2]=((fdv>>16)&0xff) as u8; pfd[3]=((fdv>>24)&0xff) as u8 154 pfd[4]=1 as u8; pfd[5]=0 as u8 155 let buf: *u8 = sys_mmap(AH_MAGIC_65536); var run: i64 = 1 156 while run == 1 { let r: i64 = sys_poll(pfd, 1, 0); if r <= 0 { run = 0 } else { if ssh_enc_recv(st, buf) < 0 { run = 0 } } } 157 return 0 158} 159// open an exec channel for `wcmd`, stream `data` (the sudo password + newline) to its stdin, print the 160// remote output (channel-data) to fd 1, drain to EOF. Same SSH-channel mechanism as nx_aw_send's writer. 161// quiet_max = drain patience in 500ms polls with NO channel data before giving up: 8 (=4s) suits fast 162// verbs; LONG-RUNNING verbs (nettap's bounded 60s capture prints nothing until a SYN arrives) pass a 163// bigger budget so the results aren't orphaned mid-window (2026-07-05: nettap output died at the banner). 164func ah_sudo_put(st: *SshState, wcmd: *u8, wcmdlen: i64, data: *u8, datalen: i64, quiet_max: i64) -> i64 { 165 let co: *u8 = sys_mmap(64); var c: i64 = 0 166 c = ssh_put_byte(co, c, 90); c = ssh_put_str(co, c, "session" as *u8, 7) 167 c = ssh_put_u32(co, c, 0); c = ssh_put_u32(co, c, AH_MAGIC_1048576); c = ssh_put_u32(co, c, AH_MAGIC_16384) 168 ssh_enc_send(st, co, c) 169 let rep: *u8 = sys_mmap(AH_MAGIC_65536); var rcid: i64 = 0 - 1; var guard: i64 = 0 170 while rcid < 0 { 171 if guard > 16 { return 0 - 1 } 172 let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { return 0 - 1 } 173 if rep[0] == 91 as u8 { rcid = ssh_u32be(rep, 5) } 174 if rep[0] == 92 as u8 { return 0 - 2 } 175 guard = guard + 1 176 } 177 let cr: *u8 = sys_mmap(AH_MAGIC_1024); var q: i64 = 0 178 q = ssh_put_byte(cr, q, 98); q = ssh_put_u32(cr, q, rcid); q = ssh_put_str(cr, q, "exec" as *u8, 4); q = ssh_put_byte(cr, q, 1); q = ssh_put_str(cr, q, wcmd, wcmdlen) 179 ssh_enc_send(st, cr, q) 180 var off: i64 = 0 181 while off < datalen { 182 var nn: i64 = datalen - off; if nn > AH_MAGIC_16384 { nn = AH_MAGIC_16384 } 183 let dp: *u8 = sys_mmap(nn + 64); var p: i64 = 0 184 p = ssh_put_byte(dp, p, 94); p = ssh_put_u32(dp, p, rcid); p = ssh_put_u32(dp, p, nn) 185 var i: i64 = 0; while i < nn { dp[p + i] = data[off + i]; i = i + 1 } p = p + nn 186 ssh_enc_send(st, dp, p) 187 ah_drain(st) 188 off = off + nn 189 } 190 let eo: *u8 = sys_mmap(16); var e: i64 = 0; e = ssh_put_byte(eo, e, 96); e = ssh_put_u32(eo, e, rcid); ssh_enc_send(st, eo, e) 191 let pfd2: *u8 = sys_mmap(8); let fdv2: i64 = st.fd 192 pfd2[0]=(fdv2&0xff) as u8; pfd2[1]=((fdv2>>8)&0xff) as u8; pfd2[2]=((fdv2>>16)&0xff) as u8; pfd2[3]=((fdv2>>24)&0xff) as u8 193 pfd2[4]=1 as u8; pfd2[5]=0 as u8 194 var done: i64 = 0; var quiet: i64 = 0 195 while done == 0 { 196 let pr: i64 = sys_poll(pfd2, 1, 500) 197 if pr <= 0 { quiet = quiet + 1; if quiet >= quiet_max { done = 1 } } 198 else { let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { done = 1 } else { 199 if rep[0] == 94 as u8 { let dl: i64 = ssh_u32be(rep, 5); sys_write(1, (rep as i64 + 9) as *u8, dl) } 200 if rep[0] == 97 as u8 { done = 1 } } } 201 } 202 let clo: *u8 = sys_mmap(16); var k: i64 = 0; k = ssh_put_byte(clo, k, 97); k = ssh_put_u32(clo, k, rcid); ssh_enc_send(st, clo, k) 203 return 0 204} 205 206func main(argc: i64, argv: *i64) -> i64 { 207 if argc < 2 { 208 ssh_puts("usage: nx_aw_hostctl <selfswap|deploy|wikideploy|galxdeploy|reconcile|kickreader|status>\n" as *u8); return 2 209 } 210 let sub: *u8 = argv[1] as *u8 211 if ah_allowed(sub) == 0 { 212 ssh_puts("nx_aw_hostctl: REFUSED -- subcommand not in the allowlist (no arbitrary remote exec)\n" as *u8); return 2 213 } 214 // QUEUE: a deploy/selfswap/reconcile restarts daemons -- concurrent ones are THE disaster. Serialize on the 215 // SAME nas_push lease as content publishes so the whole NAS mutation path is one-at-a-time (mutual exclusion). 216 let lock_fd: i64 = fl_acquire("nas_push" as *u8, AH_MAGIC_1800, 100) 217 if lock_fd < 0 { ssh_puts("nx_aw_hostctl: nas_push lease busy >180s -- aborting (retry)\n" as *u8); return 9 } 218 219 // ---- sovereign credential retrieval (no shell, no typed passphrase) ---- 220 if ah_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) != 0 { 221 ssh_puts("nx_aw_hostctl: machine-key derive FAILED\n" as *u8); ah_unlink("/tmp/nxpass" as *u8); return 1 222 } 223 if ah_run("_offc/nx_vault.elf" as *u8, "open" as *u8, AH_VAULT_NV) != 0 { 224 ssh_puts("nx_aw_hostctl: vault open nas.nv FAILED (no secret / wrong machine / tampered)\n" as *u8) 225 ah_unlink("/tmp/nxpass" as *u8); return 2 226 } 227 ah_unlink("/tmp/nxpass" as *u8) // shred the passphrase ephemeral immediately 228 let pwbox: *i64 = sys_mmap(16) as *i64 229 let pw: *u8 = sys_read_file(AH_SECRET_OUT, pwbox) 230 if (pw as i64) == 0 { ssh_puts("nx_aw_hostctl: cannot read decrypted secret\n" as *u8); return 3 } 231 var pwlen: i64 = pwbox[0] 232 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 } } } 233 234 // ---- sovereign SSH to the NAS (192.168.8.227) ---- 235 let st: *SshState = sys_mmap(SSH_STATE_BYTES) as *SshState 236 if ssh_open_session(st, (192 << 24) | (168 << 16) | (8 << 8) | 227) != 0 { 237 ssh_puts("nx_aw_hostctl: SSH session FAILED (NAS unreachable on :22)\n" as *u8); ah_unlink(AH_SECRET_OUT); return 5 238 } 239 if ssh_userauth_password(st, "elderwesto" as *u8, 10, pw, pwlen) != 1 { 240 ssh_puts("nx_aw_hostctl: SSH auth FAILED\n" as *u8); sys_close(st.fd); ah_unlink(AH_SECRET_OUT); return 6 241 } 242 ah_unlink(AH_SECRET_OUT) // shred the decrypted secret file (pw stays only in this process) 243 244 // ---- compose the SINGLE remote invocation: "<abs-binpath> <allowlisted-sub>" ---- 245 // selfswap must run the NEW binary (nx_hostctl.new) so it installs+adopts; everything else runs the live 246 // nx_hostctl. Absolute path => the remote login shell just execs the sovereign binary (no cd, no &&, no 247 // PATH lookup). One binary + one validated arg = the entire remote payload. 248 var bin: *u8 = AH_HOSTCTL 249 // ONLY selfswap runs the staged .new (to install it); everything else runs the LIVE binary -- because 250 // selfswap CONSUMES .new (renames it onto live), so after an install .new no longer exists. Live is the 251 // freshly-installed (memory-fixed) binary, so status/sitetest/startsite/etc. get the fix from live. 252 if ah_streq(sub, "selfswap" as *u8) == 1 { bin = AH_HOSTCTL_NEW } 253 // ROOT control plane: "sudo -S <abs>/nx_hostctl <sub>" with the vault password streamed to sudo's stdin. 254 // reconcile/deploy/selfswap MUST run as root to manage the boot-launched ROOT supervisor + daemons 255 // (kill/respawn). nx_hostctl self-chdirs, so NO shell `cd`; argv-driven sub, so NO .cmd staging file. 256 let pfx: *u8 = "sudo -S " as *u8 257 let pfxlen: i64 = ah_slen(pfx) 258 let binlen: i64 = ah_slen(bin) 259 let sublen: i64 = ah_slen(sub) 260 // forward ONE optional 2nd arg (e.g. `restart <service>`). The allowlisted sub bounds what it can do; the 261 // hostctl re-validates the arg (restart's fail-closed known-service allowlist), so this is not arbitrary exec. 262 var arg2: *u8 = 0 as *u8 263 var arg2len: i64 = 0 264 if argc >= 3 { arg2 = argv[2] as *u8; arg2len = ah_slen(arg2) } 265 let full: *u8 = sys_mmap(pfxlen + binlen + sublen + arg2len + 16) 266 var fo: i64 = 0 267 var ppi: i64 = 0; while ppi < pfxlen { full[fo] = pfx[ppi]; fo = fo + 1; ppi = ppi + 1 } 268 var bi: i64 = 0; while bi < binlen { full[fo] = bin[bi]; fo = fo + 1; bi = bi + 1 } 269 full[fo] = 32 as u8; fo = fo + 1 // space 270 var si: i64 = 0; while si < sublen { full[fo] = sub[si]; fo = fo + 1; si = si + 1 } 271 if arg2len > 0 { full[fo] = 32 as u8; fo = fo + 1; var ai: i64 = 0; while ai < arg2len { full[fo] = arg2[ai]; fo = fo + 1; ai = ai + 1 } } 272 273 // sudo -S reads the password from stdin: stream the vault password + newline. 274 let sin: *u8 = sys_mmap(pwlen + 4) 275 var pj: i64 = 0; while pj < pwlen { sin[pj] = pw[pj]; pj = pj + 1 } 276 sin[pwlen] = 10 as u8 277 278 ssh_puts("nx_aw_hostctl: [auth ok] sovereign ROOT control-plane call ->\n " as *u8) 279 ssh_puts(full) 280 ssh_puts("\n---- remote nx_hostctl output ----\n" as *u8) 281 // nettap runs a bounded 60s wire capture that may be SILENT the whole window -> 150*500ms = 75s 282 // of drain patience; every other verb keeps the snappy 4s disconnect. 283 var qmax: i64 = 8 284 if ah_streq(sub, "nettap" as *u8) == 1 { qmax = 150 } 285 ah_sudo_put(st, full, fo, sin, pwlen + 1, qmax) 286 rcpt_emit("nx_aw_hostctl" as *u8, sub, "nas:nishihost" as *u8, "ISSUED" as *u8, sub) // acceptance receipt -> the workstream ledger 287 sys_close(st.fd) 288 fl_release(lock_fd) // release the queue lease -> next waiting sibling op proceeds 289 return 0 290}