@ai-ecoverse/slicc-kernel 1.176.1 → 1.177.0
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 +29 -8
- package/dist/index.js +8 -1
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +371 -59
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +1 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +372 -59
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/types.d.ts +1 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/launcher.d.ts +5 -0
- package/dist/types/node.d.ts +6 -1
- package/dist/types/process/js/js-context.d.ts +2 -0
- package/dist/types/sudo-timestamp.d.ts +28 -0
- package/dist/types/sudo.d.ts +20 -1
- package/dist/types/sudoers.d.ts +25 -2
- package/package.json +3 -3
package/dist/node.js
CHANGED
|
@@ -876,14 +876,21 @@ async function ownerOnly(g, op, path, follow2) {
|
|
|
876
876
|
return walked;
|
|
877
877
|
}
|
|
878
878
|
async function chmodMode(g, path, mode) {
|
|
879
|
-
const
|
|
880
|
-
|
|
879
|
+
const walked = await need(g, "chmod", path, 0, { follow: true });
|
|
880
|
+
const perm = walked.perm;
|
|
881
|
+
const st = await g.fs.stat(walked.path).catch(() => void 0);
|
|
882
|
+
if (!st?.fat && perm && g.cred.euid !== 0 && perm.uid !== g.cred.euid) {
|
|
883
|
+
if (await present(g.fs, walked.path, false)) deny(g, "chmod", path, "EPERM");
|
|
884
|
+
}
|
|
885
|
+
if (!g.dac.enforcing || !perm || g.cred.euid === 0 || st?.fat || inGroup(g.cred, perm.gid)) {
|
|
886
|
+
return mode;
|
|
887
|
+
}
|
|
881
888
|
return mode & ~S_ISGID2;
|
|
882
889
|
}
|
|
883
890
|
function heldChmodMode(g, path, st, mode) {
|
|
884
891
|
const perm = permOf(st);
|
|
885
|
-
if (g.cred.euid !== 0 && perm.uid !== g.cred.euid) deny(g, "fchmod", path, "EPERM");
|
|
886
|
-
if (!g.dac.enforcing || g.cred.euid === 0 || inGroup(g.cred, perm.gid)) return mode;
|
|
892
|
+
if (!st.fat && g.cred.euid !== 0 && perm.uid !== g.cred.euid) deny(g, "fchmod", path, "EPERM");
|
|
893
|
+
if (!g.dac.enforcing || g.cred.euid === 0 || st.fat || inGroup(g.cred, perm.gid)) return mode;
|
|
887
894
|
return mode & ~S_ISGID2;
|
|
888
895
|
}
|
|
889
896
|
function heldRetimable(g, path, st, now) {
|
|
@@ -3702,7 +3709,7 @@ function satisfies(version, range2) {
|
|
|
3702
3709
|
}
|
|
3703
3710
|
|
|
3704
3711
|
// src/version.ts
|
|
3705
|
-
var KERNEL_VERSION = true ? "1.
|
|
3712
|
+
var KERNEL_VERSION = true ? "1.177.0" : "0.0.0-dev";
|
|
3706
3713
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3707
3714
|
function procVersion() {
|
|
3708
3715
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9599,10 +9606,15 @@ var DriverConnection = class _DriverConnection {
|
|
|
9599
9606
|
// src/mount/mount-fs.ts
|
|
9600
9607
|
var S_ISGID3 = 1024;
|
|
9601
9608
|
var ID = /^\d{1,10}$/;
|
|
9609
|
+
var MASK = /^0*[0-7]{1,4}$/;
|
|
9602
9610
|
var MAX_ID2 = 4294967294;
|
|
9603
9611
|
function idOption(value2) {
|
|
9604
9612
|
return value2 === void 0 ? 0 : Number(value2);
|
|
9605
9613
|
}
|
|
9614
|
+
function maskOption(value2) {
|
|
9615
|
+
if (value2 === void 0) return void 0;
|
|
9616
|
+
return Number.parseInt(value2, 8) & 511;
|
|
9617
|
+
}
|
|
9606
9618
|
function checkIds(options) {
|
|
9607
9619
|
for (const key of ["uid", "gid"]) {
|
|
9608
9620
|
const value2 = options[key];
|
|
@@ -9610,6 +9622,27 @@ function checkIds(options) {
|
|
|
9610
9622
|
if (!ID.test(value2) || Number(value2) > MAX_ID2) throw errnoError("EINVAL", `${key}=${value2}`);
|
|
9611
9623
|
}
|
|
9612
9624
|
}
|
|
9625
|
+
function checkMasks(options) {
|
|
9626
|
+
for (const key of ["umask", "fmask", "dmask"]) {
|
|
9627
|
+
const value2 = options[key];
|
|
9628
|
+
if (value2 === void 0) continue;
|
|
9629
|
+
if (!MASK.test(value2) || Number.parseInt(value2, 8) > 511) {
|
|
9630
|
+
throw errnoError("EINVAL", `${key}=${value2}`);
|
|
9631
|
+
}
|
|
9632
|
+
}
|
|
9633
|
+
}
|
|
9634
|
+
function modeOf(attr2, mount) {
|
|
9635
|
+
const type = attr2.kind === "directory" ? 16384 : attr2.kind === "symlink" ? 40960 : attr2.kind === "fifo" ? 4096 : 32768;
|
|
9636
|
+
const fallback = type | (attr2.kind === "directory" ? 493 : attr2.kind === "symlink" ? 511 : 420);
|
|
9637
|
+
if (mount.caps.owners) return attr2.mode ?? fallback;
|
|
9638
|
+
const umask = maskOption(mount.options.umask);
|
|
9639
|
+
const fmask = maskOption(mount.options.fmask) ?? umask;
|
|
9640
|
+
const dmask = maskOption(mount.options.dmask) ?? umask;
|
|
9641
|
+
const mask = attr2.kind === "directory" ? dmask : fmask;
|
|
9642
|
+
if (mask === void 0) return attr2.mode ?? fallback;
|
|
9643
|
+
const base = attr2.kind === "directory" || attr2.kind === "symlink" ? 511 : 438;
|
|
9644
|
+
return type | base & ~mask;
|
|
9645
|
+
}
|
|
9613
9646
|
var MAX_LINKS5 = 40;
|
|
9614
9647
|
var STALE_RETRIES = 3;
|
|
9615
9648
|
var SETTLE_ROUNDS = 4;
|
|
@@ -9876,14 +9909,13 @@ function inodeless(mount, attr2) {
|
|
|
9876
9909
|
}
|
|
9877
9910
|
function statOf2(attr2, path, mount) {
|
|
9878
9911
|
const mtime = new Date(attr2.mtime);
|
|
9879
|
-
const fallback = attr2.kind === "directory" ? 16877 : attr2.kind === "symlink" ? 41471 : attr2.kind === "fifo" ? 4516 : 33188;
|
|
9880
9912
|
return {
|
|
9881
9913
|
isFile: attr2.kind === "file",
|
|
9882
9914
|
isDirectory: attr2.kind === "directory",
|
|
9883
9915
|
isSymbolicLink: attr2.kind === "symlink",
|
|
9884
9916
|
...attr2.kind === "fifo" ? { isFifo: true } : {},
|
|
9885
9917
|
size: attr2.size,
|
|
9886
|
-
mode: attr2
|
|
9918
|
+
mode: modeOf(attr2, mount),
|
|
9887
9919
|
mtime,
|
|
9888
9920
|
atime: attr2.atime === void 0 ? mtime : new Date(attr2.atime),
|
|
9889
9921
|
ctime: mtime,
|
|
@@ -9897,7 +9929,8 @@ function statOf2(attr2, path, mount) {
|
|
|
9897
9929
|
...attr2.etag !== void 0 ? { version: attr2.etag } : {},
|
|
9898
9930
|
...mount.owners ? {
|
|
9899
9931
|
uid: (mount.caps.owners ? attr2.uid : void 0) ?? idOption(mount.options.uid),
|
|
9900
|
-
gid: (mount.caps.owners ? attr2.gid : void 0) ?? idOption(mount.options.gid)
|
|
9932
|
+
gid: (mount.caps.owners ? attr2.gid : void 0) ?? idOption(mount.options.gid),
|
|
9933
|
+
...!mount.caps.owners && !mount.caps.chmod && (mount.options.umask !== void 0 || mount.options.fmask !== void 0 || mount.options.dmask !== void 0) ? { fat: true } : {}
|
|
9901
9934
|
} : {}
|
|
9902
9935
|
};
|
|
9903
9936
|
}
|
|
@@ -10004,6 +10037,7 @@ var MountTable = class {
|
|
|
10004
10037
|
if (!st.isDirectory) throw errnoError("ENOTDIR", target);
|
|
10005
10038
|
const options = { ...spec.options };
|
|
10006
10039
|
if (this.deps.owners) checkIds(options);
|
|
10040
|
+
checkMasks(options);
|
|
10007
10041
|
const maxFile = options.maxfile !== void 0 ? parseSize(options.maxfile) : void 0;
|
|
10008
10042
|
const opened2 = await this.deps.open(spec.type, { ...spec, target, options });
|
|
10009
10043
|
let mounted;
|
|
@@ -14454,8 +14488,8 @@ var SCRUB_IDLE_MS = 50;
|
|
|
14454
14488
|
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
14455
14489
|
var encoder5 = new TextEncoder();
|
|
14456
14490
|
function scrubberOf(secrets, sameLength = false) {
|
|
14457
|
-
const
|
|
14458
|
-
return
|
|
14491
|
+
const usable3 = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
14492
|
+
return usable3.length > 0 ? compile(usable3, { idleMs: SCRUB_IDLE_MS, sameLength }) : void 0;
|
|
14459
14493
|
}
|
|
14460
14494
|
async function writeAll(file, bytes) {
|
|
14461
14495
|
const write = file.write;
|
|
@@ -15094,6 +15128,56 @@ var SealedBroker = class {
|
|
|
15094
15128
|
}
|
|
15095
15129
|
};
|
|
15096
15130
|
|
|
15131
|
+
// src/sudo-timestamp.ts
|
|
15132
|
+
var TIMESTAMPS_MAX = 64;
|
|
15133
|
+
var MINUTE_MS2 = 6e4;
|
|
15134
|
+
function timestampKey(owner, type) {
|
|
15135
|
+
if (type === "global") return "global";
|
|
15136
|
+
const { terminal, parent } = owner;
|
|
15137
|
+
if (type === "tty" && terminal) {
|
|
15138
|
+
return JSON.stringify(["tty", terminal.tty, terminal.sid, terminal.started]);
|
|
15139
|
+
}
|
|
15140
|
+
return parent ? JSON.stringify(["ppid", parent.pid, parent.started]) : void 0;
|
|
15141
|
+
}
|
|
15142
|
+
var Timestamps = class {
|
|
15143
|
+
users = /* @__PURE__ */ new Map();
|
|
15144
|
+
now;
|
|
15145
|
+
constructor(now) {
|
|
15146
|
+
this.now = now;
|
|
15147
|
+
}
|
|
15148
|
+
current(owner, policy) {
|
|
15149
|
+
if (policy.minutes === 0) return false;
|
|
15150
|
+
const key = timestampKey(owner, policy.type);
|
|
15151
|
+
const at = key === void 0 ? void 0 : this.users.get(owner.uid)?.get(key);
|
|
15152
|
+
if (at === void 0) return false;
|
|
15153
|
+
const now = this.now();
|
|
15154
|
+
return at <= now && (policy.minutes < 0 || now - at < policy.minutes * MINUTE_MS2);
|
|
15155
|
+
}
|
|
15156
|
+
stamp(owner, policy) {
|
|
15157
|
+
const key = policy.minutes === 0 ? void 0 : timestampKey(owner, policy.type);
|
|
15158
|
+
if (key === void 0) return false;
|
|
15159
|
+
const now = this.now();
|
|
15160
|
+
const records = this.users.get(owner.uid) ?? /* @__PURE__ */ new Map();
|
|
15161
|
+
this.users.set(owner.uid, records);
|
|
15162
|
+
records.delete(key);
|
|
15163
|
+
records.set(key, now);
|
|
15164
|
+
for (const [old, at] of records) {
|
|
15165
|
+
const stale = policy.minutes > 0 && (at > now || now - at >= policy.minutes * MINUTE_MS2);
|
|
15166
|
+
if (stale || records.size > TIMESTAMPS_MAX) records.delete(old);
|
|
15167
|
+
}
|
|
15168
|
+
return true;
|
|
15169
|
+
}
|
|
15170
|
+
invalidate(owner, type) {
|
|
15171
|
+
const key = timestampKey(owner, type);
|
|
15172
|
+
const records = this.users.get(owner.uid);
|
|
15173
|
+
if (key !== void 0) records?.delete(key);
|
|
15174
|
+
if (records?.size === 0) this.users.delete(owner.uid);
|
|
15175
|
+
}
|
|
15176
|
+
remove(uid) {
|
|
15177
|
+
this.users.delete(uid);
|
|
15178
|
+
}
|
|
15179
|
+
};
|
|
15180
|
+
|
|
15097
15181
|
// src/sudoers.ts
|
|
15098
15182
|
var SUDOERS = "/etc/sudoers";
|
|
15099
15183
|
var SUDOERS_D = "/etc/sudoers.d";
|
|
@@ -15113,6 +15197,8 @@ var SHOWN_MAX = 60;
|
|
|
15113
15197
|
var KERNEL_SYNTAX = "[NOPASSWD] <user|%group|ALL> [(<target>)] [Cwd <dir>] [Stdin none] Cmnd <command\u2026|*>";
|
|
15114
15198
|
var SUDOERS_SYNTAX = "<user|%group|ALL> ALL=[(<target>[,<target>\u2026])] [NOPASSWD:] <command\u2026|ALL>";
|
|
15115
15199
|
var EXPECTED = `expected '${KERNEL_SYNTAX}' or '${SUDOERS_SYNTAX}'`;
|
|
15200
|
+
var TIMESTAMP_TIMEOUT = 5;
|
|
15201
|
+
var TIMESTAMP_TYPE = "tty";
|
|
15116
15202
|
function hasControl(text) {
|
|
15117
15203
|
return CONTROL.test(text);
|
|
15118
15204
|
}
|
|
@@ -15395,9 +15481,6 @@ function directiveError(text) {
|
|
|
15395
15481
|
return /^#-?\d+\s+\S+\s*=/.test(text) ? "a #uid isn't supported: name the user, %group or ALL" : null;
|
|
15396
15482
|
}
|
|
15397
15483
|
const first = /^\S+/.exec(text)?.[0] ?? "";
|
|
15398
|
-
if (/^Defaults([:@>!]|$)/.test(first)) {
|
|
15399
|
-
return "Defaults aren't supported: the kernel's sudo has no settings, so this changes nothing";
|
|
15400
|
-
}
|
|
15401
15484
|
if (/^[A-Z][A-Za-z]*_Alias$/.test(first)) {
|
|
15402
15485
|
return "aliases aren't supported: name the users, targets and commands in each line";
|
|
15403
15486
|
}
|
|
@@ -15423,9 +15506,90 @@ function kernelLine(m, line, file) {
|
|
|
15423
15506
|
)
|
|
15424
15507
|
};
|
|
15425
15508
|
}
|
|
15509
|
+
var DEFAULTS = /^Defaults(?=[:@>!\s]|$)/;
|
|
15510
|
+
var DEFAULTS_ONLY = `Defaults aren't supported, except timestamp_timeout and timestamp_type for everyone, a user or a %group: this line changes nothing`;
|
|
15511
|
+
var PARAM = /^(!*)([A-Za-z_]+)(?:\s*([-+]?=)\s*(.*))?$/s;
|
|
15512
|
+
var MINUTES = /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)$/;
|
|
15513
|
+
var TYPES = ["tty", "ppid", "global"];
|
|
15514
|
+
function defaultsValue(raw2) {
|
|
15515
|
+
const quoted = /^"(.*)"$/s.exec(raw2);
|
|
15516
|
+
return quoted ? quoted[1] : raw2;
|
|
15517
|
+
}
|
|
15518
|
+
function timeoutParam({ text, negated, op, value: value2 }) {
|
|
15519
|
+
if (negated && op === void 0) return { timestampTimeout: 0 };
|
|
15520
|
+
if (negated || op !== "=" || !MINUTES.test(value2) || !Number.isFinite(Number(value2))) {
|
|
15521
|
+
return `timestamp_timeout takes minutes, such as =5 or =2.5 (0 always asks, below 0 never expires), not ${shown(text)}`;
|
|
15522
|
+
}
|
|
15523
|
+
return { timestampTimeout: Number(value2) };
|
|
15524
|
+
}
|
|
15525
|
+
function typeParam({ text, negated, op, value: value2 }) {
|
|
15526
|
+
if (!negated && op === "=" && TYPES.includes(value2)) {
|
|
15527
|
+
return { timestampType: value2 };
|
|
15528
|
+
}
|
|
15529
|
+
if (value2 === "kernel") return "timestamp_type=kernel isn't supported: use tty, ppid or global";
|
|
15530
|
+
return `timestamp_type takes =tty, =ppid or =global, not ${shown(text)}`;
|
|
15531
|
+
}
|
|
15532
|
+
function defaultsParam(param) {
|
|
15533
|
+
const m = PARAM.exec(param);
|
|
15534
|
+
if (!m) return DEFAULTS_ONLY;
|
|
15535
|
+
const [, bangs = "", name2, op, raw2 = ""] = m;
|
|
15536
|
+
const read = { text: param, negated: bangs !== "", op, value: defaultsValue(raw2.trim()) };
|
|
15537
|
+
const settings = name2 === "timestamp_timeout" ? timeoutParam(read) : name2 === "timestamp_type" ? typeParam(read) : DEFAULTS_ONLY;
|
|
15538
|
+
if (typeof settings === "string") return settings;
|
|
15539
|
+
const value2 = settings.timestampTimeout ?? settings.timestampType;
|
|
15540
|
+
return { settings, text: `${name2}=${value2}` };
|
|
15541
|
+
}
|
|
15542
|
+
function defaultsWho(binding) {
|
|
15543
|
+
if (binding === "") return null;
|
|
15544
|
+
if (!binding.startsWith(":")) return DEFAULTS_ONLY;
|
|
15545
|
+
const who = binding.slice(1).split(",");
|
|
15546
|
+
for (const name2 of who) {
|
|
15547
|
+
if (!validWho(name2))
|
|
15548
|
+
return `expected users, %groups or ALL after Defaults:, not ${shown(name2)}`;
|
|
15549
|
+
}
|
|
15550
|
+
return who;
|
|
15551
|
+
}
|
|
15552
|
+
function defaultsLine(text) {
|
|
15553
|
+
const m = /^Defaults(\S*)(?:\s+(.*))?$/s.exec(text);
|
|
15554
|
+
const who = defaultsWho(m?.[1] ?? "");
|
|
15555
|
+
if (typeof who === "string") return { error: who };
|
|
15556
|
+
const list = (m?.[2] ?? "").trim();
|
|
15557
|
+
if (list === "")
|
|
15558
|
+
return {
|
|
15559
|
+
error: "expected timestamp_timeout=<minutes> or timestamp_type=<type> after Defaults"
|
|
15560
|
+
};
|
|
15561
|
+
const settings = {};
|
|
15562
|
+
const params = [];
|
|
15563
|
+
for (const param of list.split(",")) {
|
|
15564
|
+
const read = defaultsParam(param.trim());
|
|
15565
|
+
if (typeof read === "string") return { error: read };
|
|
15566
|
+
Object.assign(settings, read.settings);
|
|
15567
|
+
params.push(read.text);
|
|
15568
|
+
}
|
|
15569
|
+
return { defaults: { who, settings, params } };
|
|
15570
|
+
}
|
|
15571
|
+
function resolveDefaults(entries, applies) {
|
|
15572
|
+
const everyone = entries.filter((e) => e.who === null);
|
|
15573
|
+
const mine = entries.filter((e) => e.who?.some(applies));
|
|
15574
|
+
const matching = [...everyone, ...mine];
|
|
15575
|
+
const settings = Object.assign({}, ...matching.map((e) => e.settings));
|
|
15576
|
+
return {
|
|
15577
|
+
timestampTimeout: settings.timestampTimeout ?? TIMESTAMP_TIMEOUT,
|
|
15578
|
+
timestampType: settings.timestampType ?? TIMESTAMP_TYPE,
|
|
15579
|
+
matching
|
|
15580
|
+
};
|
|
15581
|
+
}
|
|
15582
|
+
function defaultsText(entries) {
|
|
15583
|
+
const all = resolveDefaults(entries, () => false);
|
|
15584
|
+
return [
|
|
15585
|
+
`Defaults timestamp_timeout=${all.timestampTimeout}, timestamp_type=${all.timestampType}`,
|
|
15586
|
+
...entries.filter((e) => e.who !== null).map((e) => `Defaults:${e.who.join(",")} ${e.params.join(", ")}`)
|
|
15587
|
+
];
|
|
15588
|
+
}
|
|
15426
15589
|
function parseLine(line, file) {
|
|
15427
15590
|
const text = line.trim();
|
|
15428
15591
|
if (text === "") return null;
|
|
15592
|
+
if (DEFAULTS.test(text)) return defaultsLine(text);
|
|
15429
15593
|
const directive = directiveError(text);
|
|
15430
15594
|
if (directive !== void 0) return directive === null ? null : { error: directive };
|
|
15431
15595
|
const kernel = KERNEL_FORM.exec(text);
|
|
@@ -15437,14 +15601,16 @@ function parseLine(line, file) {
|
|
|
15437
15601
|
}
|
|
15438
15602
|
function parsePolicy(text, file) {
|
|
15439
15603
|
const rules = [];
|
|
15604
|
+
const defaults2 = [];
|
|
15440
15605
|
const errors = [];
|
|
15441
15606
|
for (const [n, line] of text.split("\n").entries()) {
|
|
15442
15607
|
const parsed2 = parseLine(line, file);
|
|
15443
15608
|
if (parsed2 === null) continue;
|
|
15444
15609
|
if ("error" in parsed2) errors.push({ line: n + 1, message: parsed2.error });
|
|
15610
|
+
else if ("defaults" in parsed2) defaults2.push(parsed2.defaults);
|
|
15445
15611
|
else rules.push(...parsed2.rules);
|
|
15446
15612
|
}
|
|
15447
|
-
return { rules, errors };
|
|
15613
|
+
return { rules, defaults: defaults2, errors };
|
|
15448
15614
|
}
|
|
15449
15615
|
|
|
15450
15616
|
// src/users.ts
|
|
@@ -15829,7 +15995,14 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
15829
15995
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
15830
15996
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
15831
15997
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
15832
|
-
var USAGE =
|
|
15998
|
+
var USAGE = [
|
|
15999
|
+
"usage: sudo -K | -k",
|
|
16000
|
+
" sudo -v [-kn] [-u user]",
|
|
16001
|
+
" sudo -l [-kn]",
|
|
16002
|
+
" sudo [-kn] [-u user] [--] command [args...]"
|
|
16003
|
+
].join("\n");
|
|
16004
|
+
var DONE = { done: true };
|
|
16005
|
+
var NOT_STAMPED = "sudo: approved, but the approver didn't say a person decided, so no timestamp was recorded";
|
|
15833
16006
|
var DENIED2 = "sudo: approval denied";
|
|
15834
16007
|
var DENIAL_MAX = 500;
|
|
15835
16008
|
var ABORTED = /* @__PURE__ */ Symbol("aborted");
|
|
@@ -15903,6 +16076,17 @@ async function answerOf(approve, req, signal) {
|
|
|
15903
16076
|
return cut === void 0 ? "deny" : await cut;
|
|
15904
16077
|
}
|
|
15905
16078
|
}
|
|
16079
|
+
function approvalOf(answer2) {
|
|
16080
|
+
if (answer2 === "once" || answer2 === "always") return { answer: answer2, person: false };
|
|
16081
|
+
if (typeof answer2 !== "object" || answer2 === null) return void 0;
|
|
16082
|
+
try {
|
|
16083
|
+
const { answer: kind, timestamp } = answer2;
|
|
16084
|
+
if (kind !== "once" && kind !== "always" || timestamp !== true) return void 0;
|
|
16085
|
+
return { answer: kind, person: true };
|
|
16086
|
+
} catch {
|
|
16087
|
+
return void 0;
|
|
16088
|
+
}
|
|
16089
|
+
}
|
|
15906
16090
|
function recordedCommand(argv) {
|
|
15907
16091
|
const [path = "", ...args] = argv;
|
|
15908
16092
|
return commandText({ path, args: args.map((a) => [a]) });
|
|
@@ -15912,6 +16096,9 @@ function flags(parsed2, arg, next3) {
|
|
|
15912
16096
|
const flag = arg[j];
|
|
15913
16097
|
if (flag === "n") parsed2.nonInteractive = true;
|
|
15914
16098
|
else if (flag === "l") parsed2.list = true;
|
|
16099
|
+
else if (flag === "v") parsed2.validate = true;
|
|
16100
|
+
else if (flag === "k") parsed2.reset = true;
|
|
16101
|
+
else if (flag === "K") parsed2.removeAll = true;
|
|
15915
16102
|
else if (flag !== "u") return `sudo: invalid option -- '${flag}'
|
|
15916
16103
|
${USAGE}`;
|
|
15917
16104
|
else {
|
|
@@ -15925,7 +16112,15 @@ ${USAGE}`;
|
|
|
15925
16112
|
return 0;
|
|
15926
16113
|
}
|
|
15927
16114
|
function parseArgs(args) {
|
|
15928
|
-
const parsed2 = {
|
|
16115
|
+
const parsed2 = {
|
|
16116
|
+
list: false,
|
|
16117
|
+
nonInteractive: false,
|
|
16118
|
+
validate: false,
|
|
16119
|
+
reset: false,
|
|
16120
|
+
removeAll: false,
|
|
16121
|
+
user: "root",
|
|
16122
|
+
command: []
|
|
16123
|
+
};
|
|
15929
16124
|
let i = 0;
|
|
15930
16125
|
for (; i < args.length; i++) {
|
|
15931
16126
|
const arg = args[i];
|
|
@@ -15939,8 +16134,17 @@ function parseArgs(args) {
|
|
|
15939
16134
|
i += used;
|
|
15940
16135
|
}
|
|
15941
16136
|
parsed2.command = args.slice(i);
|
|
15942
|
-
|
|
15943
|
-
|
|
16137
|
+
return usable(parsed2) ? parsed2 : USAGE;
|
|
16138
|
+
}
|
|
16139
|
+
function usable(parsed2) {
|
|
16140
|
+
const command = parsed2.command.length > 0;
|
|
16141
|
+
const modes = [parsed2.list, parsed2.validate, parsed2.removeAll].filter(Boolean).length;
|
|
16142
|
+
if (modes > 1 || parsed2.removeAll && parsed2.reset) return false;
|
|
16143
|
+
if (modes === 1) return !command;
|
|
16144
|
+
return command || parsed2.reset;
|
|
16145
|
+
}
|
|
16146
|
+
function policyOf(settings) {
|
|
16147
|
+
return { type: settings.timestampType, minutes: settings.timestampTimeout };
|
|
15944
16148
|
}
|
|
15945
16149
|
function described(rule) {
|
|
15946
16150
|
const cmnd = rule.cmnd === "*" ? "ALL" : commandText(rule.cmnd);
|
|
@@ -15952,9 +16156,11 @@ var Sudo = class {
|
|
|
15952
16156
|
o;
|
|
15953
16157
|
warned = /* @__PURE__ */ new Set();
|
|
15954
16158
|
pending = /* @__PURE__ */ new Set();
|
|
16159
|
+
timestamps;
|
|
15955
16160
|
next = 0;
|
|
15956
16161
|
constructor(options) {
|
|
15957
16162
|
this.o = options;
|
|
16163
|
+
this.timestamps = new Timestamps(options.now ?? (() => performance.now()));
|
|
15958
16164
|
}
|
|
15959
16165
|
warn(message3) {
|
|
15960
16166
|
if (this.warned.has(message3)) return;
|
|
@@ -16041,8 +16247,8 @@ var Sudo = class {
|
|
|
16041
16247
|
const code = err.code;
|
|
16042
16248
|
return skipped(`it can't be read (${typeof code === "string" ? code : "error"})`);
|
|
16043
16249
|
}
|
|
16044
|
-
const { rules, errors } = parsePolicy(text, path);
|
|
16045
|
-
return { path, rules, problems: errors, ok: true };
|
|
16250
|
+
const { rules, defaults: defaults2, errors } = parsePolicy(text, path);
|
|
16251
|
+
return { path, rules, defaults: defaults2, problems: errors, ok: true };
|
|
16046
16252
|
}
|
|
16047
16253
|
async policy() {
|
|
16048
16254
|
const files = [await this.policyFile(SUDOERS)];
|
|
@@ -16071,7 +16277,10 @@ var Sudo = class {
|
|
|
16071
16277
|
}
|
|
16072
16278
|
}
|
|
16073
16279
|
if (!detailed && skipped > 0) await caller.report?.(skippedNotice(skipped));
|
|
16074
|
-
return
|
|
16280
|
+
return {
|
|
16281
|
+
rules: files.flatMap((f) => f.rules),
|
|
16282
|
+
defaults: files.flatMap((f) => f.defaults ?? [])
|
|
16283
|
+
};
|
|
16075
16284
|
}
|
|
16076
16285
|
async check(cred, call) {
|
|
16077
16286
|
const lines2 = [];
|
|
@@ -16084,17 +16293,26 @@ var Sudo = class {
|
|
|
16084
16293
|
if (read && problems.length === 0) lines2.push([1, `${path}: parsed OK`]);
|
|
16085
16294
|
if (problems.length > 0) ok4 = false;
|
|
16086
16295
|
};
|
|
16296
|
+
const values = (defaults2) => {
|
|
16297
|
+
for (const line of defaultsText(defaults2)) lines2.push([1, line]);
|
|
16298
|
+
};
|
|
16087
16299
|
if (call.files !== void 0) {
|
|
16300
|
+
const defaults2 = [];
|
|
16088
16301
|
for (const { name: name2, text } of call.files) {
|
|
16089
|
-
|
|
16302
|
+
const parsed2 = parsePolicy(text);
|
|
16303
|
+
defaults2.push(...parsed2.defaults);
|
|
16304
|
+
report({ path: name2, rules: [], problems: parsed2.errors, ok: true });
|
|
16090
16305
|
}
|
|
16306
|
+
if (defaults2.length > 0) values(defaults2);
|
|
16091
16307
|
return { lines: lines2, ok: ok4 };
|
|
16092
16308
|
}
|
|
16093
16309
|
if (this.o.mode === "enforce" && cred.euid !== 0) {
|
|
16094
16310
|
const hint = "check the policy as root (sudo visudo -c), or a file with visudo -c -f <file>";
|
|
16095
16311
|
return { lines: [[2, `visudo: ${SUDOERS}: Permission denied: ${hint}`]], ok: false };
|
|
16096
16312
|
}
|
|
16097
|
-
|
|
16313
|
+
const files = await this.policy();
|
|
16314
|
+
for (const file of files) report(file);
|
|
16315
|
+
values(files.flatMap((f) => f.defaults ?? []));
|
|
16098
16316
|
return { lines: lines2, ok: ok4 };
|
|
16099
16317
|
}
|
|
16100
16318
|
async groupIds() {
|
|
@@ -16103,9 +16321,9 @@ var Sudo = class {
|
|
|
16103
16321
|
async applies(caller, cred) {
|
|
16104
16322
|
const gids = await this.groupIds();
|
|
16105
16323
|
const mine = /* @__PURE__ */ new Set([cred.rgid, cred.egid, ...cred.groups]);
|
|
16106
|
-
return (
|
|
16107
|
-
if (
|
|
16108
|
-
const gid =
|
|
16324
|
+
return (who) => {
|
|
16325
|
+
if (who === "ALL" || who === caller.name) return true;
|
|
16326
|
+
const gid = who.startsWith("%") ? gids.get(who.slice(1)) : void 0;
|
|
16109
16327
|
return gid !== void 0 && mine.has(gid);
|
|
16110
16328
|
};
|
|
16111
16329
|
}
|
|
@@ -16150,18 +16368,40 @@ var Sudo = class {
|
|
|
16150
16368
|
const mode = this.o.mode;
|
|
16151
16369
|
if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
|
|
16152
16370
|
` };
|
|
16153
|
-
return { run: parsed2.command };
|
|
16371
|
+
return parsed2.command.length > 0 ? { run: parsed2.command } : DONE;
|
|
16154
16372
|
}
|
|
16155
16373
|
const { cred } = caller;
|
|
16156
16374
|
const policy = await this.policyRules(caller);
|
|
16157
16375
|
const self = await this.o.users.lookup(cred.ruid);
|
|
16158
16376
|
if (!self) return failed2("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
|
|
16377
|
+
const owner = {
|
|
16378
|
+
uid: cred.ruid,
|
|
16379
|
+
terminal: caller.terminal,
|
|
16380
|
+
parent: caller.parent
|
|
16381
|
+
};
|
|
16382
|
+
const applies = await this.applies(self, cred);
|
|
16383
|
+
const settings = resolveDefaults(policy.defaults, applies);
|
|
16384
|
+
if (parsed2.removeAll) {
|
|
16385
|
+
this.timestamps.remove(owner.uid);
|
|
16386
|
+
return DONE;
|
|
16387
|
+
}
|
|
16388
|
+
if (parsed2.reset && !parsed2.validate && !parsed2.list && parsed2.command.length === 0) {
|
|
16389
|
+
this.timestamps.invalidate(owner, settings.timestampType);
|
|
16390
|
+
return DONE;
|
|
16391
|
+
}
|
|
16159
16392
|
const target = await this.lookup(parsed2.user);
|
|
16160
16393
|
if (!target) return failed2("ENOENT", `sudo: unknown user ${parsed2.user}`);
|
|
16161
16394
|
const root = cred.euid === 0;
|
|
16162
|
-
const rules = root ? [] : policy;
|
|
16163
|
-
const
|
|
16164
|
-
if (parsed2.list) return this.listed(self, root,
|
|
16395
|
+
const rules = root ? [] : policy.rules;
|
|
16396
|
+
const mine = rules.filter((rule) => applies(rule.who));
|
|
16397
|
+
if (parsed2.list) return this.listed(self, root, mine, settings.matching);
|
|
16398
|
+
const session = { caller, self, target, owner, policy: policyOf(settings), parsed: parsed2, signal };
|
|
16399
|
+
if (parsed2.validate) return this.validate(session, root, mine, call.cwd);
|
|
16400
|
+
return this.command(session, root, mine, call);
|
|
16401
|
+
}
|
|
16402
|
+
async command(s, root, mine, call) {
|
|
16403
|
+
const { caller, self, target, parsed: parsed2 } = s;
|
|
16404
|
+
const { cred } = caller;
|
|
16165
16405
|
const [word = "", ...args] = parsed2.command;
|
|
16166
16406
|
const cwd = await this.canonical(call.cwd);
|
|
16167
16407
|
if (cwd === void 0 || !await this.reachable(cred, cwd)) {
|
|
@@ -16175,8 +16415,8 @@ var Sudo = class {
|
|
|
16175
16415
|
const untrusted2 = await this.untrusted(path, cwd, word);
|
|
16176
16416
|
if (untrusted2) return untrusted2;
|
|
16177
16417
|
const argv = [path, ...args];
|
|
16178
|
-
const matching =
|
|
16179
|
-
(rule) =>
|
|
16418
|
+
const matching = mine.filter(
|
|
16419
|
+
(rule) => (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && stdinMatches(rule, caller.stdin) && commandMatches(rule.cmnd, argv)
|
|
16180
16420
|
);
|
|
16181
16421
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
16182
16422
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -16187,23 +16427,67 @@ var Sudo = class {
|
|
|
16187
16427
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
16188
16428
|
);
|
|
16189
16429
|
}
|
|
16430
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
16431
|
+
this.timestamps.stamp(s.owner, s.policy);
|
|
16432
|
+
this.logged(s, cwd, argv);
|
|
16433
|
+
return grant();
|
|
16434
|
+
}
|
|
16190
16435
|
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16191
|
-
|
|
16192
|
-
|
|
16193
|
-
|
|
16194
|
-
const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
|
|
16195
|
-
if (typeof answer2 !== "string") return answer2;
|
|
16436
|
+
return this.pendingFor(cred.ruid, async () => {
|
|
16437
|
+
const answer2 = await this.ask(s, { argv: parsed2.command, path, cwd });
|
|
16438
|
+
if ("error" in answer2) return answer2;
|
|
16196
16439
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
16197
16440
|
return failed2("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
16198
16441
|
}
|
|
16199
16442
|
const changed = await this.untrusted(path, cwd, word);
|
|
16200
16443
|
if (changed) return changed;
|
|
16201
|
-
|
|
16202
|
-
|
|
16444
|
+
const result = answer2.answer === "once" ? grant() : await this.always(self, target, cwd, argv, recordable(cwd, parsed2.command), grant);
|
|
16445
|
+
if (!("error" in result)) this.stamped(s, answer2);
|
|
16446
|
+
return result;
|
|
16447
|
+
});
|
|
16448
|
+
}
|
|
16449
|
+
async validate(s, root, mine, dir) {
|
|
16450
|
+
const { self, parsed: parsed2 } = s;
|
|
16451
|
+
if (root) return DONE;
|
|
16452
|
+
if (mine.length === 0) {
|
|
16453
|
+
return failed2("EPERM", `Sorry, user ${self.name} may not run sudo on ${this.o.hostname}.`);
|
|
16454
|
+
}
|
|
16455
|
+
if (mine.every((rule) => rule.nopasswd)) return DONE;
|
|
16456
|
+
if (!parsed2.reset && this.timestamps.current(s.owner, s.policy)) {
|
|
16457
|
+
this.timestamps.stamp(s.owner, s.policy);
|
|
16458
|
+
return DONE;
|
|
16459
|
+
}
|
|
16460
|
+
if (parsed2.nonInteractive) return failed2("EPERM", "sudo: a password is required");
|
|
16461
|
+
const cwd = await this.canonical(dir) ?? normalizePath(dir);
|
|
16462
|
+
return this.pendingFor(s.caller.cred.ruid, async () => {
|
|
16463
|
+
const answer2 = await this.ask(s, { argv: [], path: "", cwd, validate: true });
|
|
16464
|
+
if ("error" in answer2) return answer2;
|
|
16465
|
+
if (!answer2.person) await s.caller.report?.(NOT_STAMPED);
|
|
16466
|
+
this.stamped(s, answer2);
|
|
16467
|
+
return DONE;
|
|
16468
|
+
});
|
|
16469
|
+
}
|
|
16470
|
+
async pendingFor(uid, work) {
|
|
16471
|
+
if (this.pending.has(uid)) return failed2("EBUSY", "sudo: another request is pending");
|
|
16472
|
+
this.pending.add(uid);
|
|
16473
|
+
try {
|
|
16474
|
+
return await work();
|
|
16203
16475
|
} finally {
|
|
16204
|
-
this.pending.delete(
|
|
16476
|
+
this.pending.delete(uid);
|
|
16205
16477
|
}
|
|
16206
16478
|
}
|
|
16479
|
+
stamped(s, answer2) {
|
|
16480
|
+
if (answer2.person && !s.parsed.reset) this.timestamps.stamp(s.owner, s.policy);
|
|
16481
|
+
}
|
|
16482
|
+
logged(s, cwd, argv) {
|
|
16483
|
+
const { caller, self, target, owner, policy } = s;
|
|
16484
|
+
const type = policy.type === "tty" && !owner.terminal ? "ppid" : policy.type;
|
|
16485
|
+
const tty = owner.terminal?.tty ?? caller.tty ?? "unknown";
|
|
16486
|
+
const command = argv.map(quoteWord).join(" ");
|
|
16487
|
+
(this.o.warn ?? console.warn)(
|
|
16488
|
+
`sudo: ${self.name} : TTY=${tty} ; PWD=${quoteWord(cwd)} ; USER=${target.name} ; TIMESTAMP=${type} ; COMMAND=${command}`
|
|
16489
|
+
);
|
|
16490
|
+
}
|
|
16207
16491
|
async always(self, target, cwd, argv, shown2, grant) {
|
|
16208
16492
|
if (!shown2 || !recordable(cwd, argv)) return { ...grant(), notice: RAN_ONCE };
|
|
16209
16493
|
if (!await this.remember(self, target, cwd, argv)) {
|
|
@@ -16211,7 +16495,7 @@ var Sudo = class {
|
|
|
16211
16495
|
}
|
|
16212
16496
|
return grant();
|
|
16213
16497
|
}
|
|
16214
|
-
listed(self, root, rules) {
|
|
16498
|
+
listed(self, root, rules, defaults2) {
|
|
16215
16499
|
const host = this.o.hostname;
|
|
16216
16500
|
if (root) {
|
|
16217
16501
|
return {
|
|
@@ -16224,11 +16508,20 @@ var Sudo = class {
|
|
|
16224
16508
|
return failed2("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
16225
16509
|
}
|
|
16226
16510
|
const lines2 = rules.map(described).join("\n");
|
|
16227
|
-
|
|
16511
|
+
const params = defaults2.flatMap((d) => d.params).join(", ");
|
|
16512
|
+
const matching = params === "" ? "" : `Matching Defaults entries for ${self.name} on ${host}:
|
|
16513
|
+
${params}
|
|
16514
|
+
|
|
16515
|
+
`;
|
|
16516
|
+
return {
|
|
16517
|
+
list: `${matching}User ${self.name} may run the following commands on ${host}:
|
|
16228
16518
|
${lines2}
|
|
16229
|
-
`
|
|
16519
|
+
`
|
|
16520
|
+
};
|
|
16230
16521
|
}
|
|
16231
|
-
async ask(
|
|
16522
|
+
async ask(s, asked) {
|
|
16523
|
+
const { caller, self, target, signal: requester } = s;
|
|
16524
|
+
const { argv, path, cwd } = asked;
|
|
16232
16525
|
const { approve } = this.o;
|
|
16233
16526
|
if (!approve || requester.aborted) return failed2("EACCES", DENIED2);
|
|
16234
16527
|
const createdAt = Date.now();
|
|
@@ -16247,9 +16540,11 @@ ${lines2}
|
|
|
16247
16540
|
...caller.tty ? { tty: caller.tty } : {},
|
|
16248
16541
|
createdAt,
|
|
16249
16542
|
expiresAt: createdAt + timeout,
|
|
16250
|
-
always: recordable(cwd, [path, ...argv]),
|
|
16543
|
+
always: asked.validate ? false : recordable(cwd, [path, ...argv]),
|
|
16251
16544
|
stdin: caller.stdin,
|
|
16252
|
-
rootOnly: await this.rootOnly(cwd, argv.slice(1))
|
|
16545
|
+
rootOnly: asked.validate ? {} : await this.rootOnly(cwd, argv.slice(1)),
|
|
16546
|
+
...asked.validate ? { validate: true } : {},
|
|
16547
|
+
timestamp: true
|
|
16253
16548
|
};
|
|
16254
16549
|
const control = new AbortController();
|
|
16255
16550
|
const timer = setTimeout(() => control.abort("expired"), timeout);
|
|
@@ -16259,9 +16554,8 @@ ${lines2}
|
|
|
16259
16554
|
try {
|
|
16260
16555
|
const answer2 = await answerOf(approve, req, control.signal);
|
|
16261
16556
|
if (answer2 === ABORTED) return ended();
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
}
|
|
16557
|
+
const approved = approvalOf(answer2);
|
|
16558
|
+
if (approved) return control.signal.aborted ? ended() : approved;
|
|
16265
16559
|
return failed2("EACCES", denialText(answer2));
|
|
16266
16560
|
} finally {
|
|
16267
16561
|
clearTimeout(timer);
|
|
@@ -19818,7 +20112,7 @@ function replaced(text, values) {
|
|
|
19818
20112
|
for (const [ph, value2] of Object.entries(values)) out = out.split(ph).join(binary(value2));
|
|
19819
20113
|
return out;
|
|
19820
20114
|
}
|
|
19821
|
-
function
|
|
20115
|
+
function usable2(values) {
|
|
19822
20116
|
const out = {};
|
|
19823
20117
|
for (const [ph, value2] of Object.entries(values ?? {}))
|
|
19824
20118
|
if (encoder8.encode(value2).length >= MIN_VALUE) out[ph] = value2;
|
|
@@ -19833,7 +20127,7 @@ async function substituteHead(head, ask) {
|
|
|
19833
20127
|
if (!request || !found || found.length !== 1) return void 0;
|
|
19834
20128
|
const at = found[0];
|
|
19835
20129
|
if (at.placeholders.length > SESSION_PLACEHOLDERS) return void 0;
|
|
19836
|
-
const values =
|
|
20130
|
+
const values = usable2(
|
|
19837
20131
|
await ask(`header:${at.name}`, at.placeholders, {
|
|
19838
20132
|
method: request[1],
|
|
19839
20133
|
path: request[2]
|
|
@@ -20143,7 +20437,7 @@ async function cleartext(message3, asks) {
|
|
|
20143
20437
|
const placeholders = placeholdersIn(password);
|
|
20144
20438
|
if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS)
|
|
20145
20439
|
return { bytes: message3, done: true };
|
|
20146
|
-
const values =
|
|
20440
|
+
const values = usable2(await asks.cleartext(placeholders));
|
|
20147
20441
|
if (Object.keys(values).length === 0) return { bytes: message3, done: true };
|
|
20148
20442
|
return { bytes: frame3(112, `${replaced(password, values)}\0`), values, done: true };
|
|
20149
20443
|
}
|
|
@@ -20208,7 +20502,7 @@ var PgClient = class {
|
|
|
20208
20502
|
const x = got.exchange;
|
|
20209
20503
|
const binding = this.header === END_POINT ? this.server.binding : void 0;
|
|
20210
20504
|
const serverFinal = `c=${channelOf(this.header, binding)},r=${got.nonce}`;
|
|
20211
|
-
const values =
|
|
20505
|
+
const values = usable2(
|
|
20212
20506
|
await this.asks.scram({
|
|
20213
20507
|
clientFirstBare: x.clientFirstBare,
|
|
20214
20508
|
serverFirst: x.serverFirst,
|
|
@@ -20257,7 +20551,7 @@ function decoded(b642) {
|
|
|
20257
20551
|
async function swapped(text, position, ask) {
|
|
20258
20552
|
const placeholders = placeholdersIn(text);
|
|
20259
20553
|
if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS) return void 0;
|
|
20260
|
-
const values =
|
|
20554
|
+
const values = usable2(await ask(position, placeholders));
|
|
20261
20555
|
if (Object.keys(values).length === 0) return void 0;
|
|
20262
20556
|
return { text: replaced(text, values), values };
|
|
20263
20557
|
}
|
|
@@ -20355,7 +20649,7 @@ function headEnd2(bytes) {
|
|
|
20355
20649
|
}
|
|
20356
20650
|
return -1;
|
|
20357
20651
|
}
|
|
20358
|
-
function
|
|
20652
|
+
function modeOf2(start2) {
|
|
20359
20653
|
const sniffs = [
|
|
20360
20654
|
["http1", sniffHttp1(start2)],
|
|
20361
20655
|
["smtp", sniffSmtp(start2)],
|
|
@@ -20464,7 +20758,7 @@ var SessionWriter = class {
|
|
|
20464
20758
|
joined5.set(bytes, this.buffer.length);
|
|
20465
20759
|
this.buffer.fill(0);
|
|
20466
20760
|
this.buffer = joined5;
|
|
20467
|
-
if (this.mode === "sniff") this.mode =
|
|
20761
|
+
if (this.mode === "sniff") this.mode = modeOf2(latin12(joined5.subarray(0, 8))) ?? "sniff";
|
|
20468
20762
|
if (this.mode === "pg" && !this.sawPg) {
|
|
20469
20763
|
this.sawPg = true;
|
|
20470
20764
|
if (!this.s.verified) void this.proof("pg");
|
|
@@ -28904,8 +29198,8 @@ var OpfsFs = class {
|
|
|
28904
29198
|
const [entry] = await this.meta.get([target]);
|
|
28905
29199
|
if (entry?.fifo || entry?.socket) throw fsError("ENXIO", path);
|
|
28906
29200
|
const kept = fresh3 ? cached : this.files.get(target);
|
|
28907
|
-
const
|
|
28908
|
-
return [
|
|
29201
|
+
const usable3 = kept && performance.now() - (this.found.get(kept) ?? -CHECK_MS) < CHECK_MS;
|
|
29202
|
+
return [usable3 ? kept : void 0, target, true];
|
|
28909
29203
|
}
|
|
28910
29204
|
async writeAt(handle, target, path, offset, bytes) {
|
|
28911
29205
|
await this.counting(target);
|
|
@@ -31901,6 +32195,7 @@ var SUDO_SOURCE = [
|
|
|
31901
32195
|
" await say(1, answer.list);",
|
|
31902
32196
|
" return 0;",
|
|
31903
32197
|
" }",
|
|
32198
|
+
" if (answer.done === true) return 0;",
|
|
31904
32199
|
" if (answer.run !== undefined) {",
|
|
31905
32200
|
" try {",
|
|
31906
32201
|
" pid = (await ctx.spawn({ argv: answer.run, pgid: 0 })).pid;",
|
|
@@ -32536,6 +32831,7 @@ var Launcher = class {
|
|
|
32536
32831
|
);
|
|
32537
32832
|
}
|
|
32538
32833
|
this.users = new UserDb(this.fs, this.owners);
|
|
32834
|
+
const { sudoClock } = options;
|
|
32539
32835
|
this.sudoer = new Sudo({
|
|
32540
32836
|
fs: this.fs,
|
|
32541
32837
|
users: this.users,
|
|
@@ -32545,7 +32841,8 @@ var Launcher = class {
|
|
|
32545
32841
|
pnpmHome: this.pnpmHome,
|
|
32546
32842
|
backing: (path, cwd) => this.backing(path, cwd),
|
|
32547
32843
|
approve: options.approve,
|
|
32548
|
-
timeoutMs: options.sudoTimeoutMs
|
|
32844
|
+
timeoutMs: options.sudoTimeoutMs,
|
|
32845
|
+
now: sudoClock ? () => sudoClock.now() : void 0
|
|
32549
32846
|
});
|
|
32550
32847
|
this.cron = this.cronService(options.cron);
|
|
32551
32848
|
void this.unlinked.sweep("/");
|
|
@@ -33951,11 +34248,26 @@ var Launcher = class {
|
|
|
33951
34248
|
pid: this.jobs.shown(pid),
|
|
33952
34249
|
tags: this.tagsOf(pid),
|
|
33953
34250
|
tty: this.described.get(pid)?.tty,
|
|
34251
|
+
...this.timestampOwner(pid),
|
|
33954
34252
|
stdin,
|
|
33955
34253
|
report
|
|
33956
34254
|
};
|
|
33957
34255
|
return this.sudoer.request(caller, call, signal);
|
|
33958
34256
|
}
|
|
34257
|
+
timestampOwner(pid) {
|
|
34258
|
+
const sid = this.jobs.sidOf(pid);
|
|
34259
|
+
const tty = this.jobs.controllingTerminal(pid)?.name;
|
|
34260
|
+
const leader = sid === void 0 ? void 0 : this.startedOf(sid);
|
|
34261
|
+
const host = this.jobs.shownParent(pid) ?? this.jobs.shown(pid);
|
|
34262
|
+
const started = this.startedOf(host);
|
|
34263
|
+
return {
|
|
34264
|
+
...tty && sid !== void 0 && leader !== void 0 ? { terminal: { tty, sid, started: leader } } : {},
|
|
34265
|
+
...started === void 0 ? {} : { parent: { pid: host, started } }
|
|
34266
|
+
};
|
|
34267
|
+
}
|
|
34268
|
+
startedOf(shown2) {
|
|
34269
|
+
return this.running(shown2) ? this.described.get(shown2)?.started : void 0;
|
|
34270
|
+
}
|
|
33959
34271
|
visudo(pid, call) {
|
|
33960
34272
|
return this.sudoer.check(this.credOf(pid), call);
|
|
33961
34273
|
}
|
|
@@ -37642,6 +37954,7 @@ async function createNodeKernel(options = {}) {
|
|
|
37642
37954
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
37643
37955
|
...options.requests ? { embedder: checkedRequests(options.requests) } : {},
|
|
37644
37956
|
...options.approve ? { approve: options.approve } : {},
|
|
37957
|
+
...options.sudo?.clock ? { sudoClock: options.sudo.clock } : {},
|
|
37645
37958
|
...options.wasmMemories ? { wasmMemories: options.wasmMemories } : {},
|
|
37646
37959
|
cron: { lock: cronLock(root), ...options.cron?.clock ? { clock: options.cron.clock } : {} }
|
|
37647
37960
|
});
|