@ai-ecoverse/slicc-kernel 1.178.0 → 1.178.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -9
- package/dist/driver-worker.js +4 -1
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +47 -3
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +180 -56
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +4 -1
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +8 -4
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +8 -4
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +222 -57
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +8 -4
- package/dist/process-worker.js.map +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/children.d.ts +5 -0
- package/dist/types/kernel/net/http-syscalls.d.ts +1 -1
- package/dist/types/kernel/net/remote-transport.d.ts +3 -3
- package/dist/types/kernel/net/transport.d.ts +1 -0
- package/dist/types/launcher.d.ts +3 -0
- package/dist/types/node.d.ts +1 -1
- package/dist/types/realm/sync-fs-wire.d.ts +1 -1
- package/dist/types/sudo.d.ts +12 -1
- package/dist/types/sudoers.d.ts +3 -1
- package/dist/types/transport.d.ts +2 -1
- package/package.json +3 -3
package/dist/kernel-worker.js
CHANGED
|
@@ -7452,6 +7452,9 @@ var KERNEL_SIGINFO = Object.freeze({
|
|
|
7452
7452
|
// src/body-idle.ts
|
|
7453
7453
|
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
7454
7454
|
|
|
7455
|
+
// src/kernel/net/transport.ts
|
|
7456
|
+
var FORBIDDEN_HEADER = "forbidden-header";
|
|
7457
|
+
|
|
7455
7458
|
// src/kernel/net/ws-queue.ts
|
|
7456
7459
|
var INBOUND_LIMIT = 16 * 1024 * 1024;
|
|
7457
7460
|
var MESSAGE_LIMIT = 64 * 1024 * 1024;
|
|
@@ -7586,7 +7589,7 @@ function serveTransport(peer, transport, {
|
|
|
7586
7589
|
message: e instanceof Error ? e.message : String(e),
|
|
7587
7590
|
...typeof status === "number" ? { status } : {},
|
|
7588
7591
|
...typeof code === "string" ? { code } : {},
|
|
7589
|
-
...detail === "transport" ? { detail } : {}
|
|
7592
|
+
...detail === "transport" || detail === FORBIDDEN_HEADER ? { detail } : {}
|
|
7590
7593
|
});
|
|
7591
7594
|
};
|
|
7592
7595
|
const uploads = uploadsFor(peer);
|
|
@@ -8774,7 +8777,7 @@ function satisfies(version, range2) {
|
|
|
8774
8777
|
}
|
|
8775
8778
|
|
|
8776
8779
|
// src/version.ts
|
|
8777
|
-
var KERNEL_VERSION = true ? "1.178.
|
|
8780
|
+
var KERNEL_VERSION = true ? "1.178.2" : "0.0.0-dev";
|
|
8778
8781
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8779
8782
|
function procVersion() {
|
|
8780
8783
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -10056,9 +10059,9 @@ var UnlinkedKeeper = class {
|
|
|
10056
10059
|
if (kept.whole) return kept.undoing(async () => void 0);
|
|
10057
10060
|
await kept.undoing(
|
|
10058
10061
|
() => replace(target, async (gated, sealed) => {
|
|
10059
|
-
const
|
|
10060
|
-
if (
|
|
10061
|
-
else await keeper.settle(
|
|
10062
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
10063
|
+
if (pinned2.moved.has(target)) pinned2.commit();
|
|
10064
|
+
else await keeper.settle(pinned2, () => fs.rm(path, options));
|
|
10062
10065
|
})
|
|
10063
10066
|
);
|
|
10064
10067
|
},
|
|
@@ -10071,8 +10074,8 @@ var UnlinkedKeeper = class {
|
|
|
10071
10074
|
() => keeper.marks.around(
|
|
10072
10075
|
[source],
|
|
10073
10076
|
() => replace(target, async (gated, sealed) => {
|
|
10074
|
-
const
|
|
10075
|
-
await keeper.settle(
|
|
10077
|
+
const pinned2 = await keeper.pin(target, gated, sealed);
|
|
10078
|
+
await keeper.settle(pinned2, () => fs.rename(from, to));
|
|
10076
10079
|
})
|
|
10077
10080
|
)
|
|
10078
10081
|
);
|
|
@@ -10107,14 +10110,14 @@ var UnlinkedKeeper = class {
|
|
|
10107
10110
|
}
|
|
10108
10111
|
return false;
|
|
10109
10112
|
}
|
|
10110
|
-
async settle(
|
|
10113
|
+
async settle(pinned2, op) {
|
|
10111
10114
|
try {
|
|
10112
10115
|
await op();
|
|
10113
10116
|
} catch (err) {
|
|
10114
|
-
await
|
|
10117
|
+
await pinned2.rollback();
|
|
10115
10118
|
throw err;
|
|
10116
10119
|
}
|
|
10117
|
-
|
|
10120
|
+
pinned2.commit();
|
|
10118
10121
|
}
|
|
10119
10122
|
heldWithin(target) {
|
|
10120
10123
|
const held = /* @__PURE__ */ new Map();
|
|
@@ -12638,6 +12641,13 @@ var SpawnError = class extends Error {
|
|
|
12638
12641
|
this.code = code;
|
|
12639
12642
|
}
|
|
12640
12643
|
};
|
|
12644
|
+
var ChangedError = class extends SpawnError {
|
|
12645
|
+
notice;
|
|
12646
|
+
constructor(notice) {
|
|
12647
|
+
super("EPERM");
|
|
12648
|
+
this.notice = notice;
|
|
12649
|
+
}
|
|
12650
|
+
};
|
|
12641
12651
|
function interrupted(signal) {
|
|
12642
12652
|
const { promise, reject } = Promise.withResolvers();
|
|
12643
12653
|
const fail2 = () => reject(new KernelError("EINTR"));
|
|
@@ -19617,8 +19627,10 @@ var SUDOERS_D = "/etc/sudoers.d";
|
|
|
19617
19627
|
var NAME4 = /^[a-z_][a-z0-9_.-]*$/;
|
|
19618
19628
|
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
19619
19629
|
var KERNEL_FORM = new RegExp(
|
|
19620
|
-
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?Cmnd(?:\s+(.*))?$`
|
|
19630
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()]*)\)\s+)?(?:Cwd\s+(${WORD})\s+)?(?:Stdin\s+(\S+)\s+)?((?:Sha256\s+${WORD}\s+)*)Cmnd(?:\s+(.*))?$`
|
|
19621
19631
|
);
|
|
19632
|
+
var SHA256_CLAUSE = new RegExp(String.raw`Sha256\s+(${WORD})`, "g");
|
|
19633
|
+
var HEX = /^[0-9a-f]{64}$/;
|
|
19622
19634
|
var SUDOERS_FORM = /^(\S+)\s+([^\s=]+)\s*=\s*(.*)$/;
|
|
19623
19635
|
var RUNAS = /^\(([^()]*)\)\s*/;
|
|
19624
19636
|
var TAG = /^([A-Z_]+)\s*:\s*/;
|
|
@@ -19627,7 +19639,7 @@ var PLAIN2 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
|
19627
19639
|
var CONTROL2 = /[\p{Cc}\u2028\u2029]/u;
|
|
19628
19640
|
var CONTROLS = /[\p{Cc}\u2028\u2029]/gu;
|
|
19629
19641
|
var SHOWN_MAX = 60;
|
|
19630
|
-
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
19642
|
+
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] [Sha256 <file>=<sha256>\u2026] Cmnd <command\u2026|*>";
|
|
19631
19643
|
var SUDOERS_SYNTAX = "<user|%group|ALL> ALL=[(<target>[,<target>\u2026])] [NOPASSWD:] <command\u2026|ALL>";
|
|
19632
19644
|
var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
19633
19645
|
var TIMESTAMP_TIMEOUT = 5;
|
|
@@ -19794,6 +19806,23 @@ function commandOf2(text, after) {
|
|
|
19794
19806
|
if (only && /\s""$/.test(text)) return { path, args: [] };
|
|
19795
19807
|
return args.length === 0 ? { path } : { path, args };
|
|
19796
19808
|
}
|
|
19809
|
+
function sha256Of(clauses) {
|
|
19810
|
+
const files = {};
|
|
19811
|
+
for (const [, word = ""] of clauses.matchAll(SHA256_CLAUSE)) {
|
|
19812
|
+
const [text = ""] = splitWords(word) ?? [];
|
|
19813
|
+
const at = text.lastIndexOf("=");
|
|
19814
|
+
const path = text.slice(0, at);
|
|
19815
|
+
const hex4 = text.slice(at + 1).toLowerCase();
|
|
19816
|
+
if (!path.startsWith("/") || !HEX.test(hex4)) {
|
|
19817
|
+
return `Sha256 expects <absolute file>=<sha256 in hex>, not ${shown(word)}`;
|
|
19818
|
+
}
|
|
19819
|
+
files[normalizePath(path)] = hex4;
|
|
19820
|
+
}
|
|
19821
|
+
return files;
|
|
19822
|
+
}
|
|
19823
|
+
function sha256Text(files) {
|
|
19824
|
+
return Object.entries(files).map(([path, hex4]) => `Sha256 ${quoteWord(`${path}=${hex4}`)} `).join("");
|
|
19825
|
+
}
|
|
19797
19826
|
function targetError(list) {
|
|
19798
19827
|
if (list.includes(",")) {
|
|
19799
19828
|
return `(${list}) names one user in this form: write one line per user, or use '${SUDOERS_SYNTAX}'`;
|
|
@@ -19801,19 +19830,22 @@ function targetError(list) {
|
|
|
19801
19830
|
return `expected one user name or ALL in (\u2026), not ${shown(`(${list})`)}`;
|
|
19802
19831
|
}
|
|
19803
19832
|
function kernelRules(m) {
|
|
19804
|
-
const [, nopasswd, who = "", target = "root", dir, stdin, rest2 = ""] = m;
|
|
19833
|
+
const [, nopasswd, who = "", target = "root", dir, stdin, sums = "", rest2 = ""] = m;
|
|
19805
19834
|
const bad = whoError(who);
|
|
19806
19835
|
if (bad !== void 0) return bad;
|
|
19807
19836
|
if (target !== "ALL" && !NAME4.test(target)) return targetError(target);
|
|
19808
19837
|
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
19809
19838
|
if (cwd === "") return `Cwd expects one absolute directory, not ${shown(dir)}`;
|
|
19810
19839
|
if (stdin !== void 0 && stdin !== "none") return `Stdin takes none, not ${shown(stdin)}`;
|
|
19840
|
+
const sha2564 = sha256Of(sums);
|
|
19841
|
+
if (typeof sha2564 === "string") return sha2564;
|
|
19811
19842
|
const rule = {
|
|
19812
19843
|
nopasswd: !!nopasswd,
|
|
19813
19844
|
who,
|
|
19814
19845
|
target,
|
|
19815
19846
|
...cwd !== void 0 ? { cwd } : {},
|
|
19816
|
-
...stdin === "none" ? { stdin: "none" } : {}
|
|
19847
|
+
...stdin === "none" ? { stdin: "none" } : {},
|
|
19848
|
+
...sums === "" ? {} : { sha256: sha2564 }
|
|
19817
19849
|
};
|
|
19818
19850
|
const text = rest2.trim();
|
|
19819
19851
|
if (text === "*") return [{ ...rule, cmnd: "*" }];
|
|
@@ -20066,12 +20098,26 @@ var RAN_ONCE = "sudo: ran once; this command line can't be recorded as always";
|
|
|
20066
20098
|
var ROOT_ONLY_MAX = 64;
|
|
20067
20099
|
var OPERANDS_MAX = 256;
|
|
20068
20100
|
var PATH_MAX = 4096;
|
|
20101
|
+
function userWritable(bound3) {
|
|
20102
|
+
const files = Object.entries(bound3).map(([path, hex4]) => ({ path, sha256: hex4 }));
|
|
20103
|
+
return files.length > 0 ? { userWritable: files } : {};
|
|
20104
|
+
}
|
|
20069
20105
|
function stdinMatches(rule, stdin) {
|
|
20070
20106
|
return rule.stdin === void 0 || stdin === "tty" || stdin === "none";
|
|
20071
20107
|
}
|
|
20072
20108
|
function recordable(cwd, argv) {
|
|
20073
20109
|
return !hasControl(cwd) && !argv.some(hasControl);
|
|
20074
20110
|
}
|
|
20111
|
+
function changedText(file) {
|
|
20112
|
+
return `sudo: ${file} changed since it was approved`;
|
|
20113
|
+
}
|
|
20114
|
+
function changedFile(approved, now) {
|
|
20115
|
+
const files = /* @__PURE__ */ new Set([...Object.keys(approved), ...Object.keys(now)]);
|
|
20116
|
+
return [...files].find((file) => approved[file] !== now[file]);
|
|
20117
|
+
}
|
|
20118
|
+
function pinned(rule, bound3) {
|
|
20119
|
+
return rule.sha256 === void 0 || changedFile(rule.sha256, bound3) === void 0;
|
|
20120
|
+
}
|
|
20075
20121
|
var VISUDO_FILES_MAX = 64;
|
|
20076
20122
|
var VISUDO_TEXT_MAX = 1024 * 1024;
|
|
20077
20123
|
function visudoCall(req) {
|
|
@@ -20202,11 +20248,13 @@ function usable(parsed2) {
|
|
|
20202
20248
|
function policyOf(settings) {
|
|
20203
20249
|
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
20204
20250
|
}
|
|
20205
|
-
function described(rule) {
|
|
20251
|
+
function described(rule, writable2) {
|
|
20206
20252
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
20207
20253
|
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
20208
20254
|
const stdin = rule.stdin === void 0 ? "" : "STDIN=none ";
|
|
20209
|
-
|
|
20255
|
+
const sums = Object.entries(rule.sha256 ?? {}).map(([path, hex4]) => `SHA256=${quoteWord(path)}:${hex4} `).join("");
|
|
20256
|
+
const flag = writable2 ? " # user-writable command" : "";
|
|
20257
|
+
return ` (${rule.target}) ${cwd}${stdin}${sums}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}${flag}`;
|
|
20210
20258
|
}
|
|
20211
20259
|
var Sudo = class {
|
|
20212
20260
|
o;
|
|
@@ -20397,15 +20445,31 @@ var Sudo = class {
|
|
|
20397
20445
|
if (walked.denied !== void 0 || walked.missing) return false;
|
|
20398
20446
|
return (await this.o.fs.stat(cwd).catch(() => void 0))?.isDirectory === true;
|
|
20399
20447
|
}
|
|
20400
|
-
async
|
|
20401
|
-
const
|
|
20402
|
-
|
|
20403
|
-
|
|
20404
|
-
|
|
20405
|
-
|
|
20406
|
-
|
|
20448
|
+
async real(file) {
|
|
20449
|
+
const { fs } = this.o;
|
|
20450
|
+
return await fs.realpath?.(file, true).catch(() => file) ?? file;
|
|
20451
|
+
}
|
|
20452
|
+
async digests(files) {
|
|
20453
|
+
const { fs } = this.o;
|
|
20454
|
+
const found = {};
|
|
20455
|
+
for (const file of new Set(files)) {
|
|
20456
|
+
if (await this.trusted(file)) continue;
|
|
20457
|
+
const real = await this.real(file);
|
|
20458
|
+
found[real] = await fs.readFileBuffer(real).then(sha256, () => "");
|
|
20407
20459
|
}
|
|
20408
|
-
return
|
|
20460
|
+
return found;
|
|
20461
|
+
}
|
|
20462
|
+
async bound(path, cwd) {
|
|
20463
|
+
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
20464
|
+
const bound3 = files && await this.digests([path, ...files]);
|
|
20465
|
+
return bound3 && !Object.values(bound3).includes("") ? bound3 : void 0;
|
|
20466
|
+
}
|
|
20467
|
+
async writable(rule) {
|
|
20468
|
+
if (rule.cmnd === "*") return false;
|
|
20469
|
+
const { path } = rule.cmnd;
|
|
20470
|
+
const bound3 = await this.bound(path, "/");
|
|
20471
|
+
if (bound3) return Object.keys(bound3).length > 0;
|
|
20472
|
+
return !await this.trusted(await this.existing(path));
|
|
20409
20473
|
}
|
|
20410
20474
|
async locate(word, cwd) {
|
|
20411
20475
|
const { fs } = this.o;
|
|
@@ -20450,7 +20514,7 @@ var Sudo = class {
|
|
|
20450
20514
|
const root = cred.euid === 0;
|
|
20451
20515
|
const rules = root ? [] : policy.rules;
|
|
20452
20516
|
const mine = rules.filter((rule) => applies(rule.who));
|
|
20453
|
-
if (parsed2.list) return this.listed(self, root, mine, settings.matching);
|
|
20517
|
+
if (parsed2.list) return await this.listed(self, root, mine, settings.matching);
|
|
20454
20518
|
const session = { caller, self, target, owner, policy: policyOf(settings), parsed: parsed2, signal };
|
|
20455
20519
|
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
20456
20520
|
return this.command(session, root, mine, call);
|
|
@@ -20467,14 +20531,13 @@ var Sudo = class {
|
|
|
20467
20531
|
);
|
|
20468
20532
|
}
|
|
20469
20533
|
const path = await this.locate(word, cwd);
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
if (untrusted2) return untrusted2;
|
|
20534
|
+
const bound3 = path && await this.bound(path, cwd);
|
|
20535
|
+
if (!path || !bound3) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
20473
20536
|
const argv = [path, ...args];
|
|
20474
20537
|
const matching = mine.filter(
|
|
20475
|
-
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
20538
|
+
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv) && pinned(rule, bound3)
|
|
20476
20539
|
);
|
|
20477
|
-
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
20540
|
+
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term, bound3);
|
|
20478
20541
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
20479
20542
|
const quoted = argv.map(quoteWord).join(" ");
|
|
20480
20543
|
if (matching.length === 0) {
|
|
@@ -20490,14 +20553,15 @@ var Sudo = class {
|
|
|
20490
20553
|
}
|
|
20491
20554
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
20492
20555
|
return this.pendingFor(cred.ruid, async () => {
|
|
20493
|
-
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd });
|
|
20556
|
+
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd, bound: bound3 });
|
|
20494
20557
|
if ("error" in answer2) return answer2;
|
|
20495
20558
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
20496
20559
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
20497
20560
|
}
|
|
20498
|
-
const
|
|
20499
|
-
if (
|
|
20500
|
-
const
|
|
20561
|
+
const now = await this.bound(path, cwd);
|
|
20562
|
+
if (!now) return failed2("ENOENT", `sudo: ${word}: command not found`);
|
|
20563
|
+
const shown2 = recordable(cwd, [...parsed2.command, ...Object.keys(bound3)]);
|
|
20564
|
+
const result = answer2.answer === "once" ? grant() : await this.always(self, target, { cwd, argv, bound: bound3 }, now, shown2, grant);
|
|
20501
20565
|
if (!("error" in result)) this.stamped(s, answer2);
|
|
20502
20566
|
return result;
|
|
20503
20567
|
});
|
|
@@ -20516,7 +20580,7 @@ var Sudo = class {
|
|
|
20516
20580
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
20517
20581
|
const cwd = await this.canonical(dir) ?? normalizePath(dir);
|
|
20518
20582
|
return this.pendingFor(s.caller.cred.ruid, async () => {
|
|
20519
|
-
const answer2 = await this.ask(s, { argv: [], path: "", cwd, validate: true });
|
|
20583
|
+
const answer2 = await this.ask(s, { argv: [], path: "", cwd, bound: {}, validate: true });
|
|
20520
20584
|
if ("error" in answer2) return answer2;
|
|
20521
20585
|
if (!answer2.person) await s.caller.report?.(NOT_STAMPED);
|
|
20522
20586
|
this.stamped(s, answer2);
|
|
@@ -20544,14 +20608,17 @@ var Sudo = class {
|
|
|
20544
20608
|
`sudo: ${self.name} : TTY=${tty} ; PWD=${quoteWord(cwd)} ; USER=${target.name} ; TIMESTAMP=${type} ; COMMAND=${command}`
|
|
20545
20609
|
);
|
|
20546
20610
|
}
|
|
20547
|
-
async always(self, target,
|
|
20611
|
+
async always(self, target, line, now, shown2, grant) {
|
|
20612
|
+
const { cwd, argv, bound: bound3 } = line;
|
|
20548
20613
|
if (!shown2 || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
20549
|
-
|
|
20614
|
+
const changed = changedFile(bound3, now);
|
|
20615
|
+
if (changed !== void 0) return failed2("EPERM", changedText(changed));
|
|
20616
|
+
if (!await this.remember(self, target, line)) {
|
|
20550
20617
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
20551
20618
|
}
|
|
20552
20619
|
return grant();
|
|
20553
20620
|
}
|
|
20554
|
-
listed(self, root, rules, defaults2) {
|
|
20621
|
+
async listed(self, root, rules, defaults2) {
|
|
20555
20622
|
const host = this.o.hostname;
|
|
20556
20623
|
if (root) {
|
|
20557
20624
|
return {
|
|
@@ -20563,7 +20630,9 @@ var Sudo = class {
|
|
|
20563
20630
|
if (rules.length === 0) {
|
|
20564
20631
|
return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
20565
20632
|
}
|
|
20566
|
-
const
|
|
20633
|
+
const shown2 = [];
|
|
20634
|
+
for (const rule of rules) shown2.push(described(rule, await this.writable(rule)));
|
|
20635
|
+
const lines2 = shown2.join("\n");
|
|
20567
20636
|
const params = defaults2.flatMap((d) => d.params).join(", ");
|
|
20568
20637
|
const matching = params === "" ? "" : `Matching Defaults entries for ${self.name} on ${host}:
|
|
20569
20638
|
${params}
|
|
@@ -20596,9 +20665,10 @@ ${lines2}
|
|
|
20596
20665
|
...caller.tty ? { tty: caller.tty } : {},
|
|
20597
20666
|
createdAt,
|
|
20598
20667
|
expiresAt: createdAt + timeout,
|
|
20599
|
-
always: asked.validate ? false : recordable(cwd, [path, ...argv]),
|
|
20668
|
+
always: asked.validate ? false : recordable(cwd, [path, ...argv, ...Object.keys(asked.bound)]),
|
|
20600
20669
|
stdin: caller.stdin,
|
|
20601
20670
|
rootOnly: asked.validate ? {} : await this.rootOnly(cwd, argv.slice(1)),
|
|
20671
|
+
...userWritable(asked.bound),
|
|
20602
20672
|
...asked.validate ? { validate: true } : {},
|
|
20603
20673
|
timestamp: true
|
|
20604
20674
|
};
|
|
@@ -20618,7 +20688,7 @@ ${lines2}
|
|
|
20618
20688
|
requester.removeEventListener("abort", withdraw);
|
|
20619
20689
|
}
|
|
20620
20690
|
}
|
|
20621
|
-
async remember(self, target, cwd, argv) {
|
|
20691
|
+
async remember(self, target, { cwd, argv, bound: bound3 }) {
|
|
20622
20692
|
const { fs } = this.o;
|
|
20623
20693
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
20624
20694
|
if (!NAME4.test(self.name)) return false;
|
|
@@ -20629,7 +20699,7 @@ ${lines2}
|
|
|
20629
20699
|
if (st && !await this.trusted(path)) return false;
|
|
20630
20700
|
const old = st ? await fs.readFile(path) : "";
|
|
20631
20701
|
const words2 = recordedCommand(argv);
|
|
20632
|
-
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none Cmnd ${words2}
|
|
20702
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Stdin none ${sha256Text(bound3)}Cmnd ${words2}
|
|
20633
20703
|
`;
|
|
20634
20704
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
20635
20705
|
${line}`;
|
|
@@ -20640,7 +20710,7 @@ ${line}`;
|
|
|
20640
20710
|
return false;
|
|
20641
20711
|
}
|
|
20642
20712
|
}
|
|
20643
|
-
grant(self, target, cred, argv, file, cwd, term) {
|
|
20713
|
+
grant(self, target, cred, argv, file, cwd, term, files) {
|
|
20644
20714
|
const env = {
|
|
20645
20715
|
...this.o.env(),
|
|
20646
20716
|
...userEnv(target, this.o.pnpmHome),
|
|
@@ -20653,7 +20723,9 @@ ${line}`;
|
|
|
20653
20723
|
SUDO_GID: String(cred.rgid),
|
|
20654
20724
|
SUDO_COMMAND: [file, ...argv.slice(1)].join(" ")
|
|
20655
20725
|
};
|
|
20656
|
-
return {
|
|
20726
|
+
return {
|
|
20727
|
+
grant: { file, argv: [...argv], env, cwd, cred: credOf(target), caller: cred, files }
|
|
20728
|
+
};
|
|
20657
20729
|
}
|
|
20658
20730
|
};
|
|
20659
20731
|
|
|
@@ -22690,6 +22762,9 @@ var HttpHandles = class {
|
|
|
22690
22762
|
if (e instanceof PlaceholderRefused) {
|
|
22691
22763
|
return { ok: false, errno: e.code, message: text, detail: "placeholder" };
|
|
22692
22764
|
}
|
|
22765
|
+
if (e.detail === FORBIDDEN_HEADER) {
|
|
22766
|
+
return { ok: false, errno: "ENOTSUP", message: text, detail: FORBIDDEN_HEADER };
|
|
22767
|
+
}
|
|
22693
22768
|
const status = e.status;
|
|
22694
22769
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
22695
22770
|
const code = codeOf2(e);
|
|
@@ -28977,14 +29052,20 @@ var WasmProcess = class {
|
|
|
28977
29052
|
if (!("grant" in answer2)) return answer2;
|
|
28978
29053
|
if (this.dying) throw new KernelError("EINTR");
|
|
28979
29054
|
if (answer2.notice !== void 0) await this.complainLine(answer2.notice);
|
|
28980
|
-
const { file, argv, env, cwd, cred, caller } = answer2.grant;
|
|
29055
|
+
const { file, argv, env, cwd, cred, caller, files } = answer2.grant;
|
|
28981
29056
|
const stdio = [{ fd: 0 }, { fd: 1 }, { fd: 2 }];
|
|
28982
|
-
|
|
28983
|
-
|
|
28984
|
-
|
|
28985
|
-
|
|
28986
|
-
|
|
28987
|
-
|
|
29057
|
+
try {
|
|
29058
|
+
return {
|
|
29059
|
+
pid: await this.children.spawn({ file, argv, env, cwd, pgid: 0 }, stdio, [], {
|
|
29060
|
+
cred,
|
|
29061
|
+
caller,
|
|
29062
|
+
files
|
|
29063
|
+
})
|
|
29064
|
+
};
|
|
29065
|
+
} catch (err) {
|
|
29066
|
+
if (err instanceof ChangedError) return { error: err.notice, errno: err.code };
|
|
29067
|
+
throw err;
|
|
29068
|
+
}
|
|
28988
29069
|
}
|
|
28989
29070
|
stdinKind() {
|
|
28990
29071
|
if (!this.fds.has(0)) return "none";
|
|
@@ -30840,7 +30921,7 @@ var TransportError = class extends Error {
|
|
|
30840
30921
|
super(message3);
|
|
30841
30922
|
this.status = status;
|
|
30842
30923
|
this.code = code;
|
|
30843
|
-
this.detail = detail === "transport" ? detail : void 0;
|
|
30924
|
+
this.detail = detail === "transport" || detail === FORBIDDEN_HEADER ? detail : void 0;
|
|
30844
30925
|
}
|
|
30845
30926
|
};
|
|
30846
30927
|
function unfollowed2(redirect) {
|
|
@@ -33563,6 +33644,10 @@ function describe(req, tty) {
|
|
|
33563
33644
|
};
|
|
33564
33645
|
return { argv: [req.argv0, ...req.args], tty, started: Date.now(), ...exe };
|
|
33565
33646
|
}
|
|
33647
|
+
function refuseChanged(approved, now) {
|
|
33648
|
+
const changed = changedFile(approved, now);
|
|
33649
|
+
if (changed !== void 0) throw new ChangedError(changedText(changed));
|
|
33650
|
+
}
|
|
33566
33651
|
function linksOf2(req) {
|
|
33567
33652
|
return req.links === void 0 ? {} : { links: req.links };
|
|
33568
33653
|
}
|
|
@@ -34696,6 +34781,27 @@ var Launcher = class {
|
|
|
34696
34781
|
}
|
|
34697
34782
|
return true;
|
|
34698
34783
|
}
|
|
34784
|
+
async unchanged(planned, file, cwd, grant) {
|
|
34785
|
+
const approved = grant?.files;
|
|
34786
|
+
if (!approved) return {};
|
|
34787
|
+
const files = await this.backingOf(planned, file, cwd, "");
|
|
34788
|
+
refuseChanged(approved, await this.sudoer.digests([file, ...files]));
|
|
34789
|
+
return { pinned: approved };
|
|
34790
|
+
}
|
|
34791
|
+
async pinOf(path, caller) {
|
|
34792
|
+
const { pinned: pinned2 } = caller;
|
|
34793
|
+
if (!pinned2) return {};
|
|
34794
|
+
const real = await this.sudoer.real(path);
|
|
34795
|
+
const hex4 = pinned2[real];
|
|
34796
|
+
if (hex4 !== void 0) return { [real]: hex4 };
|
|
34797
|
+
if (await this.sudoer.trusted(real)) return {};
|
|
34798
|
+
throw new ChangedError(changedText(real));
|
|
34799
|
+
}
|
|
34800
|
+
async pinnedBytes(pin, bytes) {
|
|
34801
|
+
const [real = ""] = Object.keys(pin);
|
|
34802
|
+
refuseChanged(pin, { [real]: await sha256(bytes) });
|
|
34803
|
+
return bytes;
|
|
34804
|
+
}
|
|
34699
34805
|
async grantedCwd(caller, cwd) {
|
|
34700
34806
|
const real = await physicalPathAsync(this.base, cwd).catch(() => void 0);
|
|
34701
34807
|
return real === cwd && await this.sudoer.reachable(caller, cwd);
|
|
@@ -34784,13 +34890,19 @@ var Launcher = class {
|
|
|
34784
34890
|
return found;
|
|
34785
34891
|
}
|
|
34786
34892
|
async module(path, caller, asked) {
|
|
34787
|
-
const
|
|
34893
|
+
const pin = await this.pinOf(path, caller);
|
|
34894
|
+
const sum = Object.values(pin)[0];
|
|
34895
|
+
const key = sum === void 0 ? await this.cacheKey(path, asked) : `${path}:sha256:${sum}`;
|
|
34788
34896
|
return this.cached(this.compiled, key, async () => {
|
|
34789
|
-
const { bytes, key:
|
|
34897
|
+
const { bytes: read, key: readKey } = await this.keyed(path, caller, asked);
|
|
34898
|
+
const bytes = sum === void 0 ? read : await this.pinnedBytes(pin, read);
|
|
34790
34899
|
const memory = importedMemory(bytes);
|
|
34791
34900
|
const foreign = foreignImports(bytes);
|
|
34792
34901
|
const compiled = await WebAssembly.compile(bytes);
|
|
34793
|
-
return {
|
|
34902
|
+
return {
|
|
34903
|
+
value: { module: compiled, ...memory ? { memory } : {}, foreign },
|
|
34904
|
+
key: sum === void 0 ? readKey : key
|
|
34905
|
+
};
|
|
34794
34906
|
});
|
|
34795
34907
|
}
|
|
34796
34908
|
async checkedSources(planned, caller) {
|
|
@@ -34815,6 +34927,11 @@ var Launcher = class {
|
|
|
34815
34927
|
}
|
|
34816
34928
|
}
|
|
34817
34929
|
async text(path, caller, asked) {
|
|
34930
|
+
const pin = await this.pinOf(path, caller);
|
|
34931
|
+
if (Object.keys(pin).length > 0) {
|
|
34932
|
+
const { bytes } = await this.keyed(path, caller, asked);
|
|
34933
|
+
return new TextDecoder().decode(await this.pinnedBytes(pin, bytes));
|
|
34934
|
+
}
|
|
34818
34935
|
if (!this.integrity) return this.base.readFile(path);
|
|
34819
34936
|
const key = await this.cacheKey(path, asked);
|
|
34820
34937
|
return this.cached(this.texts, key, async () => {
|
|
@@ -35003,7 +35120,12 @@ var Launcher = class {
|
|
|
35003
35120
|
const own = env.HOSTNAME;
|
|
35004
35121
|
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
35005
35122
|
const planned = chosen2(asked, env);
|
|
35006
|
-
const caller = {
|
|
35123
|
+
const caller = {
|
|
35124
|
+
pid: req.ppid ?? 0,
|
|
35125
|
+
uid: req.cred.euid,
|
|
35126
|
+
tag: req.tags?.[0],
|
|
35127
|
+
pinned: req.pinned
|
|
35128
|
+
};
|
|
35007
35129
|
if (this.integrity) await this.checkedSources(planned, caller);
|
|
35008
35130
|
const [program, exeId] = await this.loaded(planned.target, env, caller);
|
|
35009
35131
|
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
@@ -35518,6 +35640,7 @@ var Launcher = class {
|
|
|
35518
35640
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
35519
35641
|
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
35520
35642
|
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
35643
|
+
const pin = await this.unchanged(planned, file, req.cwd, grant);
|
|
35521
35644
|
const { recheck, ...redeemed } = await this.redeemed(
|
|
35522
35645
|
{ ...req, file },
|
|
35523
35646
|
{ ppid, cred, scope, booked },
|
|
@@ -35529,6 +35652,7 @@ var Launcher = class {
|
|
|
35529
35652
|
const replan = () => this.planOrSearch({ ...req, file }, { ppid, cred, scope });
|
|
35530
35653
|
const again = { ...planned, replan, recheck };
|
|
35531
35654
|
const handle = await this.launch(again, {
|
|
35655
|
+
...pin,
|
|
35532
35656
|
...deciding ? { decided: deciding.promise } : {},
|
|
35533
35657
|
cwd: req.cwd,
|
|
35534
35658
|
cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
|