code wiki / _hdl_build / nx_gen_gateway_daemon.nx
nx_gen_gateway_daemon.nx source
↩ module page · 96 lines · 5226 B
1// nx_gen_gateway_daemon.nx -- the deployable OPAQUE /gen gateway: argv config + auth-context setup
2// + accept-fork loop over gw_serve_conn (nx_gen_gateway lib). Shares the family realm
3// (nishi_site_admin) keys+store = SSO with the existing nishifamily login; reverse-proxies
4// authenticated /gen/* to the gen orchestrator backend.
5// argv: [1]=listen_port [2]=keys [3]=store [4]=budget [5]=backend_port [6]=allow_register(PROD=0)
6// [7]=m_cost [8]=t [9]=p [10]=session_ttl
7// license_tier: ORIGINAL
8import "nx_gen_gateway.nx"
9import "nx_opaque_login.nx"
10import "nx_hr_admin.nx" // hra_enroll + hra_is_superadmin + HRA_LVL_OWNER (owner bootstrap)
11import "nx_syscalls.nx"
12
13func main(argc: i64, argv: *i64) -> i64 {
14 if argc < 6 {
15 sys_write(1, "usage: nx_gen_gateway_daemon <port> <keys> <store> <budget> <backend_port> [allow_register] [m] [t] [p] [ttl]\n" as *u8, 110)
16 sys_exit(2); return 2
17 }
18 let port: i64 = gw_atoi(argv[1] as *u8)
19 let keys_path: *u8 = argv[2] as *u8
20 let store_path: *u8 = argv[3] as *u8
21 let budget: i64 = gw_atoi(argv[4] as *u8)
22 let bport: i64 = gw_atoi(argv[5] as *u8)
23 var allow_reg: i64 = 0
24 if argc > 6 { allow_reg = gw_atoi(argv[6] as *u8) }
25 var m_cost: i64 = GGW_PROD_M
26 if argc > 7 { m_cost = gw_atoi(argv[7] as *u8) }
27 var t_cost: i64 = 3
28 if argc > 8 { t_cost = gw_atoi(argv[8] as *u8) }
29 var p_cost: i64 = 4
30 if argc > 9 { p_cost = gw_atoi(argv[9] as *u8) }
31 var session_ttl: i64 = GGW_SESSION_TTL
32 if argc > 10 { session_ttl = gw_atoi(argv[10] as *u8) }
33
34 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext
35 if olg_ctx_setup_ttl(ctx, keys_path, store_path, "nishi_site_admin" as *u8, 16, "Nishi Family" as *u8, 12, session_ttl, m_cost, t_cost, p_cost) != 0 {
36 sys_write(1, "CTX-INIT-FAIL\n" as *u8, 14); sys_exit(1); return 1
37 }
38
39 // OWNER BOOTSTRAP (Rule 20 fail-fast): enroll the family owner as HR superadmin so the /gen authz
40 // (hra_is_superadmin on the hex-encoded session uid) grants the owner. Idempotent (enroll-if-absent).
41 // Without this the live nishi_hr- has NO owner record -> every session, incl. the owner's, is denied 403.
42 // This is the production analog of nx_gen_gateway_gate's hra_enroll("elderwesto", OWNER) which proved 200.
43 // Grant the owner /gen via the ENTITLEMENT store (he_ent_put). The HR superadmin seg_store does NOT round-trip
44 // on the live nishi_hr- (PROVEN by nx_gen_live_probe: in_proc_super=0 despite enroll_rc=0 + manifest present),
45 // but the entitlement store DOES (ent_put+has_access=1). The gateway authorizes via he_has_access on this exact
46 // store, so this is the path that actually grants access. Idempotent: grant only if not already present.
47 let owner_cid: *u8 = sys_mmap(96)
48 let owner_chl: i64 = hr_cred_id("nishi_site_admin" as *u8, 16, "elderwesto" as *u8, 10, owner_cid)
49 if he_has_access(0, owner_cid, owner_chl, GEN_ENT_PATH, "/gen" as *u8) != 1 {
50 he_ent_put(GEN_ENT_PATH, owner_cid, "Gen Studio" as *u8, "/gen" as *u8)
51 let m1: *u8 = "OWNER-BOOTSTRAP: granted elderwesto /gen via the entitlement store\n" as *u8
52 sys_write(1, m1, gw_slen(m1))
53 } else {
54 let m2: *u8 = "OWNER-BOOTSTRAP: elderwesto already has the /gen entitlement\n" as *u8
55 sys_write(1, m2, gw_slen(m2))
56 }
57
58 let addr: *u8 = sys_mmap(16)
59 addr[0]=2 as u8; addr[1]=0 as u8
60 addr[2]=((port>>8)&0xff) as u8; addr[3]=(port&0xff) as u8
61 addr[4]=0 as u8; addr[5]=0 as u8; addr[6]=0 as u8; addr[7]=0 as u8
62 var zi: i64=8; while zi<16 { addr[zi]=0 as u8; zi=zi+1 }
63 let lfd: i64 = sys_socket(2, 1, 0)
64 if lfd < 0 { sys_write(1, "SOCKET-FAIL\n" as *u8, 12); sys_exit(1); return 1 }
65 let optv: *u8 = sys_mmap(4); optv[0]=1 as u8
66 sys_setsockopt(lfd, 1, 2, optv, 4)
67 if sys_bind(lfd, addr, 16) < 0 { sys_write(1, "BIND-FAIL\n" as *u8, 10); sys_exit(1); return 1 }
68 if sys_listen(lfd, 16) < 0 { sys_write(1, "LISTEN-FAIL\n" as *u8, 12); sys_exit(1); return 1 }
69 // FD_CLOEXEC on the LISTENER (debt 1785529579). Binds by RAW SYSCALL, never calls
70 // nx_http_server_listen, so the helper's CLOEXEC fix cannot reach it -- rebuilding alone changes
71 // nothing. Measured live by nx_livecloexec_gate: this pid held a listener on fd=4 with the bit CLEAR.
72 // A forked+exec'd child that inherits a listening fd holds the port FOREVER; restarting the victim
73 // can never free it. 72 = SYS_FCNTL, 2 = F_SETFD, 1 = FD_CLOEXEC.
74 __syscall(72, lfd, 2, 1, 0, 0, 0)
75 sys_write(1, "GEN-GATEWAY-UP\n" as *u8, 15)
76
77 let st: *i64 = sys_mmap(16) as *i64
78 var served: i64 = 0
79 while served < budget {
80 let cfd: i64 = sys_accept(lfd)
81 if cfd >= 0 {
82 let pid: i64 = sys_fork()
83 if pid == 0 {
84 sys_close(lfd)
85 gw_serve_conn(cfd, ctx, allow_reg, bport, session_ttl, GEN_HR_PATH, GEN_ENT_PATH)
86 sys_close(cfd)
87 sys_exit(0)
88 }
89 sys_close(cfd)
90 var reaped: i64 = 1
91 while reaped > 0 { reaped = sys_wait4(0 - 1, st, 1) }
92 }
93 served = served + 1
94 }
95 sys_close(lfd); sys_exit(0); return 0
96}