code wiki / _hdl_build / nx_aw_sudo.nx

nx_aw_sudo.nx source

↩ module page · 135 lines · 7236 B

1// nx_aw_sudo.nx -- run a command as ROOT on the NAS via `sudo -S`, feeding the vault-held elderwesto 2// password to sudo's stdin over the sovereign SSH channel. (sudo -l confirms: elderwesto may run 3// (ALL) ALL with a password.) The root command is read from awsudo.cmd and MUST begin "sudo -S ". 4// Spine cloned from nx_aw_push (vault unlock + ssh_put_file stream); here the STREAMED stdin is the 5// password (+newline) that sudo consumes. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_ssh_lib.nx" 8const S_MAGIC_1000000: i64 = 1000000 9const S_MAGIC_65536: i64 = 65536 10const S_MAGIC_1048576: i64 = 1048576 11const S_MAGIC_16384: i64 = 16384 12const S_MAGIC_1024: i64 = 1024 13 14const S_CMD: *u8 = "/mnt/c/Users/elder/AppData/Local/Temp/awsudo.cmd" as *u8 15const S_SECRET_OUT: *u8 = "/tmp/nxsecret.out" as *u8 16const S_VAULT_NV: *u8 = "/home/elderwesto/.nishi/secrets/nas.nv" as *u8 17 18func s_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 19 let pid: i64 = sys_fork() 20 if pid == 0 { 21 let argv: *i64 = sys_mmap(64) as *i64 22 argv[0] = path as i64 23 var ai: i64 = 1 24 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 25 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 26 argv[ai] = 0 27 let envp: *i64 = sys_mmap(16) as *i64 28 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64; envp[1] = 0 29 sys_execve(path, argv, envp) 30 sys_exit(127) 31 } 32 let st: *i64 = sys_mmap(16) as *i64 33 sys_wait4(pid, st, 0) 34 return (st[0] >> 8) & 0xff 35} 36func s_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 37func s_napms(ms: i64) -> i64 { let ts: *i64 = sys_mmap(16) as *i64; ts[0] = 0; ts[1] = ms * S_MAGIC_1000000; __syscall(35, ts as i64, 0, 0, 0, 0, 0); return 0 } 38 39func s_drain(st: *SshState) -> i64 { 40 let pfd: *u8 = sys_mmap(8); let fdv: i64 = st.fd 41 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 42 pfd[4]=1 as u8; pfd[5]=0 as u8 43 let buf: *u8 = sys_mmap(S_MAGIC_65536); var run: i64 = 1 44 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 } } } 45 return 0 46} 47// Open an exec channel for `wcmd`, stream `data` (the password+newline) as its stdin, drain to EOF. 48func s_put(st: *SshState, wcmd: *u8, wcmdlen: i64, data: *u8, datalen: i64) -> i64 { 49 let co: *u8 = sys_mmap(64); var c: i64 = 0 50 c = ssh_put_byte(co, c, 90); c = ssh_put_str(co, c, "session" as *u8, 7) 51 c = ssh_put_u32(co, c, 0); c = ssh_put_u32(co, c, S_MAGIC_1048576); c = ssh_put_u32(co, c, S_MAGIC_16384) 52 ssh_enc_send(st, co, c) 53 let rep: *u8 = sys_mmap(S_MAGIC_65536); var rcid: i64 = 0 - 1; var guard: i64 = 0 54 while rcid < 0 { 55 if guard > 16 { return 0 - 1 } 56 let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { return 0 - 1 } 57 if rep[0] == 91 as u8 { rcid = ssh_u32be(rep, 5) } 58 if rep[0] == 92 as u8 { return 0 - 2 } 59 guard = guard + 1 60 } 61 let cr: *u8 = sys_mmap(S_MAGIC_1024); var q: i64 = 0 62 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) 63 ssh_enc_send(st, cr, q) 64 var off: i64 = 0 65 while off < datalen { 66 var nn: i64 = datalen - off; if nn > S_MAGIC_16384 { nn = S_MAGIC_16384 } 67 let dp: *u8 = sys_mmap(nn + 64); var p: i64 = 0 68 p = ssh_put_byte(dp, p, 94); p = ssh_put_u32(dp, p, rcid); p = ssh_put_u32(dp, p, nn) 69 var i: i64 = 0; while i < nn { dp[p + i] = data[off + i]; i = i + 1 } p = p + nn 70 ssh_enc_send(st, dp, p) 71 s_drain(st) 72 off = off + nn 73 } 74 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) 75 let pfd2: *u8 = sys_mmap(8); let fdv2: i64 = st.fd 76 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 77 pfd2[4]=1 as u8; pfd2[5]=0 as u8 78 var done: i64 = 0; var quiet: i64 = 0 79 while done == 0 { 80 let pr: i64 = sys_poll(pfd2, 1, 500) 81 if pr <= 0 { quiet = quiet + 1; if quiet >= 8 { done = 1 } } 82 else { let rl: i64 = ssh_enc_recv(st, rep); if rl < 0 { done = 1 } else { if rep[0] == 97 as u8 { done = 1 } } } 83 } 84 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) 85 return 0 86} 87 88func main(argc: i64, argv: *i64) -> i64 { 89 // backward-compatible: no args -> fixed S_CMD (awsudo.cmd); with args, argv[1]=cmd-file so a SECOND 90 // workflow can run a root command WITHOUT sharing awsudo.cmd (defeats the staging-file race). 91 var cmd_file: *u8 = S_CMD 92 if argc >= 2 { cmd_file = argv[1] as *u8 } 93 // RESILIENT secret derivation (mirrors nx_aw_push): DSM's Warden shreds /tmp/nxpass ephemerally + WSL churns 94 // /tmp mid-op, so machine-key -> vault-open -> read-secret can transiently fail. Retry up to 12x instead of 95 // aborting -- a root/firewall op must NOT fail on a transient vault race (CLAUDE.md #14 graceful degradation). 96 let pwbox: *i64 = sys_mmap(16) as *i64 97 var pw: *u8 = 0 as *u8 98 var att: i64 = 0 99 while att < 12 { 100 if s_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) == 0 { 101 if s_run("_offc/nx_vault.elf" as *u8, "open" as *u8, S_VAULT_NV) == 0 { 102 pw = sys_read_file(S_SECRET_OUT, pwbox) 103 if (pw as i64) != 0 { att = 1000 } 104 } 105 } 106 if att < 1000 { att = att + 1; s_napms(150) } 107 } 108 s_unlink("/tmp/nxpass" as *u8) 109 if (pw as i64) == 0 { ssh_puts("sudo: secret derivation FAIL after 12 retries\n" as *u8); return 3 } 110 var pwlen: i64 = pwbox[0] 111 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 } } } 112 113 let dbox: *i64 = sys_mmap(16) as *i64 114 let dcmd: *u8 = sys_read_file(cmd_file, dbox) 115 if (dcmd as i64) == 0 { ssh_puts("sudo: no awsudo.cmd\n" as *u8); s_unlink(S_SECRET_OUT); return 6 } 116 var dlen: i64 = dbox[0] 117 while dlen > 0 { if dcmd[dlen-1] == 10 as u8 { dlen = dlen - 1 } else { break } } 118 119 let st: *SshState = sys_mmap(SSH_STATE_BYTES) as *SshState 120 if ssh_open_session(st, (192 << 24) | (168 << 16) | (8 << 8) | 227) != 0 { ssh_puts("sudo: SSH session FAIL\n" as *u8); s_unlink(S_SECRET_OUT); return 7 } 121 if ssh_userauth_password(st, "elderwesto" as *u8, 10, pw, pwlen) != 1 { ssh_puts("sudo: SSH auth FAIL\n" as *u8); sys_close(st.fd); s_unlink(S_SECRET_OUT); return 8 } 122 s_unlink(S_SECRET_OUT) 123 124 // stdin for `sudo -S <cmd>` = the password + newline. 125 let sin: *u8 = sys_mmap(pwlen + 4) 126 var i: i64 = 0; while i < pwlen { sin[i] = pw[i]; i = i + 1 } 127 sin[pwlen] = 10 as u8 128 ssh_puts("sudo: [auth ok] running root command\n" as *u8) 129 s_put(st, dcmd, dlen, sin, pwlen + 1) 130 let vcmd: *u8 = "echo ===FG-RESULT===; cat /tmp/sfg.txt 2>/dev/null; echo ===SUDO-DONE===" as *u8 131 var vl: i64 = 0; while vcmd[vl] != (0 as u8) { vl = vl + 1 } 132 ssh_exec(st, vcmd, vl) 133 sys_close(st.fd) 134 return 0 135}