code wiki / _hdl_build / nx_aw_nasfix.nx

nx_aw_nasfix.nx source

↩ module page · 86 lines · 4614 B

1// nx_aw_nasfix.nx -- SOVEREIGN NAS diagnose+restore for the live sites daemon (andelinwest.com + 2// nishifamily.com). No shells, no /tmp pre-staging: gets the NAS password straight from the sovereign 3// vault (composes _offc/nx_machine_key.elf + _offc/nx_vault.elf, exactly as nx_secret_cli does), then 4// SSHes to the NAS via the team's own nx_ssh_lib and runs the command read from a file (so diagnose vs 5// restart is driven without rebuilding). ssh_exec streams remote stdout/stderr to fd 1. READ-ONLY unless 6// the command file says otherwise. license_tier: ORIGINAL (spine reused from nx_aw_nasrecon) 7import "nx_syscalls.nx" 8import "nx_ssh_lib.nx" 9 10const NF_CMD_PATH: *u8 = "/mnt/c/Users/elder/AppData/Local/Temp/nascmd.txt" as *u8 11const NF_SECRET_OUT: *u8 = "/tmp/nxsecret.out" as *u8 12const NF_VAULT_NV: *u8 = "/home/elderwesto/.nishi/secrets/nas.nv" as *u8 13 14func nf_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 15 16// fork+execve a sovereign helper binary; parent waits; returns child WEXITSTATUS (mirrors nx_secret_cli). 17func nf_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 18 let pid: i64 = sys_fork() 19 if pid == 0 { 20 let argv: *i64 = sys_mmap(64) as *i64 21 argv[0] = path as i64 22 var ai: i64 = 1 23 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 24 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 25 argv[ai] = 0 26 let envp: *i64 = sys_mmap(16) as *i64 27 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 28 sys_execve(path, argv, envp) 29 sys_exit(127) 30 } 31 let st: *i64 = sys_mmap(16) as *i64 32 sys_wait4(pid, st, 0) 33 return (st[0] >> 8) & 0xff 34} 35func nf_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 36 37func main() -> i64 { 38 // ---- sovereign credential retrieval (no shell, no typed passphrase) ---- 39 if nf_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) != 0 { 40 ssh_puts("nasfix: machine-key derive FAILED\n" as *u8); nf_unlink("/tmp/nxpass" as *u8); return 1 41 } 42 if nf_run("_offc/nx_vault.elf" as *u8, "open" as *u8, NF_VAULT_NV) != 0 { 43 ssh_puts("nasfix: vault open nas.nv FAILED (no secret / wrong machine / tampered)\n" as *u8) 44 nf_unlink("/tmp/nxpass" as *u8); return 2 45 } 46 nf_unlink("/tmp/nxpass" as *u8) // shred the passphrase ephemeral immediately 47 let pwbox: *i64 = sys_mmap(16) as *i64 48 let pw: *u8 = sys_read_file(NF_SECRET_OUT, pwbox) 49 if (pw as i64) == 0 { ssh_puts("nasfix: cannot read decrypted secret\n" as *u8); return 3 } 50 var pwlen: i64 = pwbox[0] 51 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 } } } 52 53 // ---- the command to run on the NAS (file-driven: diagnose vs restart, no rebuild) ---- 54 let cbox: *i64 = sys_mmap(16) as *i64 55 let cmd: *u8 = sys_read_file(NF_CMD_PATH, cbox) 56 if (cmd as i64) == 0 { ssh_puts("nasfix: no command file\n" as *u8); nf_unlink(NF_SECRET_OUT); return 4 } 57 var clen: i64 = cbox[0] 58 while clen > 0 { if cmd[clen-1] == 10 as u8 { clen = clen - 1 } else { break } } 59 60 // ---- sovereign SSH to the NAS (192.168.8.227) ---- 61 let st: *SshState = sys_mmap(SSH_STATE_BYTES) as *SshState 62 if ssh_open_session(st, (192 << 24) | (168 << 16) | (8 << 8) | 227) != 0 { 63 ssh_puts("nasfix: SSH session FAILED (NAS unreachable on :22)\n" as *u8); nf_unlink(NF_SECRET_OUT); return 5 64 } 65 if ssh_userauth_password(st, "elderwesto" as *u8, 10, pw, pwlen) != 1 { 66 ssh_puts("nasfix: SSH auth FAILED\n" as *u8); sys_close(st.fd); nf_unlink(NF_SECRET_OUT); return 6 67 } 68 ssh_puts("nasfix: [auth ok] running remote command:\n" as *u8) 69 // Make the vault password available to the remote script as $NXPW (in-memory only; never staged 70 // on disk) so a root step can do: echo "$NXPW" | sudo -S -p '' sh -c '...'. Prepend an export. 71 let full: *u8 = sys_mmap(clen + pwlen + 64) 72 var fo: i64 = 0 73 let pfx: *u8 = "export NXPW='" as *u8 74 var pi: i64 = 0 75 while pfx[pi] != (0 as u8) { full[fo] = pfx[pi]; fo = fo + 1; pi = pi + 1 } 76 var qi: i64 = 0 77 while qi < pwlen { full[fo] = pw[qi]; fo = fo + 1; qi = qi + 1 } 78 full[fo] = 39 as u8; fo = fo + 1 // closing single quote 79 full[fo] = 10 as u8; fo = fo + 1 // newline 80 var ci: i64 = 0 81 while ci < clen { full[fo] = cmd[ci]; fo = fo + 1; ci = ci + 1 } 82 nf_unlink(NF_SECRET_OUT) // shred the decrypted secret file (the pw stays only in this process) 83 ssh_exec(st, full, fo) 84 sys_close(st.fd) 85 return 0 86}